From 75aa7b2d5acbb51eb7402bed08a83be4dd70e036 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 18 Mar 2017 14:15:49 -0700 Subject: [PATCH 001/138] Initial commit --- .gitignore | 33 +++++++++++++++++++++++++++++++++ LICENSE | 21 +++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f805e81 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e7fe790 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 CK Tan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 09de99f7a813a903f736495cef4f8a9684d93c85 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 18 Mar 2017 14:20:51 -0700 Subject: [PATCH 002/138] Init. --- Makefile | 28 + README.md | 101 ++ test/.gitignore | 3 + test/build.sh | 9 + test/extra/array_of_tables.toml | 1 + test/extra/inline_array.toml | 1 + test/extra/inline_table.toml | 1 + test/run.sh | 4 + toml.c | 1772 +++++++++++++++++++++++++++++++ toml.h | 108 ++ toml_cat.c | 165 +++ toml_json.c | 183 ++++ 12 files changed, 2376 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 test/.gitignore create mode 100644 test/build.sh create mode 100644 test/extra/array_of_tables.toml create mode 100644 test/extra/inline_array.toml create mode 100644 test/extra/inline_table.toml create mode 100644 test/run.sh create mode 100644 toml.c create mode 100644 toml.h create mode 100644 toml_cat.c create mode 100644 toml_json.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9dd3cf9 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +CC = gcc +CFILES = toml.c + +CFLAGS = -std=c99 -Wall -Wextra +CFLAGS += -O2 -DNDEBUG +#CFLAGS += -O0 -g + +EXEC = toml_json + +LIB = libtoml.a + +all: $(LIB) $(EXEC) + + +libtoml.a: toml.o + ar -rcs $@ $^ + +toml_json: toml_json.c $(LIB) + +prefix ?= /usr/local + +install: all + install -d ${prefix}/include ${prefix}/lib + install toml.h ${prefix}/include + install libtoml.a ${prefix}/lib + +clean: + rm -f *.o $(EXEC) $(LIB) diff --git a/README.md b/README.md new file mode 100644 index 0000000..bcbec94 --- /dev/null +++ b/README.md @@ -0,0 +1,101 @@ +# tomlc99 +TOML in c99; v0.4.0 compliant. + + +# Usage + +Please see the `toml.h` file for details. What follows is a simple example that +parses this config file: + +``` +[server] + host = www.example.com + port = 80 +``` + +For each config param, the code first extracts a raw value and then +convert it to a string or integer depending on context. + +``` + + FILE* fp; + toml_table_t* conf; + toml_table_t* server; + const char* raw; + char* host; + int64_t port; + char errbuf[200]; + + /* open file and parse */ + if (0 == (fp = fopen(FNAME, "r"))) { + perror("fopen"); + exit(1); + } + conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); + fclose(fp); + if (0 == conf) { + fprintf(stderr, "ERROR: %s\n", errbuf); + exit(1); + } + + /* locate the [server] table */ + if (0 == (server = toml_table_in(conf, "server"))) { + fprintf(stderr, "ERROR: missing [server]\n"); + toml_free(conf); + exit(1); + } + + /* extract host config value */ + if (0 == (raw = toml_raw_in(server, "host"))) { + fprintf(stderr, "ERROR: missing 'host' in [server]\n"); + toml_free(conf); + exit(1); + } + if (toml_rtos(raw, &host)) { + fprintf(stderr, "ERROR: bad value in 'host'\n"); + toml_free(conf); + exit(1); + } + + /* extract port config value */ + if (0 == (raw = toml_raw_in(server, "port"))) { + fprintf(stderr, "ERROR: missing 'port' in [server]\n"); + free(host); + toml_free(conf); + exit(1); + } + if (toml_rtoi(raw, &port)) { + fprintf(stderr, "ERROR: bad value in 'port'\n"); + free(host); + toml_free(conf); + exit(1); + } + + /* done with conf */ + toml_free(conf); + + /* use host and port */ + do_work(host, port); + + /* clean up */ + free(host); +``` + + +# Building + +A normal *make* suffices. Alternately, you can also simply include the +`toml.c` and `toml.h` files in your project. + +# Testing + +To test against the standard test set provided by BurntSushi/toml-test: + +``` + % make + % cd test + % bash build.sh # do this once + % bash run.sh # this will run the test suite + ``` + + diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..f39c742 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,3 @@ +/goworkspace +/toml-test +/toml-test-decoder diff --git a/test/build.sh b/test/build.sh new file mode 100644 index 0000000..535e03c --- /dev/null +++ b/test/build.sh @@ -0,0 +1,9 @@ + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +mkdir -p $DIR/goworkspace +export GOPATH=$DIR/goworkspace # if it isn't already set +go get github.com/BurntSushi/toml-test # install test suite +go get github.com/BurntSushi/toml/cmd/toml-test-decoder # e.g., install my parser +cp $GOPATH/bin/* . + diff --git a/test/extra/array_of_tables.toml b/test/extra/array_of_tables.toml new file mode 100644 index 0000000..86ed1f0 --- /dev/null +++ b/test/extra/array_of_tables.toml @@ -0,0 +1 @@ +x = [ {'a'= 1}, {'a'= 2} ] diff --git a/test/extra/inline_array.toml b/test/extra/inline_array.toml new file mode 100644 index 0000000..a0a971d --- /dev/null +++ b/test/extra/inline_array.toml @@ -0,0 +1 @@ +x = [1,2,3] diff --git a/test/extra/inline_table.toml b/test/extra/inline_table.toml new file mode 100644 index 0000000..7673f2e --- /dev/null +++ b/test/extra/inline_table.toml @@ -0,0 +1 @@ +x = {'a'= 1, 'b'= 2 } diff --git a/test/run.sh b/test/run.sh new file mode 100644 index 0000000..2bb548b --- /dev/null +++ b/test/run.sh @@ -0,0 +1,4 @@ +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +export GOPATH=$DIR/goworkspace # if it isn't already set +# $GOPATH/bin/toml-test $GOPATH/bin/toml-test-decoder # e.g., run tests on my parser +$GOPATH/bin/toml-test ../toml_json diff --git a/toml.c b/toml.c new file mode 100644 index 0000000..6b602e1 --- /dev/null +++ b/toml.c @@ -0,0 +1,1772 @@ +/* +MIT License + +Copyright (c) 2017 CK Tan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include "toml.h" + + +/** + * Convert a char in utf8 into UCS, and store it in *ret. + * Return #bytes consumed or -1 on failure. + */ +int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) +{ + const unsigned char* buf = (const unsigned char*) orig; + unsigned i = *buf++; + int64_t v; + + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (0 == (i >> 7)) { + if (len < 1) return -1; + v = i; + return *ret = v, 1; + } + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (0x6 == (i >> 5)) { + if (len < 2) return -1; + v = i & 0x1f; + i = *(++buf); + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + return *ret = v, (const char*) buf - orig; + } + + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (0xE == (i >> 4)) { + if (len < 3) return -1; + v = i & 0x0F; + for (int j = 0; j < 2; j++) { + i = *(++buf); + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x1E == (i >> 3)) { + if (len < 4) return -1; + v = i & 0x07; + for (int j = 0; j < 3; j++) { + i = *(++buf); + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x3E == (i >> 2)) { + if (len < 5) return -1; + v = i & 0x03; + for (int j = 0; j < 4; j++) { + i = *(++buf); + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x7e == (i >> 1)) { + if (len < 6) return -1; + v = i & 0x01; + for (int j = 0; j < 5; j++) { + i = *(++buf); + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + return -1; +} + + +/** + * Convert a UCS char to utf8 code, and return it in buf. + * Return #bytes used in buf to encode the char, or + * -1 on error. + */ +int toml_ucs_to_utf8(int64_t code, char buf[6]) +{ + /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 */ + /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well + * as 0xfffe and 0xffff (UCS noncharacters) should not appear in + * conforming UTF-8 streams. + */ + if (0xd800 <= code && code <= 0xdfff) return -1; + if (0xfffe <= code && code <= 0xffff) return -1; + + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (code < 0) return -1; + if (code <= 0x7F) { + buf[0] = (unsigned char) code; + return 1; + } + + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (code <= 0x000007FF) { + buf[0] = 0xc0 | (code >> 6); + buf[1] = 0x80 | (code & 0x3f); + return 2; + } + + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x0000FFFF) { + buf[0] = 0xe0 | (code >> 12); + buf[1] = 0x80 | ((code >> 6) & 0x3f); + buf[2] = 0x80 | (code & 0x3f); + return 3; + } + + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x001FFFFF) { + buf[0] = 0xf0 | (code >> 18); + buf[1] = 0x80 | ((code >> 12) & 0x3f); + buf[2] = 0x80 | ((code >> 6) & 0x3f); + buf[3] = 0x80 | (code & 0x3f); + return 4; + } + + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x03FFFFFF) { + buf[0] = 0xf8 | (code >> 24); + buf[1] = 0x80 | ((code >> 18) & 0x3f); + buf[2] = 0x80 | ((code >> 12) & 0x3f); + buf[3] = 0x80 | ((code >> 6) & 0x3f); + buf[4] = 0x80 | (code & 0x3f); + return 5; + } + + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x7FFFFFFF) { + buf[0] = 0xfc | (code >> 30); + buf[1] = 0x80 | ((code >> 24) & 0x3f); + buf[2] = 0x80 | ((code >> 18) & 0x3f); + buf[3] = 0x80 | ((code >> 12) & 0x3f); + buf[4] = 0x80 | ((code >> 6) & 0x3f); + buf[5] = 0x80 | (code & 0x3f); + return 6; + } + + return -1; +} + +/* + * TOML has 3 data structures: value, array, table. + * Each of them can have identification key. + */ +typedef struct toml_keyval_t toml_keyval_t; +struct toml_keyval_t { + const char* key; /* key to this value */ + const char* val; /* the raw value */ +}; + + +struct toml_array_t { + const char* key; /* key to this array */ + int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */ + int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ + + int nelem; /* number of elements */ + union { + char** val; + toml_array_t** arr; + toml_table_t** tab; + } u; +}; + + +struct toml_table_t { + const char* key; /* key to this table */ + int implicit; /* table was created implicitly */ + + /* key-values in the table */ + int nkval; + toml_keyval_t** kval; + + /* arrays in the table */ + int narr; + toml_array_t** arr; + + /* tables in the table */ + int ntab; + toml_table_t** tab; +}; + + +static inline void xfree(const void* x) { if (x) free((void*)x); } + + +enum tokentype_t { + INVALID, + DOT, + COMMA, + EQUAL, + LBRACE, + RBRACE, + NEWLINE, + LBRACKET, + RBRACKET, + STRING, +}; +typedef enum tokentype_t tokentype_t; + +typedef struct token_t token_t; +struct token_t { + tokentype_t tok; + int lineno; + char* ptr; + int len; + int eof; +}; + + +typedef struct context_t context_t; +struct context_t { + char* start; + char* stop; + char* errbuf; + int errbufsz; + jmp_buf jmp; + + token_t tok; + toml_table_t* root; + toml_table_t* curtab; + + struct { + int top; + char* key[10]; + token_t tok[10]; + } tpath; + +}; + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define FLINE __FILE__ ":" TOSTRING(__LINE__) +static int outofmemory(context_t* ctx, const char* fline); +static tokentype_t next_token(context_t* ctx, int dotisspecial); + +static int internal_error(context_t* ctx, const char* fline) +{ + snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); + longjmp(ctx->jmp, 1); + return -1; +} + +static int syntax_error(context_t* ctx, int lineno, const char* msg) +{ + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); + longjmp(ctx->jmp, 1); + return -1; +} + +static int bad_key_error(context_t* ctx, int lineno) +{ + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); + longjmp(ctx->jmp, 1); + return -1; +} + +/* +static int noimpl(context_t* ctx, const char* feature) +{ + snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature); + longjmp(ctx->jmp, 1); + return -1; +} +*/ + +static int key_exists_error(context_t* ctx, token_t keytok) +{ + char buf[100]; + int i; + for (i = 0; i < keytok.len && i < (int)sizeof(buf) - 1; i++) { + buf[i] = keytok.ptr[i]; + } + buf[i] = 0; + + snprintf(ctx->errbuf, ctx->errbufsz, + "line %d: key %s exists", keytok.lineno, buf); + longjmp(ctx->jmp, 1); + return -1; +} + + + +/* + * Convert src to raw unescaped utf-8 string. + * Returns NULL if error with errmsg in errbuf. + */ +static char* normalize_string(const char* src, int srclen, + int kill_line_ending_backslash, + char* errbuf, int errbufsz) +{ + char* dst = 0; /* will write to dst[] and return it */ + int max = 0; /* max size of dst[] */ + int off = 0; /* cur offset in dst[] */ + const char* sp = src; + const char* sq = src + srclen; + int ch; + + /* scan forward on src */ + for (;;) { + if (off >= max - 10) { /* have some slack for misc stuff */ + char* x = realloc(dst, max += 100); + if (!x) { + xfree(dst); + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + dst = x; + } + + /* finished? */ + if (sp >= sq) break; + + ch = *sp++; + if (ch != '\\') { + // a plain copy suffice + dst[off++] = ch; + continue; + } + + /* ch was backslash. we expect the escape char. */ + if (sp >= sq) { + snprintf(errbuf, errbufsz, "last backslash is invalid"); + free(dst); + return 0; + } + + /* if we want to kill line-ending-backslash ... */ + if (kill_line_ending_backslash) { + /* if this is a newline immediately following the backslash ... */ + if (*sp == '\n' || (*sp == '\r' && sp[1] == '\n')) { + /* skip all the following whitespaces */ + sp += strspn(sp, " \t\r\n"); + continue; + } + } + + /* get the escaped char */ + ch = *sp++; + switch (ch) { + case 'u': case 'U': + { + int64_t ucs = 0; + int nhex = (ch == 'u' ? 4 : 8); + for (int i = 0; i < nhex; i++) { + if (sp >= sq) { + snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); + free(dst); + return 0; + } + ch = *sp++; + int v = ('0' <= ch && ch <= '9') + ? ch - '0' + : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); + if (-1 == v) { + snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); + free(dst); + return 0; + } + ucs = ucs * 16 + v; + } + int n = toml_ucs_to_utf8(ucs, &dst[off]); + if (-1 == n) { + snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); + free(dst); + return 0; + } + off += n; + } + continue; + + case 'b': ch = '\b'; break; + case 't': ch = '\t'; break; + case 'n': ch = '\n'; break; + case 'f': ch = '\f'; break; + case 'r': ch = '\r'; break; + case '"': ch = '"'; break; + case '\\': ch = '\\'; break; + default: + snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); + free(dst); + return 0; + } + + dst[off++] = ch; + } + + // Cap with NUL and return it. + dst[off++] = 0; + return dst; +} + + +/* Normalize a key. Convert all special chars to raw unescaped utf-8 chars. */ +static char* normalize_key(context_t* ctx, token_t strtok) +{ + const char* sp = strtok.ptr; + const char* sq = strtok.ptr + strtok.len; + int lineno = strtok.lineno; + char* ret; + int ch = *sp; + char ebuf[80]; + + /* handle quoted string */ + if (ch == '\'' || ch == '\"') { + /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ + if (sp[1] == ch && sp[2] == ch) + sp += 3, sq -= 3; + else + sp++, sq--; + + if (ch == '\'') { + /* for single quote, take it verbatim. */ + if (! (ret = strndup(sp, sq - sp))) outofmemory(ctx, FLINE); + } else { + /* for double quote, we need to normalize */ + ret = normalize_string(sp, sq - sp, 0, ebuf, sizeof(ebuf)); + if (!ret) { + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); + longjmp(ctx->jmp, 1); + } + } + + /* newlines are not allowed in keys */ + if (strchr(ret, '\n')) { + free(ret); + bad_key_error(ctx, lineno); + } + return ret; + } + + /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ + const char* xp; + for (xp = sp; xp != sq; xp++) { + int ch = *xp; + if (isalnum(ch)) continue; + if (ch == '_' || ch == '-') continue; + bad_key_error(ctx, lineno); + } + + /* dup and return it */ + if (! (ret = strndup(sp, sq - sp))) outofmemory(ctx, FLINE); + return ret; +} + + +/* + * Look up key in tab. Return 0 if not found, or + * 'v'alue, 'a'rray or 't'able depending on the element. + */ +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) +{ + int i; + void* dummy; + + if (!ret_tab) ret_tab = (toml_table_t**) &dummy; + if (!ret_arr) ret_arr = (toml_array_t**) &dummy; + if (!ret_val) ret_val = (toml_keyval_t**) &dummy; + + *ret_tab = 0; *ret_arr = 0; *ret_val = 0; + + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) { + *ret_val = tab->kval[i]; + return 'v'; + } + } + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) { + *ret_arr = tab->arr[i]; + return 'a'; + } + } + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) { + *ret_tab = tab->tab[i]; + return 't'; + } + } + return 0; +} + +/* Create a keyval in the table. + */ +static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) +{ + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); + + /* if key exists: error out. */ + toml_keyval_t* dest = 0; + if (check_key(tab, newkey, 0, 0, 0)) { + free(newkey); + key_exists_error(ctx, keytok); + } + + /* make a new entry */ + int n = tab->nkval; + toml_keyval_t** base; + if (0 == (base = realloc(tab->kval, (n+1) * sizeof(*base)))) { + free(newkey); + outofmemory(ctx, FLINE); + } + tab->kval = base; + + if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + free(newkey); + outofmemory(ctx, FLINE); + } + dest = tab->kval[tab->nkval++]; + + /* save the key in the new value struct */ + dest->key = newkey; + return dest; +} + + +/* Create a table in the table. + */ +static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) +{ + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); + + /* if key exists: error out */ + toml_table_t* dest = 0; + if (check_key(tab, newkey, 0, 0, &dest)) { + free(newkey); /* don't need this anymore */ + + /* special case: if table exists, but was created implicitly ... */ + if (dest && dest->implicit) { + /* we make it explicit now, and simply return it. */ + dest->implicit = 0; + return dest; + } + key_exists_error(ctx, keytok); + } + + /* create a new table entry */ + int n = tab->ntab; + toml_table_t** base; + if (0 == (base = realloc(tab->tab, (n+1) * sizeof(*base)))) { + free(newkey); + outofmemory(ctx, FLINE); + } + tab->tab = base; + + if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + free(newkey); + outofmemory(ctx, FLINE); + } + dest = tab->tab[tab->ntab++]; + + /* save the key in the new table struct */ + dest->key = newkey; + return dest; +} + + +/* Create an array in the table. + */ +static toml_array_t* create_keyarray_in_table(context_t* ctx, + toml_table_t* tab, + token_t keytok, + int skip_if_exist) +{ + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); + + /* if key exists: error out */ + toml_array_t* dest = 0; + if (check_key(tab, newkey, 0, &dest, 0)) { + free(newkey); /* don't need this anymore */ + + /* special case skip if exists? */ + if (skip_if_exist) return dest; + + key_exists_error(ctx, keytok); + } + + /* make a new array entry */ + int n = tab->narr; + toml_array_t** base; + if (0 == (base = realloc(tab->arr, (n+1) * sizeof(*base)))) { + free(newkey); + outofmemory(ctx, FLINE); + } + tab->arr = base; + + if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + free(newkey); + outofmemory(ctx, FLINE); + } + dest = tab->arr[tab->narr++]; + + /* save the key in the new array struct */ + dest->key = newkey; + return dest; +} + +/* Create an array in an array + */ +static toml_array_t* create_array_in_array(context_t* ctx, + toml_array_t* parent) +{ + int n = parent->nelem; + toml_array_t** base; + if (0 == (base = realloc(parent->u.arr, (n+1) * sizeof(*base)))) { + outofmemory(ctx, FLINE); + } + parent->u.arr = base; + + if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + outofmemory(ctx, FLINE); + } + + return parent->u.arr[parent->nelem++]; +} + +/* Create a table in an array + */ +static toml_table_t* create_table_in_array(context_t* ctx, + toml_array_t* parent) +{ + int n = parent->nelem; + toml_table_t** base; + if (0 == (base = realloc(parent->u.tab, (n+1) * sizeof(*base)))) { + outofmemory(ctx, FLINE); + } + parent->u.tab = base; + + if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + outofmemory(ctx, FLINE); + } + + return parent->u.tab[parent->nelem++]; +} + + +#define SKIP_NEWLINES(ctx) while (ctx->tok.tok == NEWLINE) next_token(ctx, 0) +#define EAT_TOKEN(ctx, typ) \ + if ((ctx)->tok.tok != typ) internal_error(ctx, FLINE); else next_token(ctx, 0) + + +static void parse_keyval(context_t* ctx, toml_table_t* tab); + + +/* We are at '{ ... }'. + * Parse the table. + */ +static void parse_table(context_t* ctx, toml_table_t* tab) +{ + EAT_TOKEN(ctx, LBRACE); + + for (;;) { + SKIP_NEWLINES(ctx); + + /* until } */ + if (ctx->tok.tok == RBRACE) break; + + switch (ctx->tok.tok) { + case STRING: parse_keyval(ctx, tab); break; + default: syntax_error(ctx, ctx->tok.lineno, "syntax error"); + } + + SKIP_NEWLINES(ctx); + + /* on comma, continue to scan for next keyval */ + if (ctx->tok.tok == COMMA) { + EAT_TOKEN(ctx, COMMA); + continue; + } + break; + } + + if (ctx->tok.tok != RBRACE) + syntax_error(ctx, ctx->tok.lineno, "syntax error"); + + EAT_TOKEN(ctx, RBRACE); +} + +static int valtype(const char* val) +{ + toml_timestamp_t ts; + if (*val == '\'' || *val == '"') return 's'; + if (0 == toml_rtob(val, 0)) return 'b'; + if (0 == toml_rtoi(val, 0)) return 'i'; + if (0 == toml_rtod(val, 0)) return 'd'; + if (0 == toml_rtots(val, &ts)) { + if (ts.year && ts.hour) return 'T'; /* timestamp */ + if (ts.year) return 'D'; /* date */ + return 't'; /* time */ + } + return 'u'; /* unknown */ +} + + +/* We are at '[...]' */ +static void parse_array(context_t* ctx, toml_array_t* arr) +{ + EAT_TOKEN(ctx, LBRACKET); + + for (;;) { + SKIP_NEWLINES(ctx); + + /* until ] */ + if (ctx->tok.tok == RBRACKET) break; + + switch (ctx->tok.tok) { + case STRING: + { + char* val = ctx->tok.ptr; + int vlen = ctx->tok.len; + + /* set array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'v'; + /* check array kind */ + if (arr->kind != 'v') { + syntax_error(ctx, ctx->tok.lineno, + "a string array can only contain strings"); + } + + /* make a new value in array */ + char** tmp = realloc(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); + if (!tmp) outofmemory(ctx, FLINE); + arr->u.val = tmp; + if (! (val = strndup(val, vlen))) outofmemory(ctx, FLINE); + arr->u.val[arr->nelem++] = val; + + /* set array type if this is the first entry, or check that the types matched. */ + if (arr->nelem == 1) + arr->type = valtype(arr->u.val[0]); + else if (arr->type != valtype(val)) + syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + + EAT_TOKEN(ctx, STRING); + break; + } + + case LBRACKET: + { /* [ [array], [array] ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'a'; + /* check array kind */ + if (arr->kind != 'a') { + syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + } + parse_array(ctx, create_array_in_array(ctx, arr)); + break; + } + + case LBRACE: + { /* [ {table}, {table} ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 't'; + /* check array kind */ + if (arr->kind != 't') { + syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + } + parse_table(ctx, create_table_in_array(ctx, arr)); + break; + } + + default: + syntax_error(ctx, ctx->tok.lineno, "syntax error"); + } + + SKIP_NEWLINES(ctx); + + /* on comma, continue to scan for next element */ + if (ctx->tok.tok == COMMA) { + EAT_TOKEN(ctx, COMMA); + continue; + } + break; + } + + if (ctx->tok.tok != RBRACKET) + syntax_error(ctx, ctx->tok.lineno, "syntax error"); + + EAT_TOKEN(ctx, RBRACKET); +} + + + +/* handle lines like these: + key = "value" + key = [ array ] + key = { table } +*/ +static void parse_keyval(context_t* ctx, toml_table_t* tab) +{ + if (ctx->tok.tok != STRING) + internal_error(ctx, FLINE); + + token_t key = ctx->tok; + + EAT_TOKEN(ctx, STRING); + if (ctx->tok.tok != EQUAL) + syntax_error(ctx, ctx->tok.lineno, "missing ="); + + EAT_TOKEN(ctx, EQUAL); + + switch (ctx->tok.tok) { + case STRING: + { /* key = "value" */ + toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); + token_t val = ctx->tok; + assert(keyval->val == 0); + keyval->val = strndup(val.ptr, val.len); + if (! keyval->val) outofmemory(ctx, FLINE); + + EAT_TOKEN(ctx, STRING); + + return; + } + + case LBRACKET: + { /* key = [ array ] */ + toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); + parse_array(ctx, arr); + return; + } + + case LBRACE: + { /* key = { table } */ + toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); + parse_table(ctx, nxttab); + return; + } + + default: + syntax_error(ctx, ctx->tok.lineno, "syntax error"); + } +} + + +typedef struct tabpath_t tabpath_t; +struct tabpath_t { + int cnt; + token_t key[10]; +}; + +/* at [x.y.z] or [[x.y.z]] + * Scan forward and fill tabpath until it enters ] or ]] + * There will be at least one entry on return. + */ +static void fill_tabpath(context_t* ctx) +{ + int lineno = ctx->tok.lineno; + int i; + + /* clear tpath */ + for (i = 0; i < ctx->tpath.top; i++) { + char** p = &ctx->tpath.key[i]; + xfree(*p); + *p = 0; + } + ctx->tpath.top = 0; + + for (;;) { + if (ctx->tpath.top >= 10) + syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); + + if (ctx->tok.tok != STRING) + syntax_error(ctx, lineno, "invalid or missing key"); + + ctx->tpath.tok[ctx->tpath.top] = ctx->tok; + ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); + ctx->tpath.top++; + + next_token(ctx, 1); + + if (ctx->tok.tok == RBRACKET) break; + + if (ctx->tok.tok != DOT) + syntax_error(ctx, lineno, "invalid key"); + + next_token(ctx, 1); + } + + if (ctx->tpath.top <= 0) { + syntax_error(ctx, lineno, "empty table selector"); + } +} + + +/* Walk tabpath from the root, and create new tables on the way. + * Sets ctx->curtab to the final table. + */ +static void walk_tabpath(context_t* ctx) +{ + /* start from root */ + toml_table_t* curtab = ctx->root; + + for (int i = 0; i < ctx->tpath.top; i++) { + const char* key = ctx->tpath.key[i]; + + toml_keyval_t* nextval = 0; + toml_array_t* nextarr = 0; + toml_table_t* nexttab = 0; + switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { + case 't': + /* found a table. nexttab is where we will go next. */ + break; + + case 'a': + /* found an array. nexttab is the last table in the array. */ + if (nextarr->kind != 't') internal_error(ctx, FLINE); + if (nextarr->nelem == 0) internal_error(ctx, FLINE); + nexttab = nextarr->u.tab[nextarr->nelem-1]; + break; + + case 'v': + key_exists_error(ctx, ctx->tpath.tok[i]); + break; + + default: + { /* Not found. Let's create an implicit table. */ + int n = curtab->ntab; + toml_table_t** base = realloc(curtab->tab, (n+1) * sizeof(*base)); + if (0 == base) outofmemory(ctx, FLINE); + curtab->tab = base; + + if (0 == (base[n] = calloc(1, sizeof(*base[n])))) + outofmemory(ctx, FLINE); + + if (0 == (base[n]->key = strdup(key))) + outofmemory(ctx, FLINE); + + nexttab = curtab->tab[curtab->ntab++]; + + /* tabs created by walk_tabpath are considered implicit */ + nexttab->implicit = 1; + } + break; + } + + /* switch to next tab */ + curtab = nexttab; + } + + /* save it */ + ctx->curtab = curtab; +} + + +/* handle lines like [x.y.z] or [[x.y.z]] */ +static void parse_select(context_t* ctx) +{ + int count_lbracket = 0; + if (ctx->tok.tok != LBRACKET) internal_error(ctx, FLINE); + count_lbracket++; + next_token(ctx, 1 /* DOT IS SPECIAL */); + if (ctx->tok.tok == LBRACKET) { + count_lbracket++; + next_token(ctx, 1 /* DOT IS SPECIAL */); + } + + fill_tabpath(ctx); + + /* For [x.y.z] or [[x.y.z]], remove z from tpath. + */ + token_t z = ctx->tpath.tok[ctx->tpath.top-1]; + free(ctx->tpath.key[ctx->tpath.top-1]); + ctx->tpath.top--; + + walk_tabpath(ctx); + + if (count_lbracket == 1) { + /* [x.y.z] -> create z = {} in x.y */ + ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); + } else { + /* [[x.y.z]] -> create z = [] in x.y */ + toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z, + 1 /*skip_if_exist*/); + if (arr->kind == 0) arr->kind = 't'; + if (arr->kind != 't') syntax_error(ctx, z.lineno, "array mismatch"); + + /* add to z[] */ + toml_table_t* dest; + { + int n = arr->nelem; + toml_table_t** base = realloc(arr->u.tab, (n+1) * sizeof(*base)); + if (0 == base) outofmemory(ctx, FLINE); + arr->u.tab = base; + + if (0 == (base[n] = calloc(1, sizeof(*base[n])))) + outofmemory(ctx, FLINE); + + if (0 == (base[n]->key = strdup("__anon__"))) + outofmemory(ctx, FLINE); + + dest = arr->u.tab[arr->nelem++]; + } + + ctx->curtab = dest; + } + + if (ctx->tok.tok != RBRACKET) syntax_error(ctx, ctx->tok.lineno, "expects ]"); + EAT_TOKEN(ctx, RBRACKET); + + if (count_lbracket == 2) { + if (ctx->tok.tok != RBRACKET) syntax_error(ctx, ctx->tok.lineno, "expects ]]"); + EAT_TOKEN(ctx, RBRACKET); + } + if (ctx->tok.tok != NEWLINE) syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); +} + + + + +toml_table_t* toml_parse(char* conf, + char* errbuf, + int errbufsz) +{ + context_t ctx; + + // clear errbuf + if (errbufsz <= 0) errbufsz = 0; + if (errbufsz > 0) errbuf[0] = 0; + + // init context + memset(&ctx, 0, sizeof(ctx)); + ctx.start = conf; + ctx.stop = ctx.start + strlen(conf); + ctx.errbuf = errbuf; + ctx.errbufsz = errbufsz; + + // start with an artificial newline of length 0 + ctx.tok.tok = NEWLINE; + ctx.tok.lineno = 1; + ctx.tok.ptr = conf; + ctx.tok.len = 0; + + // make a root table + if (0 == (ctx.root = calloc(1, sizeof(*ctx.root)))) { + outofmemory(&ctx, FLINE); + return 0; + } + + // set root as default table + ctx.curtab = ctx.root; + + if (0 != setjmp(ctx.jmp)) { + // Got here from a long_jmp. Something bad has happened. + // Free resources and return error. + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + toml_free(ctx.root); + return 0; + } + + /* Scan forward until EOF */ + for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { + switch (tok.tok) { + + case NEWLINE: + next_token(&ctx, 1); + break; + + case STRING: + parse_keyval(&ctx, ctx.curtab); + if (ctx.tok.tok != NEWLINE) + syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); + + EAT_TOKEN(&ctx, NEWLINE); + break; + + case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ + parse_select(&ctx); + break; + + default: + snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); + longjmp(ctx.jmp, 1); + } + } + + /* success */ + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + return ctx.root; +} + + +toml_table_t* toml_parse_file(FILE* fp, + char* errbuf, + int errbufsz) +{ + int bufsz = 0; + char* buf = 0; + int off = 0; + + /* read from fp into buf */ + while (! feof(fp)) { + bufsz += 100; + + /* Allocate 1 extra byte because we will tag on a NUL */ + char* x = realloc(buf, bufsz + 1); + if (!x) { + snprintf(errbuf, errbufsz, "out of memory"); + xfree(buf); + return 0; + } + buf = x; + + errno = 0; + int n = fread(buf + off, 1, bufsz - off, fp); + if (ferror(fp)) { + snprintf(errbuf, errbufsz, "%s", + errno ? strerror(errno) : "Error reading file"); + free(buf); + return 0; + } + off += n; + } + + /* tag on a NUL to cap the string */ + buf[off] = 0; /* we accounted for this byte in the realloc() above. */ + + /* parse it, cleanup and finish */ + toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); + free(buf); + return ret; +} + + +static void xfree_kval(toml_keyval_t* p) +{ + if (!p) return; + xfree(p->key); + xfree(p->val); + xfree(p); +} + +static void xfree_tab(toml_table_t* p); + +static void xfree_arr(toml_array_t* p) +{ + if (!p) return; + + xfree(p->key); + switch (p->kind) { + case 'v': + for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); + xfree(p->u.val); + break; + + case 'a': + for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); + xfree(p->u.arr); + break; + + case 't': + for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); + xfree(p->u.tab); + break; + } + + xfree(p); +} + + +static void xfree_tab(toml_table_t* p) +{ + int i; + + if (!p) return; + + xfree(p->key); + + for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); + xfree(p->kval); + + for (i = 0; i < p->narr; i++) xfree_arr(p->arr[i]); + xfree(p->arr); + + for (i = 0; i < p->ntab; i++) xfree_tab(p->tab[i]); + xfree(p->tab); + + xfree(p); +} + + +void toml_free(toml_table_t* tab) +{ + xfree_tab(tab); +} + + +static tokentype_t ret_token(context_t* ctx, tokentype_t tok, int lineno, char* ptr, int len) +{ + token_t t; + t.tok = tok; + t.lineno = lineno; + t.ptr = ptr; + t.len = len; + t.eof = 0; + ctx->tok = t; + return tok; +} + +static tokentype_t ret_eof(context_t* ctx, int lineno) +{ + ret_token(ctx, NEWLINE, lineno, ctx->stop, 0); + ctx->tok.eof = 1; + return ctx->tok.tok; +} + + +static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) +{ + char* orig = p; + if (0 == strncmp(p, "'''", 3)) { + p = strstr(p + 3, "'''"); + if (0 == p) + syntax_error(ctx, lineno, "unterminated triple-s-quote"); + + return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); + } + + if (0 == strncmp(p, "\"\"\"", 3)) { + int hexreq = 0; /* #hex required */ + int escape = 0; + int qcnt = 0; /* count quote */ + for (p += 3; *p && qcnt < 3; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + if (*p == '\n') continue; /* allow for line ending backslash */ + syntax_error(ctx, lineno, "bad escape char"); + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + syntax_error(ctx, lineno, "expect hex char"); + } + if (*p == '\\') { escape = 1; continue; } + qcnt = (*p == '"') ? qcnt + 1 : 0; + } + if (qcnt != 3) + syntax_error(ctx, lineno, "unterminated triple-quote"); + + return ret_token(ctx, STRING, lineno, orig, p - orig); + } + + if ('\'' == *p) { + for (p++; *p && *p != '\n' && *p != '\''; p++); + if (*p != '\'') + syntax_error(ctx, lineno, "unterminated s-quote"); + + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + } + + if ('\"' == *p) { + int hexreq = 0; /* #hex required */ + int escape = 0; + for (p++; *p; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + syntax_error(ctx, lineno, "bad escape char"); + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + syntax_error(ctx, lineno, "expect hex char"); + } + if (*p == '\\') { escape = 1; continue; } + if (*p == '\n') break; + if (*p == '"') break; + } + if (*p != '"') + syntax_error(ctx, lineno, "unterminated quote"); + + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + } + + for ( ; *p && *p != '\n'; p++) { + int ch = *p; + if (ch == '.' && dotisspecial) break; + if ('A' <= ch && ch <= 'Z') continue; + if ('a' <= ch && ch <= 'z') continue; + if ('0' <= ch && ch <= '9') continue; + if (strchr("+-_.:", ch)) continue; + break; + } + + return ret_token(ctx, STRING, lineno, orig, p - orig); +} + + +static tokentype_t next_token(context_t* ctx, int dotisspecial) +{ + int lineno = ctx->tok.lineno; + char* p = ctx->tok.ptr; + int i; + + /* eat this tok */ + for (i = 0; i < ctx->tok.len; i++) { + if (*p++ == '\n') + lineno++; + } + + /* make next tok */ + while (p < ctx->stop) { + /* skip comment. stop just before the \n. */ + if (*p == '#') { + for (p++; p < ctx->stop && *p != '\n'; p++); + continue; + } + + if (dotisspecial && *p == '.') + return ret_token(ctx, DOT, lineno, p, 1); + + switch (*p) { + case ',': return ret_token(ctx, COMMA, lineno, p, 1); + case '=': return ret_token(ctx, EQUAL, lineno, p, 1); + case '{': return ret_token(ctx, LBRACE, lineno, p, 1); + case '}': return ret_token(ctx, RBRACE, lineno, p, 1); + case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); + case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); + case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); + case '\r': case ' ': case '\t': + /* ignore white spaces */ + p++; + continue; + } + + return scan_string(ctx, p, lineno, dotisspecial); + } + + return ret_eof(ctx, lineno); +} + +static int outofmemory(context_t* ctx, const char* fline) +{ + snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); + return -1; +} + +const char* toml_key_in(toml_table_t* tab, int keyidx) +{ + if (keyidx < tab->nkval) return tab->kval[keyidx]->key; + + keyidx -= tab->nkval; + if (keyidx < tab->narr) return tab->arr[keyidx]->key; + + keyidx -= tab->narr; + if (keyidx < tab->ntab) return tab->tab[keyidx]->key; + + return 0; +} + + +const char* toml_raw_in(toml_table_t* tab, const char* key) +{ + int i; + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) + return tab->kval[i]->val; + } + return 0; +} + +toml_array_t* toml_array_in(toml_table_t* tab, const char* key) +{ + int i; + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) + return tab->arr[i]; + } + return 0; +} + + +toml_table_t* toml_table_in(toml_table_t* tab, const char* key) +{ + int i; + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) + return tab->tab[i]; + } + return 0; +} + +const char* toml_raw_at(toml_array_t* arr, int idx) +{ + if (arr->kind != 'v') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.val[idx]; +} + +char toml_array_kind(toml_array_t* arr) +{ + return arr->kind; +} + + + +toml_array_t* toml_array_at(toml_array_t* arr, int idx) +{ + if (arr->kind != 'a') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.arr[idx]; +} + +toml_table_t* toml_table_at(toml_array_t* arr, int idx) +{ + if (arr->kind != 't') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.tab[idx]; +} + + +int toml_rtots(const char* src_, toml_timestamp_t* ret) +{ + if (! src_) return -1; + + const char* p = src_; + const char* q = src_ + strlen(src_); + int64_t val; + int i; + + memset(ret, 0, sizeof(*ret)); + + /* parse date */ + val = 0; + if (q - p > 4 && p[4] == '-') { + for (i = 0; i < 10; i++, p++) { + int xx = *p; + if (xx == '-') { + if (i == 4 || i == 7) continue; else return -1; + } + if (! ('0' <= xx && xx <= '9')) return -1; + val = val * 10 + (xx - '0'); + } + ret->day = &ret->__buffer.day; + ret->month = &ret->__buffer.month; + ret->year = &ret->__buffer.year; + + *ret->day = val % 100; val /= 100; + *ret->month = val % 100; val /= 100; + *ret->year = val; + + if (*p) { + if (*p != 'T') return -1; + p++; + } + } + if (q == p) return 0; + + /* parse time */ + val = 0; + if (q - p < 8) return -1; + for (i = 0; i < 8; i++, p++) { + int xx = *p; + if (xx == ':') { + if (i == 2 || i == 5) continue; else return -1; + } + if (! ('0' <= xx && xx <= '9')) return -1; + val = val * 10 + (xx - '0'); + } + ret->second = &ret->__buffer.second; + ret->minute = &ret->__buffer.minute; + ret->hour = &ret->__buffer.hour; + + *ret->second = val % 100; val /= 100; + *ret->minute = val % 100; val /= 100; + *ret->hour = val; + + /* skip fractional second */ + if (*p == '.') for (p++; '0' <= *p && *p <= '9'; p++); + if (q == p) return 0; + + /* parse and copy Z */ + ret->z = ret->__buffer.z; + char* z = ret->z; + if (*p == 'Z') { + *z++ = *p++; + *z = 0; + return (p == q) ? 0 : -1; + } + if (*p == '+' || *p == '-') { + *z++ = *p++; + + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; + *z++ = *p++; + *z++ = *p++; + + if (*p == ':') { + *z++ = *p++; + + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; + *z++ = *p++; + *z++ = *p++; + } + + *z = 0; + } + return (p == q) ? 0 : -1; +} + + +/* Raw to boolean */ +int toml_rtob(const char* src, int* ret_) +{ + if (!src) return -1; + int dummy; + int* ret = ret_ ? ret_ : &dummy; + + if (0 == strcmp(src, "true")) { + *ret = 1; + return 0; + } + if (0 == strcmp(src, "false")) { + *ret = 0; + return 0; + } + return -1; +} + + +/* Raw to integer */ +int toml_rtoi(const char* src, int64_t* ret_) +{ + if (!src) return -1; + + char buf[100]; + char* p = buf; + char* q = p + sizeof(buf); + const char* s = src; + int64_t dummy; + int64_t* ret = ret_ ? ret_ : &dummy; + + if (*s == '+') + *p++ = *s++; + else if (*s == '-') + *p++ = *s++; + + /* if 0 ... */ + if ('0' == s[0]) { + /* ensure no other digits after it */ + if (s[1]) return -1; + return *ret = 0, 0; + } + + /* just strip underscores and pass to strtoll */ + while (*s && p < q) { + int ch = *s++; + if (ch == '_') ; else *p++ = ch; + } + if (*s || p == q) return -1; + + /* cap with NUL */ + *p = 0; + + /* Run strtoll on buf to get the integer */ + char* endp; + errno = 0; + *ret = strtoll(buf, &endp, 0); + return (errno || *endp) ? -1 : 0; +} + + +int toml_rtod(const char* src, double* ret_) +{ + if (!src) return -1; + + char buf[100]; + char* p = buf; + char* q = p + sizeof(buf); + const char* s = src; + double dummy; + double* ret = ret_ ? ret_ : &dummy; + + /* check for special cases */ + if (s[0] == '+' || s[0] == '-') *p++ = *s++; + if (s[0] == '.') return -1; /* no leading zero */ + if (s[0] == '0') { + /* zero must be followed by . or NUL */ + if (s[1] && s[1] != '.') return -1; + } + + /* just strip underscores and pass to strtod */ + while (*s && p < q) { + int ch = *s++; + if (ch == '_') ; else *p++ = ch; + } + if (*s || p == q) return -1; + + if (p != buf && p[-1] == '.') + return -1; /* no trailing zero */ + + /* cap with NUL */ + *p = 0; + + /* Run strtod on buf to get the value */ + char* endp; + errno = 0; + *ret = strtod(buf, &endp); + return (errno || *endp) ? -1 : 0; +} + + +static char* kill_line_ending_backslash(char* str) +{ + if (!str) return 0; + + /* first round: find (backslash, \n) */ + char* p = str; + while (0 != (p = strstr(p, "\\\n"))) { + char* q = (p + 1); + q += strspn(q, " \t\r\n"); + memmove(p, q, strlen(q) + 1); + } + /* second round: find (backslash, \r, \n) */ + p = str; + while (0 != (p = strstr(p, "\\\r\n"))) { + char* q = (p + 1); + q += strspn(q, " \t\r\n"); + memmove(p, q, strlen(q) + 1); + } + + return str; +} + + +int toml_rtos(const char* src, char** ret) +{ + if (!src) return -1; + if (*src != '\'' && *src != '"') return -1; + + *ret = 0; + int srclen = strlen(src); + if (*src == '\'') { + if (0 == strncmp(src, "'''", 3)) { + const char* sp = src + 3; + const char* sq = src + srclen - 3; + /* last 3 chars in src must be ''' */ + if (! (sp <= sq && 0 == strcmp(sq, "'''"))) + return -1; + + /* skip first new line right after ''' */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; + + *ret = kill_line_ending_backslash(strndup(sp, sq - sp)); + } else { + const char* sp = src + 1; + const char* sq = src + srclen - 1; + /* last char in src must be ' */ + if (! (sp <= sq && *sq == '\'')) + return -1; + /* copy from sp to p */ + *ret = strndup(sp, sq - sp); + } + return *ret ? 0 : -1; + } + + const char* sp; + const char* sq; + if (0 == strncmp(src, "\"\"\"", 3)) { + sp = src + 3; + sq = src + srclen - 3; + if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) + return -1; + + /* skip first new line right after """ */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; + } else { + sp = src + 1; + sq = src + srclen - 1; + if (! (sp <= sq && *sq == '"')) + return -1; + } + + char dummy_errbuf[1]; + *ret = normalize_string(sp, sq - sp, + 1, // flag kill_line_ending_backslash + dummy_errbuf, sizeof(dummy_errbuf)); + return *ret ? 0 : -1; +} diff --git a/toml.h b/toml.h new file mode 100644 index 0000000..38d076e --- /dev/null +++ b/toml.h @@ -0,0 +1,108 @@ +/* +MIT License + +Copyright (c) 2017 CK Tan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#ifndef TOML_H +#define TOML_H + +#ifdef __cplusplus +#define TOML_EXTERN extern "C" +#else +#define TOML_EXTERN extern +#endif + +typedef struct toml_table_t toml_table_t; +typedef struct toml_array_t toml_array_t; + +/* Parse a file. Return a table on success, or 0 otherwise. + * Caller must toml_free(the-return-value) after use. + */ +TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, + char* errbuf, + int errbufsz); + +/* Parse a string containing the full config. + * Return a table on success, or 0 otherwise. + * Caller must toml_free(the-return-value) after use. + */ +TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */ + char* errbuf, + int errbufsz); + +/* Free the table returned by toml_parse() or toml_parse_file(). */ +TOML_EXTERN void toml_free(toml_table_t* tab); + +/* Retrieve the key in table at keyidx. Return 0 if out of range. */ +TOML_EXTERN const char* toml_key_in(toml_table_t* tab, int keyidx); + +/* Lookup table by key. Return the element or 0 if not found. */ +TOML_EXTERN const char* toml_raw_in(toml_table_t* tab, const char* key); +TOML_EXTERN toml_array_t* toml_array_in(toml_table_t* tab, const char* key); +TOML_EXTERN toml_table_t* toml_table_in(toml_table_t* tab, const char* key); + +/* Return the array kind: 't'able, 'a'rray, 'v'alue */ +TOML_EXTERN char toml_array_kind(toml_array_t* arr); + +/* Deref array by index. Return the element at idx or 0 if out of range. */ +TOML_EXTERN const char* toml_raw_at(toml_array_t* arr, int idx); +TOML_EXTERN toml_array_t* toml_array_at(toml_array_t* arr, int idx); +TOML_EXTERN toml_table_t* toml_table_at(toml_array_t* arr, int idx); + + +/* Raw to String. Caller must call free(ret) after use. + * Return 0 on success, -1 otherwise. + */ +TOML_EXTERN int toml_rtos(const char* s, char** ret); + +/* Raw to Boolean. Return 0 on success, -1 otherwise. */ +TOML_EXTERN int toml_rtob(const char* s, int* ret); + +/* Raw to Integer. Return 0 on success, -1 otherwise. */ +TOML_EXTERN int toml_rtoi(const char* s, int64_t* ret); + +/* Raw to Double. Return 0 on success, -1 otherwise. */ +TOML_EXTERN int toml_rtod(const char* s, double* ret); + +/* Timestamp types. The year, month, day, hour, minute, second, z + * fields may be NULL if they are not relevant. + */ +typedef struct toml_timestamp_t toml_timestamp_t; +struct toml_timestamp_t { + struct { /* internal. do not use. */ + int year, month, day; + int hour, minute, second; + char z[10]; + } __buffer; + int *year, *month, *day; + int *hour, *minute, *second; + char* z; +}; + +/* Raw to Timestamp. Return 0 on success, -1 otherwise. */ +TOML_EXTERN int toml_rtots(const char* s, toml_timestamp_t* ret); + +/* misc */ +TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); +TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); + + +#endif /* TOML_H */ diff --git a/toml_cat.c b/toml_cat.c new file mode 100644 index 0000000..f1558a0 --- /dev/null +++ b/toml_cat.c @@ -0,0 +1,165 @@ +#ifdef NDEBUG +#under NDEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include "toml.h" + +typedef struct node_t node_t; +struct node_t { + const char* key; + toml_table_t* tab; +}; + +node_t stack[20]; +int stacktop = 0; + + +static void print_table_title(const char* arrname) +{ + int i; + printf("%s", arrname ? "[[" : "["); + for (i = 1; i < stacktop; i++) { + printf("%s", stack[i].key); + if (i + 1 < stacktop) + printf("."); + } + if (arrname) + printf(".%s]]\n", arrname); + else + printf("]\n"); +} + + +static void print_array_of_tables(toml_array_t* arr, const char* key); +static void print_array(toml_array_t* arr); + + +static void print_table(toml_table_t* curtab) +{ + int i; + const char* key; + const char* raw; + toml_array_t* arr; + toml_table_t* tab; + + + for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { + if (0 != (raw = toml_raw_in(curtab, key))) { + printf("%s = %s\n", key, raw); + } else if (0 != (arr = toml_array_in(curtab, key))) { + if (toml_array_typ(arr) == 't') { + print_array_of_tables(arr, key); + } + else { + printf("%s = [\n", key); + print_array(arr); + printf(" ]\n"); + } + } else if (0 != (tab = toml_table_in(curtab, key))) { + stack[stacktop].key = key; + stack[stacktop].tab = tab; + stacktop++; + print_table_title(0); + print_table(tab); + stacktop--; + } else { + abort(); + } + } +} + +static void print_array_of_tables(toml_array_t* arr, const char* key) +{ + int i; + toml_table_t* tab; + printf("\n"); + for (i = 0; 0 != (tab = toml_table_at(arr, i)); i++) { + print_table_title(key); + print_table(tab); + printf("\n"); + } +} + + +static void print_array(toml_array_t* curarr) +{ + toml_array_t* arr; + const char* raw; + toml_table_t* tab; + int i; + + switch (toml_array_typ(curarr)) { + + case 'v': + for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { + printf(" %d: %s,\n", i, raw); + } + break; + + case 'a': + for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) { + printf(" %d: \n", i); + print_array(arr); + } + break; + + case 't': + for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) { + print_table(tab); + } + printf("\n"); + break; + + default: + abort(); + } +} + + + +static void cat(FILE* fp) +{ + char errbuf[200]; + + toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); + if (!tab) { + fprintf(stderr, "ERROR: %s\n", errbuf); + return; + } + + stack[stacktop].tab = tab; + stack[stacktop].key = ""; + stacktop++; + print_table(tab); + stacktop--; + + toml_free(tab); +} + + +int main(int argc, const char* argv[]) +{ + int i; + if (argc == 1) { + cat(stdin); + } else { + for (i = 1; i < argc; i++) { + + FILE* fp = fopen(argv[i], "r"); + if (!fp) { + fprintf(stderr, "ERROR: cannot open %s: %s\n", + argv[i], strerror(errno)); + exit(1); + } + cat(fp); + fclose(fp); + } + } + return 0; +} diff --git a/toml_json.c b/toml_json.c new file mode 100644 index 0000000..8c77fa5 --- /dev/null +++ b/toml_json.c @@ -0,0 +1,183 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "toml.h" + + +static void print_escape_string(const char* s) +{ + for ( ; *s; s++) { + int ch = *s; + switch (ch) { + case '\b': printf("\\b"); break; + case '\t': printf("\\t"); break; + case '\n': printf("\\n"); break; + case '\f': printf("\\f"); break; + case '\r': printf("\\r"); break; + case '"': printf("\\\""); break; + case '\\': printf("\\\\"); break; + default: printf("%c", ch); break; + } + } +} + +static void print_raw(const char* s) +{ + char* sval; + int64_t ival; + int bval; + double dval; + toml_timestamp_t ts; + + if (0 == toml_rtos(s, &sval)) { + printf("{\"type\":\"string\",\"value\":\""); + print_escape_string(sval); + printf("\"}"); + free(sval); + } else if (0 == toml_rtoi(s, &ival)) { + printf("{\"type\":\"integer\",\"value\":\"%" PRId64 "\"}", ival); + } else if (0 == toml_rtob(s, &bval)) { + printf("{\"type\":\"bool\",\"value\":\"%s\"}", bval ? "true" : "false"); + } else if (0 == toml_rtod(s, &dval)) { + printf("{\"type\":\"float\",\"value\":\"%s\"}", s); + } else if (0 == toml_rtots(s, &ts)) { + if (ts.year && ts.hour) { + printf("{\"type\":\"datetime\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%s\"}", + *ts.year, *ts.month, *ts.day, *ts.hour, *ts.minute, *ts.second, + (ts.z ? ts.z : "")); + } else if (ts.year) { + printf("{\"type\":\"date\",\"value\":\"%04d-%02d-%02d\"}", + *ts.year, *ts.month, *ts.day); + } else if (ts.hour) { + printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d\"}", + *ts.hour, *ts.minute, *ts.second); + } + } else { + fprintf(stderr, "unknown type\n"); + exit(1); + } +} + + +static void print_array(toml_array_t* arr); +static void print_table(toml_table_t* curtab) +{ + int i; + const char* key; + const char* raw; + toml_array_t* arr; + toml_table_t* tab; + + + printf("{"); + for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { + + printf("%s\"%s\":", i > 0 ? "," : "", key); + + if (0 != (raw = toml_raw_in(curtab, key))) { + print_raw(raw); + } else if (0 != (arr = toml_array_in(curtab, key))) { + print_array(arr); + } else if (0 != (tab = toml_table_in(curtab, key))) { + print_table(tab); + } else { + abort(); + } + } + printf("}"); +} + +static void print_table_array(toml_array_t* curarr) +{ + int i; + toml_table_t* tab; + + printf("["); + for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) { + printf("%s", i > 0 ? "," : ""); + print_table(tab); + } + printf("]"); +} + +static void print_array(toml_array_t* curarr) +{ + toml_array_t* arr; + const char* raw; + int i; + + if (toml_array_kind(curarr) == 't') { + print_table_array(curarr); + return; + } + + printf("{\"type\":\"array\",\"value\":["); + switch (toml_array_kind(curarr)) { + + case 'v': + for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { + printf("%s", i > 0 ? "," : ""); + print_raw(raw); + } + break; + + case 'a': + for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) { + printf("%s", i > 0 ? "," : ""); + print_array(arr); + } + break; + + default: + break; + } + printf("]}"); +} + + + +static void cat(FILE* fp) +{ + char errbuf[200]; + + toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); + if (!tab) { + fprintf(stderr, "ERROR: %s\n", errbuf); + exit(1); + } + + print_table(tab); + printf("\n"); + + toml_free(tab); +} + + +int main(int argc, const char* argv[]) +{ + int i; + if (argc == 1) { + cat(stdin); + } else { + for (i = 1; i < argc; i++) { + + FILE* fp = fopen(argv[i], "r"); + if (!fp) { + fprintf(stderr, "ERROR: cannot open %s: %s\n", + argv[i], strerror(errno)); + exit(1); + } + cat(fp); + fclose(fp); + } + } + return 0; +} From a0b38a34eaa8fd0c88965cbc9abb73b913f844c0 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 18 Mar 2017 14:23:09 -0700 Subject: [PATCH 003/138] Add comment --- toml.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toml.h b/toml.h index 38d076e..2752b80 100644 --- a/toml.h +++ b/toml.h @@ -83,7 +83,8 @@ TOML_EXTERN int toml_rtoi(const char* s, int64_t* ret); TOML_EXTERN int toml_rtod(const char* s, double* ret); /* Timestamp types. The year, month, day, hour, minute, second, z - * fields may be NULL if they are not relevant. + * fields may be NULL if they are not relevant. e.g. In a DATE + * type, the hour, minute, second and z fields will be NULLs. */ typedef struct toml_timestamp_t toml_timestamp_t; struct toml_timestamp_t { From 287defadb188ea230dba6b3091da4f7421f154a8 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 16 Apr 2017 23:19:51 -0700 Subject: [PATCH 004/138] Add github link to license text --- LICENSE | 1 + toml.c | 3 ++- toml.h | 1 + toml_cat.c | 27 ++++++++++++++++++++++++++- toml_json.c | 24 ++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index e7fe790..a3292b1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2017 CK Tan +https://github.com/cktan/tomlc99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/toml.c b/toml.c index 6b602e1..8bf1720 100644 --- a/toml.c +++ b/toml.c @@ -1,7 +1,8 @@ /* MIT License -Copyright (c) 2017 CK Tan +Copyright (c) 2017 CK Tan +https://github.com/cktan/tomlc99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/toml.h b/toml.h index 2752b80..54c1c82 100644 --- a/toml.h +++ b/toml.h @@ -2,6 +2,7 @@ MIT License Copyright (c) 2017 CK Tan +https://github.com/cktan/tomlc99 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/toml_cat.c b/toml_cat.c index f1558a0..e4800cd 100644 --- a/toml_cat.c +++ b/toml_cat.c @@ -1,5 +1,30 @@ +/* +MIT License + +Copyright (c) 2017 CK Tan +https://github.com/cktan/tomlc99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + #ifdef NDEBUG -#under NDEBUG +#undef NDEBUG #endif #include diff --git a/toml_json.c b/toml_json.c index 8c77fa5..c15e663 100644 --- a/toml_json.c +++ b/toml_json.c @@ -1,3 +1,27 @@ +/* +MIT License + +Copyright (c) 2017 CK Tan +https://github.com/cktan/tomlc99 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ #ifdef NDEBUG #undef NDEBUG #endif From e6a6db8bdae9beb627137babfd22dfe38defbfc4 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 6 Aug 2017 16:02:12 -0700 Subject: [PATCH 005/138] Fix some warnings and provide strndup for WIN32 --- toml.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/toml.c b/toml.c index 8bf1720..231cf25 100644 --- a/toml.c +++ b/toml.c @@ -33,6 +33,19 @@ SOFTWARE. #include #include "toml.h" +#ifdef _WIN32 +char* strndup(const char* s, size_t n) +{ + size_t len = strnlen(s, n); + char* p = malloc(s, len+1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; +} +#endif + /** * Convert a char in utf8 into UCS, and store it in *ret. @@ -499,9 +512,9 @@ static char* normalize_key(context_t* ctx, token_t strtok) /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ const char* xp; for (xp = sp; xp != sq; xp++) { - int ch = *xp; - if (isalnum(ch)) continue; - if (ch == '_' || ch == '-') continue; + int k = *xp; + if (isalnum(k)) continue; + if (k == '_' || k == '-') continue; bad_key_error(ctx, lineno); } @@ -569,13 +582,13 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, /* make a new entry */ int n = tab->nkval; toml_keyval_t** base; - if (0 == (base = realloc(tab->kval, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_keyval_t**) realloc(tab->kval, (n+1) * sizeof(*base)))) { free(newkey); outofmemory(ctx, FLINE); } tab->kval = base; - if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + if (0 == (base[n] = (toml_keyval_t*) calloc(1, sizeof(*base[n])))) { free(newkey); outofmemory(ctx, FLINE); } @@ -613,13 +626,13 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, /* create a new table entry */ int n = tab->ntab; toml_table_t** base; - if (0 == (base = realloc(tab->tab, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_table_t**) realloc(tab->tab, (n+1) * sizeof(*base)))) { free(newkey); outofmemory(ctx, FLINE); } tab->tab = base; - if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { free(newkey); outofmemory(ctx, FLINE); } @@ -657,13 +670,13 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, /* make a new array entry */ int n = tab->narr; toml_array_t** base; - if (0 == (base = realloc(tab->arr, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_array_t**) realloc(tab->arr, (n+1) * sizeof(*base)))) { free(newkey); outofmemory(ctx, FLINE); } tab->arr = base; - if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + if (0 == (base[n] = (toml_array_t*) calloc(1, sizeof(*base[n])))) { free(newkey); outofmemory(ctx, FLINE); } @@ -681,12 +694,12 @@ static toml_array_t* create_array_in_array(context_t* ctx, { int n = parent->nelem; toml_array_t** base; - if (0 == (base = realloc(parent->u.arr, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_array_t**) realloc(parent->u.arr, (n+1) * sizeof(*base)))) { outofmemory(ctx, FLINE); } parent->u.arr = base; - if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + if (0 == (base[n] = (toml_array_t*) calloc(1, sizeof(*base[n])))) { outofmemory(ctx, FLINE); } @@ -700,12 +713,12 @@ static toml_table_t* create_table_in_array(context_t* ctx, { int n = parent->nelem; toml_table_t** base; - if (0 == (base = realloc(parent->u.tab, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_table_t**) realloc(parent->u.tab, (n+1) * sizeof(*base)))) { outofmemory(ctx, FLINE); } parent->u.tab = base; - if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { outofmemory(ctx, FLINE); } @@ -797,7 +810,7 @@ static void parse_array(context_t* ctx, toml_array_t* arr) } /* make a new value in array */ - char** tmp = realloc(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); + char** tmp = (char**) realloc(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); if (!tmp) outofmemory(ctx, FLINE); arr->u.val = tmp; if (! (val = strndup(val, vlen))) outofmemory(ctx, FLINE); @@ -994,11 +1007,11 @@ static void walk_tabpath(context_t* ctx) default: { /* Not found. Let's create an implicit table. */ int n = curtab->ntab; - toml_table_t** base = realloc(curtab->tab, (n+1) * sizeof(*base)); + toml_table_t** base = (toml_table_t**) realloc(curtab->tab, (n+1) * sizeof(*base)); if (0 == base) outofmemory(ctx, FLINE); curtab->tab = base; - if (0 == (base[n] = calloc(1, sizeof(*base[n])))) + if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) outofmemory(ctx, FLINE); if (0 == (base[n]->key = strdup(key))) From a0b45225e2614d1b7b9381cc15c2d92c01887df4 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 7 Aug 2017 14:47:59 -0700 Subject: [PATCH 006/138] Fixes as suggested by mytchel 1. A critical bug in toml_parse_file when the file is empty 2. Add toml_cat.c to makefile 3. Other misc fixes related to error handling --- Makefile | 4 +- toml.c | 303 ++++++++++++++++++++++++++++++++++++----------------- toml_cat.c | 4 +- 3 files changed, 213 insertions(+), 98 deletions(-) diff --git a/Makefile b/Makefile index 9dd3cf9..695291f 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS = -std=c99 -Wall -Wextra CFLAGS += -O2 -DNDEBUG #CFLAGS += -O0 -g -EXEC = toml_json +EXEC = toml_json toml_cat LIB = libtoml.a @@ -17,6 +17,8 @@ libtoml.a: toml.o toml_json: toml_json.c $(LIB) +toml_cat: toml_cat.c $(LIB) + prefix ?= /usr/local install: all diff --git a/toml.c b/toml.c index 231cf25..0e00a83 100644 --- a/toml.c +++ b/toml.c @@ -311,24 +311,33 @@ struct context_t { #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #define FLINE __FILE__ ":" TOSTRING(__LINE__) -static int outofmemory(context_t* ctx, const char* fline); + static tokentype_t next_token(context_t* ctx, int dotisspecial); -static int internal_error(context_t* ctx, const char* fline) +/* error routines. All these functions longjmp to ctx->jmp */ +static int e_outofmemory(context_t* ctx, const char* fline) +{ + snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); + longjmp(ctx->jmp, 1); + return -1; +} + + +static int e_internal_error(context_t* ctx, const char* fline) { snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); longjmp(ctx->jmp, 1); return -1; } -static int syntax_error(context_t* ctx, int lineno, const char* msg) +static int e_syntax_error(context_t* ctx, int lineno, const char* msg) { snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); longjmp(ctx->jmp, 1); return -1; } -static int bad_key_error(context_t* ctx, int lineno) +static int e_bad_key_error(context_t* ctx, int lineno) { snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); longjmp(ctx->jmp, 1); @@ -336,7 +345,7 @@ static int bad_key_error(context_t* ctx, int lineno) } /* -static int noimpl(context_t* ctx, const char* feature) +static int e_noimpl(context_t* ctx, const char* feature) { snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature); longjmp(ctx->jmp, 1); @@ -344,7 +353,7 @@ static int noimpl(context_t* ctx, const char* feature) } */ -static int key_exists_error(context_t* ctx, token_t keytok) +static int e_key_exists_error(context_t* ctx, token_t keytok) { char buf[100]; int i; @@ -491,7 +500,10 @@ static char* normalize_key(context_t* ctx, token_t strtok) if (ch == '\'') { /* for single quote, take it verbatim. */ - if (! (ret = strndup(sp, sq - sp))) outofmemory(ctx, FLINE); + if (! (ret = strndup(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } } else { /* for double quote, we need to normalize */ ret = normalize_string(sp, sq - sp, 0, ebuf, sizeof(ebuf)); @@ -504,7 +516,8 @@ static char* normalize_key(context_t* ctx, token_t strtok) /* newlines are not allowed in keys */ if (strchr(ret, '\n')) { free(ret); - bad_key_error(ctx, lineno); + e_bad_key_error(ctx, lineno); + return 0; /* not reached */ } return ret; } @@ -515,11 +528,15 @@ static char* normalize_key(context_t* ctx, token_t strtok) int k = *xp; if (isalnum(k)) continue; if (k == '_' || k == '-') continue; - bad_key_error(ctx, lineno); + e_bad_key_error(ctx, lineno); + return 0; /* not reached */ } /* dup and return it */ - if (! (ret = strndup(sp, sq - sp))) outofmemory(ctx, FLINE); + if (! (ret = strndup(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } return ret; } @@ -576,7 +593,8 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, toml_keyval_t* dest = 0; if (check_key(tab, newkey, 0, 0, 0)) { free(newkey); - key_exists_error(ctx, keytok); + e_key_exists_error(ctx, keytok); + return 0; /* not reached */ } /* make a new entry */ @@ -584,13 +602,15 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, toml_keyval_t** base; if (0 == (base = (toml_keyval_t**) realloc(tab->kval, (n+1) * sizeof(*base)))) { free(newkey); - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } tab->kval = base; if (0 == (base[n] = (toml_keyval_t*) calloc(1, sizeof(*base[n])))) { free(newkey); - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } dest = tab->kval[tab->nkval++]; @@ -620,7 +640,8 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, dest->implicit = 0; return dest; } - key_exists_error(ctx, keytok); + e_key_exists_error(ctx, keytok); + return 0; /* not reached */ } /* create a new table entry */ @@ -628,13 +649,15 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, toml_table_t** base; if (0 == (base = (toml_table_t**) realloc(tab->tab, (n+1) * sizeof(*base)))) { free(newkey); - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } tab->tab = base; if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { free(newkey); - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } dest = tab->tab[tab->ntab++]; @@ -664,7 +687,8 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, /* special case skip if exists? */ if (skip_if_exist) return dest; - key_exists_error(ctx, keytok); + e_key_exists_error(ctx, keytok); + return 0; /* not reached */ } /* make a new array entry */ @@ -672,13 +696,15 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, toml_array_t** base; if (0 == (base = (toml_array_t**) realloc(tab->arr, (n+1) * sizeof(*base)))) { free(newkey); - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } tab->arr = base; if (0 == (base[n] = (toml_array_t*) calloc(1, sizeof(*base[n])))) { free(newkey); - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } dest = tab->arr[tab->narr++]; @@ -695,12 +721,14 @@ static toml_array_t* create_array_in_array(context_t* ctx, int n = parent->nelem; toml_array_t** base; if (0 == (base = (toml_array_t**) realloc(parent->u.arr, (n+1) * sizeof(*base)))) { - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } parent->u.arr = base; if (0 == (base[n] = (toml_array_t*) calloc(1, sizeof(*base[n])))) { - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } return parent->u.arr[parent->nelem++]; @@ -714,12 +742,14 @@ static toml_table_t* create_table_in_array(context_t* ctx, int n = parent->nelem; toml_table_t** base; if (0 == (base = (toml_table_t**) realloc(parent->u.tab, (n+1) * sizeof(*base)))) { - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } parent->u.tab = base; if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { - outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ } return parent->u.tab[parent->nelem++]; @@ -728,7 +758,7 @@ static toml_table_t* create_table_in_array(context_t* ctx, #define SKIP_NEWLINES(ctx) while (ctx->tok.tok == NEWLINE) next_token(ctx, 0) #define EAT_TOKEN(ctx, typ) \ - if ((ctx)->tok.tok != typ) internal_error(ctx, FLINE); else next_token(ctx, 0) + if ((ctx)->tok.tok != typ) e_internal_error(ctx, FLINE); else next_token(ctx, 0) static void parse_keyval(context_t* ctx, toml_table_t* tab); @@ -747,11 +777,11 @@ static void parse_table(context_t* ctx, toml_table_t* tab) /* until } */ if (ctx->tok.tok == RBRACE) break; - switch (ctx->tok.tok) { - case STRING: parse_keyval(ctx, tab); break; - default: syntax_error(ctx, ctx->tok.lineno, "syntax error"); + if (ctx->tok.tok != STRING) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ } - + parse_keyval(ctx, tab); SKIP_NEWLINES(ctx); /* on comma, continue to scan for next keyval */ @@ -762,8 +792,10 @@ static void parse_table(context_t* ctx, toml_table_t* tab) break; } - if (ctx->tok.tok != RBRACE) - syntax_error(ctx, ctx->tok.lineno, "syntax error"); + if (ctx->tok.tok != RBRACE) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } EAT_TOKEN(ctx, RBRACE); } @@ -805,22 +837,31 @@ static void parse_array(context_t* ctx, toml_array_t* arr) if (arr->kind == 0) arr->kind = 'v'; /* check array kind */ if (arr->kind != 'v') { - syntax_error(ctx, ctx->tok.lineno, - "a string array can only contain strings"); + e_syntax_error(ctx, ctx->tok.lineno, + "a string array can only contain strings"); + return; /* not reached */ } /* make a new value in array */ char** tmp = (char**) realloc(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); - if (!tmp) outofmemory(ctx, FLINE); + if (!tmp) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } arr->u.val = tmp; - if (! (val = strndup(val, vlen))) outofmemory(ctx, FLINE); + if (! (val = strndup(val, vlen))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } arr->u.val[arr->nelem++] = val; /* set array type if this is the first entry, or check that the types matched. */ if (arr->nelem == 1) arr->type = valtype(arr->u.val[0]); - else if (arr->type != valtype(val)) - syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + else if (arr->type != valtype(val)) { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + return; /* not reached */ + } EAT_TOKEN(ctx, STRING); break; @@ -832,7 +873,8 @@ static void parse_array(context_t* ctx, toml_array_t* arr) if (arr->kind == 0) arr->kind = 'a'; /* check array kind */ if (arr->kind != 'a') { - syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + return; /* not reached */ } parse_array(ctx, create_array_in_array(ctx, arr)); break; @@ -844,14 +886,16 @@ static void parse_array(context_t* ctx, toml_array_t* arr) if (arr->kind == 0) arr->kind = 't'; /* check array kind */ if (arr->kind != 't') { - syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + return; /* not reached */ } parse_table(ctx, create_table_in_array(ctx, arr)); break; } default: - syntax_error(ctx, ctx->tok.lineno, "syntax error"); + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ } SKIP_NEWLINES(ctx); @@ -864,8 +908,10 @@ static void parse_array(context_t* ctx, toml_array_t* arr) break; } - if (ctx->tok.tok != RBRACKET) - syntax_error(ctx, ctx->tok.lineno, "syntax error"); + if (ctx->tok.tok != RBRACKET) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } EAT_TOKEN(ctx, RBRACKET); } @@ -879,14 +925,18 @@ static void parse_array(context_t* ctx, toml_array_t* arr) */ static void parse_keyval(context_t* ctx, toml_table_t* tab) { - if (ctx->tok.tok != STRING) - internal_error(ctx, FLINE); + if (ctx->tok.tok != STRING) { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } token_t key = ctx->tok; EAT_TOKEN(ctx, STRING); - if (ctx->tok.tok != EQUAL) - syntax_error(ctx, ctx->tok.lineno, "missing ="); + if (ctx->tok.tok != EQUAL) { + e_syntax_error(ctx, ctx->tok.lineno, "missing ="); + return; /* not reached */ + } EAT_TOKEN(ctx, EQUAL); @@ -897,7 +947,10 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab) token_t val = ctx->tok; assert(keyval->val == 0); keyval->val = strndup(val.ptr, val.len); - if (! keyval->val) outofmemory(ctx, FLINE); + if (! keyval->val) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } EAT_TOKEN(ctx, STRING); @@ -919,7 +972,8 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab) } default: - syntax_error(ctx, ctx->tok.lineno, "syntax error"); + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ } } @@ -948,11 +1002,15 @@ static void fill_tabpath(context_t* ctx) ctx->tpath.top = 0; for (;;) { - if (ctx->tpath.top >= 10) - syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); + if (ctx->tpath.top >= 10) { + e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); + return; /* not reached */ + } - if (ctx->tok.tok != STRING) - syntax_error(ctx, lineno, "invalid or missing key"); + if (ctx->tok.tok != STRING) { + e_syntax_error(ctx, lineno, "invalid or missing key"); + return; /* not reached */ + } ctx->tpath.tok[ctx->tpath.top] = ctx->tok; ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); @@ -962,14 +1020,17 @@ static void fill_tabpath(context_t* ctx) if (ctx->tok.tok == RBRACKET) break; - if (ctx->tok.tok != DOT) - syntax_error(ctx, lineno, "invalid key"); + if (ctx->tok.tok != DOT) { + e_syntax_error(ctx, lineno, "invalid key"); + return; /* not reached */ + } next_token(ctx, 1); } if (ctx->tpath.top <= 0) { - syntax_error(ctx, lineno, "empty table selector"); + e_syntax_error(ctx, lineno, "empty table selector"); + return; /* not reached */ } } @@ -995,27 +1056,40 @@ static void walk_tabpath(context_t* ctx) case 'a': /* found an array. nexttab is the last table in the array. */ - if (nextarr->kind != 't') internal_error(ctx, FLINE); - if (nextarr->nelem == 0) internal_error(ctx, FLINE); + if (nextarr->kind != 't') { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } + if (nextarr->nelem == 0) { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } nexttab = nextarr->u.tab[nextarr->nelem-1]; break; case 'v': - key_exists_error(ctx, ctx->tpath.tok[i]); - break; + e_key_exists_error(ctx, ctx->tpath.tok[i]); + return; /* not reached */ default: { /* Not found. Let's create an implicit table. */ int n = curtab->ntab; toml_table_t** base = (toml_table_t**) realloc(curtab->tab, (n+1) * sizeof(*base)); - if (0 == base) outofmemory(ctx, FLINE); + if (0 == base) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } curtab->tab = base; - if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) - outofmemory(ctx, FLINE); + if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } - if (0 == (base[n]->key = strdup(key))) - outofmemory(ctx, FLINE); + if (0 == (base[n]->key = strdup(key))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } nexttab = curtab->tab[curtab->ntab++]; @@ -1038,7 +1112,10 @@ static void walk_tabpath(context_t* ctx) static void parse_select(context_t* ctx) { int count_lbracket = 0; - if (ctx->tok.tok != LBRACKET) internal_error(ctx, FLINE); + if (ctx->tok.tok != LBRACKET) { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } count_lbracket++; next_token(ctx, 1 /* DOT IS SPECIAL */); if (ctx->tok.tok == LBRACKET) { @@ -1064,21 +1141,31 @@ static void parse_select(context_t* ctx) toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z, 1 /*skip_if_exist*/); if (arr->kind == 0) arr->kind = 't'; - if (arr->kind != 't') syntax_error(ctx, z.lineno, "array mismatch"); + if (arr->kind != 't') { + e_syntax_error(ctx, z.lineno, "array mismatch"); + return; /* not reached */ + } /* add to z[] */ toml_table_t* dest; { int n = arr->nelem; toml_table_t** base = realloc(arr->u.tab, (n+1) * sizeof(*base)); - if (0 == base) outofmemory(ctx, FLINE); + if (0 == base) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } arr->u.tab = base; - if (0 == (base[n] = calloc(1, sizeof(*base[n])))) - outofmemory(ctx, FLINE); + if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } - if (0 == (base[n]->key = strdup("__anon__"))) - outofmemory(ctx, FLINE); + if (0 == (base[n]->key = strdup("__anon__"))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } dest = arr->u.tab[arr->nelem++]; } @@ -1086,14 +1173,23 @@ static void parse_select(context_t* ctx) ctx->curtab = dest; } - if (ctx->tok.tok != RBRACKET) syntax_error(ctx, ctx->tok.lineno, "expects ]"); + if (ctx->tok.tok != RBRACKET) { + e_syntax_error(ctx, ctx->tok.lineno, "expects ]"); + return; /* not reached */ + } EAT_TOKEN(ctx, RBRACKET); if (count_lbracket == 2) { - if (ctx->tok.tok != RBRACKET) syntax_error(ctx, ctx->tok.lineno, "expects ]]"); + if (ctx->tok.tok != RBRACKET) { + e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); + return; /* not reached */ + } EAT_TOKEN(ctx, RBRACKET); } - if (ctx->tok.tok != NEWLINE) syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); + if (ctx->tok.tok != NEWLINE) { + e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); + return; /* not reached */ + } } @@ -1124,8 +1220,9 @@ toml_table_t* toml_parse(char* conf, // make a root table if (0 == (ctx.root = calloc(1, sizeof(*ctx.root)))) { - outofmemory(&ctx, FLINE); - return 0; + /* do not call outofmemory() here... setjmp not done yet */ + snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE); + return 0; } // set root as default table @@ -1149,8 +1246,10 @@ toml_table_t* toml_parse(char* conf, case STRING: parse_keyval(&ctx, ctx.curtab); - if (ctx.tok.tok != NEWLINE) - syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); + if (ctx.tok.tok != NEWLINE) { + e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); + return 0; /* not reached */ + } EAT_TOKEN(&ctx, NEWLINE); break; @@ -1179,9 +1278,16 @@ toml_table_t* toml_parse_file(FILE* fp, char* buf = 0; int off = 0; + /* prime the buf[] */ + bufsz = 1000; + if (! (buf = malloc(bufsz + 1))) { + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + /* read from fp into buf */ while (! feof(fp)) { - bufsz += 100; + bufsz += 1000; /* Allocate 1 extra byte because we will tag on a NUL */ char* x = realloc(buf, bufsz + 1); @@ -1301,8 +1407,10 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe char* orig = p; if (0 == strncmp(p, "'''", 3)) { p = strstr(p + 3, "'''"); - if (0 == p) - syntax_error(ctx, lineno, "unterminated triple-s-quote"); + if (0 == p) { + e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); + return 0; /* not reached */ + } return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); } @@ -1318,26 +1426,32 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe if (*p == 'u') { hexreq = 4; continue; } if (*p == 'U') { hexreq = 8; continue; } if (*p == '\n') continue; /* allow for line ending backslash */ - syntax_error(ctx, lineno, "bad escape char"); + e_syntax_error(ctx, lineno, "bad escape char"); + return 0; /* not reached */ } if (hexreq) { hexreq--; if (strchr("0123456789ABCDEF", *p)) continue; - syntax_error(ctx, lineno, "expect hex char"); + e_syntax_error(ctx, lineno, "expect hex char"); + return 0; /* not reached */ } if (*p == '\\') { escape = 1; continue; } qcnt = (*p == '"') ? qcnt + 1 : 0; } - if (qcnt != 3) - syntax_error(ctx, lineno, "unterminated triple-quote"); + if (qcnt != 3) { + e_syntax_error(ctx, lineno, "unterminated triple-quote"); + return 0; /* not reached */ + } return ret_token(ctx, STRING, lineno, orig, p - orig); } if ('\'' == *p) { for (p++; *p && *p != '\n' && *p != '\''; p++); - if (*p != '\'') - syntax_error(ctx, lineno, "unterminated s-quote"); + if (*p != '\'') { + e_syntax_error(ctx, lineno, "unterminated s-quote"); + return 0; /* not reached */ + } return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); } @@ -1351,19 +1465,23 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe if (strchr("btnfr\"\\", *p)) continue; if (*p == 'u') { hexreq = 4; continue; } if (*p == 'U') { hexreq = 8; continue; } - syntax_error(ctx, lineno, "bad escape char"); + e_syntax_error(ctx, lineno, "bad escape char"); + return 0; /* not reached */ } if (hexreq) { hexreq--; if (strchr("0123456789ABCDEF", *p)) continue; - syntax_error(ctx, lineno, "expect hex char"); + e_syntax_error(ctx, lineno, "expect hex char"); + return 0; /* not reached */ } if (*p == '\\') { escape = 1; continue; } if (*p == '\n') break; if (*p == '"') break; } - if (*p != '"') - syntax_error(ctx, lineno, "unterminated quote"); + if (*p != '"') { + e_syntax_error(ctx, lineno, "unterminated quote"); + return 0; /* not reached */ + } return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); } @@ -1425,11 +1543,6 @@ static tokentype_t next_token(context_t* ctx, int dotisspecial) return ret_eof(ctx, lineno); } -static int outofmemory(context_t* ctx, const char* fline) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); - return -1; -} const char* toml_key_in(toml_table_t* tab, int keyidx) { diff --git a/toml_cat.c b/toml_cat.c index e4800cd..73eeab5 100644 --- a/toml_cat.c +++ b/toml_cat.c @@ -78,7 +78,7 @@ static void print_table(toml_table_t* curtab) if (0 != (raw = toml_raw_in(curtab, key))) { printf("%s = %s\n", key, raw); } else if (0 != (arr = toml_array_in(curtab, key))) { - if (toml_array_typ(arr) == 't') { + if (toml_array_kind(arr) == 't') { print_array_of_tables(arr, key); } else { @@ -119,7 +119,7 @@ static void print_array(toml_array_t* curarr) toml_table_t* tab; int i; - switch (toml_array_typ(curarr)) { + switch (toml_array_kind(curarr)) { case 'v': for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { From edc6a132467ac156a5eb9964bd90e805544a3f0e Mon Sep 17 00:00:00 2001 From: CK Tan Date: Fri, 17 Nov 2017 13:52:59 -0800 Subject: [PATCH 007/138] add readme --- test/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 test/README.md diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..bdf6a30 --- /dev/null +++ b/test/README.md @@ -0,0 +1,9 @@ +How to run the tests +=== + +``` +% bash build.sh +% bash run.sh +77 passed, 0 failed +``` + From 01ecb88d1399aedf0f326a2f99bd8d03f7f90585 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 18 Nov 2017 11:57:45 -0800 Subject: [PATCH 008/138] Fix issue #3 --- toml.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/toml.c b/toml.c index 0e00a83..669d6d2 100644 --- a/toml.c +++ b/toml.c @@ -1140,6 +1140,10 @@ static void parse_select(context_t* ctx) /* [[x.y.z]] -> create z = [] in x.y */ toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z, 1 /*skip_if_exist*/); + if (!arr) { + e_syntax_error(ctx, z.lineno, "key exists"); + return; + } if (arr->kind == 0) arr->kind = 't'; if (arr->kind != 't') { e_syntax_error(ctx, z.lineno, "array mismatch"); From 79b40abd946f8571010fe9d3b1a138d164fd407d Mon Sep 17 00:00:00 2001 From: bamchoh Date: Thu, 4 Jan 2018 18:56:40 +0900 Subject: [PATCH 009/138] string literal needs double quatation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bcbec94..999f035 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ parses this config file: ``` [server] - host = www.example.com +    host = "www.example.com" port = 80 ``` From 624013252b4c40eb9d0938ebd6bf604902a577f5 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 4 Jan 2018 03:18:08 -0800 Subject: [PATCH 010/138] Small fix for WIN32 --- toml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml.c b/toml.c index 669d6d2..e4b5719 100644 --- a/toml.c +++ b/toml.c @@ -37,7 +37,7 @@ SOFTWARE. char* strndup(const char* s, size_t n) { size_t len = strnlen(s, n); - char* p = malloc(s, len+1); + char* p = malloc(len+1); if (p) { memcpy(p, s, len); p[len] = 0; From 56c42b7aedb3dd17cd2c88db79c41b23550d25b1 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Fri, 8 Jun 2018 14:41:44 -0700 Subject: [PATCH 011/138] Fix #7: toml_utf8_to_ucs() returns incorrect results --- toml.c | 16 +++++++------ unittest/Makefile | 11 +++++++++ unittest/t1.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 unittest/Makefile create mode 100644 unittest/t1.c diff --git a/toml.c b/toml.c index e4b5719..fbb1663 100644 --- a/toml.c +++ b/toml.c @@ -71,9 +71,11 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) if (0x6 == (i >> 5)) { if (len < 2) return -1; v = i & 0x1f; - i = *(++buf); - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); + for (int j = 0; j < 1; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } return *ret = v, (const char*) buf - orig; } @@ -84,7 +86,7 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) if (len < 3) return -1; v = i & 0x0F; for (int j = 0; j < 2; j++) { - i = *(++buf); + i = *buf++; if (0x2 != (i >> 6)) return -1; v = (v << 6) | (i & 0x3f); } @@ -98,7 +100,7 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) if (len < 4) return -1; v = i & 0x07; for (int j = 0; j < 3; j++) { - i = *(++buf); + i = *buf++; if (0x2 != (i >> 6)) return -1; v = (v << 6) | (i & 0x3f); } @@ -112,7 +114,7 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) if (len < 5) return -1; v = i & 0x03; for (int j = 0; j < 4; j++) { - i = *(++buf); + i = *buf++; if (0x2 != (i >> 6)) return -1; v = (v << 6) | (i & 0x3f); } @@ -126,7 +128,7 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) if (len < 6) return -1; v = i & 0x01; for (int j = 0; j < 5; j++) { - i = *(++buf); + i = *buf++; if (0x2 != (i >> 6)) return -1; v = (v << 6) | (i & 0x3f); } diff --git a/unittest/Makefile b/unittest/Makefile new file mode 100644 index 0000000..0fb102f --- /dev/null +++ b/unittest/Makefile @@ -0,0 +1,11 @@ +CFLAGS = -g -I.. + +TESTS = t1 + +all: $(TESTS) + +t1: t1.c ../toml.c + +clean: + rm -f $(TESTS) + diff --git a/unittest/t1.c b/unittest/t1.c new file mode 100644 index 0000000..065ba0a --- /dev/null +++ b/unittest/t1.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include "../toml.h" + + + +int main(int argc, const char* argv[]) +{ + char xxbuf[6], buf[6]; + int64_t xxcode, code; + int xxsize; + + + xxsize = 2, xxcode = 0x80; memcpy(xxbuf, "\xc2\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 2, xxcode = 0x7ff; memcpy(xxbuf, "\xdf\xbf", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 3, xxcode = 0x800; memcpy(xxbuf, "\xe0\xa0\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 3, xxcode = 0xfffd; memcpy(xxbuf, "\xef\xbf\xbd", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 4, xxcode = 0x10000; memcpy(xxbuf, "\xf0\x90\x80\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 4, xxcode = 0x1fffff; memcpy(xxbuf, "\xf7\xbf\xbf\xbf", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 5, xxcode = 0x200000; memcpy(xxbuf, "\xf8\x88\x80\x80\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 5, xxcode = 0x3ffffff; memcpy(xxbuf, "\xfb\xbf\xbf\xbf\xbf", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 6, xxcode = 0x4000000; memcpy(xxbuf, "\xfc\x84\x80\x80\x80\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 6, xxcode = 0x7fffffff; memcpy(xxbuf, "\xfd\xbf\xbf\xbf\xbf\xbf", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + return 0; +} From 55334019ac466ed1c456e0c184efaceb6c021e6d Mon Sep 17 00:00:00 2001 From: Iain Anderson Date: Wed, 4 Jul 2018 14:30:45 +0100 Subject: [PATCH 012/138] Fix toml_cat abort on empty array --- toml_cat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/toml_cat.c b/toml_cat.c index 73eeab5..186ebf4 100644 --- a/toml_cat.c +++ b/toml_cat.c @@ -141,6 +141,9 @@ static void print_array(toml_array_t* curarr) printf("\n"); break; + case '\0': + break; + default: abort(); } From 88eacb3fe0807871cb7d7c8d61ca2043788c7fbc Mon Sep 17 00:00:00 2001 From: Stanley Pinchak Date: Tue, 8 Jan 2019 13:04:28 -0600 Subject: [PATCH 013/138] Add helper functions for tables New functions for read only access to internal nkval, narr and ntab members of toml_table_t structs. --- toml.c | 14 ++++++++++++++ toml.h | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/toml.c b/toml.c index fbb1663..fde2122 100644 --- a/toml.c +++ b/toml.c @@ -1610,6 +1610,20 @@ char toml_array_kind(toml_array_t* arr) } +int toml_table_nkval(toml_table_t* tab) +{ + return tab->nkval; +} + +int toml_table_narr(toml_table_t* tab) +{ + return tab->narr; +} + +int toml_table_ntab(toml_table_t* tab) +{ + return tab->ntab; +} toml_array_t* toml_array_at(toml_array_t* arr, int idx) { diff --git a/toml.h b/toml.h index 54c1c82..58c3194 100644 --- a/toml.h +++ b/toml.h @@ -63,6 +63,15 @@ TOML_EXTERN toml_table_t* toml_table_in(toml_table_t* tab, const char* key); /* Return the array kind: 't'able, 'a'rray, 'v'alue */ TOML_EXTERN char toml_array_kind(toml_array_t* arr); +/* Return the number of key-values in a table */ +TOML_EXTERN int toml_table_nkval(toml_table_t* tab); + +/* Return the number of arrays in a table */ +TOML_EXTERN int toml_table_narr(toml_table_t* tab); + +/* Return the number of sub-tables in a table */ +TOML_EXTERN int toml_table_ntab(toml_table_t* tab); + /* Deref array by index. Return the element at idx or 0 if out of range. */ TOML_EXTERN const char* toml_raw_at(toml_array_t* arr, int idx); TOML_EXTERN toml_array_t* toml_array_at(toml_array_t* arr, int idx); From b53c016877c515357179e2b78e8cb86607852197 Mon Sep 17 00:00:00 2001 From: Stanley Pinchak Date: Tue, 8 Jan 2019 13:12:40 -0600 Subject: [PATCH 014/138] Add helper function for arrays New function for read only access to the internal nelem member of toml_array_t structs --- toml.c | 5 +++++ toml.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/toml.c b/toml.c index fde2122..24f4f69 100644 --- a/toml.c +++ b/toml.c @@ -1610,6 +1610,11 @@ char toml_array_kind(toml_array_t* arr) } +int toml_array_nelem(toml_array_t* arr) +{ + return arr->nelem; +} + int toml_table_nkval(toml_table_t* tab) { return tab->nkval; diff --git a/toml.h b/toml.h index 58c3194..9d33397 100644 --- a/toml.h +++ b/toml.h @@ -63,6 +63,9 @@ TOML_EXTERN toml_table_t* toml_table_in(toml_table_t* tab, const char* key); /* Return the array kind: 't'able, 'a'rray, 'v'alue */ TOML_EXTERN char toml_array_kind(toml_array_t* arr); +/* Return the number of elements in the array */ +TOML_EXTERN int toml_array_nelem(toml_array_t* arr); + /* Return the number of key-values in a table */ TOML_EXTERN int toml_table_nkval(toml_table_t* tab); From 3fed0ab4553ba6e66a192f7c4032c76770d5c283 Mon Sep 17 00:00:00 2001 From: Stanley Pinchak Date: Tue, 8 Jan 2019 13:15:59 -0600 Subject: [PATCH 015/138] Add helper functions to access key New functions for read only access to the key of toml_array_t and toml_table_t structs --- toml.c | 10 ++++++++++ toml.h | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/toml.c b/toml.c index 24f4f69..85d713d 100644 --- a/toml.c +++ b/toml.c @@ -1615,6 +1615,11 @@ int toml_array_nelem(toml_array_t* arr) return arr->nelem; } +const char* toml_array_key(toml_array_t* arr) +{ + return arr ? arr->key : (const char*) NULL; +} + int toml_table_nkval(toml_table_t* tab) { return tab->nkval; @@ -1630,6 +1635,11 @@ int toml_table_ntab(toml_table_t* tab) return tab->ntab; } +const char* toml_table_key(toml_table_t* tab) +{ + return tab ? tab->key : (const char*) NULL; +} + toml_array_t* toml_array_at(toml_array_t* arr, int idx) { if (arr->kind != 'a') diff --git a/toml.h b/toml.h index 9d33397..94469c7 100644 --- a/toml.h +++ b/toml.h @@ -66,6 +66,9 @@ TOML_EXTERN char toml_array_kind(toml_array_t* arr); /* Return the number of elements in the array */ TOML_EXTERN int toml_array_nelem(toml_array_t* arr); +/* Return the key of an array */ +TOML_EXTERN const char* toml_array_key(toml_array_t* arr); + /* Return the number of key-values in a table */ TOML_EXTERN int toml_table_nkval(toml_table_t* tab); @@ -75,6 +78,9 @@ TOML_EXTERN int toml_table_narr(toml_table_t* tab); /* Return the number of sub-tables in a table */ TOML_EXTERN int toml_table_ntab(toml_table_t* tab); +/* Return the key of a table*/ +TOML_EXTERN const char* toml_table_key(toml_table_t* tab); + /* Deref array by index. Return the element at idx or 0 if out of range. */ TOML_EXTERN const char* toml_raw_at(toml_array_t* arr, int idx); TOML_EXTERN toml_array_t* toml_array_at(toml_array_t* arr, int idx); From 43f7a52064cd7a307b681e9145c454c07b943804 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 16 Feb 2019 17:37:59 -0800 Subject: [PATCH 016/138] Fix #14 and #13 --- toml.c | 1380 +++++++++++++++++++++++++-------------------------- toml.h | 19 +- toml_json.c | 2 - 3 files changed, 702 insertions(+), 699 deletions(-) diff --git a/toml.c b/toml.c index 85d713d..11760c0 100644 --- a/toml.c +++ b/toml.c @@ -39,8 +39,8 @@ char* strndup(const char* s, size_t n) size_t len = strnlen(s, n); char* p = malloc(len+1); if (p) { - memcpy(p, s, len); - p[len] = 0; + memcpy(p, s, len); + p[len] = 0; } return p; } @@ -61,78 +61,78 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) 0xxxxxxx */ if (0 == (i >> 7)) { - if (len < 1) return -1; - v = i; - return *ret = v, 1; + if (len < 1) return -1; + v = i; + return *ret = v, 1; } /* 0x00000080 - 0x000007FF: 110xxxxx 10xxxxxx */ if (0x6 == (i >> 5)) { - if (len < 2) return -1; - v = i & 0x1f; + if (len < 2) return -1; + v = i & 0x1f; for (int j = 0; j < 1; j++) { i = *buf++; if (0x2 != (i >> 6)) return -1; v = (v << 6) | (i & 0x3f); } - return *ret = v, (const char*) buf - orig; + return *ret = v, (const char*) buf - orig; } /* 0x00000800 - 0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx */ if (0xE == (i >> 4)) { - if (len < 3) return -1; - v = i & 0x0F; - for (int j = 0; j < 2; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; + if (len < 3) return -1; + v = i & 0x0F; + for (int j = 0; j < 2; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; } /* 0x00010000 - 0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (0x1E == (i >> 3)) { - if (len < 4) return -1; - v = i & 0x07; - for (int j = 0; j < 3; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; + if (len < 4) return -1; + v = i & 0x07; + for (int j = 0; j < 3; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; } /* 0x00200000 - 0x03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (0x3E == (i >> 2)) { - if (len < 5) return -1; - v = i & 0x03; - for (int j = 0; j < 4; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; + if (len < 5) return -1; + v = i & 0x03; + for (int j = 0; j < 4; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; } /* 0x04000000 - 0x7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (0x7e == (i >> 1)) { - if (len < 6) return -1; - v = i & 0x01; - for (int j = 0; j < 5; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; + if (len < 6) return -1; + v = i & 0x01; + for (int j = 0; j < 5; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; } return -1; } @@ -158,63 +158,63 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) */ if (code < 0) return -1; if (code <= 0x7F) { - buf[0] = (unsigned char) code; - return 1; + buf[0] = (unsigned char) code; + return 1; } /* 0x00000080 - 0x000007FF: 110xxxxx 10xxxxxx */ if (code <= 0x000007FF) { - buf[0] = 0xc0 | (code >> 6); - buf[1] = 0x80 | (code & 0x3f); - return 2; + buf[0] = 0xc0 | (code >> 6); + buf[1] = 0x80 | (code & 0x3f); + return 2; } /* 0x00000800 - 0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx */ if (code <= 0x0000FFFF) { - buf[0] = 0xe0 | (code >> 12); - buf[1] = 0x80 | ((code >> 6) & 0x3f); - buf[2] = 0x80 | (code & 0x3f); - return 3; + buf[0] = 0xe0 | (code >> 12); + buf[1] = 0x80 | ((code >> 6) & 0x3f); + buf[2] = 0x80 | (code & 0x3f); + return 3; } /* 0x00010000 - 0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (code <= 0x001FFFFF) { - buf[0] = 0xf0 | (code >> 18); - buf[1] = 0x80 | ((code >> 12) & 0x3f); - buf[2] = 0x80 | ((code >> 6) & 0x3f); - buf[3] = 0x80 | (code & 0x3f); - return 4; + buf[0] = 0xf0 | (code >> 18); + buf[1] = 0x80 | ((code >> 12) & 0x3f); + buf[2] = 0x80 | ((code >> 6) & 0x3f); + buf[3] = 0x80 | (code & 0x3f); + return 4; } /* 0x00200000 - 0x03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (code <= 0x03FFFFFF) { - buf[0] = 0xf8 | (code >> 24); - buf[1] = 0x80 | ((code >> 18) & 0x3f); - buf[2] = 0x80 | ((code >> 12) & 0x3f); - buf[3] = 0x80 | ((code >> 6) & 0x3f); - buf[4] = 0x80 | (code & 0x3f); - return 5; + buf[0] = 0xf8 | (code >> 24); + buf[1] = 0x80 | ((code >> 18) & 0x3f); + buf[2] = 0x80 | ((code >> 12) & 0x3f); + buf[3] = 0x80 | ((code >> 6) & 0x3f); + buf[4] = 0x80 | (code & 0x3f); + return 5; } /* 0x04000000 - 0x7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (code <= 0x7FFFFFFF) { - buf[0] = 0xfc | (code >> 30); - buf[1] = 0x80 | ((code >> 24) & 0x3f); - buf[2] = 0x80 | ((code >> 18) & 0x3f); - buf[3] = 0x80 | ((code >> 12) & 0x3f); - buf[4] = 0x80 | ((code >> 6) & 0x3f); - buf[5] = 0x80 | (code & 0x3f); - return 6; + buf[0] = 0xfc | (code >> 30); + buf[1] = 0x80 | ((code >> 24) & 0x3f); + buf[2] = 0x80 | ((code >> 18) & 0x3f); + buf[3] = 0x80 | ((code >> 12) & 0x3f); + buf[4] = 0x80 | ((code >> 6) & 0x3f); + buf[5] = 0x80 | (code & 0x3f); + return 6; } return -1; @@ -226,28 +226,28 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) */ typedef struct toml_keyval_t toml_keyval_t; struct toml_keyval_t { - const char* key; /* key to this value */ - const char* val; /* the raw value */ + const char* key; /* key to this value */ + const char* val; /* the raw value */ }; struct toml_array_t { - const char* key; /* key to this array */ + const char* key; /* key to this array */ int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */ int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ - int nelem; /* number of elements */ + int nelem; /* number of elements */ union { - char** val; - toml_array_t** arr; - toml_table_t** tab; + char** val; + toml_array_t** arr; + toml_table_t** tab; } u; }; struct toml_table_t { - const char* key; /* key to this table */ - int implicit; /* table was created implicitly */ + const char* key; /* key to this table */ + int implicit; /* table was created implicitly */ /* key-values in the table */ int nkval; @@ -303,9 +303,9 @@ struct context_t { toml_table_t* curtab; struct { - int top; - char* key[10]; - token_t tok[10]; + int top; + char* key[10]; + token_t tok[10]; } tpath; }; @@ -360,12 +360,12 @@ static int e_key_exists_error(context_t* ctx, token_t keytok) char buf[100]; int i; for (i = 0; i < keytok.len && i < (int)sizeof(buf) - 1; i++) { - buf[i] = keytok.ptr[i]; + buf[i] = keytok.ptr[i]; } buf[i] = 0; snprintf(ctx->errbuf, ctx->errbufsz, - "line %d: key %s exists", keytok.lineno, buf); + "line %d: key %s exists", keytok.lineno, buf); longjmp(ctx->jmp, 1); return -1; } @@ -377,103 +377,103 @@ static int e_key_exists_error(context_t* ctx, token_t keytok) * Returns NULL if error with errmsg in errbuf. */ static char* normalize_string(const char* src, int srclen, - int kill_line_ending_backslash, - char* errbuf, int errbufsz) + int kill_line_ending_backslash, + char* errbuf, int errbufsz) { - char* dst = 0; /* will write to dst[] and return it */ - int max = 0; /* max size of dst[] */ - int off = 0; /* cur offset in dst[] */ + char* dst = 0; /* will write to dst[] and return it */ + int max = 0; /* max size of dst[] */ + int off = 0; /* cur offset in dst[] */ const char* sp = src; const char* sq = src + srclen; int ch; /* scan forward on src */ for (;;) { - if (off >= max - 10) { /* have some slack for misc stuff */ - char* x = realloc(dst, max += 100); - if (!x) { - xfree(dst); - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - dst = x; - } - - /* finished? */ - if (sp >= sq) break; - - ch = *sp++; - if (ch != '\\') { - // a plain copy suffice - dst[off++] = ch; - continue; - } + if (off >= max - 10) { /* have some slack for misc stuff */ + char* x = realloc(dst, max += 100); + if (!x) { + xfree(dst); + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + dst = x; + } + + /* finished? */ + if (sp >= sq) break; + + ch = *sp++; + if (ch != '\\') { + // a plain copy suffice + dst[off++] = ch; + continue; + } - /* ch was backslash. we expect the escape char. */ - if (sp >= sq) { - snprintf(errbuf, errbufsz, "last backslash is invalid"); - free(dst); - return 0; - } + /* ch was backslash. we expect the escape char. */ + if (sp >= sq) { + snprintf(errbuf, errbufsz, "last backslash is invalid"); + free(dst); + return 0; + } - /* if we want to kill line-ending-backslash ... */ - if (kill_line_ending_backslash) { - /* if this is a newline immediately following the backslash ... */ - if (*sp == '\n' || (*sp == '\r' && sp[1] == '\n')) { - /* skip all the following whitespaces */ - sp += strspn(sp, " \t\r\n"); - continue; - } - } + /* if we want to kill line-ending-backslash ... */ + if (kill_line_ending_backslash) { + /* if this is a newline immediately following the backslash ... */ + if (*sp == '\n' || (*sp == '\r' && sp[1] == '\n')) { + /* skip all the following whitespaces */ + sp += strspn(sp, " \t\r\n"); + continue; + } + } - /* get the escaped char */ - ch = *sp++; - switch (ch) { - case 'u': case 'U': - { - int64_t ucs = 0; - int nhex = (ch == 'u' ? 4 : 8); - for (int i = 0; i < nhex; i++) { - if (sp >= sq) { - snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); - free(dst); - return 0; - } - ch = *sp++; - int v = ('0' <= ch && ch <= '9') - ? ch - '0' - : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); - if (-1 == v) { - snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); - free(dst); - return 0; - } - ucs = ucs * 16 + v; - } - int n = toml_ucs_to_utf8(ucs, &dst[off]); - if (-1 == n) { - snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); - free(dst); - return 0; - } - off += n; - } - continue; + /* get the escaped char */ + ch = *sp++; + switch (ch) { + case 'u': case 'U': + { + int64_t ucs = 0; + int nhex = (ch == 'u' ? 4 : 8); + for (int i = 0; i < nhex; i++) { + if (sp >= sq) { + snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); + free(dst); + return 0; + } + ch = *sp++; + int v = ('0' <= ch && ch <= '9') + ? ch - '0' + : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); + if (-1 == v) { + snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); + free(dst); + return 0; + } + ucs = ucs * 16 + v; + } + int n = toml_ucs_to_utf8(ucs, &dst[off]); + if (-1 == n) { + snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); + free(dst); + return 0; + } + off += n; + } + continue; - case 'b': ch = '\b'; break; - case 't': ch = '\t'; break; - case 'n': ch = '\n'; break; - case 'f': ch = '\f'; break; - case 'r': ch = '\r'; break; - case '"': ch = '"'; break; - case '\\': ch = '\\'; break; - default: - snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); - free(dst); - return 0; - } + case 'b': ch = '\b'; break; + case 't': ch = '\t'; break; + case 'n': ch = '\n'; break; + case 'f': ch = '\f'; break; + case 'r': ch = '\r'; break; + case '"': ch = '"'; break; + case '\\': ch = '\\'; break; + default: + snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); + free(dst); + return 0; + } - dst[off++] = ch; + dst[off++] = ch; } // Cap with NUL and return it. @@ -494,43 +494,43 @@ static char* normalize_key(context_t* ctx, token_t strtok) /* handle quoted string */ if (ch == '\'' || ch == '\"') { - /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ - if (sp[1] == ch && sp[2] == ch) - sp += 3, sq -= 3; - else - sp++, sq--; + /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ + if (sp[1] == ch && sp[2] == ch) + sp += 3, sq -= 3; + else + sp++, sq--; - if (ch == '\'') { - /* for single quote, take it verbatim. */ - if (! (ret = strndup(sp, sq - sp))) { + if (ch == '\'') { + /* for single quote, take it verbatim. */ + if (! (ret = strndup(sp, sq - sp))) { e_outofmemory(ctx, FLINE); return 0; /* not reached */ } - } else { - /* for double quote, we need to normalize */ - ret = normalize_string(sp, sq - sp, 0, ebuf, sizeof(ebuf)); - if (!ret) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); - longjmp(ctx->jmp, 1); - } - } + } else { + /* for double quote, we need to normalize */ + ret = normalize_string(sp, sq - sp, 0, ebuf, sizeof(ebuf)); + if (!ret) { + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); + longjmp(ctx->jmp, 1); + } + } - /* newlines are not allowed in keys */ - if (strchr(ret, '\n')) { - free(ret); - e_bad_key_error(ctx, lineno); + /* newlines are not allowed in keys */ + if (strchr(ret, '\n')) { + free(ret); + e_bad_key_error(ctx, lineno); return 0; /* not reached */ - } - return ret; + } + return ret; } - + /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ const char* xp; for (xp = sp; xp != sq; xp++) { - int k = *xp; - if (isalnum(k)) continue; - if (k == '_' || k == '-') continue; - e_bad_key_error(ctx, lineno); + int k = *xp; + if (isalnum(k)) continue; + if (k == '_' || k == '-') continue; + e_bad_key_error(ctx, lineno); return 0; /* not reached */ } @@ -548,9 +548,9 @@ static char* normalize_key(context_t* ctx, token_t strtok) * 'v'alue, 'a'rray or 't'able depending on the element. */ 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) + toml_keyval_t** ret_val, + toml_array_t** ret_arr, + toml_table_t** ret_tab) { int i; void* dummy; @@ -562,22 +562,22 @@ static int check_key(toml_table_t* tab, const char* key, *ret_tab = 0; *ret_arr = 0; *ret_val = 0; for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) { - *ret_val = tab->kval[i]; - return 'v'; - } + if (0 == strcmp(key, tab->kval[i]->key)) { + *ret_val = tab->kval[i]; + return 'v'; + } } for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) { - *ret_arr = tab->arr[i]; - return 'a'; - } + if (0 == strcmp(key, tab->arr[i]->key)) { + *ret_arr = tab->arr[i]; + return 'a'; + } } for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) { - *ret_tab = tab->tab[i]; - return 't'; - } + if (0 == strcmp(key, tab->tab[i]->key)) { + *ret_tab = tab->tab[i]; + return 't'; + } } return 0; } @@ -594,8 +594,8 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, /* if key exists: error out. */ toml_keyval_t* dest = 0; if (check_key(tab, newkey, 0, 0, 0)) { - free(newkey); - e_key_exists_error(ctx, keytok); + free(newkey); + e_key_exists_error(ctx, keytok); return 0; /* not reached */ } @@ -603,15 +603,15 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, int n = tab->nkval; toml_keyval_t** base; if (0 == (base = (toml_keyval_t**) realloc(tab->kval, (n+1) * sizeof(*base)))) { - free(newkey); - e_outofmemory(ctx, FLINE); + free(newkey); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } tab->kval = base; if (0 == (base[n] = (toml_keyval_t*) calloc(1, sizeof(*base[n])))) { - free(newkey); - e_outofmemory(ctx, FLINE); + free(newkey); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } dest = tab->kval[tab->nkval++]; @@ -634,15 +634,15 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, /* if key exists: error out */ toml_table_t* dest = 0; if (check_key(tab, newkey, 0, 0, &dest)) { - free(newkey); /* don't need this anymore */ - - /* special case: if table exists, but was created implicitly ... */ - if (dest && dest->implicit) { - /* we make it explicit now, and simply return it. */ - dest->implicit = 0; - return dest; - } - e_key_exists_error(ctx, keytok); + free(newkey); /* don't need this anymore */ + + /* special case: if table exists, but was created implicitly ... */ + if (dest && dest->implicit) { + /* we make it explicit now, and simply return it. */ + dest->implicit = 0; + return dest; + } + e_key_exists_error(ctx, keytok); return 0; /* not reached */ } @@ -650,15 +650,15 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, int n = tab->ntab; toml_table_t** base; if (0 == (base = (toml_table_t**) realloc(tab->tab, (n+1) * sizeof(*base)))) { - free(newkey); - e_outofmemory(ctx, FLINE); + free(newkey); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } tab->tab = base; - + if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { - free(newkey); - e_outofmemory(ctx, FLINE); + free(newkey); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } dest = tab->tab[tab->ntab++]; @@ -672,9 +672,9 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, /* Create an array in the table. */ static toml_array_t* create_keyarray_in_table(context_t* ctx, - toml_table_t* tab, - token_t keytok, - int skip_if_exist) + toml_table_t* tab, + token_t keytok, + int skip_if_exist) { /* first, normalize the key to be used for lookup. * remember to free it if we error out. @@ -684,12 +684,12 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, /* if key exists: error out */ toml_array_t* dest = 0; if (check_key(tab, newkey, 0, &dest, 0)) { - free(newkey); /* don't need this anymore */ + free(newkey); /* don't need this anymore */ - /* special case skip if exists? */ - if (skip_if_exist) return dest; - - e_key_exists_error(ctx, keytok); + /* special case skip if exists? */ + if (skip_if_exist) return dest; + + e_key_exists_error(ctx, keytok); return 0; /* not reached */ } @@ -697,15 +697,15 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, int n = tab->narr; toml_array_t** base; if (0 == (base = (toml_array_t**) realloc(tab->arr, (n+1) * sizeof(*base)))) { - free(newkey); - e_outofmemory(ctx, FLINE); + free(newkey); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } tab->arr = base; - + if (0 == (base[n] = (toml_array_t*) calloc(1, sizeof(*base[n])))) { - free(newkey); - e_outofmemory(ctx, FLINE); + free(newkey); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } dest = tab->arr[tab->narr++]; @@ -718,18 +718,18 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, /* Create an array in an array */ static toml_array_t* create_array_in_array(context_t* ctx, - toml_array_t* parent) + toml_array_t* parent) { int n = parent->nelem; toml_array_t** base; if (0 == (base = (toml_array_t**) realloc(parent->u.arr, (n+1) * sizeof(*base)))) { - e_outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } parent->u.arr = base; if (0 == (base[n] = (toml_array_t*) calloc(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } @@ -739,18 +739,18 @@ static toml_array_t* create_array_in_array(context_t* ctx, /* Create a table in an array */ static toml_table_t* create_table_in_array(context_t* ctx, - toml_array_t* parent) + toml_array_t* parent) { int n = parent->nelem; toml_table_t** base; if (0 == (base = (toml_table_t**) realloc(parent->u.tab, (n+1) * sizeof(*base)))) { - e_outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } parent->u.tab = base; if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); return 0; /* not reached */ } @@ -774,28 +774,28 @@ static void parse_table(context_t* ctx, toml_table_t* tab) EAT_TOKEN(ctx, LBRACE); for (;;) { - SKIP_NEWLINES(ctx); + SKIP_NEWLINES(ctx); - /* until } */ - if (ctx->tok.tok == RBRACE) break; + /* until } */ + if (ctx->tok.tok == RBRACE) break; - if (ctx->tok.tok != STRING) { + if (ctx->tok.tok != STRING) { e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); return; /* not reached */ - } + } parse_keyval(ctx, tab); - SKIP_NEWLINES(ctx); + SKIP_NEWLINES(ctx); - /* on comma, continue to scan for next keyval */ - if (ctx->tok.tok == COMMA) { - EAT_TOKEN(ctx, COMMA); - continue; - } - break; + /* on comma, continue to scan for next keyval */ + if (ctx->tok.tok == COMMA) { + EAT_TOKEN(ctx, COMMA); + continue; + } + break; } if (ctx->tok.tok != RBRACE) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); return; /* not reached */ } @@ -810,9 +810,9 @@ static int valtype(const char* val) if (0 == toml_rtoi(val, 0)) return 'i'; if (0 == toml_rtod(val, 0)) return 'd'; if (0 == toml_rtots(val, &ts)) { - if (ts.year && ts.hour) return 'T'; /* timestamp */ - if (ts.year) return 'D'; /* date */ - return 't'; /* time */ + if (ts.year && ts.hour) return 'T'; /* timestamp */ + if (ts.year) return 'D'; /* date */ + return 't'; /* time */ } return 'u'; /* unknown */ } @@ -824,94 +824,94 @@ static void parse_array(context_t* ctx, toml_array_t* arr) EAT_TOKEN(ctx, LBRACKET); for (;;) { - SKIP_NEWLINES(ctx); - - /* until ] */ - if (ctx->tok.tok == RBRACKET) break; + SKIP_NEWLINES(ctx); + + /* until ] */ + if (ctx->tok.tok == RBRACKET) break; - switch (ctx->tok.tok) { - case STRING: - { - char* val = ctx->tok.ptr; - int vlen = ctx->tok.len; + switch (ctx->tok.tok) { + case STRING: + { + char* val = ctx->tok.ptr; + int vlen = ctx->tok.len; - /* set array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'v'; - /* check array kind */ - if (arr->kind != 'v') { - e_syntax_error(ctx, ctx->tok.lineno, + /* set array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'v'; + /* check array kind */ + if (arr->kind != 'v') { + e_syntax_error(ctx, ctx->tok.lineno, "a string array can only contain strings"); return; /* not reached */ - } + } - /* make a new value in array */ - char** tmp = (char**) realloc(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); - if (!tmp) { + /* make a new value in array */ + char** tmp = (char**) realloc(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); + if (!tmp) { e_outofmemory(ctx, FLINE); return; /* not reached */ } - arr->u.val = tmp; - if (! (val = strndup(val, vlen))) { + arr->u.val = tmp; + if (! (val = strndup(val, vlen))) { e_outofmemory(ctx, FLINE); return; /* not reached */ } - arr->u.val[arr->nelem++] = val; + arr->u.val[arr->nelem++] = val; - /* set array type if this is the first entry, or check that the types matched. */ - if (arr->nelem == 1) - arr->type = valtype(arr->u.val[0]); - else if (arr->type != valtype(val)) { - e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + /* set array type if this is the first entry, or check that the types matched. */ + if (arr->nelem == 1) + arr->type = valtype(arr->u.val[0]); + else if (arr->type != valtype(val)) { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); return; /* not reached */ } - EAT_TOKEN(ctx, STRING); - break; - } + EAT_TOKEN(ctx, STRING); + break; + } - case LBRACKET: - { /* [ [array], [array] ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'a'; - /* check array kind */ - if (arr->kind != 'a') { - e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + case LBRACKET: + { /* [ [array], [array] ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'a'; + /* check array kind */ + if (arr->kind != 'a') { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); return; /* not reached */ - } - parse_array(ctx, create_array_in_array(ctx, arr)); - break; - } + } + parse_array(ctx, create_array_in_array(ctx, arr)); + break; + } - case LBRACE: - { /* [ {table}, {table} ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 't'; - /* check array kind */ - if (arr->kind != 't') { - e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + case LBRACE: + { /* [ {table}, {table} ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 't'; + /* check array kind */ + if (arr->kind != 't') { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); return; /* not reached */ - } - parse_table(ctx, create_table_in_array(ctx, arr)); - break; - } - - default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + } + parse_table(ctx, create_table_in_array(ctx, arr)); + break; + } + + default: + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); return; /* not reached */ - } + } - SKIP_NEWLINES(ctx); + SKIP_NEWLINES(ctx); - /* on comma, continue to scan for next element */ - if (ctx->tok.tok == COMMA) { - EAT_TOKEN(ctx, COMMA); - continue; - } - break; + /* on comma, continue to scan for next element */ + if (ctx->tok.tok == COMMA) { + EAT_TOKEN(ctx, COMMA); + continue; + } + break; } if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); return; /* not reached */ } @@ -928,7 +928,7 @@ static void parse_array(context_t* ctx, toml_array_t* arr) static void parse_keyval(context_t* ctx, toml_table_t* tab) { if (ctx->tok.tok != STRING) { - e_internal_error(ctx, FLINE); + e_internal_error(ctx, FLINE); return; /* not reached */ } @@ -936,7 +936,7 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab) EAT_TOKEN(ctx, STRING); if (ctx->tok.tok != EQUAL) { - e_syntax_error(ctx, ctx->tok.lineno, "missing ="); + e_syntax_error(ctx, ctx->tok.lineno, "missing ="); return; /* not reached */ } @@ -944,37 +944,37 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab) switch (ctx->tok.tok) { case STRING: - { /* key = "value" */ - toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); - token_t val = ctx->tok; - assert(keyval->val == 0); - keyval->val = strndup(val.ptr, val.len); - if (! keyval->val) { + { /* key = "value" */ + toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); + token_t val = ctx->tok; + assert(keyval->val == 0); + keyval->val = strndup(val.ptr, val.len); + if (! keyval->val) { e_outofmemory(ctx, FLINE); return; /* not reached */ } - EAT_TOKEN(ctx, STRING); - - return; - } + EAT_TOKEN(ctx, STRING); + + return; + } case LBRACKET: - { /* key = [ array ] */ - toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); - parse_array(ctx, arr); - return; - } + { /* key = [ array ] */ + toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); + parse_array(ctx, arr); + return; + } case LBRACE: - { /* key = { table } */ - toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); - parse_table(ctx, nxttab); - return; - } + { /* key = { table } */ + toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); + parse_table(ctx, nxttab); + return; + } default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); return; /* not reached */ } } @@ -997,41 +997,41 @@ static void fill_tabpath(context_t* ctx) /* clear tpath */ for (i = 0; i < ctx->tpath.top; i++) { - char** p = &ctx->tpath.key[i]; - xfree(*p); - *p = 0; + char** p = &ctx->tpath.key[i]; + xfree(*p); + *p = 0; } ctx->tpath.top = 0; for (;;) { - if (ctx->tpath.top >= 10) { - e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); + if (ctx->tpath.top >= 10) { + e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); return; /* not reached */ } - if (ctx->tok.tok != STRING) { - e_syntax_error(ctx, lineno, "invalid or missing key"); + if (ctx->tok.tok != STRING) { + e_syntax_error(ctx, lineno, "invalid or missing key"); return; /* not reached */ } - ctx->tpath.tok[ctx->tpath.top] = ctx->tok; - ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); - ctx->tpath.top++; - - next_token(ctx, 1); + ctx->tpath.tok[ctx->tpath.top] = ctx->tok; + ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); + ctx->tpath.top++; + + next_token(ctx, 1); - if (ctx->tok.tok == RBRACKET) break; + if (ctx->tok.tok == RBRACKET) break; - if (ctx->tok.tok != DOT) { - e_syntax_error(ctx, lineno, "invalid key"); + if (ctx->tok.tok != DOT) { + e_syntax_error(ctx, lineno, "invalid key"); return; /* not reached */ } - next_token(ctx, 1); + next_token(ctx, 1); } if (ctx->tpath.top <= 0) { - e_syntax_error(ctx, lineno, "empty table selector"); + e_syntax_error(ctx, lineno, "empty table selector"); return; /* not reached */ } } @@ -1046,63 +1046,63 @@ static void walk_tabpath(context_t* ctx) toml_table_t* curtab = ctx->root; for (int i = 0; i < ctx->tpath.top; i++) { - const char* key = ctx->tpath.key[i]; + const char* key = ctx->tpath.key[i]; - toml_keyval_t* nextval = 0; - toml_array_t* nextarr = 0; - toml_table_t* nexttab = 0; - switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { - case 't': - /* found a table. nexttab is where we will go next. */ - break; + toml_keyval_t* nextval = 0; + toml_array_t* nextarr = 0; + toml_table_t* nexttab = 0; + switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { + case 't': + /* found a table. nexttab is where we will go next. */ + break; - case 'a': - /* found an array. nexttab is the last table in the array. */ - if (nextarr->kind != 't') { + case 'a': + /* found an array. nexttab is the last table in the array. */ + if (nextarr->kind != 't') { e_internal_error(ctx, FLINE); return; /* not reached */ } - if (nextarr->nelem == 0) { + if (nextarr->nelem == 0) { e_internal_error(ctx, FLINE); return; /* not reached */ } - nexttab = nextarr->u.tab[nextarr->nelem-1]; - break; + nexttab = nextarr->u.tab[nextarr->nelem-1]; + break; - case 'v': - e_key_exists_error(ctx, ctx->tpath.tok[i]); + case 'v': + e_key_exists_error(ctx, ctx->tpath.tok[i]); return; /* not reached */ - default: - { /* Not found. Let's create an implicit table. */ - int n = curtab->ntab; - toml_table_t** base = (toml_table_t**) realloc(curtab->tab, (n+1) * sizeof(*base)); - if (0 == base) { + default: + { /* Not found. Let's create an implicit table. */ + int n = curtab->ntab; + toml_table_t** base = (toml_table_t**) realloc(curtab->tab, (n+1) * sizeof(*base)); + if (0 == base) { e_outofmemory(ctx, FLINE); return; /* not reached */ } - curtab->tab = base; - - if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); + curtab->tab = base; + + if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); return; /* not reached */ } - - if (0 == (base[n]->key = strdup(key))) { - e_outofmemory(ctx, FLINE); + + if (0 == (base[n]->key = strdup(key))) { + e_outofmemory(ctx, FLINE); return; /* not reached */ } - - nexttab = curtab->tab[curtab->ntab++]; - - /* tabs created by walk_tabpath are considered implicit */ - nexttab->implicit = 1; - } - break; - } + + nexttab = curtab->tab[curtab->ntab++]; + + /* tabs created by walk_tabpath are considered implicit */ + nexttab->implicit = 1; + } + break; + } - /* switch to next tab */ - curtab = nexttab; + /* switch to next tab */ + curtab = nexttab; } /* save it */ @@ -1121,8 +1121,8 @@ static void parse_select(context_t* ctx) count_lbracket++; next_token(ctx, 1 /* DOT IS SPECIAL */); if (ctx->tok.tok == LBRACKET) { - count_lbracket++; - next_token(ctx, 1 /* DOT IS SPECIAL */); + count_lbracket++; + next_token(ctx, 1 /* DOT IS SPECIAL */); } fill_tabpath(ctx); @@ -1136,47 +1136,47 @@ static void parse_select(context_t* ctx) walk_tabpath(ctx); if (count_lbracket == 1) { - /* [x.y.z] -> create z = {} in x.y */ - ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); + /* [x.y.z] -> create z = {} in x.y */ + ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); } else { - /* [[x.y.z]] -> create z = [] in x.y */ - toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z, - 1 /*skip_if_exist*/); + /* [[x.y.z]] -> create z = [] in x.y */ + toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z, + 1 /*skip_if_exist*/); if (!arr) { e_syntax_error(ctx, z.lineno, "key exists"); return; } - if (arr->kind == 0) arr->kind = 't'; - if (arr->kind != 't') { + if (arr->kind == 0) arr->kind = 't'; + if (arr->kind != 't') { e_syntax_error(ctx, z.lineno, "array mismatch"); return; /* not reached */ } - /* add to z[] */ - toml_table_t* dest; - { - int n = arr->nelem; - toml_table_t** base = realloc(arr->u.tab, (n+1) * sizeof(*base)); - if (0 == base) { + /* add to z[] */ + toml_table_t* dest; + { + int n = arr->nelem; + toml_table_t** base = realloc(arr->u.tab, (n+1) * sizeof(*base)); + if (0 == base) { e_outofmemory(ctx, FLINE); return; /* not reached */ } - arr->u.tab = base; - - if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); + arr->u.tab = base; + + if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); return; /* not reached */ } - + if (0 == (base[n]->key = strdup("__anon__"))) { - e_outofmemory(ctx, FLINE); + e_outofmemory(ctx, FLINE); return; /* not reached */ } - - dest = arr->u.tab[arr->nelem++]; - } + + dest = arr->u.tab[arr->nelem++]; + } - ctx->curtab = dest; + ctx->curtab = dest; } if (ctx->tok.tok != RBRACKET) { @@ -1186,11 +1186,11 @@ static void parse_select(context_t* ctx) EAT_TOKEN(ctx, RBRACKET); if (count_lbracket == 2) { - if (ctx->tok.tok != RBRACKET) { + if (ctx->tok.tok != RBRACKET) { e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); return; /* not reached */ } - EAT_TOKEN(ctx, RBRACKET); + EAT_TOKEN(ctx, RBRACKET); } if (ctx->tok.tok != NEWLINE) { e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); @@ -1202,8 +1202,8 @@ static void parse_select(context_t* ctx) toml_table_t* toml_parse(char* conf, - char* errbuf, - int errbufsz) + char* errbuf, + int errbufsz) { context_t ctx; @@ -1235,39 +1235,39 @@ toml_table_t* toml_parse(char* conf, ctx.curtab = ctx.root; if (0 != setjmp(ctx.jmp)) { - // Got here from a long_jmp. Something bad has happened. - // Free resources and return error. - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - toml_free(ctx.root); - return 0; + // Got here from a long_jmp. Something bad has happened. + // Free resources and return error. + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + toml_free(ctx.root); + return 0; } /* Scan forward until EOF */ for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { - switch (tok.tok) { - - case NEWLINE: - next_token(&ctx, 1); - break; - - case STRING: - parse_keyval(&ctx, ctx.curtab); - if (ctx.tok.tok != NEWLINE) { + switch (tok.tok) { + + case NEWLINE: + next_token(&ctx, 1); + break; + + case STRING: + parse_keyval(&ctx, ctx.curtab); + if (ctx.tok.tok != NEWLINE) { e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); return 0; /* not reached */ } - EAT_TOKEN(&ctx, NEWLINE); - break; - - case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ - parse_select(&ctx); - break; - - default: - snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); - longjmp(ctx.jmp, 1); - } + EAT_TOKEN(&ctx, NEWLINE); + break; + + case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ + parse_select(&ctx); + break; + + default: + snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); + longjmp(ctx.jmp, 1); + } } /* success */ @@ -1277,8 +1277,8 @@ toml_table_t* toml_parse(char* conf, toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz) + char* errbuf, + int errbufsz) { int bufsz = 0; char* buf = 0; @@ -1293,26 +1293,26 @@ toml_table_t* toml_parse_file(FILE* fp, /* read from fp into buf */ while (! feof(fp)) { - bufsz += 1000; - - /* Allocate 1 extra byte because we will tag on a NUL */ - char* x = realloc(buf, bufsz + 1); - if (!x) { - snprintf(errbuf, errbufsz, "out of memory"); - xfree(buf); - return 0; - } - buf = x; + bufsz += 1000; + + /* Allocate 1 extra byte because we will tag on a NUL */ + char* x = realloc(buf, bufsz + 1); + if (!x) { + snprintf(errbuf, errbufsz, "out of memory"); + xfree(buf); + return 0; + } + buf = x; - errno = 0; - int n = fread(buf + off, 1, bufsz - off, fp); - if (ferror(fp)) { - snprintf(errbuf, errbufsz, "%s", - errno ? strerror(errno) : "Error reading file"); - free(buf); - return 0; - } - off += n; + errno = 0; + int n = fread(buf + off, 1, bufsz - off, fp); + if (ferror(fp)) { + snprintf(errbuf, errbufsz, "%s", + errno ? strerror(errno) : "Error reading file"); + free(buf); + return 0; + } + off += n; } /* tag on a NUL to cap the string */ @@ -1342,19 +1342,19 @@ static void xfree_arr(toml_array_t* p) xfree(p->key); switch (p->kind) { case 'v': - for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); - xfree(p->u.val); - break; + for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); + xfree(p->u.val); + break; case 'a': - for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); - xfree(p->u.arr); - break; + for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); + xfree(p->u.arr); + break; case 't': - for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); - xfree(p->u.tab); - break; + for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); + xfree(p->u.tab); + break; } xfree(p); @@ -1412,94 +1412,94 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe { char* orig = p; if (0 == strncmp(p, "'''", 3)) { - p = strstr(p + 3, "'''"); - if (0 == p) { - e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); + p = strstr(p + 3, "'''"); + if (0 == p) { + e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); return 0; /* not reached */ } - return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); + return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); } if (0 == strncmp(p, "\"\"\"", 3)) { - int hexreq = 0; /* #hex required */ - int escape = 0; - int qcnt = 0; /* count quote */ - for (p += 3; *p && qcnt < 3; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - if (*p == '\n') continue; /* allow for line ending backslash */ - e_syntax_error(ctx, lineno, "bad escape char"); + int hexreq = 0; /* #hex required */ + int escape = 0; + int qcnt = 0; /* count quote */ + for (p += 3; *p && qcnt < 3; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + if (*p == '\n') continue; /* allow for line ending backslash */ + e_syntax_error(ctx, lineno, "bad escape char"); return 0; /* not reached */ - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + e_syntax_error(ctx, lineno, "expect hex char"); return 0; /* not reached */ - } - if (*p == '\\') { escape = 1; continue; } - qcnt = (*p == '"') ? qcnt + 1 : 0; - } - if (qcnt != 3) { - e_syntax_error(ctx, lineno, "unterminated triple-quote"); + } + if (*p == '\\') { escape = 1; continue; } + qcnt = (*p == '"') ? qcnt + 1 : 0; + } + if (qcnt != 3) { + e_syntax_error(ctx, lineno, "unterminated triple-quote"); return 0; /* not reached */ } - return ret_token(ctx, STRING, lineno, orig, p - orig); + return ret_token(ctx, STRING, lineno, orig, p - orig); } if ('\'' == *p) { - for (p++; *p && *p != '\n' && *p != '\''; p++); - if (*p != '\'') { - e_syntax_error(ctx, lineno, "unterminated s-quote"); + for (p++; *p && *p != '\n' && *p != '\''; p++); + if (*p != '\'') { + e_syntax_error(ctx, lineno, "unterminated s-quote"); return 0; /* not reached */ } - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); } if ('\"' == *p) { - int hexreq = 0; /* #hex required */ - int escape = 0; - for (p++; *p; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - e_syntax_error(ctx, lineno, "bad escape char"); + int hexreq = 0; /* #hex required */ + int escape = 0; + for (p++; *p; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + e_syntax_error(ctx, lineno, "bad escape char"); return 0; /* not reached */ - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + e_syntax_error(ctx, lineno, "expect hex char"); return 0; /* not reached */ - } - if (*p == '\\') { escape = 1; continue; } - if (*p == '\n') break; - if (*p == '"') break; - } - if (*p != '"') { - e_syntax_error(ctx, lineno, "unterminated quote"); + } + if (*p == '\\') { escape = 1; continue; } + if (*p == '\n') break; + if (*p == '"') break; + } + if (*p != '"') { + e_syntax_error(ctx, lineno, "unterminated quote"); return 0; /* not reached */ } - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); } for ( ; *p && *p != '\n'; p++) { - int ch = *p; - if (ch == '.' && dotisspecial) break; - if ('A' <= ch && ch <= 'Z') continue; - if ('a' <= ch && ch <= 'z') continue; - if ('0' <= ch && ch <= '9') continue; - if (strchr("+-_.:", ch)) continue; - break; + int ch = *p; + if (ch == '.' && dotisspecial) break; + if ('A' <= ch && ch <= 'Z') continue; + if ('a' <= ch && ch <= 'z') continue; + if ('0' <= ch && ch <= '9') continue; + if (strchr("+-_.:", ch)) continue; + break; } return ret_token(ctx, STRING, lineno, orig, p - orig); @@ -1514,36 +1514,36 @@ static tokentype_t next_token(context_t* ctx, int dotisspecial) /* eat this tok */ for (i = 0; i < ctx->tok.len; i++) { - if (*p++ == '\n') - lineno++; + if (*p++ == '\n') + lineno++; } /* make next tok */ while (p < ctx->stop) { - /* skip comment. stop just before the \n. */ - if (*p == '#') { - for (p++; p < ctx->stop && *p != '\n'; p++); - continue; - } + /* skip comment. stop just before the \n. */ + if (*p == '#') { + for (p++; p < ctx->stop && *p != '\n'; p++); + continue; + } - if (dotisspecial && *p == '.') - return ret_token(ctx, DOT, lineno, p, 1); - - switch (*p) { - case ',': return ret_token(ctx, COMMA, lineno, p, 1); - case '=': return ret_token(ctx, EQUAL, lineno, p, 1); - case '{': return ret_token(ctx, LBRACE, lineno, p, 1); - case '}': return ret_token(ctx, RBRACE, lineno, p, 1); - case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); - case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); - case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); - case '\r': case ' ': case '\t': - /* ignore white spaces */ - p++; - continue; - } + if (dotisspecial && *p == '.') + return ret_token(ctx, DOT, lineno, p, 1); + + switch (*p) { + case ',': return ret_token(ctx, COMMA, lineno, p, 1); + case '=': return ret_token(ctx, EQUAL, lineno, p, 1); + case '{': return ret_token(ctx, LBRACE, lineno, p, 1); + case '}': return ret_token(ctx, RBRACE, lineno, p, 1); + case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); + case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); + case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); + case '\r': case ' ': case '\t': + /* ignore white spaces */ + p++; + continue; + } - return scan_string(ctx, p, lineno, dotisspecial); + return scan_string(ctx, p, lineno, dotisspecial); } return ret_eof(ctx, lineno); @@ -1568,8 +1568,8 @@ const char* toml_raw_in(toml_table_t* tab, const char* key) { int i; for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) - return tab->kval[i]->val; + if (0 == strcmp(key, tab->kval[i]->key)) + return tab->kval[i]->val; } return 0; } @@ -1578,8 +1578,8 @@ toml_array_t* toml_array_in(toml_table_t* tab, const char* key) { int i; for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) - return tab->arr[i]; + if (0 == strcmp(key, tab->arr[i]->key)) + return tab->arr[i]; } return 0; } @@ -1589,8 +1589,8 @@ toml_table_t* toml_table_in(toml_table_t* tab, const char* key) { int i; for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) - return tab->tab[i]; + if (0 == strcmp(key, tab->tab[i]->key)) + return tab->tab[i]; } return 0; } @@ -1598,9 +1598,9 @@ toml_table_t* toml_table_in(toml_table_t* tab, const char* key) const char* toml_raw_at(toml_array_t* arr, int idx) { if (arr->kind != 'v') - return 0; + return 0; if (! (0 <= idx && idx < arr->nelem)) - return 0; + return 0; return arr->u.val[idx]; } @@ -1643,18 +1643,18 @@ const char* toml_table_key(toml_table_t* tab) toml_array_t* toml_array_at(toml_array_t* arr, int idx) { if (arr->kind != 'a') - return 0; + return 0; if (! (0 <= idx && idx < arr->nelem)) - return 0; + return 0; return arr->u.arr[idx]; } toml_table_t* toml_table_at(toml_array_t* arr, int idx) { if (arr->kind != 't') - return 0; + return 0; if (! (0 <= idx && idx < arr->nelem)) - return 0; + return 0; return arr->u.tab[idx]; } @@ -1673,26 +1673,26 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) /* parse date */ val = 0; if (q - p > 4 && p[4] == '-') { - for (i = 0; i < 10; i++, p++) { - int xx = *p; - if (xx == '-') { - if (i == 4 || i == 7) continue; else return -1; - } - if (! ('0' <= xx && xx <= '9')) return -1; - val = val * 10 + (xx - '0'); - } - ret->day = &ret->__buffer.day; - ret->month = &ret->__buffer.month; - ret->year = &ret->__buffer.year; - - *ret->day = val % 100; val /= 100; - *ret->month = val % 100; val /= 100; - *ret->year = val; - - if (*p) { - if (*p != 'T') return -1; - p++; - } + for (i = 0; i < 10; i++, p++) { + int xx = *p; + if (xx == '-') { + if (i == 4 || i == 7) continue; else return -1; + } + if (! ('0' <= xx && xx <= '9')) return -1; + val = val * 10 + (xx - '0'); + } + ret->day = &ret->__buffer.day; + ret->month = &ret->__buffer.month; + ret->year = &ret->__buffer.year; + + *ret->day = val % 100; val /= 100; + *ret->month = val % 100; val /= 100; + *ret->year = val; + + if (*p) { + if (*p != 'T') return -1; + p++; + } } if (q == p) return 0; @@ -1700,12 +1700,12 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) val = 0; if (q - p < 8) return -1; for (i = 0; i < 8; i++, p++) { - int xx = *p; - if (xx == ':') { - if (i == 2 || i == 5) continue; else return -1; - } - if (! ('0' <= xx && xx <= '9')) return -1; - val = val * 10 + (xx - '0'); + int xx = *p; + if (xx == ':') { + if (i == 2 || i == 5) continue; else return -1; + } + if (! ('0' <= xx && xx <= '9')) return -1; + val = val * 10 + (xx - '0'); } ret->second = &ret->__buffer.second; ret->minute = &ret->__buffer.minute; @@ -1723,26 +1723,26 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) ret->z = ret->__buffer.z; char* z = ret->z; if (*p == 'Z') { - *z++ = *p++; - *z = 0; - return (p == q) ? 0 : -1; + *z++ = *p++; + *z = 0; + return (p == q) ? 0 : -1; } if (*p == '+' || *p == '-') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - - if (*p == ':') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - } - - *z = 0; + *z++ = *p++; + + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; + *z++ = *p++; + *z++ = *p++; + + if (*p == ':') { + *z++ = *p++; + + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; + *z++ = *p++; + *z++ = *p++; + } + + *z = 0; } return (p == q) ? 0 : -1; } @@ -1756,12 +1756,12 @@ int toml_rtob(const char* src, int* ret_) int* ret = ret_ ? ret_ : &dummy; if (0 == strcmp(src, "true")) { - *ret = 1; - return 0; + *ret = 1; + return 0; } if (0 == strcmp(src, "false")) { - *ret = 0; - return 0; + *ret = 0; + return 0; } return -1; } @@ -1780,21 +1780,21 @@ int toml_rtoi(const char* src, int64_t* ret_) int64_t* ret = ret_ ? ret_ : &dummy; if (*s == '+') - *p++ = *s++; + *p++ = *s++; else if (*s == '-') - *p++ = *s++; + *p++ = *s++; /* if 0 ... */ if ('0' == s[0]) { - /* ensure no other digits after it */ - if (s[1]) return -1; - return *ret = 0, 0; + /* ensure no other digits after it */ + if (s[1]) return -1; + return *ret = 0, 0; } /* just strip underscores and pass to strtoll */ while (*s && p < q) { - int ch = *s++; - if (ch == '_') ; else *p++ = ch; + int ch = *s++; + if (ch == '_') ; else *p++ = ch; } if (*s || p == q) return -1; @@ -1822,21 +1822,21 @@ int toml_rtod(const char* src, double* ret_) /* check for special cases */ if (s[0] == '+' || s[0] == '-') *p++ = *s++; - if (s[0] == '.') return -1; /* no leading zero */ + if (s[0] == '.') return -1; /* no leading zero */ if (s[0] == '0') { - /* zero must be followed by . or NUL */ - if (s[1] && s[1] != '.') return -1; + /* zero must be followed by . or NUL */ + if (s[1] && s[1] != '.') return -1; } /* just strip underscores and pass to strtod */ while (*s && p < q) { - int ch = *s++; - if (ch == '_') ; else *p++ = ch; + int ch = *s++; + if (ch == '_') ; else *p++ = ch; } if (*s || p == q) return -1; if (p != buf && p[-1] == '.') - return -1; /* no trailing zero */ + return -1; /* no trailing zero */ /* cap with NUL */ *p = 0; @@ -1856,16 +1856,16 @@ static char* kill_line_ending_backslash(char* str) /* first round: find (backslash, \n) */ char* p = str; while (0 != (p = strstr(p, "\\\n"))) { - char* q = (p + 1); - q += strspn(q, " \t\r\n"); - memmove(p, q, strlen(q) + 1); + char* q = (p + 1); + q += strspn(q, " \t\r\n"); + memmove(p, q, strlen(q) + 1); } /* second round: find (backslash, \r, \n) */ p = str; while (0 != (p = strstr(p, "\\\r\n"))) { - char* q = (p + 1); - q += strspn(q, " \t\r\n"); - memmove(p, q, strlen(q) + 1); + char* q = (p + 1); + q += strspn(q, " \t\r\n"); + memmove(p, q, strlen(q) + 1); } return str; @@ -1880,55 +1880,55 @@ int toml_rtos(const char* src, char** ret) *ret = 0; int srclen = strlen(src); if (*src == '\'') { - if (0 == strncmp(src, "'''", 3)) { - const char* sp = src + 3; - const char* sq = src + srclen - 3; - /* last 3 chars in src must be ''' */ - if (! (sp <= sq && 0 == strcmp(sq, "'''"))) - return -1; - - /* skip first new line right after ''' */ - if (*sp == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; + if (0 == strncmp(src, "'''", 3)) { + const char* sp = src + 3; + const char* sq = src + srclen - 3; + /* last 3 chars in src must be ''' */ + if (! (sp <= sq && 0 == strcmp(sq, "'''"))) + return -1; + + /* skip first new line right after ''' */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; - *ret = kill_line_ending_backslash(strndup(sp, sq - sp)); - } else { - const char* sp = src + 1; - const char* sq = src + srclen - 1; - /* last char in src must be ' */ - if (! (sp <= sq && *sq == '\'')) - return -1; - /* copy from sp to p */ - *ret = strndup(sp, sq - sp); - } - return *ret ? 0 : -1; + *ret = kill_line_ending_backslash(strndup(sp, sq - sp)); + } else { + const char* sp = src + 1; + const char* sq = src + srclen - 1; + /* last char in src must be ' */ + if (! (sp <= sq && *sq == '\'')) + return -1; + /* copy from sp to p */ + *ret = strndup(sp, sq - sp); + } + return *ret ? 0 : -1; } const char* sp; const char* sq; if (0 == strncmp(src, "\"\"\"", 3)) { - sp = src + 3; - sq = src + srclen - 3; - if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) - return -1; - - /* skip first new line right after """ */ - if (*sp == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; + sp = src + 3; + sq = src + srclen - 3; + if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) + return -1; + + /* skip first new line right after """ */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; } else { - sp = src + 1; - sq = src + srclen - 1; - if (! (sp <= sq && *sq == '"')) - return -1; + sp = src + 1; + sq = src + srclen - 1; + if (! (sp <= sq && *sq == '"')) + return -1; } char dummy_errbuf[1]; *ret = normalize_string(sp, sq - sp, - 1, // flag kill_line_ending_backslash - dummy_errbuf, sizeof(dummy_errbuf)); + 1, // flag kill_line_ending_backslash + dummy_errbuf, sizeof(dummy_errbuf)); return *ret ? 0 : -1; } diff --git a/toml.h b/toml.h index 94469c7..09c9272 100644 --- a/toml.h +++ b/toml.h @@ -25,6 +25,11 @@ SOFTWARE. #ifndef TOML_H #define TOML_H + +#include +#include + + #ifdef __cplusplus #define TOML_EXTERN extern "C" #else @@ -38,16 +43,16 @@ typedef struct toml_array_t toml_array_t; * Caller must toml_free(the-return-value) after use. */ TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz); + char* errbuf, + int errbufsz); /* Parse a string containing the full config. * Return a table on success, or 0 otherwise. * Caller must toml_free(the-return-value) after use. */ TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */ - char* errbuf, - int errbufsz); + char* errbuf, + int errbufsz); /* Free the table returned by toml_parse() or toml_parse_file(). */ TOML_EXTERN void toml_free(toml_table_t* tab); @@ -108,9 +113,9 @@ TOML_EXTERN int toml_rtod(const char* s, double* ret); typedef struct toml_timestamp_t toml_timestamp_t; struct toml_timestamp_t { struct { /* internal. do not use. */ - int year, month, day; - int hour, minute, second; - char z[10]; + int year, month, day; + int hour, minute, second; + char z[10]; } __buffer; int *year, *month, *day; int *hour, *minute, *second; diff --git a/toml_json.c b/toml_json.c index c15e663..f57b3f5 100644 --- a/toml_json.c +++ b/toml_json.c @@ -26,11 +26,9 @@ SOFTWARE. #undef NDEBUG #endif -#include #include #include #include -#include #include #include #include "toml.h" From 05e27a7cab74fd585661add354efdb7c3f2b6366 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 19 Feb 2019 10:51:51 -0800 Subject: [PATCH 017/138] copyright years --- toml.c | 4 ++-- toml.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/toml.c b/toml.c index 11760c0..10f9db2 100644 --- a/toml.c +++ b/toml.c @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2017 CK Tan +Copyright (c) 2017 - 2019 CK Tan https://github.com/cktan/tomlc99 Permission is hereby granted, free of charge, to any person obtaining a copy @@ -284,7 +284,7 @@ typedef struct token_t token_t; struct token_t { tokentype_t tok; int lineno; - char* ptr; + char* ptr; /* points into context->start */ int len; int eof; }; diff --git a/toml.h b/toml.h index 09c9272..67ab80d 100644 --- a/toml.h +++ b/toml.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2017 CK Tan +Copyright (c) 2017 - 2019 CK Tan https://github.com/cktan/tomlc99 Permission is hereby granted, free of charge, to any person obtaining a copy From 0ce0c0d9d0d11ec9542d3bdd93959dbb9339d330 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 19 Feb 2019 15:52:01 -0800 Subject: [PATCH 018/138] handle make DEBUG=1 --- Makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 695291f..476b044 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,13 @@ CC = gcc CFILES = toml.c CFLAGS = -std=c99 -Wall -Wextra -CFLAGS += -O2 -DNDEBUG -#CFLAGS += -O0 -g +# to compile for debug: make DEBUG=1 +# to compile for no debug: make +ifdef DEBUG + CFLAGS += -O0 -g +else + CFLAGS += -O2 -DNDEBUG +endif EXEC = toml_json toml_cat From c4325a38fb6ff243f6e77fba2a47c2bc77528eec Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 27 Feb 2019 11:31:49 -0800 Subject: [PATCH 019/138] add toml_array_type() api --- toml.c | 11 +++++++++++ toml.h | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/toml.c b/toml.c index 10f9db2..2aabe7c 100644 --- a/toml.c +++ b/toml.c @@ -1609,6 +1609,17 @@ char toml_array_kind(toml_array_t* arr) return arr->kind; } +char toml_array_type(toml_array_t* arr) +{ + if (arr->kind != 'v') + return 0; + + if (arr->nelem == 0) + return 0; + + return arr->type; +} + int toml_array_nelem(toml_array_t* arr) { diff --git a/toml.h b/toml.h index 67ab80d..0ec104a 100644 --- a/toml.h +++ b/toml.h @@ -68,6 +68,13 @@ TOML_EXTERN toml_table_t* toml_table_in(toml_table_t* tab, const char* key); /* Return the array kind: 't'able, 'a'rray, 'v'alue */ TOML_EXTERN char toml_array_kind(toml_array_t* arr); +/* For array kind 'v'alue, return the type of values + i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp + 0 if unknown +*/ +TOML_EXTERN char toml_array_type(toml_array_t* arr); + + /* Return the number of elements in the array */ TOML_EXTERN int toml_array_nelem(toml_array_t* arr); From bd76f1276ee5f5df0eb064f1842af5ad1737cf1e Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 6 Mar 2019 11:44:14 -0800 Subject: [PATCH 020/138] support SPC separator in timestamp --- toml.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toml.c b/toml.c index 2aabe7c..7f22943 100644 --- a/toml.c +++ b/toml.c @@ -1701,7 +1701,8 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) *ret->year = val; if (*p) { - if (*p != 'T') return -1; + // parse the T or space separator + if (*p != 'T' && *p != ' ') return -1; p++; } } From 386dccc84fea6139da58aa06f77cb231e129c9f8 Mon Sep 17 00:00:00 2001 From: Jesper Peterson Date: Fri, 10 May 2019 17:17:29 +1000 Subject: [PATCH 021/138] Allow 0x/0o/0b integer prefixed in accordance with https://github.com/toml-lang/toml#integer --- toml.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/toml.c b/toml.c index 7f22943..d5c00ba 100644 --- a/toml.c +++ b/toml.c @@ -1788,6 +1788,7 @@ int toml_rtoi(const char* src, int64_t* ret_) char* p = buf; char* q = p + sizeof(buf); const char* s = src; + int base = 0; int64_t dummy; int64_t* ret = ret_ ? ret_ : &dummy; @@ -1798,9 +1799,15 @@ int toml_rtoi(const char* src, int64_t* ret_) /* if 0 ... */ if ('0' == s[0]) { - /* ensure no other digits after it */ - if (s[1]) return -1; - return *ret = 0, 0; + switch (s[1]) { + case 'x': base = 16; s += 2; break; + case 'o': base = 8; s += 2; break; + case 'b': base = 2; s += 2; break; + case '\0': return *ret = 0, 0; + default: + /* ensure no other digits after it */ + if (s[1]) return -1; + } } /* just strip underscores and pass to strtoll */ @@ -1816,7 +1823,7 @@ int toml_rtoi(const char* src, int64_t* ret_) /* Run strtoll on buf to get the integer */ char* endp; errno = 0; - *ret = strtoll(buf, &endp, 0); + *ret = strtoll(buf, &endp, base); return (errno || *endp) ? -1 : 0; } From 93cae7a0e66a03f8585a4e48489d2e887aa1d08f Mon Sep 17 00:00:00 2001 From: Oliver Breitwieser Date: Thu, 2 May 2019 15:33:15 +0200 Subject: [PATCH 022/138] Add rules for libtoml.so to Makefile --- Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 476b044..fb94a3c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc CFILES = toml.c -CFLAGS = -std=c99 -Wall -Wextra +CFLAGS = -std=c99 -Wall -Wextra -fpic # to compile for debug: make DEBUG=1 # to compile for no debug: make ifdef DEBUG @@ -13,13 +13,17 @@ endif EXEC = toml_json toml_cat LIB = libtoml.a +LIB_SHARED = libtoml.so -all: $(LIB) $(EXEC) +all: $(LIB) $(LIB_SHARED) $(EXEC) libtoml.a: toml.o ar -rcs $@ $^ +libtoml.so: toml.o + $(CC) -shared -o $@ $^ + toml_json: toml_json.c $(LIB) toml_cat: toml_cat.c $(LIB) @@ -29,7 +33,8 @@ prefix ?= /usr/local install: all install -d ${prefix}/include ${prefix}/lib install toml.h ${prefix}/include - install libtoml.a ${prefix}/lib + install $(LIB) ${prefix}/lib + install $(LIB_SHARED) ${prefix}/lib clean: - rm -f *.o $(EXEC) $(LIB) + rm -f *.o $(EXEC) $(LIB) $(LIB_SHARED) From aba3905eb80beee38741190d311f14f62087d7b1 Mon Sep 17 00:00:00 2001 From: Odin Hultgren Van Der Horst Date: Fri, 16 Aug 2019 09:07:48 +0200 Subject: [PATCH 023/138] Added binary files to the gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f805e81..76ce648 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,8 @@ *.i*86 *.x86_64 *.hex +toml_cat +toml_json # Debug files *.dSYM/ From 3bc235331f087a6ebf722a6474225d30bf752e3c Mon Sep 17 00:00:00 2001 From: CK Tan Date: Fri, 16 Aug 2019 04:35:14 -0700 Subject: [PATCH 024/138] Handle more test cases --- toml.c | 150 +++++++++++++++++++-------- toml.h | 6 +- toml_json.c | 289 +++++++++++++++++++++++++++------------------------- 3 files changed, 262 insertions(+), 183 deletions(-) diff --git a/toml.c b/toml.c index d5c00ba..2a9f3da 100644 --- a/toml.c +++ b/toml.c @@ -774,7 +774,10 @@ static void parse_table(context_t* ctx, toml_table_t* tab) EAT_TOKEN(ctx, LBRACE); for (;;) { - SKIP_NEWLINES(ctx); + if (ctx->tok.tok == NEWLINE) { + e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + return; /* not reached */ + } /* until } */ if (ctx->tok.tok == RBRACE) break; @@ -784,7 +787,11 @@ static void parse_table(context_t* ctx, toml_table_t* tab) return; /* not reached */ } parse_keyval(ctx, tab); - SKIP_NEWLINES(ctx); + + if (ctx->tok.tok == NEWLINE) { + e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + return; /* not reached */ + } /* on comma, continue to scan for next keyval */ if (ctx->tok.tok == COMMA) { @@ -1113,15 +1120,17 @@ static void walk_tabpath(context_t* ctx) /* handle lines like [x.y.z] or [[x.y.z]] */ static void parse_select(context_t* ctx) { - int count_lbracket = 0; - if (ctx->tok.tok != LBRACKET) { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } - count_lbracket++; + assert(ctx->tok.tok == LBRACKET); + + /* true if [[ */ + int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '['); + /* need to detect '[[' on our own because next_token() will skip whitespace, + and '[ [' would be taken as '[[', which is wrong. */ + + /* eat [ or [[ */ next_token(ctx, 1 /* DOT IS SPECIAL */); - if (ctx->tok.tok == LBRACKET) { - count_lbracket++; + if (llb) { + assert(ctx->tok.tok == LBRACKET); next_token(ctx, 1 /* DOT IS SPECIAL */); } @@ -1132,10 +1141,11 @@ static void parse_select(context_t* ctx) token_t z = ctx->tpath.tok[ctx->tpath.top-1]; free(ctx->tpath.key[ctx->tpath.top-1]); ctx->tpath.top--; - + + /* set up ctx->curtab */ walk_tabpath(ctx); - if (count_lbracket == 1) { + if (! llb) { /* [x.y.z] -> create z = {} in x.y */ ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); } else { @@ -1183,15 +1193,15 @@ static void parse_select(context_t* ctx) e_syntax_error(ctx, ctx->tok.lineno, "expects ]"); return; /* not reached */ } - EAT_TOKEN(ctx, RBRACKET); - - if (count_lbracket == 2) { - if (ctx->tok.tok != RBRACKET) { + if (llb) { + if (! (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) { e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); - return; /* not reached */ - } - EAT_TOKEN(ctx, RBRACKET); - } + return; /* not reached */ + } + EAT_TOKEN(ctx, RBRACKET); + } + EAT_TOKEN(ctx, RBRACKET); + if (ctx->tok.tok != NEWLINE) { e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); return; /* not reached */ @@ -1681,7 +1691,7 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) memset(ret, 0, sizeof(*ret)); - /* parse date */ + /* parse date YYYY-MM-DD */ val = 0; if (q - p > 4 && p[4] == '-') { for (i = 0; i < 10; i++, p++) { @@ -1708,7 +1718,7 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) } if (q == p) return 0; - /* parse time */ + /* parse time HH:MM:SS */ val = 0; if (q - p < 8) return -1; for (i = 0; i < 8; i++, p++) { @@ -1727,8 +1737,22 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) *ret->minute = val % 100; val /= 100; *ret->hour = val; - /* skip fractional second */ - if (*p == '.') for (p++; '0' <= *p && *p <= '9'; p++); + /* parse millisec */ + if (*p == '.') { + val = 0; + p++; + if ('0' <= *p && *p <= '9') { + val = (*p++ - '0') * 100; + if ('0' <= *p && *p <= '9') { + val += (*p++ - '0') * 10; + if ('0' <= *p && *p <= '9') { + val += (*p++ - '0'); + } + } + } + ret->millisec = &ret->__buffer.millisec; + *ret->millisec = val; + } if (q == p) return 0; /* parse and copy Z */ @@ -1792,10 +1816,14 @@ int toml_rtoi(const char* src, int64_t* ret_) int64_t dummy; int64_t* ret = ret_ ? ret_ : &dummy; - if (*s == '+') - *p++ = *s++; - else if (*s == '-') - *p++ = *s++; + + /* allow +/- */ + if (s[0] == '+' || s[0] == '-') + *p++ = *s++; + + /* disallow +_100 */ + if (s[0] == '_') + return -1; /* if 0 ... */ if ('0' == s[0]) { @@ -1813,9 +1841,20 @@ int toml_rtoi(const char* src, int64_t* ret_) /* just strip underscores and pass to strtoll */ while (*s && p < q) { int ch = *s++; - if (ch == '_') ; else *p++ = ch; + switch (ch) { + case '_': + // disallow '__' + if (s[0] == '_') return -1; + continue; /* skip _ */ + default: + break; + } + *p++ = ch; } if (*s || p == q) return -1; + + /* last char cannot be '_' */ + if (s[-1] == '_') return -1; /* cap with NUL */ *p = 0; @@ -1828,31 +1867,54 @@ int toml_rtoi(const char* src, int64_t* ret_) } -int toml_rtod(const char* src, double* ret_) +int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) { if (!src) return -1; - char buf[100]; char* p = buf; - char* q = p + sizeof(buf); + char* q = p + buflen; const char* s = src; double dummy; double* ret = ret_ ? ret_ : &dummy; + - /* check for special cases */ - if (s[0] == '+' || s[0] == '-') *p++ = *s++; - if (s[0] == '.') return -1; /* no leading zero */ - if (s[0] == '0') { - /* zero must be followed by . or NUL */ - if (s[1] && s[1] != '.') return -1; - } + /* allow +/- */ + if (s[0] == '+' || s[0] == '-') + *p++ = *s++; + + /* disallow +_1.00 */ + if (s[0] == '_') + return -1; + + /* disallow +.99 */ + if (s[0] == '.') + return -1; + + /* zero must be followed by . or NUL */ + if (s[0] == '0' && s[1] && s[1] != '.') + return -1; /* just strip underscores and pass to strtod */ while (*s && p < q) { int ch = *s++; - if (ch == '_') ; else *p++ = ch; + switch (ch) { + case '.': + if (s[-2] == '_') return -1; + if (s[0] == '_') return -1; + break; + case '_': + // disallow '__' + if (s[0] == '_') return -1; + continue; /* skip _ */ + default: + break; + } + *p++ = ch; } - if (*s || p == q) return -1; + if (*s || p == q) return -1; /* reached end of string or buffer is full? */ + + /* last char cannot be '_' */ + if (s[-1] == '_') return -1; if (p != buf && p[-1] == '.') return -1; /* no trailing zero */ @@ -1867,6 +1929,12 @@ int toml_rtod(const char* src, double* ret_) return (errno || *endp) ? -1 : 0; } +int toml_rtod(const char* src, double* ret_) +{ + char buf[100]; + return toml_rtod_ex(src, ret_, buf, sizeof(buf)); +} + static char* kill_line_ending_backslash(char* str) { diff --git a/toml.h b/toml.h index 0ec104a..6f23988 100644 --- a/toml.h +++ b/toml.h @@ -112,6 +112,8 @@ TOML_EXTERN int toml_rtoi(const char* s, int64_t* ret); /* Raw to Double. Return 0 on success, -1 otherwise. */ TOML_EXTERN int toml_rtod(const char* s, double* ret); +/* Same as toml_rtod, but return the sanitized double in string form as well */ +TOML_EXTERN int toml_rtod_ex(const char* s, double* ret, char* buf, int buflen); /* Timestamp types. The year, month, day, hour, minute, second, z * fields may be NULL if they are not relevant. e.g. In a DATE @@ -121,11 +123,11 @@ typedef struct toml_timestamp_t toml_timestamp_t; struct toml_timestamp_t { struct { /* internal. do not use. */ int year, month, day; - int hour, minute, second; + int hour, minute, second, millisec; char z[10]; } __buffer; int *year, *month, *day; - int *hour, *minute, *second; + int *hour, *minute, *second, *millisec; char* z; }; diff --git a/toml_json.c b/toml_json.c index f57b3f5..d443cb5 100644 --- a/toml_json.c +++ b/toml_json.c @@ -1,26 +1,26 @@ /* -MIT License + MIT License -Copyright (c) 2017 CK Tan -https://github.com/cktan/tomlc99 + Copyright (c) 2017 CK Tan + https://github.com/cktan/tomlc99 -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. */ #ifdef NDEBUG #undef NDEBUG @@ -36,170 +36,179 @@ SOFTWARE. static void print_escape_string(const char* s) { - for ( ; *s; s++) { - int ch = *s; - switch (ch) { - case '\b': printf("\\b"); break; - case '\t': printf("\\t"); break; - case '\n': printf("\\n"); break; - case '\f': printf("\\f"); break; - case '\r': printf("\\r"); break; - case '"': printf("\\\""); break; - case '\\': printf("\\\\"); break; - default: printf("%c", ch); break; + for ( ; *s; s++) { + int ch = *s; + switch (ch) { + case '\b': printf("\\b"); break; + case '\t': printf("\\t"); break; + case '\n': printf("\\n"); break; + case '\f': printf("\\f"); break; + case '\r': printf("\\r"); break; + case '"': printf("\\\""); break; + case '\\': printf("\\\\"); break; + default: printf("%c", ch); break; + } } - } } static void print_raw(const char* s) { - char* sval; - int64_t ival; - int bval; - double dval; - toml_timestamp_t ts; + char* sval; + int64_t ival; + int bval; + double dval; + toml_timestamp_t ts; + char dbuf[100]; - if (0 == toml_rtos(s, &sval)) { - printf("{\"type\":\"string\",\"value\":\""); - print_escape_string(sval); - printf("\"}"); - free(sval); - } else if (0 == toml_rtoi(s, &ival)) { - printf("{\"type\":\"integer\",\"value\":\"%" PRId64 "\"}", ival); - } else if (0 == toml_rtob(s, &bval)) { - printf("{\"type\":\"bool\",\"value\":\"%s\"}", bval ? "true" : "false"); - } else if (0 == toml_rtod(s, &dval)) { - printf("{\"type\":\"float\",\"value\":\"%s\"}", s); - } else if (0 == toml_rtots(s, &ts)) { - if (ts.year && ts.hour) { - printf("{\"type\":\"datetime\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%s\"}", - *ts.year, *ts.month, *ts.day, *ts.hour, *ts.minute, *ts.second, - (ts.z ? ts.z : "")); - } else if (ts.year) { - printf("{\"type\":\"date\",\"value\":\"%04d-%02d-%02d\"}", - *ts.year, *ts.month, *ts.day); - } else if (ts.hour) { - printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d\"}", - *ts.hour, *ts.minute, *ts.second); + if (0 == toml_rtos(s, &sval)) { + printf("{\"type\":\"string\",\"value\":\""); + print_escape_string(sval); + printf("\"}"); + free(sval); + } else if (0 == toml_rtoi(s, &ival)) { + printf("{\"type\":\"integer\",\"value\":\"%" PRId64 "\"}", ival); + } else if (0 == toml_rtob(s, &bval)) { + printf("{\"type\":\"bool\",\"value\":\"%s\"}", bval ? "true" : "false"); + } else if (0 == toml_rtod_ex(s, &dval, dbuf, sizeof(dbuf))) { + printf("{\"type\":\"float\",\"value\":\"%s\"}", dbuf); + } else if (0 == toml_rtots(s, &ts)) { + char millisec[10]; + if (ts.millisec) + sprintf(millisec, ".%d", *ts.millisec); + else + millisec[0] = 0; + if (ts.year && ts.hour) { + printf("{\"type\":\"datetime\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%s%s\"}", + *ts.year, *ts.month, *ts.day, *ts.hour, *ts.minute, *ts.second, + millisec, + (ts.z ? ts.z : "")); + } else if (ts.year) { + printf("{\"type\":\"date\",\"value\":\"%04d-%02d-%02d\"}", + *ts.year, *ts.month, *ts.day); + } else if (ts.hour) { + printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d%s\"}", + *ts.hour, *ts.minute, *ts.second, millisec); + } + } else { + fprintf(stderr, "unknown type\n"); + exit(1); } - } else { - fprintf(stderr, "unknown type\n"); - exit(1); - } } static void print_array(toml_array_t* arr); static void print_table(toml_table_t* curtab) { - int i; - const char* key; - const char* raw; - toml_array_t* arr; - toml_table_t* tab; + int i; + const char* key; + const char* raw; + toml_array_t* arr; + toml_table_t* tab; - printf("{"); - for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { + printf("{"); + for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { - printf("%s\"%s\":", i > 0 ? "," : "", key); + printf("%s\"", i > 0 ? "," : ""); + print_escape_string(key); + printf("\":"); - if (0 != (raw = toml_raw_in(curtab, key))) { - print_raw(raw); - } else if (0 != (arr = toml_array_in(curtab, key))) { - print_array(arr); - } else if (0 != (tab = toml_table_in(curtab, key))) { - print_table(tab); - } else { - abort(); + if (0 != (raw = toml_raw_in(curtab, key))) { + print_raw(raw); + } else if (0 != (arr = toml_array_in(curtab, key))) { + print_array(arr); + } else if (0 != (tab = toml_table_in(curtab, key))) { + print_table(tab); + } else { + abort(); + } } - } - printf("}"); + printf("}"); } static void print_table_array(toml_array_t* curarr) { - int i; - toml_table_t* tab; - - printf("["); - for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) { - printf("%s", i > 0 ? "," : ""); - print_table(tab); - } - printf("]"); + int i; + toml_table_t* tab; + + printf("["); + for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) { + printf("%s", i > 0 ? "," : ""); + print_table(tab); + } + printf("]"); } static void print_array(toml_array_t* curarr) { - toml_array_t* arr; - const char* raw; - int i; + toml_array_t* arr; + const char* raw; + int i; - if (toml_array_kind(curarr) == 't') { - print_table_array(curarr); - return; - } + if (toml_array_kind(curarr) == 't') { + print_table_array(curarr); + return; + } - printf("{\"type\":\"array\",\"value\":["); - switch (toml_array_kind(curarr)) { + printf("{\"type\":\"array\",\"value\":["); + switch (toml_array_kind(curarr)) { - case 'v': - for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { - printf("%s", i > 0 ? "," : ""); - print_raw(raw); + case 'v': + for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { + printf("%s", i > 0 ? "," : ""); + print_raw(raw); + } + break; + + case 'a': + for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) { + printf("%s", i > 0 ? "," : ""); + print_array(arr); + } + break; + + default: + break; } - break; - - case 'a': - for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) { - printf("%s", i > 0 ? "," : ""); - print_array(arr); - } - break; - - default: - break; - } - printf("]}"); + printf("]}"); } static void cat(FILE* fp) { - char errbuf[200]; - - toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); - if (!tab) { - fprintf(stderr, "ERROR: %s\n", errbuf); - exit(1); - } + char errbuf[200]; + + toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); + if (!tab) { + fprintf(stderr, "ERROR: %s\n", errbuf); + exit(1); + } - print_table(tab); - printf("\n"); + print_table(tab); + printf("\n"); - toml_free(tab); + toml_free(tab); } int main(int argc, const char* argv[]) { - int i; - if (argc == 1) { - cat(stdin); - } else { - for (i = 1; i < argc; i++) { - - FILE* fp = fopen(argv[i], "r"); - if (!fp) { - fprintf(stderr, "ERROR: cannot open %s: %s\n", - argv[i], strerror(errno)); - exit(1); - } - cat(fp); - fclose(fp); + int i; + if (argc == 1) { + cat(stdin); + } else { + for (i = 1; i < argc; i++) { + + FILE* fp = fopen(argv[i], "r"); + if (!fp) { + fprintf(stderr, "ERROR: cannot open %s: %s\n", + argv[i], strerror(errno)); + exit(1); + } + cat(fp); + fclose(fp); + } } - } - return 0; + return 0; } From 4a31cd8cbfbe2ccca69257be235bffd0d6e1fcce Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 12 Sep 2019 21:56:11 -0700 Subject: [PATCH 025/138] use the default CC per makefile var --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index fb94a3c..0032dc5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ -CC = gcc CFILES = toml.c CFLAGS = -std=c99 -Wall -Wextra -fpic From 9394192bfcc7f3c8a6b89275237a4302e788e624 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 26 Sep 2019 22:28:23 -0700 Subject: [PATCH 026/138] fix issue #22: add toml_set_memutil --- toml.c | 144 ++++++++++++++++++++++++++++++++++----------------------- toml.h | 49 +++++++++++--------- 2 files changed, 111 insertions(+), 82 deletions(-) diff --git a/toml.c b/toml.c index 2a9f3da..79b2b9b 100644 --- a/toml.c +++ b/toml.c @@ -1,26 +1,28 @@ /* -MIT License -Copyright (c) 2017 - 2019 CK Tan -https://github.com/cktan/tomlc99 + MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + Copyright (c) 2017 - 2019 CK Tan + https://github.com/cktan/tomlc99 + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. */ #define _POSIX_C_SOURCE 200809L #include @@ -33,11 +35,35 @@ SOFTWARE. #include #include "toml.h" + +static void* (*ppmalloc)(size_t) = malloc; +static void (*ppfree)(void*) = free; +static void* (*ppcalloc)(size_t, size_t) = calloc; +static void* (*pprealloc)(void*, size_t) = realloc; + +void toml_set_memutil(void* (*xxmalloc)(size_t), + void (*xxfree)(void*), + void* (*xxcalloc)(size_t, size_t), + void* (*xxrealloc)(void*, size_t)) +{ + ppmalloc = xxmalloc; + ppfree = xxfree; + ppcalloc = xxcalloc; + pprealloc = xxrealloc; +} + + +#define MALLOC(a) ppmalloc(a) +#define FREE(a) ppfree(a) +#define CALLOC(a,b) ppcalloc(a,b) +#define REALLOC(a,b) pprealloc(a,b) + + #ifdef _WIN32 char* strndup(const char* s, size_t n) { size_t len = strnlen(s, n); - char* p = malloc(len+1); + char* p = MALLOC(len+1); if (p) { memcpy(p, s, len); p[len] = 0; @@ -263,7 +289,7 @@ struct toml_table_t { }; -static inline void xfree(const void* x) { if (x) free((void*)x); } +static inline void xfree(const void* x) { if (x) FREE((void*)x); } enum tokentype_t { @@ -390,7 +416,7 @@ static char* normalize_string(const char* src, int srclen, /* scan forward on src */ for (;;) { if (off >= max - 10) { /* have some slack for misc stuff */ - char* x = realloc(dst, max += 100); + char* x = REALLOC(dst, max += 100); if (!x) { xfree(dst); snprintf(errbuf, errbufsz, "out of memory"); @@ -412,7 +438,7 @@ static char* normalize_string(const char* src, int srclen, /* ch was backslash. we expect the escape char. */ if (sp >= sq) { snprintf(errbuf, errbufsz, "last backslash is invalid"); - free(dst); + xfree(dst); return 0; } @@ -436,7 +462,7 @@ static char* normalize_string(const char* src, int srclen, for (int i = 0; i < nhex; i++) { if (sp >= sq) { snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); - free(dst); + xfree(dst); return 0; } ch = *sp++; @@ -445,7 +471,7 @@ static char* normalize_string(const char* src, int srclen, : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); if (-1 == v) { snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); - free(dst); + xfree(dst); return 0; } ucs = ucs * 16 + v; @@ -453,7 +479,7 @@ static char* normalize_string(const char* src, int srclen, int n = toml_ucs_to_utf8(ucs, &dst[off]); if (-1 == n) { snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); - free(dst); + xfree(dst); return 0; } off += n; @@ -469,7 +495,7 @@ static char* normalize_string(const char* src, int srclen, case '\\': ch = '\\'; break; default: snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); - free(dst); + xfree(dst); return 0; } @@ -517,7 +543,7 @@ static char* normalize_key(context_t* ctx, token_t strtok) /* newlines are not allowed in keys */ if (strchr(ret, '\n')) { - free(ret); + xfree(ret); e_bad_key_error(ctx, lineno); return 0; /* not reached */ } @@ -594,7 +620,7 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, /* if key exists: error out. */ toml_keyval_t* dest = 0; if (check_key(tab, newkey, 0, 0, 0)) { - free(newkey); + xfree(newkey); e_key_exists_error(ctx, keytok); return 0; /* not reached */ } @@ -602,15 +628,15 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, /* make a new entry */ int n = tab->nkval; toml_keyval_t** base; - if (0 == (base = (toml_keyval_t**) realloc(tab->kval, (n+1) * sizeof(*base)))) { - free(newkey); + if (0 == (base = (toml_keyval_t**) REALLOC(tab->kval, (n+1) * sizeof(*base)))) { + xfree(newkey); e_outofmemory(ctx, FLINE); return 0; /* not reached */ } tab->kval = base; - if (0 == (base[n] = (toml_keyval_t*) calloc(1, sizeof(*base[n])))) { - free(newkey); + if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); e_outofmemory(ctx, FLINE); return 0; /* not reached */ } @@ -634,7 +660,7 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, /* if key exists: error out */ toml_table_t* dest = 0; if (check_key(tab, newkey, 0, 0, &dest)) { - free(newkey); /* don't need this anymore */ + xfree(newkey); /* don't need this anymore */ /* special case: if table exists, but was created implicitly ... */ if (dest && dest->implicit) { @@ -649,15 +675,15 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, /* create a new table entry */ int n = tab->ntab; toml_table_t** base; - if (0 == (base = (toml_table_t**) realloc(tab->tab, (n+1) * sizeof(*base)))) { - free(newkey); + if (0 == (base = (toml_table_t**) REALLOC(tab->tab, (n+1) * sizeof(*base)))) { + xfree(newkey); e_outofmemory(ctx, FLINE); return 0; /* not reached */ } tab->tab = base; - if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { - free(newkey); + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); e_outofmemory(ctx, FLINE); return 0; /* not reached */ } @@ -684,7 +710,7 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, /* if key exists: error out */ toml_array_t* dest = 0; if (check_key(tab, newkey, 0, &dest, 0)) { - free(newkey); /* don't need this anymore */ + xfree(newkey); /* don't need this anymore */ /* special case skip if exists? */ if (skip_if_exist) return dest; @@ -696,15 +722,15 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, /* make a new array entry */ int n = tab->narr; toml_array_t** base; - if (0 == (base = (toml_array_t**) realloc(tab->arr, (n+1) * sizeof(*base)))) { - free(newkey); + if (0 == (base = (toml_array_t**) REALLOC(tab->arr, (n+1) * sizeof(*base)))) { + xfree(newkey); e_outofmemory(ctx, FLINE); return 0; /* not reached */ } tab->arr = base; - if (0 == (base[n] = (toml_array_t*) calloc(1, sizeof(*base[n])))) { - free(newkey); + if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); e_outofmemory(ctx, FLINE); return 0; /* not reached */ } @@ -722,13 +748,13 @@ static toml_array_t* create_array_in_array(context_t* ctx, { int n = parent->nelem; toml_array_t** base; - if (0 == (base = (toml_array_t**) realloc(parent->u.arr, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_array_t**) REALLOC(parent->u.arr, (n+1) * sizeof(*base)))) { e_outofmemory(ctx, FLINE); return 0; /* not reached */ } parent->u.arr = base; - if (0 == (base[n] = (toml_array_t*) calloc(1, sizeof(*base[n])))) { + if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { e_outofmemory(ctx, FLINE); return 0; /* not reached */ } @@ -743,13 +769,13 @@ static toml_table_t* create_table_in_array(context_t* ctx, { int n = parent->nelem; toml_table_t** base; - if (0 == (base = (toml_table_t**) realloc(parent->u.tab, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_table_t**) REALLOC(parent->u.tab, (n+1) * sizeof(*base)))) { e_outofmemory(ctx, FLINE); return 0; /* not reached */ } parent->u.tab = base; - if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { e_outofmemory(ctx, FLINE); return 0; /* not reached */ } @@ -852,7 +878,7 @@ static void parse_array(context_t* ctx, toml_array_t* arr) } /* make a new value in array */ - char** tmp = (char**) realloc(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); + char** tmp = (char**) REALLOC(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); if (!tmp) { e_outofmemory(ctx, FLINE); return; /* not reached */ @@ -1083,14 +1109,14 @@ static void walk_tabpath(context_t* ctx) default: { /* Not found. Let's create an implicit table. */ int n = curtab->ntab; - toml_table_t** base = (toml_table_t**) realloc(curtab->tab, (n+1) * sizeof(*base)); + toml_table_t** base = (toml_table_t**) REALLOC(curtab->tab, (n+1) * sizeof(*base)); if (0 == base) { e_outofmemory(ctx, FLINE); return; /* not reached */ } curtab->tab = base; - if (0 == (base[n] = (toml_table_t*) calloc(1, sizeof(*base[n])))) { + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { e_outofmemory(ctx, FLINE); return; /* not reached */ } @@ -1139,7 +1165,7 @@ static void parse_select(context_t* ctx) /* For [x.y.z] or [[x.y.z]], remove z from tpath. */ token_t z = ctx->tpath.tok[ctx->tpath.top-1]; - free(ctx->tpath.key[ctx->tpath.top-1]); + xfree(ctx->tpath.key[ctx->tpath.top-1]); ctx->tpath.top--; /* set up ctx->curtab */ @@ -1166,14 +1192,14 @@ static void parse_select(context_t* ctx) toml_table_t* dest; { int n = arr->nelem; - toml_table_t** base = realloc(arr->u.tab, (n+1) * sizeof(*base)); + toml_table_t** base = REALLOC(arr->u.tab, (n+1) * sizeof(*base)); if (0 == base) { e_outofmemory(ctx, FLINE); return; /* not reached */ } arr->u.tab = base; - if (0 == (base[n] = calloc(1, sizeof(*base[n])))) { + if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) { e_outofmemory(ctx, FLINE); return; /* not reached */ } @@ -1235,7 +1261,7 @@ toml_table_t* toml_parse(char* conf, ctx.tok.len = 0; // make a root table - if (0 == (ctx.root = calloc(1, sizeof(*ctx.root)))) { + if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { /* do not call outofmemory() here... setjmp not done yet */ snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE); return 0; @@ -1296,7 +1322,7 @@ toml_table_t* toml_parse_file(FILE* fp, /* prime the buf[] */ bufsz = 1000; - if (! (buf = malloc(bufsz + 1))) { + if (! (buf = MALLOC(bufsz + 1))) { snprintf(errbuf, errbufsz, "out of memory"); return 0; } @@ -1306,7 +1332,7 @@ toml_table_t* toml_parse_file(FILE* fp, bufsz += 1000; /* Allocate 1 extra byte because we will tag on a NUL */ - char* x = realloc(buf, bufsz + 1); + char* x = REALLOC(buf, bufsz + 1); if (!x) { snprintf(errbuf, errbufsz, "out of memory"); xfree(buf); @@ -1319,18 +1345,18 @@ toml_table_t* toml_parse_file(FILE* fp, if (ferror(fp)) { snprintf(errbuf, errbufsz, "%s", errno ? strerror(errno) : "Error reading file"); - free(buf); + xfree(buf); return 0; } off += n; } /* tag on a NUL to cap the string */ - buf[off] = 0; /* we accounted for this byte in the realloc() above. */ + buf[off] = 0; /* we accounted for this byte in the REALLOC() above. */ /* parse it, cleanup and finish */ toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); - free(buf); + xfree(buf); return ret; } diff --git a/toml.h b/toml.h index 6f23988..8acf3ee 100644 --- a/toml.h +++ b/toml.h @@ -1,26 +1,26 @@ /* -MIT License - -Copyright (c) 2017 - 2019 CK Tan -https://github.com/cktan/tomlc99 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + MIT License + + Copyright (c) 2017 - 2019 CK Tan + https://github.com/cktan/tomlc99 + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. */ #ifndef TOML_H #define TOML_H @@ -137,6 +137,9 @@ TOML_EXTERN int toml_rtots(const char* s, toml_timestamp_t* ret); /* misc */ TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); - +TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t), + void (*xxfree)(void*), + void* (*xxcalloc)(size_t, size_t), + void* (*xxrealloc)(void*, size_t)); #endif /* TOML_H */ From c5907e15049a1b557408f9f4183401e9b8e46f73 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Fri, 27 Sep 2019 16:32:59 -0700 Subject: [PATCH 027/138] use memutil functions for strdup and strndup --- toml.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/toml.c b/toml.c index 79b2b9b..2b834a3 100644 --- a/toml.c +++ b/toml.c @@ -58,9 +58,18 @@ void toml_set_memutil(void* (*xxmalloc)(size_t), #define CALLOC(a,b) ppcalloc(a,b) #define REALLOC(a,b) pprealloc(a,b) +char* STRDUP(const char* s) +{ + int len = strlen(s); + char* p = MALLOC(len+1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; +} -#ifdef _WIN32 -char* strndup(const char* s, size_t n) +char* STRNDUP(const char* s, size_t n) { size_t len = strnlen(s, n); char* p = MALLOC(len+1); @@ -70,7 +79,7 @@ char* strndup(const char* s, size_t n) } return p; } -#endif + /** @@ -528,7 +537,7 @@ static char* normalize_key(context_t* ctx, token_t strtok) if (ch == '\'') { /* for single quote, take it verbatim. */ - if (! (ret = strndup(sp, sq - sp))) { + if (! (ret = STRNDUP(sp, sq - sp))) { e_outofmemory(ctx, FLINE); return 0; /* not reached */ } @@ -561,7 +570,7 @@ static char* normalize_key(context_t* ctx, token_t strtok) } /* dup and return it */ - if (! (ret = strndup(sp, sq - sp))) { + if (! (ret = STRNDUP(sp, sq - sp))) { e_outofmemory(ctx, FLINE); return 0; /* not reached */ } @@ -884,7 +893,7 @@ static void parse_array(context_t* ctx, toml_array_t* arr) return; /* not reached */ } arr->u.val = tmp; - if (! (val = strndup(val, vlen))) { + if (! (val = STRNDUP(val, vlen))) { e_outofmemory(ctx, FLINE); return; /* not reached */ } @@ -981,7 +990,7 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab) toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); token_t val = ctx->tok; assert(keyval->val == 0); - keyval->val = strndup(val.ptr, val.len); + keyval->val = STRNDUP(val.ptr, val.len); if (! keyval->val) { e_outofmemory(ctx, FLINE); return; /* not reached */ @@ -1121,7 +1130,7 @@ static void walk_tabpath(context_t* ctx) return; /* not reached */ } - if (0 == (base[n]->key = strdup(key))) { + if (0 == (base[n]->key = STRDUP(key))) { e_outofmemory(ctx, FLINE); return; /* not reached */ } @@ -1204,7 +1213,7 @@ static void parse_select(context_t* ctx) return; /* not reached */ } - if (0 == (base[n]->key = strdup("__anon__"))) { + if (0 == (base[n]->key = STRDUP("__anon__"))) { e_outofmemory(ctx, FLINE); return; /* not reached */ } @@ -2006,7 +2015,7 @@ int toml_rtos(const char* src, char** ret) else if (sp[0] == '\r' && sp[1] == '\n') sp += 2; - *ret = kill_line_ending_backslash(strndup(sp, sq - sp)); + *ret = kill_line_ending_backslash(STRNDUP(sp, sq - sp)); } else { const char* sp = src + 1; const char* sq = src + srclen - 1; @@ -2014,7 +2023,7 @@ int toml_rtos(const char* src, char** ret) if (! (sp <= sq && *sq == '\'')) return -1; /* copy from sp to p */ - *ret = strndup(sp, sq - sp); + *ret = STRNDUP(sp, sq - sp); } return *ret ? 0 : -1; } From 15f44eba498a44aacf71554fc68e9a82defb9284 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 2 Oct 2019 01:11:34 -0700 Subject: [PATCH 028/138] tabify --- toml.c | 192 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/toml.c b/toml.c index 2b834a3..1917283 100644 --- a/toml.c +++ b/toml.c @@ -42,7 +42,7 @@ static void* (*ppcalloc)(size_t, size_t) = calloc; static void* (*pprealloc)(void*, size_t) = realloc; void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*), + void (*xxfree)(void*), void* (*xxcalloc)(size_t, size_t), void* (*xxrealloc)(void*, size_t)) { @@ -53,31 +53,31 @@ void toml_set_memutil(void* (*xxmalloc)(size_t), } -#define MALLOC(a) ppmalloc(a) -#define FREE(a) ppfree(a) -#define CALLOC(a,b) ppcalloc(a,b) +#define MALLOC(a) ppmalloc(a) +#define FREE(a) ppfree(a) +#define CALLOC(a,b) ppcalloc(a,b) #define REALLOC(a,b) pprealloc(a,b) char* STRDUP(const char* s) { int len = strlen(s); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; + char* p = MALLOC(len+1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; } char* STRNDUP(const char* s, size_t n) { - size_t len = strnlen(s, n); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; + size_t len = strnlen(s, n); + char* p = MALLOC(len+1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; } @@ -88,88 +88,88 @@ char* STRNDUP(const char* s, size_t n) */ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) { - const unsigned char* buf = (const unsigned char*) orig; - unsigned i = *buf++; - int64_t v; - - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (0 == (i >> 7)) { - if (len < 1) return -1; - v = i; - return *ret = v, 1; - } - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (0x6 == (i >> 5)) { - if (len < 2) return -1; - v = i & 0x1f; - for (int j = 0; j < 1; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + const unsigned char* buf = (const unsigned char*) orig; + unsigned i = *buf++; + int64_t v; + + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (0 == (i >> 7)) { + if (len < 1) return -1; + v = i; + return *ret = v, 1; + } + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (0x6 == (i >> 5)) { + if (len < 2) return -1; + v = i & 0x1f; + for (int j = 0; j < 1; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (0xE == (i >> 4)) { - if (len < 3) return -1; - v = i & 0x0F; - for (int j = 0; j < 2; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (0xE == (i >> 4)) { + if (len < 3) return -1; + v = i & 0x0F; + for (int j = 0; j < 2; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x1E == (i >> 3)) { - if (len < 4) return -1; - v = i & 0x07; - for (int j = 0; j < 3; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x3E == (i >> 2)) { - if (len < 5) return -1; - v = i & 0x03; - for (int j = 0; j < 4; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x1E == (i >> 3)) { + if (len < 4) return -1; + v = i & 0x07; + for (int j = 0; j < 3; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x3E == (i >> 2)) { + if (len < 5) return -1; + v = i & 0x03; + for (int j = 0; j < 4; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x7e == (i >> 1)) { - if (len < 6) return -1; - v = i & 0x01; - for (int j = 0; j < 5; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - return -1; + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x7e == (i >> 1)) { + if (len < 6) return -1; + v = i & 0x01; + for (int j = 0; j < 5; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + return -1; } From bc951780abdd7da8cddc5aadc88af67b260a86ab Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 2 Oct 2019 01:12:46 -0700 Subject: [PATCH 029/138] tabify --- toml.c | 2640 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 1320 insertions(+), 1320 deletions(-) diff --git a/toml.c b/toml.c index 1917283..3a47f7e 100644 --- a/toml.c +++ b/toml.c @@ -174,127 +174,127 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) /** - * Convert a UCS char to utf8 code, and return it in buf. - * Return #bytes used in buf to encode the char, or - * -1 on error. + * Convert a UCS char to utf8 code, and return it in buf. + * Return #bytes used in buf to encode the char, or + * -1 on error. */ int toml_ucs_to_utf8(int64_t code, char buf[6]) { - /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 */ - /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well - * as 0xfffe and 0xffff (UCS noncharacters) should not appear in - * conforming UTF-8 streams. - */ - if (0xd800 <= code && code <= 0xdfff) return -1; - if (0xfffe <= code && code <= 0xffff) return -1; + /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 */ + /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well + * as 0xfffe and 0xffff (UCS noncharacters) should not appear in + * conforming UTF-8 streams. + */ + if (0xd800 <= code && code <= 0xdfff) return -1; + if (0xfffe <= code && code <= 0xffff) return -1; - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (code < 0) return -1; - if (code <= 0x7F) { - buf[0] = (unsigned char) code; - return 1; - } + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (code < 0) return -1; + if (code <= 0x7F) { + buf[0] = (unsigned char) code; + return 1; + } - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (code <= 0x000007FF) { - buf[0] = 0xc0 | (code >> 6); - buf[1] = 0x80 | (code & 0x3f); - return 2; - } + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (code <= 0x000007FF) { + buf[0] = 0xc0 | (code >> 6); + buf[1] = 0x80 | (code & 0x3f); + return 2; + } - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x0000FFFF) { - buf[0] = 0xe0 | (code >> 12); - buf[1] = 0x80 | ((code >> 6) & 0x3f); - buf[2] = 0x80 | (code & 0x3f); - return 3; - } + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x0000FFFF) { + buf[0] = 0xe0 | (code >> 12); + buf[1] = 0x80 | ((code >> 6) & 0x3f); + buf[2] = 0x80 | (code & 0x3f); + return 3; + } - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x001FFFFF) { - buf[0] = 0xf0 | (code >> 18); - buf[1] = 0x80 | ((code >> 12) & 0x3f); - buf[2] = 0x80 | ((code >> 6) & 0x3f); - buf[3] = 0x80 | (code & 0x3f); - return 4; - } + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x001FFFFF) { + buf[0] = 0xf0 | (code >> 18); + buf[1] = 0x80 | ((code >> 12) & 0x3f); + buf[2] = 0x80 | ((code >> 6) & 0x3f); + buf[3] = 0x80 | (code & 0x3f); + return 4; + } - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x03FFFFFF) { - buf[0] = 0xf8 | (code >> 24); - buf[1] = 0x80 | ((code >> 18) & 0x3f); - buf[2] = 0x80 | ((code >> 12) & 0x3f); - buf[3] = 0x80 | ((code >> 6) & 0x3f); - buf[4] = 0x80 | (code & 0x3f); - return 5; - } - - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x7FFFFFFF) { - buf[0] = 0xfc | (code >> 30); - buf[1] = 0x80 | ((code >> 24) & 0x3f); - buf[2] = 0x80 | ((code >> 18) & 0x3f); - buf[3] = 0x80 | ((code >> 12) & 0x3f); - buf[4] = 0x80 | ((code >> 6) & 0x3f); - buf[5] = 0x80 | (code & 0x3f); - return 6; - } + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x03FFFFFF) { + buf[0] = 0xf8 | (code >> 24); + buf[1] = 0x80 | ((code >> 18) & 0x3f); + buf[2] = 0x80 | ((code >> 12) & 0x3f); + buf[3] = 0x80 | ((code >> 6) & 0x3f); + buf[4] = 0x80 | (code & 0x3f); + return 5; + } + + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x7FFFFFFF) { + buf[0] = 0xfc | (code >> 30); + buf[1] = 0x80 | ((code >> 24) & 0x3f); + buf[2] = 0x80 | ((code >> 18) & 0x3f); + buf[3] = 0x80 | ((code >> 12) & 0x3f); + buf[4] = 0x80 | ((code >> 6) & 0x3f); + buf[5] = 0x80 | (code & 0x3f); + return 6; + } - return -1; + return -1; } /* - * TOML has 3 data structures: value, array, table. - * Each of them can have identification key. + * TOML has 3 data structures: value, array, table. + * Each of them can have identification key. */ typedef struct toml_keyval_t toml_keyval_t; struct toml_keyval_t { - const char* key; /* key to this value */ - const char* val; /* the raw value */ + const char* key; /* key to this value */ + const char* val; /* the raw value */ }; struct toml_array_t { - const char* key; /* key to this array */ - int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */ - int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ - - int nelem; /* number of elements */ - union { - char** val; - toml_array_t** arr; - toml_table_t** tab; - } u; + const char* key; /* key to this array */ + int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */ + int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ + + int nelem; /* number of elements */ + union { + char** val; + toml_array_t** arr; + toml_table_t** tab; + } u; }; - + struct toml_table_t { - const char* key; /* key to this table */ - int implicit; /* table was created implicitly */ + const char* key; /* key to this table */ + int implicit; /* table was created implicitly */ - /* key-values in the table */ - int nkval; - toml_keyval_t** kval; + /* key-values in the table */ + int nkval; + toml_keyval_t** kval; - /* arrays in the table */ - int narr; - toml_array_t** arr; + /* arrays in the table */ + int narr; + toml_array_t** arr; - /* tables in the table */ - int ntab; - toml_table_t** tab; + /* tables in the table */ + int ntab; + toml_table_t** tab; }; @@ -302,51 +302,51 @@ static inline void xfree(const void* x) { if (x) FREE((void*)x); } enum tokentype_t { - INVALID, - DOT, - COMMA, - EQUAL, - LBRACE, - RBRACE, - NEWLINE, - LBRACKET, - RBRACKET, - STRING, + INVALID, + DOT, + COMMA, + EQUAL, + LBRACE, + RBRACE, + NEWLINE, + LBRACKET, + RBRACKET, + STRING, }; typedef enum tokentype_t tokentype_t; typedef struct token_t token_t; struct token_t { - tokentype_t tok; - int lineno; - char* ptr; /* points into context->start */ - int len; - int eof; + tokentype_t tok; + int lineno; + char* ptr; /* points into context->start */ + int len; + int eof; }; typedef struct context_t context_t; struct context_t { - char* start; - char* stop; - char* errbuf; - int errbufsz; - jmp_buf jmp; + char* start; + char* stop; + char* errbuf; + int errbufsz; + jmp_buf jmp; - token_t tok; - toml_table_t* root; - toml_table_t* curtab; + token_t tok; + toml_table_t* root; + toml_table_t* curtab; - struct { - int top; - char* key[10]; - token_t tok[10]; - } tpath; + struct { + int top; + char* key[10]; + token_t tok[10]; + } tpath; }; #define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) +#define TOSTRING(x) STRINGIFY(x) #define FLINE __FILE__ ":" TOSTRING(__LINE__) static tokentype_t next_token(context_t* ctx, int dotisspecial); @@ -354,55 +354,55 @@ static tokentype_t next_token(context_t* ctx, int dotisspecial); /* error routines. All these functions longjmp to ctx->jmp */ static int e_outofmemory(context_t* ctx, const char* fline) { - snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); + longjmp(ctx->jmp, 1); + return -1; } static int e_internal_error(context_t* ctx, const char* fline) { - snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); + longjmp(ctx->jmp, 1); + return -1; } static int e_syntax_error(context_t* ctx, int lineno, const char* msg) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); + longjmp(ctx->jmp, 1); + return -1; } static int e_bad_key_error(context_t* ctx, int lineno) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); + longjmp(ctx->jmp, 1); + return -1; } /* static int e_noimpl(context_t* ctx, const char* feature) { - snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature); + longjmp(ctx->jmp, 1); + return -1; } */ static int e_key_exists_error(context_t* ctx, token_t keytok) { - char buf[100]; - int i; - for (i = 0; i < keytok.len && i < (int)sizeof(buf) - 1; i++) { - buf[i] = keytok.ptr[i]; - } - buf[i] = 0; + char buf[100]; + int i; + for (i = 0; i < keytok.len && i < (int)sizeof(buf) - 1; i++) { + buf[i] = keytok.ptr[i]; + } + buf[i] = 0; - snprintf(ctx->errbuf, ctx->errbufsz, - "line %d: key %s exists", keytok.lineno, buf); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, + "line %d: key %s exists", keytok.lineno, buf); + longjmp(ctx->jmp, 1); + return -1; } @@ -412,169 +412,169 @@ static int e_key_exists_error(context_t* ctx, token_t keytok) * Returns NULL if error with errmsg in errbuf. */ static char* normalize_string(const char* src, int srclen, - int kill_line_ending_backslash, - char* errbuf, int errbufsz) + int kill_line_ending_backslash, + char* errbuf, int errbufsz) { - char* dst = 0; /* will write to dst[] and return it */ - int max = 0; /* max size of dst[] */ - int off = 0; /* cur offset in dst[] */ - const char* sp = src; - const char* sq = src + srclen; - int ch; + char* dst = 0; /* will write to dst[] and return it */ + int max = 0; /* max size of dst[] */ + int off = 0; /* cur offset in dst[] */ + const char* sp = src; + const char* sq = src + srclen; + int ch; - /* scan forward on src */ - for (;;) { - if (off >= max - 10) { /* have some slack for misc stuff */ - char* x = REALLOC(dst, max += 100); - if (!x) { - xfree(dst); - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - dst = x; - } - - /* finished? */ - if (sp >= sq) break; - - ch = *sp++; - if (ch != '\\') { - // a plain copy suffice - dst[off++] = ch; - continue; - } + /* scan forward on src */ + for (;;) { + if (off >= max - 10) { /* have some slack for misc stuff */ + char* x = REALLOC(dst, max += 100); + if (!x) { + xfree(dst); + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + dst = x; + } + + /* finished? */ + if (sp >= sq) break; + + ch = *sp++; + if (ch != '\\') { + // a plain copy suffice + dst[off++] = ch; + continue; + } - /* ch was backslash. we expect the escape char. */ - if (sp >= sq) { - snprintf(errbuf, errbufsz, "last backslash is invalid"); - xfree(dst); - return 0; - } + /* ch was backslash. we expect the escape char. */ + if (sp >= sq) { + snprintf(errbuf, errbufsz, "last backslash is invalid"); + xfree(dst); + return 0; + } - /* if we want to kill line-ending-backslash ... */ - if (kill_line_ending_backslash) { - /* if this is a newline immediately following the backslash ... */ - if (*sp == '\n' || (*sp == '\r' && sp[1] == '\n')) { - /* skip all the following whitespaces */ - sp += strspn(sp, " \t\r\n"); - continue; - } - } + /* if we want to kill line-ending-backslash ... */ + if (kill_line_ending_backslash) { + /* if this is a newline immediately following the backslash ... */ + if (*sp == '\n' || (*sp == '\r' && sp[1] == '\n')) { + /* skip all the following whitespaces */ + sp += strspn(sp, " \t\r\n"); + continue; + } + } - /* get the escaped char */ - ch = *sp++; - switch (ch) { - case 'u': case 'U': - { - int64_t ucs = 0; - int nhex = (ch == 'u' ? 4 : 8); - for (int i = 0; i < nhex; i++) { - if (sp >= sq) { - snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); - xfree(dst); - return 0; - } - ch = *sp++; - int v = ('0' <= ch && ch <= '9') - ? ch - '0' - : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); - if (-1 == v) { - snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); - xfree(dst); - return 0; - } - ucs = ucs * 16 + v; - } - int n = toml_ucs_to_utf8(ucs, &dst[off]); - if (-1 == n) { - snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); - xfree(dst); - return 0; - } - off += n; - } - continue; + /* get the escaped char */ + ch = *sp++; + switch (ch) { + case 'u': case 'U': + { + int64_t ucs = 0; + int nhex = (ch == 'u' ? 4 : 8); + for (int i = 0; i < nhex; i++) { + if (sp >= sq) { + snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); + xfree(dst); + return 0; + } + ch = *sp++; + int v = ('0' <= ch && ch <= '9') + ? ch - '0' + : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); + if (-1 == v) { + snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); + xfree(dst); + return 0; + } + ucs = ucs * 16 + v; + } + int n = toml_ucs_to_utf8(ucs, &dst[off]); + if (-1 == n) { + snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); + xfree(dst); + return 0; + } + off += n; + } + continue; - case 'b': ch = '\b'; break; - case 't': ch = '\t'; break; - case 'n': ch = '\n'; break; - case 'f': ch = '\f'; break; - case 'r': ch = '\r'; break; - case '"': ch = '"'; break; - case '\\': ch = '\\'; break; - default: - snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); - xfree(dst); - return 0; - } + case 'b': ch = '\b'; break; + case 't': ch = '\t'; break; + case 'n': ch = '\n'; break; + case 'f': ch = '\f'; break; + case 'r': ch = '\r'; break; + case '"': ch = '"'; break; + case '\\': ch = '\\'; break; + default: + snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); + xfree(dst); + return 0; + } - dst[off++] = ch; - } + dst[off++] = ch; + } - // Cap with NUL and return it. - dst[off++] = 0; - return dst; + // Cap with NUL and return it. + dst[off++] = 0; + return dst; } /* Normalize a key. Convert all special chars to raw unescaped utf-8 chars. */ static char* normalize_key(context_t* ctx, token_t strtok) { - const char* sp = strtok.ptr; - const char* sq = strtok.ptr + strtok.len; - int lineno = strtok.lineno; - char* ret; - int ch = *sp; - char ebuf[80]; + const char* sp = strtok.ptr; + const char* sq = strtok.ptr + strtok.len; + int lineno = strtok.lineno; + char* ret; + int ch = *sp; + char ebuf[80]; - /* handle quoted string */ - if (ch == '\'' || ch == '\"') { - /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ - if (sp[1] == ch && sp[2] == ch) - sp += 3, sq -= 3; - else - sp++, sq--; + /* handle quoted string */ + if (ch == '\'' || ch == '\"') { + /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ + if (sp[1] == ch && sp[2] == ch) + sp += 3, sq -= 3; + else + sp++, sq--; - if (ch == '\'') { - /* for single quote, take it verbatim. */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - } else { - /* for double quote, we need to normalize */ - ret = normalize_string(sp, sq - sp, 0, ebuf, sizeof(ebuf)); - if (!ret) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); - longjmp(ctx->jmp, 1); - } - } + if (ch == '\'') { + /* for single quote, take it verbatim. */ + if (! (ret = STRNDUP(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + } else { + /* for double quote, we need to normalize */ + ret = normalize_string(sp, sq - sp, 0, ebuf, sizeof(ebuf)); + if (!ret) { + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); + longjmp(ctx->jmp, 1); + } + } - /* newlines are not allowed in keys */ - if (strchr(ret, '\n')) { - xfree(ret); - e_bad_key_error(ctx, lineno); - return 0; /* not reached */ - } - return ret; - } - - /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ - const char* xp; - for (xp = sp; xp != sq; xp++) { - int k = *xp; - if (isalnum(k)) continue; - if (k == '_' || k == '-') continue; - e_bad_key_error(ctx, lineno); - return 0; /* not reached */ - } + /* newlines are not allowed in keys */ + if (strchr(ret, '\n')) { + xfree(ret); + e_bad_key_error(ctx, lineno); + return 0; /* not reached */ + } + return ret; + } + + /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ + const char* xp; + for (xp = sp; xp != sq; xp++) { + int k = *xp; + if (isalnum(k)) continue; + if (k == '_' || k == '-') continue; + e_bad_key_error(ctx, lineno); + return 0; /* not reached */ + } - /* dup and return it */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - return ret; + /* dup and return it */ + if (! (ret = STRNDUP(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + return ret; } @@ -583,77 +583,77 @@ static char* normalize_key(context_t* ctx, token_t strtok) * 'v'alue, 'a'rray or 't'able depending on the element. */ 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) + toml_keyval_t** ret_val, + toml_array_t** ret_arr, + toml_table_t** ret_tab) { - int i; - void* dummy; + int i; + void* dummy; - if (!ret_tab) ret_tab = (toml_table_t**) &dummy; - if (!ret_arr) ret_arr = (toml_array_t**) &dummy; - if (!ret_val) ret_val = (toml_keyval_t**) &dummy; + if (!ret_tab) ret_tab = (toml_table_t**) &dummy; + if (!ret_arr) ret_arr = (toml_array_t**) &dummy; + if (!ret_val) ret_val = (toml_keyval_t**) &dummy; - *ret_tab = 0; *ret_arr = 0; *ret_val = 0; - - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) { - *ret_val = tab->kval[i]; - return 'v'; - } - } - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) { - *ret_arr = tab->arr[i]; - return 'a'; - } - } - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) { - *ret_tab = tab->tab[i]; - return 't'; - } - } - return 0; + *ret_tab = 0; *ret_arr = 0; *ret_val = 0; + + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) { + *ret_val = tab->kval[i]; + return 'v'; + } + } + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) { + *ret_arr = tab->arr[i]; + return 'a'; + } + } + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) { + *ret_tab = tab->tab[i]; + return 't'; + } + } + return 0; } /* Create a keyval in the table. */ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); - /* if key exists: error out. */ - toml_keyval_t* dest = 0; - if (check_key(tab, newkey, 0, 0, 0)) { - xfree(newkey); - e_key_exists_error(ctx, keytok); - return 0; /* not reached */ - } + /* if key exists: error out. */ + toml_keyval_t* dest = 0; + if (check_key(tab, newkey, 0, 0, 0)) { + xfree(newkey); + e_key_exists_error(ctx, keytok); + return 0; /* not reached */ + } - /* make a new entry */ - int n = tab->nkval; - toml_keyval_t** base; - if (0 == (base = (toml_keyval_t**) REALLOC(tab->kval, (n+1) * sizeof(*base)))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - tab->kval = base; - - if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - dest = tab->kval[tab->nkval++]; + /* make a new entry */ + int n = tab->nkval; + toml_keyval_t** base; + if (0 == (base = (toml_keyval_t**) REALLOC(tab->kval, (n+1) * sizeof(*base)))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + tab->kval = base; + + if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + dest = tab->kval[tab->nkval++]; - /* save the key in the new value struct */ - dest->key = newkey; - return dest; + /* save the key in the new value struct */ + dest->key = newkey; + return dest; } @@ -661,141 +661,141 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, */ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); - /* if key exists: error out */ - toml_table_t* dest = 0; - if (check_key(tab, newkey, 0, 0, &dest)) { - xfree(newkey); /* don't need this anymore */ - - /* special case: if table exists, but was created implicitly ... */ - if (dest && dest->implicit) { - /* we make it explicit now, and simply return it. */ - dest->implicit = 0; - return dest; - } - e_key_exists_error(ctx, keytok); - return 0; /* not reached */ - } + /* if key exists: error out */ + toml_table_t* dest = 0; + if (check_key(tab, newkey, 0, 0, &dest)) { + xfree(newkey); /* don't need this anymore */ + + /* special case: if table exists, but was created implicitly ... */ + if (dest && dest->implicit) { + /* we make it explicit now, and simply return it. */ + dest->implicit = 0; + return dest; + } + e_key_exists_error(ctx, keytok); + return 0; /* not reached */ + } - /* create a new table entry */ - int n = tab->ntab; - toml_table_t** base; - if (0 == (base = (toml_table_t**) REALLOC(tab->tab, (n+1) * sizeof(*base)))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - tab->tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - dest = tab->tab[tab->ntab++]; - - /* save the key in the new table struct */ - dest->key = newkey; - return dest; + /* create a new table entry */ + int n = tab->ntab; + toml_table_t** base; + if (0 == (base = (toml_table_t**) REALLOC(tab->tab, (n+1) * sizeof(*base)))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + tab->tab = base; + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + dest = tab->tab[tab->ntab++]; + + /* save the key in the new table struct */ + dest->key = newkey; + return dest; } /* Create an array in the table. */ static toml_array_t* create_keyarray_in_table(context_t* ctx, - toml_table_t* tab, - token_t keytok, - int skip_if_exist) + toml_table_t* tab, + token_t keytok, + int skip_if_exist) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); - - /* if key exists: error out */ - toml_array_t* dest = 0; - if (check_key(tab, newkey, 0, &dest, 0)) { - xfree(newkey); /* don't need this anymore */ + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); + + /* if key exists: error out */ + toml_array_t* dest = 0; + if (check_key(tab, newkey, 0, &dest, 0)) { + xfree(newkey); /* don't need this anymore */ - /* special case skip if exists? */ - if (skip_if_exist) return dest; - - e_key_exists_error(ctx, keytok); - return 0; /* not reached */ - } + /* special case skip if exists? */ + if (skip_if_exist) return dest; + + e_key_exists_error(ctx, keytok); + return 0; /* not reached */ + } - /* make a new array entry */ - int n = tab->narr; - toml_array_t** base; - if (0 == (base = (toml_array_t**) REALLOC(tab->arr, (n+1) * sizeof(*base)))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - tab->arr = base; - - if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - dest = tab->arr[tab->narr++]; + /* make a new array entry */ + int n = tab->narr; + toml_array_t** base; + if (0 == (base = (toml_array_t**) REALLOC(tab->arr, (n+1) * sizeof(*base)))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + tab->arr = base; + + if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + dest = tab->arr[tab->narr++]; - /* save the key in the new array struct */ - dest->key = newkey; - return dest; + /* save the key in the new array struct */ + dest->key = newkey; + return dest; } /* Create an array in an array */ static toml_array_t* create_array_in_array(context_t* ctx, - toml_array_t* parent) + toml_array_t* parent) { - int n = parent->nelem; - toml_array_t** base; - if (0 == (base = (toml_array_t**) REALLOC(parent->u.arr, (n+1) * sizeof(*base)))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - parent->u.arr = base; - - if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } + int n = parent->nelem; + toml_array_t** base; + if (0 == (base = (toml_array_t**) REALLOC(parent->u.arr, (n+1) * sizeof(*base)))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + parent->u.arr = base; + + if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } - return parent->u.arr[parent->nelem++]; + return parent->u.arr[parent->nelem++]; } /* Create a table in an array */ static toml_table_t* create_table_in_array(context_t* ctx, - toml_array_t* parent) + toml_array_t* parent) { - int n = parent->nelem; - toml_table_t** base; - if (0 == (base = (toml_table_t**) REALLOC(parent->u.tab, (n+1) * sizeof(*base)))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - parent->u.tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } + int n = parent->nelem; + toml_table_t** base; + if (0 == (base = (toml_table_t**) REALLOC(parent->u.tab, (n+1) * sizeof(*base)))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + parent->u.tab = base; + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } - return parent->u.tab[parent->nelem++]; + return parent->u.tab[parent->nelem++]; } -#define SKIP_NEWLINES(ctx) while (ctx->tok.tok == NEWLINE) next_token(ctx, 0) +#define SKIP_NEWLINES(ctx) while (ctx->tok.tok == NEWLINE) next_token(ctx, 0) #define EAT_TOKEN(ctx, typ) \ - if ((ctx)->tok.tok != typ) e_internal_error(ctx, FLINE); else next_token(ctx, 0) + if ((ctx)->tok.tok != typ) e_internal_error(ctx, FLINE); else next_token(ctx, 0) static void parse_keyval(context_t* ctx, toml_table_t* tab); @@ -806,226 +806,226 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab); */ static void parse_table(context_t* ctx, toml_table_t* tab) { - EAT_TOKEN(ctx, LBRACE); + EAT_TOKEN(ctx, LBRACE); - for (;;) { + for (;;) { if (ctx->tok.tok == NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); return; /* not reached */ } - /* until } */ - if (ctx->tok.tok == RBRACE) break; + /* until } */ + if (ctx->tok.tok == RBRACE) break; - if (ctx->tok.tok != STRING) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } - parse_keyval(ctx, tab); + if (ctx->tok.tok != STRING) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } + parse_keyval(ctx, tab); if (ctx->tok.tok == NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); return; /* not reached */ } - /* on comma, continue to scan for next keyval */ - if (ctx->tok.tok == COMMA) { - EAT_TOKEN(ctx, COMMA); - continue; - } - break; - } + /* on comma, continue to scan for next keyval */ + if (ctx->tok.tok == COMMA) { + EAT_TOKEN(ctx, COMMA); + continue; + } + break; + } - if (ctx->tok.tok != RBRACE) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + if (ctx->tok.tok != RBRACE) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } - EAT_TOKEN(ctx, RBRACE); + EAT_TOKEN(ctx, RBRACE); } static int valtype(const char* val) { - toml_timestamp_t ts; - if (*val == '\'' || *val == '"') return 's'; - if (0 == toml_rtob(val, 0)) return 'b'; - if (0 == toml_rtoi(val, 0)) return 'i'; - if (0 == toml_rtod(val, 0)) return 'd'; - if (0 == toml_rtots(val, &ts)) { - if (ts.year && ts.hour) return 'T'; /* timestamp */ - if (ts.year) return 'D'; /* date */ - return 't'; /* time */ - } - return 'u'; /* unknown */ + toml_timestamp_t ts; + if (*val == '\'' || *val == '"') return 's'; + if (0 == toml_rtob(val, 0)) return 'b'; + if (0 == toml_rtoi(val, 0)) return 'i'; + if (0 == toml_rtod(val, 0)) return 'd'; + if (0 == toml_rtots(val, &ts)) { + if (ts.year && ts.hour) return 'T'; /* timestamp */ + if (ts.year) return 'D'; /* date */ + return 't'; /* time */ + } + return 'u'; /* unknown */ } /* We are at '[...]' */ static void parse_array(context_t* ctx, toml_array_t* arr) { - EAT_TOKEN(ctx, LBRACKET); + EAT_TOKEN(ctx, LBRACKET); - for (;;) { - SKIP_NEWLINES(ctx); - - /* until ] */ - if (ctx->tok.tok == RBRACKET) break; + for (;;) { + SKIP_NEWLINES(ctx); + + /* until ] */ + if (ctx->tok.tok == RBRACKET) break; - switch (ctx->tok.tok) { - case STRING: - { - char* val = ctx->tok.ptr; - int vlen = ctx->tok.len; + switch (ctx->tok.tok) { + case STRING: + { + char* val = ctx->tok.ptr; + int vlen = ctx->tok.len; - /* set array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'v'; - /* check array kind */ - if (arr->kind != 'v') { - e_syntax_error(ctx, ctx->tok.lineno, - "a string array can only contain strings"); - return; /* not reached */ - } + /* set array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'v'; + /* check array kind */ + if (arr->kind != 'v') { + e_syntax_error(ctx, ctx->tok.lineno, + "a string array can only contain strings"); + return; /* not reached */ + } - /* make a new value in array */ - char** tmp = (char**) REALLOC(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); - if (!tmp) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - arr->u.val = tmp; - if (! (val = STRNDUP(val, vlen))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - arr->u.val[arr->nelem++] = val; + /* make a new value in array */ + char** tmp = (char**) REALLOC(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); + if (!tmp) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + arr->u.val = tmp; + if (! (val = STRNDUP(val, vlen))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + arr->u.val[arr->nelem++] = val; - /* set array type if this is the first entry, or check that the types matched. */ - if (arr->nelem == 1) - arr->type = valtype(arr->u.val[0]); - else if (arr->type != valtype(val)) { - e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); - return; /* not reached */ - } + /* set array type if this is the first entry, or check that the types matched. */ + if (arr->nelem == 1) + arr->type = valtype(arr->u.val[0]); + else if (arr->type != valtype(val)) { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + return; /* not reached */ + } - EAT_TOKEN(ctx, STRING); - break; - } + EAT_TOKEN(ctx, STRING); + break; + } - case LBRACKET: - { /* [ [array], [array] ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'a'; - /* check array kind */ - if (arr->kind != 'a') { - e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); - return; /* not reached */ - } - parse_array(ctx, create_array_in_array(ctx, arr)); - break; - } + case LBRACKET: + { /* [ [array], [array] ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'a'; + /* check array kind */ + if (arr->kind != 'a') { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + return; /* not reached */ + } + parse_array(ctx, create_array_in_array(ctx, arr)); + break; + } - case LBRACE: - { /* [ {table}, {table} ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 't'; - /* check array kind */ - if (arr->kind != 't') { - e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); - return; /* not reached */ - } - parse_table(ctx, create_table_in_array(ctx, arr)); - break; - } - - default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + case LBRACE: + { /* [ {table}, {table} ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 't'; + /* check array kind */ + if (arr->kind != 't') { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); + return; /* not reached */ + } + parse_table(ctx, create_table_in_array(ctx, arr)); + break; + } + + default: + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } - SKIP_NEWLINES(ctx); + SKIP_NEWLINES(ctx); - /* on comma, continue to scan for next element */ - if (ctx->tok.tok == COMMA) { - EAT_TOKEN(ctx, COMMA); - continue; - } - break; - } + /* on comma, continue to scan for next element */ + if (ctx->tok.tok == COMMA) { + EAT_TOKEN(ctx, COMMA); + continue; + } + break; + } - if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + if (ctx->tok.tok != RBRACKET) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } - EAT_TOKEN(ctx, RBRACKET); + EAT_TOKEN(ctx, RBRACKET); } /* handle lines like these: - key = "value" - key = [ array ] - key = { table } + key = "value" + key = [ array ] + key = { table } */ static void parse_keyval(context_t* ctx, toml_table_t* tab) { - if (ctx->tok.tok != STRING) { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } + if (ctx->tok.tok != STRING) { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } - token_t key = ctx->tok; + token_t key = ctx->tok; - EAT_TOKEN(ctx, STRING); - if (ctx->tok.tok != EQUAL) { - e_syntax_error(ctx, ctx->tok.lineno, "missing ="); - return; /* not reached */ - } + EAT_TOKEN(ctx, STRING); + if (ctx->tok.tok != EQUAL) { + e_syntax_error(ctx, ctx->tok.lineno, "missing ="); + return; /* not reached */ + } - EAT_TOKEN(ctx, EQUAL); + EAT_TOKEN(ctx, EQUAL); - switch (ctx->tok.tok) { - case STRING: - { /* key = "value" */ - toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); - token_t val = ctx->tok; - assert(keyval->val == 0); - keyval->val = STRNDUP(val.ptr, val.len); - if (! keyval->val) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + switch (ctx->tok.tok) { + case STRING: + { /* key = "value" */ + toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); + token_t val = ctx->tok; + assert(keyval->val == 0); + keyval->val = STRNDUP(val.ptr, val.len); + if (! keyval->val) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } - EAT_TOKEN(ctx, STRING); - - return; - } + EAT_TOKEN(ctx, STRING); + + return; + } - case LBRACKET: - { /* key = [ array ] */ - toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); - parse_array(ctx, arr); - return; - } + case LBRACKET: + { /* key = [ array ] */ + toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); + parse_array(ctx, arr); + return; + } - case LBRACE: - { /* key = { table } */ - toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); - parse_table(ctx, nxttab); - return; - } + case LBRACE: + { /* key = { table } */ + toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); + parse_table(ctx, nxttab); + return; + } - default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + default: + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } } typedef struct tabpath_t tabpath_t; struct tabpath_t { - int cnt; - token_t key[10]; + int cnt; + token_t key[10]; }; /* at [x.y.z] or [[x.y.z]] @@ -1034,48 +1034,48 @@ struct tabpath_t { */ static void fill_tabpath(context_t* ctx) { - int lineno = ctx->tok.lineno; - int i; - - /* clear tpath */ - for (i = 0; i < ctx->tpath.top; i++) { - char** p = &ctx->tpath.key[i]; - xfree(*p); - *p = 0; - } - ctx->tpath.top = 0; - - for (;;) { - if (ctx->tpath.top >= 10) { - e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); - return; /* not reached */ - } + int lineno = ctx->tok.lineno; + int i; + + /* clear tpath */ + for (i = 0; i < ctx->tpath.top; i++) { + char** p = &ctx->tpath.key[i]; + xfree(*p); + *p = 0; + } + ctx->tpath.top = 0; + + for (;;) { + if (ctx->tpath.top >= 10) { + e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); + return; /* not reached */ + } - if (ctx->tok.tok != STRING) { - e_syntax_error(ctx, lineno, "invalid or missing key"); - return; /* not reached */ - } + if (ctx->tok.tok != STRING) { + e_syntax_error(ctx, lineno, "invalid or missing key"); + return; /* not reached */ + } - ctx->tpath.tok[ctx->tpath.top] = ctx->tok; - ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); - ctx->tpath.top++; - - next_token(ctx, 1); + ctx->tpath.tok[ctx->tpath.top] = ctx->tok; + ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); + ctx->tpath.top++; + + next_token(ctx, 1); - if (ctx->tok.tok == RBRACKET) break; + if (ctx->tok.tok == RBRACKET) break; - if (ctx->tok.tok != DOT) { - e_syntax_error(ctx, lineno, "invalid key"); - return; /* not reached */ - } + if (ctx->tok.tok != DOT) { + e_syntax_error(ctx, lineno, "invalid key"); + return; /* not reached */ + } - next_token(ctx, 1); - } + next_token(ctx, 1); + } - if (ctx->tpath.top <= 0) { - e_syntax_error(ctx, lineno, "empty table selector"); - return; /* not reached */ - } + if (ctx->tpath.top <= 0) { + e_syntax_error(ctx, lineno, "empty table selector"); + return; /* not reached */ + } } @@ -1084,78 +1084,78 @@ static void fill_tabpath(context_t* ctx) */ static void walk_tabpath(context_t* ctx) { - /* start from root */ - toml_table_t* curtab = ctx->root; - - for (int i = 0; i < ctx->tpath.top; i++) { - const char* key = ctx->tpath.key[i]; + /* start from root */ + toml_table_t* curtab = ctx->root; + + for (int i = 0; i < ctx->tpath.top; i++) { + const char* key = ctx->tpath.key[i]; - toml_keyval_t* nextval = 0; - toml_array_t* nextarr = 0; - toml_table_t* nexttab = 0; - switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { - case 't': - /* found a table. nexttab is where we will go next. */ - break; + toml_keyval_t* nextval = 0; + toml_array_t* nextarr = 0; + toml_table_t* nexttab = 0; + switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { + case 't': + /* found a table. nexttab is where we will go next. */ + break; - case 'a': - /* found an array. nexttab is the last table in the array. */ - if (nextarr->kind != 't') { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } - if (nextarr->nelem == 0) { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } - nexttab = nextarr->u.tab[nextarr->nelem-1]; - break; + case 'a': + /* found an array. nexttab is the last table in the array. */ + if (nextarr->kind != 't') { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } + if (nextarr->nelem == 0) { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } + nexttab = nextarr->u.tab[nextarr->nelem-1]; + break; - case 'v': - e_key_exists_error(ctx, ctx->tpath.tok[i]); - return; /* not reached */ + case 'v': + e_key_exists_error(ctx, ctx->tpath.tok[i]); + return; /* not reached */ - default: - { /* Not found. Let's create an implicit table. */ - int n = curtab->ntab; - toml_table_t** base = (toml_table_t**) REALLOC(curtab->tab, (n+1) * sizeof(*base)); - if (0 == base) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - curtab->tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - if (0 == (base[n]->key = STRDUP(key))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - nexttab = curtab->tab[curtab->ntab++]; - - /* tabs created by walk_tabpath are considered implicit */ - nexttab->implicit = 1; - } - break; - } + default: + { /* Not found. Let's create an implicit table. */ + int n = curtab->ntab; + toml_table_t** base = (toml_table_t**) REALLOC(curtab->tab, (n+1) * sizeof(*base)); + if (0 == base) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + curtab->tab = base; + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + if (0 == (base[n]->key = STRDUP(key))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + nexttab = curtab->tab[curtab->ntab++]; + + /* tabs created by walk_tabpath are considered implicit */ + nexttab->implicit = 1; + } + break; + } - /* switch to next tab */ - curtab = nexttab; - } + /* switch to next tab */ + curtab = nexttab; + } - /* save it */ - ctx->curtab = curtab; + /* save it */ + ctx->curtab = curtab; } - + /* handle lines like [x.y.z] or [[x.y.z]] */ static void parse_select(context_t* ctx) { - assert(ctx->tok.tok == LBRACKET); + assert(ctx->tok.tok == LBRACKET); /* true if [[ */ int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '['); @@ -1163,512 +1163,512 @@ static void parse_select(context_t* ctx) and '[ [' would be taken as '[[', which is wrong. */ /* eat [ or [[ */ - next_token(ctx, 1 /* DOT IS SPECIAL */); + next_token(ctx, 1 /* DOT IS SPECIAL */); if (llb) { assert(ctx->tok.tok == LBRACKET); - next_token(ctx, 1 /* DOT IS SPECIAL */); - } + next_token(ctx, 1 /* DOT IS SPECIAL */); + } - fill_tabpath(ctx); + fill_tabpath(ctx); - /* For [x.y.z] or [[x.y.z]], remove z from tpath. - */ - token_t z = ctx->tpath.tok[ctx->tpath.top-1]; - xfree(ctx->tpath.key[ctx->tpath.top-1]); - ctx->tpath.top--; + /* For [x.y.z] or [[x.y.z]], remove z from tpath. + */ + token_t z = ctx->tpath.tok[ctx->tpath.top-1]; + xfree(ctx->tpath.key[ctx->tpath.top-1]); + ctx->tpath.top--; /* set up ctx->curtab */ - walk_tabpath(ctx); + walk_tabpath(ctx); - if (! llb) { - /* [x.y.z] -> create z = {} in x.y */ - ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); - } else { - /* [[x.y.z]] -> create z = [] in x.y */ - toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z, - 1 /*skip_if_exist*/); - if (!arr) { - e_syntax_error(ctx, z.lineno, "key exists"); - return; - } - if (arr->kind == 0) arr->kind = 't'; - if (arr->kind != 't') { - e_syntax_error(ctx, z.lineno, "array mismatch"); - return; /* not reached */ - } + if (! llb) { + /* [x.y.z] -> create z = {} in x.y */ + ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); + } else { + /* [[x.y.z]] -> create z = [] in x.y */ + toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z, + 1 /*skip_if_exist*/); + if (!arr) { + e_syntax_error(ctx, z.lineno, "key exists"); + return; + } + if (arr->kind == 0) arr->kind = 't'; + if (arr->kind != 't') { + e_syntax_error(ctx, z.lineno, "array mismatch"); + return; /* not reached */ + } - /* add to z[] */ - toml_table_t* dest; - { - int n = arr->nelem; - toml_table_t** base = REALLOC(arr->u.tab, (n+1) * sizeof(*base)); - if (0 == base) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - arr->u.tab = base; - - if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - if (0 == (base[n]->key = STRDUP("__anon__"))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - dest = arr->u.tab[arr->nelem++]; - } + /* add to z[] */ + toml_table_t* dest; + { + int n = arr->nelem; + toml_table_t** base = REALLOC(arr->u.tab, (n+1) * sizeof(*base)); + if (0 == base) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + arr->u.tab = base; + + if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + if (0 == (base[n]->key = STRDUP("__anon__"))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + dest = arr->u.tab[arr->nelem++]; + } - ctx->curtab = dest; - } + ctx->curtab = dest; + } - if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "expects ]"); - return; /* not reached */ - } + if (ctx->tok.tok != RBRACKET) { + e_syntax_error(ctx, ctx->tok.lineno, "expects ]"); + return; /* not reached */ + } if (llb) { if (! (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) { - e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); + e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); return; /* not reached */ } EAT_TOKEN(ctx, RBRACKET); } EAT_TOKEN(ctx, RBRACKET); - if (ctx->tok.tok != NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); - return; /* not reached */ - } + if (ctx->tok.tok != NEWLINE) { + e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); + return; /* not reached */ + } } toml_table_t* toml_parse(char* conf, - char* errbuf, - int errbufsz) + char* errbuf, + int errbufsz) { - context_t ctx; + context_t ctx; - // clear errbuf - if (errbufsz <= 0) errbufsz = 0; - if (errbufsz > 0) errbuf[0] = 0; + // clear errbuf + if (errbufsz <= 0) errbufsz = 0; + if (errbufsz > 0) errbuf[0] = 0; - // init context - memset(&ctx, 0, sizeof(ctx)); - ctx.start = conf; - ctx.stop = ctx.start + strlen(conf); - ctx.errbuf = errbuf; - ctx.errbufsz = errbufsz; + // init context + memset(&ctx, 0, sizeof(ctx)); + ctx.start = conf; + ctx.stop = ctx.start + strlen(conf); + ctx.errbuf = errbuf; + ctx.errbufsz = errbufsz; - // start with an artificial newline of length 0 - ctx.tok.tok = NEWLINE; - ctx.tok.lineno = 1; - ctx.tok.ptr = conf; - ctx.tok.len = 0; + // start with an artificial newline of length 0 + ctx.tok.tok = NEWLINE; + ctx.tok.lineno = 1; + ctx.tok.ptr = conf; + ctx.tok.len = 0; - // make a root table - if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { - /* do not call outofmemory() here... setjmp not done yet */ - snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE); - return 0; - } + // make a root table + if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { + /* do not call outofmemory() here... setjmp not done yet */ + snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE); + return 0; + } - // set root as default table - ctx.curtab = ctx.root; + // set root as default table + ctx.curtab = ctx.root; - if (0 != setjmp(ctx.jmp)) { - // Got here from a long_jmp. Something bad has happened. - // Free resources and return error. - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - toml_free(ctx.root); - return 0; - } + if (0 != setjmp(ctx.jmp)) { + // Got here from a long_jmp. Something bad has happened. + // Free resources and return error. + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + toml_free(ctx.root); + return 0; + } - /* Scan forward until EOF */ - for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { - switch (tok.tok) { - - case NEWLINE: - next_token(&ctx, 1); - break; - - case STRING: - parse_keyval(&ctx, ctx.curtab); - if (ctx.tok.tok != NEWLINE) { - e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); - return 0; /* not reached */ - } + /* Scan forward until EOF */ + for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { + switch (tok.tok) { + + case NEWLINE: + next_token(&ctx, 1); + break; + + case STRING: + parse_keyval(&ctx, ctx.curtab); + if (ctx.tok.tok != NEWLINE) { + e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); + return 0; /* not reached */ + } - EAT_TOKEN(&ctx, NEWLINE); - break; - - case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ - parse_select(&ctx); - break; - - default: - snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); - longjmp(ctx.jmp, 1); - } - } + EAT_TOKEN(&ctx, NEWLINE); + break; + + case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ + parse_select(&ctx); + break; + + default: + snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); + longjmp(ctx.jmp, 1); + } + } - /* success */ - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - return ctx.root; + /* success */ + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + return ctx.root; } toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz) + char* errbuf, + int errbufsz) { - int bufsz = 0; - char* buf = 0; - int off = 0; + int bufsz = 0; + char* buf = 0; + int off = 0; - /* prime the buf[] */ - bufsz = 1000; - if (! (buf = MALLOC(bufsz + 1))) { - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } + /* prime the buf[] */ + bufsz = 1000; + if (! (buf = MALLOC(bufsz + 1))) { + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } - /* read from fp into buf */ - while (! feof(fp)) { - bufsz += 1000; - - /* Allocate 1 extra byte because we will tag on a NUL */ - char* x = REALLOC(buf, bufsz + 1); - if (!x) { - snprintf(errbuf, errbufsz, "out of memory"); - xfree(buf); - return 0; - } - buf = x; + /* read from fp into buf */ + while (! feof(fp)) { + bufsz += 1000; + + /* Allocate 1 extra byte because we will tag on a NUL */ + char* x = REALLOC(buf, bufsz + 1); + if (!x) { + snprintf(errbuf, errbufsz, "out of memory"); + xfree(buf); + return 0; + } + buf = x; - errno = 0; - int n = fread(buf + off, 1, bufsz - off, fp); - if (ferror(fp)) { - snprintf(errbuf, errbufsz, "%s", - errno ? strerror(errno) : "Error reading file"); - xfree(buf); - return 0; - } - off += n; - } + errno = 0; + int n = fread(buf + off, 1, bufsz - off, fp); + if (ferror(fp)) { + snprintf(errbuf, errbufsz, "%s", + errno ? strerror(errno) : "Error reading file"); + xfree(buf); + return 0; + } + off += n; + } - /* tag on a NUL to cap the string */ - buf[off] = 0; /* we accounted for this byte in the REALLOC() above. */ + /* tag on a NUL to cap the string */ + buf[off] = 0; /* we accounted for this byte in the REALLOC() above. */ - /* parse it, cleanup and finish */ - toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); - xfree(buf); - return ret; + /* parse it, cleanup and finish */ + toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); + xfree(buf); + return ret; } static void xfree_kval(toml_keyval_t* p) { - if (!p) return; - xfree(p->key); - xfree(p->val); - xfree(p); + if (!p) return; + xfree(p->key); + xfree(p->val); + xfree(p); } static void xfree_tab(toml_table_t* p); static void xfree_arr(toml_array_t* p) { - if (!p) return; + if (!p) return; - xfree(p->key); - switch (p->kind) { - case 'v': - for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); - xfree(p->u.val); - break; + xfree(p->key); + switch (p->kind) { + case 'v': + for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); + xfree(p->u.val); + break; - case 'a': - for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); - xfree(p->u.arr); - break; + case 'a': + for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); + xfree(p->u.arr); + break; - case 't': - for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); - xfree(p->u.tab); - break; - } + case 't': + for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); + xfree(p->u.tab); + break; + } - xfree(p); + xfree(p); } static void xfree_tab(toml_table_t* p) { - int i; - - if (!p) return; - - xfree(p->key); - - for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); - xfree(p->kval); + int i; + + if (!p) return; + + xfree(p->key); + + for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); + xfree(p->kval); - for (i = 0; i < p->narr; i++) xfree_arr(p->arr[i]); - xfree(p->arr); + for (i = 0; i < p->narr; i++) xfree_arr(p->arr[i]); + xfree(p->arr); - for (i = 0; i < p->ntab; i++) xfree_tab(p->tab[i]); - xfree(p->tab); + for (i = 0; i < p->ntab; i++) xfree_tab(p->tab[i]); + xfree(p->tab); - xfree(p); + xfree(p); } void toml_free(toml_table_t* tab) { - xfree_tab(tab); + xfree_tab(tab); } static tokentype_t ret_token(context_t* ctx, tokentype_t tok, int lineno, char* ptr, int len) { - token_t t; - t.tok = tok; - t.lineno = lineno; - t.ptr = ptr; - t.len = len; - t.eof = 0; - ctx->tok = t; - return tok; + token_t t; + t.tok = tok; + t.lineno = lineno; + t.ptr = ptr; + t.len = len; + t.eof = 0; + ctx->tok = t; + return tok; } static tokentype_t ret_eof(context_t* ctx, int lineno) { - ret_token(ctx, NEWLINE, lineno, ctx->stop, 0); - ctx->tok.eof = 1; - return ctx->tok.tok; + ret_token(ctx, NEWLINE, lineno, ctx->stop, 0); + ctx->tok.eof = 1; + return ctx->tok.tok; } - + static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) { - char* orig = p; - if (0 == strncmp(p, "'''", 3)) { - p = strstr(p + 3, "'''"); - if (0 == p) { - e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); - return 0; /* not reached */ - } + char* orig = p; + if (0 == strncmp(p, "'''", 3)) { + p = strstr(p + 3, "'''"); + if (0 == p) { + e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); + return 0; /* not reached */ + } - return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); - } + return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); + } - if (0 == strncmp(p, "\"\"\"", 3)) { - int hexreq = 0; /* #hex required */ - int escape = 0; - int qcnt = 0; /* count quote */ - for (p += 3; *p && qcnt < 3; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - if (*p == '\n') continue; /* allow for line ending backslash */ - e_syntax_error(ctx, lineno, "bad escape char"); - return 0; /* not reached */ - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); - return 0; /* not reached */ - } - if (*p == '\\') { escape = 1; continue; } - qcnt = (*p == '"') ? qcnt + 1 : 0; - } - if (qcnt != 3) { - e_syntax_error(ctx, lineno, "unterminated triple-quote"); - return 0; /* not reached */ - } + if (0 == strncmp(p, "\"\"\"", 3)) { + int hexreq = 0; /* #hex required */ + int escape = 0; + int qcnt = 0; /* count quote */ + for (p += 3; *p && qcnt < 3; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + if (*p == '\n') continue; /* allow for line ending backslash */ + e_syntax_error(ctx, lineno, "bad escape char"); + return 0; /* not reached */ + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + e_syntax_error(ctx, lineno, "expect hex char"); + return 0; /* not reached */ + } + if (*p == '\\') { escape = 1; continue; } + qcnt = (*p == '"') ? qcnt + 1 : 0; + } + if (qcnt != 3) { + e_syntax_error(ctx, lineno, "unterminated triple-quote"); + return 0; /* not reached */ + } - return ret_token(ctx, STRING, lineno, orig, p - orig); - } + return ret_token(ctx, STRING, lineno, orig, p - orig); + } - if ('\'' == *p) { - for (p++; *p && *p != '\n' && *p != '\''; p++); - if (*p != '\'') { - e_syntax_error(ctx, lineno, "unterminated s-quote"); - return 0; /* not reached */ - } + if ('\'' == *p) { + for (p++; *p && *p != '\n' && *p != '\''; p++); + if (*p != '\'') { + e_syntax_error(ctx, lineno, "unterminated s-quote"); + return 0; /* not reached */ + } - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); - } + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + } - if ('\"' == *p) { - int hexreq = 0; /* #hex required */ - int escape = 0; - for (p++; *p; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - e_syntax_error(ctx, lineno, "bad escape char"); - return 0; /* not reached */ - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); - return 0; /* not reached */ - } - if (*p == '\\') { escape = 1; continue; } - if (*p == '\n') break; - if (*p == '"') break; - } - if (*p != '"') { - e_syntax_error(ctx, lineno, "unterminated quote"); - return 0; /* not reached */ - } + if ('\"' == *p) { + int hexreq = 0; /* #hex required */ + int escape = 0; + for (p++; *p; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + e_syntax_error(ctx, lineno, "bad escape char"); + return 0; /* not reached */ + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + e_syntax_error(ctx, lineno, "expect hex char"); + return 0; /* not reached */ + } + if (*p == '\\') { escape = 1; continue; } + if (*p == '\n') break; + if (*p == '"') break; + } + if (*p != '"') { + e_syntax_error(ctx, lineno, "unterminated quote"); + return 0; /* not reached */ + } - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); - } + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + } - for ( ; *p && *p != '\n'; p++) { - int ch = *p; - if (ch == '.' && dotisspecial) break; - if ('A' <= ch && ch <= 'Z') continue; - if ('a' <= ch && ch <= 'z') continue; - if ('0' <= ch && ch <= '9') continue; - if (strchr("+-_.:", ch)) continue; - break; - } + for ( ; *p && *p != '\n'; p++) { + int ch = *p; + if (ch == '.' && dotisspecial) break; + if ('A' <= ch && ch <= 'Z') continue; + if ('a' <= ch && ch <= 'z') continue; + if ('0' <= ch && ch <= '9') continue; + if (strchr("+-_.:", ch)) continue; + break; + } - return ret_token(ctx, STRING, lineno, orig, p - orig); + return ret_token(ctx, STRING, lineno, orig, p - orig); } static tokentype_t next_token(context_t* ctx, int dotisspecial) { - int lineno = ctx->tok.lineno; - char* p = ctx->tok.ptr; - int i; + int lineno = ctx->tok.lineno; + char* p = ctx->tok.ptr; + int i; - /* eat this tok */ - for (i = 0; i < ctx->tok.len; i++) { - if (*p++ == '\n') - lineno++; - } + /* eat this tok */ + for (i = 0; i < ctx->tok.len; i++) { + if (*p++ == '\n') + lineno++; + } - /* make next tok */ - while (p < ctx->stop) { - /* skip comment. stop just before the \n. */ - if (*p == '#') { - for (p++; p < ctx->stop && *p != '\n'; p++); - continue; - } + /* make next tok */ + while (p < ctx->stop) { + /* skip comment. stop just before the \n. */ + if (*p == '#') { + for (p++; p < ctx->stop && *p != '\n'; p++); + continue; + } - if (dotisspecial && *p == '.') - return ret_token(ctx, DOT, lineno, p, 1); - - switch (*p) { - case ',': return ret_token(ctx, COMMA, lineno, p, 1); - case '=': return ret_token(ctx, EQUAL, lineno, p, 1); - case '{': return ret_token(ctx, LBRACE, lineno, p, 1); - case '}': return ret_token(ctx, RBRACE, lineno, p, 1); - case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); - case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); - case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); - case '\r': case ' ': case '\t': - /* ignore white spaces */ - p++; - continue; - } + if (dotisspecial && *p == '.') + return ret_token(ctx, DOT, lineno, p, 1); + + switch (*p) { + case ',': return ret_token(ctx, COMMA, lineno, p, 1); + case '=': return ret_token(ctx, EQUAL, lineno, p, 1); + case '{': return ret_token(ctx, LBRACE, lineno, p, 1); + case '}': return ret_token(ctx, RBRACE, lineno, p, 1); + case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); + case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); + case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); + case '\r': case ' ': case '\t': + /* ignore white spaces */ + p++; + continue; + } - return scan_string(ctx, p, lineno, dotisspecial); - } + return scan_string(ctx, p, lineno, dotisspecial); + } - return ret_eof(ctx, lineno); + return ret_eof(ctx, lineno); } const char* toml_key_in(toml_table_t* tab, int keyidx) { - if (keyidx < tab->nkval) return tab->kval[keyidx]->key; - - keyidx -= tab->nkval; - if (keyidx < tab->narr) return tab->arr[keyidx]->key; - - keyidx -= tab->narr; - if (keyidx < tab->ntab) return tab->tab[keyidx]->key; + if (keyidx < tab->nkval) return tab->kval[keyidx]->key; + + keyidx -= tab->nkval; + if (keyidx < tab->narr) return tab->arr[keyidx]->key; + + keyidx -= tab->narr; + if (keyidx < tab->ntab) return tab->tab[keyidx]->key; - return 0; + return 0; } const char* toml_raw_in(toml_table_t* tab, const char* key) { - int i; - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) - return tab->kval[i]->val; - } - return 0; + int i; + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) + return tab->kval[i]->val; + } + return 0; } toml_array_t* toml_array_in(toml_table_t* tab, const char* key) { - int i; - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) - return tab->arr[i]; - } - return 0; + int i; + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) + return tab->arr[i]; + } + return 0; } toml_table_t* toml_table_in(toml_table_t* tab, const char* key) { - int i; - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) - return tab->tab[i]; - } - return 0; + int i; + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) + return tab->tab[i]; + } + return 0; } const char* toml_raw_at(toml_array_t* arr, int idx) { - if (arr->kind != 'v') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.val[idx]; + if (arr->kind != 'v') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.val[idx]; } char toml_array_kind(toml_array_t* arr) { - return arr->kind; + return arr->kind; } char toml_array_type(toml_array_t* arr) { - if (arr->kind != 'v') - return 0; + if (arr->kind != 'v') + return 0; - if (arr->nelem == 0) - return 0; + if (arr->nelem == 0) + return 0; - return arr->type; + return arr->type; } int toml_array_nelem(toml_array_t* arr) { - return arr->nelem; + return arr->nelem; } const char* toml_array_key(toml_array_t* arr) @@ -1698,82 +1698,82 @@ const char* toml_table_key(toml_table_t* tab) toml_array_t* toml_array_at(toml_array_t* arr, int idx) { - if (arr->kind != 'a') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.arr[idx]; + if (arr->kind != 'a') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.arr[idx]; } toml_table_t* toml_table_at(toml_array_t* arr, int idx) { - if (arr->kind != 't') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.tab[idx]; + if (arr->kind != 't') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.tab[idx]; } int toml_rtots(const char* src_, toml_timestamp_t* ret) { - if (! src_) return -1; - - const char* p = src_; - const char* q = src_ + strlen(src_); - int64_t val; - int i; - - memset(ret, 0, sizeof(*ret)); + if (! src_) return -1; + + const char* p = src_; + const char* q = src_ + strlen(src_); + int64_t val; + int i; + + memset(ret, 0, sizeof(*ret)); - /* parse date YYYY-MM-DD */ - val = 0; - if (q - p > 4 && p[4] == '-') { - for (i = 0; i < 10; i++, p++) { - int xx = *p; - if (xx == '-') { - if (i == 4 || i == 7) continue; else return -1; - } - if (! ('0' <= xx && xx <= '9')) return -1; - val = val * 10 + (xx - '0'); - } - ret->day = &ret->__buffer.day; - ret->month = &ret->__buffer.month; - ret->year = &ret->__buffer.year; - - *ret->day = val % 100; val /= 100; - *ret->month = val % 100; val /= 100; - *ret->year = val; - - if (*p) { - // parse the T or space separator - if (*p != 'T' && *p != ' ') return -1; - p++; - } - } - if (q == p) return 0; + /* parse date YYYY-MM-DD */ + val = 0; + if (q - p > 4 && p[4] == '-') { + for (i = 0; i < 10; i++, p++) { + int xx = *p; + if (xx == '-') { + if (i == 4 || i == 7) continue; else return -1; + } + if (! ('0' <= xx && xx <= '9')) return -1; + val = val * 10 + (xx - '0'); + } + ret->day = &ret->__buffer.day; + ret->month = &ret->__buffer.month; + ret->year = &ret->__buffer.year; + + *ret->day = val % 100; val /= 100; + *ret->month = val % 100; val /= 100; + *ret->year = val; + + if (*p) { + // parse the T or space separator + if (*p != 'T' && *p != ' ') return -1; + p++; + } + } + if (q == p) return 0; - /* parse time HH:MM:SS */ - val = 0; - if (q - p < 8) return -1; - for (i = 0; i < 8; i++, p++) { - int xx = *p; - if (xx == ':') { - if (i == 2 || i == 5) continue; else return -1; - } - if (! ('0' <= xx && xx <= '9')) return -1; - val = val * 10 + (xx - '0'); - } - ret->second = &ret->__buffer.second; - ret->minute = &ret->__buffer.minute; - ret->hour = &ret->__buffer.hour; - - *ret->second = val % 100; val /= 100; - *ret->minute = val % 100; val /= 100; - *ret->hour = val; - - /* parse millisec */ - if (*p == '.') { + /* parse time HH:MM:SS */ + val = 0; + if (q - p < 8) return -1; + for (i = 0; i < 8; i++, p++) { + int xx = *p; + if (xx == ':') { + if (i == 2 || i == 5) continue; else return -1; + } + if (! ('0' <= xx && xx <= '9')) return -1; + val = val * 10 + (xx - '0'); + } + ret->second = &ret->__buffer.second; + ret->minute = &ret->__buffer.minute; + ret->hour = &ret->__buffer.hour; + + *ret->second = val % 100; val /= 100; + *ret->minute = val % 100; val /= 100; + *ret->hour = val; + + /* parse millisec */ + if (*p == '.') { val = 0; p++; if ('0' <= *p && *p <= '9') { @@ -1788,71 +1788,71 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) ret->millisec = &ret->__buffer.millisec; *ret->millisec = val; } - if (q == p) return 0; - - /* parse and copy Z */ - ret->z = ret->__buffer.z; - char* z = ret->z; - if (*p == 'Z') { - *z++ = *p++; - *z = 0; - return (p == q) ? 0 : -1; - } - if (*p == '+' || *p == '-') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - - if (*p == ':') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - } - - *z = 0; - } - return (p == q) ? 0 : -1; + if (q == p) return 0; + + /* parse and copy Z */ + ret->z = ret->__buffer.z; + char* z = ret->z; + if (*p == 'Z') { + *z++ = *p++; + *z = 0; + return (p == q) ? 0 : -1; + } + if (*p == '+' || *p == '-') { + *z++ = *p++; + + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; + *z++ = *p++; + *z++ = *p++; + + if (*p == ':') { + *z++ = *p++; + + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; + *z++ = *p++; + *z++ = *p++; + } + + *z = 0; + } + return (p == q) ? 0 : -1; } /* Raw to boolean */ int toml_rtob(const char* src, int* ret_) { - if (!src) return -1; - int dummy; - int* ret = ret_ ? ret_ : &dummy; - - if (0 == strcmp(src, "true")) { - *ret = 1; - return 0; - } - if (0 == strcmp(src, "false")) { - *ret = 0; - return 0; - } - return -1; + if (!src) return -1; + int dummy; + int* ret = ret_ ? ret_ : &dummy; + + if (0 == strcmp(src, "true")) { + *ret = 1; + return 0; + } + if (0 == strcmp(src, "false")) { + *ret = 0; + return 0; + } + return -1; } /* Raw to integer */ int toml_rtoi(const char* src, int64_t* ret_) { - if (!src) return -1; - - char buf[100]; - char* p = buf; - char* q = p + sizeof(buf); - const char* s = src; - int base = 0; - int64_t dummy; - int64_t* ret = ret_ ? ret_ : &dummy; - + if (!src) return -1; + + char buf[100]; + char* p = buf; + char* q = p + sizeof(buf); + const char* s = src; + int base = 0; + int64_t dummy; + int64_t* ret = ret_ ? ret_ : &dummy; + - /* allow +/- */ + /* allow +/- */ if (s[0] == '+' || s[0] == '-') *p++ = *s++; @@ -1860,60 +1860,60 @@ int toml_rtoi(const char* src, int64_t* ret_) if (s[0] == '_') return -1; - /* if 0 ... */ - if ('0' == s[0]) { - switch (s[1]) { - case 'x': base = 16; s += 2; break; - case 'o': base = 8; s += 2; break; - case 'b': base = 2; s += 2; break; - case '\0': return *ret = 0, 0; - default: - /* ensure no other digits after it */ - if (s[1]) return -1; - } - } + /* if 0 ... */ + if ('0' == s[0]) { + switch (s[1]) { + case 'x': base = 16; s += 2; break; + case 'o': base = 8; s += 2; break; + case 'b': base = 2; s += 2; break; + case '\0': return *ret = 0, 0; + default: + /* ensure no other digits after it */ + if (s[1]) return -1; + } + } - /* just strip underscores and pass to strtoll */ - while (*s && p < q) { - int ch = *s++; + /* just strip underscores and pass to strtoll */ + while (*s && p < q) { + int ch = *s++; switch (ch) { case '_': // disallow '__' if (s[0] == '_') return -1; - continue; /* skip _ */ + continue; /* skip _ */ default: break; } - *p++ = ch; - } - if (*s || p == q) return -1; + *p++ = ch; + } + if (*s || p == q) return -1; /* last char cannot be '_' */ if (s[-1] == '_') return -1; - - /* cap with NUL */ - *p = 0; + + /* cap with NUL */ + *p = 0; - /* Run strtoll on buf to get the integer */ - char* endp; - errno = 0; - *ret = strtoll(buf, &endp, base); - return (errno || *endp) ? -1 : 0; + /* Run strtoll on buf to get the integer */ + char* endp; + errno = 0; + *ret = strtoll(buf, &endp, base); + return (errno || *endp) ? -1 : 0; } int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) { - if (!src) return -1; - - char* p = buf; - char* q = p + buflen; - const char* s = src; - double dummy; - double* ret = ret_ ? ret_ : &dummy; + if (!src) return -1; + + char* p = buf; + char* q = p + buflen; + const char* s = src; + double dummy; + double* ret = ret_ ? ret_ : &dummy; - /* allow +/- */ + /* allow +/- */ if (s[0] == '+' || s[0] == '-') *p++ = *s++; @@ -1929,9 +1929,9 @@ int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) if (s[0] == '0' && s[1] && s[1] != '.') return -1; - /* just strip underscores and pass to strtod */ - while (*s && p < q) { - int ch = *s++; + /* just strip underscores and pass to strtod */ + while (*s && p < q) { + int ch = *s++; switch (ch) { case '.': if (s[-2] == '_') return -1; @@ -1944,24 +1944,24 @@ int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) default: break; } - *p++ = ch; - } - if (*s || p == q) return -1; /* reached end of string or buffer is full? */ + *p++ = ch; + } + if (*s || p == q) return -1; /* reached end of string or buffer is full? */ /* last char cannot be '_' */ if (s[-1] == '_') return -1; - if (p != buf && p[-1] == '.') - return -1; /* no trailing zero */ + if (p != buf && p[-1] == '.') + return -1; /* no trailing zero */ - /* cap with NUL */ - *p = 0; + /* cap with NUL */ + *p = 0; - /* Run strtod on buf to get the value */ - char* endp; - errno = 0; - *ret = strtod(buf, &endp); - return (errno || *endp) ? -1 : 0; + /* Run strtod on buf to get the value */ + char* endp; + errno = 0; + *ret = strtod(buf, &endp); + return (errno || *endp) ? -1 : 0; } int toml_rtod(const char* src, double* ret_) @@ -1973,84 +1973,84 @@ int toml_rtod(const char* src, double* ret_) static char* kill_line_ending_backslash(char* str) { - if (!str) return 0; - - /* first round: find (backslash, \n) */ - char* p = str; - while (0 != (p = strstr(p, "\\\n"))) { - char* q = (p + 1); - q += strspn(q, " \t\r\n"); - memmove(p, q, strlen(q) + 1); - } - /* second round: find (backslash, \r, \n) */ - p = str; - while (0 != (p = strstr(p, "\\\r\n"))) { - char* q = (p + 1); - q += strspn(q, " \t\r\n"); - memmove(p, q, strlen(q) + 1); - } + if (!str) return 0; + + /* first round: find (backslash, \n) */ + char* p = str; + while (0 != (p = strstr(p, "\\\n"))) { + char* q = (p + 1); + q += strspn(q, " \t\r\n"); + memmove(p, q, strlen(q) + 1); + } + /* second round: find (backslash, \r, \n) */ + p = str; + while (0 != (p = strstr(p, "\\\r\n"))) { + char* q = (p + 1); + q += strspn(q, " \t\r\n"); + memmove(p, q, strlen(q) + 1); + } - return str; + return str; } int toml_rtos(const char* src, char** ret) { - if (!src) return -1; - if (*src != '\'' && *src != '"') return -1; + if (!src) return -1; + if (*src != '\'' && *src != '"') return -1; - *ret = 0; - int srclen = strlen(src); - if (*src == '\'') { - if (0 == strncmp(src, "'''", 3)) { - const char* sp = src + 3; - const char* sq = src + srclen - 3; - /* last 3 chars in src must be ''' */ - if (! (sp <= sq && 0 == strcmp(sq, "'''"))) - return -1; - - /* skip first new line right after ''' */ - if (*sp == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; + *ret = 0; + int srclen = strlen(src); + if (*src == '\'') { + if (0 == strncmp(src, "'''", 3)) { + const char* sp = src + 3; + const char* sq = src + srclen - 3; + /* last 3 chars in src must be ''' */ + if (! (sp <= sq && 0 == strcmp(sq, "'''"))) + return -1; + + /* skip first new line right after ''' */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; - *ret = kill_line_ending_backslash(STRNDUP(sp, sq - sp)); - } else { - const char* sp = src + 1; - const char* sq = src + srclen - 1; - /* last char in src must be ' */ - if (! (sp <= sq && *sq == '\'')) - return -1; - /* copy from sp to p */ - *ret = STRNDUP(sp, sq - sp); - } - return *ret ? 0 : -1; - } + *ret = kill_line_ending_backslash(STRNDUP(sp, sq - sp)); + } else { + const char* sp = src + 1; + const char* sq = src + srclen - 1; + /* last char in src must be ' */ + if (! (sp <= sq && *sq == '\'')) + return -1; + /* copy from sp to p */ + *ret = STRNDUP(sp, sq - sp); + } + return *ret ? 0 : -1; + } - const char* sp; - const char* sq; - if (0 == strncmp(src, "\"\"\"", 3)) { - sp = src + 3; - sq = src + srclen - 3; - if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) - return -1; - - /* skip first new line right after """ */ - if (*sp == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; - } else { - sp = src + 1; - sq = src + srclen - 1; - if (! (sp <= sq && *sq == '"')) - return -1; - } + const char* sp; + const char* sq; + if (0 == strncmp(src, "\"\"\"", 3)) { + sp = src + 3; + sq = src + srclen - 3; + if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) + return -1; + + /* skip first new line right after """ */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; + } else { + sp = src + 1; + sq = src + srclen - 1; + if (! (sp <= sq && *sq == '"')) + return -1; + } - char dummy_errbuf[1]; - *ret = normalize_string(sp, sq - sp, - 1, // flag kill_line_ending_backslash - dummy_errbuf, sizeof(dummy_errbuf)); - return *ret ? 0 : -1; + char dummy_errbuf[1]; + *ret = normalize_string(sp, sq - sp, + 1, // flag kill_line_ending_backslash + dummy_errbuf, sizeof(dummy_errbuf)); + return *ret ? 0 : -1; } From 63793f92ef32c7c9fe18221301db8da697a04018 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Fri, 4 Oct 2019 10:08:57 -0700 Subject: [PATCH 030/138] make STRDUP and STRNDUP static --- toml.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toml.c b/toml.c index 3a47f7e..83509fc 100644 --- a/toml.c +++ b/toml.c @@ -58,7 +58,7 @@ void toml_set_memutil(void* (*xxmalloc)(size_t), #define CALLOC(a,b) ppcalloc(a,b) #define REALLOC(a,b) pprealloc(a,b) -char* STRDUP(const char* s) +static char* STRDUP(const char* s) { int len = strlen(s); char* p = MALLOC(len+1); @@ -69,7 +69,7 @@ char* STRDUP(const char* s) return p; } -char* STRNDUP(const char* s, size_t n) +static char* STRNDUP(const char* s, size_t n) { size_t len = strnlen(s, n); char* p = MALLOC(len+1); From c32a6e92f1eaf94cc5334eb83ad236a415b4a380 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 8 Oct 2019 16:58:18 -0700 Subject: [PATCH 031/138] v0.5 compliant --- .gitignore | 2 + README.md | 18 +- {test => test1}/.gitignore | 0 {test => test1}/README.md | 0 {test => test1}/build.sh | 2 +- {test => test1}/extra/array_of_tables.toml | 0 {test => test1}/extra/inline_array.toml | 0 {test => test1}/extra/inline_table.toml | 0 {test => test1}/run.sh | 0 test2/.gitignore | 1 + test2/build.sh | 6 + test2/run.sh | 31 + toml.c | 2976 ++++++++++---------- 13 files changed, 1592 insertions(+), 1444 deletions(-) rename {test => test1}/.gitignore (100%) rename {test => test1}/README.md (100%) rename {test => test1}/build.sh (81%) rename {test => test1}/extra/array_of_tables.toml (100%) rename {test => test1}/extra/inline_array.toml (100%) rename {test => test1}/extra/inline_table.toml (100%) rename {test => test1}/run.sh (100%) create mode 100644 test2/.gitignore create mode 100644 test2/build.sh create mode 100644 test2/run.sh diff --git a/.gitignore b/.gitignore index 76ce648..50f144d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*~ + # Object files *.o *.ko diff --git a/README.md b/README.md index 999f035..9e1ff88 100644 --- a/README.md +++ b/README.md @@ -92,10 +92,18 @@ A normal *make* suffices. Alternately, you can also simply include the To test against the standard test set provided by BurntSushi/toml-test: ``` - % make - % cd test - % bash build.sh # do this once - % bash run.sh # this will run the test suite - ``` + % make + % cd test1 + % bash build.sh # do this once + % bash run.sh # this will run the test suite +``` +To test against the standard test set provided by iarna/toml: + +``` + % make + % cd test2 + % bash build.sh # do this once + % bash run.sh # this will run the test suite +``` diff --git a/test/.gitignore b/test1/.gitignore similarity index 100% rename from test/.gitignore rename to test1/.gitignore diff --git a/test/README.md b/test1/README.md similarity index 100% rename from test/README.md rename to test1/README.md diff --git a/test/build.sh b/test1/build.sh similarity index 81% rename from test/build.sh rename to test1/build.sh index 535e03c..9007489 100644 --- a/test/build.sh +++ b/test1/build.sh @@ -2,7 +2,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" mkdir -p $DIR/goworkspace -export GOPATH=$DIR/goworkspace # if it isn't already set +export GOPATH=$DIR/goworkspace go get github.com/BurntSushi/toml-test # install test suite go get github.com/BurntSushi/toml/cmd/toml-test-decoder # e.g., install my parser cp $GOPATH/bin/* . diff --git a/test/extra/array_of_tables.toml b/test1/extra/array_of_tables.toml similarity index 100% rename from test/extra/array_of_tables.toml rename to test1/extra/array_of_tables.toml diff --git a/test/extra/inline_array.toml b/test1/extra/inline_array.toml similarity index 100% rename from test/extra/inline_array.toml rename to test1/extra/inline_array.toml diff --git a/test/extra/inline_table.toml b/test1/extra/inline_table.toml similarity index 100% rename from test/extra/inline_table.toml rename to test1/extra/inline_table.toml diff --git a/test/run.sh b/test1/run.sh similarity index 100% rename from test/run.sh rename to test1/run.sh diff --git a/test2/.gitignore b/test2/.gitignore new file mode 100644 index 0000000..21335a0 --- /dev/null +++ b/test2/.gitignore @@ -0,0 +1 @@ +/toml-spec-tests \ No newline at end of file diff --git a/test2/build.sh b/test2/build.sh new file mode 100644 index 0000000..81af053 --- /dev/null +++ b/test2/build.sh @@ -0,0 +1,6 @@ +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +[ -d toml-spec-tests ] || git clone https://github.com/iarna/toml-spec-tests.git + diff --git a/test2/run.sh b/test2/run.sh new file mode 100644 index 0000000..e18f306 --- /dev/null +++ b/test2/run.sh @@ -0,0 +1,31 @@ +# +# POSITIVE tests +# +for i in toml-spec-tests/values/*.toml; do + echo -n $i ' ' + ../toml_json $i >& $i.json.out + rc=$? + [ -f $i.json ] && diff=$(diff $i.json $i.json.out) || diff='' + if [ "$rc" != "0" ] || [ "$diff" != "" ]; then + echo '[FAILED]' + else + echo '[OK]' + fi +done + + +# +# NEGATIVE tests +# +for i in toml-spec-tests/errors/*.toml; do + echo -n $i ' ' + ../toml_json $i >& $i.json.out + rc=$? + + if [ "$rc" != "0" ]; then + echo '[OK]' + else + echo '[FAILED]' + fi + +done diff --git a/toml.c b/toml.c index 83509fc..a9781b5 100644 --- a/toml.c +++ b/toml.c @@ -42,7 +42,7 @@ static void* (*ppcalloc)(size_t, size_t) = calloc; static void* (*pprealloc)(void*, size_t) = realloc; void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*), + void (*xxfree)(void*), void* (*xxcalloc)(size_t, size_t), void* (*xxrealloc)(void*, size_t)) { @@ -53,31 +53,31 @@ void toml_set_memutil(void* (*xxmalloc)(size_t), } -#define MALLOC(a) ppmalloc(a) -#define FREE(a) ppfree(a) -#define CALLOC(a,b) ppcalloc(a,b) +#define MALLOC(a) ppmalloc(a) +#define FREE(a) ppfree(a) +#define CALLOC(a,b) ppcalloc(a,b) #define REALLOC(a,b) pprealloc(a,b) -static char* STRDUP(const char* s) +char* STRDUP(const char* s) { int len = strlen(s); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; + char* p = MALLOC(len+1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; } -static char* STRNDUP(const char* s, size_t n) +char* STRNDUP(const char* s, size_t n) { - size_t len = strnlen(s, n); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; + size_t len = strnlen(s, n); + char* p = MALLOC(len+1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; } @@ -88,213 +88,213 @@ static char* STRNDUP(const char* s, size_t n) */ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) { - const unsigned char* buf = (const unsigned char*) orig; - unsigned i = *buf++; - int64_t v; - - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (0 == (i >> 7)) { - if (len < 1) return -1; - v = i; - return *ret = v, 1; - } - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (0x6 == (i >> 5)) { - if (len < 2) return -1; - v = i & 0x1f; - for (int j = 0; j < 1; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + const unsigned char* buf = (const unsigned char*) orig; + unsigned i = *buf++; + int64_t v; + + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (0 == (i >> 7)) { + if (len < 1) return -1; + v = i; + return *ret = v, 1; + } + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (0x6 == (i >> 5)) { + if (len < 2) return -1; + v = i & 0x1f; + for (int j = 0; j < 1; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (0xE == (i >> 4)) { - if (len < 3) return -1; - v = i & 0x0F; - for (int j = 0; j < 2; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (0xE == (i >> 4)) { + if (len < 3) return -1; + v = i & 0x0F; + for (int j = 0; j < 2; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x1E == (i >> 3)) { - if (len < 4) return -1; - v = i & 0x07; - for (int j = 0; j < 3; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x3E == (i >> 2)) { - if (len < 5) return -1; - v = i & 0x03; - for (int j = 0; j < 4; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x1E == (i >> 3)) { + if (len < 4) return -1; + v = i & 0x07; + for (int j = 0; j < 3; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x3E == (i >> 2)) { + if (len < 5) return -1; + v = i & 0x03; + for (int j = 0; j < 4; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x7e == (i >> 1)) { - if (len < 6) return -1; - v = i & 0x01; - for (int j = 0; j < 5; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - return -1; + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x7e == (i >> 1)) { + if (len < 6) return -1; + v = i & 0x01; + for (int j = 0; j < 5; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + return -1; } /** - * Convert a UCS char to utf8 code, and return it in buf. - * Return #bytes used in buf to encode the char, or - * -1 on error. + * Convert a UCS char to utf8 code, and return it in buf. + * Return #bytes used in buf to encode the char, or + * -1 on error. */ int toml_ucs_to_utf8(int64_t code, char buf[6]) { - /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 */ - /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well - * as 0xfffe and 0xffff (UCS noncharacters) should not appear in - * conforming UTF-8 streams. - */ - if (0xd800 <= code && code <= 0xdfff) return -1; - if (0xfffe <= code && code <= 0xffff) return -1; + /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 */ + /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well + * as 0xfffe and 0xffff (UCS noncharacters) should not appear in + * conforming UTF-8 streams. + */ + if (0xd800 <= code && code <= 0xdfff) return -1; + if (0xfffe <= code && code <= 0xffff) return -1; - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (code < 0) return -1; - if (code <= 0x7F) { - buf[0] = (unsigned char) code; - return 1; - } + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (code < 0) return -1; + if (code <= 0x7F) { + buf[0] = (unsigned char) code; + return 1; + } - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (code <= 0x000007FF) { - buf[0] = 0xc0 | (code >> 6); - buf[1] = 0x80 | (code & 0x3f); - return 2; - } + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (code <= 0x000007FF) { + buf[0] = 0xc0 | (code >> 6); + buf[1] = 0x80 | (code & 0x3f); + return 2; + } - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x0000FFFF) { - buf[0] = 0xe0 | (code >> 12); - buf[1] = 0x80 | ((code >> 6) & 0x3f); - buf[2] = 0x80 | (code & 0x3f); - return 3; - } + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x0000FFFF) { + buf[0] = 0xe0 | (code >> 12); + buf[1] = 0x80 | ((code >> 6) & 0x3f); + buf[2] = 0x80 | (code & 0x3f); + return 3; + } - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x001FFFFF) { - buf[0] = 0xf0 | (code >> 18); - buf[1] = 0x80 | ((code >> 12) & 0x3f); - buf[2] = 0x80 | ((code >> 6) & 0x3f); - buf[3] = 0x80 | (code & 0x3f); - return 4; - } + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x001FFFFF) { + buf[0] = 0xf0 | (code >> 18); + buf[1] = 0x80 | ((code >> 12) & 0x3f); + buf[2] = 0x80 | ((code >> 6) & 0x3f); + buf[3] = 0x80 | (code & 0x3f); + return 4; + } - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x03FFFFFF) { - buf[0] = 0xf8 | (code >> 24); - buf[1] = 0x80 | ((code >> 18) & 0x3f); - buf[2] = 0x80 | ((code >> 12) & 0x3f); - buf[3] = 0x80 | ((code >> 6) & 0x3f); - buf[4] = 0x80 | (code & 0x3f); - return 5; - } - - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x7FFFFFFF) { - buf[0] = 0xfc | (code >> 30); - buf[1] = 0x80 | ((code >> 24) & 0x3f); - buf[2] = 0x80 | ((code >> 18) & 0x3f); - buf[3] = 0x80 | ((code >> 12) & 0x3f); - buf[4] = 0x80 | ((code >> 6) & 0x3f); - buf[5] = 0x80 | (code & 0x3f); - return 6; - } + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x03FFFFFF) { + buf[0] = 0xf8 | (code >> 24); + buf[1] = 0x80 | ((code >> 18) & 0x3f); + buf[2] = 0x80 | ((code >> 12) & 0x3f); + buf[3] = 0x80 | ((code >> 6) & 0x3f); + buf[4] = 0x80 | (code & 0x3f); + return 5; + } + + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x7FFFFFFF) { + buf[0] = 0xfc | (code >> 30); + buf[1] = 0x80 | ((code >> 24) & 0x3f); + buf[2] = 0x80 | ((code >> 18) & 0x3f); + buf[3] = 0x80 | ((code >> 12) & 0x3f); + buf[4] = 0x80 | ((code >> 6) & 0x3f); + buf[5] = 0x80 | (code & 0x3f); + return 6; + } - return -1; + return -1; } /* - * TOML has 3 data structures: value, array, table. - * Each of them can have identification key. + * TOML has 3 data structures: value, array, table. + * Each of them can have identification key. */ typedef struct toml_keyval_t toml_keyval_t; struct toml_keyval_t { - const char* key; /* key to this value */ - const char* val; /* the raw value */ + const char* key; /* key to this value */ + const char* val; /* the raw value */ }; struct toml_array_t { - const char* key; /* key to this array */ - int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */ - int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ - - int nelem; /* number of elements */ - union { - char** val; - toml_array_t** arr; - toml_table_t** tab; - } u; + const char* key; /* key to this array */ + int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */ + int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ + + int nelem; /* number of elements */ + union { + char** val; + toml_array_t** arr; + toml_table_t** tab; + } u; }; - + struct toml_table_t { - const char* key; /* key to this table */ - int implicit; /* table was created implicitly */ + const char* key; /* key to this table */ + int implicit; /* table was created implicitly */ - /* key-values in the table */ - int nkval; - toml_keyval_t** kval; + /* key-values in the table */ + int nkval; + toml_keyval_t** kval; - /* arrays in the table */ - int narr; - toml_array_t** arr; + /* arrays in the table */ + int narr; + toml_array_t** arr; - /* tables in the table */ - int ntab; - toml_table_t** tab; + /* tables in the table */ + int ntab; + toml_table_t** tab; }; @@ -302,51 +302,51 @@ static inline void xfree(const void* x) { if (x) FREE((void*)x); } enum tokentype_t { - INVALID, - DOT, - COMMA, - EQUAL, - LBRACE, - RBRACE, - NEWLINE, - LBRACKET, - RBRACKET, - STRING, + INVALID, + DOT, + COMMA, + EQUAL, + LBRACE, + RBRACE, + NEWLINE, + LBRACKET, + RBRACKET, + STRING, }; typedef enum tokentype_t tokentype_t; typedef struct token_t token_t; struct token_t { - tokentype_t tok; - int lineno; - char* ptr; /* points into context->start */ - int len; - int eof; + tokentype_t tok; + int lineno; + char* ptr; /* points into context->start */ + int len; + int eof; }; typedef struct context_t context_t; struct context_t { - char* start; - char* stop; - char* errbuf; - int errbufsz; - jmp_buf jmp; + char* start; + char* stop; + char* errbuf; + int errbufsz; + jmp_buf jmp; - token_t tok; - toml_table_t* root; - toml_table_t* curtab; + token_t tok; + toml_table_t* root; + toml_table_t* curtab; - struct { - int top; - char* key[10]; - token_t tok[10]; - } tpath; + struct { + int top; + char* key[10]; + token_t tok[10]; + } tpath; }; #define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) +#define TOSTRING(x) STRINGIFY(x) #define FLINE __FILE__ ":" TOSTRING(__LINE__) static tokentype_t next_token(context_t* ctx, int dotisspecial); @@ -354,227 +354,282 @@ static tokentype_t next_token(context_t* ctx, int dotisspecial); /* error routines. All these functions longjmp to ctx->jmp */ static int e_outofmemory(context_t* ctx, const char* fline) { - snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); + longjmp(ctx->jmp, 1); + return -1; } static int e_internal_error(context_t* ctx, const char* fline) { - snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); + longjmp(ctx->jmp, 1); + return -1; } static int e_syntax_error(context_t* ctx, int lineno, const char* msg) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); + longjmp(ctx->jmp, 1); + return -1; } static int e_bad_key_error(context_t* ctx, int lineno) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); + longjmp(ctx->jmp, 1); + return -1; } /* static int e_noimpl(context_t* ctx, const char* feature) { - snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature); + longjmp(ctx->jmp, 1); + return -1; } */ -static int e_key_exists_error(context_t* ctx, token_t keytok) +static int e_key_exists_error(context_t* ctx, int lineno, const char* key) { - char buf[100]; - int i; - for (i = 0; i < keytok.len && i < (int)sizeof(buf) - 1; i++) { - buf[i] = keytok.ptr[i]; - } - buf[i] = 0; - - snprintf(ctx->errbuf, ctx->errbufsz, - "line %d: key %s exists", keytok.lineno, buf); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, + "line %d: key %s exists", lineno, key); + longjmp(ctx->jmp, 1); + return -1; } +static char* norm_lit_str(const char* src, int srclen, + int multiline, + char* errbuf, int errbufsz) +{ + char* dst = 0; /* will write to dst[] and return it */ + int max = 0; /* max size of dst[] */ + int off = 0; /* cur offset in dst[] */ + const char* sp = src; + const char* sq = src + srclen; + int ch; + + /* scan forward on src */ + for (;;) { + if (off >= max - 10) { /* have some slack for misc stuff */ + char* x = REALLOC(dst, max += 50); + if (!x) { + xfree(dst); + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + dst = x; + } + + /* finished? */ + if (sp >= sq) break; + + ch = *sp++; + /* control characters other than tab is not allowed */ + if ((0 <= ch && ch <= 0x08) + || (0x0a <= ch && ch <= 0x1f) + || (ch == 0x7f)) { + if (! (multiline && (ch == '\r' || ch == '\n'))) { + xfree(dst); + snprintf(errbuf, errbufsz, "invalid char U+%04x", ch); + return 0; + } + } + + // a plain copy suffice + dst[off++] = ch; + } + + dst[off++] = 0; + return dst; +} + + /* * Convert src to raw unescaped utf-8 string. * Returns NULL if error with errmsg in errbuf. */ -static char* normalize_string(const char* src, int srclen, - int kill_line_ending_backslash, - char* errbuf, int errbufsz) +static char* norm_basic_str(const char* src, int srclen, + int multiline, + char* errbuf, int errbufsz) { - char* dst = 0; /* will write to dst[] and return it */ - int max = 0; /* max size of dst[] */ - int off = 0; /* cur offset in dst[] */ - const char* sp = src; - const char* sq = src + srclen; - int ch; + char* dst = 0; /* will write to dst[] and return it */ + int max = 0; /* max size of dst[] */ + int off = 0; /* cur offset in dst[] */ + const char* sp = src; + const char* sq = src + srclen; + int ch; - /* scan forward on src */ - for (;;) { - if (off >= max - 10) { /* have some slack for misc stuff */ - char* x = REALLOC(dst, max += 100); - if (!x) { - xfree(dst); - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - dst = x; - } - - /* finished? */ - if (sp >= sq) break; - - ch = *sp++; - if (ch != '\\') { - // a plain copy suffice - dst[off++] = ch; - continue; - } - - /* ch was backslash. we expect the escape char. */ - if (sp >= sq) { - snprintf(errbuf, errbufsz, "last backslash is invalid"); - xfree(dst); - return 0; - } - - /* if we want to kill line-ending-backslash ... */ - if (kill_line_ending_backslash) { - /* if this is a newline immediately following the backslash ... */ - if (*sp == '\n' || (*sp == '\r' && sp[1] == '\n')) { - /* skip all the following whitespaces */ - sp += strspn(sp, " \t\r\n"); - continue; - } - } - - /* get the escaped char */ - ch = *sp++; - switch (ch) { - case 'u': case 'U': - { - int64_t ucs = 0; - int nhex = (ch == 'u' ? 4 : 8); - for (int i = 0; i < nhex; i++) { - if (sp >= sq) { - snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); - xfree(dst); - return 0; - } - ch = *sp++; - int v = ('0' <= ch && ch <= '9') - ? ch - '0' - : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); - if (-1 == v) { - snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); - xfree(dst); - return 0; - } - ucs = ucs * 16 + v; - } - int n = toml_ucs_to_utf8(ucs, &dst[off]); - if (-1 == n) { - snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); + /* scan forward on src */ + for (;;) { + if (off >= max - 10) { /* have some slack for misc stuff */ + char* x = REALLOC(dst, max += 50); + if (!x) { + xfree(dst); + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + dst = x; + } + + /* finished? */ + if (sp >= sq) break; + + ch = *sp++; + if (ch != '\\') { + /* these chars must be escaped: U+0000 to U+0008, U+000A to U+001F, U+007F */ + if ((0 <= ch && ch <= 0x08) + || (0x0a <= ch && ch <= 0x1f) + || (ch == 0x7f)) { + if (! (multiline && (ch == '\r' || ch == '\n'))) { xfree(dst); + snprintf(errbuf, errbufsz, "invalid char U+%04x", ch); return 0; } - off += n; } - continue; + + // a plain copy suffice + dst[off++] = ch; + continue; + } - case 'b': ch = '\b'; break; - case 't': ch = '\t'; break; - case 'n': ch = '\n'; break; - case 'f': ch = '\f'; break; - case 'r': ch = '\r'; break; - case '"': ch = '"'; break; - case '\\': ch = '\\'; break; - default: - snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); - xfree(dst); - return 0; - } + /* ch was backslash. we expect the escape char. */ + if (sp >= sq) { + snprintf(errbuf, errbufsz, "last backslash is invalid"); + xfree(dst); + return 0; + } - dst[off++] = ch; - } + /* for multi-line, we want to kill line-ending-backslash ... */ + if (multiline) { - // Cap with NUL and return it. - dst[off++] = 0; - return dst; + // if there is only whitespace after the backslash ... + if (sp[strspn(sp, " \t\r")] == '\n') { + /* skip all the following whitespaces */ + sp += strspn(sp, " \t\r\n"); + continue; + } + } + + /* get the escaped char */ + ch = *sp++; + switch (ch) { + case 'u': case 'U': + { + int64_t ucs = 0; + int nhex = (ch == 'u' ? 4 : 8); + for (int i = 0; i < nhex; i++) { + if (sp >= sq) { + snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); + xfree(dst); + return 0; + } + ch = *sp++; + int v = ('0' <= ch && ch <= '9') + ? ch - '0' + : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); + if (-1 == v) { + snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); + xfree(dst); + return 0; + } + ucs = ucs * 16 + v; + } + int n = toml_ucs_to_utf8(ucs, &dst[off]); + if (-1 == n) { + snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); + xfree(dst); + return 0; + } + off += n; + } + continue; + + case 'b': ch = '\b'; break; + case 't': ch = '\t'; break; + case 'n': ch = '\n'; break; + case 'f': ch = '\f'; break; + case 'r': ch = '\r'; break; + case '"': ch = '"'; break; + case '\\': ch = '\\'; break; + default: + snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); + xfree(dst); + return 0; + } + + dst[off++] = ch; + } + + // Cap with NUL and return it. + dst[off++] = 0; + return dst; } /* Normalize a key. Convert all special chars to raw unescaped utf-8 chars. */ static char* normalize_key(context_t* ctx, token_t strtok) { - const char* sp = strtok.ptr; - const char* sq = strtok.ptr + strtok.len; - int lineno = strtok.lineno; - char* ret; - int ch = *sp; - char ebuf[80]; + const char* sp = strtok.ptr; + const char* sq = strtok.ptr + strtok.len; + int lineno = strtok.lineno; + char* ret; + int ch = *sp; + char ebuf[80]; - /* handle quoted string */ - if (ch == '\'' || ch == '\"') { - /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ - if (sp[1] == ch && sp[2] == ch) - sp += 3, sq -= 3; - else - sp++, sq--; - - if (ch == '\'') { - /* for single quote, take it verbatim. */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - } else { - /* for double quote, we need to normalize */ - ret = normalize_string(sp, sq - sp, 0, ebuf, sizeof(ebuf)); - if (!ret) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); - longjmp(ctx->jmp, 1); - } + /* handle quoted string */ + if (ch == '\'' || ch == '\"') { + /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ + int multiline = 0; + if (sp[1] == ch && sp[2] == ch) { + sp += 3, sq -= 3; + multiline = 1; } + else + sp++, sq--; - /* newlines are not allowed in keys */ - if (strchr(ret, '\n')) { - xfree(ret); - e_bad_key_error(ctx, lineno); - return 0; /* not reached */ - } - return ret; - } - - /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ - const char* xp; - for (xp = sp; xp != sq; xp++) { - int k = *xp; - if (isalnum(k)) continue; - if (k == '_' || k == '-') continue; - e_bad_key_error(ctx, lineno); - return 0; /* not reached */ - } + if (ch == '\'') { + /* for single quote, take it verbatim. */ + if (! (ret = STRNDUP(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + } else { + /* for double quote, we need to normalize */ + ret = norm_basic_str(sp, sq - sp, multiline, ebuf, sizeof(ebuf)); + if (!ret) { + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); + longjmp(ctx->jmp, 1); + } + } - /* dup and return it */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - return ret; + /* newlines are not allowed in keys */ + if (strchr(ret, '\n')) { + xfree(ret); + e_bad_key_error(ctx, lineno); + return 0; /* not reached */ + } + return ret; + } + + /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ + const char* xp; + for (xp = sp; xp != sq; xp++) { + int k = *xp; + if (isalnum(k)) continue; + if (k == '_' || k == '-') continue; + e_bad_key_error(ctx, lineno); + return 0; /* not reached */ + } + + /* dup and return it */ + if (! (ret = STRNDUP(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + return ret; } @@ -583,77 +638,83 @@ static char* normalize_key(context_t* ctx, token_t strtok) * 'v'alue, 'a'rray or 't'able depending on the element. */ 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) + toml_keyval_t** ret_val, + toml_array_t** ret_arr, + toml_table_t** ret_tab) { - int i; - void* dummy; + int i; + void* dummy; - if (!ret_tab) ret_tab = (toml_table_t**) &dummy; - if (!ret_arr) ret_arr = (toml_array_t**) &dummy; - if (!ret_val) ret_val = (toml_keyval_t**) &dummy; + if (!ret_tab) ret_tab = (toml_table_t**) &dummy; + if (!ret_arr) ret_arr = (toml_array_t**) &dummy; + if (!ret_val) ret_val = (toml_keyval_t**) &dummy; - *ret_tab = 0; *ret_arr = 0; *ret_val = 0; - - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) { - *ret_val = tab->kval[i]; - return 'v'; - } - } - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) { - *ret_arr = tab->arr[i]; - return 'a'; - } - } - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) { - *ret_tab = tab->tab[i]; - return 't'; - } - } - return 0; + *ret_tab = 0; *ret_arr = 0; *ret_val = 0; + + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) { + *ret_val = tab->kval[i]; + return 'v'; + } + } + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) { + *ret_arr = tab->arr[i]; + return 'a'; + } + } + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) { + *ret_tab = tab->tab[i]; + return 't'; + } + } + return 0; +} + + +static int key_kind(toml_table_t* tab, const char* key) +{ + return check_key(tab, key, 0, 0, 0); } /* Create a keyval in the table. */ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); - /* if key exists: error out. */ - toml_keyval_t* dest = 0; - if (check_key(tab, newkey, 0, 0, 0)) { - xfree(newkey); - e_key_exists_error(ctx, keytok); - return 0; /* not reached */ - } + /* if key exists: error out. */ + toml_keyval_t* dest = 0; + if (key_kind(tab, newkey)) { + xfree(newkey); + e_key_exists_error(ctx, keytok.lineno, newkey); + return 0; /* not reached */ + } - /* make a new entry */ - int n = tab->nkval; - toml_keyval_t** base; - if (0 == (base = (toml_keyval_t**) REALLOC(tab->kval, (n+1) * sizeof(*base)))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - tab->kval = base; - - if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - dest = tab->kval[tab->nkval++]; + /* make a new entry */ + int n = tab->nkval; + toml_keyval_t** base; + if (0 == (base = (toml_keyval_t**) REALLOC(tab->kval, (n+1) * sizeof(*base)))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + tab->kval = base; + + if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + dest = tab->kval[tab->nkval++]; - /* save the key in the new value struct */ - dest->key = newkey; - return dest; + /* save the key in the new value struct */ + dest->key = newkey; + return dest; } @@ -661,141 +722,137 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, */ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); - /* if key exists: error out */ - toml_table_t* dest = 0; - if (check_key(tab, newkey, 0, 0, &dest)) { - xfree(newkey); /* don't need this anymore */ - - /* special case: if table exists, but was created implicitly ... */ - if (dest && dest->implicit) { - /* we make it explicit now, and simply return it. */ - dest->implicit = 0; - return dest; - } - e_key_exists_error(ctx, keytok); - return 0; /* not reached */ - } + /* if key exists: error out */ + toml_table_t* dest = 0; + if (check_key(tab, newkey, 0, 0, &dest)) { + xfree(newkey); /* don't need this anymore */ + + /* special case: if table exists, but was created implicitly ... */ + if (dest && dest->implicit) { + /* we make it explicit now, and simply return it. */ + dest->implicit = 0; + return dest; + } + e_key_exists_error(ctx, keytok.lineno, newkey); + return 0; /* not reached */ + } - /* create a new table entry */ - int n = tab->ntab; - toml_table_t** base; - if (0 == (base = (toml_table_t**) REALLOC(tab->tab, (n+1) * sizeof(*base)))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - tab->tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - dest = tab->tab[tab->ntab++]; - - /* save the key in the new table struct */ - dest->key = newkey; - return dest; + /* create a new table entry */ + int n = tab->ntab; + toml_table_t** base; + if (0 == (base = (toml_table_t**) REALLOC(tab->tab, (n+1) * sizeof(*base)))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + tab->tab = base; + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + dest = tab->tab[tab->ntab++]; + + /* save the key in the new table struct */ + dest->key = newkey; + return dest; } /* Create an array in the table. */ static toml_array_t* create_keyarray_in_table(context_t* ctx, - toml_table_t* tab, - token_t keytok, - int skip_if_exist) + toml_table_t* tab, + token_t keytok, + char kind) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); - - /* if key exists: error out */ - toml_array_t* dest = 0; - if (check_key(tab, newkey, 0, &dest, 0)) { - xfree(newkey); /* don't need this anymore */ + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); + + /* if key exists: error out */ + if (key_kind(tab, newkey)) { + xfree(newkey); /* don't need this anymore */ + e_key_exists_error(ctx, keytok.lineno, newkey); + return 0; /* not reached */ + } - /* special case skip if exists? */ - if (skip_if_exist) return dest; - - e_key_exists_error(ctx, keytok); - return 0; /* not reached */ - } + /* make a new array entry */ + int n = tab->narr; + toml_array_t** base; + if (0 == (base = (toml_array_t**) REALLOC(tab->arr, (n+1) * sizeof(*base)))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + tab->arr = base; + + if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + toml_array_t* dest = tab->arr[tab->narr++]; - /* make a new array entry */ - int n = tab->narr; - toml_array_t** base; - if (0 == (base = (toml_array_t**) REALLOC(tab->arr, (n+1) * sizeof(*base)))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - tab->arr = base; - - if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - dest = tab->arr[tab->narr++]; - - /* save the key in the new array struct */ - dest->key = newkey; - return dest; + /* save the key in the new array struct */ + dest->key = newkey; + dest->kind = kind; + return dest; } /* Create an array in an array */ static toml_array_t* create_array_in_array(context_t* ctx, - toml_array_t* parent) + toml_array_t* parent) { - int n = parent->nelem; - toml_array_t** base; - if (0 == (base = (toml_array_t**) REALLOC(parent->u.arr, (n+1) * sizeof(*base)))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - parent->u.arr = base; - - if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } + int n = parent->nelem; + toml_array_t** base; + if (0 == (base = (toml_array_t**) REALLOC(parent->u.arr, (n+1) * sizeof(*base)))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + parent->u.arr = base; + + if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } - return parent->u.arr[parent->nelem++]; + return parent->u.arr[parent->nelem++]; } /* Create a table in an array */ static toml_table_t* create_table_in_array(context_t* ctx, - toml_array_t* parent) + toml_array_t* parent) { - int n = parent->nelem; - toml_table_t** base; - if (0 == (base = (toml_table_t**) REALLOC(parent->u.tab, (n+1) * sizeof(*base)))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - parent->u.tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } + int n = parent->nelem; + toml_table_t** base; + if (0 == (base = (toml_table_t**) REALLOC(parent->u.tab, (n+1) * sizeof(*base)))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + parent->u.tab = base; + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } - return parent->u.tab[parent->nelem++]; + return parent->u.tab[parent->nelem++]; } -#define SKIP_NEWLINES(ctx) while (ctx->tok.tok == NEWLINE) next_token(ctx, 0) -#define EAT_TOKEN(ctx, typ) \ - if ((ctx)->tok.tok != typ) e_internal_error(ctx, FLINE); else next_token(ctx, 0) +#define SKIP_NEWLINES(ctx, isdotspecial) while (ctx->tok.tok == NEWLINE) next_token(ctx, isdotspecial) +#define EAT_TOKEN(ctx, typ, isdotspecial) \ + if ((ctx)->tok.tok != typ) e_internal_error(ctx, FLINE); else next_token(ctx, isdotspecial) static void parse_keyval(context_t* ctx, toml_table_t* tab); @@ -806,226 +863,243 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab); */ static void parse_table(context_t* ctx, toml_table_t* tab) { - EAT_TOKEN(ctx, LBRACE); + EAT_TOKEN(ctx, LBRACE, 1); - for (;;) { + for (;;) { if (ctx->tok.tok == NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); return; /* not reached */ } - /* until } */ - if (ctx->tok.tok == RBRACE) break; + /* until } */ + if (ctx->tok.tok == RBRACE) break; - if (ctx->tok.tok != STRING) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } - parse_keyval(ctx, tab); + if (ctx->tok.tok != STRING) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } + parse_keyval(ctx, tab); if (ctx->tok.tok == NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); return; /* not reached */ } - /* on comma, continue to scan for next keyval */ - if (ctx->tok.tok == COMMA) { - EAT_TOKEN(ctx, COMMA); - continue; - } - break; - } + /* on comma, continue to scan for next keyval */ + if (ctx->tok.tok == COMMA) { + EAT_TOKEN(ctx, COMMA, 1); + continue; + } + break; + } - if (ctx->tok.tok != RBRACE) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + if (ctx->tok.tok != RBRACE) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } - EAT_TOKEN(ctx, RBRACE); + EAT_TOKEN(ctx, RBRACE, 1); } static int valtype(const char* val) { - toml_timestamp_t ts; - if (*val == '\'' || *val == '"') return 's'; - if (0 == toml_rtob(val, 0)) return 'b'; - if (0 == toml_rtoi(val, 0)) return 'i'; - if (0 == toml_rtod(val, 0)) return 'd'; - if (0 == toml_rtots(val, &ts)) { - if (ts.year && ts.hour) return 'T'; /* timestamp */ - if (ts.year) return 'D'; /* date */ - return 't'; /* time */ - } - return 'u'; /* unknown */ + toml_timestamp_t ts; + if (*val == '\'' || *val == '"') return 's'; + if (0 == toml_rtob(val, 0)) return 'b'; + if (0 == toml_rtoi(val, 0)) return 'i'; + if (0 == toml_rtod(val, 0)) return 'd'; + if (0 == toml_rtots(val, &ts)) { + if (ts.year && ts.hour) return 'T'; /* timestamp */ + if (ts.year) return 'D'; /* date */ + return 't'; /* time */ + } + return 'u'; /* unknown */ } /* We are at '[...]' */ static void parse_array(context_t* ctx, toml_array_t* arr) { - EAT_TOKEN(ctx, LBRACKET); + EAT_TOKEN(ctx, LBRACKET, 0); - for (;;) { - SKIP_NEWLINES(ctx); - - /* until ] */ - if (ctx->tok.tok == RBRACKET) break; + for (;;) { + SKIP_NEWLINES(ctx, 0); + + /* until ] */ + if (ctx->tok.tok == RBRACKET) break; - switch (ctx->tok.tok) { - case STRING: - { - char* val = ctx->tok.ptr; - int vlen = ctx->tok.len; + switch (ctx->tok.tok) { + case STRING: + { + char* val = ctx->tok.ptr; + int vlen = ctx->tok.len; - /* set array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'v'; - /* check array kind */ - if (arr->kind != 'v') { - e_syntax_error(ctx, ctx->tok.lineno, - "a string array can only contain strings"); - return; /* not reached */ - } + /* set array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'v'; + /* check array kind */ + if (arr->kind != 'v') { + e_syntax_error(ctx, ctx->tok.lineno, + "a string array can only contain strings"); + return; /* not reached */ + } - /* make a new value in array */ - char** tmp = (char**) REALLOC(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); - if (!tmp) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - arr->u.val = tmp; - if (! (val = STRNDUP(val, vlen))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - arr->u.val[arr->nelem++] = val; + /* make a new value in array */ + char** tmp = (char**) REALLOC(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); + if (!tmp) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + arr->u.val = tmp; + if (! (val = STRNDUP(val, vlen))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + arr->u.val[arr->nelem++] = val; - /* set array type if this is the first entry, or check that the types matched. */ - if (arr->nelem == 1) - arr->type = valtype(arr->u.val[0]); - else if (arr->type != valtype(val)) { - e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); - return; /* not reached */ - } + /* set array type if this is the first entry, or check that the types matched. */ + if (arr->nelem == 1) + arr->type = valtype(arr->u.val[0]); + else if (arr->type != valtype(val)) { + e_syntax_error(ctx, ctx->tok.lineno, + "array type mismatch while processing array of values"); + return; /* not reached */ + } - EAT_TOKEN(ctx, STRING); - break; - } + EAT_TOKEN(ctx, STRING, 0); + break; + } - case LBRACKET: - { /* [ [array], [array] ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'a'; - /* check array kind */ - if (arr->kind != 'a') { - e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); - return; /* not reached */ - } - parse_array(ctx, create_array_in_array(ctx, arr)); - break; - } + case LBRACKET: + { /* [ [array], [array] ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'a'; + /* check array kind */ + if (arr->kind != 'a') { + e_syntax_error(ctx, ctx->tok.lineno, + "array type mismatch while processing array of arrays"); + return; /* not reached */ + } + parse_array(ctx, create_array_in_array(ctx, arr)); + break; + } - case LBRACE: - { /* [ {table}, {table} ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 't'; - /* check array kind */ - if (arr->kind != 't') { - e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); - return; /* not reached */ - } - parse_table(ctx, create_table_in_array(ctx, arr)); - break; - } - - default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + case LBRACE: + { /* [ {table}, {table} ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 't'; + /* check array kind */ + if (arr->kind != 't') { + e_syntax_error(ctx, ctx->tok.lineno, + "array type mismatch while processing array of tables"); + return; /* not reached */ + } + parse_table(ctx, create_table_in_array(ctx, arr)); + break; + } + + default: + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } - SKIP_NEWLINES(ctx); + SKIP_NEWLINES(ctx, 0); - /* on comma, continue to scan for next element */ - if (ctx->tok.tok == COMMA) { - EAT_TOKEN(ctx, COMMA); - continue; - } - break; - } + /* on comma, continue to scan for next element */ + if (ctx->tok.tok == COMMA) { + EAT_TOKEN(ctx, COMMA, 0); + continue; + } + break; + } - if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + if (ctx->tok.tok != RBRACKET) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } - EAT_TOKEN(ctx, RBRACKET); + EAT_TOKEN(ctx, RBRACKET, 1); } - /* handle lines like these: - key = "value" - key = [ array ] - key = { table } + key = "value" + key = [ array ] + key = { table } */ static void parse_keyval(context_t* ctx, toml_table_t* tab) { - if (ctx->tok.tok != STRING) { - e_internal_error(ctx, FLINE); - return; /* not reached */ + token_t key = ctx->tok; + EAT_TOKEN(ctx, STRING, 1); + + if (ctx->tok.tok == DOT) { + /* handle inline dotted key. + e.g. + physical.color = "orange" + physical.shape = "round" + */ + toml_table_t* subtab = 0; + { + char* subtabstr = normalize_key(ctx, key); + subtab = toml_table_in(tab, subtabstr); + xfree(subtabstr); + } + if (!subtab) { + subtab = create_keytable_in_table(ctx, tab, key); + } + next_token(ctx, 1); + parse_keyval(ctx, subtab); + return; } - token_t key = ctx->tok; + if (ctx->tok.tok != EQUAL) { + e_syntax_error(ctx, ctx->tok.lineno, "missing ="); + return; /* not reached */ + } - EAT_TOKEN(ctx, STRING); - if (ctx->tok.tok != EQUAL) { - e_syntax_error(ctx, ctx->tok.lineno, "missing ="); - return; /* not reached */ - } + next_token(ctx, 0); - EAT_TOKEN(ctx, EQUAL); + switch (ctx->tok.tok) { + case STRING: + { /* key = "value" */ + toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); + token_t val = ctx->tok; + assert(keyval->val == 0); + keyval->val = STRNDUP(val.ptr, val.len); + if (! keyval->val) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } - switch (ctx->tok.tok) { - case STRING: - { /* key = "value" */ - toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); - token_t val = ctx->tok; - assert(keyval->val == 0); - keyval->val = STRNDUP(val.ptr, val.len); - if (! keyval->val) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + next_token(ctx, 1); + + return; + } - EAT_TOKEN(ctx, STRING); - - return; - } + case LBRACKET: + { /* key = [ array ] */ + toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); + parse_array(ctx, arr); + return; + } - case LBRACKET: - { /* key = [ array ] */ - toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); - parse_array(ctx, arr); - return; - } + case LBRACE: + { /* key = { table } */ + toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); + parse_table(ctx, nxttab); + return; + } - case LBRACE: - { /* key = { table } */ - toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); - parse_table(ctx, nxttab); - return; - } - - default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + default: + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } } typedef struct tabpath_t tabpath_t; struct tabpath_t { - int cnt; - token_t key[10]; + int cnt; + token_t key[10]; }; /* at [x.y.z] or [[x.y.z]] @@ -1034,48 +1108,48 @@ struct tabpath_t { */ static void fill_tabpath(context_t* ctx) { - int lineno = ctx->tok.lineno; - int i; - - /* clear tpath */ - for (i = 0; i < ctx->tpath.top; i++) { - char** p = &ctx->tpath.key[i]; - xfree(*p); - *p = 0; - } - ctx->tpath.top = 0; - - for (;;) { - if (ctx->tpath.top >= 10) { - e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); - return; /* not reached */ - } + int lineno = ctx->tok.lineno; + int i; + + /* clear tpath */ + for (i = 0; i < ctx->tpath.top; i++) { + char** p = &ctx->tpath.key[i]; + xfree(*p); + *p = 0; + } + ctx->tpath.top = 0; + + for (;;) { + if (ctx->tpath.top >= 10) { + e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); + return; /* not reached */ + } - if (ctx->tok.tok != STRING) { - e_syntax_error(ctx, lineno, "invalid or missing key"); - return; /* not reached */ - } + if (ctx->tok.tok != STRING) { + e_syntax_error(ctx, lineno, "invalid or missing key"); + return; /* not reached */ + } - ctx->tpath.tok[ctx->tpath.top] = ctx->tok; - ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); - ctx->tpath.top++; - - next_token(ctx, 1); + ctx->tpath.tok[ctx->tpath.top] = ctx->tok; + ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); + ctx->tpath.top++; + + next_token(ctx, 1); - if (ctx->tok.tok == RBRACKET) break; + if (ctx->tok.tok == RBRACKET) break; - if (ctx->tok.tok != DOT) { - e_syntax_error(ctx, lineno, "invalid key"); - return; /* not reached */ - } + if (ctx->tok.tok != DOT) { + e_syntax_error(ctx, lineno, "invalid key"); + return; /* not reached */ + } - next_token(ctx, 1); - } + next_token(ctx, 1); + } - if (ctx->tpath.top <= 0) { - e_syntax_error(ctx, lineno, "empty table selector"); - return; /* not reached */ - } + if (ctx->tpath.top <= 0) { + e_syntax_error(ctx, lineno, "empty table selector"); + return; /* not reached */ + } } @@ -1084,78 +1158,78 @@ static void fill_tabpath(context_t* ctx) */ static void walk_tabpath(context_t* ctx) { - /* start from root */ - toml_table_t* curtab = ctx->root; - - for (int i = 0; i < ctx->tpath.top; i++) { - const char* key = ctx->tpath.key[i]; + /* start from root */ + toml_table_t* curtab = ctx->root; + + for (int i = 0; i < ctx->tpath.top; i++) { + const char* key = ctx->tpath.key[i]; - toml_keyval_t* nextval = 0; - toml_array_t* nextarr = 0; - toml_table_t* nexttab = 0; - switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { - case 't': - /* found a table. nexttab is where we will go next. */ - break; + toml_keyval_t* nextval = 0; + toml_array_t* nextarr = 0; + toml_table_t* nexttab = 0; + switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { + case 't': + /* found a table. nexttab is where we will go next. */ + break; - case 'a': - /* found an array. nexttab is the last table in the array. */ - if (nextarr->kind != 't') { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } - if (nextarr->nelem == 0) { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } - nexttab = nextarr->u.tab[nextarr->nelem-1]; - break; + case 'a': + /* found an array. nexttab is the last table in the array. */ + if (nextarr->kind != 't') { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } + if (nextarr->nelem == 0) { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } + nexttab = nextarr->u.tab[nextarr->nelem-1]; + break; - case 'v': - e_key_exists_error(ctx, ctx->tpath.tok[i]); - return; /* not reached */ + case 'v': + e_key_exists_error(ctx, ctx->tpath.tok[i].lineno, key); + return; /* not reached */ - default: - { /* Not found. Let's create an implicit table. */ - int n = curtab->ntab; - toml_table_t** base = (toml_table_t**) REALLOC(curtab->tab, (n+1) * sizeof(*base)); - if (0 == base) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - curtab->tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - if (0 == (base[n]->key = STRDUP(key))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - nexttab = curtab->tab[curtab->ntab++]; - - /* tabs created by walk_tabpath are considered implicit */ - nexttab->implicit = 1; - } - break; - } + default: + { /* Not found. Let's create an implicit table. */ + int n = curtab->ntab; + toml_table_t** base = (toml_table_t**) REALLOC(curtab->tab, (n+1) * sizeof(*base)); + if (0 == base) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + curtab->tab = base; + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + if (0 == (base[n]->key = STRDUP(key))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + nexttab = curtab->tab[curtab->ntab++]; + + /* tabs created by walk_tabpath are considered implicit */ + nexttab->implicit = 1; + } + break; + } - /* switch to next tab */ - curtab = nexttab; - } + /* switch to next tab */ + curtab = nexttab; + } - /* save it */ - ctx->curtab = curtab; + /* save it */ + ctx->curtab = curtab; } - + /* handle lines like [x.y.z] or [[x.y.z]] */ static void parse_select(context_t* ctx) { - assert(ctx->tok.tok == LBRACKET); + assert(ctx->tok.tok == LBRACKET); /* true if [[ */ int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '['); @@ -1163,512 +1237,563 @@ static void parse_select(context_t* ctx) and '[ [' would be taken as '[[', which is wrong. */ /* eat [ or [[ */ - next_token(ctx, 1 /* DOT IS SPECIAL */); + EAT_TOKEN(ctx, LBRACKET, 1); if (llb) { assert(ctx->tok.tok == LBRACKET); - next_token(ctx, 1 /* DOT IS SPECIAL */); - } + EAT_TOKEN(ctx, LBRACKET, 1); + } - fill_tabpath(ctx); + fill_tabpath(ctx); - /* For [x.y.z] or [[x.y.z]], remove z from tpath. - */ - token_t z = ctx->tpath.tok[ctx->tpath.top-1]; - xfree(ctx->tpath.key[ctx->tpath.top-1]); - ctx->tpath.top--; + /* For [x.y.z] or [[x.y.z]], remove z from tpath. + */ + token_t z = ctx->tpath.tok[ctx->tpath.top-1]; + xfree(ctx->tpath.key[ctx->tpath.top-1]); + ctx->tpath.top--; /* set up ctx->curtab */ - walk_tabpath(ctx); + walk_tabpath(ctx); - if (! llb) { - /* [x.y.z] -> create z = {} in x.y */ - ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); - } else { - /* [[x.y.z]] -> create z = [] in x.y */ - toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z, - 1 /*skip_if_exist*/); - if (!arr) { - e_syntax_error(ctx, z.lineno, "key exists"); - return; - } - if (arr->kind == 0) arr->kind = 't'; - if (arr->kind != 't') { - e_syntax_error(ctx, z.lineno, "array mismatch"); - return; /* not reached */ - } - - /* add to z[] */ - toml_table_t* dest; + if (! llb) { + /* [x.y.z] -> create z = {} in x.y */ + ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); + } else { + /* [[x.y.z]] -> create z = [] in x.y */ + toml_array_t* arr = 0; { - int n = arr->nelem; - toml_table_t** base = REALLOC(arr->u.tab, (n+1) * sizeof(*base)); - if (0 == base) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - arr->u.tab = base; - - if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - if (0 == (base[n]->key = STRDUP("__anon__"))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - dest = arr->u.tab[arr->nelem++]; + char* zstr = normalize_key(ctx, z); + arr = toml_array_in(ctx->curtab, zstr); + xfree(zstr); } + if (!arr) { + arr = create_keyarray_in_table(ctx, ctx->curtab, z, 't'); + if (!arr) { + e_internal_error(ctx, FLINE); + return; + } + } + if (arr->kind != 't') { + e_syntax_error(ctx, z.lineno, "array mismatch"); + return; /* not reached */ + } - ctx->curtab = dest; - } + /* add to z[] */ + toml_table_t* dest; + { + int n = arr->nelem; + toml_table_t** base = REALLOC(arr->u.tab, (n+1) * sizeof(*base)); + if (0 == base) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + arr->u.tab = base; + + if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + if (0 == (base[n]->key = STRDUP("__anon__"))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + dest = arr->u.tab[arr->nelem++]; + } - if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "expects ]"); - return; /* not reached */ - } + ctx->curtab = dest; + } + + if (ctx->tok.tok != RBRACKET) { + e_syntax_error(ctx, ctx->tok.lineno, "expects ]"); + return; /* not reached */ + } if (llb) { if (! (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) { - e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); + e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); return; /* not reached */ } - EAT_TOKEN(ctx, RBRACKET); + EAT_TOKEN(ctx, RBRACKET, 1); } - EAT_TOKEN(ctx, RBRACKET); + EAT_TOKEN(ctx, RBRACKET, 1); - if (ctx->tok.tok != NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); - return; /* not reached */ - } + if (ctx->tok.tok != NEWLINE) { + e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); + return; /* not reached */ + } } toml_table_t* toml_parse(char* conf, - char* errbuf, - int errbufsz) + char* errbuf, + int errbufsz) { - context_t ctx; + context_t ctx; - // clear errbuf - if (errbufsz <= 0) errbufsz = 0; - if (errbufsz > 0) errbuf[0] = 0; + // clear errbuf + if (errbufsz <= 0) errbufsz = 0; + if (errbufsz > 0) errbuf[0] = 0; - // init context - memset(&ctx, 0, sizeof(ctx)); - ctx.start = conf; - ctx.stop = ctx.start + strlen(conf); - ctx.errbuf = errbuf; - ctx.errbufsz = errbufsz; + // init context + memset(&ctx, 0, sizeof(ctx)); + ctx.start = conf; + ctx.stop = ctx.start + strlen(conf); + ctx.errbuf = errbuf; + ctx.errbufsz = errbufsz; - // start with an artificial newline of length 0 - ctx.tok.tok = NEWLINE; - ctx.tok.lineno = 1; - ctx.tok.ptr = conf; - ctx.tok.len = 0; + // start with an artificial newline of length 0 + ctx.tok.tok = NEWLINE; + ctx.tok.lineno = 1; + ctx.tok.ptr = conf; + ctx.tok.len = 0; - // make a root table - if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { - /* do not call outofmemory() here... setjmp not done yet */ - snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE); - return 0; - } + // make a root table + if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { + /* do not call outofmemory() here... setjmp not done yet */ + snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE); + return 0; + } - // set root as default table - ctx.curtab = ctx.root; + // set root as default table + ctx.curtab = ctx.root; - if (0 != setjmp(ctx.jmp)) { - // Got here from a long_jmp. Something bad has happened. - // Free resources and return error. - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - toml_free(ctx.root); - return 0; - } + if (0 != setjmp(ctx.jmp)) { + // Got here from a long_jmp. Something bad has happened. + // Free resources and return error. + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + toml_free(ctx.root); + return 0; + } - /* Scan forward until EOF */ - for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { - switch (tok.tok) { - - case NEWLINE: - next_token(&ctx, 1); - break; - - case STRING: - parse_keyval(&ctx, ctx.curtab); - if (ctx.tok.tok != NEWLINE) { - e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); - return 0; /* not reached */ - } + /* Scan forward until EOF */ + for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { + switch (tok.tok) { + + case NEWLINE: + next_token(&ctx, 1); + break; + + case STRING: + parse_keyval(&ctx, ctx.curtab); + if (ctx.tok.tok != NEWLINE) { + e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); + return 0; /* not reached */ + } - EAT_TOKEN(&ctx, NEWLINE); - break; - - case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ - parse_select(&ctx); - break; - - default: - snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); - longjmp(ctx.jmp, 1); - } - } + EAT_TOKEN(&ctx, NEWLINE, 1); + break; + + case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ + parse_select(&ctx); + break; + + default: + snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); + longjmp(ctx.jmp, 1); + } + } - /* success */ - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - return ctx.root; + /* success */ + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + return ctx.root; } toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz) + char* errbuf, + int errbufsz) { - int bufsz = 0; - char* buf = 0; - int off = 0; + int bufsz = 0; + char* buf = 0; + int off = 0; - /* prime the buf[] */ - bufsz = 1000; - if (! (buf = MALLOC(bufsz + 1))) { - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } + /* prime the buf[] */ + bufsz = 1000; + if (! (buf = MALLOC(bufsz + 1))) { + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } - /* read from fp into buf */ - while (! feof(fp)) { - bufsz += 1000; - - /* Allocate 1 extra byte because we will tag on a NUL */ - char* x = REALLOC(buf, bufsz + 1); - if (!x) { - snprintf(errbuf, errbufsz, "out of memory"); - xfree(buf); - return 0; - } - buf = x; + /* read from fp into buf */ + while (! feof(fp)) { + bufsz += 1000; + + /* Allocate 1 extra byte because we will tag on a NUL */ + char* x = REALLOC(buf, bufsz + 1); + if (!x) { + snprintf(errbuf, errbufsz, "out of memory"); + xfree(buf); + return 0; + } + buf = x; - errno = 0; - int n = fread(buf + off, 1, bufsz - off, fp); - if (ferror(fp)) { - snprintf(errbuf, errbufsz, "%s", - errno ? strerror(errno) : "Error reading file"); - xfree(buf); - return 0; - } - off += n; - } + errno = 0; + int n = fread(buf + off, 1, bufsz - off, fp); + if (ferror(fp)) { + snprintf(errbuf, errbufsz, "%s", + errno ? strerror(errno) : "Error reading file"); + xfree(buf); + return 0; + } + off += n; + } - /* tag on a NUL to cap the string */ - buf[off] = 0; /* we accounted for this byte in the REALLOC() above. */ + /* tag on a NUL to cap the string */ + buf[off] = 0; /* we accounted for this byte in the REALLOC() above. */ - /* parse it, cleanup and finish */ - toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); - xfree(buf); - return ret; + /* parse it, cleanup and finish */ + toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); + xfree(buf); + return ret; } static void xfree_kval(toml_keyval_t* p) { - if (!p) return; - xfree(p->key); - xfree(p->val); - xfree(p); + if (!p) return; + xfree(p->key); + xfree(p->val); + xfree(p); } static void xfree_tab(toml_table_t* p); static void xfree_arr(toml_array_t* p) { - if (!p) return; + if (!p) return; - xfree(p->key); - switch (p->kind) { - case 'v': - for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); - xfree(p->u.val); - break; + xfree(p->key); + switch (p->kind) { + case 'v': + for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); + xfree(p->u.val); + break; - case 'a': - for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); - xfree(p->u.arr); - break; + case 'a': + for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); + xfree(p->u.arr); + break; - case 't': - for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); - xfree(p->u.tab); - break; - } + case 't': + for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); + xfree(p->u.tab); + break; + } - xfree(p); + xfree(p); } static void xfree_tab(toml_table_t* p) { - int i; - - if (!p) return; - - xfree(p->key); - - for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); - xfree(p->kval); + int i; + + if (!p) return; + + xfree(p->key); + + for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); + xfree(p->kval); - for (i = 0; i < p->narr; i++) xfree_arr(p->arr[i]); - xfree(p->arr); + for (i = 0; i < p->narr; i++) xfree_arr(p->arr[i]); + xfree(p->arr); - for (i = 0; i < p->ntab; i++) xfree_tab(p->tab[i]); - xfree(p->tab); + for (i = 0; i < p->ntab; i++) xfree_tab(p->tab[i]); + xfree(p->tab); - xfree(p); + xfree(p); } void toml_free(toml_table_t* tab) { - xfree_tab(tab); + xfree_tab(tab); } static tokentype_t ret_token(context_t* ctx, tokentype_t tok, int lineno, char* ptr, int len) { - token_t t; - t.tok = tok; - t.lineno = lineno; - t.ptr = ptr; - t.len = len; - t.eof = 0; - ctx->tok = t; - return tok; + token_t t; + t.tok = tok; + t.lineno = lineno; + t.ptr = ptr; + t.len = len; + t.eof = 0; + ctx->tok = t; + return tok; } static tokentype_t ret_eof(context_t* ctx, int lineno) { - ret_token(ctx, NEWLINE, lineno, ctx->stop, 0); - ctx->tok.eof = 1; - return ctx->tok.tok; + ret_token(ctx, NEWLINE, lineno, ctx->stop, 0); + ctx->tok.eof = 1; + return ctx->tok.tok; } - + + +/* Scan p for n digits compositing entirely of [0-9] */ +static int scan_digits(const char* p, int n) +{ + int ret = 0; + for ( ; n > 0 && isdigit(*p); n--, p++) { + ret = 10 * ret + (*p - '0'); + } + return n ? -1 : ret; +} + +static int scan_date(const char* p, int* YY, int* MM, int* DD) +{ + int year, month, day; + year = scan_digits(p, 4); + month = (year >= 0 && p[4] == '-') ? scan_digits(p+5, 2) : -1; + day = (month >= 0 && p[7] == '-') ? scan_digits(p+8, 2) : -1; + if (YY) *YY = year; + if (MM) *MM = month; + if (DD) *DD = day; + return (year >= 0 && month >= 0 && day >= 0) ? 0 : -1; +} + +static int scan_time(const char* p, int* hh, int* mm, int* ss) +{ + int hour, minute, second; + hour = scan_digits(p, 2); + minute = (hour >= 0 && p[2] == ':') ? scan_digits(p+3, 2) : -1; + second = (minute >= 0 && p[5] == ':') ? scan_digits(p+6, 2) : -1; + if (hh) *hh = hour; + if (mm) *mm = minute; + if (ss) *ss = second; + return (hour >= 0 && minute >= 0 && second >= 0) ? 0 : -1; +} + static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) { - char* orig = p; - if (0 == strncmp(p, "'''", 3)) { - p = strstr(p + 3, "'''"); - if (0 == p) { - e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); - return 0; /* not reached */ - } + char* orig = p; + if (0 == strncmp(p, "'''", 3)) { + p = strstr(p + 3, "'''"); + if (0 == p) { + e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); + return 0; /* not reached */ + } - return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); - } + return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); + } - if (0 == strncmp(p, "\"\"\"", 3)) { - int hexreq = 0; /* #hex required */ - int escape = 0; - int qcnt = 0; /* count quote */ - for (p += 3; *p && qcnt < 3; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - if (*p == '\n') continue; /* allow for line ending backslash */ - e_syntax_error(ctx, lineno, "bad escape char"); - return 0; /* not reached */ - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); - return 0; /* not reached */ - } - if (*p == '\\') { escape = 1; continue; } - qcnt = (*p == '"') ? qcnt + 1 : 0; - } - if (qcnt != 3) { - e_syntax_error(ctx, lineno, "unterminated triple-quote"); - return 0; /* not reached */ - } + if (0 == strncmp(p, "\"\"\"", 3)) { + int hexreq = 0; /* #hex required */ + int escape = 0; + int qcnt = 0; /* count quote */ + for (p += 3; *p && qcnt < 3; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + if (p[strspn(p, " \t\r")] == '\n') continue; /* allow for line ending backslash */ + e_syntax_error(ctx, lineno, "bad escape char"); + return 0; /* not reached */ + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + e_syntax_error(ctx, lineno, "expect hex char"); + return 0; /* not reached */ + } + if (*p == '\\') { escape = 1; continue; } + qcnt = (*p == '"') ? qcnt + 1 : 0; + } + if (qcnt != 3) { + e_syntax_error(ctx, lineno, "unterminated triple-quote"); + return 0; /* not reached */ + } + return ret_token(ctx, STRING, lineno, orig, p - orig); + } + + if ('\'' == *p) { + for (p++; *p && *p != '\n' && *p != '\''; p++); + if (*p != '\'') { + e_syntax_error(ctx, lineno, "unterminated s-quote"); + return 0; /* not reached */ + } + + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + } + + if ('\"' == *p) { + int hexreq = 0; /* #hex required */ + int escape = 0; + for (p++; *p; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + e_syntax_error(ctx, lineno, "bad escape char"); + return 0; /* not reached */ + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + e_syntax_error(ctx, lineno, "expect hex char"); + return 0; /* not reached */ + } + if (*p == '\\') { escape = 1; continue; } + if (*p == '\n') break; + if (*p == '"') break; + } + if (*p != '"') { + e_syntax_error(ctx, lineno, "unterminated quote"); + return 0; /* not reached */ + } + + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + } + + /* check for timestamp without quotes */ + if (0 == scan_date(p, 0, 0, 0) || 0 == scan_time(p, 0, 0, 0)) { + // forward thru the timestamp + for ( ; strchr("0123456789.:+-T Z", toupper(*p)); p++); + // squeeze out any spaces at end of string + for ( ; p[-1] == ' '; p--); + // tokenize return ret_token(ctx, STRING, lineno, orig, p - orig); } - if ('\'' == *p) { - for (p++; *p && *p != '\n' && *p != '\''; p++); - if (*p != '\'') { - e_syntax_error(ctx, lineno, "unterminated s-quote"); - return 0; /* not reached */ - } + /* literals */ + for ( ; *p && *p != '\n'; p++) { + int ch = *p; + if (ch == '.' && dotisspecial) break; + if ('A' <= ch && ch <= 'Z') continue; + if ('a' <= ch && ch <= 'z') continue; + if (strchr("0123456789+-_.", ch)) continue; + break; + } - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); - } - - if ('\"' == *p) { - int hexreq = 0; /* #hex required */ - int escape = 0; - for (p++; *p; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - e_syntax_error(ctx, lineno, "bad escape char"); - return 0; /* not reached */ - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); - return 0; /* not reached */ - } - if (*p == '\\') { escape = 1; continue; } - if (*p == '\n') break; - if (*p == '"') break; - } - if (*p != '"') { - e_syntax_error(ctx, lineno, "unterminated quote"); - return 0; /* not reached */ - } - - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); - } - - for ( ; *p && *p != '\n'; p++) { - int ch = *p; - if (ch == '.' && dotisspecial) break; - if ('A' <= ch && ch <= 'Z') continue; - if ('a' <= ch && ch <= 'z') continue; - if ('0' <= ch && ch <= '9') continue; - if (strchr("+-_.:", ch)) continue; - break; - } - - return ret_token(ctx, STRING, lineno, orig, p - orig); + return ret_token(ctx, STRING, lineno, orig, p - orig); } static tokentype_t next_token(context_t* ctx, int dotisspecial) { - int lineno = ctx->tok.lineno; - char* p = ctx->tok.ptr; - int i; + int lineno = ctx->tok.lineno; + char* p = ctx->tok.ptr; + int i; - /* eat this tok */ - for (i = 0; i < ctx->tok.len; i++) { - if (*p++ == '\n') - lineno++; - } + /* eat this tok */ + for (i = 0; i < ctx->tok.len; i++) { + if (*p++ == '\n') + lineno++; + } - /* make next tok */ - while (p < ctx->stop) { - /* skip comment. stop just before the \n. */ - if (*p == '#') { - for (p++; p < ctx->stop && *p != '\n'; p++); - continue; - } + /* make next tok */ + while (p < ctx->stop) { + /* skip comment. stop just before the \n. */ + if (*p == '#') { + for (p++; p < ctx->stop && *p != '\n'; p++); + continue; + } - if (dotisspecial && *p == '.') - return ret_token(ctx, DOT, lineno, p, 1); - - switch (*p) { - case ',': return ret_token(ctx, COMMA, lineno, p, 1); - case '=': return ret_token(ctx, EQUAL, lineno, p, 1); - case '{': return ret_token(ctx, LBRACE, lineno, p, 1); - case '}': return ret_token(ctx, RBRACE, lineno, p, 1); - case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); - case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); - case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); - case '\r': case ' ': case '\t': - /* ignore white spaces */ - p++; - continue; - } + if (dotisspecial && *p == '.') + return ret_token(ctx, DOT, lineno, p, 1); + + switch (*p) { + case ',': return ret_token(ctx, COMMA, lineno, p, 1); + case '=': return ret_token(ctx, EQUAL, lineno, p, 1); + case '{': return ret_token(ctx, LBRACE, lineno, p, 1); + case '}': return ret_token(ctx, RBRACE, lineno, p, 1); + case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); + case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); + case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); + case '\r': case ' ': case '\t': + /* ignore white spaces */ + p++; + continue; + } - return scan_string(ctx, p, lineno, dotisspecial); - } + return scan_string(ctx, p, lineno, dotisspecial); + } - return ret_eof(ctx, lineno); + return ret_eof(ctx, lineno); } const char* toml_key_in(toml_table_t* tab, int keyidx) { - if (keyidx < tab->nkval) return tab->kval[keyidx]->key; - - keyidx -= tab->nkval; - if (keyidx < tab->narr) return tab->arr[keyidx]->key; - - keyidx -= tab->narr; - if (keyidx < tab->ntab) return tab->tab[keyidx]->key; + if (keyidx < tab->nkval) return tab->kval[keyidx]->key; + + keyidx -= tab->nkval; + if (keyidx < tab->narr) return tab->arr[keyidx]->key; + + keyidx -= tab->narr; + if (keyidx < tab->ntab) return tab->tab[keyidx]->key; - return 0; + return 0; } const char* toml_raw_in(toml_table_t* tab, const char* key) { - int i; - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) - return tab->kval[i]->val; - } - return 0; + int i; + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) + return tab->kval[i]->val; + } + return 0; } toml_array_t* toml_array_in(toml_table_t* tab, const char* key) { - int i; - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) - return tab->arr[i]; - } - return 0; + int i; + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) + return tab->arr[i]; + } + return 0; } toml_table_t* toml_table_in(toml_table_t* tab, const char* key) { - int i; - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) - return tab->tab[i]; - } - return 0; + int i; + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) + return tab->tab[i]; + } + return 0; } const char* toml_raw_at(toml_array_t* arr, int idx) { - if (arr->kind != 'v') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.val[idx]; + if (arr->kind != 'v') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.val[idx]; } char toml_array_kind(toml_array_t* arr) { - return arr->kind; + return arr->kind; } char toml_array_type(toml_array_t* arr) { - if (arr->kind != 'v') - return 0; + if (arr->kind != 'v') + return 0; - if (arr->nelem == 0) - return 0; + if (arr->nelem == 0) + return 0; - return arr->type; + return arr->type; } int toml_array_nelem(toml_array_t* arr) { - return arr->nelem; + return arr->nelem; } const char* toml_array_key(toml_array_t* arr) @@ -1698,161 +1823,150 @@ const char* toml_table_key(toml_table_t* tab) toml_array_t* toml_array_at(toml_array_t* arr, int idx) { - if (arr->kind != 'a') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.arr[idx]; + if (arr->kind != 'a') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.arr[idx]; } toml_table_t* toml_table_at(toml_array_t* arr, int idx) { - if (arr->kind != 't') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.tab[idx]; + if (arr->kind != 't') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.tab[idx]; } int toml_rtots(const char* src_, toml_timestamp_t* ret) { - if (! src_) return -1; - - const char* p = src_; - const char* q = src_ + strlen(src_); - int64_t val; - int i; - - memset(ret, 0, sizeof(*ret)); + if (! src_) return -1; + + const char* p = src_; + int must_parse_time = 0; + + memset(ret, 0, sizeof(*ret)); - /* parse date YYYY-MM-DD */ - val = 0; - if (q - p > 4 && p[4] == '-') { - for (i = 0; i < 10; i++, p++) { - int xx = *p; - if (xx == '-') { - if (i == 4 || i == 7) continue; else return -1; - } - if (! ('0' <= xx && xx <= '9')) return -1; - val = val * 10 + (xx - '0'); - } - ret->day = &ret->__buffer.day; - ret->month = &ret->__buffer.month; - ret->year = &ret->__buffer.year; - - *ret->day = val % 100; val /= 100; - *ret->month = val % 100; val /= 100; - *ret->year = val; + int* year = &ret->__buffer.year; + int* month = &ret->__buffer.month; + int* day = &ret->__buffer.day; + int* hour = &ret->__buffer.hour; + int* minute = &ret->__buffer.minute; + int* second = &ret->__buffer.second; + int* millisec = &ret->__buffer.millisec; + + /* parse date YYYY-MM-DD */ + if (0 == scan_date(p, year, month, day)) { + ret->year = year; + ret->month = month; + ret->day = day; + p += 10; if (*p) { - // parse the T or space separator - if (*p != 'T' && *p != ' ') return -1; - p++; - } - } - if (q == p) return 0; + // parse the T or space separator + if (*p != 'T' && *p != ' ') return -1; + must_parse_time = 1; + p++; + } + } - /* parse time HH:MM:SS */ - val = 0; - if (q - p < 8) return -1; - for (i = 0; i < 8; i++, p++) { - int xx = *p; - if (xx == ':') { - if (i == 2 || i == 5) continue; else return -1; + /* parse time HH:MM:SS */ + if (0 == scan_time(p, hour, minute, second)) { + ret->hour = hour; + ret->minute = minute; + ret->second = second; + + /* optionally, parse millisec */ + p += 8; + if (*p == '.') { + char* qq; + p++; + errno = 0; + *millisec = strtol(p, &qq, 0); + if (errno) { + return -1; + } + while (*millisec > 999) { + *millisec /= 10; + } + + ret->millisec = millisec; + p = qq; } - if (! ('0' <= xx && xx <= '9')) return -1; - val = val * 10 + (xx - '0'); - } - ret->second = &ret->__buffer.second; - ret->minute = &ret->__buffer.minute; - ret->hour = &ret->__buffer.hour; - - *ret->second = val % 100; val /= 100; - *ret->minute = val % 100; val /= 100; - *ret->hour = val; - - /* parse millisec */ - if (*p == '.') { - val = 0; - p++; - if ('0' <= *p && *p <= '9') { - val = (*p++ - '0') * 100; - if ('0' <= *p && *p <= '9') { - val += (*p++ - '0') * 10; - if ('0' <= *p && *p <= '9') { - val += (*p++ - '0'); + + if (*p) { + /* parse and copy Z */ + char* z = ret->__buffer.z; + ret->z = z; + if (*p == 'Z' || *p == 'z') { + *z++ = 'Z'; p++; + *z = 0; + + } else if (*p == '+' || *p == '-') { + *z++ = *p++; + + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; + *z++ = *p++; + *z++ = *p++; + + if (*p == ':') { + *z++ = *p++; + + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; + *z++ = *p++; + *z++ = *p++; } + + *z = 0; } } - ret->millisec = &ret->__buffer.millisec; - *ret->millisec = val; } - if (q == p) return 0; + if (*p != 0) + return -1; - /* parse and copy Z */ - ret->z = ret->__buffer.z; - char* z = ret->z; - if (*p == 'Z') { - *z++ = *p++; - *z = 0; - return (p == q) ? 0 : -1; - } - if (*p == '+' || *p == '-') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - - if (*p == ':') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - } - - *z = 0; - } - return (p == q) ? 0 : -1; + if (must_parse_time && !ret->hour) + return -1; + + return 0; } /* Raw to boolean */ int toml_rtob(const char* src, int* ret_) { - if (!src) return -1; - int dummy; - int* ret = ret_ ? ret_ : &dummy; - - if (0 == strcmp(src, "true")) { - *ret = 1; - return 0; - } - if (0 == strcmp(src, "false")) { - *ret = 0; - return 0; - } - return -1; + if (!src) return -1; + int dummy; + int* ret = ret_ ? ret_ : &dummy; + + if (0 == strcmp(src, "true")) { + *ret = 1; + return 0; + } + if (0 == strcmp(src, "false")) { + *ret = 0; + return 0; + } + return -1; } /* Raw to integer */ int toml_rtoi(const char* src, int64_t* ret_) { - if (!src) return -1; - - char buf[100]; - char* p = buf; - char* q = p + sizeof(buf); - const char* s = src; - int base = 0; - int64_t dummy; - int64_t* ret = ret_ ? ret_ : &dummy; - + if (!src) return -1; + + char buf[100]; + char* p = buf; + char* q = p + sizeof(buf); + const char* s = src; + int base = 0; + int64_t dummy; + int64_t* ret = ret_ ? ret_ : &dummy; + - /* allow +/- */ + /* allow +/- */ if (s[0] == '+' || s[0] == '-') *p++ = *s++; @@ -1860,60 +1974,60 @@ int toml_rtoi(const char* src, int64_t* ret_) if (s[0] == '_') return -1; - /* if 0 ... */ - if ('0' == s[0]) { - switch (s[1]) { - case 'x': base = 16; s += 2; break; - case 'o': base = 8; s += 2; break; - case 'b': base = 2; s += 2; break; - case '\0': return *ret = 0, 0; - default: - /* ensure no other digits after it */ - if (s[1]) return -1; - } - } + /* if 0 ... */ + if ('0' == s[0]) { + switch (s[1]) { + case 'x': base = 16; s += 2; break; + case 'o': base = 8; s += 2; break; + case 'b': base = 2; s += 2; break; + case '\0': return *ret = 0, 0; + default: + /* ensure no other digits after it */ + if (s[1]) return -1; + } + } - /* just strip underscores and pass to strtoll */ - while (*s && p < q) { - int ch = *s++; + /* just strip underscores and pass to strtoll */ + while (*s && p < q) { + int ch = *s++; switch (ch) { case '_': // disallow '__' if (s[0] == '_') return -1; - continue; /* skip _ */ + continue; /* skip _ */ default: break; } - *p++ = ch; - } - if (*s || p == q) return -1; + *p++ = ch; + } + if (*s || p == q) return -1; /* last char cannot be '_' */ if (s[-1] == '_') return -1; - - /* cap with NUL */ - *p = 0; + + /* cap with NUL */ + *p = 0; - /* Run strtoll on buf to get the integer */ - char* endp; - errno = 0; - *ret = strtoll(buf, &endp, base); - return (errno || *endp) ? -1 : 0; + /* Run strtoll on buf to get the integer */ + char* endp; + errno = 0; + *ret = strtoll(buf, &endp, base); + return (errno || *endp) ? -1 : 0; } int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) { - if (!src) return -1; - - char* p = buf; - char* q = p + buflen; - const char* s = src; - double dummy; - double* ret = ret_ ? ret_ : &dummy; + if (!src) return -1; + + char* p = buf; + char* q = p + buflen; + const char* s = src; + double dummy; + double* ret = ret_ ? ret_ : &dummy; - /* allow +/- */ + /* allow +/- */ if (s[0] == '+' || s[0] == '-') *p++ = *s++; @@ -1925,13 +2039,13 @@ int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) if (s[0] == '.') return -1; - /* zero must be followed by . or NUL */ - if (s[0] == '0' && s[1] && s[1] != '.') + /* zero must be followed by . or 'e', or NUL */ + if (s[0] == '0' && s[1] && !strchr("eE.", s[1])) return -1; - /* just strip underscores and pass to strtod */ - while (*s && p < q) { - int ch = *s++; + /* just strip underscores and pass to strtod */ + while (*s && p < q) { + int ch = *s++; switch (ch) { case '.': if (s[-2] == '_') return -1; @@ -1944,24 +2058,24 @@ int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) default: break; } - *p++ = ch; - } - if (*s || p == q) return -1; /* reached end of string or buffer is full? */ + *p++ = ch; + } + if (*s || p == q) return -1; /* reached end of string or buffer is full? */ /* last char cannot be '_' */ if (s[-1] == '_') return -1; - if (p != buf && p[-1] == '.') - return -1; /* no trailing zero */ + if (p != buf && p[-1] == '.') + return -1; /* no trailing zero */ - /* cap with NUL */ - *p = 0; + /* cap with NUL */ + *p = 0; - /* Run strtod on buf to get the value */ - char* endp; - errno = 0; - *ret = strtod(buf, &endp); - return (errno || *endp) ? -1 : 0; + /* Run strtod on buf to get the value */ + char* endp; + errno = 0; + *ret = strtod(buf, &endp); + return (errno || *endp) ? -1 : 0; } int toml_rtod(const char* src, double* ret_) @@ -1971,86 +2085,72 @@ int toml_rtod(const char* src, double* ret_) } -static char* kill_line_ending_backslash(char* str) -{ - if (!str) return 0; - - /* first round: find (backslash, \n) */ - char* p = str; - while (0 != (p = strstr(p, "\\\n"))) { - char* q = (p + 1); - q += strspn(q, " \t\r\n"); - memmove(p, q, strlen(q) + 1); - } - /* second round: find (backslash, \r, \n) */ - p = str; - while (0 != (p = strstr(p, "\\\r\n"))) { - char* q = (p + 1); - q += strspn(q, " \t\r\n"); - memmove(p, q, strlen(q) + 1); - } - - return str; -} int toml_rtos(const char* src, char** ret) { - if (!src) return -1; - if (*src != '\'' && *src != '"') return -1; - - *ret = 0; - int srclen = strlen(src); - if (*src == '\'') { - if (0 == strncmp(src, "'''", 3)) { - const char* sp = src + 3; - const char* sq = src + srclen - 3; - /* last 3 chars in src must be ''' */ - if (! (sp <= sq && 0 == strcmp(sq, "'''"))) - return -1; - - /* skip first new line right after ''' */ - if (*sp == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; - - *ret = kill_line_ending_backslash(STRNDUP(sp, sq - sp)); - } else { - const char* sp = src + 1; - const char* sq = src + srclen - 1; - /* last char in src must be ' */ - if (! (sp <= sq && *sq == '\'')) - return -1; - /* copy from sp to p */ - *ret = STRNDUP(sp, sq - sp); - } - return *ret ? 0 : -1; - } - + char dummy_errbuf[1]; + int multiline = 0; const char* sp; const char* sq; - if (0 == strncmp(src, "\"\"\"", 3)) { - sp = src + 3; - sq = src + srclen - 3; - if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) - return -1; - - /* skip first new line right after """ */ - if (*sp == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; - } else { - sp = src + 1; - sq = src + srclen - 1; - if (! (sp <= sq && *sq == '"')) - return -1; - } + + if (!src) return -1; + if (*src != '\'' && *src != '"') return -1; - char dummy_errbuf[1]; - *ret = normalize_string(sp, sq - sp, - 1, // flag kill_line_ending_backslash + *ret = 0; + int srclen = strlen(src); + if (*src == '\'') { + if (0 == strncmp(src, "'''", 3)) { + multiline = 1; + sp = src + 3; + sq = src + srclen - 3; + /* last 3 chars in src must be ''' */ + if (! (sp <= sq && 0 == strcmp(sq, "'''"))) + return -1; + + /* skip first new line right after ''' */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; + + } else { + sp = src + 1; + sq = src + srclen - 1; + /* last char in src must be ' */ + if (! (sp <= sq && *sq == '\'')) + return -1; + /* copy from sp to p */ + *ret = STRNDUP(sp, sq - sp); + } + + *ret = norm_lit_str(sp, sq - sp, + multiline, dummy_errbuf, sizeof(dummy_errbuf)); - return *ret ? 0 : -1; + return *ret ? 0 : -1; + } + + if (0 == strncmp(src, "\"\"\"", 3)) { + multiline = 1; + sp = src + 3; + sq = src + srclen - 3; + if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) + return -1; + + /* skip first new line right after """ */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; + } else { + sp = src + 1; + sq = src + srclen - 1; + if (! (sp <= sq && *sq == '"')) + return -1; + } + + *ret = norm_basic_str(sp, sq - sp, + multiline, + dummy_errbuf, sizeof(dummy_errbuf)); + return *ret ? 0 : -1; } From a1a8911503af4e263d9fe65b5789a8eeee92a357 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 9 Oct 2019 16:40:11 -0700 Subject: [PATCH 032/138] Updated Readme.md v0.5 compliant --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e1ff88..095a9e1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # tomlc99 -TOML in c99; v0.4.0 compliant. +TOML in c99; v0.5.0 compliant. # Usage From 9ed009b95011a58cdda71aa9f791976757969440 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 9 Oct 2019 16:44:07 -0700 Subject: [PATCH 033/138] simplify example in README.md --- README.md | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 095a9e1..2ef0526 100644 --- a/README.md +++ b/README.md @@ -28,47 +28,33 @@ convert it to a string or integer depending on context. /* open file and parse */ if (0 == (fp = fopen(FNAME, "r"))) { - perror("fopen"); - exit(1); + return handle_error(); } conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); fclose(fp); if (0 == conf) { - fprintf(stderr, "ERROR: %s\n", errbuf); - exit(1); + return handle_error(); } /* locate the [server] table */ if (0 == (server = toml_table_in(conf, "server"))) { - fprintf(stderr, "ERROR: missing [server]\n"); - toml_free(conf); - exit(1); + return handle_error(); } /* extract host config value */ if (0 == (raw = toml_raw_in(server, "host"))) { - fprintf(stderr, "ERROR: missing 'host' in [server]\n"); - toml_free(conf); - exit(1); + return handle_error(); } if (toml_rtos(raw, &host)) { - fprintf(stderr, "ERROR: bad value in 'host'\n"); - toml_free(conf); - exit(1); + return handle_error(); } /* extract port config value */ if (0 == (raw = toml_raw_in(server, "port"))) { - fprintf(stderr, "ERROR: missing 'port' in [server]\n"); - free(host); - toml_free(conf); - exit(1); + return handle_error(); } if (toml_rtoi(raw, &port)) { - fprintf(stderr, "ERROR: bad value in 'port'\n"); - free(host); - toml_free(conf); - exit(1); + return handle_error(); } /* done with conf */ From 896561d5b73097bb4df18cd04635b1c882d738d0 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 10 Oct 2019 01:11:52 -0700 Subject: [PATCH 034/138] update test2 --- test2/build.sh | 2 +- test2/run.sh | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/test2/build.sh b/test2/build.sh index 81af053..74da4d0 100644 --- a/test2/build.sh +++ b/test2/build.sh @@ -2,5 +2,5 @@ set -e DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -d toml-spec-tests ] || git clone https://github.com/iarna/toml-spec-tests.git +[ -d toml-spec-tests ] || git clone https://github.com/cktan/toml-spec-tests.git diff --git a/test2/run.sh b/test2/run.sh index e18f306..95504f8 100644 --- a/test2/run.sh +++ b/test2/run.sh @@ -1,16 +1,22 @@ +if ! (which jq >& /dev/null); then + echo "ERROR: please install the 'jq' utility" + exit 1 +fi + # # POSITIVE tests # for i in toml-spec-tests/values/*.toml; do echo -n $i ' ' - ../toml_json $i >& $i.json.out - rc=$? - [ -f $i.json ] && diff=$(diff $i.json $i.json.out) || diff='' - if [ "$rc" != "0" ] || [ "$diff" != "" ]; then - echo '[FAILED]' - else - echo '[OK]' + res='[OK]' + if (../toml_json $i >& $i.json.out); then + jq . $i.json.out > t.json + mv t.json $i.json.out + if (diff $i.json $i.json.out >& /dev/null); then + res='[FAILED]' + fi fi + echo $res done @@ -19,13 +25,10 @@ done # for i in toml-spec-tests/errors/*.toml; do echo -n $i ' ' - ../toml_json $i >& $i.json.out - rc=$? - - if [ "$rc" != "0" ]; then - echo '[OK]' - else + if (../toml_json $i >& $i.json.out); then echo '[FAILED]' + else + echo '[OK]' fi done From 685ca9747062e2ba928b51ada967e97a343acc30 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 10 Oct 2019 01:23:20 -0700 Subject: [PATCH 035/138] refine run.sh --- test2/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test2/run.sh b/test2/run.sh index 95504f8..d5b9b1d 100644 --- a/test2/run.sh +++ b/test2/run.sh @@ -11,8 +11,8 @@ for i in toml-spec-tests/values/*.toml; do res='[OK]' if (../toml_json $i >& $i.json.out); then jq . $i.json.out > t.json - mv t.json $i.json.out - if (diff $i.json $i.json.out >& /dev/null); then + if (diff $i.json t.json >& /dev/null); then + mv t.json $i.json.failed res='[FAILED]' fi fi From 987f4ef0d7175fbeaf8808802eed47ad972ed0ef Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 10 Oct 2019 01:28:09 -0700 Subject: [PATCH 036/138] refine run.sh --- test2/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test2/run.sh b/test2/run.sh index d5b9b1d..515e8c5 100644 --- a/test2/run.sh +++ b/test2/run.sh @@ -11,8 +11,8 @@ for i in toml-spec-tests/values/*.toml; do res='[OK]' if (../toml_json $i >& $i.json.out); then jq . $i.json.out > t.json - if (diff $i.json t.json >& /dev/null); then - mv t.json $i.json.failed + mv t.json $i.json.out + if [ -f $i.json ] && (diff $i.json $i.json.out >& /dev/null); then res='[FAILED]' fi fi From 2453664abbb99fa5ccf4153aae34da326819bb69 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 10 Oct 2019 04:15:45 -0700 Subject: [PATCH 037/138] updated test2/run.sh --- test2/run.sh | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/test2/run.sh b/test2/run.sh index 515e8c5..c2c84a0 100644 --- a/test2/run.sh +++ b/test2/run.sh @@ -7,13 +7,22 @@ fi # POSITIVE tests # for i in toml-spec-tests/values/*.toml; do - echo -n $i ' ' + fname="$i" + ext="${fname##*.}" + fname="${fname%.*}" + echo -n $fname ' ' res='[OK]' - if (../toml_json $i >& $i.json.out); then - jq . $i.json.out > t.json - mv t.json $i.json.out - if [ -f $i.json ] && (diff $i.json $i.json.out >& /dev/null); then - res='[FAILED]' + if (../toml_json $fname.toml >& $fname.json.out); then + jq . $fname.json.out > t.json + mv t.json $fname.json.out + if [ -f $fname.json ]; then + if ! (diff $fname.json $fname.json.out >& /dev/null); then + res='[FAILED]' + else + rm -f $fname.json.out + fi + else + res='[??]' fi fi echo $res From f782b12864bc23df6c05b779601a363cb6e90c79 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 10 Oct 2019 17:32:54 -0700 Subject: [PATCH 038/138] test output from jq needs to be sorted --- test2/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test2/run.sh b/test2/run.sh index c2c84a0..3e8266c 100644 --- a/test2/run.sh +++ b/test2/run.sh @@ -13,7 +13,7 @@ for i in toml-spec-tests/values/*.toml; do echo -n $fname ' ' res='[OK]' if (../toml_json $fname.toml >& $fname.json.out); then - jq . $fname.json.out > t.json + jq -S . $fname.json.out > t.json mv t.json $fname.json.out if [ -f $fname.json ]; then if ! (diff $fname.json $fname.json.out >& /dev/null); then From f31bcd0adfecf8a0817c0423f3e746f320434182 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 10 Oct 2019 17:34:45 -0700 Subject: [PATCH 039/138] prettier prints --- test2/run.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test2/run.sh b/test2/run.sh index 3e8266c..e1d93df 100644 --- a/test2/run.sh +++ b/test2/run.sh @@ -25,7 +25,7 @@ for i in toml-spec-tests/values/*.toml; do res='[??]' fi fi - echo $res + echo ... $res done @@ -34,10 +34,9 @@ done # for i in toml-spec-tests/errors/*.toml; do echo -n $i ' ' + res='[OK]' if (../toml_json $i >& $i.json.out); then - echo '[FAILED]' - else - echo '[OK]' + res='[FAILED]' fi - + echo ... $res done From b92d6a2c82394bea01ae5e0dad5089a4ab745ad7 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 3 Nov 2019 09:06:01 -0800 Subject: [PATCH 040/138] remove use of dummy errbuf due to benign gcc warnings --- toml.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/toml.c b/toml.c index a9781b5..dcd7053 100644 --- a/toml.c +++ b/toml.c @@ -2089,7 +2089,6 @@ int toml_rtod(const char* src, double* ret_) int toml_rtos(const char* src, char** ret) { - char dummy_errbuf[1]; int multiline = 0; const char* sp; const char* sq; @@ -2126,7 +2125,7 @@ int toml_rtos(const char* src, char** ret) *ret = norm_lit_str(sp, sq - sp, multiline, - dummy_errbuf, sizeof(dummy_errbuf)); + 0, 0); return *ret ? 0 : -1; } @@ -2151,6 +2150,6 @@ int toml_rtos(const char* src, char** ret) *ret = norm_basic_str(sp, sq - sp, multiline, - dummy_errbuf, sizeof(dummy_errbuf)); + 0, 0); return *ret ? 0 : -1; } From 7efd69ca83b0b7dc21422743756fa61e29bed8fa Mon Sep 17 00:00:00 2001 From: Theak Date: Sun, 29 Dec 2019 14:09:02 +0000 Subject: [PATCH 041/138] Fix for #29: STRNDUP memory leak fix --- toml.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/toml.c b/toml.c index dcd7053..53308f4 100644 --- a/toml.c +++ b/toml.c @@ -2119,8 +2119,6 @@ int toml_rtos(const char* src, char** ret) /* last char in src must be ' */ if (! (sp <= sq && *sq == '\'')) return -1; - /* copy from sp to p */ - *ret = STRNDUP(sp, sq - sp); } *ret = norm_lit_str(sp, sq - sp, From 10787cbff973f3438585f4ec72acaf325a4f5c31 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 29 Dec 2019 11:34:12 -0800 Subject: [PATCH 042/138] re-indent --- toml.c | 2642 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 1321 insertions(+), 1321 deletions(-) diff --git a/toml.c b/toml.c index 53308f4..cafc0ff 100644 --- a/toml.c +++ b/toml.c @@ -42,7 +42,7 @@ static void* (*ppcalloc)(size_t, size_t) = calloc; static void* (*pprealloc)(void*, size_t) = realloc; void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*), + void (*xxfree)(void*), void* (*xxcalloc)(size_t, size_t), void* (*xxrealloc)(void*, size_t)) { @@ -53,31 +53,31 @@ void toml_set_memutil(void* (*xxmalloc)(size_t), } -#define MALLOC(a) ppmalloc(a) -#define FREE(a) ppfree(a) -#define CALLOC(a,b) ppcalloc(a,b) +#define MALLOC(a) ppmalloc(a) +#define FREE(a) ppfree(a) +#define CALLOC(a,b) ppcalloc(a,b) #define REALLOC(a,b) pprealloc(a,b) char* STRDUP(const char* s) { int len = strlen(s); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; + char* p = MALLOC(len+1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; } char* STRNDUP(const char* s, size_t n) { - size_t len = strnlen(s, n); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; + size_t len = strnlen(s, n); + char* p = MALLOC(len+1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; } @@ -88,213 +88,213 @@ char* STRNDUP(const char* s, size_t n) */ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) { - const unsigned char* buf = (const unsigned char*) orig; - unsigned i = *buf++; - int64_t v; - - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (0 == (i >> 7)) { - if (len < 1) return -1; - v = i; - return *ret = v, 1; - } - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (0x6 == (i >> 5)) { - if (len < 2) return -1; - v = i & 0x1f; - for (int j = 0; j < 1; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + const unsigned char* buf = (const unsigned char*) orig; + unsigned i = *buf++; + int64_t v; + + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (0 == (i >> 7)) { + if (len < 1) return -1; + v = i; + return *ret = v, 1; + } + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (0x6 == (i >> 5)) { + if (len < 2) return -1; + v = i & 0x1f; + for (int j = 0; j < 1; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (0xE == (i >> 4)) { - if (len < 3) return -1; - v = i & 0x0F; - for (int j = 0; j < 2; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (0xE == (i >> 4)) { + if (len < 3) return -1; + v = i & 0x0F; + for (int j = 0; j < 2; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x1E == (i >> 3)) { - if (len < 4) return -1; - v = i & 0x07; - for (int j = 0; j < 3; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x3E == (i >> 2)) { - if (len < 5) return -1; - v = i & 0x03; - for (int j = 0; j < 4; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x1E == (i >> 3)) { + if (len < 4) return -1; + v = i & 0x07; + for (int j = 0; j < 3; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x3E == (i >> 2)) { + if (len < 5) return -1; + v = i & 0x03; + for (int j = 0; j < 4; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x7e == (i >> 1)) { - if (len < 6) return -1; - v = i & 0x01; - for (int j = 0; j < 5; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - return -1; + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x7e == (i >> 1)) { + if (len < 6) return -1; + v = i & 0x01; + for (int j = 0; j < 5; j++) { + i = *buf++; + if (0x2 != (i >> 6)) return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char*) buf - orig; + } + return -1; } /** - * Convert a UCS char to utf8 code, and return it in buf. - * Return #bytes used in buf to encode the char, or - * -1 on error. + * Convert a UCS char to utf8 code, and return it in buf. + * Return #bytes used in buf to encode the char, or + * -1 on error. */ int toml_ucs_to_utf8(int64_t code, char buf[6]) { - /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 */ - /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well - * as 0xfffe and 0xffff (UCS noncharacters) should not appear in - * conforming UTF-8 streams. - */ - if (0xd800 <= code && code <= 0xdfff) return -1; - if (0xfffe <= code && code <= 0xffff) return -1; + /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 */ + /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well + * as 0xfffe and 0xffff (UCS noncharacters) should not appear in + * conforming UTF-8 streams. + */ + if (0xd800 <= code && code <= 0xdfff) return -1; + if (0xfffe <= code && code <= 0xffff) return -1; - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (code < 0) return -1; - if (code <= 0x7F) { - buf[0] = (unsigned char) code; - return 1; - } + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (code < 0) return -1; + if (code <= 0x7F) { + buf[0] = (unsigned char) code; + return 1; + } - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (code <= 0x000007FF) { - buf[0] = 0xc0 | (code >> 6); - buf[1] = 0x80 | (code & 0x3f); - return 2; - } + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (code <= 0x000007FF) { + buf[0] = 0xc0 | (code >> 6); + buf[1] = 0x80 | (code & 0x3f); + return 2; + } - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x0000FFFF) { - buf[0] = 0xe0 | (code >> 12); - buf[1] = 0x80 | ((code >> 6) & 0x3f); - buf[2] = 0x80 | (code & 0x3f); - return 3; - } + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x0000FFFF) { + buf[0] = 0xe0 | (code >> 12); + buf[1] = 0x80 | ((code >> 6) & 0x3f); + buf[2] = 0x80 | (code & 0x3f); + return 3; + } - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x001FFFFF) { - buf[0] = 0xf0 | (code >> 18); - buf[1] = 0x80 | ((code >> 12) & 0x3f); - buf[2] = 0x80 | ((code >> 6) & 0x3f); - buf[3] = 0x80 | (code & 0x3f); - return 4; - } + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x001FFFFF) { + buf[0] = 0xf0 | (code >> 18); + buf[1] = 0x80 | ((code >> 12) & 0x3f); + buf[2] = 0x80 | ((code >> 6) & 0x3f); + buf[3] = 0x80 | (code & 0x3f); + return 4; + } - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x03FFFFFF) { - buf[0] = 0xf8 | (code >> 24); - buf[1] = 0x80 | ((code >> 18) & 0x3f); - buf[2] = 0x80 | ((code >> 12) & 0x3f); - buf[3] = 0x80 | ((code >> 6) & 0x3f); - buf[4] = 0x80 | (code & 0x3f); - return 5; - } - - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x7FFFFFFF) { - buf[0] = 0xfc | (code >> 30); - buf[1] = 0x80 | ((code >> 24) & 0x3f); - buf[2] = 0x80 | ((code >> 18) & 0x3f); - buf[3] = 0x80 | ((code >> 12) & 0x3f); - buf[4] = 0x80 | ((code >> 6) & 0x3f); - buf[5] = 0x80 | (code & 0x3f); - return 6; - } + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x03FFFFFF) { + buf[0] = 0xf8 | (code >> 24); + buf[1] = 0x80 | ((code >> 18) & 0x3f); + buf[2] = 0x80 | ((code >> 12) & 0x3f); + buf[3] = 0x80 | ((code >> 6) & 0x3f); + buf[4] = 0x80 | (code & 0x3f); + return 5; + } + + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x7FFFFFFF) { + buf[0] = 0xfc | (code >> 30); + buf[1] = 0x80 | ((code >> 24) & 0x3f); + buf[2] = 0x80 | ((code >> 18) & 0x3f); + buf[3] = 0x80 | ((code >> 12) & 0x3f); + buf[4] = 0x80 | ((code >> 6) & 0x3f); + buf[5] = 0x80 | (code & 0x3f); + return 6; + } - return -1; + return -1; } /* - * TOML has 3 data structures: value, array, table. - * Each of them can have identification key. + * TOML has 3 data structures: value, array, table. + * Each of them can have identification key. */ typedef struct toml_keyval_t toml_keyval_t; struct toml_keyval_t { - const char* key; /* key to this value */ - const char* val; /* the raw value */ + const char* key; /* key to this value */ + const char* val; /* the raw value */ }; struct toml_array_t { - const char* key; /* key to this array */ - int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */ - int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ - - int nelem; /* number of elements */ - union { - char** val; - toml_array_t** arr; - toml_table_t** tab; - } u; + const char* key; /* key to this array */ + int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */ + int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ + + int nelem; /* number of elements */ + union { + char** val; + toml_array_t** arr; + toml_table_t** tab; + } u; }; - + struct toml_table_t { - const char* key; /* key to this table */ - int implicit; /* table was created implicitly */ + const char* key; /* key to this table */ + int implicit; /* table was created implicitly */ - /* key-values in the table */ - int nkval; - toml_keyval_t** kval; + /* key-values in the table */ + int nkval; + toml_keyval_t** kval; - /* arrays in the table */ - int narr; - toml_array_t** arr; + /* arrays in the table */ + int narr; + toml_array_t** arr; - /* tables in the table */ - int ntab; - toml_table_t** tab; + /* tables in the table */ + int ntab; + toml_table_t** tab; }; @@ -302,51 +302,51 @@ static inline void xfree(const void* x) { if (x) FREE((void*)x); } enum tokentype_t { - INVALID, - DOT, - COMMA, - EQUAL, - LBRACE, - RBRACE, - NEWLINE, - LBRACKET, - RBRACKET, - STRING, + INVALID, + DOT, + COMMA, + EQUAL, + LBRACE, + RBRACE, + NEWLINE, + LBRACKET, + RBRACKET, + STRING, }; typedef enum tokentype_t tokentype_t; typedef struct token_t token_t; struct token_t { - tokentype_t tok; - int lineno; - char* ptr; /* points into context->start */ - int len; - int eof; + tokentype_t tok; + int lineno; + char* ptr; /* points into context->start */ + int len; + int eof; }; typedef struct context_t context_t; struct context_t { - char* start; - char* stop; - char* errbuf; - int errbufsz; - jmp_buf jmp; + char* start; + char* stop; + char* errbuf; + int errbufsz; + jmp_buf jmp; - token_t tok; - toml_table_t* root; - toml_table_t* curtab; + token_t tok; + toml_table_t* root; + toml_table_t* curtab; - struct { - int top; - char* key[10]; - token_t tok[10]; - } tpath; + struct { + int top; + char* key[10]; + token_t tok[10]; + } tpath; }; #define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) +#define TOSTRING(x) STRINGIFY(x) #define FLINE __FILE__ ":" TOSTRING(__LINE__) static tokentype_t next_token(context_t* ctx, int dotisspecial); @@ -354,77 +354,77 @@ static tokentype_t next_token(context_t* ctx, int dotisspecial); /* error routines. All these functions longjmp to ctx->jmp */ static int e_outofmemory(context_t* ctx, const char* fline) { - snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); + longjmp(ctx->jmp, 1); + return -1; } static int e_internal_error(context_t* ctx, const char* fline) { - snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); + longjmp(ctx->jmp, 1); + return -1; } static int e_syntax_error(context_t* ctx, int lineno, const char* msg) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); + longjmp(ctx->jmp, 1); + return -1; } static int e_bad_key_error(context_t* ctx, int lineno) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); + longjmp(ctx->jmp, 1); + return -1; } /* -static int e_noimpl(context_t* ctx, const char* feature) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature); - longjmp(ctx->jmp, 1); - return -1; -} + static int e_noimpl(context_t* ctx, const char* feature) + { + snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature); + longjmp(ctx->jmp, 1); + return -1; + } */ static int e_key_exists_error(context_t* ctx, int lineno, const char* key) { - snprintf(ctx->errbuf, ctx->errbufsz, - "line %d: key %s exists", lineno, key); - longjmp(ctx->jmp, 1); - return -1; + snprintf(ctx->errbuf, ctx->errbufsz, + "line %d: key %s exists", lineno, key); + longjmp(ctx->jmp, 1); + return -1; } static char* norm_lit_str(const char* src, int srclen, int multiline, char* errbuf, int errbufsz) { - char* dst = 0; /* will write to dst[] and return it */ - int max = 0; /* max size of dst[] */ - int off = 0; /* cur offset in dst[] */ - const char* sp = src; - const char* sq = src + srclen; - int ch; + char* dst = 0; /* will write to dst[] and return it */ + int max = 0; /* max size of dst[] */ + int off = 0; /* cur offset in dst[] */ + const char* sp = src; + const char* sq = src + srclen; + int ch; - /* scan forward on src */ - for (;;) { - if (off >= max - 10) { /* have some slack for misc stuff */ - char* x = REALLOC(dst, max += 50); - if (!x) { - xfree(dst); - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - dst = x; - } - - /* finished? */ - if (sp >= sq) break; - - ch = *sp++; + /* scan forward on src */ + for (;;) { + if (off >= max - 10) { /* have some slack for misc stuff */ + char* x = REALLOC(dst, max += 50); + if (!x) { + xfree(dst); + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + dst = x; + } + + /* finished? */ + if (sp >= sq) break; + + ch = *sp++; /* control characters other than tab is not allowed */ if ((0 <= ch && ch <= 0x08) || (0x0a <= ch && ch <= 0x1f) @@ -455,30 +455,30 @@ static char* norm_basic_str(const char* src, int srclen, int multiline, char* errbuf, int errbufsz) { - char* dst = 0; /* will write to dst[] and return it */ - int max = 0; /* max size of dst[] */ - int off = 0; /* cur offset in dst[] */ - const char* sp = src; - const char* sq = src + srclen; - int ch; + char* dst = 0; /* will write to dst[] and return it */ + int max = 0; /* max size of dst[] */ + int off = 0; /* cur offset in dst[] */ + const char* sp = src; + const char* sq = src + srclen; + int ch; - /* scan forward on src */ - for (;;) { - if (off >= max - 10) { /* have some slack for misc stuff */ - char* x = REALLOC(dst, max += 50); - if (!x) { - xfree(dst); - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - dst = x; - } - - /* finished? */ - if (sp >= sq) break; - - ch = *sp++; - if (ch != '\\') { + /* scan forward on src */ + for (;;) { + if (off >= max - 10) { /* have some slack for misc stuff */ + char* x = REALLOC(dst, max += 50); + if (!x) { + xfree(dst); + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + dst = x; + } + + /* finished? */ + if (sp >= sq) break; + + ch = *sp++; + if (ch != '\\') { /* these chars must be escaped: U+0000 to U+0008, U+000A to U+001F, U+007F */ if ((0 <= ch && ch <= 0x08) || (0x0a <= ch && ch <= 0x1f) @@ -490,146 +490,146 @@ static char* norm_basic_str(const char* src, int srclen, } } - // a plain copy suffice - dst[off++] = ch; - continue; - } + // a plain copy suffice + dst[off++] = ch; + continue; + } - /* ch was backslash. we expect the escape char. */ - if (sp >= sq) { - snprintf(errbuf, errbufsz, "last backslash is invalid"); - xfree(dst); - return 0; - } + /* ch was backslash. we expect the escape char. */ + if (sp >= sq) { + snprintf(errbuf, errbufsz, "last backslash is invalid"); + xfree(dst); + return 0; + } - /* for multi-line, we want to kill line-ending-backslash ... */ - if (multiline) { + /* for multi-line, we want to kill line-ending-backslash ... */ + if (multiline) { // if there is only whitespace after the backslash ... if (sp[strspn(sp, " \t\r")] == '\n') { - /* skip all the following whitespaces */ - sp += strspn(sp, " \t\r\n"); - continue; - } - } + /* skip all the following whitespaces */ + sp += strspn(sp, " \t\r\n"); + continue; + } + } - /* get the escaped char */ - ch = *sp++; - switch (ch) { - case 'u': case 'U': - { - int64_t ucs = 0; - int nhex = (ch == 'u' ? 4 : 8); - for (int i = 0; i < nhex; i++) { - if (sp >= sq) { - snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); - xfree(dst); - return 0; - } - ch = *sp++; - int v = ('0' <= ch && ch <= '9') - ? ch - '0' - : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); - if (-1 == v) { - snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); - xfree(dst); - return 0; - } - ucs = ucs * 16 + v; - } - int n = toml_ucs_to_utf8(ucs, &dst[off]); - if (-1 == n) { - snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); - xfree(dst); - return 0; - } - off += n; - } - continue; + /* get the escaped char */ + ch = *sp++; + switch (ch) { + case 'u': case 'U': + { + int64_t ucs = 0; + int nhex = (ch == 'u' ? 4 : 8); + for (int i = 0; i < nhex; i++) { + if (sp >= sq) { + snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); + xfree(dst); + return 0; + } + ch = *sp++; + int v = ('0' <= ch && ch <= '9') + ? ch - '0' + : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); + if (-1 == v) { + snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); + xfree(dst); + return 0; + } + ucs = ucs * 16 + v; + } + int n = toml_ucs_to_utf8(ucs, &dst[off]); + if (-1 == n) { + snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); + xfree(dst); + return 0; + } + off += n; + } + continue; - case 'b': ch = '\b'; break; - case 't': ch = '\t'; break; - case 'n': ch = '\n'; break; - case 'f': ch = '\f'; break; - case 'r': ch = '\r'; break; - case '"': ch = '"'; break; - case '\\': ch = '\\'; break; - default: - snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); - xfree(dst); - return 0; - } + case 'b': ch = '\b'; break; + case 't': ch = '\t'; break; + case 'n': ch = '\n'; break; + case 'f': ch = '\f'; break; + case 'r': ch = '\r'; break; + case '"': ch = '"'; break; + case '\\': ch = '\\'; break; + default: + snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); + xfree(dst); + return 0; + } - dst[off++] = ch; - } + dst[off++] = ch; + } - // Cap with NUL and return it. - dst[off++] = 0; - return dst; + // Cap with NUL and return it. + dst[off++] = 0; + return dst; } /* Normalize a key. Convert all special chars to raw unescaped utf-8 chars. */ static char* normalize_key(context_t* ctx, token_t strtok) { - const char* sp = strtok.ptr; - const char* sq = strtok.ptr + strtok.len; - int lineno = strtok.lineno; - char* ret; - int ch = *sp; - char ebuf[80]; + const char* sp = strtok.ptr; + const char* sq = strtok.ptr + strtok.len; + int lineno = strtok.lineno; + char* ret; + int ch = *sp; + char ebuf[80]; - /* handle quoted string */ - if (ch == '\'' || ch == '\"') { - /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ + /* handle quoted string */ + if (ch == '\'' || ch == '\"') { + /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ int multiline = 0; - if (sp[1] == ch && sp[2] == ch) { - sp += 3, sq -= 3; + if (sp[1] == ch && sp[2] == ch) { + sp += 3, sq -= 3; multiline = 1; } - else - sp++, sq--; + else + sp++, sq--; - if (ch == '\'') { - /* for single quote, take it verbatim. */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - } else { - /* for double quote, we need to normalize */ - ret = norm_basic_str(sp, sq - sp, multiline, ebuf, sizeof(ebuf)); - if (!ret) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); - longjmp(ctx->jmp, 1); - } - } + if (ch == '\'') { + /* for single quote, take it verbatim. */ + if (! (ret = STRNDUP(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + } else { + /* for double quote, we need to normalize */ + ret = norm_basic_str(sp, sq - sp, multiline, ebuf, sizeof(ebuf)); + if (!ret) { + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); + longjmp(ctx->jmp, 1); + } + } - /* newlines are not allowed in keys */ - if (strchr(ret, '\n')) { - xfree(ret); - e_bad_key_error(ctx, lineno); - return 0; /* not reached */ - } - return ret; - } - - /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ - const char* xp; - for (xp = sp; xp != sq; xp++) { - int k = *xp; - if (isalnum(k)) continue; - if (k == '_' || k == '-') continue; - e_bad_key_error(ctx, lineno); - return 0; /* not reached */ - } + /* newlines are not allowed in keys */ + if (strchr(ret, '\n')) { + xfree(ret); + e_bad_key_error(ctx, lineno); + return 0; /* not reached */ + } + return ret; + } + + /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ + const char* xp; + for (xp = sp; xp != sq; xp++) { + int k = *xp; + if (isalnum(k)) continue; + if (k == '_' || k == '-') continue; + e_bad_key_error(ctx, lineno); + return 0; /* not reached */ + } - /* dup and return it */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - return ret; + /* dup and return it */ + if (! (ret = STRNDUP(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + return ret; } @@ -638,38 +638,38 @@ static char* normalize_key(context_t* ctx, token_t strtok) * 'v'alue, 'a'rray or 't'able depending on the element. */ 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) + toml_keyval_t** ret_val, + toml_array_t** ret_arr, + toml_table_t** ret_tab) { - int i; - void* dummy; + int i; + void* dummy; - if (!ret_tab) ret_tab = (toml_table_t**) &dummy; - if (!ret_arr) ret_arr = (toml_array_t**) &dummy; - if (!ret_val) ret_val = (toml_keyval_t**) &dummy; + if (!ret_tab) ret_tab = (toml_table_t**) &dummy; + if (!ret_arr) ret_arr = (toml_array_t**) &dummy; + if (!ret_val) ret_val = (toml_keyval_t**) &dummy; - *ret_tab = 0; *ret_arr = 0; *ret_val = 0; - - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) { - *ret_val = tab->kval[i]; - return 'v'; - } - } - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) { - *ret_arr = tab->arr[i]; - return 'a'; - } - } - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) { - *ret_tab = tab->tab[i]; - return 't'; - } - } - return 0; + *ret_tab = 0; *ret_arr = 0; *ret_val = 0; + + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) { + *ret_val = tab->kval[i]; + return 'v'; + } + } + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) { + *ret_arr = tab->arr[i]; + return 'a'; + } + } + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) { + *ret_tab = tab->tab[i]; + return 't'; + } + } + return 0; } @@ -682,39 +682,39 @@ static int key_kind(toml_table_t* tab, const char* key) */ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); - /* if key exists: error out. */ - toml_keyval_t* dest = 0; - if (key_kind(tab, newkey)) { - xfree(newkey); - e_key_exists_error(ctx, keytok.lineno, newkey); - return 0; /* not reached */ - } + /* if key exists: error out. */ + toml_keyval_t* dest = 0; + if (key_kind(tab, newkey)) { + xfree(newkey); + e_key_exists_error(ctx, keytok.lineno, newkey); + return 0; /* not reached */ + } - /* make a new entry */ - int n = tab->nkval; - toml_keyval_t** base; - if (0 == (base = (toml_keyval_t**) REALLOC(tab->kval, (n+1) * sizeof(*base)))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - tab->kval = base; - - if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - dest = tab->kval[tab->nkval++]; + /* make a new entry */ + int n = tab->nkval; + toml_keyval_t** base; + if (0 == (base = (toml_keyval_t**) REALLOC(tab->kval, (n+1) * sizeof(*base)))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + tab->kval = base; + + if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + dest = tab->kval[tab->nkval++]; - /* save the key in the new value struct */ - dest->key = newkey; - return dest; + /* save the key in the new value struct */ + dest->key = newkey; + return dest; } @@ -722,137 +722,137 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, */ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); - /* if key exists: error out */ - toml_table_t* dest = 0; - if (check_key(tab, newkey, 0, 0, &dest)) { - xfree(newkey); /* don't need this anymore */ - - /* special case: if table exists, but was created implicitly ... */ - if (dest && dest->implicit) { - /* we make it explicit now, and simply return it. */ - dest->implicit = 0; - return dest; - } - e_key_exists_error(ctx, keytok.lineno, newkey); - return 0; /* not reached */ - } + /* if key exists: error out */ + toml_table_t* dest = 0; + if (check_key(tab, newkey, 0, 0, &dest)) { + xfree(newkey); /* don't need this anymore */ + + /* special case: if table exists, but was created implicitly ... */ + if (dest && dest->implicit) { + /* we make it explicit now, and simply return it. */ + dest->implicit = 0; + return dest; + } + e_key_exists_error(ctx, keytok.lineno, newkey); + return 0; /* not reached */ + } - /* create a new table entry */ - int n = tab->ntab; - toml_table_t** base; - if (0 == (base = (toml_table_t**) REALLOC(tab->tab, (n+1) * sizeof(*base)))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - tab->tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - dest = tab->tab[tab->ntab++]; - - /* save the key in the new table struct */ - dest->key = newkey; - return dest; + /* create a new table entry */ + int n = tab->ntab; + toml_table_t** base; + if (0 == (base = (toml_table_t**) REALLOC(tab->tab, (n+1) * sizeof(*base)))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + tab->tab = base; + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + dest = tab->tab[tab->ntab++]; + + /* save the key in the new table struct */ + dest->key = newkey; + return dest; } /* Create an array in the table. */ static toml_array_t* create_keyarray_in_table(context_t* ctx, - toml_table_t* tab, - token_t keytok, + toml_table_t* tab, + token_t keytok, char kind) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); - - /* if key exists: error out */ - if (key_kind(tab, newkey)) { - xfree(newkey); /* don't need this anymore */ - e_key_exists_error(ctx, keytok.lineno, newkey); - return 0; /* not reached */ - } + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char* newkey = normalize_key(ctx, keytok); + + /* if key exists: error out */ + if (key_kind(tab, newkey)) { + xfree(newkey); /* don't need this anymore */ + e_key_exists_error(ctx, keytok.lineno, newkey); + return 0; /* not reached */ + } - /* make a new array entry */ - int n = tab->narr; - toml_array_t** base; - if (0 == (base = (toml_array_t**) REALLOC(tab->arr, (n+1) * sizeof(*base)))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - tab->arr = base; - - if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - toml_array_t* dest = tab->arr[tab->narr++]; + /* make a new array entry */ + int n = tab->narr; + toml_array_t** base; + if (0 == (base = (toml_array_t**) REALLOC(tab->arr, (n+1) * sizeof(*base)))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + tab->arr = base; + + if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + toml_array_t* dest = tab->arr[tab->narr++]; - /* save the key in the new array struct */ - dest->key = newkey; + /* save the key in the new array struct */ + dest->key = newkey; dest->kind = kind; - return dest; + return dest; } /* Create an array in an array */ static toml_array_t* create_array_in_array(context_t* ctx, - toml_array_t* parent) + toml_array_t* parent) { - int n = parent->nelem; - toml_array_t** base; - if (0 == (base = (toml_array_t**) REALLOC(parent->u.arr, (n+1) * sizeof(*base)))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - parent->u.arr = base; - - if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } + int n = parent->nelem; + toml_array_t** base; + if (0 == (base = (toml_array_t**) REALLOC(parent->u.arr, (n+1) * sizeof(*base)))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + parent->u.arr = base; + + if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } - return parent->u.arr[parent->nelem++]; + return parent->u.arr[parent->nelem++]; } /* Create a table in an array */ static toml_table_t* create_table_in_array(context_t* ctx, - toml_array_t* parent) + toml_array_t* parent) { - int n = parent->nelem; - toml_table_t** base; - if (0 == (base = (toml_table_t**) REALLOC(parent->u.tab, (n+1) * sizeof(*base)))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } - parent->u.tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return 0; /* not reached */ - } + int n = parent->nelem; + toml_table_t** base; + if (0 == (base = (toml_table_t**) REALLOC(parent->u.tab, (n+1) * sizeof(*base)))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } + parent->u.tab = base; + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return 0; /* not reached */ + } - return parent->u.tab[parent->nelem++]; + return parent->u.tab[parent->nelem++]; } #define SKIP_NEWLINES(ctx, isdotspecial) while (ctx->tok.tok == NEWLINE) next_token(ctx, isdotspecial) -#define EAT_TOKEN(ctx, typ, isdotspecial) \ - if ((ctx)->tok.tok != typ) e_internal_error(ctx, FLINE); else next_token(ctx, isdotspecial) +#define EAT_TOKEN(ctx, typ, isdotspecial) \ + if ((ctx)->tok.tok != typ) e_internal_error(ctx, FLINE); else next_token(ctx, isdotspecial) static void parse_keyval(context_t* ctx, toml_table_t* tab); @@ -863,172 +863,172 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab); */ static void parse_table(context_t* ctx, toml_table_t* tab) { - EAT_TOKEN(ctx, LBRACE, 1); + EAT_TOKEN(ctx, LBRACE, 1); - for (;;) { + for (;;) { if (ctx->tok.tok == NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); return; /* not reached */ } - /* until } */ - if (ctx->tok.tok == RBRACE) break; + /* until } */ + if (ctx->tok.tok == RBRACE) break; - if (ctx->tok.tok != STRING) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } - parse_keyval(ctx, tab); + if (ctx->tok.tok != STRING) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } + parse_keyval(ctx, tab); if (ctx->tok.tok == NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); return; /* not reached */ } - /* on comma, continue to scan for next keyval */ - if (ctx->tok.tok == COMMA) { + /* on comma, continue to scan for next keyval */ + if (ctx->tok.tok == COMMA) { EAT_TOKEN(ctx, COMMA, 1); - continue; - } - break; - } + continue; + } + break; + } - if (ctx->tok.tok != RBRACE) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + if (ctx->tok.tok != RBRACE) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } - EAT_TOKEN(ctx, RBRACE, 1); + EAT_TOKEN(ctx, RBRACE, 1); } static int valtype(const char* val) { - toml_timestamp_t ts; - if (*val == '\'' || *val == '"') return 's'; - if (0 == toml_rtob(val, 0)) return 'b'; - if (0 == toml_rtoi(val, 0)) return 'i'; - if (0 == toml_rtod(val, 0)) return 'd'; - if (0 == toml_rtots(val, &ts)) { - if (ts.year && ts.hour) return 'T'; /* timestamp */ - if (ts.year) return 'D'; /* date */ - return 't'; /* time */ - } - return 'u'; /* unknown */ + toml_timestamp_t ts; + if (*val == '\'' || *val == '"') return 's'; + if (0 == toml_rtob(val, 0)) return 'b'; + if (0 == toml_rtoi(val, 0)) return 'i'; + if (0 == toml_rtod(val, 0)) return 'd'; + if (0 == toml_rtots(val, &ts)) { + if (ts.year && ts.hour) return 'T'; /* timestamp */ + if (ts.year) return 'D'; /* date */ + return 't'; /* time */ + } + return 'u'; /* unknown */ } /* We are at '[...]' */ static void parse_array(context_t* ctx, toml_array_t* arr) { - EAT_TOKEN(ctx, LBRACKET, 0); + EAT_TOKEN(ctx, LBRACKET, 0); - for (;;) { - SKIP_NEWLINES(ctx, 0); - - /* until ] */ - if (ctx->tok.tok == RBRACKET) break; + for (;;) { + SKIP_NEWLINES(ctx, 0); + + /* until ] */ + if (ctx->tok.tok == RBRACKET) break; - switch (ctx->tok.tok) { - case STRING: - { - char* val = ctx->tok.ptr; - int vlen = ctx->tok.len; + switch (ctx->tok.tok) { + case STRING: + { + char* val = ctx->tok.ptr; + int vlen = ctx->tok.len; - /* set array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'v'; - /* check array kind */ - if (arr->kind != 'v') { - e_syntax_error(ctx, ctx->tok.lineno, - "a string array can only contain strings"); - return; /* not reached */ - } + /* set array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'v'; + /* check array kind */ + if (arr->kind != 'v') { + e_syntax_error(ctx, ctx->tok.lineno, + "a string array can only contain strings"); + return; /* not reached */ + } - /* make a new value in array */ - char** tmp = (char**) REALLOC(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); - if (!tmp) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - arr->u.val = tmp; - if (! (val = STRNDUP(val, vlen))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - arr->u.val[arr->nelem++] = val; + /* make a new value in array */ + char** tmp = (char**) REALLOC(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); + if (!tmp) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + arr->u.val = tmp; + if (! (val = STRNDUP(val, vlen))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + arr->u.val[arr->nelem++] = val; - /* set array type if this is the first entry, or check that the types matched. */ - if (arr->nelem == 1) - arr->type = valtype(arr->u.val[0]); - else if (arr->type != valtype(val)) { - e_syntax_error(ctx, ctx->tok.lineno, + /* set array type if this is the first entry, or check that the types matched. */ + if (arr->nelem == 1) + arr->type = valtype(arr->u.val[0]); + else if (arr->type != valtype(val)) { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch while processing array of values"); - return; /* not reached */ - } + return; /* not reached */ + } - EAT_TOKEN(ctx, STRING, 0); - break; - } + EAT_TOKEN(ctx, STRING, 0); + break; + } - case LBRACKET: - { /* [ [array], [array] ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'a'; - /* check array kind */ - if (arr->kind != 'a') { - e_syntax_error(ctx, ctx->tok.lineno, + case LBRACKET: + { /* [ [array], [array] ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 'a'; + /* check array kind */ + if (arr->kind != 'a') { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch while processing array of arrays"); - return; /* not reached */ - } - parse_array(ctx, create_array_in_array(ctx, arr)); - break; - } + return; /* not reached */ + } + parse_array(ctx, create_array_in_array(ctx, arr)); + break; + } - case LBRACE: - { /* [ {table}, {table} ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 't'; - /* check array kind */ - if (arr->kind != 't') { - e_syntax_error(ctx, ctx->tok.lineno, + case LBRACE: + { /* [ {table}, {table} ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) arr->kind = 't'; + /* check array kind */ + if (arr->kind != 't') { + e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch while processing array of tables"); - return; /* not reached */ - } - parse_table(ctx, create_table_in_array(ctx, arr)); - break; - } - - default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + return; /* not reached */ + } + parse_table(ctx, create_table_in_array(ctx, arr)); + break; + } + + default: + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } - SKIP_NEWLINES(ctx, 0); + SKIP_NEWLINES(ctx, 0); - /* on comma, continue to scan for next element */ - if (ctx->tok.tok == COMMA) { - EAT_TOKEN(ctx, COMMA, 0); - continue; - } - break; - } + /* on comma, continue to scan for next element */ + if (ctx->tok.tok == COMMA) { + EAT_TOKEN(ctx, COMMA, 0); + continue; + } + break; + } - if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + if (ctx->tok.tok != RBRACKET) { + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } - EAT_TOKEN(ctx, RBRACKET, 1); + EAT_TOKEN(ctx, RBRACKET, 1); } /* handle lines like these: - key = "value" - key = [ array ] - key = { table } + key = "value" + key = [ array ] + key = { table } */ static void parse_keyval(context_t* ctx, toml_table_t* tab) { - token_t key = ctx->tok; + token_t key = ctx->tok; EAT_TOKEN(ctx, STRING, 1); if (ctx->tok.tok == DOT) { @@ -1036,7 +1036,7 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab) e.g. physical.color = "orange" physical.shape = "round" - */ + */ toml_table_t* subtab = 0; { char* subtabstr = normalize_key(ctx, key); @@ -1051,55 +1051,55 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab) return; } - if (ctx->tok.tok != EQUAL) { - e_syntax_error(ctx, ctx->tok.lineno, "missing ="); - return; /* not reached */ - } + if (ctx->tok.tok != EQUAL) { + e_syntax_error(ctx, ctx->tok.lineno, "missing ="); + return; /* not reached */ + } next_token(ctx, 0); - switch (ctx->tok.tok) { - case STRING: - { /* key = "value" */ - toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); - token_t val = ctx->tok; - assert(keyval->val == 0); - keyval->val = STRNDUP(val.ptr, val.len); - if (! keyval->val) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + switch (ctx->tok.tok) { + case STRING: + { /* key = "value" */ + toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); + token_t val = ctx->tok; + assert(keyval->val == 0); + keyval->val = STRNDUP(val.ptr, val.len); + if (! keyval->val) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } next_token(ctx, 1); - - return; - } + + return; + } - case LBRACKET: - { /* key = [ array ] */ - toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); - parse_array(ctx, arr); - return; - } + case LBRACKET: + { /* key = [ array ] */ + toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); + parse_array(ctx, arr); + return; + } - case LBRACE: - { /* key = { table } */ - toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); - parse_table(ctx, nxttab); - return; - } + case LBRACE: + { /* key = { table } */ + toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); + parse_table(ctx, nxttab); + return; + } - default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } + default: + e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + return; /* not reached */ + } } typedef struct tabpath_t tabpath_t; struct tabpath_t { - int cnt; - token_t key[10]; + int cnt; + token_t key[10]; }; /* at [x.y.z] or [[x.y.z]] @@ -1108,48 +1108,48 @@ struct tabpath_t { */ static void fill_tabpath(context_t* ctx) { - int lineno = ctx->tok.lineno; - int i; - - /* clear tpath */ - for (i = 0; i < ctx->tpath.top; i++) { - char** p = &ctx->tpath.key[i]; - xfree(*p); - *p = 0; - } - ctx->tpath.top = 0; - - for (;;) { - if (ctx->tpath.top >= 10) { - e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); - return; /* not reached */ - } + int lineno = ctx->tok.lineno; + int i; + + /* clear tpath */ + for (i = 0; i < ctx->tpath.top; i++) { + char** p = &ctx->tpath.key[i]; + xfree(*p); + *p = 0; + } + ctx->tpath.top = 0; + + for (;;) { + if (ctx->tpath.top >= 10) { + e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); + return; /* not reached */ + } - if (ctx->tok.tok != STRING) { - e_syntax_error(ctx, lineno, "invalid or missing key"); - return; /* not reached */ - } + if (ctx->tok.tok != STRING) { + e_syntax_error(ctx, lineno, "invalid or missing key"); + return; /* not reached */ + } - ctx->tpath.tok[ctx->tpath.top] = ctx->tok; - ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); - ctx->tpath.top++; - - next_token(ctx, 1); + ctx->tpath.tok[ctx->tpath.top] = ctx->tok; + ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); + ctx->tpath.top++; + + next_token(ctx, 1); - if (ctx->tok.tok == RBRACKET) break; + if (ctx->tok.tok == RBRACKET) break; - if (ctx->tok.tok != DOT) { - e_syntax_error(ctx, lineno, "invalid key"); - return; /* not reached */ - } + if (ctx->tok.tok != DOT) { + e_syntax_error(ctx, lineno, "invalid key"); + return; /* not reached */ + } - next_token(ctx, 1); - } + next_token(ctx, 1); + } - if (ctx->tpath.top <= 0) { - e_syntax_error(ctx, lineno, "empty table selector"); - return; /* not reached */ - } + if (ctx->tpath.top <= 0) { + e_syntax_error(ctx, lineno, "empty table selector"); + return; /* not reached */ + } } @@ -1158,78 +1158,78 @@ static void fill_tabpath(context_t* ctx) */ static void walk_tabpath(context_t* ctx) { - /* start from root */ - toml_table_t* curtab = ctx->root; - - for (int i = 0; i < ctx->tpath.top; i++) { - const char* key = ctx->tpath.key[i]; + /* start from root */ + toml_table_t* curtab = ctx->root; + + for (int i = 0; i < ctx->tpath.top; i++) { + const char* key = ctx->tpath.key[i]; - toml_keyval_t* nextval = 0; - toml_array_t* nextarr = 0; - toml_table_t* nexttab = 0; - switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { - case 't': - /* found a table. nexttab is where we will go next. */ - break; + toml_keyval_t* nextval = 0; + toml_array_t* nextarr = 0; + toml_table_t* nexttab = 0; + switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { + case 't': + /* found a table. nexttab is where we will go next. */ + break; - case 'a': - /* found an array. nexttab is the last table in the array. */ - if (nextarr->kind != 't') { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } - if (nextarr->nelem == 0) { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } - nexttab = nextarr->u.tab[nextarr->nelem-1]; - break; + case 'a': + /* found an array. nexttab is the last table in the array. */ + if (nextarr->kind != 't') { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } + if (nextarr->nelem == 0) { + e_internal_error(ctx, FLINE); + return; /* not reached */ + } + nexttab = nextarr->u.tab[nextarr->nelem-1]; + break; - case 'v': - e_key_exists_error(ctx, ctx->tpath.tok[i].lineno, key); - return; /* not reached */ + case 'v': + e_key_exists_error(ctx, ctx->tpath.tok[i].lineno, key); + return; /* not reached */ - default: - { /* Not found. Let's create an implicit table. */ - int n = curtab->ntab; - toml_table_t** base = (toml_table_t**) REALLOC(curtab->tab, (n+1) * sizeof(*base)); - if (0 == base) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - curtab->tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - if (0 == (base[n]->key = STRDUP(key))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - nexttab = curtab->tab[curtab->ntab++]; - - /* tabs created by walk_tabpath are considered implicit */ - nexttab->implicit = 1; - } - break; - } + default: + { /* Not found. Let's create an implicit table. */ + int n = curtab->ntab; + toml_table_t** base = (toml_table_t**) REALLOC(curtab->tab, (n+1) * sizeof(*base)); + if (0 == base) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + curtab->tab = base; + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + if (0 == (base[n]->key = STRDUP(key))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + nexttab = curtab->tab[curtab->ntab++]; + + /* tabs created by walk_tabpath are considered implicit */ + nexttab->implicit = 1; + } + break; + } - /* switch to next tab */ - curtab = nexttab; - } + /* switch to next tab */ + curtab = nexttab; + } - /* save it */ - ctx->curtab = curtab; + /* save it */ + ctx->curtab = curtab; } - + /* handle lines like [x.y.z] or [[x.y.z]] */ static void parse_select(context_t* ctx) { - assert(ctx->tok.tok == LBRACKET); + assert(ctx->tok.tok == LBRACKET); /* true if [[ */ int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '['); @@ -1237,28 +1237,28 @@ static void parse_select(context_t* ctx) and '[ [' would be taken as '[[', which is wrong. */ /* eat [ or [[ */ - EAT_TOKEN(ctx, LBRACKET, 1); + EAT_TOKEN(ctx, LBRACKET, 1); if (llb) { assert(ctx->tok.tok == LBRACKET); EAT_TOKEN(ctx, LBRACKET, 1); - } + } - fill_tabpath(ctx); + fill_tabpath(ctx); - /* For [x.y.z] or [[x.y.z]], remove z from tpath. - */ - token_t z = ctx->tpath.tok[ctx->tpath.top-1]; - xfree(ctx->tpath.key[ctx->tpath.top-1]); - ctx->tpath.top--; + /* For [x.y.z] or [[x.y.z]], remove z from tpath. + */ + token_t z = ctx->tpath.tok[ctx->tpath.top-1]; + xfree(ctx->tpath.key[ctx->tpath.top-1]); + ctx->tpath.top--; /* set up ctx->curtab */ - walk_tabpath(ctx); + walk_tabpath(ctx); - if (! llb) { - /* [x.y.z] -> create z = {} in x.y */ - ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); - } else { - /* [[x.y.z]] -> create z = [] in x.y */ + if (! llb) { + /* [x.y.z] -> create z = {} in x.y */ + ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); + } else { + /* [[x.y.z]] -> create z = [] in x.y */ toml_array_t* arr = 0; { char* zstr = normalize_key(ctx, z); @@ -1271,265 +1271,265 @@ static void parse_select(context_t* ctx) e_internal_error(ctx, FLINE); return; } - } - if (arr->kind != 't') { - e_syntax_error(ctx, z.lineno, "array mismatch"); - return; /* not reached */ - } + } + if (arr->kind != 't') { + e_syntax_error(ctx, z.lineno, "array mismatch"); + return; /* not reached */ + } - /* add to z[] */ - toml_table_t* dest; - { - int n = arr->nelem; - toml_table_t** base = REALLOC(arr->u.tab, (n+1) * sizeof(*base)); - if (0 == base) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - arr->u.tab = base; - - if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - if (0 == (base[n]->key = STRDUP("__anon__"))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } - - dest = arr->u.tab[arr->nelem++]; - } + /* add to z[] */ + toml_table_t* dest; + { + int n = arr->nelem; + toml_table_t** base = REALLOC(arr->u.tab, (n+1) * sizeof(*base)); + if (0 == base) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + arr->u.tab = base; + + if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + if (0 == (base[n]->key = STRDUP("__anon__"))) { + e_outofmemory(ctx, FLINE); + return; /* not reached */ + } + + dest = arr->u.tab[arr->nelem++]; + } - ctx->curtab = dest; - } + ctx->curtab = dest; + } - if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "expects ]"); - return; /* not reached */ - } + if (ctx->tok.tok != RBRACKET) { + e_syntax_error(ctx, ctx->tok.lineno, "expects ]"); + return; /* not reached */ + } if (llb) { if (! (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) { - e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); + e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); return; /* not reached */ } EAT_TOKEN(ctx, RBRACKET, 1); } EAT_TOKEN(ctx, RBRACKET, 1); - if (ctx->tok.tok != NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); - return; /* not reached */ - } + if (ctx->tok.tok != NEWLINE) { + e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); + return; /* not reached */ + } } toml_table_t* toml_parse(char* conf, - char* errbuf, - int errbufsz) + char* errbuf, + int errbufsz) { - context_t ctx; + context_t ctx; - // clear errbuf - if (errbufsz <= 0) errbufsz = 0; - if (errbufsz > 0) errbuf[0] = 0; + // clear errbuf + if (errbufsz <= 0) errbufsz = 0; + if (errbufsz > 0) errbuf[0] = 0; - // init context - memset(&ctx, 0, sizeof(ctx)); - ctx.start = conf; - ctx.stop = ctx.start + strlen(conf); - ctx.errbuf = errbuf; - ctx.errbufsz = errbufsz; + // init context + memset(&ctx, 0, sizeof(ctx)); + ctx.start = conf; + ctx.stop = ctx.start + strlen(conf); + ctx.errbuf = errbuf; + ctx.errbufsz = errbufsz; - // start with an artificial newline of length 0 - ctx.tok.tok = NEWLINE; - ctx.tok.lineno = 1; - ctx.tok.ptr = conf; - ctx.tok.len = 0; + // start with an artificial newline of length 0 + ctx.tok.tok = NEWLINE; + ctx.tok.lineno = 1; + ctx.tok.ptr = conf; + ctx.tok.len = 0; - // make a root table - if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { - /* do not call outofmemory() here... setjmp not done yet */ - snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE); - return 0; - } + // make a root table + if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { + /* do not call outofmemory() here... setjmp not done yet */ + snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE); + return 0; + } - // set root as default table - ctx.curtab = ctx.root; + // set root as default table + ctx.curtab = ctx.root; - if (0 != setjmp(ctx.jmp)) { - // Got here from a long_jmp. Something bad has happened. - // Free resources and return error. - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - toml_free(ctx.root); - return 0; - } + if (0 != setjmp(ctx.jmp)) { + // Got here from a long_jmp. Something bad has happened. + // Free resources and return error. + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + toml_free(ctx.root); + return 0; + } - /* Scan forward until EOF */ - for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { - switch (tok.tok) { - - case NEWLINE: - next_token(&ctx, 1); - break; - - case STRING: - parse_keyval(&ctx, ctx.curtab); - if (ctx.tok.tok != NEWLINE) { - e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); - return 0; /* not reached */ - } + /* Scan forward until EOF */ + for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { + switch (tok.tok) { + + case NEWLINE: + next_token(&ctx, 1); + break; + + case STRING: + parse_keyval(&ctx, ctx.curtab); + if (ctx.tok.tok != NEWLINE) { + e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); + return 0; /* not reached */ + } - EAT_TOKEN(&ctx, NEWLINE, 1); - break; - - case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ - parse_select(&ctx); - break; - - default: - snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); - longjmp(ctx.jmp, 1); - } - } + EAT_TOKEN(&ctx, NEWLINE, 1); + break; + + case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ + parse_select(&ctx); + break; + + default: + snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); + longjmp(ctx.jmp, 1); + } + } - /* success */ - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - return ctx.root; + /* success */ + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + return ctx.root; } toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz) + char* errbuf, + int errbufsz) { - int bufsz = 0; - char* buf = 0; - int off = 0; + int bufsz = 0; + char* buf = 0; + int off = 0; - /* prime the buf[] */ - bufsz = 1000; - if (! (buf = MALLOC(bufsz + 1))) { - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } + /* prime the buf[] */ + bufsz = 1000; + if (! (buf = MALLOC(bufsz + 1))) { + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } - /* read from fp into buf */ - while (! feof(fp)) { - bufsz += 1000; - - /* Allocate 1 extra byte because we will tag on a NUL */ - char* x = REALLOC(buf, bufsz + 1); - if (!x) { - snprintf(errbuf, errbufsz, "out of memory"); - xfree(buf); - return 0; - } - buf = x; + /* read from fp into buf */ + while (! feof(fp)) { + bufsz += 1000; + + /* Allocate 1 extra byte because we will tag on a NUL */ + char* x = REALLOC(buf, bufsz + 1); + if (!x) { + snprintf(errbuf, errbufsz, "out of memory"); + xfree(buf); + return 0; + } + buf = x; - errno = 0; - int n = fread(buf + off, 1, bufsz - off, fp); - if (ferror(fp)) { - snprintf(errbuf, errbufsz, "%s", - errno ? strerror(errno) : "Error reading file"); - xfree(buf); - return 0; - } - off += n; - } + errno = 0; + int n = fread(buf + off, 1, bufsz - off, fp); + if (ferror(fp)) { + snprintf(errbuf, errbufsz, "%s", + errno ? strerror(errno) : "Error reading file"); + xfree(buf); + return 0; + } + off += n; + } - /* tag on a NUL to cap the string */ - buf[off] = 0; /* we accounted for this byte in the REALLOC() above. */ + /* tag on a NUL to cap the string */ + buf[off] = 0; /* we accounted for this byte in the REALLOC() above. */ - /* parse it, cleanup and finish */ - toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); - xfree(buf); - return ret; + /* parse it, cleanup and finish */ + toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); + xfree(buf); + return ret; } static void xfree_kval(toml_keyval_t* p) { - if (!p) return; - xfree(p->key); - xfree(p->val); - xfree(p); + if (!p) return; + xfree(p->key); + xfree(p->val); + xfree(p); } static void xfree_tab(toml_table_t* p); static void xfree_arr(toml_array_t* p) { - if (!p) return; + if (!p) return; - xfree(p->key); - switch (p->kind) { - case 'v': - for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); - xfree(p->u.val); - break; + xfree(p->key); + switch (p->kind) { + case 'v': + for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); + xfree(p->u.val); + break; - case 'a': - for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); - xfree(p->u.arr); - break; + case 'a': + for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); + xfree(p->u.arr); + break; - case 't': - for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); - xfree(p->u.tab); - break; - } + case 't': + for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); + xfree(p->u.tab); + break; + } - xfree(p); + xfree(p); } static void xfree_tab(toml_table_t* p) { - int i; - - if (!p) return; - - xfree(p->key); - - for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); - xfree(p->kval); + int i; + + if (!p) return; + + xfree(p->key); + + for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); + xfree(p->kval); - for (i = 0; i < p->narr; i++) xfree_arr(p->arr[i]); - xfree(p->arr); + for (i = 0; i < p->narr; i++) xfree_arr(p->arr[i]); + xfree(p->arr); - for (i = 0; i < p->ntab; i++) xfree_tab(p->tab[i]); - xfree(p->tab); + for (i = 0; i < p->ntab; i++) xfree_tab(p->tab[i]); + xfree(p->tab); - xfree(p); + xfree(p); } void toml_free(toml_table_t* tab) { - xfree_tab(tab); + xfree_tab(tab); } static tokentype_t ret_token(context_t* ctx, tokentype_t tok, int lineno, char* ptr, int len) { - token_t t; - t.tok = tok; - t.lineno = lineno; - t.ptr = ptr; - t.len = len; - t.eof = 0; - ctx->tok = t; - return tok; + token_t t; + t.tok = tok; + t.lineno = lineno; + t.ptr = ptr; + t.len = len; + t.eof = 0; + ctx->tok = t; + return tok; } static tokentype_t ret_eof(context_t* ctx, int lineno) { - ret_token(ctx, NEWLINE, lineno, ctx->stop, 0); - ctx->tok.eof = 1; - return ctx->tok.tok; + ret_token(ctx, NEWLINE, lineno, ctx->stop, 0); + ctx->tok.eof = 1; + return ctx->tok.tok; } @@ -1566,91 +1566,91 @@ static int scan_time(const char* p, int* hh, int* mm, int* ss) if (ss) *ss = second; return (hour >= 0 && minute >= 0 && second >= 0) ? 0 : -1; } - + static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) { - char* orig = p; - if (0 == strncmp(p, "'''", 3)) { - p = strstr(p + 3, "'''"); - if (0 == p) { - e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); - return 0; /* not reached */ - } + char* orig = p; + if (0 == strncmp(p, "'''", 3)) { + p = strstr(p + 3, "'''"); + if (0 == p) { + e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); + return 0; /* not reached */ + } - return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); - } + return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); + } - if (0 == strncmp(p, "\"\"\"", 3)) { - int hexreq = 0; /* #hex required */ - int escape = 0; - int qcnt = 0; /* count quote */ - for (p += 3; *p && qcnt < 3; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - if (p[strspn(p, " \t\r")] == '\n') continue; /* allow for line ending backslash */ - e_syntax_error(ctx, lineno, "bad escape char"); - return 0; /* not reached */ - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); - return 0; /* not reached */ - } - if (*p == '\\') { escape = 1; continue; } - qcnt = (*p == '"') ? qcnt + 1 : 0; - } - if (qcnt != 3) { - e_syntax_error(ctx, lineno, "unterminated triple-quote"); - return 0; /* not reached */ - } + if (0 == strncmp(p, "\"\"\"", 3)) { + int hexreq = 0; /* #hex required */ + int escape = 0; + int qcnt = 0; /* count quote */ + for (p += 3; *p && qcnt < 3; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + if (p[strspn(p, " \t\r")] == '\n') continue; /* allow for line ending backslash */ + e_syntax_error(ctx, lineno, "bad escape char"); + return 0; /* not reached */ + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + e_syntax_error(ctx, lineno, "expect hex char"); + return 0; /* not reached */ + } + if (*p == '\\') { escape = 1; continue; } + qcnt = (*p == '"') ? qcnt + 1 : 0; + } + if (qcnt != 3) { + e_syntax_error(ctx, lineno, "unterminated triple-quote"); + return 0; /* not reached */ + } - return ret_token(ctx, STRING, lineno, orig, p - orig); - } + return ret_token(ctx, STRING, lineno, orig, p - orig); + } - if ('\'' == *p) { - for (p++; *p && *p != '\n' && *p != '\''; p++); - if (*p != '\'') { - e_syntax_error(ctx, lineno, "unterminated s-quote"); - return 0; /* not reached */ - } + if ('\'' == *p) { + for (p++; *p && *p != '\n' && *p != '\''; p++); + if (*p != '\'') { + e_syntax_error(ctx, lineno, "unterminated s-quote"); + return 0; /* not reached */ + } - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); - } + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + } - if ('\"' == *p) { - int hexreq = 0; /* #hex required */ - int escape = 0; - for (p++; *p; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - e_syntax_error(ctx, lineno, "bad escape char"); - return 0; /* not reached */ - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); - return 0; /* not reached */ - } - if (*p == '\\') { escape = 1; continue; } - if (*p == '\n') break; - if (*p == '"') break; - } - if (*p != '"') { - e_syntax_error(ctx, lineno, "unterminated quote"); - return 0; /* not reached */ - } + if ('\"' == *p) { + int hexreq = 0; /* #hex required */ + int escape = 0; + for (p++; *p; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) continue; + if (*p == 'u') { hexreq = 4; continue; } + if (*p == 'U') { hexreq = 8; continue; } + e_syntax_error(ctx, lineno, "bad escape char"); + return 0; /* not reached */ + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) continue; + e_syntax_error(ctx, lineno, "expect hex char"); + return 0; /* not reached */ + } + if (*p == '\\') { escape = 1; continue; } + if (*p == '\n') break; + if (*p == '"') break; + } + if (*p != '"') { + e_syntax_error(ctx, lineno, "unterminated quote"); + return 0; /* not reached */ + } - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); - } + return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + } /* check for timestamp without quotes */ if (0 == scan_date(p, 0, 0, 0) || 0 == scan_time(p, 0, 0, 0)) { @@ -1663,191 +1663,191 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe } /* literals */ - for ( ; *p && *p != '\n'; p++) { - int ch = *p; - if (ch == '.' && dotisspecial) break; - if ('A' <= ch && ch <= 'Z') continue; - if ('a' <= ch && ch <= 'z') continue; - if (strchr("0123456789+-_.", ch)) continue; - break; - } + for ( ; *p && *p != '\n'; p++) { + int ch = *p; + if (ch == '.' && dotisspecial) break; + if ('A' <= ch && ch <= 'Z') continue; + if ('a' <= ch && ch <= 'z') continue; + if (strchr("0123456789+-_.", ch)) continue; + break; + } - return ret_token(ctx, STRING, lineno, orig, p - orig); + return ret_token(ctx, STRING, lineno, orig, p - orig); } static tokentype_t next_token(context_t* ctx, int dotisspecial) { - int lineno = ctx->tok.lineno; - char* p = ctx->tok.ptr; - int i; + int lineno = ctx->tok.lineno; + char* p = ctx->tok.ptr; + int i; - /* eat this tok */ - for (i = 0; i < ctx->tok.len; i++) { - if (*p++ == '\n') - lineno++; - } + /* eat this tok */ + for (i = 0; i < ctx->tok.len; i++) { + if (*p++ == '\n') + lineno++; + } - /* make next tok */ - while (p < ctx->stop) { - /* skip comment. stop just before the \n. */ - if (*p == '#') { - for (p++; p < ctx->stop && *p != '\n'; p++); - continue; - } + /* make next tok */ + while (p < ctx->stop) { + /* skip comment. stop just before the \n. */ + if (*p == '#') { + for (p++; p < ctx->stop && *p != '\n'; p++); + continue; + } - if (dotisspecial && *p == '.') - return ret_token(ctx, DOT, lineno, p, 1); - - switch (*p) { - case ',': return ret_token(ctx, COMMA, lineno, p, 1); - case '=': return ret_token(ctx, EQUAL, lineno, p, 1); - case '{': return ret_token(ctx, LBRACE, lineno, p, 1); - case '}': return ret_token(ctx, RBRACE, lineno, p, 1); - case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); - case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); - case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); - case '\r': case ' ': case '\t': - /* ignore white spaces */ - p++; - continue; - } + if (dotisspecial && *p == '.') + return ret_token(ctx, DOT, lineno, p, 1); + + switch (*p) { + case ',': return ret_token(ctx, COMMA, lineno, p, 1); + case '=': return ret_token(ctx, EQUAL, lineno, p, 1); + case '{': return ret_token(ctx, LBRACE, lineno, p, 1); + case '}': return ret_token(ctx, RBRACE, lineno, p, 1); + case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); + case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); + case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); + case '\r': case ' ': case '\t': + /* ignore white spaces */ + p++; + continue; + } - return scan_string(ctx, p, lineno, dotisspecial); - } + return scan_string(ctx, p, lineno, dotisspecial); + } - return ret_eof(ctx, lineno); + return ret_eof(ctx, lineno); } const char* toml_key_in(toml_table_t* tab, int keyidx) { - if (keyidx < tab->nkval) return tab->kval[keyidx]->key; - - keyidx -= tab->nkval; - if (keyidx < tab->narr) return tab->arr[keyidx]->key; - - keyidx -= tab->narr; - if (keyidx < tab->ntab) return tab->tab[keyidx]->key; + if (keyidx < tab->nkval) return tab->kval[keyidx]->key; + + keyidx -= tab->nkval; + if (keyidx < tab->narr) return tab->arr[keyidx]->key; + + keyidx -= tab->narr; + if (keyidx < tab->ntab) return tab->tab[keyidx]->key; - return 0; + return 0; } const char* toml_raw_in(toml_table_t* tab, const char* key) { - int i; - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) - return tab->kval[i]->val; - } - return 0; + int i; + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) + return tab->kval[i]->val; + } + return 0; } toml_array_t* toml_array_in(toml_table_t* tab, const char* key) { - int i; - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) - return tab->arr[i]; - } - return 0; + int i; + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) + return tab->arr[i]; + } + return 0; } toml_table_t* toml_table_in(toml_table_t* tab, const char* key) { - int i; - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) - return tab->tab[i]; - } - return 0; + int i; + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) + return tab->tab[i]; + } + return 0; } const char* toml_raw_at(toml_array_t* arr, int idx) { - if (arr->kind != 'v') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.val[idx]; + if (arr->kind != 'v') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.val[idx]; } char toml_array_kind(toml_array_t* arr) { - return arr->kind; + return arr->kind; } char toml_array_type(toml_array_t* arr) { - if (arr->kind != 'v') - return 0; + if (arr->kind != 'v') + return 0; - if (arr->nelem == 0) - return 0; + if (arr->nelem == 0) + return 0; - return arr->type; + return arr->type; } int toml_array_nelem(toml_array_t* arr) { - return arr->nelem; + return arr->nelem; } const char* toml_array_key(toml_array_t* arr) { - return arr ? arr->key : (const char*) NULL; + return arr ? arr->key : (const char*) NULL; } int toml_table_nkval(toml_table_t* tab) { - return tab->nkval; + return tab->nkval; } int toml_table_narr(toml_table_t* tab) { - return tab->narr; + return tab->narr; } int toml_table_ntab(toml_table_t* tab) { - return tab->ntab; + return tab->ntab; } const char* toml_table_key(toml_table_t* tab) { - return tab ? tab->key : (const char*) NULL; + return tab ? tab->key : (const char*) NULL; } toml_array_t* toml_array_at(toml_array_t* arr, int idx) { - if (arr->kind != 'a') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.arr[idx]; + if (arr->kind != 'a') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.arr[idx]; } toml_table_t* toml_table_at(toml_array_t* arr, int idx) { - if (arr->kind != 't') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.tab[idx]; + if (arr->kind != 't') + return 0; + if (! (0 <= idx && idx < arr->nelem)) + return 0; + return arr->u.tab[idx]; } int toml_rtots(const char* src_, toml_timestamp_t* ret) { - if (! src_) return -1; - - const char* p = src_; + if (! src_) return -1; + + const char* p = src_; int must_parse_time = 0; - - memset(ret, 0, sizeof(*ret)); + + memset(ret, 0, sizeof(*ret)); int* year = &ret->__buffer.year; int* month = &ret->__buffer.month; @@ -1857,7 +1857,7 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) int* second = &ret->__buffer.second; int* millisec = &ret->__buffer.millisec; - /* parse date YYYY-MM-DD */ + /* parse date YYYY-MM-DD */ if (0 == scan_date(p, year, month, day)) { ret->year = year; ret->month = month; @@ -1865,16 +1865,16 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) p += 10; if (*p) { - // parse the T or space separator - if (*p != 'T' && *p != ' ') return -1; + // parse the T or space separator + if (*p != 'T' && *p != ' ') return -1; must_parse_time = 1; - p++; - } - } + p++; + } + } - /* parse time HH:MM:SS */ + /* parse time HH:MM:SS */ if (0 == scan_time(p, hour, minute, second)) { - ret->hour = hour; + ret->hour = hour; ret->minute = minute; ret->second = second; @@ -1929,44 +1929,44 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) if (must_parse_time && !ret->hour) return -1; - return 0; + return 0; } /* Raw to boolean */ int toml_rtob(const char* src, int* ret_) { - if (!src) return -1; - int dummy; - int* ret = ret_ ? ret_ : &dummy; - - if (0 == strcmp(src, "true")) { - *ret = 1; - return 0; - } - if (0 == strcmp(src, "false")) { - *ret = 0; - return 0; - } - return -1; + if (!src) return -1; + int dummy; + int* ret = ret_ ? ret_ : &dummy; + + if (0 == strcmp(src, "true")) { + *ret = 1; + return 0; + } + if (0 == strcmp(src, "false")) { + *ret = 0; + return 0; + } + return -1; } /* Raw to integer */ int toml_rtoi(const char* src, int64_t* ret_) { - if (!src) return -1; - - char buf[100]; - char* p = buf; - char* q = p + sizeof(buf); - const char* s = src; - int base = 0; - int64_t dummy; - int64_t* ret = ret_ ? ret_ : &dummy; - + if (!src) return -1; + + char buf[100]; + char* p = buf; + char* q = p + sizeof(buf); + const char* s = src; + int base = 0; + int64_t dummy; + int64_t* ret = ret_ ? ret_ : &dummy; + - /* allow +/- */ + /* allow +/- */ if (s[0] == '+' || s[0] == '-') *p++ = *s++; @@ -1974,60 +1974,60 @@ int toml_rtoi(const char* src, int64_t* ret_) if (s[0] == '_') return -1; - /* if 0 ... */ - if ('0' == s[0]) { - switch (s[1]) { - case 'x': base = 16; s += 2; break; - case 'o': base = 8; s += 2; break; - case 'b': base = 2; s += 2; break; - case '\0': return *ret = 0, 0; - default: - /* ensure no other digits after it */ - if (s[1]) return -1; - } - } + /* if 0 ... */ + if ('0' == s[0]) { + switch (s[1]) { + case 'x': base = 16; s += 2; break; + case 'o': base = 8; s += 2; break; + case 'b': base = 2; s += 2; break; + case '\0': return *ret = 0, 0; + default: + /* ensure no other digits after it */ + if (s[1]) return -1; + } + } - /* just strip underscores and pass to strtoll */ - while (*s && p < q) { - int ch = *s++; + /* just strip underscores and pass to strtoll */ + while (*s && p < q) { + int ch = *s++; switch (ch) { case '_': // disallow '__' if (s[0] == '_') return -1; - continue; /* skip _ */ + continue; /* skip _ */ default: break; } - *p++ = ch; - } - if (*s || p == q) return -1; + *p++ = ch; + } + if (*s || p == q) return -1; /* last char cannot be '_' */ if (s[-1] == '_') return -1; - - /* cap with NUL */ - *p = 0; + + /* cap with NUL */ + *p = 0; - /* Run strtoll on buf to get the integer */ - char* endp; - errno = 0; - *ret = strtoll(buf, &endp, base); - return (errno || *endp) ? -1 : 0; + /* Run strtoll on buf to get the integer */ + char* endp; + errno = 0; + *ret = strtoll(buf, &endp, base); + return (errno || *endp) ? -1 : 0; } int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) { - if (!src) return -1; - - char* p = buf; - char* q = p + buflen; - const char* s = src; - double dummy; - double* ret = ret_ ? ret_ : &dummy; + if (!src) return -1; + + char* p = buf; + char* q = p + buflen; + const char* s = src; + double dummy; + double* ret = ret_ ? ret_ : &dummy; - /* allow +/- */ + /* allow +/- */ if (s[0] == '+' || s[0] == '-') *p++ = *s++; @@ -2043,9 +2043,9 @@ int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) if (s[0] == '0' && s[1] && !strchr("eE.", s[1])) return -1; - /* just strip underscores and pass to strtod */ - while (*s && p < q) { - int ch = *s++; + /* just strip underscores and pass to strtod */ + while (*s && p < q) { + int ch = *s++; switch (ch) { case '.': if (s[-2] == '_') return -1; @@ -2058,24 +2058,24 @@ int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) default: break; } - *p++ = ch; - } - if (*s || p == q) return -1; /* reached end of string or buffer is full? */ + *p++ = ch; + } + if (*s || p == q) return -1; /* reached end of string or buffer is full? */ /* last char cannot be '_' */ if (s[-1] == '_') return -1; - if (p != buf && p[-1] == '.') - return -1; /* no trailing zero */ + if (p != buf && p[-1] == '.') + return -1; /* no trailing zero */ - /* cap with NUL */ - *p = 0; + /* cap with NUL */ + *p = 0; - /* Run strtod on buf to get the value */ - char* endp; - errno = 0; - *ret = strtod(buf, &endp); - return (errno || *endp) ? -1 : 0; + /* Run strtod on buf to get the value */ + char* endp; + errno = 0; + *ret = strtod(buf, &endp); + return (errno || *endp) ? -1 : 0; } int toml_rtod(const char* src, double* ret_) @@ -2093,61 +2093,61 @@ int toml_rtos(const char* src, char** ret) const char* sp; const char* sq; - if (!src) return -1; - if (*src != '\'' && *src != '"') return -1; + if (!src) return -1; + if (*src != '\'' && *src != '"') return -1; - *ret = 0; - int srclen = strlen(src); - if (*src == '\'') { - if (0 == strncmp(src, "'''", 3)) { + *ret = 0; + int srclen = strlen(src); + if (*src == '\'') { + if (0 == strncmp(src, "'''", 3)) { multiline = 1; - sp = src + 3; + sp = src + 3; sq = src + srclen - 3; - /* last 3 chars in src must be ''' */ - if (! (sp <= sq && 0 == strcmp(sq, "'''"))) - return -1; - - /* skip first new line right after ''' */ - if (*sp == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; + /* last 3 chars in src must be ''' */ + if (! (sp <= sq && 0 == strcmp(sq, "'''"))) + return -1; + + /* skip first new line right after ''' */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; - } else { - sp = src + 1; - sq = src + srclen - 1; - /* last char in src must be ' */ - if (! (sp <= sq && *sq == '\'')) - return -1; - } + } else { + sp = src + 1; + sq = src + srclen - 1; + /* last char in src must be ' */ + if (! (sp <= sq && *sq == '\'')) + return -1; + } *ret = norm_lit_str(sp, sq - sp, multiline, 0, 0); - return *ret ? 0 : -1; - } + return *ret ? 0 : -1; + } - if (0 == strncmp(src, "\"\"\"", 3)) { + if (0 == strncmp(src, "\"\"\"", 3)) { multiline = 1; - sp = src + 3; - sq = src + srclen - 3; - if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) - return -1; - - /* skip first new line right after """ */ - if (*sp == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; - } else { - sp = src + 1; - sq = src + srclen - 1; - if (! (sp <= sq && *sq == '"')) - return -1; - } + sp = src + 3; + sq = src + srclen - 3; + if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) + return -1; + + /* skip first new line right after """ */ + if (*sp == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; + } else { + sp = src + 1; + sq = src + srclen - 1; + if (! (sp <= sq && *sq == '"')) + return -1; + } - *ret = norm_basic_str(sp, sq - sp, + *ret = norm_basic_str(sp, sq - sp, multiline, 0, 0); - return *ret ? 0 : -1; + return *ret ? 0 : -1; } From 416be8de635b67c9a8d3d2392ceb2135f3c49e36 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 29 Dec 2019 11:35:24 -0800 Subject: [PATCH 043/138] re-indent --- toml.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/toml.h b/toml.h index 8acf3ee..34872c9 100644 --- a/toml.h +++ b/toml.h @@ -43,16 +43,16 @@ typedef struct toml_array_t toml_array_t; * Caller must toml_free(the-return-value) after use. */ TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz); + char* errbuf, + int errbufsz); /* Parse a string containing the full config. * Return a table on success, or 0 otherwise. * Caller must toml_free(the-return-value) after use. */ TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */ - char* errbuf, - int errbufsz); + char* errbuf, + int errbufsz); /* Free the table returned by toml_parse() or toml_parse_file(). */ TOML_EXTERN void toml_free(toml_table_t* tab); @@ -121,14 +121,14 @@ TOML_EXTERN int toml_rtod_ex(const char* s, double* ret, char* buf, int buflen); */ typedef struct toml_timestamp_t toml_timestamp_t; struct toml_timestamp_t { - struct { /* internal. do not use. */ - int year, month, day; - int hour, minute, second, millisec; - char z[10]; - } __buffer; - int *year, *month, *day; - int *hour, *minute, *second, *millisec; - char* z; + struct { /* internal. do not use. */ + int year, month, day; + int hour, minute, second, millisec; + char z[10]; + } __buffer; + int *year, *month, *day; + int *hour, *minute, *second, *millisec; + char* z; }; /* Raw to Timestamp. Return 0 on success, -1 otherwise. */ @@ -138,7 +138,7 @@ TOML_EXTERN int toml_rtots(const char* s, toml_timestamp_t* ret); TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*), + void (*xxfree)(void*), void* (*xxcalloc)(size_t, size_t), void* (*xxrealloc)(void*, size_t)); From 4078d23a33eb8e24cbc9a1c3e29dbdbe82fc62cc Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 29 Dec 2019 11:55:17 -0800 Subject: [PATCH 044/138] restructure and clean up toml_rtos --- toml.c | 68 +++++++++++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 41 deletions(-) diff --git a/toml.c b/toml.c index cafc0ff..9dd9558 100644 --- a/toml.c +++ b/toml.c @@ -2093,61 +2093,47 @@ int toml_rtos(const char* src, char** ret) const char* sp; const char* sq; - if (!src) return -1; - if (*src != '\'' && *src != '"') return -1; - *ret = 0; + if (!src) return -1; + + int qchar = src[0]; int srclen = strlen(src); - if (*src == '\'') { - if (0 == strncmp(src, "'''", 3)) { - multiline = 1; - sp = src + 3; - sq = src + srclen - 3; - /* last 3 chars in src must be ''' */ - if (! (sp <= sq && 0 == strcmp(sq, "'''"))) - return -1; - - /* skip first new line right after ''' */ - if (*sp == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; - - } else { - sp = src + 1; - sq = src + srclen - 1; - /* last char in src must be ' */ - if (! (sp <= sq && *sq == '\'')) - return -1; - } - - *ret = norm_lit_str(sp, sq - sp, - multiline, - 0, 0); - return *ret ? 0 : -1; + if (! (qchar == '\'' || qchar == '"')) { + return -1; } - - if (0 == strncmp(src, "\"\"\"", 3)) { + + // triple quotes? + if (qchar == src[1] && qchar == src[2]) { multiline = 1; sp = src + 3; sq = src + srclen - 3; - if (! (sp <= sq && 0 == strcmp(sq, "\"\"\""))) + /* last 3 chars in src must be qchar */ + if (! (sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) return -1; - - /* skip first new line right after """ */ - if (*sp == '\n') + + /* skip new line immediate after qchar */ + if (sp[0] == '\n') sp++; else if (sp[0] == '\r' && sp[1] == '\n') sp += 2; + } else { sp = src + 1; sq = src + srclen - 1; - if (! (sp <= sq && *sq == '"')) + /* last char in src must be qchar */ + if (! (sp <= sq && *sq == qchar)) return -1; } - - *ret = norm_basic_str(sp, sq - sp, - multiline, - 0, 0); + + if (qchar == '\'') { + *ret = norm_lit_str(sp, sq - sp, + multiline, + 0, 0); + } else { + *ret = norm_basic_str(sp, sq - sp, + multiline, + 0, 0); + } + return *ret ? 0 : -1; } From eaa5d045391ee823532c47ff77107b50541a123d Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 18 Jan 2020 10:46:14 -0800 Subject: [PATCH 045/138] fix memory leak --- toml.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/toml.c b/toml.c index 9dd9558..c1d8c38 100644 --- a/toml.c +++ b/toml.c @@ -390,10 +390,10 @@ static int e_bad_key_error(context_t* ctx, int lineno) } */ -static int e_key_exists_error(context_t* ctx, int lineno, const char* key) +static int e_key_exists_error(context_t* ctx, int lineno) { snprintf(ctx->errbuf, ctx->errbufsz, - "line %d: key %s exists", lineno, key); + "line %d: key exists", lineno); longjmp(ctx->jmp, 1); return -1; } @@ -691,7 +691,7 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, toml_keyval_t* dest = 0; if (key_kind(tab, newkey)) { xfree(newkey); - e_key_exists_error(ctx, keytok.lineno, newkey); + e_key_exists_error(ctx, keytok.lineno); return 0; /* not reached */ } @@ -738,7 +738,7 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, dest->implicit = 0; return dest; } - e_key_exists_error(ctx, keytok.lineno, newkey); + e_key_exists_error(ctx, keytok.lineno); return 0; /* not reached */ } @@ -780,7 +780,7 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, /* if key exists: error out */ if (key_kind(tab, newkey)) { xfree(newkey); /* don't need this anymore */ - e_key_exists_error(ctx, keytok.lineno, newkey); + e_key_exists_error(ctx, keytok.lineno); return 0; /* not reached */ } @@ -1186,7 +1186,7 @@ static void walk_tabpath(context_t* ctx) break; case 'v': - e_key_exists_error(ctx, ctx->tpath.tok[i].lineno, key); + e_key_exists_error(ctx, ctx->tpath.tok[i].lineno); return; /* not reached */ default: From cdbb9decfb315e9a51041fc91786f93d9baf6502 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 8 Feb 2020 12:54:09 -0800 Subject: [PATCH 046/138] Fixed issue #33 --- toml.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/toml.c b/toml.c index c1d8c38..a26b032 100644 --- a/toml.c +++ b/toml.c @@ -850,7 +850,15 @@ static toml_table_t* create_table_in_array(context_t* ctx, } -#define SKIP_NEWLINES(ctx, isdotspecial) while (ctx->tok.tok == NEWLINE) next_token(ctx, isdotspecial) +static void skip_newlines(context_t* ctx, int isdotspecial) +{ + while (ctx->tok.tok == NEWLINE) { + next_token(ctx, isdotspecial); + if (ctx->tok.eof) break; + } +} + + #define EAT_TOKEN(ctx, typ, isdotspecial) \ if ((ctx)->tok.tok != typ) e_internal_error(ctx, FLINE); else next_token(ctx, isdotspecial) @@ -923,7 +931,7 @@ static void parse_array(context_t* ctx, toml_array_t* arr) EAT_TOKEN(ctx, LBRACKET, 0); for (;;) { - SKIP_NEWLINES(ctx, 0); + skip_newlines(ctx, 0); /* until ] */ if (ctx->tok.tok == RBRACKET) break; @@ -1002,7 +1010,7 @@ static void parse_array(context_t* ctx, toml_array_t* arr) return; /* not reached */ } - SKIP_NEWLINES(ctx, 0); + skip_newlines(ctx, 0); /* on comma, continue to scan for next element */ if (ctx->tok.tok == COMMA) { @@ -1013,7 +1021,7 @@ static void parse_array(context_t* ctx, toml_array_t* arr) } if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); + e_syntax_error(ctx, ctx->tok.lineno, "expect a right bracket"); return; /* not reached */ } From 5bc8f64fdd77938b06913553e796e2e478b8bfc1 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 13 Jun 2020 16:18:57 -0700 Subject: [PATCH 047/138] Note.txt --- Makefile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 0032dc5..fe6a54c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,12 @@ +HFILES = toml.h CFILES = toml.c +OBJ = $(CFILES:.c=.o) +EXEC = toml_json toml_cat CFLAGS = -std=c99 -Wall -Wextra -fpic +LIB = libtoml.a +LIB_SHARED = libtoml.so + # to compile for debug: make DEBUG=1 # to compile for no debug: make ifdef DEBUG @@ -9,13 +15,10 @@ else CFLAGS += -O2 -DNDEBUG endif -EXEC = toml_json toml_cat - -LIB = libtoml.a -LIB_SHARED = libtoml.so all: $(LIB) $(LIB_SHARED) $(EXEC) +*.o: $(HFILES) libtoml.a: toml.o ar -rcs $@ $^ From c59fa7a0581dbf5aef26369993e1f32b89b300c9 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 13 Jun 2020 16:19:27 -0700 Subject: [PATCH 048/138] Note.txt --- test2/Note.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test2/Note.txt diff --git a/test2/Note.txt b/test2/Note.txt new file mode 100644 index 0000000..bb931de --- /dev/null +++ b/test2/Note.txt @@ -0,0 +1,5 @@ +Note that these tests are expected to fail as we do not validate Unicode strings. + +% bash run.sh | grep FAIL +toml-spec-tests/errors/string-basic-multiline-out-of-range-unicode-escape-2.toml ... [FAILED] +toml-spec-tests/errors/string-basic-out-of-range-unicode-escape-2.toml ... [FAILED] From 8278e68df99c2c6646eac85e0095e984b84bde14 Mon Sep 17 00:00:00 2001 From: Stanley Pinchak Date: Tue, 29 Oct 2019 14:03:44 -0500 Subject: [PATCH 049/138] Add const qualifiers for access functions The access functions do not mutate the toml_table. Add const qualifiers to the parameters which are not mutated. --- toml.c | 30 +++++++++++++++--------------- toml.h | 32 +++++++++++++++++--------------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/toml.c b/toml.c index a26b032..ad7efb4 100644 --- a/toml.c +++ b/toml.c @@ -1728,7 +1728,7 @@ static tokentype_t next_token(context_t* ctx, int dotisspecial) } -const char* toml_key_in(toml_table_t* tab, int keyidx) +const char* toml_key_in(const toml_table_t* tab, int keyidx) { if (keyidx < tab->nkval) return tab->kval[keyidx]->key; @@ -1742,7 +1742,7 @@ const char* toml_key_in(toml_table_t* tab, int keyidx) } -const char* toml_raw_in(toml_table_t* tab, const char* key) +const char* toml_raw_in(const toml_table_t* tab, const char* key) { int i; for (i = 0; i < tab->nkval; i++) { @@ -1752,7 +1752,7 @@ const char* toml_raw_in(toml_table_t* tab, const char* key) return 0; } -toml_array_t* toml_array_in(toml_table_t* tab, const char* key) +toml_array_t* toml_array_in(const toml_table_t* tab, const char* key) { int i; for (i = 0; i < tab->narr; i++) { @@ -1763,7 +1763,7 @@ toml_array_t* toml_array_in(toml_table_t* tab, const char* key) } -toml_table_t* toml_table_in(toml_table_t* tab, const char* key) +toml_table_t* toml_table_in(const toml_table_t* tab, const char* key) { int i; for (i = 0; i < tab->ntab; i++) { @@ -1773,7 +1773,7 @@ toml_table_t* toml_table_in(toml_table_t* tab, const char* key) return 0; } -const char* toml_raw_at(toml_array_t* arr, int idx) +const char* toml_raw_at(const toml_array_t* arr, int idx) { if (arr->kind != 'v') return 0; @@ -1782,12 +1782,12 @@ const char* toml_raw_at(toml_array_t* arr, int idx) return arr->u.val[idx]; } -char toml_array_kind(toml_array_t* arr) +char toml_array_kind(const toml_array_t* arr) { return arr->kind; } -char toml_array_type(toml_array_t* arr) +char toml_array_type(const toml_array_t* arr) { if (arr->kind != 'v') return 0; @@ -1799,37 +1799,37 @@ char toml_array_type(toml_array_t* arr) } -int toml_array_nelem(toml_array_t* arr) +int toml_array_nelem(const toml_array_t* arr) { return arr->nelem; } -const char* toml_array_key(toml_array_t* arr) +const char* toml_array_key(const toml_array_t* arr) { return arr ? arr->key : (const char*) NULL; } -int toml_table_nkval(toml_table_t* tab) +int toml_table_nkval(const toml_table_t* tab) { return tab->nkval; } -int toml_table_narr(toml_table_t* tab) +int toml_table_narr(const toml_table_t* tab) { return tab->narr; } -int toml_table_ntab(toml_table_t* tab) +int toml_table_ntab(const toml_table_t* tab) { return tab->ntab; } -const char* toml_table_key(toml_table_t* tab) +const char* toml_table_key(const toml_table_t* tab) { return tab ? tab->key : (const char*) NULL; } -toml_array_t* toml_array_at(toml_array_t* arr, int idx) +toml_array_t* toml_array_at(const toml_array_t* arr, int idx) { if (arr->kind != 'a') return 0; @@ -1838,7 +1838,7 @@ toml_array_t* toml_array_at(toml_array_t* arr, int idx) return arr->u.arr[idx]; } -toml_table_t* toml_table_at(toml_array_t* arr, int idx) +toml_table_t* toml_table_at(const toml_array_t* arr, int idx) { if (arr->kind != 't') return 0; diff --git a/toml.h b/toml.h index 34872c9..f61135d 100644 --- a/toml.h +++ b/toml.h @@ -58,45 +58,47 @@ TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */ TOML_EXTERN void toml_free(toml_table_t* tab); /* Retrieve the key in table at keyidx. Return 0 if out of range. */ -TOML_EXTERN const char* toml_key_in(toml_table_t* tab, int keyidx); +TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx); /* Lookup table by key. Return the element or 0 if not found. */ -TOML_EXTERN const char* toml_raw_in(toml_table_t* tab, const char* key); -TOML_EXTERN toml_array_t* toml_array_in(toml_table_t* tab, const char* key); -TOML_EXTERN toml_table_t* toml_table_in(toml_table_t* tab, const char* key); +TOML_EXTERN const char* toml_raw_in(const toml_table_t* tab, const char* key); +TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab, + const char* key); +TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab, + const char* key); /* Return the array kind: 't'able, 'a'rray, 'v'alue */ -TOML_EXTERN char toml_array_kind(toml_array_t* arr); +TOML_EXTERN char toml_array_kind(const toml_array_t* arr); /* For array kind 'v'alue, return the type of values i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp 0 if unknown */ -TOML_EXTERN char toml_array_type(toml_array_t* arr); +TOML_EXTERN char toml_array_type(const toml_array_t* arr); /* Return the number of elements in the array */ -TOML_EXTERN int toml_array_nelem(toml_array_t* arr); +TOML_EXTERN int toml_array_nelem(const toml_array_t* arr); /* Return the key of an array */ -TOML_EXTERN const char* toml_array_key(toml_array_t* arr); +TOML_EXTERN const char* toml_array_key(const toml_array_t* arr); /* Return the number of key-values in a table */ -TOML_EXTERN int toml_table_nkval(toml_table_t* tab); +TOML_EXTERN int toml_table_nkval(const toml_table_t* tab); /* Return the number of arrays in a table */ -TOML_EXTERN int toml_table_narr(toml_table_t* tab); +TOML_EXTERN int toml_table_narr(const toml_table_t* tab); /* Return the number of sub-tables in a table */ -TOML_EXTERN int toml_table_ntab(toml_table_t* tab); +TOML_EXTERN int toml_table_ntab(const toml_table_t* tab); /* Return the key of a table*/ -TOML_EXTERN const char* toml_table_key(toml_table_t* tab); +TOML_EXTERN const char* toml_table_key(const toml_table_t* tab); /* Deref array by index. Return the element at idx or 0 if out of range. */ -TOML_EXTERN const char* toml_raw_at(toml_array_t* arr, int idx); -TOML_EXTERN toml_array_t* toml_array_at(toml_array_t* arr, int idx); -TOML_EXTERN toml_table_t* toml_table_at(toml_array_t* arr, int idx); +TOML_EXTERN const char* toml_raw_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx); /* Raw to String. Caller must call free(ret) after use. From f25dee127353355784859194eba006976ddc7be0 Mon Sep 17 00:00:00 2001 From: Stanley Pinchak Date: Wed, 17 Jun 2020 17:43:36 -0500 Subject: [PATCH 050/138] Add editorconfig file --- .editorconfig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e46ee4c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = false +trim_trailing_whitespace = true + +[*.{c,h}] +indent_style = tab +indent_size = 4 + +[Makefile] +indent_style = tab +indent_size = 4 From 7af2dbf91f75ca06d76a72975cacec3fd259dda3 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 8 Jul 2020 02:13:18 -0700 Subject: [PATCH 051/138] use static decl for local STRDUP, STRNDUP funcs --- toml.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toml.c b/toml.c index ad7efb4..556beef 100644 --- a/toml.c +++ b/toml.c @@ -58,7 +58,7 @@ void toml_set_memutil(void* (*xxmalloc)(size_t), #define CALLOC(a,b) ppcalloc(a,b) #define REALLOC(a,b) pprealloc(a,b) -char* STRDUP(const char* s) +static char* STRDUP(const char* s) { int len = strlen(s); char* p = MALLOC(len+1); @@ -69,7 +69,7 @@ char* STRDUP(const char* s) return p; } -char* STRNDUP(const char* s, size_t n) +static char* STRNDUP(const char* s, size_t n) { size_t len = strnlen(s, n); char* p = MALLOC(len+1); From a1d23056ac0334d13014167eb98347e888b29fc9 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 8 Jul 2020 02:26:12 -0700 Subject: [PATCH 052/138] fixed const qual warning as suggested by @mheily --- toml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml.c b/toml.c index 556beef..4fd84a4 100644 --- a/toml.c +++ b/toml.c @@ -298,7 +298,7 @@ struct toml_table_t { }; -static inline void xfree(const void* x) { if (x) FREE((void*)x); } +static inline void xfree(const void* x) { if (x) FREE((void*)(intptr_t)x); } enum tokentype_t { From e1e73699072f5d0cf58ea45b523e56d25b420dde Mon Sep 17 00:00:00 2001 From: dcresswell Date: Sat, 4 Jul 2020 16:35:46 -0700 Subject: [PATCH 053/138] Reformats Readme to provide better instructions This makes the Readme much cleaner so new users have an easier time starting out with this library. --- README.md | 156 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 2ef0526..708cd29 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,125 @@ # tomlc99 + TOML in c99; v0.5.0 compliant. - -# Usage +## Usage Please see the `toml.h` file for details. What follows is a simple example that parses this config file: -``` +```toml [server] -    host = "www.example.com" - port = 80 + host = "www.example.com" + port = 80 ``` -For each config param, the code first extracts a raw value and then -convert it to a string or integer depending on context. +The steps for getting values from our file is usually : +1. Parse the whole TOML file. +2. Get a single table from the file. +3. Find a value from the table. +4. Convert that value to the appropriate type (I.E. string, int). +5. Then, free up that memory if needed. + +Below is an example of parsing the values from the example table. + +1. Parse the whole TOML file. + +```c +FILE* fp; +toml_table_t* conf; +char errbuf[200]; + +/* Open the file. */ +if (0 == (fp = fopen("path/to/file.toml", "r"))) { + return handle_error(); +} + +/* Run the file through the parser. */ +conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); +if (0 == conf) { + return handle_error(); +} + +fclose(fp); + +/* Alternatively, use `toml_parse` which takes a string rather than a file. */ +conf = toml_parse("A null terminated string that is TOML\0", errbuf, sizeof(errbuf); ``` - FILE* fp; - toml_table_t* conf; - toml_table_t* server; - const char* raw; - char* host; - int64_t port; - char errbuf[200]; +2. Get a single table from the file. - /* open file and parse */ - if (0 == (fp = fopen(FNAME, "r"))) { - return handle_error(); - } - conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); - fclose(fp); - if (0 == conf) { - return handle_error(); - } +```c +toml_table_t* server; - /* locate the [server] table */ - if (0 == (server = toml_table_in(conf, "server"))) { +/* Locate the [server] table. */ +if (0 == (server = toml_table_in(conf, "server"))) { return handle_error(); - } - - /* extract host config value */ - if (0 == (raw = toml_raw_in(server, "host"))) { - return handle_error(); - } - if (toml_rtos(raw, &host)) { - return handle_error(); - } - - /* extract port config value */ - if (0 == (raw = toml_raw_in(server, "port"))) { - return handle_error(); - } - if (toml_rtoi(raw, &port)) { - return handle_error(); - } - - /* done with conf */ - toml_free(conf); - - /* use host and port */ - do_work(host, port); - - /* clean up */ - free(host); +} ``` +3. Find a value from the table. +4. Convert that value to the appropriate type (I.E. string, int). -# Building +```c +const char* raw; +char* host; +int64_t port; + +/* Extract 'host' config value. */ +if (0 == (raw = toml_raw_in(server, "host"))) { + return handle_error(); +} + +/* Convert the raw value into a string. */ +if (toml_rtos(raw, &host)) { + return handle_error(); +} + +/* Extract 'port' config value. */ +if (0 == (raw = toml_raw_in(server, "port"))) { + return handle_error(); +} + +/* Convert the raw value into an int. */ +if (toml_rtoi(raw, &port)) { + return handle_error(); +} +``` + +5. Then, free up that memory if needed. + +```c +/* Use `toml_free` on the table returned from `toml_parse[_file]`. */ +toml_free(conf); + +/* Free any values returned from `toml_rto*`. */ +free(host); +free(port); +``` + +## Building A normal *make* suffices. Alternately, you can also simply include the `toml.c` and `toml.h` files in your project. -# Testing +## Testing To test against the standard test set provided by BurntSushi/toml-test: -``` - % make - % cd test1 - % bash build.sh # do this once - % bash run.sh # this will run the test suite +```sh +% make +% cd test1 +% bash build.sh # do this once +% bash run.sh # this will run the test suite ``` To test against the standard test set provided by iarna/toml: -``` - % make - % cd test2 - % bash build.sh # do this once - % bash run.sh # this will run the test suite +```sh +% make +% cd test2 +% bash build.sh # do this once +% bash run.sh # this will run the test suite ``` From 5d1d8e33894947949c98eba5d77c096a6a28ff4c Mon Sep 17 00:00:00 2001 From: dcresswell Date: Sat, 4 Jul 2020 16:48:10 -0700 Subject: [PATCH 054/138] Adds toml_raw_t to seperate raw and processed data This just makes it more obvious that toml_raw_at returns a incomplete bit of data. Users can easily see how to use rto* with this. --- README.md | 2 +- toml.c | 17 ++++++++--------- toml.h | 21 ++++++++++++--------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 708cd29..6b5b544 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ if (0 == (server = toml_table_in(conf, "server"))) { 4. Convert that value to the appropriate type (I.E. string, int). ```c -const char* raw; +toml_raw_t raw; char* host; int64_t port; diff --git a/toml.c b/toml.c index 4fd84a4..a5c8052 100644 --- a/toml.c +++ b/toml.c @@ -1741,8 +1741,7 @@ const char* toml_key_in(const toml_table_t* tab, int keyidx) return 0; } - -const char* toml_raw_in(const toml_table_t* tab, const char* key) +toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key) { int i; for (i = 0; i < tab->nkval; i++) { @@ -1773,7 +1772,7 @@ toml_table_t* toml_table_in(const toml_table_t* tab, const char* key) return 0; } -const char* toml_raw_at(const toml_array_t* arr, int idx) +toml_raw_t toml_raw_at(const toml_array_t* arr, int idx) { if (arr->kind != 'v') return 0; @@ -1848,7 +1847,7 @@ toml_table_t* toml_table_at(const toml_array_t* arr, int idx) } -int toml_rtots(const char* src_, toml_timestamp_t* ret) +int toml_rtots(toml_raw_t src_, toml_timestamp_t* ret) { if (! src_) return -1; @@ -1942,7 +1941,7 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret) /* Raw to boolean */ -int toml_rtob(const char* src, int* ret_) +int toml_rtob(toml_raw_t src, int* ret_) { if (!src) return -1; int dummy; @@ -1961,7 +1960,7 @@ int toml_rtob(const char* src, int* ret_) /* Raw to integer */ -int toml_rtoi(const char* src, int64_t* ret_) +int toml_rtoi(toml_raw_t src, int64_t* ret_) { if (!src) return -1; @@ -2024,7 +2023,7 @@ int toml_rtoi(const char* src, int64_t* ret_) } -int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) +int toml_rtod_ex(toml_raw_t src, double* ret_, char* buf, int buflen) { if (!src) return -1; @@ -2086,7 +2085,7 @@ int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen) return (errno || *endp) ? -1 : 0; } -int toml_rtod(const char* src, double* ret_) +int toml_rtod(toml_raw_t src, double* ret_) { char buf[100]; return toml_rtod_ex(src, ret_, buf, sizeof(buf)); @@ -2095,7 +2094,7 @@ int toml_rtod(const char* src, double* ret_) -int toml_rtos(const char* src, char** ret) +int toml_rtos(toml_raw_t src, char** ret) { int multiline = 0; const char* sp; diff --git a/toml.h b/toml.h index f61135d..ff851ba 100644 --- a/toml.h +++ b/toml.h @@ -39,6 +39,9 @@ typedef struct toml_table_t toml_table_t; typedef struct toml_array_t toml_array_t; +/* A raw value, must be processed by toml_rto* before using. */ +typedef const char* toml_raw_t; + /* Parse a file. Return a table on success, or 0 otherwise. * Caller must toml_free(the-return-value) after use. */ @@ -61,7 +64,7 @@ TOML_EXTERN void toml_free(toml_table_t* tab); TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx); /* Lookup table by key. Return the element or 0 if not found. */ -TOML_EXTERN const char* toml_raw_in(const toml_table_t* tab, const char* key); +TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key); TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab, const char* key); TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab, @@ -96,26 +99,26 @@ TOML_EXTERN int toml_table_ntab(const toml_table_t* tab); TOML_EXTERN const char* toml_table_key(const toml_table_t* tab); /* Deref array by index. Return the element at idx or 0 if out of range. */ -TOML_EXTERN const char* toml_raw_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t* arr, int idx); TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx); TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx); - /* Raw to String. Caller must call free(ret) after use. * Return 0 on success, -1 otherwise. */ -TOML_EXTERN int toml_rtos(const char* s, char** ret); +TOML_EXTERN int toml_rtos(toml_raw_t s, char** ret); /* Raw to Boolean. Return 0 on success, -1 otherwise. */ -TOML_EXTERN int toml_rtob(const char* s, int* ret); +TOML_EXTERN int toml_rtob(toml_raw_t s, int* ret); /* Raw to Integer. Return 0 on success, -1 otherwise. */ -TOML_EXTERN int toml_rtoi(const char* s, int64_t* ret); +TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t* ret); /* Raw to Double. Return 0 on success, -1 otherwise. */ -TOML_EXTERN int toml_rtod(const char* s, double* ret); +TOML_EXTERN int toml_rtod(toml_raw_t s, double* ret); + /* Same as toml_rtod, but return the sanitized double in string form as well */ -TOML_EXTERN int toml_rtod_ex(const char* s, double* ret, char* buf, int buflen); +TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen); /* Timestamp types. The year, month, day, hour, minute, second, z * fields may be NULL if they are not relevant. e.g. In a DATE @@ -134,7 +137,7 @@ struct toml_timestamp_t { }; /* Raw to Timestamp. Return 0 on success, -1 otherwise. */ -TOML_EXTERN int toml_rtots(const char* s, toml_timestamp_t* ret); +TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret); /* misc */ TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); From b539e3f20ec443d7046153ed4623da277da89170 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 9 Jul 2020 16:50:57 -0700 Subject: [PATCH 055/138] minor --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 6b5b544..094d2ae 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The steps for getting values from our file is usually : 1. Parse the whole TOML file. 2. Get a single table from the file. 3. Find a value from the table. -4. Convert that value to the appropriate type (I.E. string, int). +4. Convert that value to the appropriate type, i.e., string, int, etc. 5. Then, free up that memory if needed. Below is an example of parsing the values from the example table. @@ -95,7 +95,6 @@ toml_free(conf); /* Free any values returned from `toml_rto*`. */ free(host); -free(port); ``` ## Building From 9ea8eedd85dc0736997ae9f1183ea407a3460e34 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 14 Jul 2020 16:57:35 -0700 Subject: [PATCH 056/138] updated Note.txt to reflect expected error conditions in test2/ --- test2/Note.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test2/Note.txt b/test2/Note.txt index bb931de..6ca7347 100644 --- a/test2/Note.txt +++ b/test2/Note.txt @@ -1,5 +1,6 @@ -Note that these tests are expected to fail as we do not validate Unicode strings. +Note that we utilize the 'jq' command to normalize json files for comparison. Depending the +verson of jq on your system, some tests may generate error that looks like this: -% bash run.sh | grep FAIL -toml-spec-tests/errors/string-basic-multiline-out-of-range-unicode-escape-2.toml ... [FAILED] -toml-spec-tests/errors/string-basic-out-of-range-unicode-escape-2.toml ... [FAILED] + parse error: Exceeds depth limit for parsing at line 1 + +This is an error in 'jq', and it does not indicate that the tests themselves fail. From e3a03f5ec7d8d33be705c5ce8a632d998ce9b4d1 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 18 Aug 2020 14:46:20 -0700 Subject: [PATCH 057/138] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 094d2ae..c0c4d32 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # tomlc99 -TOML in c99; v0.5.0 compliant. +TOML in c99; v1.0 compliant. ## Usage From 4b42548c3dc76f6cc8059c2090bfcfd8fe497b18 Mon Sep 17 00:00:00 2001 From: Fridfinnur M Date: Fri, 18 Sep 2020 16:39:53 +0000 Subject: [PATCH 058/138] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c0c4d32..c3ed79c 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ if (0 == conf) { fclose(fp); /* Alternatively, use `toml_parse` which takes a string rather than a file. */ -conf = toml_parse("A null terminated string that is TOML\0", errbuf, sizeof(errbuf); +conf = toml_parse("A null terminated string that is TOML\0", errbuf, sizeof(errbuf)); ``` 2. Get a single table from the file. From 1901ac316682768541f44cfe700df2eb6759f2aa Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 25 Oct 2020 18:48:14 -0700 Subject: [PATCH 059/138] remove use of setjmp/longjmp --- toml.c | 519 +++++++++++++++++++++++++++------------------------------ 1 file changed, 243 insertions(+), 276 deletions(-) diff --git a/toml.c b/toml.c index a5c8052..f0a80bc 100644 --- a/toml.c +++ b/toml.c @@ -26,13 +26,13 @@ */ #define _POSIX_C_SOURCE 200809L #include -#include #include #include #include #include #include #include +#include #include "toml.h" @@ -282,7 +282,7 @@ struct toml_array_t { struct toml_table_t { const char* key; /* key to this table */ - int implicit; /* table was created implicitly */ + bool implicit; /* table was created implicitly */ /* key-values in the table */ int nkval; @@ -331,7 +331,6 @@ struct context_t { char* stop; char* errbuf; int errbufsz; - jmp_buf jmp; token_t tok; toml_table_t* root; @@ -349,52 +348,39 @@ struct context_t { #define TOSTRING(x) STRINGIFY(x) #define FLINE __FILE__ ":" TOSTRING(__LINE__) -static tokentype_t next_token(context_t* ctx, int dotisspecial); +static int next_token(context_t* ctx, int dotisspecial); -/* error routines. All these functions longjmp to ctx->jmp */ +/* + Error reporting. Call when an error is detected. Always return -1. +*/ static int e_outofmemory(context_t* ctx, const char* fline) { snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); - longjmp(ctx->jmp, 1); return -1; } -static int e_internal_error(context_t* ctx, const char* fline) +static int e_internal(context_t* ctx, const char* fline) { snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); - longjmp(ctx->jmp, 1); return -1; } -static int e_syntax_error(context_t* ctx, int lineno, const char* msg) +static int e_syntax(context_t* ctx, int lineno, const char* msg) { snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); - longjmp(ctx->jmp, 1); return -1; } -static int e_bad_key_error(context_t* ctx, int lineno) +static int e_badkey(context_t* ctx, int lineno) { snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); - longjmp(ctx->jmp, 1); return -1; } -/* - static int e_noimpl(context_t* ctx, const char* feature) - { - snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature); - longjmp(ctx->jmp, 1); - return -1; - } -*/ - -static int e_key_exists_error(context_t* ctx, int lineno) +static int e_keyexists(context_t* ctx, int lineno) { - snprintf(ctx->errbuf, ctx->errbufsz, - "line %d: key exists", lineno); - longjmp(ctx->jmp, 1); + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: key exists", lineno); return -1; } @@ -594,22 +580,22 @@ static char* normalize_key(context_t* ctx, token_t strtok) /* for single quote, take it verbatim. */ if (! (ret = STRNDUP(sp, sq - sp))) { e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } } else { /* for double quote, we need to normalize */ ret = norm_basic_str(sp, sq - sp, multiline, ebuf, sizeof(ebuf)); if (!ret) { - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf); - longjmp(ctx->jmp, 1); + e_syntax(ctx, lineno, ebuf); + return 0; } } /* newlines are not allowed in keys */ if (strchr(ret, '\n')) { xfree(ret); - e_bad_key_error(ctx, lineno); - return 0; /* not reached */ + e_badkey(ctx, lineno); + return 0; } return ret; } @@ -620,14 +606,14 @@ static char* normalize_key(context_t* ctx, token_t strtok) int k = *xp; if (isalnum(k)) continue; if (k == '_' || k == '-') continue; - e_bad_key_error(ctx, lineno); - return 0; /* not reached */ + e_badkey(ctx, lineno); + return 0; } /* dup and return it */ if (! (ret = STRNDUP(sp, sq - sp))) { e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } return ret; } @@ -686,13 +672,14 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, * remember to free it if we error out. */ char* newkey = normalize_key(ctx, keytok); + if (!newkey) return 0; /* if key exists: error out. */ toml_keyval_t* dest = 0; if (key_kind(tab, newkey)) { xfree(newkey); - e_key_exists_error(ctx, keytok.lineno); - return 0; /* not reached */ + e_keyexists(ctx, keytok.lineno); + return 0; } /* make a new entry */ @@ -701,14 +688,14 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, if (0 == (base = (toml_keyval_t**) REALLOC(tab->kval, (n+1) * sizeof(*base)))) { xfree(newkey); e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } tab->kval = base; if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { xfree(newkey); e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } dest = tab->kval[tab->nkval++]; @@ -726,6 +713,7 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, * remember to free it if we error out. */ char* newkey = normalize_key(ctx, keytok); + if (!newkey) return 0; /* if key exists: error out */ toml_table_t* dest = 0; @@ -735,11 +723,11 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, /* special case: if table exists, but was created implicitly ... */ if (dest && dest->implicit) { /* we make it explicit now, and simply return it. */ - dest->implicit = 0; + dest->implicit = false; return dest; } - e_key_exists_error(ctx, keytok.lineno); - return 0; /* not reached */ + e_keyexists(ctx, keytok.lineno); + return 0; } /* create a new table entry */ @@ -748,14 +736,14 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, if (0 == (base = (toml_table_t**) REALLOC(tab->tab, (n+1) * sizeof(*base)))) { xfree(newkey); e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } tab->tab = base; if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { xfree(newkey); e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } dest = tab->tab[tab->ntab++]; @@ -776,12 +764,13 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, * remember to free it if we error out. */ char* newkey = normalize_key(ctx, keytok); + if (!newkey) return 0; /* if key exists: error out */ if (key_kind(tab, newkey)) { xfree(newkey); /* don't need this anymore */ - e_key_exists_error(ctx, keytok.lineno); - return 0; /* not reached */ + e_keyexists(ctx, keytok.lineno); + return 0; } /* make a new array entry */ @@ -790,14 +779,14 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, if (0 == (base = (toml_array_t**) REALLOC(tab->arr, (n+1) * sizeof(*base)))) { xfree(newkey); e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } tab->arr = base; if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { xfree(newkey); e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } toml_array_t* dest = tab->arr[tab->narr++]; @@ -816,13 +805,13 @@ static toml_array_t* create_array_in_array(context_t* ctx, toml_array_t** base; if (0 == (base = (toml_array_t**) REALLOC(parent->u.arr, (n+1) * sizeof(*base)))) { e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } parent->u.arr = base; if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } return parent->u.arr[parent->nelem++]; @@ -837,76 +826,81 @@ static toml_table_t* create_table_in_array(context_t* ctx, toml_table_t** base; if (0 == (base = (toml_table_t**) REALLOC(parent->u.tab, (n+1) * sizeof(*base)))) { e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } parent->u.tab = base; if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { e_outofmemory(ctx, FLINE); - return 0; /* not reached */ + return 0; } return parent->u.tab[parent->nelem++]; } -static void skip_newlines(context_t* ctx, int isdotspecial) +static int skip_newlines(context_t* ctx, int isdotspecial) { while (ctx->tok.tok == NEWLINE) { - next_token(ctx, isdotspecial); + if (next_token(ctx, isdotspecial)) return -1; if (ctx->tok.eof) break; } + return 0; } -#define EAT_TOKEN(ctx, typ, isdotspecial) \ - if ((ctx)->tok.tok != typ) e_internal_error(ctx, FLINE); else next_token(ctx, isdotspecial) +static int parse_keyval(context_t* ctx, toml_table_t* tab); +static inline int eat_token(context_t* ctx, tokentype_t typ, int isdotspecial, const char* fline) +{ + if (ctx->tok.tok != typ) + return e_internal(ctx, fline); + + if (next_token(ctx, isdotspecial)) + return -1; + + return 0; +} -static void parse_keyval(context_t* ctx, toml_table_t* tab); /* We are at '{ ... }'. * Parse the table. */ -static void parse_table(context_t* ctx, toml_table_t* tab) +static int parse_table(context_t* ctx, toml_table_t* tab) { - EAT_TOKEN(ctx, LBRACE, 1); + if (eat_token(ctx, LBRACE, 1, FLINE)) + return -1; for (;;) { - if (ctx->tok.tok == NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); - return; /* not reached */ - } + if (ctx->tok.tok == NEWLINE) + return e_syntax(ctx, ctx->tok.lineno, "newline not allowed in inline table"); /* until } */ - if (ctx->tok.tok == RBRACE) break; + if (ctx->tok.tok == RBRACE) + break; - if (ctx->tok.tok != STRING) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } - parse_keyval(ctx, tab); + if (ctx->tok.tok != STRING) + return e_syntax(ctx, ctx->tok.lineno, "expect a string"); + + if (parse_keyval(ctx, tab)) + return -1; - if (ctx->tok.tok == NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "newline not allowed in inline table"); - return; /* not reached */ - } + if (ctx->tok.tok == NEWLINE) + return e_syntax(ctx, ctx->tok.lineno, "newline not allowed in inline table"); /* on comma, continue to scan for next keyval */ if (ctx->tok.tok == COMMA) { - EAT_TOKEN(ctx, COMMA, 1); + if (eat_token(ctx, COMMA, 1, FLINE)) + return -1; continue; } break; } - if (ctx->tok.tok != RBRACE) { - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ - } - - EAT_TOKEN(ctx, RBRACE, 1); + if (eat_token(ctx, RBRACE, 1, FLINE)) + return -1; + return 0; } static int valtype(const char* val) @@ -926,12 +920,12 @@ static int valtype(const char* val) /* We are at '[...]' */ -static void parse_array(context_t* ctx, toml_array_t* arr) +static int parse_array(context_t* ctx, toml_array_t* arr) { - EAT_TOKEN(ctx, LBRACKET, 0); - + if (eat_token(ctx, LBRACKET, 0, FLINE)) return -1; + for (;;) { - skip_newlines(ctx, 0); + if (skip_newlines(ctx, 0)) return -1; /* until ] */ if (ctx->tok.tok == RBRACKET) break; @@ -945,35 +939,29 @@ static void parse_array(context_t* ctx, toml_array_t* arr) /* set array kind if this will be the first entry */ if (arr->kind == 0) arr->kind = 'v'; /* check array kind */ - if (arr->kind != 'v') { - e_syntax_error(ctx, ctx->tok.lineno, - "a string array can only contain strings"); - return; /* not reached */ - } + if (arr->kind != 'v') + return e_syntax(ctx, ctx->tok.lineno, "a string array can only contain strings"); /* make a new value in array */ char** tmp = (char**) REALLOC(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); - if (!tmp) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + if (!tmp) + return e_outofmemory(ctx, FLINE); + arr->u.val = tmp; - if (! (val = STRNDUP(val, vlen))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + if (! (val = STRNDUP(val, vlen))) + return e_outofmemory(ctx, FLINE); + arr->u.val[arr->nelem++] = val; /* set array type if this is the first entry, or check that the types matched. */ if (arr->nelem == 1) arr->type = valtype(arr->u.val[0]); else if (arr->type != valtype(val)) { - e_syntax_error(ctx, ctx->tok.lineno, + return e_syntax(ctx, ctx->tok.lineno, "array type mismatch while processing array of values"); - return; /* not reached */ } - EAT_TOKEN(ctx, STRING, 0); + if (eat_token(ctx, STRING, 0, FLINE)) return -1; break; } @@ -983,11 +971,12 @@ static void parse_array(context_t* ctx, toml_array_t* arr) if (arr->kind == 0) arr->kind = 'a'; /* check array kind */ if (arr->kind != 'a') { - e_syntax_error(ctx, ctx->tok.lineno, - "array type mismatch while processing array of arrays"); - return; /* not reached */ + return e_syntax(ctx, ctx->tok.lineno, + "array type mismatch while processing array of arrays"); } - parse_array(ctx, create_array_in_array(ctx, arr)); + toml_array_t* subarr = create_array_in_array(ctx, arr); + if (!subarr) return -1; + if (parse_array(ctx, subarr)) return -1; break; } @@ -997,35 +986,31 @@ static void parse_array(context_t* ctx, toml_array_t* arr) if (arr->kind == 0) arr->kind = 't'; /* check array kind */ if (arr->kind != 't') { - e_syntax_error(ctx, ctx->tok.lineno, - "array type mismatch while processing array of tables"); - return; /* not reached */ + return e_syntax(ctx, ctx->tok.lineno, + "array type mismatch while processing array of tables"); } - parse_table(ctx, create_table_in_array(ctx, arr)); + toml_table_t* subtab = create_table_in_array(ctx, arr); + if (!subtab) return -1; + if (parse_table(ctx, subtab)) return -1; break; } default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ + return e_syntax(ctx, ctx->tok.lineno, "syntax error"); } - skip_newlines(ctx, 0); + if (skip_newlines(ctx, 0)) return -1; /* on comma, continue to scan for next element */ if (ctx->tok.tok == COMMA) { - EAT_TOKEN(ctx, COMMA, 0); + if (eat_token(ctx, COMMA, 0, FLINE)) return -1; continue; } break; } - if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "expect a right bracket"); - return; /* not reached */ - } - - EAT_TOKEN(ctx, RBRACKET, 1); + if (eat_token(ctx, RBRACKET, 1, FLINE)) return -1; + return 0; } @@ -1034,11 +1019,11 @@ static void parse_array(context_t* ctx, toml_array_t* arr) key = [ array ] key = { table } */ -static void parse_keyval(context_t* ctx, toml_table_t* tab) +static int parse_keyval(context_t* ctx, toml_table_t* tab) { token_t key = ctx->tok; - EAT_TOKEN(ctx, STRING, 1); - + if (eat_token(ctx, STRING, 1, FLINE)) return -1; + if (ctx->tok.tok == DOT) { /* handle inline dotted key. e.g. @@ -1053,54 +1038,55 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab) } if (!subtab) { subtab = create_keytable_in_table(ctx, tab, key); + if (!subtab) return -1; } - next_token(ctx, 1); - parse_keyval(ctx, subtab); - return; + if (next_token(ctx, 1)) return -1; + if (parse_keyval(ctx, subtab)) return -1; + return 0; } if (ctx->tok.tok != EQUAL) { - e_syntax_error(ctx, ctx->tok.lineno, "missing ="); - return; /* not reached */ + return e_syntax(ctx, ctx->tok.lineno, "missing ="); } - next_token(ctx, 0); + if (next_token(ctx, 0)) return -1; switch (ctx->tok.tok) { case STRING: { /* key = "value" */ toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); + if (!keyval) return -1; token_t val = ctx->tok; + assert(keyval->val == 0); - keyval->val = STRNDUP(val.ptr, val.len); - if (! keyval->val) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + if (! (keyval->val = STRNDUP(val.ptr, val.len))) + return e_outofmemory(ctx, FLINE); - next_token(ctx, 1); + if (next_token(ctx, 1)) return -1; - return; + return 0; } case LBRACKET: { /* key = [ array ] */ toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); - parse_array(ctx, arr); - return; + if (!arr) return -1; + if (parse_array(ctx, arr)) return -1; + return 0; } case LBRACE: { /* key = { table } */ toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); - parse_table(ctx, nxttab); - return; + if (!nxttab) return -1; + if (parse_table(ctx, nxttab)) return -1; + return 0; } default: - e_syntax_error(ctx, ctx->tok.lineno, "syntax error"); - return; /* not reached */ + return e_syntax(ctx, ctx->tok.lineno, "syntax error"); } + return 0; } @@ -1114,7 +1100,7 @@ struct tabpath_t { * Scan forward and fill tabpath until it enters ] or ]] * There will be at least one entry on return. */ -static void fill_tabpath(context_t* ctx) +static int fill_tabpath(context_t* ctx) { int lineno = ctx->tok.lineno; int i; @@ -1128,43 +1114,39 @@ static void fill_tabpath(context_t* ctx) ctx->tpath.top = 0; for (;;) { - if (ctx->tpath.top >= 10) { - e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); - return; /* not reached */ - } + if (ctx->tpath.top >= 10) + return e_syntax(ctx, lineno, "table path is too deep; max allowed is 10."); - if (ctx->tok.tok != STRING) { - e_syntax_error(ctx, lineno, "invalid or missing key"); - return; /* not reached */ - } + if (ctx->tok.tok != STRING) + return e_syntax(ctx, lineno, "invalid or missing key"); + char* key = normalize_key(ctx, ctx->tok); + if (!key) return -1; ctx->tpath.tok[ctx->tpath.top] = ctx->tok; - ctx->tpath.key[ctx->tpath.top] = normalize_key(ctx, ctx->tok); + ctx->tpath.key[ctx->tpath.top] = key; ctx->tpath.top++; - next_token(ctx, 1); + if (next_token(ctx, 1)) return -1; if (ctx->tok.tok == RBRACKET) break; - if (ctx->tok.tok != DOT) { - e_syntax_error(ctx, lineno, "invalid key"); - return; /* not reached */ - } + if (ctx->tok.tok != DOT) + return e_syntax(ctx, lineno, "invalid key"); - next_token(ctx, 1); + if (next_token(ctx, 1)) return -1; } - if (ctx->tpath.top <= 0) { - e_syntax_error(ctx, lineno, "empty table selector"); - return; /* not reached */ - } + if (ctx->tpath.top <= 0) + return e_syntax(ctx, lineno, "empty table selector"); + + return 0; } /* Walk tabpath from the root, and create new tables on the way. * Sets ctx->curtab to the final table. */ -static void walk_tabpath(context_t* ctx) +static int walk_tabpath(context_t* ctx) { /* start from root */ toml_table_t* curtab = ctx->root; @@ -1182,45 +1164,37 @@ static void walk_tabpath(context_t* ctx) case 'a': /* found an array. nexttab is the last table in the array. */ - if (nextarr->kind != 't') { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } - if (nextarr->nelem == 0) { - e_internal_error(ctx, FLINE); - return; /* not reached */ - } + if (nextarr->kind != 't') + return e_internal(ctx, FLINE); + + if (nextarr->nelem == 0) + return e_internal(ctx, FLINE); + nexttab = nextarr->u.tab[nextarr->nelem-1]; break; case 'v': - e_key_exists_error(ctx, ctx->tpath.tok[i].lineno); - return; /* not reached */ + return e_keyexists(ctx, ctx->tpath.tok[i].lineno); default: { /* Not found. Let's create an implicit table. */ int n = curtab->ntab; toml_table_t** base = (toml_table_t**) REALLOC(curtab->tab, (n+1) * sizeof(*base)); - if (0 == base) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + if (0 == base) + return e_outofmemory(ctx, FLINE); + curtab->tab = base; - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) + return e_outofmemory(ctx, FLINE); - if (0 == (base[n]->key = STRDUP(key))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + if (0 == (base[n]->key = STRDUP(key))) + return e_outofmemory(ctx, FLINE); nexttab = curtab->tab[curtab->ntab++]; /* tabs created by walk_tabpath are considered implicit */ - nexttab->implicit = 1; + nexttab->implicit = true; } break; } @@ -1231,11 +1205,13 @@ static void walk_tabpath(context_t* ctx) /* save it */ ctx->curtab = curtab; + + return 0; } /* handle lines like [x.y.z] or [[x.y.z]] */ -static void parse_select(context_t* ctx) +static int parse_select(context_t* ctx) { assert(ctx->tok.tok == LBRACKET); @@ -1245,13 +1221,13 @@ static void parse_select(context_t* ctx) and '[ [' would be taken as '[[', which is wrong. */ /* eat [ or [[ */ - EAT_TOKEN(ctx, LBRACKET, 1); + if (eat_token(ctx, LBRACKET, 1, FLINE)) return -1; if (llb) { assert(ctx->tok.tok == LBRACKET); - EAT_TOKEN(ctx, LBRACKET, 1); + if (eat_token(ctx, LBRACKET, 1, FLINE)) return -1; } - fill_tabpath(ctx); + if (fill_tabpath(ctx)) return -1; /* For [x.y.z] or [[x.y.z]], remove z from tpath. */ @@ -1260,51 +1236,44 @@ static void parse_select(context_t* ctx) ctx->tpath.top--; /* set up ctx->curtab */ - walk_tabpath(ctx); + if (walk_tabpath(ctx)) return -1; if (! llb) { /* [x.y.z] -> create z = {} in x.y */ - ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z); + toml_table_t* curtab = create_keytable_in_table(ctx, ctx->curtab, z); + if (!curtab) return -1; + ctx->curtab = curtab; } else { /* [[x.y.z]] -> create z = [] in x.y */ toml_array_t* arr = 0; { char* zstr = normalize_key(ctx, z); + if (!zstr) return -1; arr = toml_array_in(ctx->curtab, zstr); xfree(zstr); } if (!arr) { arr = create_keyarray_in_table(ctx, ctx->curtab, z, 't'); - if (!arr) { - e_internal_error(ctx, FLINE); - return; - } - } - if (arr->kind != 't') { - e_syntax_error(ctx, z.lineno, "array mismatch"); - return; /* not reached */ + if (!arr) return -1; } + if (arr->kind != 't') + return e_syntax(ctx, z.lineno, "array mismatch"); /* add to z[] */ toml_table_t* dest; { int n = arr->nelem; toml_table_t** base = REALLOC(arr->u.tab, (n+1) * sizeof(*base)); - if (0 == base) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + if (0 == base) + return e_outofmemory(ctx, FLINE); + arr->u.tab = base; - if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) + return e_outofmemory(ctx, FLINE); - if (0 == (base[n]->key = STRDUP("__anon__"))) { - e_outofmemory(ctx, FLINE); - return; /* not reached */ - } + if (0 == (base[n]->key = STRDUP("__anon__"))) + return e_outofmemory(ctx, FLINE); dest = arr->u.tab[arr->nelem++]; } @@ -1313,22 +1282,22 @@ static void parse_select(context_t* ctx) } if (ctx->tok.tok != RBRACKET) { - e_syntax_error(ctx, ctx->tok.lineno, "expects ]"); - return; /* not reached */ + return e_syntax(ctx, ctx->tok.lineno, "expects ]"); } if (llb) { if (! (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) { - e_syntax_error(ctx, ctx->tok.lineno, "expects ]]"); - return; /* not reached */ + return e_syntax(ctx, ctx->tok.lineno, "expects ]]"); } - EAT_TOKEN(ctx, RBRACKET, 1); - } - EAT_TOKEN(ctx, RBRACKET, 1); - - if (ctx->tok.tok != NEWLINE) { - e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); - return; /* not reached */ + if (eat_token(ctx, RBRACKET, 1, FLINE)) return -1; } + + if (eat_token(ctx, RBRACKET, 1, FLINE)) + return -1; + + if (ctx->tok.tok != NEWLINE) + return e_syntax(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); + + return 0; } @@ -1359,53 +1328,52 @@ toml_table_t* toml_parse(char* conf, // make a root table if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { - /* do not call outofmemory() here... setjmp not done yet */ - snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE); + e_outofmemory(&ctx, FLINE); + // Do not goto fail, root table not set up yet return 0; } // set root as default table ctx.curtab = ctx.root; - if (0 != setjmp(ctx.jmp)) { - // Got here from a long_jmp. Something bad has happened. - // Free resources and return error. - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - toml_free(ctx.root); - return 0; - } - /* Scan forward until EOF */ for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { switch (tok.tok) { case NEWLINE: - next_token(&ctx, 1); + if (next_token(&ctx, 1)) goto fail; break; case STRING: - parse_keyval(&ctx, ctx.curtab); + if (parse_keyval(&ctx, ctx.curtab)) goto fail; + if (ctx.tok.tok != NEWLINE) { - e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); - return 0; /* not reached */ + e_syntax(&ctx, ctx.tok.lineno, "extra chars after value"); + goto fail; } - EAT_TOKEN(&ctx, NEWLINE, 1); + if (eat_token(&ctx, NEWLINE, 1, FLINE)) goto fail; break; case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ - parse_select(&ctx); + if (parse_select(&ctx)) goto fail; break; default: - snprintf(ctx.errbuf, ctx.errbufsz, "line %d: syntax error", tok.lineno); - longjmp(ctx.jmp, 1); + e_syntax(&ctx, tok.lineno, "syntax error"); + goto fail; } } /* success */ for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); return ctx.root; + +fail: + // Something bad has happened. Free resources and return error. + for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); + toml_free(ctx.root); + return 0; } @@ -1521,7 +1489,7 @@ void toml_free(toml_table_t* tab) } -static tokentype_t ret_token(context_t* ctx, tokentype_t tok, int lineno, char* ptr, int len) +static void set_token(context_t* ctx, tokentype_t tok, int lineno, char* ptr, int len) { token_t t; t.tok = tok; @@ -1530,14 +1498,12 @@ static tokentype_t ret_token(context_t* ctx, tokentype_t tok, int lineno, char* t.len = len; t.eof = 0; ctx->tok = t; - return tok; } -static tokentype_t ret_eof(context_t* ctx, int lineno) +static void set_eof(context_t* ctx, int lineno) { - ret_token(ctx, NEWLINE, lineno, ctx->stop, 0); + set_token(ctx, NEWLINE, lineno, ctx->stop, 0); ctx->tok.eof = 1; - return ctx->tok.tok; } @@ -1576,17 +1542,17 @@ static int scan_time(const char* p, int* hh, int* mm, int* ss) } -static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) +static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) { char* orig = p; if (0 == strncmp(p, "'''", 3)) { p = strstr(p + 3, "'''"); if (0 == p) { - e_syntax_error(ctx, lineno, "unterminated triple-s-quote"); - return 0; /* not reached */ + return e_syntax(ctx, lineno, "unterminated triple-s-quote"); } - return ret_token(ctx, STRING, lineno, orig, p + 3 - orig); + set_token(ctx, STRING, lineno, orig, p + 3 - orig); + return 0; } if (0 == strncmp(p, "\"\"\"", 3)) { @@ -1600,34 +1566,32 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe if (*p == 'u') { hexreq = 4; continue; } if (*p == 'U') { hexreq = 8; continue; } if (p[strspn(p, " \t\r")] == '\n') continue; /* allow for line ending backslash */ - e_syntax_error(ctx, lineno, "bad escape char"); - return 0; /* not reached */ + return e_syntax(ctx, lineno, "bad escape char"); } if (hexreq) { hexreq--; if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); - return 0; /* not reached */ + return e_syntax(ctx, lineno, "expect hex char"); } if (*p == '\\') { escape = 1; continue; } qcnt = (*p == '"') ? qcnt + 1 : 0; } if (qcnt != 3) { - e_syntax_error(ctx, lineno, "unterminated triple-quote"); - return 0; /* not reached */ + return e_syntax(ctx, lineno, "unterminated triple-quote"); } - return ret_token(ctx, STRING, lineno, orig, p - orig); + set_token(ctx, STRING, lineno, orig, p - orig); + return 0; } if ('\'' == *p) { for (p++; *p && *p != '\n' && *p != '\''; p++); if (*p != '\'') { - e_syntax_error(ctx, lineno, "unterminated s-quote"); - return 0; /* not reached */ + return e_syntax(ctx, lineno, "unterminated s-quote"); } - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + set_token(ctx, STRING, lineno, orig, p + 1 - orig); + return 0; } if ('\"' == *p) { @@ -1639,25 +1603,23 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe if (strchr("btnfr\"\\", *p)) continue; if (*p == 'u') { hexreq = 4; continue; } if (*p == 'U') { hexreq = 8; continue; } - e_syntax_error(ctx, lineno, "bad escape char"); - return 0; /* not reached */ + return e_syntax(ctx, lineno, "bad escape char"); } if (hexreq) { hexreq--; if (strchr("0123456789ABCDEF", *p)) continue; - e_syntax_error(ctx, lineno, "expect hex char"); - return 0; /* not reached */ + return e_syntax(ctx, lineno, "expect hex char"); } if (*p == '\\') { escape = 1; continue; } if (*p == '\n') break; if (*p == '"') break; } if (*p != '"') { - e_syntax_error(ctx, lineno, "unterminated quote"); - return 0; /* not reached */ + return e_syntax(ctx, lineno, "unterminated quote"); } - return ret_token(ctx, STRING, lineno, orig, p + 1 - orig); + set_token(ctx, STRING, lineno, orig, p + 1 - orig); + return 0; } /* check for timestamp without quotes */ @@ -1667,7 +1629,8 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe // squeeze out any spaces at end of string for ( ; p[-1] == ' '; p--); // tokenize - return ret_token(ctx, STRING, lineno, orig, p - orig); + set_token(ctx, STRING, lineno, orig, p - orig); + return 0; } /* literals */ @@ -1680,11 +1643,12 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe break; } - return ret_token(ctx, STRING, lineno, orig, p - orig); + set_token(ctx, STRING, lineno, orig, p - orig); + return 0; } -static tokentype_t next_token(context_t* ctx, int dotisspecial) +static int next_token(context_t* ctx, int dotisspecial) { int lineno = ctx->tok.lineno; char* p = ctx->tok.ptr; @@ -1704,17 +1668,19 @@ static tokentype_t next_token(context_t* ctx, int dotisspecial) continue; } - if (dotisspecial && *p == '.') - return ret_token(ctx, DOT, lineno, p, 1); + if (dotisspecial && *p == '.') { + set_token(ctx, DOT, lineno, p, 1); + return 0; + } switch (*p) { - case ',': return ret_token(ctx, COMMA, lineno, p, 1); - case '=': return ret_token(ctx, EQUAL, lineno, p, 1); - case '{': return ret_token(ctx, LBRACE, lineno, p, 1); - case '}': return ret_token(ctx, RBRACE, lineno, p, 1); - case '[': return ret_token(ctx, LBRACKET, lineno, p, 1); - case ']': return ret_token(ctx, RBRACKET, lineno, p, 1); - case '\n': return ret_token(ctx, NEWLINE, lineno, p, 1); + case ',': set_token(ctx, COMMA, lineno, p, 1); return 0; + case '=': set_token(ctx, EQUAL, lineno, p, 1); return 0; + case '{': set_token(ctx, LBRACE, lineno, p, 1); return 0; + case '}': set_token(ctx, RBRACE, lineno, p, 1); return 0; + case '[': set_token(ctx, LBRACKET, lineno, p, 1); return 0; + case ']': set_token(ctx, RBRACKET, lineno, p, 1); return 0; + case '\n': set_token(ctx, NEWLINE, lineno, p, 1); return 0; case '\r': case ' ': case '\t': /* ignore white spaces */ p++; @@ -1724,7 +1690,8 @@ static tokentype_t next_token(context_t* ctx, int dotisspecial) return scan_string(ctx, p, lineno, dotisspecial); } - return ret_eof(ctx, lineno); + set_eof(ctx, lineno); + return 0; } From 2e8feafae869abba81289e5c6f56487b75a7a582 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 26 Oct 2020 13:52:28 -0700 Subject: [PATCH 060/138] enhance toml_set_memutil to assign default --- toml.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/toml.c b/toml.c index f0a80bc..b41b647 100644 --- a/toml.c +++ b/toml.c @@ -46,10 +46,10 @@ void toml_set_memutil(void* (*xxmalloc)(size_t), void* (*xxcalloc)(size_t, size_t), void* (*xxrealloc)(void*, size_t)) { - ppmalloc = xxmalloc; - ppfree = xxfree; - ppcalloc = xxcalloc; - pprealloc = xxrealloc; + if (xxmalloc) ppmalloc = xxmalloc; + if (xxfree) ppfree = xxfree; + if (xxcalloc) ppcalloc = xxcalloc; + if (xxrealloc) pprealloc = xxrealloc; } From bc6f2fa6b808bb876a66b5dfb70c68cbcfc880c2 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 27 Oct 2020 03:32:22 -0700 Subject: [PATCH 061/138] remove use of realloc --- toml.c | 99 +++++++++++++++++++++++++++++++++++++--------------------- toml.h | 3 +- 2 files changed, 65 insertions(+), 37 deletions(-) diff --git a/toml.c b/toml.c index b41b647..df2e0aa 100644 --- a/toml.c +++ b/toml.c @@ -39,24 +39,20 @@ static void* (*ppmalloc)(size_t) = malloc; static void (*ppfree)(void*) = free; static void* (*ppcalloc)(size_t, size_t) = calloc; -static void* (*pprealloc)(void*, size_t) = realloc; void toml_set_memutil(void* (*xxmalloc)(size_t), void (*xxfree)(void*), - void* (*xxcalloc)(size_t, size_t), - void* (*xxrealloc)(void*, size_t)) + void* (*xxcalloc)(size_t, size_t)) { if (xxmalloc) ppmalloc = xxmalloc; if (xxfree) ppfree = xxfree; if (xxcalloc) ppcalloc = xxcalloc; - if (xxrealloc) pprealloc = xxrealloc; } #define MALLOC(a) ppmalloc(a) #define FREE(a) ppfree(a) #define CALLOC(a,b) ppcalloc(a,b) -#define REALLOC(a,b) pprealloc(a,b) static char* STRDUP(const char* s) { @@ -384,6 +380,28 @@ static int e_keyexists(context_t* ctx, int lineno) return -1; } +static void* expand(void* p, int sz, int newsz) +{ + void* s = malloc(newsz); + if (!s) return 0; + + memcpy(s, p, sz); + free(p); + return s; +} + +static void** expand_ptrarr(void** p, int n) +{ + void** s = malloc((n+1) * sizeof(void*)); + if (!s) return 0; + + s[n] = 0; + memcpy(s, p, n * sizeof(void*)); + free(p); + return s; +} + + static char* norm_lit_str(const char* src, int srclen, int multiline, char* errbuf, int errbufsz) @@ -398,13 +416,15 @@ static char* norm_lit_str(const char* src, int srclen, /* scan forward on src */ for (;;) { if (off >= max - 10) { /* have some slack for misc stuff */ - char* x = REALLOC(dst, max += 50); + int newmax = max + 50; + char* x = expand(dst, max, newmax); if (!x) { xfree(dst); snprintf(errbuf, errbufsz, "out of memory"); return 0; } dst = x; + max = newmax; } /* finished? */ @@ -451,13 +471,15 @@ static char* norm_basic_str(const char* src, int srclen, /* scan forward on src */ for (;;) { if (off >= max - 10) { /* have some slack for misc stuff */ - char* x = REALLOC(dst, max += 50); + int newmax = max + 50; + char* x = expand(dst, max, newmax); if (!x) { xfree(dst); snprintf(errbuf, errbufsz, "out of memory"); return 0; } dst = x; + max = newmax; } /* finished? */ @@ -685,7 +707,7 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, /* make a new entry */ int n = tab->nkval; toml_keyval_t** base; - if (0 == (base = (toml_keyval_t**) REALLOC(tab->kval, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_keyval_t**) expand_ptrarr((void**)tab->kval, n))) { xfree(newkey); e_outofmemory(ctx, FLINE); return 0; @@ -733,7 +755,7 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, /* create a new table entry */ int n = tab->ntab; toml_table_t** base; - if (0 == (base = (toml_table_t**) REALLOC(tab->tab, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_table_t**) expand_ptrarr((void**)tab->tab, n))) { xfree(newkey); e_outofmemory(ctx, FLINE); return 0; @@ -776,7 +798,7 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, /* make a new array entry */ int n = tab->narr; toml_array_t** base; - if (0 == (base = (toml_array_t**) REALLOC(tab->arr, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_array_t**) expand_ptrarr((void**)tab->arr, n))) { xfree(newkey); e_outofmemory(ctx, FLINE); return 0; @@ -801,20 +823,21 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, static toml_array_t* create_array_in_array(context_t* ctx, toml_array_t* parent) { - int n = parent->nelem; + const int n = parent->nelem; toml_array_t** base; - if (0 == (base = (toml_array_t**) REALLOC(parent->u.arr, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_array_t**) expand_ptrarr((void**)parent->u.arr, n))) { e_outofmemory(ctx, FLINE); return 0; } parent->u.arr = base; + parent->nelem++; if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { e_outofmemory(ctx, FLINE); return 0; } - return parent->u.arr[parent->nelem++]; + return parent->u.arr[n]; } /* Create a table in an array @@ -824,7 +847,7 @@ static toml_table_t* create_table_in_array(context_t* ctx, { int n = parent->nelem; toml_table_t** base; - if (0 == (base = (toml_table_t**) REALLOC(parent->u.tab, (n+1) * sizeof(*base)))) { + if (0 == (base = (toml_table_t**) expand_ptrarr((void**)parent->u.tab, n))) { e_outofmemory(ctx, FLINE); return 0; } @@ -943,7 +966,7 @@ static int parse_array(context_t* ctx, toml_array_t* arr) return e_syntax(ctx, ctx->tok.lineno, "a string array can only contain strings"); /* make a new value in array */ - char** tmp = (char**) REALLOC(arr->u.val, (arr->nelem+1) * sizeof(*tmp)); + char** tmp = (char**) expand_ptrarr((void**)arr->u.val, arr->nelem); if (!tmp) return e_outofmemory(ctx, FLINE); @@ -1179,7 +1202,7 @@ static int walk_tabpath(context_t* ctx) default: { /* Not found. Let's create an implicit table. */ int n = curtab->ntab; - toml_table_t** base = (toml_table_t**) REALLOC(curtab->tab, (n+1) * sizeof(*base)); + toml_table_t** base = (toml_table_t**) expand_ptrarr((void**)curtab->tab, n); if (0 == base) return e_outofmemory(ctx, FLINE); @@ -1263,7 +1286,7 @@ static int parse_select(context_t* ctx) toml_table_t* dest; { int n = arr->nelem; - toml_table_t** base = REALLOC(arr->u.tab, (n+1) * sizeof(*base)); + toml_table_t** base = (toml_table_t**) expand_ptrarr((void**)arr->u.tab, n); if (0 == base) return e_outofmemory(ctx, FLINE); @@ -1385,26 +1408,21 @@ toml_table_t* toml_parse_file(FILE* fp, char* buf = 0; int off = 0; - /* prime the buf[] */ - bufsz = 1000; - if (! (buf = MALLOC(bufsz + 1))) { - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - /* read from fp into buf */ while (! feof(fp)) { - bufsz += 1000; - - /* Allocate 1 extra byte because we will tag on a NUL */ - char* x = REALLOC(buf, bufsz + 1); - if (!x) { - snprintf(errbuf, errbufsz, "out of memory"); - xfree(buf); - return 0; - } - buf = x; + if (off == bufsz) { + int xsz = bufsz + 1000; + char* x = expand(buf, bufsz, xsz); + if (!x) { + snprintf(errbuf, errbufsz, "out of memory"); + xfree(buf); + return 0; + } + buf = x; + bufsz = xsz; + } + errno = 0; int n = fread(buf + off, 1, bufsz - off, fp); if (ferror(fp)) { @@ -1417,7 +1435,18 @@ toml_table_t* toml_parse_file(FILE* fp, } /* tag on a NUL to cap the string */ - buf[off] = 0; /* we accounted for this byte in the REALLOC() above. */ + if (off == bufsz) { + int xsz = bufsz + 1; + char* x = expand(buf, bufsz, xsz); + if (!x) { + snprintf(errbuf, errbufsz, "out of memory"); + xfree(buf); + return 0; + } + buf = x; + bufsz = xsz; + } + buf[off] = 0; /* parse it, cleanup and finish */ toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); diff --git a/toml.h b/toml.h index ff851ba..9e0fe21 100644 --- a/toml.h +++ b/toml.h @@ -144,7 +144,6 @@ TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t), void (*xxfree)(void*), - void* (*xxcalloc)(size_t, size_t), - void* (*xxrealloc)(void*, size_t)); + void* (*xxcalloc)(size_t, size_t)); #endif /* TOML_H */ From 5be06807ad5f2230cad99e15380c4f4076c9dd83 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 27 Oct 2020 16:59:43 -0700 Subject: [PATCH 062/138] remove use of calloc --- toml.c | 29 ++++++++++++++++++----------- toml.h | 3 +-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/toml.c b/toml.c index df2e0aa..1db5a5b 100644 --- a/toml.c +++ b/toml.c @@ -38,21 +38,28 @@ static void* (*ppmalloc)(size_t) = malloc; static void (*ppfree)(void*) = free; -static void* (*ppcalloc)(size_t, size_t) = calloc; void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*), - void* (*xxcalloc)(size_t, size_t)) + void (*xxfree)(void*)) { if (xxmalloc) ppmalloc = xxmalloc; if (xxfree) ppfree = xxfree; - if (xxcalloc) ppcalloc = xxcalloc; } #define MALLOC(a) ppmalloc(a) #define FREE(a) ppfree(a) -#define CALLOC(a,b) ppcalloc(a,b) + +static void* CALLOC(size_t nmemb, size_t sz) +{ + int nb = sz * nmemb; + void* p = MALLOC(nb); + if (p) { + memset(p, 0, nb); + } + return p; +} + static char* STRDUP(const char* s) { @@ -382,22 +389,22 @@ static int e_keyexists(context_t* ctx, int lineno) static void* expand(void* p, int sz, int newsz) { - void* s = malloc(newsz); + void* s = MALLOC(newsz); if (!s) return 0; memcpy(s, p, sz); - free(p); + FREE(p); return s; } static void** expand_ptrarr(void** p, int n) { - void** s = malloc((n+1) * sizeof(void*)); + void** s = MALLOC((n+1) * sizeof(void*)); if (!s) return 0; s[n] = 0; memcpy(s, p, n * sizeof(void*)); - free(p); + FREE(p); return s; } @@ -1047,8 +1054,8 @@ static int parse_keyval(context_t* ctx, toml_table_t* tab) token_t key = ctx->tok; if (eat_token(ctx, STRING, 1, FLINE)) return -1; - if (ctx->tok.tok == DOT) { - /* handle inline dotted key. + if (ctx->tok.tok == DOT) { + /* handle inline dotted key. e.g. physical.color = "orange" physical.shape = "round" diff --git a/toml.h b/toml.h index 9e0fe21..d541ec8 100644 --- a/toml.h +++ b/toml.h @@ -143,7 +143,6 @@ TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret); TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*), - void* (*xxcalloc)(size_t, size_t)); + void (*xxfree)(void*)); #endif /* TOML_H */ From 7a3f8afc15c1cf43feab2a5169086623ff967343 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 01:17:17 -0700 Subject: [PATCH 063/138] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c3ed79c..622a0b6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ TOML in c99; v1.0 compliant. +If you are looking for a C++ library, you might try this [wrapper](https://github.com/cktan/tomlcpp). + ## Usage Please see the `toml.h` file for details. What follows is a simple example that From 3c50f43516b3e4a228ed6478856a0d0b02034300 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 01:18:00 -0700 Subject: [PATCH 064/138] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 622a0b6..00060ed 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ TOML in c99; v1.0 compliant. -If you are looking for a C++ library, you might try this [wrapper](https://github.com/cktan/tomlcpp). +If you are looking for a C++ library, you might try this [wrapper: https://github.com/cktan/tomlcpp](https://github.com/cktan/tomlcpp). ## Usage From d17c005da8bf510b2ccd7a746310fba9c4d84911 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 01:18:30 -0700 Subject: [PATCH 065/138] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00060ed..30839c1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ TOML in c99; v1.0 compliant. -If you are looking for a C++ library, you might try this [wrapper: https://github.com/cktan/tomlcpp](https://github.com/cktan/tomlcpp). +If you are looking for a C++ library, you might try this wrapper: [https://github.com/cktan/tomlcpp](https://github.com/cktan/tomlcpp). ## Usage From 71a9fd9772a3a669b7987353467a24315f716ecf Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 17:52:57 -0800 Subject: [PATCH 066/138] Add enhanced access methods --- Makefile | 3 ++ README.md | 34 +++++++---------- toml.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ toml.h | 31 ++++++++++++++- 4 files changed, 157 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index fe6a54c..039d83a 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,9 @@ toml_json: toml_json.c $(LIB) toml_cat: toml_cat.c $(LIB) + +tomlcpp.o: tomlcpp.cpp + prefix ?= /usr/local install: all diff --git a/README.md b/README.md index c3ed79c..0d3ef8b 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,7 @@ The steps for getting values from our file is usually : 1. Parse the whole TOML file. 2. Get a single table from the file. 3. Find a value from the table. -4. Convert that value to the appropriate type, i.e., string, int, etc. -5. Then, free up that memory if needed. +4. Then, free up that memory if needed. Below is an example of parsing the values from the example table. @@ -59,42 +58,35 @@ if (0 == (server = toml_table_in(conf, "server"))) { ``` 3. Find a value from the table. -4. Convert that value to the appropriate type (I.E. string, int). ```c -toml_raw_t raw; -char* host; -int64_t port; - /* Extract 'host' config value. */ -if (0 == (raw = toml_raw_in(server, "host"))) { +toml_access_t host = toml_string_in(server, "host"); +if (!host.ok) { + toml_free(conf); return handle_error(); } -/* Convert the raw value into a string. */ -if (toml_rtos(raw, &host)) { +toml_access_t port = toml_int_in(server, "port"); +if (!port.ok) { + toml_free(conf); + free(host.u.s); return handle_error(); } -/* Extract 'port' config value. */ -if (0 == (raw = toml_raw_in(server, "port"))) { - return handle_error(); -} +printf("host %s\n", host.u.s); +printf("port %d\n", port.u.i); -/* Convert the raw value into an int. */ -if (toml_rtoi(raw, &port)) { - return handle_error(); -} ``` -5. Then, free up that memory if needed. +4. Then, free up that memory if needed. ```c /* Use `toml_free` on the table returned from `toml_parse[_file]`. */ toml_free(conf); -/* Free any values returned from `toml_rto*`. */ -free(host); +/* Free any string values returned from access functions. */ +free(host.u.s); ``` ## Building diff --git a/toml.c b/toml.c index 1db5a5b..0a5c569 100644 --- a/toml.c +++ b/toml.c @@ -2147,3 +2147,114 @@ int toml_rtos(toml_raw_t src, char** ret) return *ret ? 0 : -1; } + + +toml_access_t toml_string_at(const toml_array_t* arr, int idx) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_at(arr, idx); + if (raw) { + ret.ok = (0 == toml_rtos(raw, &ret.u.s)); + } + return ret; +} + +toml_access_t toml_bool_at(const toml_array_t* arr, int idx) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_at(arr, idx); + if (raw) { + ret.ok = (0 == toml_rtob(raw, &ret.u.b)); + } + return ret; +} + +toml_access_t toml_int_at(const toml_array_t* arr, int idx) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_at(arr, idx); + if (raw) { + ret.ok = (0 == toml_rtoi(raw, &ret.u.i)); + } + return ret; +} + +toml_access_t toml_double_at(const toml_array_t* arr, int idx) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_at(arr, idx); + if (raw) { + ret.ok = (0 == toml_rtod(raw, &ret.u.d)); + } + return ret; +} + +toml_access_t toml_timestamp_at(const toml_array_t* arr, int idx) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_at(arr, idx); + if (raw) { + ret.ok = (0 == toml_rtots(raw, &ret.u.ts)); + } + return ret; +} + +toml_access_t toml_string_in(const toml_table_t* arr, const char* key) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_in(arr, key); + if (raw) { + ret.ok = (0 == toml_rtos(raw, &ret.u.s)); + } + return ret; +} + +toml_access_t toml_bool_in(const toml_table_t* arr, const char* key) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_in(arr, key); + if (raw) { + ret.ok = (0 == toml_rtob(raw, &ret.u.b)); + } + return ret; +} + +toml_access_t toml_int_in(const toml_table_t* arr, const char* key) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_in(arr, key); + if (raw) { + ret.ok = (0 == toml_rtoi(raw, &ret.u.i)); + } + return ret; +} + +toml_access_t toml_double_in(const toml_table_t* arr, const char* key) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_in(arr, key); + if (raw) { + ret.ok = (0 == toml_rtod(raw, &ret.u.d)); + } + return ret; +} + +toml_access_t toml_timestamp_in(const toml_table_t* arr, const char* key) +{ + toml_access_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_in(arr, key); + if (raw) { + ret.ok = (0 == toml_rtots(raw, &ret.u.ts)); + } + return ret; +} diff --git a/toml.h b/toml.h index d541ec8..b433b54 100644 --- a/toml.h +++ b/toml.h @@ -36,8 +36,10 @@ #define TOML_EXTERN extern #endif +typedef struct toml_timestamp_t toml_timestamp_t; typedef struct toml_table_t toml_table_t; typedef struct toml_array_t toml_array_t; +typedef struct toml_access_t toml_access_t; /* A raw value, must be processed by toml_rto* before using. */ typedef const char* toml_raw_t; @@ -124,7 +126,6 @@ TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen); * fields may be NULL if they are not relevant. e.g. In a DATE * type, the hour, minute, second and z fields will be NULLs. */ -typedef struct toml_timestamp_t toml_timestamp_t; struct toml_timestamp_t { struct { /* internal. do not use. */ int year, month, day; @@ -139,10 +140,38 @@ struct toml_timestamp_t { /* Raw to Timestamp. Return 0 on success, -1 otherwise. */ TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret); +/* Enhanced access methods */ +struct toml_access_t { + int ok; + union { + char* s; /* string value. s must be freed after use */ + int b; /* bool value */ + int64_t i; /* int value */ + double d; /* double value */ + toml_timestamp_t ts; + } u; +}; +TOML_EXTERN toml_access_t toml_string_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_access_t toml_bool_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_access_t toml_int_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_access_t toml_double_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_access_t toml_timestamp_at(const toml_array_t* arr, int idx); + +TOML_EXTERN toml_access_t toml_string_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_access_t toml_bool_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_access_t toml_int_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_access_t toml_double_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_access_t toml_timestamp_in(const toml_table_t* arr, const char* key); + + /* misc */ TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t), void (*xxfree)(void*)); + + + + #endif /* TOML_H */ From 6e1f2e3db8bb8822ddc1ba105e3e2077533489cc Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 17:55:33 -0800 Subject: [PATCH 067/138] readme --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bcd39a5..1ecc3df 100644 --- a/README.md +++ b/README.md @@ -31,18 +31,16 @@ FILE* fp; toml_table_t* conf; char errbuf[200]; -/* Open the file. */ +/* Open the file and parse content */ if (0 == (fp = fopen("path/to/file.toml", "r"))) { return handle_error(); } - -/* Run the file through the parser. */ conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); +fclose(fp); if (0 == conf) { return handle_error(); } -fclose(fp); /* Alternatively, use `toml_parse` which takes a string rather than a file. */ conf = toml_parse("A null terminated string that is TOML\0", errbuf, sizeof(errbuf)); From a28aae757f0506480652f5cd61f6e634f78a83d0 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 18:05:37 -0800 Subject: [PATCH 068/138] readme --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 1ecc3df..eec5316 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,32 @@ toml_free(conf); free(host.u.s); ``` +### Accessing Table Content + +Tables are dictionaries where lookups are done using string keys. In +general, all access methods on tables are named `toml_*_in(...)`. + +Keys in tables can be iterrogated using a key index: + +```c +toml_table_t* tab = toml_parse_file(...); +for (int i = 0; ; i++) { + const char* key = toml_key_in(tab, i); + if (!key) break; + printf("key %d: %s\n", i, key); +} +``` + +Once you know a key and its content type, you can obtain its content in the table by one of these methods: +```c +toml_string_in(tab, key); +toml_bool_in(tab, key); +toml_int_in(tab, key); +toml_double_in(tab, key); +toml_timestamp_in(tab, key); +``` + + ## Building A normal *make* suffices. Alternately, you can also simply include the From 7a3e402cee854274499e962787c7ff1d565919a9 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 18:17:31 -0800 Subject: [PATCH 069/138] readme --- README.md | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eec5316..e92efa4 100644 --- a/README.md +++ b/README.md @@ -82,16 +82,19 @@ printf("port %d\n", port.u.i); 4. Then, free up that memory if needed. ```c -/* Use `toml_free` on the table returned from `toml_parse[_file]`. */ +/* Use `toml_free` on the table returned from `toml_parse[_file]`. + * NOTE: you only need to `toml_free` the root table returned by `toml_parse[_file]`; + * internal tables do not need to be freed. + */ toml_free(conf); /* Free any string values returned from access functions. */ free(host.u.s); ``` -### Accessing Table Content +#### Accessing Table Content -Tables are dictionaries where lookups are done using string keys. In +TOML tables are dictionaries where lookups are done using string keys. In general, all access methods on tables are named `toml_*_in(...)`. Keys in tables can be iterrogated using a key index: @@ -112,8 +115,45 @@ toml_bool_in(tab, key); toml_int_in(tab, key); toml_double_in(tab, key); toml_timestamp_in(tab, key); +toml_table_in(tab, key); +toml_array_in(tab, key); ``` +#### Accessing Array Content + +TOML arrays can be deref-ed using integer values. In general, all access methods on arrays are named `toml_*_at()`. + +To obtain the size of an array: +```c +int size = toml_array_nelem(arr); +``` + +To obtain the content of an array, use an valid index and call one of these functions: +```c +toml_string_at(arr, idx); +toml_bool_at(arr, idx); +toml_int_at(arr, idx); +toml_double_at(arr, idx); +toml_timestamp_at(arr, idx); +toml_table_at(arr, idx); +toml_array_at(arr, idx); +``` + +#### toml_access_t + +Some `toml_*_at` and `toml_*_in` functions return a toml_access_t +structure. The `ok` flag in the structure indicates if the function +call was successful. If so, you may proceed to read the value +corresponding to the type of the call. + +For example: +``` +toml_access_t host = toml_string_in(tab, "host"); +if (host.ok) { + printf("host: %s\n", host.u.s); + free(host.u.s); /* FREE applies to string type only */ +} +``` ## Building From 3941e0badea910fc301dcf7b697946075a73b348 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 18:31:50 -0800 Subject: [PATCH 070/138] add sample program --- .gitignore | 1 + Makefile | 4 +++- sample.toml | 3 +++ toml_sample.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 sample.toml create mode 100644 toml_sample.c diff --git a/.gitignore b/.gitignore index 50f144d..3017290 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ *.hex toml_cat toml_json +toml_sample # Debug files *.dSYM/ diff --git a/Makefile b/Makefile index 039d83a..99f053a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ HFILES = toml.h CFILES = toml.c OBJ = $(CFILES:.c=.o) -EXEC = toml_json toml_cat +EXEC = toml_json toml_cat toml_sample CFLAGS = -std=c99 -Wall -Wextra -fpic LIB = libtoml.a @@ -30,6 +30,8 @@ toml_json: toml_json.c $(LIB) toml_cat: toml_cat.c $(LIB) +toml_sample: toml_sample.c $(LIB) + tomlcpp.o: tomlcpp.cpp diff --git a/sample.toml b/sample.toml new file mode 100644 index 0000000..bf3e825 --- /dev/null +++ b/sample.toml @@ -0,0 +1,3 @@ +[server] + host = "example.com" + port = 80 diff --git a/toml_sample.c b/toml_sample.c new file mode 100644 index 0000000..1bd48c0 --- /dev/null +++ b/toml_sample.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include "toml.h" + +toml_table_t* load() +{ + FILE* fp; + char errbuf[200]; + fp = fopen("sample.toml", "r"); + if (!fp) { + fprintf(stderr, "ERROR: cannot open sample.toml - %s\n", strerror(errno)); + exit(1); + } + + toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); + fclose(fp); + + if (!conf) { + fprintf(stderr, "ERROR: cannot parse - %s\n", errbuf); + exit(1); + } + + return conf; +} + +int main() +{ + toml_table_t* conf = load(); + toml_table_t* server = toml_table_in(conf, "server"); + if (!server) { + fprintf(stderr, "ERROR: missing [server]\n"); + exit(1); + } + + toml_access_t host = toml_string_in(server, "host"); + if (!host.ok) { + fprintf(stderr, "ERROR: cannot read server.host.\n"); + exit(1); + } + + toml_access_t port = toml_int_in(server, "port"); + if (!port.ok) { + fprintf(stderr, "ERROR: cannot read server.port.\n"); + exit(1); + } + + printf("host: %s, port %d\n", host.u.s, (int)port.u.i); + free(host.u.s); + toml_free(conf); + return 0; +} From 6eb7ea27f24a2ad7850831b110f839448677000f Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 18:39:32 -0800 Subject: [PATCH 071/138] readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e92efa4..0ce2308 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,10 @@ if (host.ok) { A normal *make* suffices. Alternately, you can also simply include the `toml.c` and `toml.h` files in your project. +## Install + +Invoking `make install` will install the header file in /usr/local/include and library files in /usr/local/lib. Alternatively, specify `make install prefix=/a/file/path` to install into /a/file/path/include and /a/file/path/lib/. + ## Testing To test against the standard test set provided by BurntSushi/toml-test: From f01507cabe6bbd5625db5221019d62436eed1452 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 18:41:46 -0800 Subject: [PATCH 072/138] readme --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0ce2308..c8db2e5 100644 --- a/README.md +++ b/README.md @@ -155,14 +155,16 @@ if (host.ok) { } ``` -## Building +## Building and installing -A normal *make* suffices. Alternately, you can also simply include the +A normal *make* suffices. You can also simply include the `toml.c` and `toml.h` files in your project. -## Install +Invoking `make install` will install the header file in +/usr/local/include and library files in /usr/local/lib. -Invoking `make install` will install the header file in /usr/local/include and library files in /usr/local/lib. Alternatively, specify `make install prefix=/a/file/path` to install into /a/file/path/include and /a/file/path/lib/. +Alternatively, specify `make install prefix=/a/file/path` to install into +/a/file/path/include and /a/file/path/lib/. ## Testing From 5c60d1e15c7fca606042cfff2aa641dff1126bb1 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 18:55:16 -0800 Subject: [PATCH 073/138] cleanup --- toml.h | 134 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 66 insertions(+), 68 deletions(-) diff --git a/toml.h b/toml.h index b433b54..a256fb9 100644 --- a/toml.h +++ b/toml.h @@ -41,9 +41,6 @@ typedef struct toml_table_t toml_table_t; typedef struct toml_array_t toml_array_t; typedef struct toml_access_t toml_access_t; -/* A raw value, must be processed by toml_rto* before using. */ -typedef const char* toml_raw_t; - /* Parse a file. Return a table on success, or 0 otherwise. * Caller must toml_free(the-return-value) after use. */ @@ -59,68 +56,12 @@ TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */ char* errbuf, int errbufsz); -/* Free the table returned by toml_parse() or toml_parse_file(). */ +/* Free the table returned by toml_parse() or toml_parse_file(). Once + * this function is called, any handles accessed through this tab + * directly or indirectly are no longer valid. + */ TOML_EXTERN void toml_free(toml_table_t* tab); -/* Retrieve the key in table at keyidx. Return 0 if out of range. */ -TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx); - -/* Lookup table by key. Return the element or 0 if not found. */ -TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key); -TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab, - const char* key); -TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab, - const char* key); - -/* Return the array kind: 't'able, 'a'rray, 'v'alue */ -TOML_EXTERN char toml_array_kind(const toml_array_t* arr); - -/* For array kind 'v'alue, return the type of values - i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp - 0 if unknown -*/ -TOML_EXTERN char toml_array_type(const toml_array_t* arr); - - -/* Return the number of elements in the array */ -TOML_EXTERN int toml_array_nelem(const toml_array_t* arr); - -/* Return the key of an array */ -TOML_EXTERN const char* toml_array_key(const toml_array_t* arr); - -/* Return the number of key-values in a table */ -TOML_EXTERN int toml_table_nkval(const toml_table_t* tab); - -/* Return the number of arrays in a table */ -TOML_EXTERN int toml_table_narr(const toml_table_t* tab); - -/* Return the number of sub-tables in a table */ -TOML_EXTERN int toml_table_ntab(const toml_table_t* tab); - -/* Return the key of a table*/ -TOML_EXTERN const char* toml_table_key(const toml_table_t* tab); - -/* Deref array by index. Return the element at idx or 0 if out of range. */ -TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx); - -/* Raw to String. Caller must call free(ret) after use. - * Return 0 on success, -1 otherwise. - */ -TOML_EXTERN int toml_rtos(toml_raw_t s, char** ret); - -/* Raw to Boolean. Return 0 on success, -1 otherwise. */ -TOML_EXTERN int toml_rtob(toml_raw_t s, int* ret); - -/* Raw to Integer. Return 0 on success, -1 otherwise. */ -TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t* ret); - -/* Raw to Double. Return 0 on success, -1 otherwise. */ -TOML_EXTERN int toml_rtod(toml_raw_t s, double* ret); - -/* Same as toml_rtod, but return the sanitized double in string form as well */ -TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen); /* Timestamp types. The year, month, day, hour, minute, second, z * fields may be NULL if they are not relevant. e.g. In a DATE @@ -137,10 +78,10 @@ struct toml_timestamp_t { char* z; }; -/* Raw to Timestamp. Return 0 on success, -1 otherwise. */ -TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret); -/* Enhanced access methods */ +/*----------------------------------------------------------------- + * Enhanced access methods + */ struct toml_access_t { int ok; union { @@ -151,27 +92,84 @@ struct toml_access_t { toml_timestamp_t ts; } u; }; + +/* on arrays: */ +/* ... retrieve size of array. */ +TOML_EXTERN int toml_array_nelem(const toml_array_t* arr); +/* ... retrieve values using index. */ TOML_EXTERN toml_access_t toml_string_at(const toml_array_t* arr, int idx); TOML_EXTERN toml_access_t toml_bool_at(const toml_array_t* arr, int idx); TOML_EXTERN toml_access_t toml_int_at(const toml_array_t* arr, int idx); TOML_EXTERN toml_access_t toml_double_at(const toml_array_t* arr, int idx); TOML_EXTERN toml_access_t toml_timestamp_at(const toml_array_t* arr, int idx); +/* ... retrieve array or table using index. */ +TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx); +/* on tables: */ +/* ... retrieve the key in table at keyidx. Return 0 if out of range. */ +TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx); +/* ... retrieve values using key. */ TOML_EXTERN toml_access_t toml_string_in(const toml_table_t* arr, const char* key); TOML_EXTERN toml_access_t toml_bool_in(const toml_table_t* arr, const char* key); TOML_EXTERN toml_access_t toml_int_in(const toml_table_t* arr, const char* key); TOML_EXTERN toml_access_t toml_double_in(const toml_table_t* arr, const char* key); TOML_EXTERN toml_access_t toml_timestamp_in(const toml_table_t* arr, const char* key); +/* .. retrieve array or table using key. */ +TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab, + const char* key); +TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab, + const char* key); +/*----------------------------------------------------------------- + * lesser used + */ +/* Return the array kind: 't'able, 'a'rray, 'v'alue */ +TOML_EXTERN char toml_array_kind(const toml_array_t* arr); -/* misc */ +/* For array kind 'v'alue, return the type of values + i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp + 0 if unknown +*/ +TOML_EXTERN char toml_array_type(const toml_array_t* arr); + +/* Return the key of an array */ +TOML_EXTERN const char* toml_array_key(const toml_array_t* arr); + +/* Return the number of key-values in a table */ +TOML_EXTERN int toml_table_nkval(const toml_table_t* tab); + +/* Return the number of arrays in a table */ +TOML_EXTERN int toml_table_narr(const toml_table_t* tab); + +/* Return the number of sub-tables in a table */ +TOML_EXTERN int toml_table_ntab(const toml_table_t* tab); + +/* Return the key of a table*/ +TOML_EXTERN const char* toml_table_key(const toml_table_t* tab); + +/*-------------------------------------------------------------- + * misc + */ TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t), void (*xxfree)(void*)); - +/*-------------------------------------------------------------- + * deprecated + */ +/* A raw value, must be processed by toml_rto* before using. */ +typedef const char* toml_raw_t; +TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key); +TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t* arr, int idx); +TOML_EXTERN int toml_rtos(toml_raw_t s, char** ret); +TOML_EXTERN int toml_rtob(toml_raw_t s, int* ret); +TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t* ret); +TOML_EXTERN int toml_rtod(toml_raw_t s, double* ret); +TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen); +TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret); #endif /* TOML_H */ From 26fdad9205f2b13dfa7e1bf331887bd40db25b69 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 1 Nov 2020 18:56:36 -0800 Subject: [PATCH 074/138] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c8db2e5..34589ec 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ To obtain the size of an array: int size = toml_array_nelem(arr); ``` -To obtain the content of an array, use an valid index and call one of these functions: +To obtain the content of an array, use a valid index and call one of these functions: ```c toml_string_at(arr, idx); toml_bool_at(arr, idx); From 3fdd187b2ab9a433ed1b475e69c897f2df9130ec Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 2 Nov 2020 10:07:33 -0800 Subject: [PATCH 075/138] rename toml_access_t -> toml_datum_t --- toml.c | 40 ++++++++++++++++++++-------------------- toml.h | 24 ++++++++++++------------ toml_sample.c | 4 ++-- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/toml.c b/toml.c index 0a5c569..c120788 100644 --- a/toml.c +++ b/toml.c @@ -2149,9 +2149,9 @@ int toml_rtos(toml_raw_t src, char** ret) } -toml_access_t toml_string_at(const toml_array_t* arr, int idx) +toml_datum_t toml_string_at(const toml_array_t* arr, int idx) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_at(arr, idx); if (raw) { @@ -2160,9 +2160,9 @@ toml_access_t toml_string_at(const toml_array_t* arr, int idx) return ret; } -toml_access_t toml_bool_at(const toml_array_t* arr, int idx) +toml_datum_t toml_bool_at(const toml_array_t* arr, int idx) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_at(arr, idx); if (raw) { @@ -2171,9 +2171,9 @@ toml_access_t toml_bool_at(const toml_array_t* arr, int idx) return ret; } -toml_access_t toml_int_at(const toml_array_t* arr, int idx) +toml_datum_t toml_int_at(const toml_array_t* arr, int idx) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_at(arr, idx); if (raw) { @@ -2182,9 +2182,9 @@ toml_access_t toml_int_at(const toml_array_t* arr, int idx) return ret; } -toml_access_t toml_double_at(const toml_array_t* arr, int idx) +toml_datum_t toml_double_at(const toml_array_t* arr, int idx) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_at(arr, idx); if (raw) { @@ -2193,9 +2193,9 @@ toml_access_t toml_double_at(const toml_array_t* arr, int idx) return ret; } -toml_access_t toml_timestamp_at(const toml_array_t* arr, int idx) +toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_at(arr, idx); if (raw) { @@ -2204,9 +2204,9 @@ toml_access_t toml_timestamp_at(const toml_array_t* arr, int idx) return ret; } -toml_access_t toml_string_in(const toml_table_t* arr, const char* key) +toml_datum_t toml_string_in(const toml_table_t* arr, const char* key) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_in(arr, key); if (raw) { @@ -2215,9 +2215,9 @@ toml_access_t toml_string_in(const toml_table_t* arr, const char* key) return ret; } -toml_access_t toml_bool_in(const toml_table_t* arr, const char* key) +toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_in(arr, key); if (raw) { @@ -2226,9 +2226,9 @@ toml_access_t toml_bool_in(const toml_table_t* arr, const char* key) return ret; } -toml_access_t toml_int_in(const toml_table_t* arr, const char* key) +toml_datum_t toml_int_in(const toml_table_t* arr, const char* key) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_in(arr, key); if (raw) { @@ -2237,9 +2237,9 @@ toml_access_t toml_int_in(const toml_table_t* arr, const char* key) return ret; } -toml_access_t toml_double_in(const toml_table_t* arr, const char* key) +toml_datum_t toml_double_in(const toml_table_t* arr, const char* key) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_in(arr, key); if (raw) { @@ -2248,9 +2248,9 @@ toml_access_t toml_double_in(const toml_table_t* arr, const char* key) return ret; } -toml_access_t toml_timestamp_in(const toml_table_t* arr, const char* key) +toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key) { - toml_access_t ret; + toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_in(arr, key); if (raw) { diff --git a/toml.h b/toml.h index a256fb9..d81471b 100644 --- a/toml.h +++ b/toml.h @@ -39,7 +39,7 @@ typedef struct toml_timestamp_t toml_timestamp_t; typedef struct toml_table_t toml_table_t; typedef struct toml_array_t toml_array_t; -typedef struct toml_access_t toml_access_t; +typedef struct toml_datum_t toml_datum_t; /* Parse a file. Return a table on success, or 0 otherwise. * Caller must toml_free(the-return-value) after use. @@ -82,7 +82,7 @@ struct toml_timestamp_t { /*----------------------------------------------------------------- * Enhanced access methods */ -struct toml_access_t { +struct toml_datum_t { int ok; union { char* s; /* string value. s must be freed after use */ @@ -97,11 +97,11 @@ struct toml_access_t { /* ... retrieve size of array. */ TOML_EXTERN int toml_array_nelem(const toml_array_t* arr); /* ... retrieve values using index. */ -TOML_EXTERN toml_access_t toml_string_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_access_t toml_bool_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_access_t toml_int_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_access_t toml_double_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_access_t toml_timestamp_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx); /* ... retrieve array or table using index. */ TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx); TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx); @@ -110,11 +110,11 @@ TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx); /* ... retrieve the key in table at keyidx. Return 0 if out of range. */ TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx); /* ... retrieve values using key. */ -TOML_EXTERN toml_access_t toml_string_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_access_t toml_bool_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_access_t toml_int_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_access_t toml_double_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_access_t toml_timestamp_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key); /* .. retrieve array or table using key. */ TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab, const char* key); diff --git a/toml_sample.c b/toml_sample.c index 1bd48c0..c20048b 100644 --- a/toml_sample.c +++ b/toml_sample.c @@ -34,13 +34,13 @@ int main() exit(1); } - toml_access_t host = toml_string_in(server, "host"); + toml_datum_t host = toml_string_in(server, "host"); if (!host.ok) { fprintf(stderr, "ERROR: cannot read server.host.\n"); exit(1); } - toml_access_t port = toml_int_in(server, "port"); + toml_datum_t port = toml_int_in(server, "port"); if (!port.ok) { fprintf(stderr, "ERROR: cannot read server.port.\n"); exit(1); From 893f24e2066c64c55843f93e7085cdef82e819c0 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 2 Nov 2020 10:08:47 -0800 Subject: [PATCH 076/138] rename toml_access_t -> toml_datum_t --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 34589ec..9e6c93b 100644 --- a/README.md +++ b/README.md @@ -61,13 +61,13 @@ if (0 == (server = toml_table_in(conf, "server"))) { ```c /* Extract 'host' config value. */ -toml_access_t host = toml_string_in(server, "host"); +toml_datum_t host = toml_string_in(server, "host"); if (!host.ok) { toml_free(conf); return handle_error(); } -toml_access_t port = toml_int_in(server, "port"); +toml_datum_t port = toml_int_in(server, "port"); if (!port.ok) { toml_free(conf); free(host.u.s); @@ -139,16 +139,16 @@ toml_table_at(arr, idx); toml_array_at(arr, idx); ``` -#### toml_access_t +#### toml_datum_t -Some `toml_*_at` and `toml_*_in` functions return a toml_access_t +Some `toml_*_at` and `toml_*_in` functions return a toml_datum_t structure. The `ok` flag in the structure indicates if the function call was successful. If so, you may proceed to read the value corresponding to the type of the call. For example: ``` -toml_access_t host = toml_string_in(tab, "host"); +toml_datum_t host = toml_string_in(tab, "host"); if (host.ok) { printf("host: %s\n", host.u.s); free(host.u.s); /* FREE applies to string type only */ From 6c72be57df8534a1d858f6420deb0ba7b7ea8c5b Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 9 Nov 2020 13:45:25 -0800 Subject: [PATCH 077/138] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9e6c93b..ac725a3 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ free(host.u.s); TOML tables are dictionaries where lookups are done using string keys. In general, all access methods on tables are named `toml_*_in(...)`. -Keys in tables can be iterrogated using a key index: +Keys in tables can be interrogated using an integer index: ```c toml_table_t* tab = toml_parse_file(...); @@ -108,7 +108,7 @@ for (int i = 0; ; i++) { } ``` -Once you know a key and its content type, you can obtain its content in the table by one of these methods: +Once you know a key and its content type, retrievals can be done with one of these methods: ```c toml_string_in(tab, key); toml_bool_in(tab, key); @@ -144,7 +144,7 @@ toml_array_at(arr, idx); Some `toml_*_at` and `toml_*_in` functions return a toml_datum_t structure. The `ok` flag in the structure indicates if the function call was successful. If so, you may proceed to read the value -corresponding to the type of the call. +corresponding to the type of the content. For example: ``` From 94136b9f04b2a90b33664f12bfd806c45b07af6a Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 9 Nov 2020 14:00:27 -0800 Subject: [PATCH 078/138] slight change in returning timestamp. now returns a malloc-ed ptr --- toml.c | 18 ++++++++++++++++-- toml.h | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/toml.c b/toml.c index c120788..98f765b 100644 --- a/toml.c +++ b/toml.c @@ -2195,11 +2195,18 @@ toml_datum_t toml_double_at(const toml_array_t* arr, int idx) toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx) { + toml_timestamp_t ts; toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_at(arr, idx); if (raw) { - ret.ok = (0 == toml_rtots(raw, &ret.u.ts)); + ret.ok = (0 == toml_rtots(raw, &ts)); + if (ret.ok) { + ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); + if (ret.ok) { + *ret.u.ts = ts; + } + } } return ret; } @@ -2250,11 +2257,18 @@ toml_datum_t toml_double_in(const toml_table_t* arr, const char* key) toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key) { + toml_timestamp_t ts; toml_datum_t ret; memset(&ret, 0, sizeof(ret)); toml_raw_t raw = toml_raw_in(arr, key); if (raw) { - ret.ok = (0 == toml_rtots(raw, &ret.u.ts)); + ret.ok = (0 == toml_rtots(raw, &ts)); + if (ret.ok) { + ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); + if (ret.ok) { + *ret.u.ts = ts; + } + } } return ret; } diff --git a/toml.h b/toml.h index d81471b..19f6f64 100644 --- a/toml.h +++ b/toml.h @@ -85,11 +85,11 @@ struct toml_timestamp_t { struct toml_datum_t { int ok; union { + toml_timestamp_t* ts; /* ts must be freed after use */ char* s; /* string value. s must be freed after use */ int b; /* bool value */ int64_t i; /* int value */ double d; /* double value */ - toml_timestamp_t ts; } u; }; From 577e48e03fdc1b8994799ae44a13ea66a4f20e30 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 9 Nov 2020 22:39:39 -0800 Subject: [PATCH 079/138] minor --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index 99f053a..295ae02 100644 --- a/Makefile +++ b/Makefile @@ -33,8 +33,6 @@ toml_cat: toml_cat.c $(LIB) toml_sample: toml_sample.c $(LIB) -tomlcpp.o: tomlcpp.cpp - prefix ?= /usr/local install: all From 5fb977508a79f7edc72a2e1735777d2a51414ea0 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Fri, 13 Nov 2020 13:14:16 -0800 Subject: [PATCH 080/138] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac725a3..fff2f1d 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ For example: toml_datum_t host = toml_string_in(tab, "host"); if (host.ok) { printf("host: %s\n", host.u.s); - free(host.u.s); /* FREE applies to string type only */ + free(host.u.s); /* FREE applies to string and timestamp types only */ } ``` From 579e72c3774055713daa53367fb012ad5987c159 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 24 Nov 2020 04:47:23 -0800 Subject: [PATCH 081/138] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index fff2f1d..e6abbf6 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,9 @@ if (host.ok) { } ``` +*IMPORTANT:* If the accessed value is a string or a timestamp, you must call +`free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. + ## Building and installing A normal *make* suffices. You can also simply include the From e9ea925e0536159d835594b5ecc8ae50b08db054 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 24 Nov 2020 04:48:46 -0800 Subject: [PATCH 082/138] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e6abbf6..36fe334 100644 --- a/README.md +++ b/README.md @@ -155,8 +155,8 @@ if (host.ok) { } ``` -*IMPORTANT:* If the accessed value is a string or a timestamp, you must call -`free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. +__IMPORTANT: if the accessed value is a string or a timestamp, you must call +`free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. __ ## Building and installing From 32636ccd01a4a3005058c33a05ea028a76255453 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 24 Nov 2020 04:49:46 -0800 Subject: [PATCH 083/138] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 36fe334..a34917d 100644 --- a/README.md +++ b/README.md @@ -155,8 +155,7 @@ if (host.ok) { } ``` -__IMPORTANT: if the accessed value is a string or a timestamp, you must call -`free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. __ +***IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. *** ## Building and installing From ba73b18f50ebde2b086364b838d63c5cade885f6 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 24 Nov 2020 04:50:13 -0800 Subject: [PATCH 084/138] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a34917d..98bbdf3 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ if (host.ok) { } ``` -***IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. *** +*IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. * ## Building and installing From 0a280911def1de9cb18ceaa7c654e7924970c3f3 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 24 Nov 2020 04:52:20 -0800 Subject: [PATCH 085/138] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 98bbdf3..45ccd59 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ if (host.ok) { } ``` -*IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. * +**IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. ** ## Building and installing From f7c39273fe6bcee1bd41b1562385e3dd005bc1dc Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 24 Nov 2020 04:54:40 -0800 Subject: [PATCH 086/138] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45ccd59..675ddee 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ if (host.ok) { } ``` -**IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. ** +** IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. ** ## Building and installing From 51e9daabd28889d6cf2095ac1d38ac77a7552fe6 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 1 Dec 2020 15:04:13 -0800 Subject: [PATCH 087/138] Update README.md --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 675ddee..dff30d6 100644 --- a/README.md +++ b/README.md @@ -97,18 +97,8 @@ free(host.u.s); TOML tables are dictionaries where lookups are done using string keys. In general, all access methods on tables are named `toml_*_in(...)`. -Keys in tables can be interrogated using an integer index: - -```c -toml_table_t* tab = toml_parse_file(...); -for (int i = 0; ; i++) { - const char* key = toml_key_in(tab, i); - if (!key) break; - printf("key %d: %s\n", i, key); -} -``` - -Once you know a key and its content type, retrievals can be done with one of these methods: +In the normal case, you know the key and its content type, and retrievals can be done +using one of these functions: ```c toml_string_in(tab, key); toml_bool_in(tab, key); @@ -119,9 +109,19 @@ toml_table_in(tab, key); toml_array_in(tab, key); ``` +You can also interrogate the keys in a table using an integer index: +```c +toml_table_t* tab = toml_parse_file(...); +for (int i = 0; ; i++) { + const char* key = toml_key_in(tab, i); + if (!key) break; + printf("key %d: %s\n", i, key); +} +``` + #### Accessing Array Content -TOML arrays can be deref-ed using integer values. In general, all access methods on arrays are named `toml_*_at()`. +TOML arrays can be deref-ed using integer indices. In general, all access methods on arrays are named `toml_*_at()`. To obtain the size of an array: ```c From 72eda69b5a308a77b9921c55e23c10de47a8503b Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 2 Dec 2020 13:22:46 -0800 Subject: [PATCH 088/138] cleanup --- toml.c | 65 +++++++++++++++++----------------------------------------- 1 file changed, 19 insertions(+), 46 deletions(-) diff --git a/toml.c b/toml.c index 98f765b..bb899d5 100644 --- a/toml.c +++ b/toml.c @@ -2153,10 +2153,7 @@ toml_datum_t toml_string_at(const toml_array_t* arr, int idx) { toml_datum_t ret; memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_at(arr, idx); - if (raw) { - ret.ok = (0 == toml_rtos(raw, &ret.u.s)); - } + ret.ok = (0 == toml_rtos(toml_raw_at(arr, idx), &ret.u.s)); return ret; } @@ -2164,10 +2161,7 @@ toml_datum_t toml_bool_at(const toml_array_t* arr, int idx) { toml_datum_t ret; memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_at(arr, idx); - if (raw) { - ret.ok = (0 == toml_rtob(raw, &ret.u.b)); - } + ret.ok = (0 == toml_rtob(toml_raw_at(arr, idx), &ret.u.b)); return ret; } @@ -2175,10 +2169,7 @@ toml_datum_t toml_int_at(const toml_array_t* arr, int idx) { toml_datum_t ret; memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_at(arr, idx); - if (raw) { - ret.ok = (0 == toml_rtoi(raw, &ret.u.i)); - } + ret.ok = (0 == toml_rtoi(toml_raw_at(arr, idx), &ret.u.i)); return ret; } @@ -2186,30 +2177,24 @@ toml_datum_t toml_double_at(const toml_array_t* arr, int idx) { toml_datum_t ret; memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_at(arr, idx); - if (raw) { - ret.ok = (0 == toml_rtod(raw, &ret.u.d)); - } + ret.ok = (0 == toml_rtod(toml_raw_at(arr, idx), &ret.u.d)); return ret; -} +} toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx) { toml_timestamp_t ts; toml_datum_t ret; memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_at(arr, idx); - if (raw) { - ret.ok = (0 == toml_rtots(raw, &ts)); + ret.ok = (0 == toml_rtots(toml_raw_at(arr, idx), &ts)); + if (ret.ok) { + ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); if (ret.ok) { - ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); - if (ret.ok) { - *ret.u.ts = ts; - } + *ret.u.ts = ts; } } return ret; -} +} toml_datum_t toml_string_in(const toml_table_t* arr, const char* key) { @@ -2226,10 +2211,7 @@ toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key) { toml_datum_t ret; memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_in(arr, key); - if (raw) { - ret.ok = (0 == toml_rtob(raw, &ret.u.b)); - } + ret.ok = (0 == toml_rtob(toml_raw_in(arr, key), &ret.u.b)); return ret; } @@ -2237,37 +2219,28 @@ toml_datum_t toml_int_in(const toml_table_t* arr, const char* key) { toml_datum_t ret; memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_in(arr, key); - if (raw) { - ret.ok = (0 == toml_rtoi(raw, &ret.u.i)); - } + ret.ok = (0 == toml_rtoi(toml_raw_in(arr, key), &ret.u.i)); return ret; -} +} toml_datum_t toml_double_in(const toml_table_t* arr, const char* key) { toml_datum_t ret; memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_in(arr, key); - if (raw) { - ret.ok = (0 == toml_rtod(raw, &ret.u.d)); - } + ret.ok = (0 == toml_rtod(toml_raw_in(arr, key), &ret.u.d)); return ret; -} +} toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key) { toml_timestamp_t ts; toml_datum_t ret; memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_in(arr, key); - if (raw) { - ret.ok = (0 == toml_rtots(raw, &ts)); + ret.ok = (0 == toml_rtots(toml_raw_in(arr, key), &ts)); + if (ret.ok) { + ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); if (ret.ok) { - ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); - if (ret.ok) { - *ret.u.ts = ts; - } + *ret.u.ts = ts; } } return ret; From f7fde945e69256c9e6e773e9d03077ace18e0874 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 3 Dec 2020 23:16:55 -0800 Subject: [PATCH 089/138] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index dff30d6..d07d750 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,9 @@ parses this config file: The steps for getting values from our file is usually : 1. Parse the whole TOML file. -2. Get a single table from the file. +2. Traverse and locate a table in TOML. 3. Find a value from the table. -4. Then, free up that memory if needed. +4. Free up allocated memory. Below is an example of parsing the values from the example table. @@ -46,7 +46,7 @@ if (0 == conf) { conf = toml_parse("A null terminated string that is TOML\0", errbuf, sizeof(errbuf)); ``` -2. Get a single table from the file. +2. Traverse and locate a table in toml. ```c toml_table_t* server; @@ -79,7 +79,7 @@ printf("port %d\n", port.u.i); ``` -4. Then, free up that memory if needed. +4. Free up allocated memory. ```c /* Use `toml_free` on the table returned from `toml_parse[_file]`. From 13b8fde20470240b1978537ad1519947729b5e38 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Fri, 4 Dec 2020 14:30:15 -0800 Subject: [PATCH 090/138] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d07d750..99244ef 100644 --- a/README.md +++ b/README.md @@ -162,11 +162,11 @@ if (host.ok) { A normal *make* suffices. You can also simply include the `toml.c` and `toml.h` files in your project. -Invoking `make install` will install the header file in -/usr/local/include and library files in /usr/local/lib. +Invoking `make install` will install the header and library files into +/usr/local/{include,lib}. Alternatively, specify `make install prefix=/a/file/path` to install into -/a/file/path/include and /a/file/path/lib/. +/a/file/path/{include,lib}. ## Testing From ae9514e87bc95bda670794a16c0bb3472bb35e04 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 5 Dec 2020 14:19:53 -0800 Subject: [PATCH 091/138] revised example --- README.md | 118 ++++++++++++++++++++++++++------------------------ sample.toml | 2 +- toml_sample.c | 61 +++++++++++++++----------- 3 files changed, 97 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index dff30d6..aea37f8 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,13 @@ TOML in c99; v1.0 compliant. If you are looking for a C++ library, you might try this wrapper: [https://github.com/cktan/tomlcpp](https://github.com/cktan/tomlcpp). +* Compatible with [TOML v1.0.0-rc.3](https://toml.io/en/v1.0.0-rc.3). +* Tested with multiple test suites, including +[BurntSushi/toml-test](https://github.com/BurntSushi/toml-test) and +[iarna/toml-spec-tests](https://github.com/iarna/toml-spec-tests). +* Provides very simple and intuitive interface. + + ## Usage Please see the `toml.h` file for details. What follows is a simple example that @@ -12,84 +19,81 @@ parses this config file: ```toml [server] host = "www.example.com" - port = 80 + port = [ 8080, 8181, 8282 ] ``` The steps for getting values from our file is usually : -1. Parse the whole TOML file. -2. Get a single table from the file. -3. Find a value from the table. +1. Parse the TOML file. +2. Traverse to a table. +3. Extract values from the table. 4. Then, free up that memory if needed. Below is an example of parsing the values from the example table. -1. Parse the whole TOML file. - ```c -FILE* fp; -toml_table_t* conf; -char errbuf[200]; +#include +#include +#include +#include +#include "toml.h" -/* Open the file and parse content */ -if (0 == (fp = fopen("path/to/file.toml", "r"))) { - return handle_error(); -} -conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); -fclose(fp); -if (0 == conf) { - return handle_error(); +static void fatal(const char* msg, const char* msg1) +{ + fprintf(stderr, "ERROR: %s%s\n", msg, msg1?msg1:""); + exit(1); } -/* Alternatively, use `toml_parse` which takes a string rather than a file. */ -conf = toml_parse("A null terminated string that is TOML\0", errbuf, sizeof(errbuf)); -``` +int main() +{ + FILE* fp; + char errbuf[200]; -2. Get a single table from the file. + // 1. Read and parse toml file + fp = fopen("sample.toml", "r"); + if (!fp) { + fatal("cannot open sample.toml - ", strerror(errno)); + } -```c -toml_table_t* server; + toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); + fclose(fp); -/* Locate the [server] table. */ -if (0 == (server = toml_table_in(conf, "server"))) { - return handle_error(); -} -``` + if (!conf) { + fatal("cannot parse - ", errbuf); + } -3. Find a value from the table. + // 2. Traverse to a table. + toml_table_t* server = toml_table_in(conf, "server"); + if (!server) { + fatal("missing [server]", ""); + } -```c -/* Extract 'host' config value. */ -toml_datum_t host = toml_string_in(server, "host"); -if (!host.ok) { - toml_free(conf); - return handle_error(); -} + // 3. Extract values + toml_datum_t host = toml_string_in(server, "host"); + if (!host.ok) { + fatal("cannot read server.host", ""); + } -toml_datum_t port = toml_int_in(server, "port"); -if (!port.ok) { - toml_free(conf); + toml_array_t* portarray = toml_array_in(server, "port"); + if (!portarray) { + fatal("cannot read server.port", ""); + } + + printf("host: %s\n", host.u.s); + printf("port: "); + for (int i = 0; ; i++) { + toml_datum_t port = toml_int_at(portarray, i); + if (!port.ok) break; + printf("%d ", (int)port.u.i); + } + printf("\n"); + + // 4. Free memory free(host.u.s); - return handle_error(); + toml_free(conf); + return 0; } - -printf("host %s\n", host.u.s); -printf("port %d\n", port.u.i); - -``` - -4. Then, free up that memory if needed. - -```c -/* Use `toml_free` on the table returned from `toml_parse[_file]`. - * NOTE: you only need to `toml_free` the root table returned by `toml_parse[_file]`; - * internal tables do not need to be freed. - */ -toml_free(conf); - -/* Free any string values returned from access functions. */ -free(host.u.s); ``` #### Accessing Table Content diff --git a/sample.toml b/sample.toml index bf3e825..e613d17 100644 --- a/sample.toml +++ b/sample.toml @@ -1,3 +1,3 @@ [server] host = "example.com" - port = 80 + port = [ 8080, 8181, 8282 ] diff --git a/toml_sample.c b/toml_sample.c index c20048b..f9b635b 100644 --- a/toml_sample.c +++ b/toml_sample.c @@ -4,49 +4,58 @@ #include #include "toml.h" -toml_table_t* load() +static void fatal(const char* msg, const char* msg1) +{ + fprintf(stderr, "ERROR: %s%s\n", msg, msg1?msg1:""); + exit(1); +} + + +int main() { FILE* fp; char errbuf[200]; + + // 1. Read and parse toml file fp = fopen("sample.toml", "r"); if (!fp) { - fprintf(stderr, "ERROR: cannot open sample.toml - %s\n", strerror(errno)); - exit(1); + fatal("cannot open sample.toml - ", strerror(errno)); } toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); fclose(fp); if (!conf) { - fprintf(stderr, "ERROR: cannot parse - %s\n", errbuf); - exit(1); + fatal("cannot parse - ", errbuf); } - - return conf; -} -int main() -{ - toml_table_t* conf = load(); + // 2. Traverse to a table. toml_table_t* server = toml_table_in(conf, "server"); if (!server) { - fprintf(stderr, "ERROR: missing [server]\n"); - exit(1); - } - - toml_datum_t host = toml_string_in(server, "host"); - if (!host.ok) { - fprintf(stderr, "ERROR: cannot read server.host.\n"); - exit(1); - } - - toml_datum_t port = toml_int_in(server, "port"); - if (!port.ok) { - fprintf(stderr, "ERROR: cannot read server.port.\n"); - exit(1); + fatal("missing [server]", ""); } - printf("host: %s, port %d\n", host.u.s, (int)port.u.i); + // 3. Extract values + toml_datum_t host = toml_string_in(server, "host"); + if (!host.ok) { + fatal("cannot read server.host", ""); + } + + toml_array_t* portarray = toml_array_in(server, "port"); + if (!portarray) { + fatal("cannot read server.port", ""); + } + + printf("host: %s\n", host.u.s); + printf("port: "); + for (int i = 0; ; i++) { + toml_datum_t port = toml_int_at(portarray, i); + if (!port.ok) break; + printf("%d ", (int)port.u.i); + } + printf("\n"); + + // 4. Free memory free(host.u.s); toml_free(conf); return 0; From 5039045945827ec32cd7d61e08dfbd1f61986ca2 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 5 Dec 2020 14:25:39 -0800 Subject: [PATCH 092/138] minor --- test1/run.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test1/run.sh b/test1/run.sh index 2bb548b..86c77cb 100644 --- a/test1/run.sh +++ b/test1/run.sh @@ -1,4 +1,5 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export GOPATH=$DIR/goworkspace # if it isn't already set + # $GOPATH/bin/toml-test $GOPATH/bin/toml-test-decoder # e.g., run tests on my parser $GOPATH/bin/toml-test ../toml_json From 63feb40e3b21de35a7791794baf5a5ac8f458c91 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 5 Dec 2020 15:45:30 -0800 Subject: [PATCH 093/138] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b954ea4..3efa2d6 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ int main() #### Accessing Table Content TOML tables are dictionaries where lookups are done using string keys. In -general, all access methods on tables are named `toml_*_in(...)`. +general, all access functions on tables are named `toml_*_in(...)`. In the normal case, you know the key and its content type, and retrievals can be done using one of these functions: From 94ded5f2c1625cb09496d83d2cf2854e70dee38b Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 22 Dec 2020 23:09:36 -0800 Subject: [PATCH 094/138] readme --- README.md | 83 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 3efa2d6..4b9e254 100644 --- a/README.md +++ b/README.md @@ -38,63 +38,62 @@ Below is an example of parsing the values from the example table. #include #include "toml.h" -static void fatal(const char* msg, const char* msg1) +static void error(const char* msg, const char* msg1) { - fprintf(stderr, "ERROR: %s%s\n", msg, msg1?msg1:""); - exit(1); + fprintf(stderr, "ERROR: %s%s\n", msg, msg1?msg1:""); + exit(1); } int main() { - FILE* fp; - char errbuf[200]; + FILE* fp; + char errbuf[200]; - // 1. Read and parse toml file - fp = fopen("sample.toml", "r"); - if (!fp) { - fatal("cannot open sample.toml - ", strerror(errno)); - } + // 1. Read and parse toml file + fp = fopen("sample.toml", "r"); + if (!fp) { + error("cannot open sample.toml - ", strerror(errno)); + } - toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); - fclose(fp); + toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); + fclose(fp); - if (!conf) { - fatal("cannot parse - ", errbuf); - } + if (!conf) { + error("cannot parse - ", errbuf); + } - // 2. Traverse to a table. - toml_table_t* server = toml_table_in(conf, "server"); - if (!server) { - fatal("missing [server]", ""); - } + // 2. Traverse to a table. + toml_table_t* server = toml_table_in(conf, "server"); + if (!server) { + error("missing [server]", ""); + } - // 3. Extract values - toml_datum_t host = toml_string_in(server, "host"); - if (!host.ok) { - fatal("cannot read server.host", ""); - } + // 3. Extract values + toml_datum_t host = toml_string_in(server, "host"); + if (!host.ok) { + error("cannot read server.host", ""); + } - toml_array_t* portarray = toml_array_in(server, "port"); - if (!portarray) { - fatal("cannot read server.port", ""); - } + toml_array_t* portarray = toml_array_in(server, "port"); + if (!portarray) { + error("cannot read server.port", ""); + } - printf("host: %s\n", host.u.s); - printf("port: "); - for (int i = 0; ; i++) { - toml_datum_t port = toml_int_at(portarray, i); - if (!port.ok) break; - printf("%d ", (int)port.u.i); - } - printf("\n"); + printf("host: %s\n", host.u.s); + printf("port: "); + for (int i = 0; ; i++) { + toml_datum_t port = toml_int_at(portarray, i); + if (!port.ok) break; + printf("%d ", (int)port.u.i); + } + printf("\n"); - // 4. Free memory - free(host.u.s); - toml_free(conf); - return 0; + // 4. Free memory + free(host.u.s); + toml_free(conf); + return 0; } - ``` #### Accessing Table Content From e97a56633e54297990158ab56a7e50a089cddf7d Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 9 Jan 2021 17:19:09 -0800 Subject: [PATCH 095/138] minor --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 295ae02..8554f35 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ HFILES = toml.h CFILES = toml.c -OBJ = $(CFILES:.c=.o) +OBJ = $(CFILES:.c=.o) EXEC = toml_json toml_cat toml_sample CFLAGS = -std=c99 -Wall -Wextra -fpic @@ -43,3 +43,6 @@ install: all clean: rm -f *.o $(EXEC) $(LIB) $(LIB_SHARED) + + +.PHONY: all clean install From c5d2e37db734fc58f515aaab87d2e037155f6434 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 27 Jan 2021 18:53:31 -0800 Subject: [PATCH 096/138] updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b9e254..6715b5b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ TOML in c99; v1.0 compliant. If you are looking for a C++ library, you might try this wrapper: [https://github.com/cktan/tomlcpp](https://github.com/cktan/tomlcpp). -* Compatible with [TOML v1.0.0-rc.3](https://toml.io/en/v1.0.0-rc.3). +* Compatible with [TOML v1.0.0](https://toml.io/en/v1.0.0). * Tested with multiple test suites, including [BurntSushi/toml-test](https://github.com/BurntSushi/toml-test) and [iarna/toml-spec-tests](https://github.com/iarna/toml-spec-tests). From 970ab84baea6d596d9293a5971daf55f20dfcd3a Mon Sep 17 00:00:00 2001 From: mweshahy Date: Tue, 16 Feb 2021 12:45:18 +0100 Subject: [PATCH 097/138] Add proper SONAME to TOML shared library This patch renames the shared library output to libtoml.so.$(LIB_VERSION) instead of libtoml.so. This matches the Yocto standards so that the library can be integrated into Yocto build. --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8554f35..0f1b5fa 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,9 @@ OBJ = $(CFILES:.c=.o) EXEC = toml_json toml_cat toml_sample CFLAGS = -std=c99 -Wall -Wextra -fpic +LIB_VERSION = 1.0 LIB = libtoml.a -LIB_SHARED = libtoml.so +LIB_SHARED = libtoml.so.$(LIB_VERSION) # to compile for debug: make DEBUG=1 # to compile for no debug: make @@ -23,7 +24,7 @@ all: $(LIB) $(LIB_SHARED) $(EXEC) libtoml.a: toml.o ar -rcs $@ $^ -libtoml.so: toml.o +libtoml.so.$(LIB_VERSION): toml.o $(CC) -shared -o $@ $^ toml_json: toml_json.c $(LIB) From fd82018f7939df1c6fd4c5a064d28221ddbec0d3 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Tue, 16 Feb 2021 17:10:51 -0800 Subject: [PATCH 098/138] fix #50: crash on input --- toml.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/toml.c b/toml.c index bb899d5..073974b 100644 --- a/toml.c +++ b/toml.c @@ -1063,6 +1063,8 @@ static int parse_keyval(context_t* ctx, toml_table_t* tab) toml_table_t* subtab = 0; { char* subtabstr = normalize_key(ctx, key); + if (!subtabstr) return -1; + subtab = toml_table_in(tab, subtabstr); xfree(subtabstr); } From 715fa54d451fbb3cd8ae2ac3464185696998886e Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 6 Mar 2021 23:54:24 -0800 Subject: [PATCH 099/138] fixed issue #51 --- stdex/.gitignore | 1 + stdex/RUN.sh | 15 ++ stdex/comment.toml | 3 + stdex/comment.toml.res | 4 + stdex/keys00.toml | 4 + stdex/keys00.toml.res | 6 + stdex/keys01.toml | 5 + stdex/keys01.toml.res | 7 + stdex/keys02.toml | 1 + stdex/keys02.toml.res | 1 + stdex/keys03.toml | 1 + stdex/keys03.toml.res | 3 + stdex/keys04.toml | 4 + stdex/keys04.toml.res | 10 + stdex/keys05.toml | 3 + stdex/keys05.toml.res | 7 + stdex/keys06.toml | 3 + stdex/keys06.toml.res | 1 + stdex/keys07.toml | 3 + stdex/keys07.toml.res | 1 + stdex/keys08.toml | 5 + stdex/keys08.toml.res | 8 + stdex/keys09.toml | 8 + stdex/keys09.toml.res | 1 + stdex/keys10.toml | 10 + stdex/keys10.toml.res | 12 + stdex/keys11.toml | 9 + stdex/keys11.toml.res | 12 + stdex/keys12.toml | 1 + stdex/keys12.toml.res | 5 + stdex/kvpair0.toml | 1 + stdex/kvpair0.toml.res | 3 + stdex/kvpair1.toml | 1 + stdex/kvpair1.toml.res | 1 + stdex/kvpair2.toml | 1 + stdex/kvpair2.toml.res | 1 + stdex/string0.toml | 1 + stdex/string0.toml.res | 3 + stdex/string1.toml | 9 + stdex/string1.toml.res | 5 + stdex/string3.toml | 15 ++ stdex/string3.toml.res | 5 + stdex/string4.toml | 7 + stdex/string4.toml.res | 6 + stdex/string5.toml | 5 + stdex/string5.toml.res | 6 + stdex/string6.toml | 7 + stdex/string6.toml.res | 4 + stdex/string7.toml | 4 + stdex/string7.toml.res | 4 + stdex/string8.toml | 3 + stdex/string8.toml.res | 1 + toml.c | 511 ++++++++++++++++++++++------------------- toml.h | 34 +-- toml_cat.c | 321 +++++++++++++++++--------- 55 files changed, 747 insertions(+), 366 deletions(-) create mode 100644 stdex/.gitignore create mode 100644 stdex/RUN.sh create mode 100644 stdex/comment.toml create mode 100644 stdex/comment.toml.res create mode 100644 stdex/keys00.toml create mode 100644 stdex/keys00.toml.res create mode 100644 stdex/keys01.toml create mode 100644 stdex/keys01.toml.res create mode 100644 stdex/keys02.toml create mode 100644 stdex/keys02.toml.res create mode 100644 stdex/keys03.toml create mode 100644 stdex/keys03.toml.res create mode 100644 stdex/keys04.toml create mode 100644 stdex/keys04.toml.res create mode 100644 stdex/keys05.toml create mode 100644 stdex/keys05.toml.res create mode 100644 stdex/keys06.toml create mode 100644 stdex/keys06.toml.res create mode 100644 stdex/keys07.toml create mode 100644 stdex/keys07.toml.res create mode 100644 stdex/keys08.toml create mode 100644 stdex/keys08.toml.res create mode 100644 stdex/keys09.toml create mode 100644 stdex/keys09.toml.res create mode 100644 stdex/keys10.toml create mode 100644 stdex/keys10.toml.res create mode 100644 stdex/keys11.toml create mode 100644 stdex/keys11.toml.res create mode 100644 stdex/keys12.toml create mode 100644 stdex/keys12.toml.res create mode 100644 stdex/kvpair0.toml create mode 100644 stdex/kvpair0.toml.res create mode 100644 stdex/kvpair1.toml create mode 100644 stdex/kvpair1.toml.res create mode 100644 stdex/kvpair2.toml create mode 100644 stdex/kvpair2.toml.res create mode 100644 stdex/string0.toml create mode 100644 stdex/string0.toml.res create mode 100644 stdex/string1.toml create mode 100644 stdex/string1.toml.res create mode 100644 stdex/string3.toml create mode 100644 stdex/string3.toml.res create mode 100644 stdex/string4.toml create mode 100644 stdex/string4.toml.res create mode 100644 stdex/string5.toml create mode 100644 stdex/string5.toml.res create mode 100644 stdex/string6.toml create mode 100644 stdex/string6.toml.res create mode 100644 stdex/string7.toml create mode 100644 stdex/string7.toml.res create mode 100644 stdex/string8.toml create mode 100644 stdex/string8.toml.res diff --git a/stdex/.gitignore b/stdex/.gitignore new file mode 100644 index 0000000..e87afd9 --- /dev/null +++ b/stdex/.gitignore @@ -0,0 +1 @@ +/*.out diff --git a/stdex/RUN.sh b/stdex/RUN.sh new file mode 100644 index 0000000..1391e7c --- /dev/null +++ b/stdex/RUN.sh @@ -0,0 +1,15 @@ +rm -f *.out +for i in *.toml; do + echo -n $i + ../toml_cat $i >& $i.out + if [ -f $i.res ]; then + if $(diff $i.out $i.res >& /dev/null); then + echo " [OK]" + else + echo " [FAILED]" + fi + else + echo " [??]" + fi + +done diff --git a/stdex/comment.toml b/stdex/comment.toml new file mode 100644 index 0000000..fae57c6 --- /dev/null +++ b/stdex/comment.toml @@ -0,0 +1,3 @@ +# This is a full-line comment +key = "value" # This is a comment at the end of a line +another = "# This is not a comment" diff --git a/stdex/comment.toml.res b/stdex/comment.toml.res new file mode 100644 index 0000000..ae1a16e --- /dev/null +++ b/stdex/comment.toml.res @@ -0,0 +1,4 @@ +{ + key = "value", + another = "# This is not a comment", +} diff --git a/stdex/keys00.toml b/stdex/keys00.toml new file mode 100644 index 0000000..657ff24 --- /dev/null +++ b/stdex/keys00.toml @@ -0,0 +1,4 @@ +key = "value" +bare_key = "value" +bare-key = "value" +1234 = "value" diff --git a/stdex/keys00.toml.res b/stdex/keys00.toml.res new file mode 100644 index 0000000..b28b39e --- /dev/null +++ b/stdex/keys00.toml.res @@ -0,0 +1,6 @@ +{ + key = "value", + bare_key = "value", + bare-key = "value", + 1234 = "value", +} diff --git a/stdex/keys01.toml b/stdex/keys01.toml new file mode 100644 index 0000000..cc2d1d0 --- /dev/null +++ b/stdex/keys01.toml @@ -0,0 +1,5 @@ +"127.0.0.1" = "value" +"character encoding" = "value" +"ʎǝʞ" = "value" +'key2' = "value" +'quoted "value"' = "value" diff --git a/stdex/keys01.toml.res b/stdex/keys01.toml.res new file mode 100644 index 0000000..5fc4091 --- /dev/null +++ b/stdex/keys01.toml.res @@ -0,0 +1,7 @@ +{ + 127.0.0.1 = "value", + character encoding = "value", + ʎǝʞ = "value", + key2 = "value", + quoted "value" = "value", +} diff --git a/stdex/keys02.toml b/stdex/keys02.toml new file mode 100644 index 0000000..cd9fa90 --- /dev/null +++ b/stdex/keys02.toml @@ -0,0 +1 @@ += "no key name" # INVALID diff --git a/stdex/keys02.toml.res b/stdex/keys02.toml.res new file mode 100644 index 0000000..13a97f7 --- /dev/null +++ b/stdex/keys02.toml.res @@ -0,0 +1 @@ +ERROR: line 1: syntax error diff --git a/stdex/keys03.toml b/stdex/keys03.toml new file mode 100644 index 0000000..5aea8ee --- /dev/null +++ b/stdex/keys03.toml @@ -0,0 +1 @@ +"" = "blank" # VALID but discouraged diff --git a/stdex/keys03.toml.res b/stdex/keys03.toml.res new file mode 100644 index 0000000..1478e36 --- /dev/null +++ b/stdex/keys03.toml.res @@ -0,0 +1,3 @@ +{ + = "blank", +} diff --git a/stdex/keys04.toml b/stdex/keys04.toml new file mode 100644 index 0000000..8f83571 --- /dev/null +++ b/stdex/keys04.toml @@ -0,0 +1,4 @@ +name = "Orange" +physical.color = "orange" +physical.shape = "round" +site."google.com" = true diff --git a/stdex/keys04.toml.res b/stdex/keys04.toml.res new file mode 100644 index 0000000..8bedb21 --- /dev/null +++ b/stdex/keys04.toml.res @@ -0,0 +1,10 @@ +{ + name = "Orange", + physical = { + color = "orange", + shape = "round", + }, + site = { + google.com = true, + }, +} diff --git a/stdex/keys05.toml b/stdex/keys05.toml new file mode 100644 index 0000000..75bf90b --- /dev/null +++ b/stdex/keys05.toml @@ -0,0 +1,3 @@ +fruit.name = "banana" # this is best practice +fruit. color = "yellow" # same as fruit.color +fruit . flavor = "banana" # same as fruit.flavor diff --git a/stdex/keys05.toml.res b/stdex/keys05.toml.res new file mode 100644 index 0000000..33db031 --- /dev/null +++ b/stdex/keys05.toml.res @@ -0,0 +1,7 @@ +{ + fruit = { + name = "banana", + color = "yellow", + flavor = "banana", + }, +} diff --git a/stdex/keys06.toml b/stdex/keys06.toml new file mode 100644 index 0000000..7847bd4 --- /dev/null +++ b/stdex/keys06.toml @@ -0,0 +1,3 @@ +# DO NOT DO THIS +name = "Tom" +name = "Pradyun" diff --git a/stdex/keys06.toml.res b/stdex/keys06.toml.res new file mode 100644 index 0000000..0a6a07c --- /dev/null +++ b/stdex/keys06.toml.res @@ -0,0 +1 @@ +ERROR: line 3: key exists diff --git a/stdex/keys07.toml b/stdex/keys07.toml new file mode 100644 index 0000000..acff1cc --- /dev/null +++ b/stdex/keys07.toml @@ -0,0 +1,3 @@ +# THIS WILL NOT WORK +spelling = "favorite" +"spelling" = "favourite" diff --git a/stdex/keys07.toml.res b/stdex/keys07.toml.res new file mode 100644 index 0000000..0a6a07c --- /dev/null +++ b/stdex/keys07.toml.res @@ -0,0 +1 @@ +ERROR: line 3: key exists diff --git a/stdex/keys08.toml b/stdex/keys08.toml new file mode 100644 index 0000000..b4d1b37 --- /dev/null +++ b/stdex/keys08.toml @@ -0,0 +1,5 @@ +# This makes the key "fruit" into a table. +fruit.apple.smooth = true + +# So then you can add to the table "fruit" like so: +fruit.orange = 2 diff --git a/stdex/keys08.toml.res b/stdex/keys08.toml.res new file mode 100644 index 0000000..df743ec --- /dev/null +++ b/stdex/keys08.toml.res @@ -0,0 +1,8 @@ +{ + fruit = { + orange = 2, + apple = { + smooth = true, + }, + }, +} diff --git a/stdex/keys09.toml b/stdex/keys09.toml new file mode 100644 index 0000000..a6c5ea6 --- /dev/null +++ b/stdex/keys09.toml @@ -0,0 +1,8 @@ +# THE FOLLOWING IS INVALID + +# This defines the value of fruit.apple to be an integer. +fruit.apple = 1 + +# But then this treats fruit.apple like it's a table. +# You can't turn an integer into a table. +fruit.apple.smooth = true diff --git a/stdex/keys09.toml.res b/stdex/keys09.toml.res new file mode 100644 index 0000000..9365cbc --- /dev/null +++ b/stdex/keys09.toml.res @@ -0,0 +1 @@ +ERROR: line 8: key exists diff --git a/stdex/keys10.toml b/stdex/keys10.toml new file mode 100644 index 0000000..dc94a8c --- /dev/null +++ b/stdex/keys10.toml @@ -0,0 +1,10 @@ +# VALID BUT DISCOURAGED + +apple.type = "fruit" +orange.type = "fruit" + +apple.skin = "thin" +orange.skin = "thick" + +apple.color = "red" +orange.color = "orange" diff --git a/stdex/keys10.toml.res b/stdex/keys10.toml.res new file mode 100644 index 0000000..fac0f25 --- /dev/null +++ b/stdex/keys10.toml.res @@ -0,0 +1,12 @@ +{ + apple = { + type = "fruit", + skin = "thin", + color = "red", + }, + orange = { + type = "fruit", + skin = "thick", + color = "orange", + }, +} diff --git a/stdex/keys11.toml b/stdex/keys11.toml new file mode 100644 index 0000000..705686c --- /dev/null +++ b/stdex/keys11.toml @@ -0,0 +1,9 @@ +# RECOMMENDED + +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/stdex/keys11.toml.res b/stdex/keys11.toml.res new file mode 100644 index 0000000..fac0f25 --- /dev/null +++ b/stdex/keys11.toml.res @@ -0,0 +1,12 @@ +{ + apple = { + type = "fruit", + skin = "thin", + color = "red", + }, + orange = { + type = "fruit", + skin = "thick", + color = "orange", + }, +} diff --git a/stdex/keys12.toml b/stdex/keys12.toml new file mode 100644 index 0000000..2efd659 --- /dev/null +++ b/stdex/keys12.toml @@ -0,0 +1 @@ +3.14159 = "pi" diff --git a/stdex/keys12.toml.res b/stdex/keys12.toml.res new file mode 100644 index 0000000..3f59e3a --- /dev/null +++ b/stdex/keys12.toml.res @@ -0,0 +1,5 @@ +{ + 3 = { + 14159 = "pi", + }, +} diff --git a/stdex/kvpair0.toml b/stdex/kvpair0.toml new file mode 100644 index 0000000..e5b34eb --- /dev/null +++ b/stdex/kvpair0.toml @@ -0,0 +1 @@ +key = "value" diff --git a/stdex/kvpair0.toml.res b/stdex/kvpair0.toml.res new file mode 100644 index 0000000..4b640b6 --- /dev/null +++ b/stdex/kvpair0.toml.res @@ -0,0 +1,3 @@ +{ + key = "value", +} diff --git a/stdex/kvpair1.toml b/stdex/kvpair1.toml new file mode 100644 index 0000000..56f085a --- /dev/null +++ b/stdex/kvpair1.toml @@ -0,0 +1 @@ +key = # INVALID diff --git a/stdex/kvpair1.toml.res b/stdex/kvpair1.toml.res new file mode 100644 index 0000000..13a97f7 --- /dev/null +++ b/stdex/kvpair1.toml.res @@ -0,0 +1 @@ +ERROR: line 1: syntax error diff --git a/stdex/kvpair2.toml b/stdex/kvpair2.toml new file mode 100644 index 0000000..e05c47c --- /dev/null +++ b/stdex/kvpair2.toml @@ -0,0 +1 @@ +first = "Tom" last = "Preston-Werner" # INVALID diff --git a/stdex/kvpair2.toml.res b/stdex/kvpair2.toml.res new file mode 100644 index 0000000..a307757 --- /dev/null +++ b/stdex/kvpair2.toml.res @@ -0,0 +1 @@ +ERROR: line 1: extra chars after value diff --git a/stdex/string0.toml b/stdex/string0.toml new file mode 100644 index 0000000..b611549 --- /dev/null +++ b/stdex/string0.toml @@ -0,0 +1 @@ +str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF." diff --git a/stdex/string0.toml.res b/stdex/string0.toml.res new file mode 100644 index 0000000..8b6e2e5 --- /dev/null +++ b/stdex/string0.toml.res @@ -0,0 +1,3 @@ +{ + str = "I'm a string. \"You can quote me\". Name\tJos\0xc3\0xa9\nLocation\tSF.", +} diff --git a/stdex/string1.toml b/stdex/string1.toml new file mode 100644 index 0000000..74c2f51 --- /dev/null +++ b/stdex/string1.toml @@ -0,0 +1,9 @@ +str1 = """ +Roses are red +Violets are blue""" + +# On a Unix system, the above multi-line string will most likely be the same as: +str2 = "Roses are red\nViolets are blue" + +# On a Windows system, it will most likely be equivalent to: +str3 = "Roses are red\r\nViolets are blue" diff --git a/stdex/string1.toml.res b/stdex/string1.toml.res new file mode 100644 index 0000000..364437d --- /dev/null +++ b/stdex/string1.toml.res @@ -0,0 +1,5 @@ +{ + str1 = "Roses are red\nViolets are blue", + str2 = "Roses are red\nViolets are blue", + str3 = "Roses are red\r\nViolets are blue", +} diff --git a/stdex/string3.toml b/stdex/string3.toml new file mode 100644 index 0000000..20b4aa7 --- /dev/null +++ b/stdex/string3.toml @@ -0,0 +1,15 @@ +# The following strings are byte-for-byte equivalent: +str1 = "The quick brown fox jumps over the lazy dog." + +str2 = """ +The quick brown \ + + + fox jumps over \ + the lazy dog.""" + +str3 = """\ + The quick brown \ + fox jumps over \ + the lazy dog.\ + """ diff --git a/stdex/string3.toml.res b/stdex/string3.toml.res new file mode 100644 index 0000000..f2f6886 --- /dev/null +++ b/stdex/string3.toml.res @@ -0,0 +1,5 @@ +{ + str1 = "The quick brown fox jumps over the lazy dog.", + str2 = "The quick brown fox jumps over the lazy dog.", + str3 = "The quick brown fox jumps over the lazy dog.", +} diff --git a/stdex/string4.toml b/stdex/string4.toml new file mode 100644 index 0000000..8f51b11 --- /dev/null +++ b/stdex/string4.toml @@ -0,0 +1,7 @@ +str4 = """Here are two quotation marks: "". Simple enough.""" +# str5 = """Here are three quotation marks: """.""" # INVALID +str5 = """Here are three quotation marks: ""\".""" +str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" + +# "This," she said, "is just a pointless statement." +str7 = """"This," she said, "is just a pointless statement."""" diff --git a/stdex/string4.toml.res b/stdex/string4.toml.res new file mode 100644 index 0000000..e6289b2 --- /dev/null +++ b/stdex/string4.toml.res @@ -0,0 +1,6 @@ +{ + str4 = "Here are two quotation marks: \"\". Simple enough.", + str5 = "Here are three quotation marks: \"\"\".", + str6 = "Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".", + str7 = "\"This,\" she said, \"is just a pointless statement.\"", +} diff --git a/stdex/string5.toml b/stdex/string5.toml new file mode 100644 index 0000000..36772bb --- /dev/null +++ b/stdex/string5.toml @@ -0,0 +1,5 @@ +# What you see is what you get. +winpath = 'C:\Users\nodejs\templates' +winpath2 = '\\ServerX\admin$\system32\' +quoted = 'Tom "Dubs" Preston-Werner' +regex = '<\i\c*\s*>' diff --git a/stdex/string5.toml.res b/stdex/string5.toml.res new file mode 100644 index 0000000..31a4447 --- /dev/null +++ b/stdex/string5.toml.res @@ -0,0 +1,6 @@ +{ + winpath = "C:\\Users\\nodejs\\templates", + winpath2 = "\\\\ServerX\\admin$\\system32\\", + quoted = "Tom \"Dubs\" Preston-Werner", + regex = "<\\i\\c*\\s*>", +} diff --git a/stdex/string6.toml b/stdex/string6.toml new file mode 100644 index 0000000..bc88494 --- /dev/null +++ b/stdex/string6.toml @@ -0,0 +1,7 @@ +regex2 = '''I [dw]on't need \d{2} apples''' +lines = ''' +The first newline is +trimmed in raw strings. + All other whitespace + is preserved. +''' diff --git a/stdex/string6.toml.res b/stdex/string6.toml.res new file mode 100644 index 0000000..7ed3a14 --- /dev/null +++ b/stdex/string6.toml.res @@ -0,0 +1,4 @@ +{ + regex2 = "I [dw]on't need \\d{2} apples", + lines = "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", +} diff --git a/stdex/string7.toml b/stdex/string7.toml new file mode 100644 index 0000000..f87153e --- /dev/null +++ b/stdex/string7.toml @@ -0,0 +1,4 @@ +quot15 = '''Here are fifteen quotation marks: """""""""""""""''' + +# 'That,' she said, 'is still pointless.' +str = ''''That,' she said, 'is still pointless.'''' diff --git a/stdex/string7.toml.res b/stdex/string7.toml.res new file mode 100644 index 0000000..f194093 --- /dev/null +++ b/stdex/string7.toml.res @@ -0,0 +1,4 @@ +{ + quot15 = "Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"", + str = "'That,' she said, 'is still pointless.'", +} diff --git a/stdex/string8.toml b/stdex/string8.toml new file mode 100644 index 0000000..fd74bf2 --- /dev/null +++ b/stdex/string8.toml @@ -0,0 +1,3 @@ +# apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID +apos15 = "Here are fifteen apostrophes: '''''''''''''''" + diff --git a/stdex/string8.toml.res b/stdex/string8.toml.res new file mode 100644 index 0000000..cb2526f --- /dev/null +++ b/stdex/string8.toml.res @@ -0,0 +1 @@ +ERROR: line 2: triple-s-quote inside string lit diff --git a/toml.c b/toml.c index 073974b..1afa0a4 100644 --- a/toml.c +++ b/toml.c @@ -2,19 +2,19 @@ MIT License - Copyright (c) 2017 - 2019 CK Tan + Copyright (c) 2017 - 2021 CK Tan https://github.com/cktan/tomlc99 - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -94,7 +94,7 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) const unsigned char* buf = (const unsigned char*) orig; unsigned i = *buf++; int64_t v; - + /* 0x00000000 - 0x0000007F: 0xxxxxxx */ @@ -144,7 +144,7 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) } return *ret = v, (const char*) buf - orig; } - + /* 0x00200000 - 0x03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ @@ -178,7 +178,7 @@ int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) /** * Convert a UCS char to utf8 code, and return it in buf. - * Return #bytes used in buf to encode the char, or + * Return #bytes used in buf to encode the char, or * -1 on error. */ int toml_ucs_to_utf8(int64_t code, char buf[6]) @@ -241,7 +241,7 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) buf[4] = 0x80 | (code & 0x3f); return 5; } - + /* 0x04000000 - 0x7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ @@ -259,7 +259,7 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) } /* - * TOML has 3 data structures: value, array, table. + * TOML has 3 data structures: value, array, table. * Each of them can have identification key. */ typedef struct toml_keyval_t toml_keyval_t; @@ -268,20 +268,24 @@ struct toml_keyval_t { const char* val; /* the raw value */ }; +typedef struct toml_arritem_t toml_arritem_t; +struct toml_arritem_t { + int valtype; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ + char* val; + toml_array_t* arr; + toml_table_t* tab; +}; + struct toml_array_t { const char* key; /* key to this array */ - int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */ - int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ - - int nelem; /* number of elements */ - union { - char** val; - toml_array_t** arr; - toml_table_t** tab; - } u; + int kind; /* element kind: 'v'alue, 'a'rray, or 't'able, 'm'ixed */ + int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp, 'm'ixed */ + + int nitem; /* number of elements */ + toml_arritem_t* item; }; - + struct toml_table_t { const char* key; /* key to this table */ @@ -391,7 +395,7 @@ static void* expand(void* p, int sz, int newsz) { void* s = MALLOC(newsz); if (!s) return 0; - + memcpy(s, p, sz); FREE(p); return s; @@ -408,6 +412,15 @@ static void** expand_ptrarr(void** p, int n) return s; } +static toml_arritem_t* expand_arritem(toml_arritem_t* p, int n) +{ + toml_arritem_t* pp = expand(p, n*sizeof(*p), (n+1)*sizeof(*p)); + if (!pp) return 0; + + memset(&pp[n], 0, sizeof(pp[n])); + return pp; +} + static char* norm_lit_str(const char* src, int srclen, int multiline, @@ -433,10 +446,10 @@ static char* norm_lit_str(const char* src, int srclen, dst = x; max = newmax; } - + /* finished? */ - if (sp >= sq) break; - + if (sp >= sq) break; + ch = *sp++; /* control characters other than tab is not allowed */ if ((0 <= ch && ch <= 0x08) @@ -448,7 +461,7 @@ static char* norm_lit_str(const char* src, int srclen, return 0; } } - + // a plain copy suffice dst[off++] = ch; } @@ -460,7 +473,7 @@ static char* norm_lit_str(const char* src, int srclen, -/* +/* * Convert src to raw unescaped utf-8 string. * Returns NULL if error with errmsg in errbuf. */ @@ -488,10 +501,10 @@ static char* norm_basic_str(const char* src, int srclen, dst = x; max = newmax; } - + /* finished? */ - if (sp >= sq) break; - + if (sp >= sq) break; + ch = *sp++; if (ch != '\\') { /* these chars must be escaped: U+0000 to U+0008, U+000A to U+001F, U+007F */ @@ -504,7 +517,7 @@ static char* norm_basic_str(const char* src, int srclen, return 0; } } - + // a plain copy suffice dst[off++] = ch; continue; @@ -569,7 +582,7 @@ static char* norm_basic_str(const char* src, int srclen, case 'r': ch = '\r'; break; case '"': ch = '"'; break; case '\\': ch = '\\'; break; - default: + default: snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); xfree(dst); return 0; @@ -579,7 +592,7 @@ static char* norm_basic_str(const char* src, int srclen, } // Cap with NUL and return it. - dst[off++] = 0; + dst[off++] = 0; return dst; } @@ -628,7 +641,7 @@ static char* normalize_key(context_t* ctx, token_t strtok) } return ret; } - + /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ const char* xp; for (xp = sp; xp != sq; xp++) { @@ -648,7 +661,7 @@ static char* normalize_key(context_t* ctx, token_t strtok) } -/* +/* * Look up key in tab. Return 0 if not found, or * 'v'alue, 'a'rray or 't'able depending on the element. */ @@ -665,7 +678,7 @@ static int check_key(toml_table_t* tab, const char* key, if (!ret_val) ret_val = (toml_keyval_t**) &dummy; *ret_tab = 0; *ret_arr = 0; *ret_val = 0; - + for (i = 0; i < tab->nkval; i++) { if (0 == strcmp(key, tab->kval[i]->key)) { *ret_val = tab->kval[i]; @@ -693,12 +706,12 @@ static int key_kind(toml_table_t* tab, const char* key) return check_key(tab, key, 0, 0, 0); } -/* Create a keyval in the table. +/* Create a keyval in the table. */ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. */ char* newkey = normalize_key(ctx, keytok); if (!newkey) return 0; @@ -720,7 +733,7 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, return 0; } tab->kval = base; - + if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { xfree(newkey); e_outofmemory(ctx, FLINE); @@ -738,8 +751,8 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, */ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. */ char* newkey = normalize_key(ctx, keytok); if (!newkey) return 0; @@ -748,7 +761,7 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, toml_table_t* dest = 0; if (check_key(tab, newkey, 0, 0, &dest)) { xfree(newkey); /* don't need this anymore */ - + /* special case: if table exists, but was created implicitly ... */ if (dest && dest->implicit) { /* we make it explicit now, and simply return it. */ @@ -768,14 +781,14 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, return 0; } tab->tab = base; - + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { xfree(newkey); e_outofmemory(ctx, FLINE); return 0; } dest = tab->tab[tab->ntab++]; - + /* save the key in the new table struct */ dest->key = newkey; return dest; @@ -789,12 +802,12 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, token_t keytok, char kind) { - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. */ char* newkey = normalize_key(ctx, keytok); if (!newkey) return 0; - + /* if key exists: error out */ if (key_kind(tab, newkey)) { xfree(newkey); /* don't need this anymore */ @@ -811,7 +824,7 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, return 0; } tab->arr = base; - + if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { xfree(newkey); e_outofmemory(ctx, FLINE); @@ -825,47 +838,63 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx, return dest; } -/* Create an array in an array + +static toml_arritem_t* create_value_in_array(context_t* ctx, + toml_array_t* parent) +{ + const int n = parent->nitem; + toml_arritem_t* base = expand_arritem(parent->item, n); + if (!base) { + e_outofmemory(ctx, FLINE); + return 0; + } + parent->item = base; + parent->nitem++; + return &parent->item[n]; +} + +/* Create an array in an array */ static toml_array_t* create_array_in_array(context_t* ctx, toml_array_t* parent) { - const int n = parent->nelem; - toml_array_t** base; - if (0 == (base = (toml_array_t**) expand_ptrarr((void**)parent->u.arr, n))) { + const int n = parent->nitem; + toml_arritem_t* base = expand_arritem(parent->item, n); + if (!base) { e_outofmemory(ctx, FLINE); return 0; } - parent->u.arr = base; - parent->nelem++; - - if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { + toml_array_t* ret = (toml_array_t*) CALLOC(1, sizeof(toml_array_t)); + if (!ret) { e_outofmemory(ctx, FLINE); return 0; } - - return parent->u.arr[n]; + base[n].arr = ret; + parent->item = base; + parent->nitem++; + return ret; } -/* Create a table in an array +/* Create a table in an array */ static toml_table_t* create_table_in_array(context_t* ctx, toml_array_t* parent) { - int n = parent->nelem; - toml_table_t** base; - if (0 == (base = (toml_table_t**) expand_ptrarr((void**)parent->u.tab, n))) { + int n = parent->nitem; + toml_arritem_t* base = expand_arritem(parent->item, n); + if (!base) { e_outofmemory(ctx, FLINE); return 0; } - parent->u.tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { + toml_table_t* ret = (toml_table_t*) CALLOC(1, sizeof(toml_table_t)); + if (!ret) { e_outofmemory(ctx, FLINE); return 0; } - - return parent->u.tab[parent->nelem++]; + base[n].tab = ret; + parent->item = base; + parent->nitem++; + return ret; } @@ -883,7 +912,7 @@ static int parse_keyval(context_t* ctx, toml_table_t* tab); static inline int eat_token(context_t* ctx, tokentype_t typ, int isdotspecial, const char* fline) { - if (ctx->tok.tok != typ) + if (ctx->tok.tok != typ) return e_internal(ctx, fline); if (next_token(ctx, isdotspecial)) @@ -903,20 +932,20 @@ static int parse_table(context_t* ctx, toml_table_t* tab) return -1; for (;;) { - if (ctx->tok.tok == NEWLINE) + if (ctx->tok.tok == NEWLINE) return e_syntax(ctx, ctx->tok.lineno, "newline not allowed in inline table"); /* until } */ if (ctx->tok.tok == RBRACE) break; - if (ctx->tok.tok != STRING) + if (ctx->tok.tok != STRING) return e_syntax(ctx, ctx->tok.lineno, "expect a string"); if (parse_keyval(ctx, tab)) return -1; - - if (ctx->tok.tok == NEWLINE) + + if (ctx->tok.tok == NEWLINE) return e_syntax(ctx, ctx->tok.lineno, "newline not allowed in inline table"); /* on comma, continue to scan for next keyval */ @@ -953,43 +982,40 @@ static int valtype(const char* val) static int parse_array(context_t* ctx, toml_array_t* arr) { if (eat_token(ctx, LBRACKET, 0, FLINE)) return -1; - + for (;;) { if (skip_newlines(ctx, 0)) return -1; - + /* until ] */ if (ctx->tok.tok == RBRACKET) break; switch (ctx->tok.tok) { case STRING: { + /* set array kind if this will be the first entry */ + if (arr->kind == 0) + arr->kind = 'v'; + else if (arr->kind != 'v') + arr->kind = 'm'; + char* val = ctx->tok.ptr; int vlen = ctx->tok.len; - /* set array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'v'; - /* check array kind */ - if (arr->kind != 'v') - return e_syntax(ctx, ctx->tok.lineno, "a string array can only contain strings"); - /* make a new value in array */ - char** tmp = (char**) expand_ptrarr((void**)arr->u.val, arr->nelem); - if (!tmp) - return e_outofmemory(ctx, FLINE); - - arr->u.val = tmp; - if (! (val = STRNDUP(val, vlen))) + toml_arritem_t* newval = create_value_in_array(ctx, arr); + if (!newval) return e_outofmemory(ctx, FLINE); - arr->u.val[arr->nelem++] = val; + if (! (newval->val = STRNDUP(val, vlen))) + return e_outofmemory(ctx, FLINE); - /* set array type if this is the first entry, or check that the types matched. */ - if (arr->nelem == 1) - arr->type = valtype(arr->u.val[0]); - else if (arr->type != valtype(val)) { - return e_syntax(ctx, ctx->tok.lineno, - "array type mismatch while processing array of values"); - } + newval->valtype = valtype(newval->val); + + /* set array type if this is the first entry */ + if (arr->nitem == 1) + arr->type = newval->valtype; + else if (arr->type != newval->valtype) + arr->type = 'm'; /* mixed */ if (eat_token(ctx, STRING, 0, FLINE)) return -1; break; @@ -998,12 +1024,11 @@ static int parse_array(context_t* ctx, toml_array_t* arr) case LBRACKET: { /* [ [array], [array] ... ] */ /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 'a'; - /* check array kind */ - if (arr->kind != 'a') { - return e_syntax(ctx, ctx->tok.lineno, - "array type mismatch while processing array of arrays"); - } + if (arr->kind == 0) + arr->kind = 'a'; + else if (arr->kind != 'a') + arr->kind = 'm'; + toml_array_t* subarr = create_array_in_array(ctx, arr); if (!subarr) return -1; if (parse_array(ctx, subarr)) return -1; @@ -1013,18 +1038,17 @@ static int parse_array(context_t* ctx, toml_array_t* arr) case LBRACE: { /* [ {table}, {table} ... ] */ /* set the array kind if this will be the first entry */ - if (arr->kind == 0) arr->kind = 't'; - /* check array kind */ - if (arr->kind != 't') { - return e_syntax(ctx, ctx->tok.lineno, - "array type mismatch while processing array of tables"); - } + if (arr->kind == 0) + arr->kind = 't'; + else if (arr->kind != 't') + arr->kind = 'm'; + toml_table_t* subtab = create_table_in_array(ctx, arr); if (!subtab) return -1; if (parse_table(ctx, subtab)) return -1; break; } - + default: return e_syntax(ctx, ctx->tok.lineno, "syntax error"); } @@ -1053,10 +1077,10 @@ static int parse_keyval(context_t* ctx, toml_table_t* tab) { token_t key = ctx->tok; if (eat_token(ctx, STRING, 1, FLINE)) return -1; - - if (ctx->tok.tok == DOT) { - /* handle inline dotted key. - e.g. + + if (ctx->tok.tok == DOT) { + /* handle inline dotted key. + e.g. physical.color = "orange" physical.shape = "round" */ @@ -1089,13 +1113,13 @@ static int parse_keyval(context_t* ctx, toml_table_t* tab) toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); if (!keyval) return -1; token_t val = ctx->tok; - + assert(keyval->val == 0); - if (! (keyval->val = STRNDUP(val.ptr, val.len))) + if (! (keyval->val = STRNDUP(val.ptr, val.len))) return e_outofmemory(ctx, FLINE); if (next_token(ctx, 1)) return -1; - + return 0; } @@ -1136,7 +1160,7 @@ static int fill_tabpath(context_t* ctx) { int lineno = ctx->tok.lineno; int i; - + /* clear tpath */ for (i = 0; i < ctx->tpath.top; i++) { char** p = &ctx->tpath.key[i]; @@ -1144,12 +1168,12 @@ static int fill_tabpath(context_t* ctx) *p = 0; } ctx->tpath.top = 0; - + for (;;) { if (ctx->tpath.top >= 10) return e_syntax(ctx, lineno, "table path is too deep; max allowed is 10."); - if (ctx->tok.tok != STRING) + if (ctx->tok.tok != STRING) return e_syntax(ctx, lineno, "invalid or missing key"); char* key = normalize_key(ctx, ctx->tok); @@ -1157,12 +1181,12 @@ static int fill_tabpath(context_t* ctx) ctx->tpath.tok[ctx->tpath.top] = ctx->tok; ctx->tpath.key[ctx->tpath.top] = key; ctx->tpath.top++; - + if (next_token(ctx, 1)) return -1; if (ctx->tok.tok == RBRACKET) break; - if (ctx->tok.tok != DOT) + if (ctx->tok.tok != DOT) return e_syntax(ctx, lineno, "invalid key"); if (next_token(ctx, 1)) return -1; @@ -1182,7 +1206,7 @@ static int walk_tabpath(context_t* ctx) { /* start from root */ toml_table_t* curtab = ctx->root; - + for (int i = 0; i < ctx->tpath.top; i++) { const char* key = ctx->tpath.key[i]; @@ -1196,13 +1220,13 @@ static int walk_tabpath(context_t* ctx) case 'a': /* found an array. nexttab is the last table in the array. */ - if (nextarr->kind != 't') + if (nextarr->kind != 't') return e_internal(ctx, FLINE); - if (nextarr->nelem == 0) + if (nextarr->nitem == 0) return e_internal(ctx, FLINE); - nexttab = nextarr->u.tab[nextarr->nelem-1]; + nexttab = nextarr->item[nextarr->nitem-1].tab; break; case 'v': @@ -1212,19 +1236,19 @@ static int walk_tabpath(context_t* ctx) { /* Not found. Let's create an implicit table. */ int n = curtab->ntab; toml_table_t** base = (toml_table_t**) expand_ptrarr((void**)curtab->tab, n); - if (0 == base) + if (0 == base) return e_outofmemory(ctx, FLINE); curtab->tab = base; - - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) + + if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) return e_outofmemory(ctx, FLINE); - - if (0 == (base[n]->key = STRDUP(key))) + + if (0 == (base[n]->key = STRDUP(key))) return e_outofmemory(ctx, FLINE); - + nexttab = curtab->tab[curtab->ntab++]; - + /* tabs created by walk_tabpath are considered implicit */ nexttab->implicit = true; } @@ -1241,15 +1265,15 @@ static int walk_tabpath(context_t* ctx) return 0; } - + /* handle lines like [x.y.z] or [[x.y.z]] */ static int parse_select(context_t* ctx) { assert(ctx->tok.tok == LBRACKET); - + /* true if [[ */ int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '['); - /* need to detect '[[' on our own because next_token() will skip whitespace, + /* need to detect '[[' on our own because next_token() will skip whitespace, and '[ [' would be taken as '[[', which is wrong. */ /* eat [ or [[ */ @@ -1261,7 +1285,7 @@ static int parse_select(context_t* ctx) if (fill_tabpath(ctx)) return -1; - /* For [x.y.z] or [[x.y.z]], remove z from tpath. + /* For [x.y.z] or [[x.y.z]], remove z from tpath. */ token_t z = ctx->tpath.tok[ctx->tpath.top-1]; xfree(ctx->tpath.key[ctx->tpath.top-1]); @@ -1288,26 +1312,19 @@ static int parse_select(context_t* ctx) arr = create_keyarray_in_table(ctx, ctx->curtab, z, 't'); if (!arr) return -1; } - if (arr->kind != 't') + if (arr->kind != 't') return e_syntax(ctx, z.lineno, "array mismatch"); /* add to z[] */ toml_table_t* dest; { - int n = arr->nelem; - toml_table_t** base = (toml_table_t**) expand_ptrarr((void**)arr->u.tab, n); - if (0 == base) + toml_table_t* t = create_table_in_array(ctx, arr); + if (!t) return -1; + + if (0 == (t->key = STRDUP("__anon__"))) return e_outofmemory(ctx, FLINE); - arr->u.tab = base; - - if (0 == (base[n] = CALLOC(1, sizeof(*base[n])))) - return e_outofmemory(ctx, FLINE); - - if (0 == (base[n]->key = STRDUP("__anon__"))) - return e_outofmemory(ctx, FLINE); - - dest = arr->u.tab[arr->nelem++]; + dest = t; } ctx->curtab = dest; @@ -1322,11 +1339,11 @@ static int parse_select(context_t* ctx) } if (eat_token(ctx, RBRACKET, 1, FLINE)) return -1; } - + if (eat_token(ctx, RBRACKET, 1, FLINE)) return -1; - - if (ctx->tok.tok != NEWLINE) + + if (ctx->tok.tok != NEWLINE) return e_syntax(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); return 0; @@ -1341,11 +1358,11 @@ toml_table_t* toml_parse(char* conf, { context_t ctx; - // clear errbuf + // clear errbuf if (errbufsz <= 0) errbufsz = 0; if (errbufsz > 0) errbuf[0] = 0; - // init context + // init context memset(&ctx, 0, sizeof(ctx)); ctx.start = conf; ctx.stop = ctx.start + strlen(conf); @@ -1353,7 +1370,7 @@ toml_table_t* toml_parse(char* conf, ctx.errbufsz = errbufsz; // start with an artificial newline of length 0 - ctx.tok.tok = NEWLINE; + ctx.tok.tok = NEWLINE; ctx.tok.lineno = 1; ctx.tok.ptr = conf; ctx.tok.len = 0; @@ -1371,14 +1388,14 @@ toml_table_t* toml_parse(char* conf, /* Scan forward until EOF */ for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { switch (tok.tok) { - + case NEWLINE: if (next_token(&ctx, 1)) goto fail; break; - + case STRING: if (parse_keyval(&ctx, ctx.curtab)) goto fail; - + if (ctx.tok.tok != NEWLINE) { e_syntax(&ctx, ctx.tok.lineno, "extra chars after value"); goto fail; @@ -1386,11 +1403,11 @@ toml_table_t* toml_parse(char* conf, if (eat_token(&ctx, NEWLINE, 1, FLINE)) goto fail; break; - + case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ if (parse_select(&ctx)) goto fail; break; - + default: e_syntax(&ctx, tok.lineno, "syntax error"); goto fail; @@ -1431,7 +1448,7 @@ toml_table_t* toml_parse_file(FILE* fp, buf = x; bufsz = xsz; } - + errno = 0; int n = fread(buf + off, 1, bufsz - off, fp); if (ferror(fp)) { @@ -1455,7 +1472,7 @@ toml_table_t* toml_parse_file(FILE* fp, buf = x; bufsz = xsz; } - buf[off] = 0; + buf[off] = 0; /* parse it, cleanup and finish */ toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); @@ -1479,23 +1496,17 @@ static void xfree_arr(toml_array_t* p) if (!p) return; xfree(p->key); - switch (p->kind) { - case 'v': - for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]); - xfree(p->u.val); - break; - - case 'a': - for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]); - xfree(p->u.arr); - break; - - case 't': - for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]); - xfree(p->u.tab); - break; + const int n = p->nitem; + for (int i = 0; i < n; i++) { + toml_arritem_t* a = &p->item[i]; + if (a->val) + xfree(a->val); + else if (a->arr) + xfree_arr(a->arr); + else if (a->tab) + xfree_tab(a->tab); } - + xfree(p->item); xfree(p); } @@ -1503,11 +1514,11 @@ static void xfree_arr(toml_array_t* p) static void xfree_tab(toml_table_t* p) { int i; - + if (!p) return; - + xfree(p->key); - + for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); xfree(p->kval); @@ -1578,26 +1589,50 @@ static int scan_time(const char* p, int* hh, int* mm, int* ss) if (ss) *ss = second; return (hour >= 0 && minute >= 0 && second >= 0) ? 0 : -1; } - + static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) { char* orig = p; if (0 == strncmp(p, "'''", 3)) { - p = strstr(p + 3, "'''"); - if (0 == p) { - return e_syntax(ctx, lineno, "unterminated triple-s-quote"); + char* q = p + 3; + + while (1) { + q = strstr(q, "'''"); + if (0 == q) { + return e_syntax(ctx, lineno, "unterminated triple-s-quote"); + } + while (q[3] == '\'') q++; + break; } - set_token(ctx, STRING, lineno, orig, p + 3 - orig); + set_token(ctx, STRING, lineno, orig, q + 3 - orig); return 0; } if (0 == strncmp(p, "\"\"\"", 3)) { + char* q = p + 3; + + while (1) { + q = strstr(q, "\"\"\""); + if (0 == q) { + return e_syntax(ctx, lineno, "unterminated triple-d-quote"); + } + if (q[-1] == '\\') { + q++; + continue; + } + while (q[3] == '\"') q++; + break; + } + + char* tsq = strstr(p, "\'\'\'"); + + // the string is [p+3, q-1] + int hexreq = 0; /* #hex required */ int escape = 0; - int qcnt = 0; /* count quote */ - for (p += 3; *p && qcnt < 3; p++) { + for (p += 3; p < q; p++) { if (escape) { escape = 0; if (strchr("btnfr\"\\", *p)) continue; @@ -1612,13 +1647,16 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) return e_syntax(ctx, lineno, "expect hex char"); } if (*p == '\\') { escape = 1; continue; } - qcnt = (*p == '"') ? qcnt + 1 : 0; - } - if (qcnt != 3) { - return e_syntax(ctx, lineno, "unterminated triple-quote"); } + if (escape) + return e_syntax(ctx, lineno, "expect an escape char"); + if (hexreq) + return e_syntax(ctx, lineno, "expected more hex char"); - set_token(ctx, STRING, lineno, orig, p - orig); + if (tsq && tsq < q) { + return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); + } + set_token(ctx, STRING, lineno, orig, q + 3 - orig); return 0; } @@ -1633,6 +1671,7 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) } if ('\"' == *p) { + char* tsq = strstr(p, "\'\'\'"); int hexreq = 0; /* #hex required */ int escape = 0; for (p++; *p; p++) { @@ -1656,6 +1695,10 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) return e_syntax(ctx, lineno, "unterminated quote"); } + if (tsq && tsq < p) { + return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); + } + set_token(ctx, STRING, lineno, orig, p + 1 - orig); return 0; } @@ -1710,7 +1753,7 @@ static int next_token(context_t* ctx, int dotisspecial) set_token(ctx, DOT, lineno, p, 1); return 0; } - + switch (*p) { case ',': set_token(ctx, COMMA, lineno, p, 1); return 0; case '=': set_token(ctx, EQUAL, lineno, p, 1); return 0; @@ -1736,10 +1779,10 @@ static int next_token(context_t* ctx, int dotisspecial) const char* toml_key_in(const toml_table_t* tab, int keyidx) { if (keyidx < tab->nkval) return tab->kval[keyidx]->key; - + keyidx -= tab->nkval; if (keyidx < tab->narr) return tab->arr[keyidx]->key; - + keyidx -= tab->narr; if (keyidx < tab->ntab) return tab->tab[keyidx]->key; @@ -1779,11 +1822,7 @@ toml_table_t* toml_table_in(const toml_table_t* tab, const char* key) toml_raw_t toml_raw_at(const toml_array_t* arr, int idx) { - if (arr->kind != 'v') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.val[idx]; + return (0 <= idx && idx < arr->nitem) ? arr->item[idx].val : 0; } char toml_array_kind(const toml_array_t* arr) @@ -1796,7 +1835,7 @@ char toml_array_type(const toml_array_t* arr) if (arr->kind != 'v') return 0; - if (arr->nelem == 0) + if (arr->nitem == 0) return 0; return arr->type; @@ -1805,7 +1844,7 @@ char toml_array_type(const toml_array_t* arr) int toml_array_nelem(const toml_array_t* arr) { - return arr->nelem; + return arr->nitem; } const char* toml_array_key(const toml_array_t* arr) @@ -1835,30 +1874,22 @@ const char* toml_table_key(const toml_table_t* tab) toml_array_t* toml_array_at(const toml_array_t* arr, int idx) { - if (arr->kind != 'a') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.arr[idx]; + return (0 <= idx && idx < arr->nitem) ? arr->item[idx].arr : 0; } toml_table_t* toml_table_at(const toml_array_t* arr, int idx) { - if (arr->kind != 't') - return 0; - if (! (0 <= idx && idx < arr->nelem)) - return 0; - return arr->u.tab[idx]; + return (0 <= idx && idx < arr->nitem) ? arr->item[idx].tab : 0; } int toml_rtots(toml_raw_t src_, toml_timestamp_t* ret) { if (! src_) return -1; - + const char* p = src_; int must_parse_time = 0; - + memset(ret, 0, sizeof(*ret)); int* year = &ret->__buffer.year; @@ -1874,7 +1905,7 @@ int toml_rtots(toml_raw_t src_, toml_timestamp_t* ret) ret->year = year; ret->month = month; ret->day = day; - + p += 10; if (*p) { // parse the T or space separator @@ -1915,29 +1946,29 @@ int toml_rtots(toml_raw_t src_, toml_timestamp_t* ret) if (*p == 'Z' || *p == 'z') { *z++ = 'Z'; p++; *z = 0; - + } else if (*p == '+' || *p == '-') { *z++ = *p++; - + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; *z++ = *p++; *z++ = *p++; - + if (*p == ':') { *z++ = *p++; - + if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; *z++ = *p++; *z++ = *p++; } - + *z = 0; } } } if (*p != 0) return -1; - + if (must_parse_time && !ret->hour) return -1; @@ -1951,7 +1982,7 @@ int toml_rtob(toml_raw_t src, int* ret_) if (!src) return -1; int dummy; int* ret = ret_ ? ret_ : &dummy; - + if (0 == strcmp(src, "true")) { *ret = 1; return 0; @@ -1968,7 +1999,7 @@ int toml_rtob(toml_raw_t src, int* ret_) int toml_rtoi(toml_raw_t src, int64_t* ret_) { if (!src) return -1; - + char buf[100]; char* p = buf; char* q = p + sizeof(buf); @@ -1976,12 +2007,12 @@ int toml_rtoi(toml_raw_t src, int64_t* ret_) int base = 0; int64_t dummy; int64_t* ret = ret_ ? ret_ : &dummy; - + /* allow +/- */ if (s[0] == '+' || s[0] == '-') *p++ = *s++; - + /* disallow +_100 */ if (s[0] == '_') return -1; @@ -2005,7 +2036,7 @@ int toml_rtoi(toml_raw_t src, int64_t* ret_) switch (ch) { case '_': // disallow '__' - if (s[0] == '_') return -1; + if (s[0] == '_') return -1; continue; /* skip _ */ default: break; @@ -2016,7 +2047,7 @@ int toml_rtoi(toml_raw_t src, int64_t* ret_) /* last char cannot be '_' */ if (s[-1] == '_') return -1; - + /* cap with NUL */ *p = 0; @@ -2031,13 +2062,13 @@ int toml_rtoi(toml_raw_t src, int64_t* ret_) int toml_rtod_ex(toml_raw_t src, double* ret_, char* buf, int buflen) { if (!src) return -1; - + char* p = buf; char* q = p + buflen; const char* s = src; double dummy; double* ret = ret_ ? ret_ : &dummy; - + /* allow +/- */ if (s[0] == '+' || s[0] == '-') @@ -2050,7 +2081,7 @@ int toml_rtod_ex(toml_raw_t src, double* ret_, char* buf, int buflen) /* disallow +.99 */ if (s[0] == '.') return -1; - + /* zero must be followed by . or 'e', or NUL */ if (s[0] == '0' && s[1] && !strchr("eE.", s[1])) return -1; @@ -2065,7 +2096,7 @@ int toml_rtod_ex(toml_raw_t src, double* ret_, char* buf, int buflen) break; case '_': // disallow '__' - if (s[0] == '_') return -1; + if (s[0] == '_') return -1; continue; /* skip _ */ default: break; @@ -2073,11 +2104,11 @@ int toml_rtod_ex(toml_raw_t src, double* ret_, char* buf, int buflen) *p++ = ch; } if (*s || p == q) return -1; /* reached end of string or buffer is full? */ - + /* last char cannot be '_' */ if (s[-1] == '_') return -1; - if (p != buf && p[-1] == '.') + if (p != buf && p[-1] == '.') return -1; /* no trailing zero */ /* cap with NUL */ @@ -2104,7 +2135,7 @@ int toml_rtos(toml_raw_t src, char** ret) int multiline = 0; const char* sp; const char* sq; - + *ret = 0; if (!src) return -1; @@ -2113,22 +2144,22 @@ int toml_rtos(toml_raw_t src, char** ret) if (! (qchar == '\'' || qchar == '"')) { return -1; } - + // triple quotes? if (qchar == src[1] && qchar == src[2]) { multiline = 1; sp = src + 3; sq = src + srclen - 3; /* last 3 chars in src must be qchar */ - if (! (sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) + if (! (sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) return -1; - + /* skip new line immediate after qchar */ if (sp[0] == '\n') sp++; else if (sp[0] == '\r' && sp[1] == '\n') sp += 2; - + } else { sp = src + 1; sq = src + srclen - 1; @@ -2136,7 +2167,7 @@ int toml_rtos(toml_raw_t src, char** ret) if (! (sp <= sq && *sq == qchar)) return -1; } - + if (qchar == '\'') { *ret = norm_lit_str(sp, sq - sp, multiline, @@ -2146,7 +2177,7 @@ int toml_rtos(toml_raw_t src, char** ret) multiline, 0, 0); } - + return *ret ? 0 : -1; } @@ -2173,7 +2204,7 @@ toml_datum_t toml_int_at(const toml_array_t* arr, int idx) memset(&ret, 0, sizeof(ret)); ret.ok = (0 == toml_rtoi(toml_raw_at(arr, idx), &ret.u.i)); return ret; -} +} toml_datum_t toml_double_at(const toml_array_t* arr, int idx) { @@ -2246,4 +2277,4 @@ toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key) } } return ret; -} +} diff --git a/toml.h b/toml.h index 19f6f64..b91ef89 100644 --- a/toml.h +++ b/toml.h @@ -1,19 +1,19 @@ /* MIT License - + Copyright (c) 2017 - 2019 CK Tan https://github.com/cktan/tomlc99 - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -41,14 +41,14 @@ typedef struct toml_table_t toml_table_t; typedef struct toml_array_t toml_array_t; typedef struct toml_datum_t toml_datum_t; -/* Parse a file. Return a table on success, or 0 otherwise. +/* Parse a file. Return a table on success, or 0 otherwise. * Caller must toml_free(the-return-value) after use. */ -TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, +TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, char* errbuf, int errbufsz); -/* Parse a string containing the full config. +/* Parse a string containing the full config. * Return a table on success, or 0 otherwise. * Caller must toml_free(the-return-value) after use. */ @@ -56,14 +56,14 @@ TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */ char* errbuf, int errbufsz); -/* Free the table returned by toml_parse() or toml_parse_file(). Once - * this function is called, any handles accessed through this tab +/* Free the table returned by toml_parse() or toml_parse_file(). Once + * this function is called, any handles accessed through this tab * directly or indirectly are no longer valid. */ TOML_EXTERN void toml_free(toml_table_t* tab); -/* Timestamp types. The year, month, day, hour, minute, second, z +/* Timestamp types. The year, month, day, hour, minute, second, z * fields may be NULL if they are not relevant. e.g. In a DATE * type, the hour, minute, second and z fields will be NULLs. */ @@ -80,7 +80,7 @@ struct toml_timestamp_t { /*----------------------------------------------------------------- - * Enhanced access methods + * Enhanced access methods */ struct toml_datum_t { int ok; @@ -122,13 +122,13 @@ TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab, const char* key); /*----------------------------------------------------------------- - * lesser used + * lesser used */ -/* Return the array kind: 't'able, 'a'rray, 'v'alue */ +/* Return the array kind: 't'able, 'a'rray, 'v'alue, 'm'ixed */ TOML_EXTERN char toml_array_kind(const toml_array_t* arr); -/* For array kind 'v'alue, return the type of values - i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp +/* For array kind 'v'alue, return the type of values + i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp, 'm'ixed 0 if unknown */ TOML_EXTERN char toml_array_type(const toml_array_t* arr); @@ -149,7 +149,7 @@ TOML_EXTERN int toml_table_ntab(const toml_table_t* tab); TOML_EXTERN const char* toml_table_key(const toml_table_t* tab); /*-------------------------------------------------------------- - * misc + * misc */ TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); @@ -158,7 +158,7 @@ TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t), /*-------------------------------------------------------------- - * deprecated + * deprecated */ /* A raw value, must be processed by toml_rto* before using. */ typedef const char* toml_raw_t; diff --git a/toml_cat.c b/toml_cat.c index 186ebf4..6292fa0 100644 --- a/toml_cat.c +++ b/toml_cat.c @@ -1,26 +1,26 @@ /* -MIT License + MIT License -Copyright (c) 2017 CK Tan -https://github.com/cktan/tomlc99 + Copyright (c) 2017 CK Tan + https://github.com/cktan/tomlc99 -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. */ #ifdef NDEBUG @@ -33,6 +33,8 @@ SOFTWARE. #include #include #include +#include +#include #include "toml.h" typedef struct node_t node_t; @@ -43,128 +45,229 @@ struct node_t { node_t stack[20]; int stacktop = 0; +int indent = 0; - -static void print_table_title(const char* arrname) +static void prindent() { - int i; - printf("%s", arrname ? "[[" : "["); - for (i = 1; i < stacktop; i++) { - printf("%s", stack[i].key); - if (i + 1 < stacktop) - printf("."); - } - if (arrname) - printf(".%s]]\n", arrname); - else - printf("]\n"); + for (int i = 0; i < indent; i++) printf(" "); +} + + +static void print_string(const char* s) +{ + int ok = 1; + for (const char* p = s; *p && ok; p++) { + int ch = *p; + ok = isprint(ch) && ch != '"' && ch != '\\'; + } + + if (ok) { + printf("\"%s\"", s); + return; + } + + int len = strlen(s); + + printf("\""); + for ( ; len; len--, s++) { + int ch = *s; + if (isprint(ch) && ch != '"' && ch != '\\') { + putchar(ch); + continue; + } + + switch (ch) { + case 0x8: printf("\\b"); continue; + case 0x9: printf("\\t"); continue; + case 0xa: printf("\\n"); continue; + case 0xc: printf("\\f"); continue; + case 0xd: printf("\\r"); continue; + case '"': printf("\\\""); continue; + case '\\': printf("\\\\"); continue; + default: printf("\\0x%02x", ch & 0xff); continue; + } + } + printf("\""); } -static void print_array_of_tables(toml_array_t* arr, const char* key); static void print_array(toml_array_t* arr); static void print_table(toml_table_t* curtab) { + toml_datum_t d; int i; const char* key; - const char* raw; toml_array_t* arr; toml_table_t* tab; - for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { - if (0 != (raw = toml_raw_in(curtab, key))) { - printf("%s = %s\n", key, raw); - } else if (0 != (arr = toml_array_in(curtab, key))) { - if (toml_array_kind(arr) == 't') { - print_array_of_tables(arr, key); - } - else { - printf("%s = [\n", key); - print_array(arr); - printf(" ]\n"); - } - } else if (0 != (tab = toml_table_in(curtab, key))) { - stack[stacktop].key = key; - stack[stacktop].tab = tab; - stacktop++; - print_table_title(0); - print_table(tab); - stacktop--; - } else { - abort(); - } - } -} -static void print_array_of_tables(toml_array_t* arr, const char* key) -{ - int i; - toml_table_t* tab; - printf("\n"); - for (i = 0; 0 != (tab = toml_table_at(arr, i)); i++) { - print_table_title(key); - print_table(tab); - printf("\n"); + if (0 != (arr = toml_array_in(curtab, key))) { + prindent(); + printf("%s = [\n", key); + indent++; + print_array(arr); + indent--; + prindent(); + printf("],\n"); + continue; + } + + if (0 != (tab = toml_table_in(curtab, key))) { + stack[stacktop].key = key; + stack[stacktop].tab = tab; + stacktop++; + prindent(); + printf("%s = {\n", key); + indent++; + print_table(tab); + indent--; + prindent(); + printf("},\n"); + stacktop--; + continue; + } + + d = toml_string_in(curtab, key); + if (d.ok) { + prindent(); + printf("%s = ", key); + print_string(d.u.s); + printf(",\n"); + free(d.u.s); + continue; + } + + d = toml_bool_in(curtab, key); + if (d.ok) { + prindent(); + printf("%s = %s,\n", key, d.u.b ? "true" : "false"); + continue; + } + + d = toml_int_in(curtab, key); + if (d.ok) { + prindent(); + printf("%s = %" PRId64 ",\n", key, d.u.i); + continue; + } + + d = toml_double_in(curtab, key); + if (d.ok) { + prindent(); + printf("%s = %g,\n", key, d.u.d); + continue; + } + + d = toml_timestamp_in(curtab, key); + if (d.ok) { + prindent(); + printf(" %s = %s,\n", key, toml_raw_in(curtab, key)); + free(d.u.ts); + continue; + } + + abort(); } } static void print_array(toml_array_t* curarr) { + toml_datum_t d; toml_array_t* arr; - const char* raw; toml_table_t* tab; - int i; + const int n = toml_array_nelem(curarr); - switch (toml_array_kind(curarr)) { + for (int i = 0; i < n; i++) { - case 'v': - for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { - printf(" %d: %s,\n", i, raw); + if (0 != (arr = toml_array_at(curarr, i))) { + prindent(); + printf("[\n"); + indent++; + print_array(arr); + indent--; + prindent(); + printf("],\n"); + continue; + } + + if (0 != (tab = toml_table_at(curarr, i))) { + prindent(); + printf("{\n"); + indent++; + print_table(tab); + indent--; + prindent(); + printf("},\n"); + continue; + } + + d = toml_string_at(curarr, i); + if (d.ok) { + prindent(); + print_string(d.u.s); + printf(",\n"); + free(d.u.s); + continue; + } + + d = toml_bool_at(curarr, i); + if (d.ok) { + prindent(); + printf("%s,\n", d.u.b ? "true" : "false"); + continue; + } + + d = toml_int_at(curarr, i); + if (d.ok) { + prindent(); + printf("%" PRId64 ",\n", d.u.i); + continue; + } + + d = toml_double_at(curarr, i); + if (d.ok) { + prindent(); + printf("%g,\n", d.u.d); + continue; + } + + d = toml_timestamp_at(curarr, i); + if (d.ok) { + prindent(); + printf("%s,\n", toml_raw_at(curarr, i)); + free(d.u.ts); + continue; + } + + abort(); } - break; - - case 'a': - for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) { - printf(" %d: \n", i); - print_array(arr); - } - break; - - case 't': - for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) { - print_table(tab); - } - printf("\n"); - break; - - case '\0': - break; - - default: - abort(); - } } + static void cat(FILE* fp) { char errbuf[200]; - + toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); if (!tab) { - fprintf(stderr, "ERROR: %s\n", errbuf); - return; + fprintf(stderr, "ERROR: %s\n", errbuf); + return; } stack[stacktop].tab = tab; stack[stacktop].key = ""; stacktop++; + printf("{\n"); + indent++; print_table(tab); + indent--; + printf("}\n"); stacktop--; toml_free(tab); @@ -175,19 +278,19 @@ int main(int argc, const char* argv[]) { int i; if (argc == 1) { - cat(stdin); + cat(stdin); } else { - for (i = 1; i < argc; i++) { - - FILE* fp = fopen(argv[i], "r"); - if (!fp) { - fprintf(stderr, "ERROR: cannot open %s: %s\n", - argv[i], strerror(errno)); - exit(1); - } - cat(fp); - fclose(fp); - } + for (i = 1; i < argc; i++) { + + FILE* fp = fopen(argv[i], "r"); + if (!fp) { + fprintf(stderr, "ERROR: cannot open %s: %s\n", + argv[i], strerror(errno)); + exit(1); + } + cat(fp); + fclose(fp); + } } return 0; } From 20bee50b592e5dc520346cdd1fd26b8f692b312f Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 7 Mar 2021 01:07:03 -0800 Subject: [PATCH 100/138] minor fix --- toml.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/toml.c b/toml.c index 1afa0a4..58ed216 100644 --- a/toml.c +++ b/toml.c @@ -1626,8 +1626,6 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) break; } - char* tsq = strstr(p, "\'\'\'"); - // the string is [p+3, q-1] int hexreq = 0; /* #hex required */ @@ -1653,9 +1651,6 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) if (hexreq) return e_syntax(ctx, lineno, "expected more hex char"); - if (tsq && tsq < q) { - return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); - } set_token(ctx, STRING, lineno, orig, q + 3 - orig); return 0; } From 836ac94afe02ca1c85f8c76700d9c2520cac7a73 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 7 Mar 2021 02:26:19 -0800 Subject: [PATCH 101/138] bug fix for timestmap --- stdex/RUN.sh | 2 +- stdex/bool1.toml | 3 +++ stdex/bool1.toml.res | 4 ++++ stdex/float1.toml | 13 ++++++++++++ stdex/float1.toml.res | 9 +++++++++ stdex/float2.toml | 1 + stdex/float2.toml.res | 2 ++ stdex/float3.toml | 2 ++ stdex/float3.toml.res | 2 ++ stdex/float4.toml | 1 + stdex/float4.toml.res | 2 ++ stdex/float5.toml | 1 + stdex/float5.toml.res | 3 +++ stdex/float6.toml | 10 ++++++++++ stdex/float6.toml.res | 8 ++++++++ stdex/int0.toml | 9 +++++++++ stdex/int0.toml.res | 10 ++++++++++ stdex/int1.toml | 12 +++++++++++ stdex/int1.toml.res | 8 ++++++++ stdex/ts1.toml | 4 ++++ stdex/ts1.toml.res | 5 +++++ stdex/ts2.toml | 1 + stdex/ts2.toml.res | 3 +++ stdex/ts3.toml | 2 ++ stdex/ts3.toml.res | 4 ++++ stdex/ts4.toml | 1 + stdex/ts4.toml.res | 3 +++ stdex/ts5.toml | 2 ++ stdex/ts5.toml.res | 4 ++++ toml.c | 46 ++++++++++++++++++++++++++----------------- toml_cat.c | 43 ++++++++++++++++++++++++++++++++++------ 31 files changed, 195 insertions(+), 25 deletions(-) create mode 100644 stdex/bool1.toml create mode 100644 stdex/bool1.toml.res create mode 100644 stdex/float1.toml create mode 100644 stdex/float1.toml.res create mode 100644 stdex/float2.toml create mode 100644 stdex/float2.toml.res create mode 100644 stdex/float3.toml create mode 100644 stdex/float3.toml.res create mode 100644 stdex/float4.toml create mode 100644 stdex/float4.toml.res create mode 100644 stdex/float5.toml create mode 100644 stdex/float5.toml.res create mode 100644 stdex/float6.toml create mode 100644 stdex/float6.toml.res create mode 100644 stdex/int0.toml create mode 100644 stdex/int0.toml.res create mode 100644 stdex/int1.toml create mode 100644 stdex/int1.toml.res create mode 100644 stdex/ts1.toml create mode 100644 stdex/ts1.toml.res create mode 100644 stdex/ts2.toml create mode 100644 stdex/ts2.toml.res create mode 100644 stdex/ts3.toml create mode 100644 stdex/ts3.toml.res create mode 100644 stdex/ts4.toml create mode 100644 stdex/ts4.toml.res create mode 100644 stdex/ts5.toml create mode 100644 stdex/ts5.toml.res diff --git a/stdex/RUN.sh b/stdex/RUN.sh index 1391e7c..8395baf 100644 --- a/stdex/RUN.sh +++ b/stdex/RUN.sh @@ -9,7 +9,7 @@ for i in *.toml; do echo " [FAILED]" fi else - echo " [??]" + echo " [?????]" fi done diff --git a/stdex/bool1.toml b/stdex/bool1.toml new file mode 100644 index 0000000..6a53ecc --- /dev/null +++ b/stdex/bool1.toml @@ -0,0 +1,3 @@ +bool1 = true +bool2 = false + diff --git a/stdex/bool1.toml.res b/stdex/bool1.toml.res new file mode 100644 index 0000000..76a0816 --- /dev/null +++ b/stdex/bool1.toml.res @@ -0,0 +1,4 @@ +{ + bool1 = true, + bool2 = false, +} diff --git a/stdex/float1.toml b/stdex/float1.toml new file mode 100644 index 0000000..faa5c4f --- /dev/null +++ b/stdex/float1.toml @@ -0,0 +1,13 @@ +# fractional +flt1 = +1.0 +flt2 = 3.1415 +flt3 = -0.01 + +# exponent +flt4 = 5e+22 +flt5 = 1e06 +flt6 = -2E-2 + +# both +flt7 = 6.626e-34 + diff --git a/stdex/float1.toml.res b/stdex/float1.toml.res new file mode 100644 index 0000000..a01bf36 --- /dev/null +++ b/stdex/float1.toml.res @@ -0,0 +1,9 @@ +{ + flt1 = 1.000000, + flt2 = 3.141500, + flt3 = -0.010000, + flt4 = 49999999999999995805696.000000, + flt5 = 1000000.000000, + flt6 = -0.020000, + flt7 = 0.000000, +} diff --git a/stdex/float2.toml b/stdex/float2.toml new file mode 100644 index 0000000..7744e4f --- /dev/null +++ b/stdex/float2.toml @@ -0,0 +1 @@ +invalid_float_1 = .7 diff --git a/stdex/float2.toml.res b/stdex/float2.toml.res new file mode 100644 index 0000000..9af2622 --- /dev/null +++ b/stdex/float2.toml.res @@ -0,0 +1,2 @@ +{ +ERROR: unable to decode value in table diff --git a/stdex/float3.toml b/stdex/float3.toml new file mode 100644 index 0000000..508260e --- /dev/null +++ b/stdex/float3.toml @@ -0,0 +1,2 @@ +invalid_float_2 = 7. + diff --git a/stdex/float3.toml.res b/stdex/float3.toml.res new file mode 100644 index 0000000..9af2622 --- /dev/null +++ b/stdex/float3.toml.res @@ -0,0 +1,2 @@ +{ +ERROR: unable to decode value in table diff --git a/stdex/float4.toml b/stdex/float4.toml new file mode 100644 index 0000000..c50ef3b --- /dev/null +++ b/stdex/float4.toml @@ -0,0 +1 @@ +invalid_float_3 = 3.e+20 diff --git a/stdex/float4.toml.res b/stdex/float4.toml.res new file mode 100644 index 0000000..9af2622 --- /dev/null +++ b/stdex/float4.toml.res @@ -0,0 +1,2 @@ +{ +ERROR: unable to decode value in table diff --git a/stdex/float5.toml b/stdex/float5.toml new file mode 100644 index 0000000..3c8f0aa --- /dev/null +++ b/stdex/float5.toml @@ -0,0 +1 @@ +flt8 = 224_617.445_991_228 diff --git a/stdex/float5.toml.res b/stdex/float5.toml.res new file mode 100644 index 0000000..1ffb208 --- /dev/null +++ b/stdex/float5.toml.res @@ -0,0 +1,3 @@ +{ + flt8 = 224617.445991, +} diff --git a/stdex/float6.toml b/stdex/float6.toml new file mode 100644 index 0000000..2e77cef --- /dev/null +++ b/stdex/float6.toml @@ -0,0 +1,10 @@ +# infinity +sf1 = inf # positive infinity +sf2 = +inf # positive infinity +sf3 = -inf # negative infinity + +# not a number +sf4 = nan # actual sNaN/qNaN encoding is implementation-specific +sf5 = +nan # same as `nan` +sf6 = -nan # valid, actual encoding is implementation-specific + diff --git a/stdex/float6.toml.res b/stdex/float6.toml.res new file mode 100644 index 0000000..95f0a7f --- /dev/null +++ b/stdex/float6.toml.res @@ -0,0 +1,8 @@ +{ + sf1 = inf, + sf2 = inf, + sf3 = -inf, + sf4 = nan, + sf5 = nan, + sf6 = nan, +} diff --git a/stdex/int0.toml b/stdex/int0.toml new file mode 100644 index 0000000..107a6b7 --- /dev/null +++ b/stdex/int0.toml @@ -0,0 +1,9 @@ +int1 = +99 +int2 = 42 +int3 = 0 +int4 = -17 +int5 = 1_000 +int6 = 5_349_221 +int7 = 53_49_221 # Indian number system grouping +int8 = 1_2_3_4_5 # VALID but discouraged + diff --git a/stdex/int0.toml.res b/stdex/int0.toml.res new file mode 100644 index 0000000..4e350ca --- /dev/null +++ b/stdex/int0.toml.res @@ -0,0 +1,10 @@ +{ + int1 = 99, + int2 = 42, + int3 = 0, + int4 = -17, + int5 = 1000, + int6 = 5349221, + int7 = 5349221, + int8 = 12345, +} diff --git a/stdex/int1.toml b/stdex/int1.toml new file mode 100644 index 0000000..03bf25b --- /dev/null +++ b/stdex/int1.toml @@ -0,0 +1,12 @@ +# hexadecimal with prefix `0x` +hex1 = 0xDEADBEEF +hex2 = 0xdeadbeef +hex3 = 0xdead_beef + +# octal with prefix `0o` +oct1 = 0o01234567 +oct2 = 0o755 # useful for Unix file permissions + +# binary with prefix `0b` +bin1 = 0b11010110 + diff --git a/stdex/int1.toml.res b/stdex/int1.toml.res new file mode 100644 index 0000000..3e8e1bd --- /dev/null +++ b/stdex/int1.toml.res @@ -0,0 +1,8 @@ +{ + hex1 = 3735928559, + hex2 = 3735928559, + hex3 = 3735928559, + oct1 = 342391, + oct2 = 493, + bin1 = 214, +} diff --git a/stdex/ts1.toml b/stdex/ts1.toml new file mode 100644 index 0000000..08f29f7 --- /dev/null +++ b/stdex/ts1.toml @@ -0,0 +1,4 @@ +odt1 = 1979-05-27T07:32:00Z +odt2 = 1979-05-27T00:32:00-07:00 +odt3 = 1979-05-27T00:32:00.999999-07:00 + diff --git a/stdex/ts1.toml.res b/stdex/ts1.toml.res new file mode 100644 index 0000000..4d756a7 --- /dev/null +++ b/stdex/ts1.toml.res @@ -0,0 +1,5 @@ +{ + odt1 = 1979-05-27T07:32:00Z, + odt2 = 1979-05-27T00:32:00-07:00, + odt3 = 1979-05-27T00:32:00.999-07:00, +} diff --git a/stdex/ts2.toml b/stdex/ts2.toml new file mode 100644 index 0000000..da9bd3b --- /dev/null +++ b/stdex/ts2.toml @@ -0,0 +1 @@ +odt4 = 1979-05-27 07:32:00Z diff --git a/stdex/ts2.toml.res b/stdex/ts2.toml.res new file mode 100644 index 0000000..1b5d0a8 --- /dev/null +++ b/stdex/ts2.toml.res @@ -0,0 +1,3 @@ +{ + odt4 = 1979-05-27T07:32:00Z, +} diff --git a/stdex/ts3.toml b/stdex/ts3.toml new file mode 100644 index 0000000..38700d2 --- /dev/null +++ b/stdex/ts3.toml @@ -0,0 +1,2 @@ +ldt1 = 1979-05-27T07:32:00 +ldt2 = 1979-05-27T00:32:00.999999 diff --git a/stdex/ts3.toml.res b/stdex/ts3.toml.res new file mode 100644 index 0000000..54a0438 --- /dev/null +++ b/stdex/ts3.toml.res @@ -0,0 +1,4 @@ +{ + ldt1 = 1979-05-27T07:32:00, + ldt2 = 1979-05-27T00:32:00.999, +} diff --git a/stdex/ts4.toml b/stdex/ts4.toml new file mode 100644 index 0000000..6670e5d --- /dev/null +++ b/stdex/ts4.toml @@ -0,0 +1 @@ +ld1 = 1979-05-27 diff --git a/stdex/ts4.toml.res b/stdex/ts4.toml.res new file mode 100644 index 0000000..473b6c2 --- /dev/null +++ b/stdex/ts4.toml.res @@ -0,0 +1,3 @@ +{ + ld1 = 1979-05-27, +} diff --git a/stdex/ts5.toml b/stdex/ts5.toml new file mode 100644 index 0000000..dbd058a --- /dev/null +++ b/stdex/ts5.toml @@ -0,0 +1,2 @@ +lt1 = 07:32:00 +lt2 = 00:32:00.999999 diff --git a/stdex/ts5.toml.res b/stdex/ts5.toml.res new file mode 100644 index 0000000..cd5b62e --- /dev/null +++ b/stdex/ts5.toml.res @@ -0,0 +1,4 @@ +{ + lt1 = 07:32:00, + lt2 = 00:32:00.999, +} diff --git a/toml.c b/toml.c index 58ed216..df93354 100644 --- a/toml.c +++ b/toml.c @@ -1079,7 +1079,7 @@ static int parse_keyval(context_t* ctx, toml_table_t* tab) if (eat_token(ctx, STRING, 1, FLINE)) return -1; if (ctx->tok.tok == DOT) { - /* handle inline dotted key. + /* handle inline dotted key. e.g. physical.color = "orange" physical.shape = "round" @@ -2073,9 +2073,14 @@ int toml_rtod_ex(toml_raw_t src, double* ret_, char* buf, int buflen) if (s[0] == '_') return -1; - /* disallow +.99 */ - if (s[0] == '.') - return -1; + /* decimal point, if used, must be surrounded by at least one digit on each side */ + { + char* dot = strchr(s, '.'); + if (dot) { + if (dot == s || !isdigit(dot[-1]) || !isdigit(dot[1])) + return -1; + } + } /* zero must be followed by . or 'e', or NUL */ if (s[0] == '0' && s[1] && !strchr("eE.", s[1])) @@ -2084,28 +2089,17 @@ int toml_rtod_ex(toml_raw_t src, double* ret_, char* buf, int buflen) /* just strip underscores and pass to strtod */ while (*s && p < q) { int ch = *s++; - switch (ch) { - case '.': - if (s[-2] == '_') return -1; - if (s[0] == '_') return -1; - break; - case '_': + if (ch == '_') { // disallow '__' if (s[0] == '_') return -1; + // disallow last char '_' + if (s[0] == 0) return -1; continue; /* skip _ */ - default: - break; } *p++ = ch; } if (*s || p == q) return -1; /* reached end of string or buffer is full? */ - /* last char cannot be '_' */ - if (s[-1] == '_') return -1; - - if (p != buf && p[-1] == '.') - return -1; /* no trailing zero */ - /* cap with NUL */ *p = 0; @@ -2219,6 +2213,14 @@ toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx) ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); if (ret.ok) { *ret.u.ts = ts; + if (ret.u.ts->year) ret.u.ts->year = &ret.u.ts->__buffer.year; + if (ret.u.ts->month) ret.u.ts->month = &ret.u.ts->__buffer.month; + if (ret.u.ts->day) ret.u.ts->day = &ret.u.ts->__buffer.day; + if (ret.u.ts->hour) ret.u.ts->hour = &ret.u.ts->__buffer.hour; + if (ret.u.ts->minute) ret.u.ts->minute = &ret.u.ts->__buffer.minute; + if (ret.u.ts->second) ret.u.ts->second = &ret.u.ts->__buffer.second; + if (ret.u.ts->millisec) ret.u.ts->millisec = &ret.u.ts->__buffer.millisec; + if (ret.u.ts->z) ret.u.ts->z = ret.u.ts->__buffer.z; } } return ret; @@ -2269,6 +2271,14 @@ toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key) ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); if (ret.ok) { *ret.u.ts = ts; + if (ret.u.ts->year) ret.u.ts->year = &ret.u.ts->__buffer.year; + if (ret.u.ts->month) ret.u.ts->month = &ret.u.ts->__buffer.month; + if (ret.u.ts->day) ret.u.ts->day = &ret.u.ts->__buffer.day; + if (ret.u.ts->hour) ret.u.ts->hour = &ret.u.ts->__buffer.hour; + if (ret.u.ts->minute) ret.u.ts->minute = &ret.u.ts->__buffer.minute; + if (ret.u.ts->second) ret.u.ts->second = &ret.u.ts->__buffer.second; + if (ret.u.ts->millisec) ret.u.ts->millisec = &ret.u.ts->__buffer.millisec; + if (ret.u.ts->z) ret.u.ts->z = ret.u.ts->__buffer.z; } } return ret; diff --git a/toml_cat.c b/toml_cat.c index 6292fa0..5fe4ac5 100644 --- a/toml_cat.c +++ b/toml_cat.c @@ -157,19 +157,35 @@ static void print_table(toml_table_t* curtab) d = toml_double_in(curtab, key); if (d.ok) { prindent(); - printf("%s = %g,\n", key, d.u.d); + printf("%s = %f,\n", key, d.u.d); continue; } d = toml_timestamp_in(curtab, key); if (d.ok) { prindent(); - printf(" %s = %s,\n", key, toml_raw_in(curtab, key)); + printf("%s = ", key); + if (d.u.ts->year) { + printf("%04d-%02d-%02d%s", *d.u.ts->year, *d.u.ts->month, *d.u.ts->day, + d.u.ts->hour ? "T" : ""); + } + if (d.u.ts->hour) { + printf("%02d:%02d:%02d", *d.u.ts->hour, *d.u.ts->minute, *d.u.ts->second); + if (d.u.ts->millisec) { + printf(".%d", *d.u.ts->millisec); + } + if (d.u.ts->z) { + printf("%s", d.u.ts->z); + } + } + printf(",\n"); free(d.u.ts); continue; } - abort(); + fflush(stdout); + fprintf(stderr, "ERROR: unable to decode value in table\n"); + exit(1); } } @@ -231,19 +247,34 @@ static void print_array(toml_array_t* curarr) d = toml_double_at(curarr, i); if (d.ok) { prindent(); - printf("%g,\n", d.u.d); + printf("%f,\n", d.u.d); continue; } d = toml_timestamp_at(curarr, i); if (d.ok) { prindent(); - printf("%s,\n", toml_raw_at(curarr, i)); + if (d.u.ts->year) { + printf("%04d-%02d-%02d%s", *d.u.ts->year, *d.u.ts->month, *d.u.ts->day, + d.u.ts->hour ? "T" : ""); + } + if (d.u.ts->hour) { + printf("%02d:%02d:%02d", *d.u.ts->hour, *d.u.ts->minute, *d.u.ts->second); + if (d.u.ts->millisec) { + printf(".%d", *d.u.ts->millisec); + } + if (d.u.ts->z) { + printf("%s", d.u.ts->z); + } + } + printf(",\n"); free(d.u.ts); continue; } - abort(); + fflush(stdout); + fprintf(stderr, "ERROR: unable to decode value in array\n"); + exit(1); } } From 937d88e0097cbb2cc875d615d09c3677d18be7c6 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 7 Mar 2021 02:29:43 -0800 Subject: [PATCH 102/138] more tests --- stdex/arr1.toml | 13 +++++++++++ stdex/arr1.toml.res | 56 +++++++++++++++++++++++++++++++++++++++++++++ stdex/arr2.toml | 8 +++++++ stdex/arr2.toml.res | 11 +++++++++ 4 files changed, 88 insertions(+) create mode 100644 stdex/arr1.toml create mode 100644 stdex/arr1.toml.res create mode 100644 stdex/arr2.toml create mode 100644 stdex/arr2.toml.res diff --git a/stdex/arr1.toml b/stdex/arr1.toml new file mode 100644 index 0000000..ce497e6 --- /dev/null +++ b/stdex/arr1.toml @@ -0,0 +1,13 @@ +integers = [ 1, 2, 3 ] +colors = [ "red", "yellow", "green" ] +nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ] +nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ] +string_array = [ "all", 'strings', """are the same""", '''type''' ] + +# Mixed-type arrays are allowed +numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ] +contributors = [ + "Foo Bar ", + { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" } +] + diff --git a/stdex/arr1.toml.res b/stdex/arr1.toml.res new file mode 100644 index 0000000..a3177b0 --- /dev/null +++ b/stdex/arr1.toml.res @@ -0,0 +1,56 @@ +{ + integers = [ + 1, + 2, + 3, + ], + colors = [ + "red", + "yellow", + "green", + ], + nested_arrays_of_ints = [ + [ + 1, + 2, + ], + [ + 3, + 4, + 5, + ], + ], + nested_mixed_array = [ + [ + 1, + 2, + ], + [ + "a", + "b", + "c", + ], + ], + string_array = [ + "all", + "strings", + "are the same", + "type", + ], + numbers = [ + 0.100000, + 0.200000, + 0.500000, + 1, + 2, + 5, + ], + contributors = [ + "Foo Bar ", + { + name = "Baz Qux", + email = "bazqux@example.com", + url = "https://example.com/bazqux", + }, + ], +} diff --git a/stdex/arr2.toml b/stdex/arr2.toml new file mode 100644 index 0000000..6acd9ca --- /dev/null +++ b/stdex/arr2.toml @@ -0,0 +1,8 @@ +integers2 = [ + 1, 2, 3 +] + +integers3 = [ + 1, + 2, # this is ok +] diff --git a/stdex/arr2.toml.res b/stdex/arr2.toml.res new file mode 100644 index 0000000..af381cf --- /dev/null +++ b/stdex/arr2.toml.res @@ -0,0 +1,11 @@ +{ + integers2 = [ + 1, + 2, + 3, + ], + integers3 = [ + 1, + 2, + ], +} From dbc1ef26d603e98dbdbd39cc93d80cf60534b2ce Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 7 Mar 2021 17:28:41 -0800 Subject: [PATCH 103/138] more tests --- stdex/inlinetab1.toml | 3 +++ stdex/inlinetab1.toml.res | 15 +++++++++++++++ stdex/inlinetab2.toml | 3 +++ stdex/inlinetab2.toml.res | 1 + stdex/inlinetab3.toml | 3 +++ stdex/inlinetab3.toml.res | 1 + stdex/tab01.toml | 7 +++++++ stdex/tab01.toml.res | 10 ++++++++++ stdex/tab02.toml | 2 ++ stdex/tab02.toml.res | 9 +++++++++ stdex/tab03.toml | 4 ++++ stdex/tab03.toml.res | 26 ++++++++++++++++++++++++++ stdex/tab04.toml | 6 ++++++ stdex/tab04.toml.res | 10 ++++++++++ stdex/tab05.toml | 7 +++++++ stdex/tab05.toml.res | 1 + stdex/tab06.toml | 7 +++++++ stdex/tab06.toml.res | 1 + stdex/tab07.toml | 4 ++++ stdex/tab07.toml.res | 10 ++++++++++ stdex/tab08.toml | 8 ++++++++ stdex/tab08.toml.res | 8 ++++++++ stdex/tab09.toml | 7 +++++++ stdex/tab09.toml.res | 10 ++++++++++ stdex/tab10.toml | 5 +++++ stdex/tab10.toml.res | 1 + stdex/tab11.toml | 9 +++++++++ stdex/tab11.toml.res | 13 +++++++++++++ toml.c | 22 ++++++++++++++++++---- 29 files changed, 209 insertions(+), 4 deletions(-) create mode 100644 stdex/inlinetab1.toml create mode 100644 stdex/inlinetab1.toml.res create mode 100644 stdex/inlinetab2.toml create mode 100644 stdex/inlinetab2.toml.res create mode 100644 stdex/inlinetab3.toml create mode 100644 stdex/inlinetab3.toml.res create mode 100644 stdex/tab01.toml create mode 100644 stdex/tab01.toml.res create mode 100644 stdex/tab02.toml create mode 100644 stdex/tab02.toml.res create mode 100644 stdex/tab03.toml create mode 100644 stdex/tab03.toml.res create mode 100644 stdex/tab04.toml create mode 100644 stdex/tab04.toml.res create mode 100644 stdex/tab05.toml create mode 100644 stdex/tab05.toml.res create mode 100644 stdex/tab06.toml create mode 100644 stdex/tab06.toml.res create mode 100644 stdex/tab07.toml create mode 100644 stdex/tab07.toml.res create mode 100644 stdex/tab08.toml create mode 100644 stdex/tab08.toml.res create mode 100644 stdex/tab09.toml create mode 100644 stdex/tab09.toml.res create mode 100644 stdex/tab10.toml create mode 100644 stdex/tab10.toml.res create mode 100644 stdex/tab11.toml create mode 100644 stdex/tab11.toml.res diff --git a/stdex/inlinetab1.toml b/stdex/inlinetab1.toml new file mode 100644 index 0000000..26062b5 --- /dev/null +++ b/stdex/inlinetab1.toml @@ -0,0 +1,3 @@ +name = { first = "Tom", last = "Preston-Werner" } +point = { x = 1, y = 2 } +animal = { type.name = "pug" } diff --git a/stdex/inlinetab1.toml.res b/stdex/inlinetab1.toml.res new file mode 100644 index 0000000..7553b02 --- /dev/null +++ b/stdex/inlinetab1.toml.res @@ -0,0 +1,15 @@ +{ + name = { + first = "Tom", + last = "Preston-Werner", + }, + point = { + x = 1, + y = 2, + }, + animal = { + type = { + name = "pug", + }, + }, +} diff --git a/stdex/inlinetab2.toml b/stdex/inlinetab2.toml new file mode 100644 index 0000000..7689e14 --- /dev/null +++ b/stdex/inlinetab2.toml @@ -0,0 +1,3 @@ +[product] +type = { name = "Nail" } +type.edible = false # INVALID diff --git a/stdex/inlinetab2.toml.res b/stdex/inlinetab2.toml.res new file mode 100644 index 0000000..9684a3d --- /dev/null +++ b/stdex/inlinetab2.toml.res @@ -0,0 +1 @@ +ERROR: line 3: cannot insert new entry into existing table diff --git a/stdex/inlinetab3.toml b/stdex/inlinetab3.toml new file mode 100644 index 0000000..d6937eb --- /dev/null +++ b/stdex/inlinetab3.toml @@ -0,0 +1,3 @@ +[product] +type.name = "Nail" +type = { edible = false } # INVALID diff --git a/stdex/inlinetab3.toml.res b/stdex/inlinetab3.toml.res new file mode 100644 index 0000000..0a6a07c --- /dev/null +++ b/stdex/inlinetab3.toml.res @@ -0,0 +1 @@ +ERROR: line 3: key exists diff --git a/stdex/tab01.toml b/stdex/tab01.toml new file mode 100644 index 0000000..6b4884c --- /dev/null +++ b/stdex/tab01.toml @@ -0,0 +1,7 @@ +[table-1] +key1 = "some string" +key2 = 123 + +[table-2] +key1 = "another string" +key2 = 456 diff --git a/stdex/tab01.toml.res b/stdex/tab01.toml.res new file mode 100644 index 0000000..0418849 --- /dev/null +++ b/stdex/tab01.toml.res @@ -0,0 +1,10 @@ +{ + table-1 = { + key1 = "some string", + key2 = 123, + }, + table-2 = { + key1 = "another string", + key2 = 456, + }, +} diff --git a/stdex/tab02.toml b/stdex/tab02.toml new file mode 100644 index 0000000..32cbe79 --- /dev/null +++ b/stdex/tab02.toml @@ -0,0 +1,2 @@ +[dog."tater.man"] +type.name = "pug" diff --git a/stdex/tab02.toml.res b/stdex/tab02.toml.res new file mode 100644 index 0000000..82cfae1 --- /dev/null +++ b/stdex/tab02.toml.res @@ -0,0 +1,9 @@ +{ + dog = { + tater.man = { + type = { + name = "pug", + }, + }, + }, +} diff --git a/stdex/tab03.toml b/stdex/tab03.toml new file mode 100644 index 0000000..0b10db3 --- /dev/null +++ b/stdex/tab03.toml @@ -0,0 +1,4 @@ +[a.b.c] # this is best practice +[ d.e.f ] # same as [d.e.f] +[ g . h . i ] # same as [g.h.i] +[ j . "ʞ" . 'l' ] # same as [j."ʞ".'l'] diff --git a/stdex/tab03.toml.res b/stdex/tab03.toml.res new file mode 100644 index 0000000..983d6cb --- /dev/null +++ b/stdex/tab03.toml.res @@ -0,0 +1,26 @@ +{ + a = { + b = { + c = { + }, + }, + }, + d = { + e = { + f = { + }, + }, + }, + g = { + h = { + i = { + }, + }, + }, + j = { + ʞ = { + l = { + }, + }, + }, +} diff --git a/stdex/tab04.toml b/stdex/tab04.toml new file mode 100644 index 0000000..256e6c0 --- /dev/null +++ b/stdex/tab04.toml @@ -0,0 +1,6 @@ +# [x] you +# [x.y] don't +# [x.y.z] need these +[x.y.z.w] # for this to work + +[x] # defining a super-table afterward is ok diff --git a/stdex/tab04.toml.res b/stdex/tab04.toml.res new file mode 100644 index 0000000..718d94a --- /dev/null +++ b/stdex/tab04.toml.res @@ -0,0 +1,10 @@ +{ + x = { + y = { + z = { + w = { + }, + }, + }, + }, +} diff --git a/stdex/tab05.toml b/stdex/tab05.toml new file mode 100644 index 0000000..0704ba7 --- /dev/null +++ b/stdex/tab05.toml @@ -0,0 +1,7 @@ +# DO NOT DO THIS + +[fruit] +apple = "red" + +[fruit] +orange = "orange" diff --git a/stdex/tab05.toml.res b/stdex/tab05.toml.res new file mode 100644 index 0000000..b57e247 --- /dev/null +++ b/stdex/tab05.toml.res @@ -0,0 +1 @@ +ERROR: line 6: key exists diff --git a/stdex/tab06.toml b/stdex/tab06.toml new file mode 100644 index 0000000..e58bf8e --- /dev/null +++ b/stdex/tab06.toml @@ -0,0 +1,7 @@ +# DO NOT DO THIS EITHER + +[fruit] +apple = "red" + +[fruit.apple] +texture = "smooth" diff --git a/stdex/tab06.toml.res b/stdex/tab06.toml.res new file mode 100644 index 0000000..b57e247 --- /dev/null +++ b/stdex/tab06.toml.res @@ -0,0 +1 @@ +ERROR: line 6: key exists diff --git a/stdex/tab07.toml b/stdex/tab07.toml new file mode 100644 index 0000000..03fe3a3 --- /dev/null +++ b/stdex/tab07.toml @@ -0,0 +1,4 @@ +# VALID BUT DISCOURAGED +[fruit.apple] +[animal] +[fruit.orange] diff --git a/stdex/tab07.toml.res b/stdex/tab07.toml.res new file mode 100644 index 0000000..239ced9 --- /dev/null +++ b/stdex/tab07.toml.res @@ -0,0 +1,10 @@ +{ + fruit = { + apple = { + }, + orange = { + }, + }, + animal = { + }, +} diff --git a/stdex/tab08.toml b/stdex/tab08.toml new file mode 100644 index 0000000..c57a229 --- /dev/null +++ b/stdex/tab08.toml @@ -0,0 +1,8 @@ +# Top-level table begins. +name = "Fido" +breed = "pug" + +# Top-level table ends. +[owner] +name = "Regina Dogman" +member_since = 1999-08-04 diff --git a/stdex/tab08.toml.res b/stdex/tab08.toml.res new file mode 100644 index 0000000..64371ae --- /dev/null +++ b/stdex/tab08.toml.res @@ -0,0 +1,8 @@ +{ + name = "Fido", + breed = "pug", + owner = { + name = "Regina Dogman", + member_since = 1999-08-04, + }, +} diff --git a/stdex/tab09.toml b/stdex/tab09.toml new file mode 100644 index 0000000..d5a2c11 --- /dev/null +++ b/stdex/tab09.toml @@ -0,0 +1,7 @@ +fruit.apple.color = "red" +# Defines a table named fruit +# Defines a table named fruit.apple + +fruit.apple.taste.sweet = true +# Defines a table named fruit.apple.taste +# fruit and fruit.apple were already created diff --git a/stdex/tab09.toml.res b/stdex/tab09.toml.res new file mode 100644 index 0000000..9346469 --- /dev/null +++ b/stdex/tab09.toml.res @@ -0,0 +1,10 @@ +{ + fruit = { + apple = { + color = "red", + taste = { + sweet = true, + }, + }, + }, +} diff --git a/stdex/tab10.toml b/stdex/tab10.toml new file mode 100644 index 0000000..9eac5f6 --- /dev/null +++ b/stdex/tab10.toml @@ -0,0 +1,5 @@ +[fruit] +apple.color = "red" +apple.taste.sweet = true + +[fruit.apple] # INVALID diff --git a/stdex/tab10.toml.res b/stdex/tab10.toml.res new file mode 100644 index 0000000..eb9b163 --- /dev/null +++ b/stdex/tab10.toml.res @@ -0,0 +1 @@ +ERROR: line 5: key exists diff --git a/stdex/tab11.toml b/stdex/tab11.toml new file mode 100644 index 0000000..ae2d65b --- /dev/null +++ b/stdex/tab11.toml @@ -0,0 +1,9 @@ +[fruit] +apple.color = "red" +apple.taste.sweet = true + +# [fruit.apple] # INVALID +# [fruit.apple.taste] # INVALID + +[fruit.apple.texture] # you can add sub-tables +smooth = true diff --git a/stdex/tab11.toml.res b/stdex/tab11.toml.res new file mode 100644 index 0000000..914481b --- /dev/null +++ b/stdex/tab11.toml.res @@ -0,0 +1,13 @@ +{ + fruit = { + apple = { + color = "red", + taste = { + sweet = true, + }, + texture = { + smooth = true, + }, + }, + }, +} diff --git a/toml.c b/toml.c index df93354..e89bade 100644 --- a/toml.c +++ b/toml.c @@ -288,8 +288,9 @@ struct toml_array_t { struct toml_table_t { - const char* key; /* key to this table */ + const char* key; /* key to this table */ bool implicit; /* table was created implicitly */ + bool readonly; /* no more modification allowed */ /* key-values in the table */ int nkval; @@ -391,6 +392,12 @@ static int e_keyexists(context_t* ctx, int lineno) return -1; } +static int e_forbid(context_t* ctx, int lineno, const char* msg) +{ + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); + return -1; +} + static void* expand(void* p, int sz, int newsz) { void* s = MALLOC(newsz); @@ -926,7 +933,7 @@ static inline int eat_token(context_t* ctx, tokentype_t typ, int isdotspecial, c /* We are at '{ ... }'. * Parse the table. */ -static int parse_table(context_t* ctx, toml_table_t* tab) +static int parse_inline_table(context_t* ctx, toml_table_t* tab) { if (eat_token(ctx, LBRACE, 1, FLINE)) return -1; @@ -959,6 +966,9 @@ static int parse_table(context_t* ctx, toml_table_t* tab) if (eat_token(ctx, RBRACE, 1, FLINE)) return -1; + + tab->readonly = 1; + return 0; } @@ -1045,7 +1055,7 @@ static int parse_array(context_t* ctx, toml_array_t* arr) toml_table_t* subtab = create_table_in_array(ctx, arr); if (!subtab) return -1; - if (parse_table(ctx, subtab)) return -1; + if (parse_inline_table(ctx, subtab)) return -1; break; } @@ -1075,6 +1085,10 @@ static int parse_array(context_t* ctx, toml_array_t* arr) */ static int parse_keyval(context_t* ctx, toml_table_t* tab) { + if (tab->readonly) { + return e_forbid(ctx, ctx->tok.lineno, "cannot insert new entry into existing table"); + } + token_t key = ctx->tok; if (eat_token(ctx, STRING, 1, FLINE)) return -1; @@ -1135,7 +1149,7 @@ static int parse_keyval(context_t* ctx, toml_table_t* tab) { /* key = { table } */ toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); if (!nxttab) return -1; - if (parse_table(ctx, nxttab)) return -1; + if (parse_inline_table(ctx, nxttab)) return -1; return 0; } From 369fd2451b775af0283ac4febdda38425df3a320 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 7 Mar 2021 17:41:18 -0800 Subject: [PATCH 104/138] more tests --- stdex/arrtab1.toml | 11 +++++++++++ stdex/arrtab1.toml.res | 15 +++++++++++++++ stdex/arrtab2.toml | 19 +++++++++++++++++++ stdex/arrtab2.toml.res | 27 +++++++++++++++++++++++++++ stdex/arrtab3.toml | 8 ++++++++ stdex/arrtab3.toml.res | 1 + stdex/arrtab4.toml | 4 ++++ stdex/arrtab4.toml.res | 1 + stdex/arrtab5.toml | 11 +++++++++++ stdex/arrtab5.toml.res | 1 + stdex/arrtab6.toml | 14 ++++++++++++++ stdex/arrtab6.toml.res | 1 + stdex/arrtab7.toml | 3 +++ stdex/arrtab7.toml.res | 19 +++++++++++++++++++ 14 files changed, 135 insertions(+) create mode 100644 stdex/arrtab1.toml create mode 100644 stdex/arrtab1.toml.res create mode 100644 stdex/arrtab2.toml create mode 100644 stdex/arrtab2.toml.res create mode 100644 stdex/arrtab3.toml create mode 100644 stdex/arrtab3.toml.res create mode 100644 stdex/arrtab4.toml create mode 100644 stdex/arrtab4.toml.res create mode 100644 stdex/arrtab5.toml create mode 100644 stdex/arrtab5.toml.res create mode 100644 stdex/arrtab6.toml create mode 100644 stdex/arrtab6.toml.res create mode 100644 stdex/arrtab7.toml create mode 100644 stdex/arrtab7.toml.res diff --git a/stdex/arrtab1.toml b/stdex/arrtab1.toml new file mode 100644 index 0000000..544d142 --- /dev/null +++ b/stdex/arrtab1.toml @@ -0,0 +1,11 @@ +[[products]] +name = "Hammer" +sku = 738594937 + +[[products]] # empty table within the array + +[[products]] +name = "Nail" +sku = 284758393 + +color = "gray" diff --git a/stdex/arrtab1.toml.res b/stdex/arrtab1.toml.res new file mode 100644 index 0000000..4e94d8e --- /dev/null +++ b/stdex/arrtab1.toml.res @@ -0,0 +1,15 @@ +{ + products = [ + { + name = "Hammer", + sku = 738594937, + }, + { + }, + { + name = "Nail", + sku = 284758393, + color = "gray", + }, + ], +} diff --git a/stdex/arrtab2.toml b/stdex/arrtab2.toml new file mode 100644 index 0000000..7a3971f --- /dev/null +++ b/stdex/arrtab2.toml @@ -0,0 +1,19 @@ +[[fruits]] +name = "apple" + +[fruits.physical] # subtable +color = "red" +shape = "round" + +[[fruits.varieties]] # nested array of tables +name = "red delicious" + +[[fruits.varieties]] +name = "granny smith" + + +[[fruits]] +name = "banana" + +[[fruits.varieties]] +name = "plantain" diff --git a/stdex/arrtab2.toml.res b/stdex/arrtab2.toml.res new file mode 100644 index 0000000..d889196 --- /dev/null +++ b/stdex/arrtab2.toml.res @@ -0,0 +1,27 @@ +{ + fruits = [ + { + name = "apple", + varieties = [ + { + name = "red delicious", + }, + { + name = "granny smith", + }, + ], + physical = { + color = "red", + shape = "round", + }, + }, + { + name = "banana", + varieties = [ + { + name = "plantain", + }, + ], + }, + ], +} diff --git a/stdex/arrtab3.toml b/stdex/arrtab3.toml new file mode 100644 index 0000000..703130e --- /dev/null +++ b/stdex/arrtab3.toml @@ -0,0 +1,8 @@ +# INVALID TOML DOC +[fruit.physical] # subtable, but to which parent element should it belong? +color = "red" +shape = "round" + +[[fruit]] # parser must throw an error upon discovering that "fruit" is + # an array rather than a table +name = "apple" diff --git a/stdex/arrtab3.toml.res b/stdex/arrtab3.toml.res new file mode 100644 index 0000000..b57e247 --- /dev/null +++ b/stdex/arrtab3.toml.res @@ -0,0 +1 @@ +ERROR: line 6: key exists diff --git a/stdex/arrtab4.toml b/stdex/arrtab4.toml new file mode 100644 index 0000000..65b2505 --- /dev/null +++ b/stdex/arrtab4.toml @@ -0,0 +1,4 @@ +# INVALID TOML DOC +fruits = [] + +[[fruits]] # Not allowed diff --git a/stdex/arrtab4.toml.res b/stdex/arrtab4.toml.res new file mode 100644 index 0000000..4a89d92 --- /dev/null +++ b/stdex/arrtab4.toml.res @@ -0,0 +1 @@ +ERROR: line 4: array mismatch diff --git a/stdex/arrtab5.toml b/stdex/arrtab5.toml new file mode 100644 index 0000000..b36540e --- /dev/null +++ b/stdex/arrtab5.toml @@ -0,0 +1,11 @@ +# INVALID TOML DOC +[[fruits]] +name = "apple" + +[[fruits.varieties]] +name = "red delicious" + +# INVALID: This table conflicts with the previous array of tables +[fruits.varieties] +name = "granny smith" + diff --git a/stdex/arrtab5.toml.res b/stdex/arrtab5.toml.res new file mode 100644 index 0000000..617cdf1 --- /dev/null +++ b/stdex/arrtab5.toml.res @@ -0,0 +1 @@ +ERROR: line 9: key exists diff --git a/stdex/arrtab6.toml b/stdex/arrtab6.toml new file mode 100644 index 0000000..8324c88 --- /dev/null +++ b/stdex/arrtab6.toml @@ -0,0 +1,14 @@ +# INVALID TOML DOC +[[fruits]] +name = "apple" + +[[fruits.varieties]] +name = "red delicious" + +[fruits.physical] +color = "red" +shape = "round" + +# INVALID: This array of tables conflicts with the previous table +[[fruits.physical]] +color = "green" diff --git a/stdex/arrtab6.toml.res b/stdex/arrtab6.toml.res new file mode 100644 index 0000000..b9a224d --- /dev/null +++ b/stdex/arrtab6.toml.res @@ -0,0 +1 @@ +ERROR: line 13: key exists diff --git a/stdex/arrtab7.toml b/stdex/arrtab7.toml new file mode 100644 index 0000000..ba5584a --- /dev/null +++ b/stdex/arrtab7.toml @@ -0,0 +1,3 @@ +points = [ { x = 1, y = 2, z = 3 }, + { x = 7, y = 8, z = 9 }, + { x = 2, y = 4, z = 8 } ] diff --git a/stdex/arrtab7.toml.res b/stdex/arrtab7.toml.res new file mode 100644 index 0000000..aa0ef41 --- /dev/null +++ b/stdex/arrtab7.toml.res @@ -0,0 +1,19 @@ +{ + points = [ + { + x = 1, + y = 2, + z = 3, + }, + { + x = 7, + y = 8, + z = 9, + }, + { + x = 2, + y = 4, + z = 8, + }, + ], +} From 06e2fceedff563a656c4b5b5abfe5c99a214fa75 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 11 Apr 2021 15:18:32 -0700 Subject: [PATCH 105/138] speed up parse --- toml.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/toml.c b/toml.c index e89bade..9eeb6e8 100644 --- a/toml.c +++ b/toml.c @@ -1680,9 +1680,9 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) } if ('\"' == *p) { - char* tsq = strstr(p, "\'\'\'"); int hexreq = 0; /* #hex required */ int escape = 0; + int sqcnt = 0; /* count single-quote */ for (p++; *p; p++) { if (escape) { escape = 0; @@ -1699,15 +1699,15 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) if (*p == '\\') { escape = 1; continue; } if (*p == '\n') break; if (*p == '"') break; + if (*p == '\'' && ++sqcnt == 3) { + return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); + } + sqcnt = 0; } if (*p != '"') { return e_syntax(ctx, lineno, "unterminated quote"); } - if (tsq && tsq < p) { - return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); - } - set_token(ctx, STRING, lineno, orig, p + 1 - orig); return 0; } From e9bfb63807c1d87a4b74362b976420ff1d73a305 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 11 Apr 2021 15:24:10 -0700 Subject: [PATCH 106/138] updated --- test1/README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test1/README.md b/test1/README.md index bdf6a30..1a83616 100644 --- a/test1/README.md +++ b/test1/README.md @@ -4,6 +4,19 @@ How to run the tests ``` % bash build.sh % bash run.sh -77 passed, 0 failed +Test: array-mixed-types-arrays-and-ints (invalid) + +Expected an error, but no error was reported. +------------------------------------------------------------------------------- +Test: array-mixed-types-ints-and-floats (invalid) + +Expected an error, but no error was reported. +------------------------------------------------------------------------------- +Test: array-mixed-types-strings-and-ints (invalid) + +Expected an error, but no error was reported. + +129 passed, 3 failed ``` +Note: toml version 1.0 allows mixed types in arrays. From a7557174ae4fcc2b07ca360070c2424e5ff93ad6 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 11 Apr 2021 15:27:55 -0700 Subject: [PATCH 107/138] fix #52 --- toml.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/toml.c b/toml.c index 9eeb6e8..f00e48e 100644 --- a/toml.c +++ b/toml.c @@ -1699,8 +1699,11 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) if (*p == '\\') { escape = 1; continue; } if (*p == '\n') break; if (*p == '"') break; - if (*p == '\'' && ++sqcnt == 3) { - return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); + if (*p == '\'') { + if (++sqcnt == 3) { + return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); + } + continue; } sqcnt = 0; } From 45e8f3c903e109501be0b46f11131e0233bf4fc2 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 11 Apr 2021 15:36:04 -0700 Subject: [PATCH 108/138] cleanup --- toml.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/toml.c b/toml.c index f00e48e..80b5d80 100644 --- a/toml.c +++ b/toml.c @@ -1696,16 +1696,18 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) if (strchr("0123456789ABCDEF", *p)) continue; return e_syntax(ctx, lineno, "expect hex char"); } - if (*p == '\\') { escape = 1; continue; } - if (*p == '\n') break; - if (*p == '"') break; - if (*p == '\'') { - if (++sqcnt == 3) { + if (sqcnt) { + if (*p == '\'') { + if (++sqcnt < 3) continue; return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); } - continue; + sqcnt = 0; } - sqcnt = 0; + + if (*p == '\\') { escape = 1; continue; } + if (*p == '\'') { sqcnt = 1; continue; } + if (*p == '\n') break; + if (*p == '"') break; } if (*p != '"') { return e_syntax(ctx, lineno, "unterminated quote"); From 3c1107177f019e37952dfb91f48235551a49f90a Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 11 Apr 2021 18:48:41 -0700 Subject: [PATCH 109/138] simplify --- toml.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/toml.c b/toml.c index 80b5d80..e46e62e 100644 --- a/toml.c +++ b/toml.c @@ -1682,7 +1682,6 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) if ('\"' == *p) { int hexreq = 0; /* #hex required */ int escape = 0; - int sqcnt = 0; /* count single-quote */ for (p++; *p; p++) { if (escape) { escape = 0; @@ -1696,16 +1695,13 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) if (strchr("0123456789ABCDEF", *p)) continue; return e_syntax(ctx, lineno, "expect hex char"); } - if (sqcnt) { - if (*p == '\'') { - if (++sqcnt < 3) continue; + if (*p == '\\') { escape = 1; continue; } + if (*p == '\'') { + if (p[1] == '\'' && p[2] == '\'') { return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); } - sqcnt = 0; + continue; } - - if (*p == '\\') { escape = 1; continue; } - if (*p == '\'') { sqcnt = 1; continue; } if (*p == '\n') break; if (*p == '"') break; } From 22aa38e31da702f688187b9f1e63810f76ec9b9d Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 17 Apr 2021 12:55:51 -0700 Subject: [PATCH 110/138] catch unexpected use of malloc --- toml.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/toml.c b/toml.c index e46e62e..e9c39a2 100644 --- a/toml.c +++ b/toml.c @@ -50,6 +50,10 @@ void toml_set_memutil(void* (*xxmalloc)(size_t), #define MALLOC(a) ppmalloc(a) #define FREE(a) ppfree(a) +#define malloc(x) error:do-not-use---use-MALLOC-instead +#define free(x) error:do-not-use---use-FREE-instead + +#define calloc(x,y) error:do-not-use---use-CALLOC-instead static void* CALLOC(size_t nmemb, size_t sz) { int nb = sz * nmemb; @@ -61,6 +65,7 @@ static void* CALLOC(size_t nmemb, size_t sz) } +#define strdup(x) error:do-not-use---use-STRDUP-instead static char* STRDUP(const char* s) { int len = strlen(s); @@ -72,6 +77,7 @@ static char* STRDUP(const char* s) return p; } +#define strndup(x) error:do-not-use---use-STRNDUP-instead static char* STRNDUP(const char* s, size_t n) { size_t len = strnlen(s, n); @@ -85,6 +91,7 @@ static char* STRNDUP(const char* s, size_t n) + /** * Convert a char in utf8 into UCS, and store it in *ret. * Return #bytes consumed or -1 on failure. @@ -2225,7 +2232,7 @@ toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx) memset(&ret, 0, sizeof(ret)); ret.ok = (0 == toml_rtots(toml_raw_at(arr, idx), &ts)); if (ret.ok) { - ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); + ret.ok = !!(ret.u.ts = MALLOC(sizeof(*ret.u.ts))); if (ret.ok) { *ret.u.ts = ts; if (ret.u.ts->year) ret.u.ts->year = &ret.u.ts->__buffer.year; @@ -2283,7 +2290,7 @@ toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key) memset(&ret, 0, sizeof(ret)); ret.ok = (0 == toml_rtots(toml_raw_in(arr, key), &ts)); if (ret.ok) { - ret.ok = !!(ret.u.ts = malloc(sizeof(*ret.u.ts))); + ret.ok = !!(ret.u.ts = MALLOC(sizeof(*ret.u.ts))); if (ret.ok) { *ret.u.ts = ts; if (ret.u.ts->year) ret.u.ts->year = &ret.u.ts->__buffer.year; From d7dd697c35ead435733764c63d47f7cbf00b8fa9 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 17 Apr 2021 13:06:59 -0700 Subject: [PATCH 111/138] minor --- toml.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/toml.c b/toml.c index e9c39a2..169172d 100644 --- a/toml.c +++ b/toml.c @@ -2034,7 +2034,7 @@ int toml_rtoi(toml_raw_t src, int64_t* ret_) if (s[0] == '_') return -1; - /* if 0 ... */ + /* if 0* ... */ if ('0' == s[0]) { switch (s[1]) { case 'x': base = 16; s += 2; break; @@ -2050,20 +2050,18 @@ int toml_rtoi(toml_raw_t src, int64_t* ret_) /* just strip underscores and pass to strtoll */ while (*s && p < q) { int ch = *s++; - switch (ch) { - case '_': + if (ch == '_') { // disallow '__' if (s[0] == '_') return -1; + // numbers cannot end with '_' + if (s[0] == '\0') return -1; continue; /* skip _ */ - default: - break; } *p++ = ch; } - if (*s || p == q) return -1; - /* last char cannot be '_' */ - if (s[-1] == '_') return -1; + // if not at end-of-string or we ran out of buffer ... + if (*s || p == q) return -1; /* cap with NUL */ *p = 0; From 789930f7c97223abbbae702274d08ca949849eb7 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Fri, 4 Jun 2021 17:09:25 -0700 Subject: [PATCH 112/138] when parsing millisec in timestamp, force use of base 10 in strtol() --- toml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml.c b/toml.c index 169172d..cad2657 100644 --- a/toml.c +++ b/toml.c @@ -1944,7 +1944,7 @@ int toml_rtots(toml_raw_t src_, toml_timestamp_t* ret) char* qq; p++; errno = 0; - *millisec = strtol(p, &qq, 0); + *millisec = strtol(p, &qq, 10); if (errno) { return -1; } From 24e4472b44a200a6507e53a84198b871f437a5e7 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 4 Jul 2021 19:10:32 -0700 Subject: [PATCH 113/138] tabify --- toml_cat.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/toml_cat.c b/toml_cat.c index 5fe4ac5..55133b9 100644 --- a/toml_cat.c +++ b/toml_cat.c @@ -39,8 +39,8 @@ typedef struct node_t node_t; struct node_t { - const char* key; - toml_table_t* tab; + const char* key; + toml_table_t* tab; }; node_t stack[20]; @@ -97,12 +97,12 @@ static void print_array(toml_array_t* arr); static void print_table(toml_table_t* curtab) { toml_datum_t d; - int i; - const char* key; - toml_array_t* arr; - toml_table_t* tab; + int i; + const char* key; + toml_array_t* arr; + toml_table_t* tab; - for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { + for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { if (0 != (arr = toml_array_in(curtab, key))) { prindent(); @@ -186,15 +186,15 @@ static void print_table(toml_table_t* curtab) fflush(stdout); fprintf(stderr, "ERROR: unable to decode value in table\n"); exit(1); - } + } } static void print_array(toml_array_t* curarr) { toml_datum_t d; - toml_array_t* arr; - toml_table_t* tab; + toml_array_t* arr; + toml_table_t* tab; const int n = toml_array_nelem(curarr); for (int i = 0; i < n; i++) { @@ -283,34 +283,34 @@ static void print_array(toml_array_t* curarr) static void cat(FILE* fp) { - char errbuf[200]; + char errbuf[200]; - toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); - if (!tab) { + toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); + if (!tab) { fprintf(stderr, "ERROR: %s\n", errbuf); return; - } + } - stack[stacktop].tab = tab; - stack[stacktop].key = ""; - stacktop++; + stack[stacktop].tab = tab; + stack[stacktop].key = ""; + stacktop++; printf("{\n"); indent++; - print_table(tab); + print_table(tab); indent--; printf("}\n"); - stacktop--; + stacktop--; - toml_free(tab); + toml_free(tab); } int main(int argc, const char* argv[]) { - int i; - if (argc == 1) { + int i; + if (argc == 1) { cat(stdin); - } else { + } else { for (i = 1; i < argc; i++) { FILE* fp = fopen(argv[i], "r"); @@ -322,6 +322,6 @@ int main(int argc, const char* argv[]) cat(fp); fclose(fp); } - } - return 0; + } + return 0; } From 511749ebb97102b98896fe5c91ca169259a065a7 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 4 Jul 2021 19:20:08 -0700 Subject: [PATCH 114/138] fix bug in millisec parsing --- toml.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/toml.c b/toml.c index cad2657..5c73773 100644 --- a/toml.c +++ b/toml.c @@ -1900,6 +1900,8 @@ toml_table_t* toml_table_at(const toml_array_t* arr, int idx) } +static int parse_millisec(const char* p, const char** endp); + int toml_rtots(toml_raw_t src_, toml_timestamp_t* ret) { if (! src_) return -1; @@ -1941,17 +1943,9 @@ int toml_rtots(toml_raw_t src_, toml_timestamp_t* ret) /* optionally, parse millisec */ p += 8; if (*p == '.') { - char* qq; - p++; - errno = 0; - *millisec = strtol(p, &qq, 10); - if (errno) { - return -1; - } - while (*millisec > 999) { - *millisec /= 10; - } - + p++; /* skip '.' */ + const char* qq; + *millisec = parse_millisec(p, &qq); ret->millisec = millisec; p = qq; } @@ -2303,3 +2297,15 @@ toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key) } return ret; } + + +static int parse_millisec(const char* p, const char** endp) +{ + int ret = 0; + int unit = 100; /* unit in millisec */ + for ( ; '0' <= *p && *p <= '9'; p++, unit /= 10) { + ret += (*p - '0') * unit; + } + *endp = p; + return ret; +} From bf0447ab499932752679f1abb54e833c9fba4092 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 4 Jul 2021 19:25:24 -0700 Subject: [PATCH 115/138] add timestamp test --- stdex/ts1.toml | 1 + stdex/ts1.toml.res | 1 + 2 files changed, 2 insertions(+) diff --git a/stdex/ts1.toml b/stdex/ts1.toml index 08f29f7..f020b6e 100644 --- a/stdex/ts1.toml +++ b/stdex/ts1.toml @@ -1,4 +1,5 @@ odt1 = 1979-05-27T07:32:00Z odt2 = 1979-05-27T00:32:00-07:00 odt3 = 1979-05-27T00:32:00.999999-07:00 +odt4 = 1979-05-27T00:32:00.1-07:00 diff --git a/stdex/ts1.toml.res b/stdex/ts1.toml.res index 4d756a7..d26c9ae 100644 --- a/stdex/ts1.toml.res +++ b/stdex/ts1.toml.res @@ -2,4 +2,5 @@ odt1 = 1979-05-27T07:32:00Z, odt2 = 1979-05-27T00:32:00-07:00, odt3 = 1979-05-27T00:32:00.999-07:00, + odt4 = 1979-05-27T00:32:00.100-07:00, } From 45921ae3db96468f3bfdffd814d251a4c58147d4 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sun, 4 Jul 2021 19:41:16 -0700 Subject: [PATCH 116/138] add test for timestamp millisec --- stdex/ts1.toml | 2 +- stdex/ts1.toml.res | 2 +- toml_cat.c | 46 ++++++++++++++++++++-------------------------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/stdex/ts1.toml b/stdex/ts1.toml index f020b6e..9c15c6b 100644 --- a/stdex/ts1.toml +++ b/stdex/ts1.toml @@ -1,5 +1,5 @@ odt1 = 1979-05-27T07:32:00Z odt2 = 1979-05-27T00:32:00-07:00 odt3 = 1979-05-27T00:32:00.999999-07:00 -odt4 = 1979-05-27T00:32:00.1-07:00 +odt4 = 1979-05-27T00:32:00.01-07:00 diff --git a/stdex/ts1.toml.res b/stdex/ts1.toml.res index d26c9ae..2df13b0 100644 --- a/stdex/ts1.toml.res +++ b/stdex/ts1.toml.res @@ -2,5 +2,5 @@ odt1 = 1979-05-27T07:32:00Z, odt2 = 1979-05-27T00:32:00-07:00, odt3 = 1979-05-27T00:32:00.999-07:00, - odt4 = 1979-05-27T00:32:00.100-07:00, + odt4 = 1979-05-27T00:32:00.010-07:00, } diff --git a/toml_cat.c b/toml_cat.c index 55133b9..6203b5d 100644 --- a/toml_cat.c +++ b/toml_cat.c @@ -93,6 +93,24 @@ static void print_string(const char* s) static void print_array(toml_array_t* arr); +static void print_timestamp(toml_datum_t d) +{ + if (d.u.ts->year) { + printf("%04d-%02d-%02d%s", *d.u.ts->year, *d.u.ts->month, *d.u.ts->day, + d.u.ts->hour ? "T" : ""); + } + if (d.u.ts->hour) { + printf("%02d:%02d:%02d", *d.u.ts->hour, *d.u.ts->minute, *d.u.ts->second); + if (d.u.ts->millisec) { + printf(".%03d", *d.u.ts->millisec); + } + if (d.u.ts->z) { + printf("%s", d.u.ts->z); + } + } +} + + static void print_table(toml_table_t* curtab) { @@ -165,19 +183,7 @@ static void print_table(toml_table_t* curtab) if (d.ok) { prindent(); printf("%s = ", key); - if (d.u.ts->year) { - printf("%04d-%02d-%02d%s", *d.u.ts->year, *d.u.ts->month, *d.u.ts->day, - d.u.ts->hour ? "T" : ""); - } - if (d.u.ts->hour) { - printf("%02d:%02d:%02d", *d.u.ts->hour, *d.u.ts->minute, *d.u.ts->second); - if (d.u.ts->millisec) { - printf(".%d", *d.u.ts->millisec); - } - if (d.u.ts->z) { - printf("%s", d.u.ts->z); - } - } + print_timestamp(d); printf(",\n"); free(d.u.ts); continue; @@ -254,19 +260,7 @@ static void print_array(toml_array_t* curarr) d = toml_timestamp_at(curarr, i); if (d.ok) { prindent(); - if (d.u.ts->year) { - printf("%04d-%02d-%02d%s", *d.u.ts->year, *d.u.ts->month, *d.u.ts->day, - d.u.ts->hour ? "T" : ""); - } - if (d.u.ts->hour) { - printf("%02d:%02d:%02d", *d.u.ts->hour, *d.u.ts->minute, *d.u.ts->second); - if (d.u.ts->millisec) { - printf(".%d", *d.u.ts->millisec); - } - if (d.u.ts->z) { - printf("%s", d.u.ts->z); - } - } + print_timestamp(d); printf(",\n"); free(d.u.ts); continue; From 6b49aaf86335a9515ca3add31e60f44ef6dc7bb5 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 5 Jul 2021 00:11:10 -0700 Subject: [PATCH 117/138] fix to make it run --- test1/run.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test1/run.sh b/test1/run.sh index 86c77cb..356a8cb 100644 --- a/test1/run.sh +++ b/test1/run.sh @@ -1,5 +1,5 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -export GOPATH=$DIR/goworkspace # if it isn't already set -# $GOPATH/bin/toml-test $GOPATH/bin/toml-test-decoder # e.g., run tests on my parser -$GOPATH/bin/toml-test ../toml_json +rm -f tests +ln -s ./goworkspace/pkg/mod/github.com/\!burnt\!sushi/toml-test@v0.1.0/tests +./toml-test ../toml_json From 4636173feded76df475c3286cff2469e425978ca Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 5 Jul 2021 09:51:50 -0700 Subject: [PATCH 118/138] fix print of millisec --- toml_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml_json.c b/toml_json.c index d443cb5..c2677d4 100644 --- a/toml_json.c +++ b/toml_json.c @@ -74,7 +74,7 @@ static void print_raw(const char* s) } else if (0 == toml_rtots(s, &ts)) { char millisec[10]; if (ts.millisec) - sprintf(millisec, ".%d", *ts.millisec); + sprintf(millisec, ".%03d", *ts.millisec); else millisec[0] = 0; if (ts.year && ts.hour) { From b5818182a4841460a4b8556a1e0c816c4c5ef2f4 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 14 Jul 2021 20:20:15 -0700 Subject: [PATCH 119/138] fix an overflow bug in the scanner --- toml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml.c b/toml.c index 5c73773..e495115 100644 --- a/toml.c +++ b/toml.c @@ -1723,7 +1723,7 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) /* check for timestamp without quotes */ if (0 == scan_date(p, 0, 0, 0) || 0 == scan_time(p, 0, 0, 0)) { // forward thru the timestamp - for ( ; strchr("0123456789.:+-T Z", toupper(*p)); p++); + for ( ; *p && strchr("0123456789.:+-T Z", toupper(*p)); p++); // squeeze out any spaces at end of string for ( ; p[-1] == ' '; p--); // tokenize From 208203af46bdbdb29ba199660ed78d09c220b6c5 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 15 Jul 2021 13:32:11 -0700 Subject: [PATCH 120/138] minor --- toml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml.c b/toml.c index e495115..8ec554e 100644 --- a/toml.c +++ b/toml.c @@ -1723,7 +1723,7 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) /* check for timestamp without quotes */ if (0 == scan_date(p, 0, 0, 0) || 0 == scan_time(p, 0, 0, 0)) { // forward thru the timestamp - for ( ; *p && strchr("0123456789.:+-T Z", toupper(*p)); p++); + p += strspn(p, "0123456789.:+-T Z"); // squeeze out any spaces at end of string for ( ; p[-1] == ' '; p--); // tokenize From 37954d9b20c2cd30a7635b367122bf1c9baf2511 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 25 Oct 2021 23:21:48 -0700 Subject: [PATCH 121/138] add toml_key_exists() --- LICENSE | 2 +- toml.c | 21 ++++++++++++++++++++- toml.h | 4 +++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index a3292b1..bb09e49 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 CK Tan +Copyright (c) CK Tan https://github.com/cktan/tomlc99 Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/toml.c b/toml.c index 8ec554e..89c0a26 100644 --- a/toml.c +++ b/toml.c @@ -2,7 +2,7 @@ MIT License - Copyright (c) 2017 - 2021 CK Tan + Copyright (c) CK Tan https://github.com/cktan/tomlc99 Permission is hereby granted, free of charge, to any person obtaining a copy @@ -1806,6 +1806,25 @@ const char* toml_key_in(const toml_table_t* tab, int keyidx) return 0; } +int toml_key_exists(const toml_table_t* tab, const char* key) +{ + int i; + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) + return 1; + } + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) + return 1; + } + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) + return 1; + } + return 0; +} + + toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key) { int i; diff --git a/toml.h b/toml.h index b91ef89..03adcbe 100644 --- a/toml.h +++ b/toml.h @@ -1,7 +1,7 @@ /* MIT License - Copyright (c) 2017 - 2019 CK Tan + Copyright (c) CK Tan https://github.com/cktan/tomlc99 Permission is hereby granted, free of charge, to any person obtaining a copy @@ -109,6 +109,8 @@ TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx); /* on tables: */ /* ... retrieve the key in table at keyidx. Return 0 if out of range. */ TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx); +/* ... returns 1 if key exists in tab, 0 otherwise */ +TOML_EXTERN int toml_key_exists(const toml_table_t* tab, const char* key); /* ... retrieve values using key. */ TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t* arr, const char* key); TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key); From 1d4fc82ebc4ff6314b448c47da0e94b7a8284bb1 Mon Sep 17 00:00:00 2001 From: Cameron Moore Date: Mon, 22 Nov 2021 18:51:50 -0600 Subject: [PATCH 122/138] fix toml-test build script for Go 1.17 Fixes #62 --- test1/build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test1/build.sh b/test1/build.sh index 9007489..645a271 100644 --- a/test1/build.sh +++ b/test1/build.sh @@ -2,8 +2,8 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" mkdir -p $DIR/goworkspace -export GOPATH=$DIR/goworkspace -go get github.com/BurntSushi/toml-test # install test suite -go get github.com/BurntSushi/toml/cmd/toml-test-decoder # e.g., install my parser +export GOPATH=$DIR/goworkspace +go get github.com/BurntSushi/toml-test@latest # install test suite +go install github.com/BurntSushi/toml/cmd/toml-test-decoder@latest # e.g., install my parser cp $GOPATH/bin/* . From 62320462f5f7b49543e70839079aec493667377a Mon Sep 17 00:00:00 2001 From: Toni Date: Sat, 11 Dec 2021 01:57:07 +0100 Subject: [PATCH 123/138] Avoid redefinition warnings from strdup functions (#67) --- toml.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/toml.c b/toml.c index 89c0a26..0f1a77a 100644 --- a/toml.c +++ b/toml.c @@ -65,6 +65,7 @@ static void* CALLOC(size_t nmemb, size_t sz) } +#undef strdup #define strdup(x) error:do-not-use---use-STRDUP-instead static char* STRDUP(const char* s) { @@ -77,6 +78,7 @@ static char* STRDUP(const char* s) return p; } +#undef strndup #define strndup(x) error:do-not-use---use-STRNDUP-instead static char* STRNDUP(const char* s, size_t n) { From 310f02dd67e66bdb99d20e764ff979c16ed44379 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Fri, 10 Dec 2021 16:59:47 -0800 Subject: [PATCH 124/138] comment --- toml.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/toml.c b/toml.c index 0f1a77a..19047bd 100644 --- a/toml.c +++ b/toml.c @@ -65,6 +65,7 @@ static void* CALLOC(size_t nmemb, size_t sz) } +// some old platforms define strdup macro -- drop it. #undef strdup #define strdup(x) error:do-not-use---use-STRDUP-instead static char* STRDUP(const char* s) @@ -78,6 +79,7 @@ static char* STRDUP(const char* s) return p; } +// some old platforms define strndup macro -- drop it. #undef strndup #define strndup(x) error:do-not-use---use-STRNDUP-instead static char* STRNDUP(const char* s, size_t n) From 8434e750066191e53da271d63232ba5b02e46853 Mon Sep 17 00:00:00 2001 From: ownesis <83978267+ownesis@users.noreply.github.com> Date: Sat, 11 Dec 2021 02:01:52 +0100 Subject: [PATCH 125/138] Adding libtoml.pc for pkg-config (#63) --- Makefile | 2 ++ libtoml.pc | 11 +++++++++++ 2 files changed, 13 insertions(+) create mode 100644 libtoml.pc diff --git a/Makefile b/Makefile index 0f1b5fa..93fcb29 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ HFILES = toml.h CFILES = toml.c OBJ = $(CFILES:.c=.o) EXEC = toml_json toml_cat toml_sample +PCFILE = libtoml.pc CFLAGS = -std=c99 -Wall -Wextra -fpic LIB_VERSION = 1.0 @@ -41,6 +42,7 @@ install: all install toml.h ${prefix}/include install $(LIB) ${prefix}/lib install $(LIB_SHARED) ${prefix}/lib + install $(PCFILE) /usr/lib/pkgconfig clean: rm -f *.o $(EXEC) $(LIB) $(LIB_SHARED) diff --git a/libtoml.pc b/libtoml.pc new file mode 100644 index 0000000..62e7ecb --- /dev/null +++ b/libtoml.pc @@ -0,0 +1,11 @@ +prefix=/usr/local/ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libtoml +URL: https://github.com/cktan/tomlc99/ +Description: TOML C library in c99. +Version: v1.0 +Libs: -L${libdir} -ltoml +Cflags: -I${includedir} From 64e280e20b3d46b9ddb8369011613fd7722f2b6b Mon Sep 17 00:00:00 2001 From: CK Tan Date: Thu, 16 Dec 2021 13:36:32 -0800 Subject: [PATCH 126/138] fix: Makefile install prefix missing for libtoml.pc #68 --- Makefile | 6 ++++-- libtoml.pc => libtoml.pc.sample | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) rename libtoml.pc => libtoml.pc.sample (82%) diff --git a/Makefile b/Makefile index 93fcb29..1ca63f2 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +prefix ?= /usr/local HFILES = toml.h CFILES = toml.c OBJ = $(CFILES:.c=.o) @@ -35,14 +36,15 @@ toml_cat: toml_cat.c $(LIB) toml_sample: toml_sample.c $(LIB) -prefix ?= /usr/local install: all install -d ${prefix}/include ${prefix}/lib install toml.h ${prefix}/include install $(LIB) ${prefix}/lib install $(LIB_SHARED) ${prefix}/lib - install $(PCFILE) /usr/lib/pkgconfig +ifeq "$(prefix)" "/usr/local" + install $(PCFILE) /usr/local/lib/pkgconfig +endif clean: rm -f *.o $(EXEC) $(LIB) $(LIB_SHARED) diff --git a/libtoml.pc b/libtoml.pc.sample similarity index 82% rename from libtoml.pc rename to libtoml.pc.sample index 62e7ecb..e343634 100644 --- a/libtoml.pc +++ b/libtoml.pc.sample @@ -1,4 +1,4 @@ -prefix=/usr/local/ +prefix=/usr/local exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include @@ -8,4 +8,4 @@ URL: https://github.com/cktan/tomlc99/ Description: TOML C library in c99. Version: v1.0 Libs: -L${libdir} -ltoml -Cflags: -I${includedir} +Cflags: -I${includedir} From 32c38751b9b09d5e41347d2fe9d30fd922b0e4c3 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Sat, 25 Dec 2021 23:42:50 -0800 Subject: [PATCH 127/138] format with clang-format --- .editorconfig | 4 +- toml.c | 3727 +++++++++++++++++++++++++------------------------ toml.h | 130 +- toml_cat.c | 485 +++---- toml_json.c | 319 ++--- toml_sample.c | 96 +- 6 files changed, 2401 insertions(+), 2360 deletions(-) diff --git a/.editorconfig b/.editorconfig index e46ee4c..804650e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,8 +6,8 @@ insert_final_newline = false trim_trailing_whitespace = true [*.{c,h}] -indent_style = tab -indent_size = 4 +indent_style = space +indent_size = 2 [Makefile] indent_style = tab diff --git a/toml.c b/toml.c index 19047bd..99baaf2 100644 --- a/toml.c +++ b/toml.c @@ -25,248 +25,253 @@ */ #define _POSIX_C_SOURCE 200809L +#include "toml.h" +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include #include -#include -#include "toml.h" +static void *(*ppmalloc)(size_t) = malloc; +static void (*ppfree)(void *) = free; -static void* (*ppmalloc)(size_t) = malloc; -static void (*ppfree)(void*) = free; - -void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*)) -{ - if (xxmalloc) ppmalloc = xxmalloc; - if (xxfree) ppfree = xxfree; +void toml_set_memutil(void *(*xxmalloc)(size_t), void (*xxfree)(void *)) { + if (xxmalloc) + ppmalloc = xxmalloc; + if (xxfree) + ppfree = xxfree; } +#define MALLOC(a) ppmalloc(a) +#define FREE(a) ppfree(a) -#define MALLOC(a) ppmalloc(a) -#define FREE(a) ppfree(a) +#define malloc(x) error - forbidden - use MALLOC instead +#define free(x) error - forbidden - use FREE instead +#define calloc(x, y) error - forbidden - use CALLOC instead -#define malloc(x) error:do-not-use---use-MALLOC-instead -#define free(x) error:do-not-use---use-FREE-instead - -#define calloc(x,y) error:do-not-use---use-CALLOC-instead -static void* CALLOC(size_t nmemb, size_t sz) -{ - int nb = sz * nmemb; - void* p = MALLOC(nb); - if (p) { - memset(p, 0, nb); - } - return p; +static void *CALLOC(size_t nmemb, size_t sz) { + int nb = sz * nmemb; + void *p = MALLOC(nb); + if (p) { + memset(p, 0, nb); + } + return p; } - // some old platforms define strdup macro -- drop it. #undef strdup -#define strdup(x) error:do-not-use---use-STRDUP-instead -static char* STRDUP(const char* s) -{ - int len = strlen(s); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; +#define strdup(x) error - forbidden - use STRDUP instead + +static char *STRDUP(const char *s) { + int len = strlen(s); + char *p = MALLOC(len + 1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; } // some old platforms define strndup macro -- drop it. #undef strndup -#define strndup(x) error:do-not-use---use-STRNDUP-instead -static char* STRNDUP(const char* s, size_t n) -{ - size_t len = strnlen(s, n); - char* p = MALLOC(len+1); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; +#define strndup(x) error - forbiden - use STRNDUP instead + +static char *STRNDUP(const char *s, size_t n) { + size_t len = strnlen(s, n); + char *p = MALLOC(len + 1); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; } - - - /** * Convert a char in utf8 into UCS, and store it in *ret. * Return #bytes consumed or -1 on failure. */ -int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret) -{ - const unsigned char* buf = (const unsigned char*) orig; - unsigned i = *buf++; - int64_t v; +int toml_utf8_to_ucs(const char *orig, int len, int64_t *ret) { + const unsigned char *buf = (const unsigned char *)orig; + unsigned i = *buf++; + int64_t v; - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (0 == (i >> 7)) { - if (len < 1) return -1; - v = i; - return *ret = v, 1; - } - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (0x6 == (i >> 5)) { - if (len < 2) return -1; - v = i & 0x1f; - for (int j = 0; j < 1; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (0 == (i >> 7)) { + if (len < 1) + return -1; + v = i; + return *ret = v, 1; + } + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (0x6 == (i >> 5)) { + if (len < 2) + return -1; + v = i & 0x1f; + for (int j = 0; j < 1; j++) { + i = *buf++; + if (0x2 != (i >> 6)) + return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char *)buf - orig; + } - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (0xE == (i >> 4)) { - if (len < 3) return -1; - v = i & 0x0F; - for (int j = 0; j < 2; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (0xE == (i >> 4)) { + if (len < 3) + return -1; + v = i & 0x0F; + for (int j = 0; j < 2; j++) { + i = *buf++; + if (0x2 != (i >> 6)) + return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char *)buf - orig; + } - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x1E == (i >> 3)) { - if (len < 4) return -1; - v = i & 0x07; - for (int j = 0; j < 3; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x1E == (i >> 3)) { + if (len < 4) + return -1; + v = i & 0x07; + for (int j = 0; j < 3; j++) { + i = *buf++; + if (0x2 != (i >> 6)) + return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char *)buf - orig; + } - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x3E == (i >> 2)) { - if (len < 5) return -1; - v = i & 0x03; - for (int j = 0; j < 4; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x3E == (i >> 2)) { + if (len < 5) + return -1; + v = i & 0x03; + for (int j = 0; j < 4; j++) { + i = *buf++; + if (0x2 != (i >> 6)) + return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char *)buf - orig; + } - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (0x7e == (i >> 1)) { - if (len < 6) return -1; - v = i & 0x01; - for (int j = 0; j < 5; j++) { - i = *buf++; - if (0x2 != (i >> 6)) return -1; - v = (v << 6) | (i & 0x3f); - } - return *ret = v, (const char*) buf - orig; - } - return -1; + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (0x7e == (i >> 1)) { + if (len < 6) + return -1; + v = i & 0x01; + for (int j = 0; j < 5; j++) { + i = *buf++; + if (0x2 != (i >> 6)) + return -1; + v = (v << 6) | (i & 0x3f); + } + return *ret = v, (const char *)buf - orig; + } + return -1; } - /** * Convert a UCS char to utf8 code, and return it in buf. * Return #bytes used in buf to encode the char, or * -1 on error. */ -int toml_ucs_to_utf8(int64_t code, char buf[6]) -{ - /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 */ - /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well - * as 0xfffe and 0xffff (UCS noncharacters) should not appear in - * conforming UTF-8 streams. - */ - if (0xd800 <= code && code <= 0xdfff) return -1; - if (0xfffe <= code && code <= 0xffff) return -1; +int toml_ucs_to_utf8(int64_t code, char buf[6]) { + /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 + */ + /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well + * as 0xfffe and 0xffff (UCS noncharacters) should not appear in + * conforming UTF-8 streams. + */ + if (0xd800 <= code && code <= 0xdfff) + return -1; + if (0xfffe <= code && code <= 0xffff) + return -1; - /* 0x00000000 - 0x0000007F: - 0xxxxxxx - */ - if (code < 0) return -1; - if (code <= 0x7F) { - buf[0] = (unsigned char) code; - return 1; - } + /* 0x00000000 - 0x0000007F: + 0xxxxxxx + */ + if (code < 0) + return -1; + if (code <= 0x7F) { + buf[0] = (unsigned char)code; + return 1; + } - /* 0x00000080 - 0x000007FF: - 110xxxxx 10xxxxxx - */ - if (code <= 0x000007FF) { - buf[0] = 0xc0 | (code >> 6); - buf[1] = 0x80 | (code & 0x3f); - return 2; - } + /* 0x00000080 - 0x000007FF: + 110xxxxx 10xxxxxx + */ + if (code <= 0x000007FF) { + buf[0] = 0xc0 | (code >> 6); + buf[1] = 0x80 | (code & 0x3f); + return 2; + } - /* 0x00000800 - 0x0000FFFF: - 1110xxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x0000FFFF) { - buf[0] = 0xe0 | (code >> 12); - buf[1] = 0x80 | ((code >> 6) & 0x3f); - buf[2] = 0x80 | (code & 0x3f); - return 3; - } + /* 0x00000800 - 0x0000FFFF: + 1110xxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x0000FFFF) { + buf[0] = 0xe0 | (code >> 12); + buf[1] = 0x80 | ((code >> 6) & 0x3f); + buf[2] = 0x80 | (code & 0x3f); + return 3; + } - /* 0x00010000 - 0x001FFFFF: - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x001FFFFF) { - buf[0] = 0xf0 | (code >> 18); - buf[1] = 0x80 | ((code >> 12) & 0x3f); - buf[2] = 0x80 | ((code >> 6) & 0x3f); - buf[3] = 0x80 | (code & 0x3f); - return 4; - } + /* 0x00010000 - 0x001FFFFF: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x001FFFFF) { + buf[0] = 0xf0 | (code >> 18); + buf[1] = 0x80 | ((code >> 12) & 0x3f); + buf[2] = 0x80 | ((code >> 6) & 0x3f); + buf[3] = 0x80 | (code & 0x3f); + return 4; + } - /* 0x00200000 - 0x03FFFFFF: - 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x03FFFFFF) { - buf[0] = 0xf8 | (code >> 24); - buf[1] = 0x80 | ((code >> 18) & 0x3f); - buf[2] = 0x80 | ((code >> 12) & 0x3f); - buf[3] = 0x80 | ((code >> 6) & 0x3f); - buf[4] = 0x80 | (code & 0x3f); - return 5; - } + /* 0x00200000 - 0x03FFFFFF: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x03FFFFFF) { + buf[0] = 0xf8 | (code >> 24); + buf[1] = 0x80 | ((code >> 18) & 0x3f); + buf[2] = 0x80 | ((code >> 12) & 0x3f); + buf[3] = 0x80 | ((code >> 6) & 0x3f); + buf[4] = 0x80 | (code & 0x3f); + return 5; + } - /* 0x04000000 - 0x7FFFFFFF: - 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - if (code <= 0x7FFFFFFF) { - buf[0] = 0xfc | (code >> 30); - buf[1] = 0x80 | ((code >> 24) & 0x3f); - buf[2] = 0x80 | ((code >> 18) & 0x3f); - buf[3] = 0x80 | ((code >> 12) & 0x3f); - buf[4] = 0x80 | ((code >> 6) & 0x3f); - buf[5] = 0x80 | (code & 0x3f); - return 6; - } + /* 0x04000000 - 0x7FFFFFFF: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + if (code <= 0x7FFFFFFF) { + buf[0] = 0xfc | (code >> 30); + buf[1] = 0x80 | ((code >> 24) & 0x3f); + buf[2] = 0x80 | ((code >> 18) & 0x3f); + buf[3] = 0x80 | ((code >> 12) & 0x3f); + buf[4] = 0x80 | ((code >> 6) & 0x3f); + buf[5] = 0x80 | (code & 0x3f); + return 6; + } - return -1; + return -1; } /* @@ -275,2060 +280,2100 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) */ typedef struct toml_keyval_t toml_keyval_t; struct toml_keyval_t { - const char* key; /* key to this value */ - const char* val; /* the raw value */ + const char *key; /* key to this value */ + const char *val; /* the raw value */ }; typedef struct toml_arritem_t toml_arritem_t; struct toml_arritem_t { - int valtype; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */ - char* val; - toml_array_t* arr; - toml_table_t* tab; + int valtype; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, + 'D'ate, 'T'imestamp */ + char *val; + toml_array_t *arr; + toml_table_t *tab; }; - struct toml_array_t { - const char* key; /* key to this array */ - int kind; /* element kind: 'v'alue, 'a'rray, or 't'able, 'm'ixed */ - int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp, 'm'ixed */ + const char *key; /* key to this array */ + int kind; /* element kind: 'v'alue, 'a'rray, or 't'able, 'm'ixed */ + int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, + 'D'ate, 'T'imestamp, 'm'ixed */ - int nitem; /* number of elements */ - toml_arritem_t* item; + int nitem; /* number of elements */ + toml_arritem_t *item; }; - struct toml_table_t { - const char* key; /* key to this table */ - bool implicit; /* table was created implicitly */ - bool readonly; /* no more modification allowed */ + const char *key; /* key to this table */ + bool implicit; /* table was created implicitly */ + bool readonly; /* no more modification allowed */ - /* key-values in the table */ - int nkval; - toml_keyval_t** kval; + /* key-values in the table */ + int nkval; + toml_keyval_t **kval; - /* arrays in the table */ - int narr; - toml_array_t** arr; + /* arrays in the table */ + int narr; + toml_array_t **arr; - /* tables in the table */ - int ntab; - toml_table_t** tab; + /* tables in the table */ + int ntab; + toml_table_t **tab; }; - -static inline void xfree(const void* x) { if (x) FREE((void*)(intptr_t)x); } - +static inline void xfree(const void *x) { + if (x) + FREE((void *)(intptr_t)x); +} enum tokentype_t { - INVALID, - DOT, - COMMA, - EQUAL, - LBRACE, - RBRACE, - NEWLINE, - LBRACKET, - RBRACKET, - STRING, + INVALID, + DOT, + COMMA, + EQUAL, + LBRACE, + RBRACE, + NEWLINE, + LBRACKET, + RBRACKET, + STRING, }; typedef enum tokentype_t tokentype_t; typedef struct token_t token_t; struct token_t { - tokentype_t tok; - int lineno; - char* ptr; /* points into context->start */ - int len; - int eof; + tokentype_t tok; + int lineno; + char *ptr; /* points into context->start */ + int len; + int eof; }; - typedef struct context_t context_t; struct context_t { - char* start; - char* stop; - char* errbuf; - int errbufsz; + char *start; + char *stop; + char *errbuf; + int errbufsz; - token_t tok; - toml_table_t* root; - toml_table_t* curtab; - - struct { - int top; - char* key[10]; - token_t tok[10]; - } tpath; + token_t tok; + toml_table_t *root; + toml_table_t *curtab; + struct { + int top; + char *key[10]; + token_t tok[10]; + } tpath; }; #define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) +#define TOSTRING(x) STRINGIFY(x) #define FLINE __FILE__ ":" TOSTRING(__LINE__) -static int next_token(context_t* ctx, int dotisspecial); +static int next_token(context_t *ctx, int dotisspecial); /* Error reporting. Call when an error is detected. Always return -1. */ -static int e_outofmemory(context_t* ctx, const char* fline) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); - return -1; +static int e_outofmemory(context_t *ctx, const char *fline) { + snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline); + return -1; } - -static int e_internal(context_t* ctx, const char* fline) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); - return -1; +static int e_internal(context_t *ctx, const char *fline) { + snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline); + return -1; } -static int e_syntax(context_t* ctx, int lineno, const char* msg) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); - return -1; +static int e_syntax(context_t *ctx, int lineno, const char *msg) { + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); + return -1; } -static int e_badkey(context_t* ctx, int lineno) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); - return -1; +static int e_badkey(context_t *ctx, int lineno) { + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno); + return -1; } -static int e_keyexists(context_t* ctx, int lineno) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: key exists", lineno); - return -1; +static int e_keyexists(context_t *ctx, int lineno) { + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: key exists", lineno); + return -1; } -static int e_forbid(context_t* ctx, int lineno, const char* msg) -{ - snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); - return -1; +static int e_forbid(context_t *ctx, int lineno, const char *msg) { + snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg); + return -1; } -static void* expand(void* p, int sz, int newsz) -{ - void* s = MALLOC(newsz); - if (!s) return 0; +static void *expand(void *p, int sz, int newsz) { + void *s = MALLOC(newsz); + if (!s) + return 0; - memcpy(s, p, sz); - FREE(p); - return s; + memcpy(s, p, sz); + FREE(p); + return s; } -static void** expand_ptrarr(void** p, int n) -{ - void** s = MALLOC((n+1) * sizeof(void*)); - if (!s) return 0; +static void **expand_ptrarr(void **p, int n) { + void **s = MALLOC((n + 1) * sizeof(void *)); + if (!s) + return 0; - s[n] = 0; - memcpy(s, p, n * sizeof(void*)); - FREE(p); - return s; + s[n] = 0; + memcpy(s, p, n * sizeof(void *)); + FREE(p); + return s; } -static toml_arritem_t* expand_arritem(toml_arritem_t* p, int n) -{ - toml_arritem_t* pp = expand(p, n*sizeof(*p), (n+1)*sizeof(*p)); - if (!pp) return 0; +static toml_arritem_t *expand_arritem(toml_arritem_t *p, int n) { + toml_arritem_t *pp = expand(p, n * sizeof(*p), (n + 1) * sizeof(*p)); + if (!pp) + return 0; - memset(&pp[n], 0, sizeof(pp[n])); - return pp; + memset(&pp[n], 0, sizeof(pp[n])); + return pp; } +static char *norm_lit_str(const char *src, int srclen, int multiline, + char *errbuf, int errbufsz) { + char *dst = 0; /* will write to dst[] and return it */ + int max = 0; /* max size of dst[] */ + int off = 0; /* cur offset in dst[] */ + const char *sp = src; + const char *sq = src + srclen; + int ch; -static char* norm_lit_str(const char* src, int srclen, - int multiline, - char* errbuf, int errbufsz) -{ - char* dst = 0; /* will write to dst[] and return it */ - int max = 0; /* max size of dst[] */ - int off = 0; /* cur offset in dst[] */ - const char* sp = src; - const char* sq = src + srclen; - int ch; + /* scan forward on src */ + for (;;) { + if (off >= max - 10) { /* have some slack for misc stuff */ + int newmax = max + 50; + char *x = expand(dst, max, newmax); + if (!x) { + xfree(dst); + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + dst = x; + max = newmax; + } - /* scan forward on src */ - for (;;) { - if (off >= max - 10) { /* have some slack for misc stuff */ - int newmax = max + 50; - char* x = expand(dst, max, newmax); - if (!x) { - xfree(dst); - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - dst = x; - max = newmax; - } + /* finished? */ + if (sp >= sq) + break; - /* finished? */ - if (sp >= sq) break; + ch = *sp++; + /* control characters other than tab is not allowed */ + if ((0 <= ch && ch <= 0x08) || (0x0a <= ch && ch <= 0x1f) || (ch == 0x7f)) { + if (!(multiline && (ch == '\r' || ch == '\n'))) { + xfree(dst); + snprintf(errbuf, errbufsz, "invalid char U+%04x", ch); + return 0; + } + } - ch = *sp++; - /* control characters other than tab is not allowed */ - if ((0 <= ch && ch <= 0x08) - || (0x0a <= ch && ch <= 0x1f) - || (ch == 0x7f)) { - if (! (multiline && (ch == '\r' || ch == '\n'))) { - xfree(dst); - snprintf(errbuf, errbufsz, "invalid char U+%04x", ch); - return 0; - } - } + // a plain copy suffice + dst[off++] = ch; + } - // a plain copy suffice - dst[off++] = ch; - } - - dst[off++] = 0; - return dst; + dst[off++] = 0; + return dst; } - - - /* * Convert src to raw unescaped utf-8 string. * Returns NULL if error with errmsg in errbuf. */ -static char* norm_basic_str(const char* src, int srclen, - int multiline, - char* errbuf, int errbufsz) -{ - char* dst = 0; /* will write to dst[] and return it */ - int max = 0; /* max size of dst[] */ - int off = 0; /* cur offset in dst[] */ - const char* sp = src; - const char* sq = src + srclen; - int ch; +static char *norm_basic_str(const char *src, int srclen, int multiline, + char *errbuf, int errbufsz) { + char *dst = 0; /* will write to dst[] and return it */ + int max = 0; /* max size of dst[] */ + int off = 0; /* cur offset in dst[] */ + const char *sp = src; + const char *sq = src + srclen; + int ch; - /* scan forward on src */ - for (;;) { - if (off >= max - 10) { /* have some slack for misc stuff */ - int newmax = max + 50; - char* x = expand(dst, max, newmax); - if (!x) { - xfree(dst); - snprintf(errbuf, errbufsz, "out of memory"); - return 0; - } - dst = x; - max = newmax; - } + /* scan forward on src */ + for (;;) { + if (off >= max - 10) { /* have some slack for misc stuff */ + int newmax = max + 50; + char *x = expand(dst, max, newmax); + if (!x) { + xfree(dst); + snprintf(errbuf, errbufsz, "out of memory"); + return 0; + } + dst = x; + max = newmax; + } - /* finished? */ - if (sp >= sq) break; + /* finished? */ + if (sp >= sq) + break; - ch = *sp++; - if (ch != '\\') { - /* these chars must be escaped: U+0000 to U+0008, U+000A to U+001F, U+007F */ - if ((0 <= ch && ch <= 0x08) - || (0x0a <= ch && ch <= 0x1f) - || (ch == 0x7f)) { - if (! (multiline && (ch == '\r' || ch == '\n'))) { - xfree(dst); - snprintf(errbuf, errbufsz, "invalid char U+%04x", ch); - return 0; - } - } + ch = *sp++; + if (ch != '\\') { + /* these chars must be escaped: U+0000 to U+0008, U+000A to U+001F, U+007F + */ + if ((0 <= ch && ch <= 0x08) || (0x0a <= ch && ch <= 0x1f) || + (ch == 0x7f)) { + if (!(multiline && (ch == '\r' || ch == '\n'))) { + xfree(dst); + snprintf(errbuf, errbufsz, "invalid char U+%04x", ch); + return 0; + } + } - // a plain copy suffice - dst[off++] = ch; - continue; - } + // a plain copy suffice + dst[off++] = ch; + continue; + } - /* ch was backslash. we expect the escape char. */ - if (sp >= sq) { - snprintf(errbuf, errbufsz, "last backslash is invalid"); - xfree(dst); - return 0; - } + /* ch was backslash. we expect the escape char. */ + if (sp >= sq) { + snprintf(errbuf, errbufsz, "last backslash is invalid"); + xfree(dst); + return 0; + } - /* for multi-line, we want to kill line-ending-backslash ... */ - if (multiline) { + /* for multi-line, we want to kill line-ending-backslash ... */ + if (multiline) { - // if there is only whitespace after the backslash ... - if (sp[strspn(sp, " \t\r")] == '\n') { - /* skip all the following whitespaces */ - sp += strspn(sp, " \t\r\n"); - continue; - } - } + // if there is only whitespace after the backslash ... + if (sp[strspn(sp, " \t\r")] == '\n') { + /* skip all the following whitespaces */ + sp += strspn(sp, " \t\r\n"); + continue; + } + } - /* get the escaped char */ - ch = *sp++; - switch (ch) { - case 'u': case 'U': - { - int64_t ucs = 0; - int nhex = (ch == 'u' ? 4 : 8); - for (int i = 0; i < nhex; i++) { - if (sp >= sq) { - snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); - xfree(dst); - return 0; - } - ch = *sp++; - int v = ('0' <= ch && ch <= '9') - ? ch - '0' - : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); - if (-1 == v) { - snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); - xfree(dst); - return 0; - } - ucs = ucs * 16 + v; - } - int n = toml_ucs_to_utf8(ucs, &dst[off]); - if (-1 == n) { - snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); - xfree(dst); - return 0; - } - off += n; - } - continue; + /* get the escaped char */ + ch = *sp++; + switch (ch) { + case 'u': + case 'U': { + int64_t ucs = 0; + int nhex = (ch == 'u' ? 4 : 8); + for (int i = 0; i < nhex; i++) { + if (sp >= sq) { + snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex); + xfree(dst); + return 0; + } + ch = *sp++; + int v = ('0' <= ch && ch <= '9') + ? ch - '0' + : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1); + if (-1 == v) { + snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U"); + xfree(dst); + return 0; + } + ucs = ucs * 16 + v; + } + int n = toml_ucs_to_utf8(ucs, &dst[off]); + if (-1 == n) { + snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U"); + xfree(dst); + return 0; + } + off += n; + } + continue; - case 'b': ch = '\b'; break; - case 't': ch = '\t'; break; - case 'n': ch = '\n'; break; - case 'f': ch = '\f'; break; - case 'r': ch = '\r'; break; - case '"': ch = '"'; break; - case '\\': ch = '\\'; break; - default: - snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); - xfree(dst); - return 0; - } + case 'b': + ch = '\b'; + break; + case 't': + ch = '\t'; + break; + case 'n': + ch = '\n'; + break; + case 'f': + ch = '\f'; + break; + case 'r': + ch = '\r'; + break; + case '"': + ch = '"'; + break; + case '\\': + ch = '\\'; + break; + default: + snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch); + xfree(dst); + return 0; + } - dst[off++] = ch; - } + dst[off++] = ch; + } - // Cap with NUL and return it. - dst[off++] = 0; - return dst; + // Cap with NUL and return it. + dst[off++] = 0; + return dst; } - /* Normalize a key. Convert all special chars to raw unescaped utf-8 chars. */ -static char* normalize_key(context_t* ctx, token_t strtok) -{ - const char* sp = strtok.ptr; - const char* sq = strtok.ptr + strtok.len; - int lineno = strtok.lineno; - char* ret; - int ch = *sp; - char ebuf[80]; +static char *normalize_key(context_t *ctx, token_t strtok) { + const char *sp = strtok.ptr; + const char *sq = strtok.ptr + strtok.len; + int lineno = strtok.lineno; + char *ret; + int ch = *sp; + char ebuf[80]; - /* handle quoted string */ - if (ch == '\'' || ch == '\"') { - /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ - int multiline = 0; - if (sp[1] == ch && sp[2] == ch) { - sp += 3, sq -= 3; - multiline = 1; - } - else - sp++, sq--; + /* handle quoted string */ + if (ch == '\'' || ch == '\"') { + /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */ + int multiline = 0; + if (sp[1] == ch && sp[2] == ch) { + sp += 3, sq -= 3; + multiline = 1; + } else + sp++, sq--; - if (ch == '\'') { - /* for single quote, take it verbatim. */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; - } - } else { - /* for double quote, we need to normalize */ - ret = norm_basic_str(sp, sq - sp, multiline, ebuf, sizeof(ebuf)); - if (!ret) { - e_syntax(ctx, lineno, ebuf); - return 0; - } - } + if (ch == '\'') { + /* for single quote, take it verbatim. */ + if (!(ret = STRNDUP(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; + } + } else { + /* for double quote, we need to normalize */ + ret = norm_basic_str(sp, sq - sp, multiline, ebuf, sizeof(ebuf)); + if (!ret) { + e_syntax(ctx, lineno, ebuf); + return 0; + } + } - /* newlines are not allowed in keys */ - if (strchr(ret, '\n')) { - xfree(ret); - e_badkey(ctx, lineno); - return 0; - } - return ret; - } + /* newlines are not allowed in keys */ + if (strchr(ret, '\n')) { + xfree(ret); + e_badkey(ctx, lineno); + return 0; + } + return ret; + } - /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ - const char* xp; - for (xp = sp; xp != sq; xp++) { - int k = *xp; - if (isalnum(k)) continue; - if (k == '_' || k == '-') continue; - e_badkey(ctx, lineno); - return 0; - } + /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */ + const char *xp; + for (xp = sp; xp != sq; xp++) { + int k = *xp; + if (isalnum(k)) + continue; + if (k == '_' || k == '-') + continue; + e_badkey(ctx, lineno); + return 0; + } - /* dup and return it */ - if (! (ret = STRNDUP(sp, sq - sp))) { - e_outofmemory(ctx, FLINE); - return 0; - } - return ret; + /* dup and return it */ + if (!(ret = STRNDUP(sp, sq - sp))) { + e_outofmemory(ctx, FLINE); + return 0; + } + return ret; } - /* * Look up key in tab. Return 0 if not found, or * 'v'alue, 'a'rray or 't'able depending on the element. */ -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) -{ - int i; - void* dummy; +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) { + int i; + void *dummy; - if (!ret_tab) ret_tab = (toml_table_t**) &dummy; - if (!ret_arr) ret_arr = (toml_array_t**) &dummy; - if (!ret_val) ret_val = (toml_keyval_t**) &dummy; + if (!ret_tab) + ret_tab = (toml_table_t **)&dummy; + if (!ret_arr) + ret_arr = (toml_array_t **)&dummy; + if (!ret_val) + ret_val = (toml_keyval_t **)&dummy; - *ret_tab = 0; *ret_arr = 0; *ret_val = 0; + *ret_tab = 0; + *ret_arr = 0; + *ret_val = 0; - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) { - *ret_val = tab->kval[i]; - return 'v'; - } - } - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) { - *ret_arr = tab->arr[i]; - return 'a'; - } - } - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) { - *ret_tab = tab->tab[i]; - return 't'; - } - } - return 0; + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) { + *ret_val = tab->kval[i]; + return 'v'; + } + } + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) { + *ret_arr = tab->arr[i]; + return 'a'; + } + } + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) { + *ret_tab = tab->tab[i]; + return 't'; + } + } + return 0; } - -static int key_kind(toml_table_t* tab, const char* key) -{ - return check_key(tab, key, 0, 0, 0); +static int key_kind(toml_table_t *tab, const char *key) { + return check_key(tab, key, 0, 0, 0); } /* Create a keyval in the table. */ -static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) -{ - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); - if (!newkey) return 0; +static toml_keyval_t *create_keyval_in_table(context_t *ctx, toml_table_t *tab, + token_t keytok) { + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char *newkey = normalize_key(ctx, keytok); + if (!newkey) + return 0; - /* if key exists: error out. */ - toml_keyval_t* dest = 0; - if (key_kind(tab, newkey)) { - xfree(newkey); - e_keyexists(ctx, keytok.lineno); - return 0; - } + /* if key exists: error out. */ + toml_keyval_t *dest = 0; + if (key_kind(tab, newkey)) { + xfree(newkey); + e_keyexists(ctx, keytok.lineno); + return 0; + } - /* make a new entry */ - int n = tab->nkval; - toml_keyval_t** base; - if (0 == (base = (toml_keyval_t**) expand_ptrarr((void**)tab->kval, n))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - tab->kval = base; + /* make a new entry */ + int n = tab->nkval; + toml_keyval_t **base; + if (0 == (base = (toml_keyval_t **)expand_ptrarr((void **)tab->kval, n))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; + } + tab->kval = base; - if (0 == (base[n] = (toml_keyval_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - dest = tab->kval[tab->nkval++]; + if (0 == (base[n] = (toml_keyval_t *)CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; + } + dest = tab->kval[tab->nkval++]; - /* save the key in the new value struct */ - dest->key = newkey; - return dest; + /* save the key in the new value struct */ + dest->key = newkey; + return dest; } - /* Create a table in the table. */ -static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab, token_t keytok) -{ - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); - if (!newkey) return 0; +static toml_table_t *create_keytable_in_table(context_t *ctx, toml_table_t *tab, + token_t keytok) { + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char *newkey = normalize_key(ctx, keytok); + if (!newkey) + return 0; - /* if key exists: error out */ - toml_table_t* dest = 0; - if (check_key(tab, newkey, 0, 0, &dest)) { - xfree(newkey); /* don't need this anymore */ + /* if key exists: error out */ + toml_table_t *dest = 0; + if (check_key(tab, newkey, 0, 0, &dest)) { + xfree(newkey); /* don't need this anymore */ - /* special case: if table exists, but was created implicitly ... */ - if (dest && dest->implicit) { - /* we make it explicit now, and simply return it. */ - dest->implicit = false; - return dest; - } - e_keyexists(ctx, keytok.lineno); - return 0; - } + /* special case: if table exists, but was created implicitly ... */ + if (dest && dest->implicit) { + /* we make it explicit now, and simply return it. */ + dest->implicit = false; + return dest; + } + e_keyexists(ctx, keytok.lineno); + return 0; + } - /* create a new table entry */ - int n = tab->ntab; - toml_table_t** base; - if (0 == (base = (toml_table_t**) expand_ptrarr((void**)tab->tab, n))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - tab->tab = base; + /* create a new table entry */ + int n = tab->ntab; + toml_table_t **base; + if (0 == (base = (toml_table_t **)expand_ptrarr((void **)tab->tab, n))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; + } + tab->tab = base; - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - dest = tab->tab[tab->ntab++]; + if (0 == (base[n] = (toml_table_t *)CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; + } + dest = tab->tab[tab->ntab++]; - /* save the key in the new table struct */ - dest->key = newkey; - return dest; + /* save the key in the new table struct */ + dest->key = newkey; + return dest; } - /* Create an array in the table. */ -static toml_array_t* create_keyarray_in_table(context_t* ctx, - toml_table_t* tab, - token_t keytok, - char kind) -{ - /* first, normalize the key to be used for lookup. - * remember to free it if we error out. - */ - char* newkey = normalize_key(ctx, keytok); - if (!newkey) return 0; +static toml_array_t *create_keyarray_in_table(context_t *ctx, toml_table_t *tab, + token_t keytok, char kind) { + /* first, normalize the key to be used for lookup. + * remember to free it if we error out. + */ + char *newkey = normalize_key(ctx, keytok); + if (!newkey) + return 0; - /* if key exists: error out */ - if (key_kind(tab, newkey)) { - xfree(newkey); /* don't need this anymore */ - e_keyexists(ctx, keytok.lineno); - return 0; - } + /* if key exists: error out */ + if (key_kind(tab, newkey)) { + xfree(newkey); /* don't need this anymore */ + e_keyexists(ctx, keytok.lineno); + return 0; + } - /* make a new array entry */ - int n = tab->narr; - toml_array_t** base; - if (0 == (base = (toml_array_t**) expand_ptrarr((void**)tab->arr, n))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - tab->arr = base; + /* make a new array entry */ + int n = tab->narr; + toml_array_t **base; + if (0 == (base = (toml_array_t **)expand_ptrarr((void **)tab->arr, n))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; + } + tab->arr = base; - if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) { - xfree(newkey); - e_outofmemory(ctx, FLINE); - return 0; - } - toml_array_t* dest = tab->arr[tab->narr++]; + if (0 == (base[n] = (toml_array_t *)CALLOC(1, sizeof(*base[n])))) { + xfree(newkey); + e_outofmemory(ctx, FLINE); + return 0; + } + toml_array_t *dest = tab->arr[tab->narr++]; - /* save the key in the new array struct */ - dest->key = newkey; - dest->kind = kind; - return dest; + /* save the key in the new array struct */ + dest->key = newkey; + dest->kind = kind; + return dest; } - -static toml_arritem_t* create_value_in_array(context_t* ctx, - toml_array_t* parent) -{ - const int n = parent->nitem; - toml_arritem_t* base = expand_arritem(parent->item, n); - if (!base) { - e_outofmemory(ctx, FLINE); - return 0; - } - parent->item = base; - parent->nitem++; - return &parent->item[n]; +static toml_arritem_t *create_value_in_array(context_t *ctx, + toml_array_t *parent) { + const int n = parent->nitem; + toml_arritem_t *base = expand_arritem(parent->item, n); + if (!base) { + e_outofmemory(ctx, FLINE); + return 0; + } + parent->item = base; + parent->nitem++; + return &parent->item[n]; } /* Create an array in an array */ -static toml_array_t* create_array_in_array(context_t* ctx, - toml_array_t* parent) -{ - const int n = parent->nitem; - toml_arritem_t* base = expand_arritem(parent->item, n); - if (!base) { - e_outofmemory(ctx, FLINE); - return 0; - } - toml_array_t* ret = (toml_array_t*) CALLOC(1, sizeof(toml_array_t)); - if (!ret) { - e_outofmemory(ctx, FLINE); - return 0; - } - base[n].arr = ret; - parent->item = base; - parent->nitem++; - return ret; +static toml_array_t *create_array_in_array(context_t *ctx, + toml_array_t *parent) { + const int n = parent->nitem; + toml_arritem_t *base = expand_arritem(parent->item, n); + if (!base) { + e_outofmemory(ctx, FLINE); + return 0; + } + toml_array_t *ret = (toml_array_t *)CALLOC(1, sizeof(toml_array_t)); + if (!ret) { + e_outofmemory(ctx, FLINE); + return 0; + } + base[n].arr = ret; + parent->item = base; + parent->nitem++; + return ret; } /* Create a table in an array */ -static toml_table_t* create_table_in_array(context_t* ctx, - toml_array_t* parent) -{ - int n = parent->nitem; - toml_arritem_t* base = expand_arritem(parent->item, n); - if (!base) { - e_outofmemory(ctx, FLINE); - return 0; - } - toml_table_t* ret = (toml_table_t*) CALLOC(1, sizeof(toml_table_t)); - if (!ret) { - e_outofmemory(ctx, FLINE); - return 0; - } - base[n].tab = ret; - parent->item = base; - parent->nitem++; - return ret; +static toml_table_t *create_table_in_array(context_t *ctx, + toml_array_t *parent) { + int n = parent->nitem; + toml_arritem_t *base = expand_arritem(parent->item, n); + if (!base) { + e_outofmemory(ctx, FLINE); + return 0; + } + toml_table_t *ret = (toml_table_t *)CALLOC(1, sizeof(toml_table_t)); + if (!ret) { + e_outofmemory(ctx, FLINE); + return 0; + } + base[n].tab = ret; + parent->item = base; + parent->nitem++; + return ret; } - -static int skip_newlines(context_t* ctx, int isdotspecial) -{ - while (ctx->tok.tok == NEWLINE) { - if (next_token(ctx, isdotspecial)) return -1; - if (ctx->tok.eof) break; - } - return 0; +static int skip_newlines(context_t *ctx, int isdotspecial) { + while (ctx->tok.tok == NEWLINE) { + if (next_token(ctx, isdotspecial)) + return -1; + if (ctx->tok.eof) + break; + } + return 0; } +static int parse_keyval(context_t *ctx, toml_table_t *tab); -static int parse_keyval(context_t* ctx, toml_table_t* tab); +static inline int eat_token(context_t *ctx, tokentype_t typ, int isdotspecial, + const char *fline) { + if (ctx->tok.tok != typ) + return e_internal(ctx, fline); -static inline int eat_token(context_t* ctx, tokentype_t typ, int isdotspecial, const char* fline) -{ - if (ctx->tok.tok != typ) - return e_internal(ctx, fline); + if (next_token(ctx, isdotspecial)) + return -1; - if (next_token(ctx, isdotspecial)) - return -1; - - return 0; + return 0; } - - /* We are at '{ ... }'. * Parse the table. */ -static int parse_inline_table(context_t* ctx, toml_table_t* tab) -{ - if (eat_token(ctx, LBRACE, 1, FLINE)) - return -1; +static int parse_inline_table(context_t *ctx, toml_table_t *tab) { + if (eat_token(ctx, LBRACE, 1, FLINE)) + return -1; - for (;;) { - if (ctx->tok.tok == NEWLINE) - return e_syntax(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + for (;;) { + if (ctx->tok.tok == NEWLINE) + return e_syntax(ctx, ctx->tok.lineno, + "newline not allowed in inline table"); - /* until } */ - if (ctx->tok.tok == RBRACE) - break; + /* until } */ + if (ctx->tok.tok == RBRACE) + break; - if (ctx->tok.tok != STRING) - return e_syntax(ctx, ctx->tok.lineno, "expect a string"); + if (ctx->tok.tok != STRING) + return e_syntax(ctx, ctx->tok.lineno, "expect a string"); - if (parse_keyval(ctx, tab)) - return -1; + if (parse_keyval(ctx, tab)) + return -1; - if (ctx->tok.tok == NEWLINE) - return e_syntax(ctx, ctx->tok.lineno, "newline not allowed in inline table"); + if (ctx->tok.tok == NEWLINE) + return e_syntax(ctx, ctx->tok.lineno, + "newline not allowed in inline table"); - /* on comma, continue to scan for next keyval */ - if (ctx->tok.tok == COMMA) { - if (eat_token(ctx, COMMA, 1, FLINE)) - return -1; - continue; - } - break; - } + /* on comma, continue to scan for next keyval */ + if (ctx->tok.tok == COMMA) { + if (eat_token(ctx, COMMA, 1, FLINE)) + return -1; + continue; + } + break; + } - if (eat_token(ctx, RBRACE, 1, FLINE)) - return -1; + if (eat_token(ctx, RBRACE, 1, FLINE)) + return -1; - tab->readonly = 1; + tab->readonly = 1; - return 0; + return 0; } -static int valtype(const char* val) -{ - toml_timestamp_t ts; - if (*val == '\'' || *val == '"') return 's'; - if (0 == toml_rtob(val, 0)) return 'b'; - if (0 == toml_rtoi(val, 0)) return 'i'; - if (0 == toml_rtod(val, 0)) return 'd'; - if (0 == toml_rtots(val, &ts)) { - if (ts.year && ts.hour) return 'T'; /* timestamp */ - if (ts.year) return 'D'; /* date */ - return 't'; /* time */ - } - return 'u'; /* unknown */ +static int valtype(const char *val) { + toml_timestamp_t ts; + if (*val == '\'' || *val == '"') + return 's'; + if (0 == toml_rtob(val, 0)) + return 'b'; + if (0 == toml_rtoi(val, 0)) + return 'i'; + if (0 == toml_rtod(val, 0)) + return 'd'; + if (0 == toml_rtots(val, &ts)) { + if (ts.year && ts.hour) + return 'T'; /* timestamp */ + if (ts.year) + return 'D'; /* date */ + return 't'; /* time */ + } + return 'u'; /* unknown */ } - /* We are at '[...]' */ -static int parse_array(context_t* ctx, toml_array_t* arr) -{ - if (eat_token(ctx, LBRACKET, 0, FLINE)) return -1; +static int parse_array(context_t *ctx, toml_array_t *arr) { + if (eat_token(ctx, LBRACKET, 0, FLINE)) + return -1; - for (;;) { - if (skip_newlines(ctx, 0)) return -1; + for (;;) { + if (skip_newlines(ctx, 0)) + return -1; - /* until ] */ - if (ctx->tok.tok == RBRACKET) break; + /* until ] */ + if (ctx->tok.tok == RBRACKET) + break; - switch (ctx->tok.tok) { - case STRING: - { - /* set array kind if this will be the first entry */ - if (arr->kind == 0) - arr->kind = 'v'; - else if (arr->kind != 'v') - arr->kind = 'm'; + switch (ctx->tok.tok) { + case STRING: { + /* set array kind if this will be the first entry */ + if (arr->kind == 0) + arr->kind = 'v'; + else if (arr->kind != 'v') + arr->kind = 'm'; - char* val = ctx->tok.ptr; - int vlen = ctx->tok.len; + char *val = ctx->tok.ptr; + int vlen = ctx->tok.len; - /* make a new value in array */ - toml_arritem_t* newval = create_value_in_array(ctx, arr); - if (!newval) - return e_outofmemory(ctx, FLINE); + /* make a new value in array */ + toml_arritem_t *newval = create_value_in_array(ctx, arr); + if (!newval) + return e_outofmemory(ctx, FLINE); - if (! (newval->val = STRNDUP(val, vlen))) - return e_outofmemory(ctx, FLINE); + if (!(newval->val = STRNDUP(val, vlen))) + return e_outofmemory(ctx, FLINE); - newval->valtype = valtype(newval->val); + newval->valtype = valtype(newval->val); - /* set array type if this is the first entry */ - if (arr->nitem == 1) - arr->type = newval->valtype; - else if (arr->type != newval->valtype) - arr->type = 'm'; /* mixed */ + /* set array type if this is the first entry */ + if (arr->nitem == 1) + arr->type = newval->valtype; + else if (arr->type != newval->valtype) + arr->type = 'm'; /* mixed */ - if (eat_token(ctx, STRING, 0, FLINE)) return -1; - break; - } + if (eat_token(ctx, STRING, 0, FLINE)) + return -1; + break; + } - case LBRACKET: - { /* [ [array], [array] ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) - arr->kind = 'a'; - else if (arr->kind != 'a') - arr->kind = 'm'; + case LBRACKET: { /* [ [array], [array] ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) + arr->kind = 'a'; + else if (arr->kind != 'a') + arr->kind = 'm'; - toml_array_t* subarr = create_array_in_array(ctx, arr); - if (!subarr) return -1; - if (parse_array(ctx, subarr)) return -1; - break; - } + toml_array_t *subarr = create_array_in_array(ctx, arr); + if (!subarr) + return -1; + if (parse_array(ctx, subarr)) + return -1; + break; + } - case LBRACE: - { /* [ {table}, {table} ... ] */ - /* set the array kind if this will be the first entry */ - if (arr->kind == 0) - arr->kind = 't'; - else if (arr->kind != 't') - arr->kind = 'm'; + case LBRACE: { /* [ {table}, {table} ... ] */ + /* set the array kind if this will be the first entry */ + if (arr->kind == 0) + arr->kind = 't'; + else if (arr->kind != 't') + arr->kind = 'm'; - toml_table_t* subtab = create_table_in_array(ctx, arr); - if (!subtab) return -1; - if (parse_inline_table(ctx, subtab)) return -1; - break; - } + toml_table_t *subtab = create_table_in_array(ctx, arr); + if (!subtab) + return -1; + if (parse_inline_table(ctx, subtab)) + return -1; + break; + } - default: - return e_syntax(ctx, ctx->tok.lineno, "syntax error"); - } + default: + return e_syntax(ctx, ctx->tok.lineno, "syntax error"); + } - if (skip_newlines(ctx, 0)) return -1; + if (skip_newlines(ctx, 0)) + return -1; - /* on comma, continue to scan for next element */ - if (ctx->tok.tok == COMMA) { - if (eat_token(ctx, COMMA, 0, FLINE)) return -1; - continue; - } - break; - } + /* on comma, continue to scan for next element */ + if (ctx->tok.tok == COMMA) { + if (eat_token(ctx, COMMA, 0, FLINE)) + return -1; + continue; + } + break; + } - if (eat_token(ctx, RBRACKET, 1, FLINE)) return -1; - return 0; + if (eat_token(ctx, RBRACKET, 1, FLINE)) + return -1; + return 0; } - /* handle lines like these: key = "value" key = [ array ] key = { table } */ -static int parse_keyval(context_t* ctx, toml_table_t* tab) -{ - if (tab->readonly) { - return e_forbid(ctx, ctx->tok.lineno, "cannot insert new entry into existing table"); - } +static int parse_keyval(context_t *ctx, toml_table_t *tab) { + if (tab->readonly) { + return e_forbid(ctx, ctx->tok.lineno, + "cannot insert new entry into existing table"); + } - token_t key = ctx->tok; - if (eat_token(ctx, STRING, 1, FLINE)) return -1; + token_t key = ctx->tok; + if (eat_token(ctx, STRING, 1, FLINE)) + return -1; - if (ctx->tok.tok == DOT) { - /* handle inline dotted key. - e.g. - physical.color = "orange" - physical.shape = "round" - */ - toml_table_t* subtab = 0; - { - char* subtabstr = normalize_key(ctx, key); - if (!subtabstr) return -1; + if (ctx->tok.tok == DOT) { + /* handle inline dotted key. + e.g. + physical.color = "orange" + physical.shape = "round" + */ + toml_table_t *subtab = 0; + { + char *subtabstr = normalize_key(ctx, key); + if (!subtabstr) + return -1; - subtab = toml_table_in(tab, subtabstr); - xfree(subtabstr); - } - if (!subtab) { - subtab = create_keytable_in_table(ctx, tab, key); - if (!subtab) return -1; - } - if (next_token(ctx, 1)) return -1; - if (parse_keyval(ctx, subtab)) return -1; - return 0; - } + subtab = toml_table_in(tab, subtabstr); + xfree(subtabstr); + } + if (!subtab) { + subtab = create_keytable_in_table(ctx, tab, key); + if (!subtab) + return -1; + } + if (next_token(ctx, 1)) + return -1; + if (parse_keyval(ctx, subtab)) + return -1; + return 0; + } - if (ctx->tok.tok != EQUAL) { - return e_syntax(ctx, ctx->tok.lineno, "missing ="); - } + if (ctx->tok.tok != EQUAL) { + return e_syntax(ctx, ctx->tok.lineno, "missing ="); + } - if (next_token(ctx, 0)) return -1; + if (next_token(ctx, 0)) + return -1; - switch (ctx->tok.tok) { - case STRING: - { /* key = "value" */ - toml_keyval_t* keyval = create_keyval_in_table(ctx, tab, key); - if (!keyval) return -1; - token_t val = ctx->tok; + switch (ctx->tok.tok) { + case STRING: { /* key = "value" */ + toml_keyval_t *keyval = create_keyval_in_table(ctx, tab, key); + if (!keyval) + return -1; + token_t val = ctx->tok; - assert(keyval->val == 0); - if (! (keyval->val = STRNDUP(val.ptr, val.len))) - return e_outofmemory(ctx, FLINE); + assert(keyval->val == 0); + if (!(keyval->val = STRNDUP(val.ptr, val.len))) + return e_outofmemory(ctx, FLINE); - if (next_token(ctx, 1)) return -1; + if (next_token(ctx, 1)) + return -1; - return 0; - } + return 0; + } - case LBRACKET: - { /* key = [ array ] */ - toml_array_t* arr = create_keyarray_in_table(ctx, tab, key, 0); - if (!arr) return -1; - if (parse_array(ctx, arr)) return -1; - return 0; - } + case LBRACKET: { /* key = [ array ] */ + toml_array_t *arr = create_keyarray_in_table(ctx, tab, key, 0); + if (!arr) + return -1; + if (parse_array(ctx, arr)) + return -1; + return 0; + } - case LBRACE: - { /* key = { table } */ - toml_table_t* nxttab = create_keytable_in_table(ctx, tab, key); - if (!nxttab) return -1; - if (parse_inline_table(ctx, nxttab)) return -1; - return 0; - } + case LBRACE: { /* key = { table } */ + toml_table_t *nxttab = create_keytable_in_table(ctx, tab, key); + if (!nxttab) + return -1; + if (parse_inline_table(ctx, nxttab)) + return -1; + return 0; + } - default: - return e_syntax(ctx, ctx->tok.lineno, "syntax error"); - } - return 0; + default: + return e_syntax(ctx, ctx->tok.lineno, "syntax error"); + } + return 0; } - typedef struct tabpath_t tabpath_t; struct tabpath_t { - int cnt; - token_t key[10]; + int cnt; + token_t key[10]; }; /* at [x.y.z] or [[x.y.z]] * Scan forward and fill tabpath until it enters ] or ]] * There will be at least one entry on return. */ -static int fill_tabpath(context_t* ctx) -{ - int lineno = ctx->tok.lineno; - int i; +static int fill_tabpath(context_t *ctx) { + int lineno = ctx->tok.lineno; + int i; - /* clear tpath */ - for (i = 0; i < ctx->tpath.top; i++) { - char** p = &ctx->tpath.key[i]; - xfree(*p); - *p = 0; - } - ctx->tpath.top = 0; + /* clear tpath */ + for (i = 0; i < ctx->tpath.top; i++) { + char **p = &ctx->tpath.key[i]; + xfree(*p); + *p = 0; + } + ctx->tpath.top = 0; - for (;;) { - if (ctx->tpath.top >= 10) - return e_syntax(ctx, lineno, "table path is too deep; max allowed is 10."); + for (;;) { + if (ctx->tpath.top >= 10) + return e_syntax(ctx, lineno, + "table path is too deep; max allowed is 10."); - if (ctx->tok.tok != STRING) - return e_syntax(ctx, lineno, "invalid or missing key"); + if (ctx->tok.tok != STRING) + return e_syntax(ctx, lineno, "invalid or missing key"); - char* key = normalize_key(ctx, ctx->tok); - if (!key) return -1; - ctx->tpath.tok[ctx->tpath.top] = ctx->tok; - ctx->tpath.key[ctx->tpath.top] = key; - ctx->tpath.top++; + char *key = normalize_key(ctx, ctx->tok); + if (!key) + return -1; + ctx->tpath.tok[ctx->tpath.top] = ctx->tok; + ctx->tpath.key[ctx->tpath.top] = key; + ctx->tpath.top++; - if (next_token(ctx, 1)) return -1; + if (next_token(ctx, 1)) + return -1; - if (ctx->tok.tok == RBRACKET) break; + if (ctx->tok.tok == RBRACKET) + break; - if (ctx->tok.tok != DOT) - return e_syntax(ctx, lineno, "invalid key"); + if (ctx->tok.tok != DOT) + return e_syntax(ctx, lineno, "invalid key"); - if (next_token(ctx, 1)) return -1; - } + if (next_token(ctx, 1)) + return -1; + } - if (ctx->tpath.top <= 0) - return e_syntax(ctx, lineno, "empty table selector"); + if (ctx->tpath.top <= 0) + return e_syntax(ctx, lineno, "empty table selector"); - return 0; + return 0; } - /* Walk tabpath from the root, and create new tables on the way. * Sets ctx->curtab to the final table. */ -static int walk_tabpath(context_t* ctx) -{ - /* start from root */ - toml_table_t* curtab = ctx->root; +static int walk_tabpath(context_t *ctx) { + /* start from root */ + toml_table_t *curtab = ctx->root; - for (int i = 0; i < ctx->tpath.top; i++) { - const char* key = ctx->tpath.key[i]; + for (int i = 0; i < ctx->tpath.top; i++) { + const char *key = ctx->tpath.key[i]; - toml_keyval_t* nextval = 0; - toml_array_t* nextarr = 0; - toml_table_t* nexttab = 0; - switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { - case 't': - /* found a table. nexttab is where we will go next. */ - break; + toml_keyval_t *nextval = 0; + toml_array_t *nextarr = 0; + toml_table_t *nexttab = 0; + switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) { + case 't': + /* found a table. nexttab is where we will go next. */ + break; - case 'a': - /* found an array. nexttab is the last table in the array. */ - if (nextarr->kind != 't') - return e_internal(ctx, FLINE); + case 'a': + /* found an array. nexttab is the last table in the array. */ + if (nextarr->kind != 't') + return e_internal(ctx, FLINE); - if (nextarr->nitem == 0) - return e_internal(ctx, FLINE); + if (nextarr->nitem == 0) + return e_internal(ctx, FLINE); - nexttab = nextarr->item[nextarr->nitem-1].tab; - break; + nexttab = nextarr->item[nextarr->nitem - 1].tab; + break; - case 'v': - return e_keyexists(ctx, ctx->tpath.tok[i].lineno); + case 'v': + return e_keyexists(ctx, ctx->tpath.tok[i].lineno); - default: - { /* Not found. Let's create an implicit table. */ - int n = curtab->ntab; - toml_table_t** base = (toml_table_t**) expand_ptrarr((void**)curtab->tab, n); - if (0 == base) - return e_outofmemory(ctx, FLINE); + default: { /* Not found. Let's create an implicit table. */ + int n = curtab->ntab; + toml_table_t **base = + (toml_table_t **)expand_ptrarr((void **)curtab->tab, n); + if (0 == base) + return e_outofmemory(ctx, FLINE); - curtab->tab = base; + curtab->tab = base; - if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) - return e_outofmemory(ctx, FLINE); + if (0 == (base[n] = (toml_table_t *)CALLOC(1, sizeof(*base[n])))) + return e_outofmemory(ctx, FLINE); - if (0 == (base[n]->key = STRDUP(key))) - return e_outofmemory(ctx, FLINE); + if (0 == (base[n]->key = STRDUP(key))) + return e_outofmemory(ctx, FLINE); - nexttab = curtab->tab[curtab->ntab++]; + nexttab = curtab->tab[curtab->ntab++]; - /* tabs created by walk_tabpath are considered implicit */ - nexttab->implicit = true; - } - break; - } + /* tabs created by walk_tabpath are considered implicit */ + nexttab->implicit = true; + } break; + } - /* switch to next tab */ - curtab = nexttab; - } + /* switch to next tab */ + curtab = nexttab; + } - /* save it */ - ctx->curtab = curtab; + /* save it */ + ctx->curtab = curtab; - return 0; + return 0; } - /* handle lines like [x.y.z] or [[x.y.z]] */ -static int parse_select(context_t* ctx) -{ - assert(ctx->tok.tok == LBRACKET); +static int parse_select(context_t *ctx) { + assert(ctx->tok.tok == LBRACKET); - /* true if [[ */ - int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '['); - /* need to detect '[[' on our own because next_token() will skip whitespace, - and '[ [' would be taken as '[[', which is wrong. */ + /* true if [[ */ + int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '['); + /* need to detect '[[' on our own because next_token() will skip whitespace, + and '[ [' would be taken as '[[', which is wrong. */ - /* eat [ or [[ */ - if (eat_token(ctx, LBRACKET, 1, FLINE)) return -1; - if (llb) { - assert(ctx->tok.tok == LBRACKET); - if (eat_token(ctx, LBRACKET, 1, FLINE)) return -1; - } + /* eat [ or [[ */ + if (eat_token(ctx, LBRACKET, 1, FLINE)) + return -1; + if (llb) { + assert(ctx->tok.tok == LBRACKET); + if (eat_token(ctx, LBRACKET, 1, FLINE)) + return -1; + } - if (fill_tabpath(ctx)) return -1; + if (fill_tabpath(ctx)) + return -1; - /* For [x.y.z] or [[x.y.z]], remove z from tpath. - */ - token_t z = ctx->tpath.tok[ctx->tpath.top-1]; - xfree(ctx->tpath.key[ctx->tpath.top-1]); - ctx->tpath.top--; + /* For [x.y.z] or [[x.y.z]], remove z from tpath. + */ + token_t z = ctx->tpath.tok[ctx->tpath.top - 1]; + xfree(ctx->tpath.key[ctx->tpath.top - 1]); + ctx->tpath.top--; - /* set up ctx->curtab */ - if (walk_tabpath(ctx)) return -1; + /* set up ctx->curtab */ + if (walk_tabpath(ctx)) + return -1; - if (! llb) { - /* [x.y.z] -> create z = {} in x.y */ - toml_table_t* curtab = create_keytable_in_table(ctx, ctx->curtab, z); - if (!curtab) return -1; - ctx->curtab = curtab; - } else { - /* [[x.y.z]] -> create z = [] in x.y */ - toml_array_t* arr = 0; - { - char* zstr = normalize_key(ctx, z); - if (!zstr) return -1; - arr = toml_array_in(ctx->curtab, zstr); - xfree(zstr); - } - if (!arr) { - arr = create_keyarray_in_table(ctx, ctx->curtab, z, 't'); - if (!arr) return -1; - } - if (arr->kind != 't') - return e_syntax(ctx, z.lineno, "array mismatch"); + if (!llb) { + /* [x.y.z] -> create z = {} in x.y */ + toml_table_t *curtab = create_keytable_in_table(ctx, ctx->curtab, z); + if (!curtab) + return -1; + ctx->curtab = curtab; + } else { + /* [[x.y.z]] -> create z = [] in x.y */ + toml_array_t *arr = 0; + { + char *zstr = normalize_key(ctx, z); + if (!zstr) + return -1; + arr = toml_array_in(ctx->curtab, zstr); + xfree(zstr); + } + if (!arr) { + arr = create_keyarray_in_table(ctx, ctx->curtab, z, 't'); + if (!arr) + return -1; + } + if (arr->kind != 't') + return e_syntax(ctx, z.lineno, "array mismatch"); - /* add to z[] */ - toml_table_t* dest; - { - toml_table_t* t = create_table_in_array(ctx, arr); - if (!t) return -1; + /* add to z[] */ + toml_table_t *dest; + { + toml_table_t *t = create_table_in_array(ctx, arr); + if (!t) + return -1; - if (0 == (t->key = STRDUP("__anon__"))) - return e_outofmemory(ctx, FLINE); + if (0 == (t->key = STRDUP("__anon__"))) + return e_outofmemory(ctx, FLINE); - dest = t; - } + dest = t; + } - ctx->curtab = dest; - } + ctx->curtab = dest; + } - if (ctx->tok.tok != RBRACKET) { - return e_syntax(ctx, ctx->tok.lineno, "expects ]"); - } - if (llb) { - if (! (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) { - return e_syntax(ctx, ctx->tok.lineno, "expects ]]"); - } - if (eat_token(ctx, RBRACKET, 1, FLINE)) return -1; - } + if (ctx->tok.tok != RBRACKET) { + return e_syntax(ctx, ctx->tok.lineno, "expects ]"); + } + if (llb) { + if (!(ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) { + return e_syntax(ctx, ctx->tok.lineno, "expects ]]"); + } + if (eat_token(ctx, RBRACKET, 1, FLINE)) + return -1; + } - if (eat_token(ctx, RBRACKET, 1, FLINE)) - return -1; + if (eat_token(ctx, RBRACKET, 1, FLINE)) + return -1; - if (ctx->tok.tok != NEWLINE) - return e_syntax(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); + if (ctx->tok.tok != NEWLINE) + return e_syntax(ctx, ctx->tok.lineno, "extra chars after ] or ]]"); - return 0; + return 0; } +toml_table_t *toml_parse(char *conf, char *errbuf, int errbufsz) { + context_t ctx; + // clear errbuf + if (errbufsz <= 0) + errbufsz = 0; + if (errbufsz > 0) + errbuf[0] = 0; + // init context + memset(&ctx, 0, sizeof(ctx)); + ctx.start = conf; + ctx.stop = ctx.start + strlen(conf); + ctx.errbuf = errbuf; + ctx.errbufsz = errbufsz; -toml_table_t* toml_parse(char* conf, - char* errbuf, - int errbufsz) -{ - context_t ctx; + // start with an artificial newline of length 0 + ctx.tok.tok = NEWLINE; + ctx.tok.lineno = 1; + ctx.tok.ptr = conf; + ctx.tok.len = 0; - // clear errbuf - if (errbufsz <= 0) errbufsz = 0; - if (errbufsz > 0) errbuf[0] = 0; + // make a root table + if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { + e_outofmemory(&ctx, FLINE); + // Do not goto fail, root table not set up yet + return 0; + } - // init context - memset(&ctx, 0, sizeof(ctx)); - ctx.start = conf; - ctx.stop = ctx.start + strlen(conf); - ctx.errbuf = errbuf; - ctx.errbufsz = errbufsz; + // set root as default table + ctx.curtab = ctx.root; - // start with an artificial newline of length 0 - ctx.tok.tok = NEWLINE; - ctx.tok.lineno = 1; - ctx.tok.ptr = conf; - ctx.tok.len = 0; + /* Scan forward until EOF */ + for (token_t tok = ctx.tok; !tok.eof; tok = ctx.tok) { + switch (tok.tok) { - // make a root table - if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) { - e_outofmemory(&ctx, FLINE); - // Do not goto fail, root table not set up yet - return 0; - } + case NEWLINE: + if (next_token(&ctx, 1)) + goto fail; + break; - // set root as default table - ctx.curtab = ctx.root; + case STRING: + if (parse_keyval(&ctx, ctx.curtab)) + goto fail; - /* Scan forward until EOF */ - for (token_t tok = ctx.tok; ! tok.eof ; tok = ctx.tok) { - switch (tok.tok) { + if (ctx.tok.tok != NEWLINE) { + e_syntax(&ctx, ctx.tok.lineno, "extra chars after value"); + goto fail; + } - case NEWLINE: - if (next_token(&ctx, 1)) goto fail; - break; + if (eat_token(&ctx, NEWLINE, 1, FLINE)) + goto fail; + break; - case STRING: - if (parse_keyval(&ctx, ctx.curtab)) goto fail; + case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ + if (parse_select(&ctx)) + goto fail; + break; - if (ctx.tok.tok != NEWLINE) { - e_syntax(&ctx, ctx.tok.lineno, "extra chars after value"); - goto fail; - } + default: + e_syntax(&ctx, tok.lineno, "syntax error"); + goto fail; + } + } - if (eat_token(&ctx, NEWLINE, 1, FLINE)) goto fail; - break; - - case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */ - if (parse_select(&ctx)) goto fail; - break; - - default: - e_syntax(&ctx, tok.lineno, "syntax error"); - goto fail; - } - } - - /* success */ - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - return ctx.root; + /* success */ + for (int i = 0; i < ctx.tpath.top; i++) + xfree(ctx.tpath.key[i]); + return ctx.root; fail: - // Something bad has happened. Free resources and return error. - for (int i = 0; i < ctx.tpath.top; i++) xfree(ctx.tpath.key[i]); - toml_free(ctx.root); - return 0; + // Something bad has happened. Free resources and return error. + for (int i = 0; i < ctx.tpath.top; i++) + xfree(ctx.tpath.key[i]); + toml_free(ctx.root); + return 0; } +toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz) { + int bufsz = 0; + char *buf = 0; + int off = 0; -toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz) -{ - int bufsz = 0; - char* buf = 0; - int off = 0; + /* read from fp into buf */ + while (!feof(fp)) { - /* read from fp into buf */ - while (! feof(fp)) { + if (off == bufsz) { + int xsz = bufsz + 1000; + char *x = expand(buf, bufsz, xsz); + if (!x) { + snprintf(errbuf, errbufsz, "out of memory"); + xfree(buf); + return 0; + } + buf = x; + bufsz = xsz; + } - if (off == bufsz) { - int xsz = bufsz + 1000; - char* x = expand(buf, bufsz, xsz); - if (!x) { - snprintf(errbuf, errbufsz, "out of memory"); - xfree(buf); - return 0; - } - buf = x; - bufsz = xsz; - } + errno = 0; + int n = fread(buf + off, 1, bufsz - off, fp); + if (ferror(fp)) { + snprintf(errbuf, errbufsz, "%s", + errno ? strerror(errno) : "Error reading file"); + xfree(buf); + return 0; + } + off += n; + } - errno = 0; - int n = fread(buf + off, 1, bufsz - off, fp); - if (ferror(fp)) { - snprintf(errbuf, errbufsz, "%s", - errno ? strerror(errno) : "Error reading file"); - xfree(buf); - return 0; - } - off += n; - } + /* tag on a NUL to cap the string */ + if (off == bufsz) { + int xsz = bufsz + 1; + char *x = expand(buf, bufsz, xsz); + if (!x) { + snprintf(errbuf, errbufsz, "out of memory"); + xfree(buf); + return 0; + } + buf = x; + bufsz = xsz; + } + buf[off] = 0; - /* tag on a NUL to cap the string */ - if (off == bufsz) { - int xsz = bufsz + 1; - char* x = expand(buf, bufsz, xsz); - if (!x) { - snprintf(errbuf, errbufsz, "out of memory"); - xfree(buf); - return 0; - } - buf = x; - bufsz = xsz; - } - buf[off] = 0; - - /* parse it, cleanup and finish */ - toml_table_t* ret = toml_parse(buf, errbuf, errbufsz); - xfree(buf); - return ret; + /* parse it, cleanup and finish */ + toml_table_t *ret = toml_parse(buf, errbuf, errbufsz); + xfree(buf); + return ret; } - -static void xfree_kval(toml_keyval_t* p) -{ - if (!p) return; - xfree(p->key); - xfree(p->val); - xfree(p); +static void xfree_kval(toml_keyval_t *p) { + if (!p) + return; + xfree(p->key); + xfree(p->val); + xfree(p); } -static void xfree_tab(toml_table_t* p); +static void xfree_tab(toml_table_t *p); -static void xfree_arr(toml_array_t* p) -{ - if (!p) return; +static void xfree_arr(toml_array_t *p) { + if (!p) + return; - xfree(p->key); - const int n = p->nitem; - for (int i = 0; i < n; i++) { - toml_arritem_t* a = &p->item[i]; - if (a->val) - xfree(a->val); - else if (a->arr) - xfree_arr(a->arr); - else if (a->tab) - xfree_tab(a->tab); - } - xfree(p->item); - xfree(p); + xfree(p->key); + const int n = p->nitem; + for (int i = 0; i < n; i++) { + toml_arritem_t *a = &p->item[i]; + if (a->val) + xfree(a->val); + else if (a->arr) + xfree_arr(a->arr); + else if (a->tab) + xfree_tab(a->tab); + } + xfree(p->item); + xfree(p); } +static void xfree_tab(toml_table_t *p) { + int i; -static void xfree_tab(toml_table_t* p) -{ - int i; + if (!p) + return; - if (!p) return; + xfree(p->key); - xfree(p->key); + for (i = 0; i < p->nkval; i++) + xfree_kval(p->kval[i]); + xfree(p->kval); - for (i = 0; i < p->nkval; i++) xfree_kval(p->kval[i]); - xfree(p->kval); + for (i = 0; i < p->narr; i++) + xfree_arr(p->arr[i]); + xfree(p->arr); - for (i = 0; i < p->narr; i++) xfree_arr(p->arr[i]); - xfree(p->arr); + for (i = 0; i < p->ntab; i++) + xfree_tab(p->tab[i]); + xfree(p->tab); - for (i = 0; i < p->ntab; i++) xfree_tab(p->tab[i]); - xfree(p->tab); - - xfree(p); + xfree(p); } +void toml_free(toml_table_t *tab) { xfree_tab(tab); } -void toml_free(toml_table_t* tab) -{ - xfree_tab(tab); +static void set_token(context_t *ctx, tokentype_t tok, int lineno, char *ptr, + int len) { + token_t t; + t.tok = tok; + t.lineno = lineno; + t.ptr = ptr; + t.len = len; + t.eof = 0; + ctx->tok = t; } - -static void set_token(context_t* ctx, tokentype_t tok, int lineno, char* ptr, int len) -{ - token_t t; - t.tok = tok; - t.lineno = lineno; - t.ptr = ptr; - t.len = len; - t.eof = 0; - ctx->tok = t; +static void set_eof(context_t *ctx, int lineno) { + set_token(ctx, NEWLINE, lineno, ctx->stop, 0); + ctx->tok.eof = 1; } -static void set_eof(context_t* ctx, int lineno) -{ - set_token(ctx, NEWLINE, lineno, ctx->stop, 0); - ctx->tok.eof = 1; -} - - /* Scan p for n digits compositing entirely of [0-9] */ -static int scan_digits(const char* p, int n) -{ - int ret = 0; - for ( ; n > 0 && isdigit(*p); n--, p++) { - ret = 10 * ret + (*p - '0'); - } - return n ? -1 : ret; +static int scan_digits(const char *p, int n) { + int ret = 0; + for (; n > 0 && isdigit(*p); n--, p++) { + ret = 10 * ret + (*p - '0'); + } + return n ? -1 : ret; } -static int scan_date(const char* p, int* YY, int* MM, int* DD) -{ - int year, month, day; - year = scan_digits(p, 4); - month = (year >= 0 && p[4] == '-') ? scan_digits(p+5, 2) : -1; - day = (month >= 0 && p[7] == '-') ? scan_digits(p+8, 2) : -1; - if (YY) *YY = year; - if (MM) *MM = month; - if (DD) *DD = day; - return (year >= 0 && month >= 0 && day >= 0) ? 0 : -1; +static int scan_date(const char *p, int *YY, int *MM, int *DD) { + int year, month, day; + year = scan_digits(p, 4); + month = (year >= 0 && p[4] == '-') ? scan_digits(p + 5, 2) : -1; + day = (month >= 0 && p[7] == '-') ? scan_digits(p + 8, 2) : -1; + if (YY) + *YY = year; + if (MM) + *MM = month; + if (DD) + *DD = day; + return (year >= 0 && month >= 0 && day >= 0) ? 0 : -1; } -static int scan_time(const char* p, int* hh, int* mm, int* ss) -{ - int hour, minute, second; - hour = scan_digits(p, 2); - minute = (hour >= 0 && p[2] == ':') ? scan_digits(p+3, 2) : -1; - second = (minute >= 0 && p[5] == ':') ? scan_digits(p+6, 2) : -1; - if (hh) *hh = hour; - if (mm) *mm = minute; - if (ss) *ss = second; - return (hour >= 0 && minute >= 0 && second >= 0) ? 0 : -1; +static int scan_time(const char *p, int *hh, int *mm, int *ss) { + int hour, minute, second; + hour = scan_digits(p, 2); + minute = (hour >= 0 && p[2] == ':') ? scan_digits(p + 3, 2) : -1; + second = (minute >= 0 && p[5] == ':') ? scan_digits(p + 6, 2) : -1; + if (hh) + *hh = hour; + if (mm) + *mm = minute; + if (ss) + *ss = second; + return (hour >= 0 && minute >= 0 && second >= 0) ? 0 : -1; } +static int scan_string(context_t *ctx, char *p, int lineno, int dotisspecial) { + char *orig = p; + if (0 == strncmp(p, "'''", 3)) { + char *q = p + 3; -static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial) -{ - char* orig = p; - if (0 == strncmp(p, "'''", 3)) { - char* q = p + 3; + while (1) { + q = strstr(q, "'''"); + if (0 == q) { + return e_syntax(ctx, lineno, "unterminated triple-s-quote"); + } + while (q[3] == '\'') + q++; + break; + } - while (1) { - q = strstr(q, "'''"); - if (0 == q) { - return e_syntax(ctx, lineno, "unterminated triple-s-quote"); - } - while (q[3] == '\'') q++; - break; - } + set_token(ctx, STRING, lineno, orig, q + 3 - orig); + return 0; + } - set_token(ctx, STRING, lineno, orig, q + 3 - orig); - return 0; - } + if (0 == strncmp(p, "\"\"\"", 3)) { + char *q = p + 3; - if (0 == strncmp(p, "\"\"\"", 3)) { - char* q = p + 3; + while (1) { + q = strstr(q, "\"\"\""); + if (0 == q) { + return e_syntax(ctx, lineno, "unterminated triple-d-quote"); + } + if (q[-1] == '\\') { + q++; + continue; + } + while (q[3] == '\"') + q++; + break; + } - while (1) { - q = strstr(q, "\"\"\""); - if (0 == q) { - return e_syntax(ctx, lineno, "unterminated triple-d-quote"); - } - if (q[-1] == '\\') { - q++; - continue; - } - while (q[3] == '\"') q++; - break; - } + // the string is [p+3, q-1] - // the string is [p+3, q-1] + int hexreq = 0; /* #hex required */ + int escape = 0; + for (p += 3; p < q; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) + continue; + if (*p == 'u') { + hexreq = 4; + continue; + } + if (*p == 'U') { + hexreq = 8; + continue; + } + if (p[strspn(p, " \t\r")] == '\n') + continue; /* allow for line ending backslash */ + return e_syntax(ctx, lineno, "bad escape char"); + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) + continue; + return e_syntax(ctx, lineno, "expect hex char"); + } + if (*p == '\\') { + escape = 1; + continue; + } + } + if (escape) + return e_syntax(ctx, lineno, "expect an escape char"); + if (hexreq) + return e_syntax(ctx, lineno, "expected more hex char"); - int hexreq = 0; /* #hex required */ - int escape = 0; - for (p += 3; p < q; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - if (p[strspn(p, " \t\r")] == '\n') continue; /* allow for line ending backslash */ - return e_syntax(ctx, lineno, "bad escape char"); - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - return e_syntax(ctx, lineno, "expect hex char"); - } - if (*p == '\\') { escape = 1; continue; } - } - if (escape) - return e_syntax(ctx, lineno, "expect an escape char"); - if (hexreq) - return e_syntax(ctx, lineno, "expected more hex char"); + set_token(ctx, STRING, lineno, orig, q + 3 - orig); + return 0; + } - set_token(ctx, STRING, lineno, orig, q + 3 - orig); - return 0; - } + if ('\'' == *p) { + for (p++; *p && *p != '\n' && *p != '\''; p++) + ; + if (*p != '\'') { + return e_syntax(ctx, lineno, "unterminated s-quote"); + } - if ('\'' == *p) { - for (p++; *p && *p != '\n' && *p != '\''; p++); - if (*p != '\'') { - return e_syntax(ctx, lineno, "unterminated s-quote"); - } + set_token(ctx, STRING, lineno, orig, p + 1 - orig); + return 0; + } - set_token(ctx, STRING, lineno, orig, p + 1 - orig); - return 0; - } + if ('\"' == *p) { + int hexreq = 0; /* #hex required */ + int escape = 0; + for (p++; *p; p++) { + if (escape) { + escape = 0; + if (strchr("btnfr\"\\", *p)) + continue; + if (*p == 'u') { + hexreq = 4; + continue; + } + if (*p == 'U') { + hexreq = 8; + continue; + } + return e_syntax(ctx, lineno, "bad escape char"); + } + if (hexreq) { + hexreq--; + if (strchr("0123456789ABCDEF", *p)) + continue; + return e_syntax(ctx, lineno, "expect hex char"); + } + if (*p == '\\') { + escape = 1; + continue; + } + if (*p == '\'') { + if (p[1] == '\'' && p[2] == '\'') { + return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); + } + continue; + } + if (*p == '\n') + break; + if (*p == '"') + break; + } + if (*p != '"') { + return e_syntax(ctx, lineno, "unterminated quote"); + } - if ('\"' == *p) { - int hexreq = 0; /* #hex required */ - int escape = 0; - for (p++; *p; p++) { - if (escape) { - escape = 0; - if (strchr("btnfr\"\\", *p)) continue; - if (*p == 'u') { hexreq = 4; continue; } - if (*p == 'U') { hexreq = 8; continue; } - return e_syntax(ctx, lineno, "bad escape char"); - } - if (hexreq) { - hexreq--; - if (strchr("0123456789ABCDEF", *p)) continue; - return e_syntax(ctx, lineno, "expect hex char"); - } - if (*p == '\\') { escape = 1; continue; } - if (*p == '\'') { - if (p[1] == '\'' && p[2] == '\'') { - return e_syntax(ctx, lineno, "triple-s-quote inside string lit"); - } - continue; - } - if (*p == '\n') break; - if (*p == '"') break; - } - if (*p != '"') { - return e_syntax(ctx, lineno, "unterminated quote"); - } + set_token(ctx, STRING, lineno, orig, p + 1 - orig); + return 0; + } - set_token(ctx, STRING, lineno, orig, p + 1 - orig); - return 0; - } + /* check for timestamp without quotes */ + if (0 == scan_date(p, 0, 0, 0) || 0 == scan_time(p, 0, 0, 0)) { + // forward thru the timestamp + p += strspn(p, "0123456789.:+-T Z"); + // squeeze out any spaces at end of string + for (; p[-1] == ' '; p--) + ; + // tokenize + set_token(ctx, STRING, lineno, orig, p - orig); + return 0; + } - /* check for timestamp without quotes */ - if (0 == scan_date(p, 0, 0, 0) || 0 == scan_time(p, 0, 0, 0)) { - // forward thru the timestamp - p += strspn(p, "0123456789.:+-T Z"); - // squeeze out any spaces at end of string - for ( ; p[-1] == ' '; p--); - // tokenize - set_token(ctx, STRING, lineno, orig, p - orig); - return 0; - } + /* literals */ + for (; *p && *p != '\n'; p++) { + int ch = *p; + if (ch == '.' && dotisspecial) + break; + if ('A' <= ch && ch <= 'Z') + continue; + if ('a' <= ch && ch <= 'z') + continue; + if (strchr("0123456789+-_.", ch)) + continue; + break; + } - /* literals */ - for ( ; *p && *p != '\n'; p++) { - int ch = *p; - if (ch == '.' && dotisspecial) break; - if ('A' <= ch && ch <= 'Z') continue; - if ('a' <= ch && ch <= 'z') continue; - if (strchr("0123456789+-_.", ch)) continue; - break; - } - - set_token(ctx, STRING, lineno, orig, p - orig); - return 0; + set_token(ctx, STRING, lineno, orig, p - orig); + return 0; } +static int next_token(context_t *ctx, int dotisspecial) { + int lineno = ctx->tok.lineno; + char *p = ctx->tok.ptr; + int i; -static int next_token(context_t* ctx, int dotisspecial) -{ - int lineno = ctx->tok.lineno; - char* p = ctx->tok.ptr; - int i; + /* eat this tok */ + for (i = 0; i < ctx->tok.len; i++) { + if (*p++ == '\n') + lineno++; + } - /* eat this tok */ - for (i = 0; i < ctx->tok.len; i++) { - if (*p++ == '\n') - lineno++; - } + /* make next tok */ + while (p < ctx->stop) { + /* skip comment. stop just before the \n. */ + if (*p == '#') { + for (p++; p < ctx->stop && *p != '\n'; p++) + ; + continue; + } - /* make next tok */ - while (p < ctx->stop) { - /* skip comment. stop just before the \n. */ - if (*p == '#') { - for (p++; p < ctx->stop && *p != '\n'; p++); - continue; - } + if (dotisspecial && *p == '.') { + set_token(ctx, DOT, lineno, p, 1); + return 0; + } - if (dotisspecial && *p == '.') { - set_token(ctx, DOT, lineno, p, 1); - return 0; - } + switch (*p) { + case ',': + set_token(ctx, COMMA, lineno, p, 1); + return 0; + case '=': + set_token(ctx, EQUAL, lineno, p, 1); + return 0; + case '{': + set_token(ctx, LBRACE, lineno, p, 1); + return 0; + case '}': + set_token(ctx, RBRACE, lineno, p, 1); + return 0; + case '[': + set_token(ctx, LBRACKET, lineno, p, 1); + return 0; + case ']': + set_token(ctx, RBRACKET, lineno, p, 1); + return 0; + case '\n': + set_token(ctx, NEWLINE, lineno, p, 1); + return 0; + case '\r': + case ' ': + case '\t': + /* ignore white spaces */ + p++; + continue; + } - switch (*p) { - case ',': set_token(ctx, COMMA, lineno, p, 1); return 0; - case '=': set_token(ctx, EQUAL, lineno, p, 1); return 0; - case '{': set_token(ctx, LBRACE, lineno, p, 1); return 0; - case '}': set_token(ctx, RBRACE, lineno, p, 1); return 0; - case '[': set_token(ctx, LBRACKET, lineno, p, 1); return 0; - case ']': set_token(ctx, RBRACKET, lineno, p, 1); return 0; - case '\n': set_token(ctx, NEWLINE, lineno, p, 1); return 0; - case '\r': case ' ': case '\t': - /* ignore white spaces */ - p++; - continue; - } + return scan_string(ctx, p, lineno, dotisspecial); + } - return scan_string(ctx, p, lineno, dotisspecial); - } - - set_eof(ctx, lineno); - return 0; + set_eof(ctx, lineno); + return 0; } +const char *toml_key_in(const toml_table_t *tab, int keyidx) { + if (keyidx < tab->nkval) + return tab->kval[keyidx]->key; -const char* toml_key_in(const toml_table_t* tab, int keyidx) -{ - if (keyidx < tab->nkval) return tab->kval[keyidx]->key; + keyidx -= tab->nkval; + if (keyidx < tab->narr) + return tab->arr[keyidx]->key; - keyidx -= tab->nkval; - if (keyidx < tab->narr) return tab->arr[keyidx]->key; + keyidx -= tab->narr; + if (keyidx < tab->ntab) + return tab->tab[keyidx]->key; - keyidx -= tab->narr; - if (keyidx < tab->ntab) return tab->tab[keyidx]->key; - - return 0; + return 0; } -int toml_key_exists(const toml_table_t* tab, const char* key) -{ - int i; - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) - return 1; - } - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) - return 1; - } - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) - return 1; - } - return 0; +int toml_key_exists(const toml_table_t *tab, const char *key) { + int i; + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) + return 1; + } + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) + return 1; + } + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) + return 1; + } + return 0; } - -toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key) -{ - int i; - for (i = 0; i < tab->nkval; i++) { - if (0 == strcmp(key, tab->kval[i]->key)) - return tab->kval[i]->val; - } - return 0; +toml_raw_t toml_raw_in(const toml_table_t *tab, const char *key) { + int i; + for (i = 0; i < tab->nkval; i++) { + if (0 == strcmp(key, tab->kval[i]->key)) + return tab->kval[i]->val; + } + return 0; } -toml_array_t* toml_array_in(const toml_table_t* tab, const char* key) -{ - int i; - for (i = 0; i < tab->narr; i++) { - if (0 == strcmp(key, tab->arr[i]->key)) - return tab->arr[i]; - } - return 0; +toml_array_t *toml_array_in(const toml_table_t *tab, const char *key) { + int i; + for (i = 0; i < tab->narr; i++) { + if (0 == strcmp(key, tab->arr[i]->key)) + return tab->arr[i]; + } + return 0; } - -toml_table_t* toml_table_in(const toml_table_t* tab, const char* key) -{ - int i; - for (i = 0; i < tab->ntab; i++) { - if (0 == strcmp(key, tab->tab[i]->key)) - return tab->tab[i]; - } - return 0; +toml_table_t *toml_table_in(const toml_table_t *tab, const char *key) { + int i; + for (i = 0; i < tab->ntab; i++) { + if (0 == strcmp(key, tab->tab[i]->key)) + return tab->tab[i]; + } + return 0; } -toml_raw_t toml_raw_at(const toml_array_t* arr, int idx) -{ - return (0 <= idx && idx < arr->nitem) ? arr->item[idx].val : 0; +toml_raw_t toml_raw_at(const toml_array_t *arr, int idx) { + return (0 <= idx && idx < arr->nitem) ? arr->item[idx].val : 0; } -char toml_array_kind(const toml_array_t* arr) -{ - return arr->kind; +char toml_array_kind(const toml_array_t *arr) { return arr->kind; } + +char toml_array_type(const toml_array_t *arr) { + if (arr->kind != 'v') + return 0; + + if (arr->nitem == 0) + return 0; + + return arr->type; } -char toml_array_type(const toml_array_t* arr) -{ - if (arr->kind != 'v') - return 0; +int toml_array_nelem(const toml_array_t *arr) { return arr->nitem; } - if (arr->nitem == 0) - return 0; - - return arr->type; +const char *toml_array_key(const toml_array_t *arr) { + return arr ? arr->key : (const char *)NULL; } +int toml_table_nkval(const toml_table_t *tab) { return tab->nkval; } -int toml_array_nelem(const toml_array_t* arr) -{ - return arr->nitem; +int toml_table_narr(const toml_table_t *tab) { return tab->narr; } + +int toml_table_ntab(const toml_table_t *tab) { return tab->ntab; } + +const char *toml_table_key(const toml_table_t *tab) { + return tab ? tab->key : (const char *)NULL; } -const char* toml_array_key(const toml_array_t* arr) -{ - return arr ? arr->key : (const char*) NULL; +toml_array_t *toml_array_at(const toml_array_t *arr, int idx) { + return (0 <= idx && idx < arr->nitem) ? arr->item[idx].arr : 0; } -int toml_table_nkval(const toml_table_t* tab) -{ - return tab->nkval; +toml_table_t *toml_table_at(const toml_array_t *arr, int idx) { + return (0 <= idx && idx < arr->nitem) ? arr->item[idx].tab : 0; } -int toml_table_narr(const toml_table_t* tab) -{ - return tab->narr; +static int parse_millisec(const char *p, const char **endp); + +int toml_rtots(toml_raw_t src_, toml_timestamp_t *ret) { + if (!src_) + return -1; + + const char *p = src_; + int must_parse_time = 0; + + memset(ret, 0, sizeof(*ret)); + + int *year = &ret->__buffer.year; + int *month = &ret->__buffer.month; + int *day = &ret->__buffer.day; + int *hour = &ret->__buffer.hour; + int *minute = &ret->__buffer.minute; + int *second = &ret->__buffer.second; + int *millisec = &ret->__buffer.millisec; + + /* parse date YYYY-MM-DD */ + if (0 == scan_date(p, year, month, day)) { + ret->year = year; + ret->month = month; + ret->day = day; + + p += 10; + if (*p) { + // parse the T or space separator + if (*p != 'T' && *p != ' ') + return -1; + must_parse_time = 1; + p++; + } + } + + /* parse time HH:MM:SS */ + if (0 == scan_time(p, hour, minute, second)) { + ret->hour = hour; + ret->minute = minute; + ret->second = second; + + /* optionally, parse millisec */ + p += 8; + if (*p == '.') { + p++; /* skip '.' */ + const char *qq; + *millisec = parse_millisec(p, &qq); + ret->millisec = millisec; + p = qq; + } + + if (*p) { + /* parse and copy Z */ + char *z = ret->__buffer.z; + ret->z = z; + if (*p == 'Z' || *p == 'z') { + *z++ = 'Z'; + p++; + *z = 0; + + } else if (*p == '+' || *p == '-') { + *z++ = *p++; + + if (!(isdigit(p[0]) && isdigit(p[1]))) + return -1; + *z++ = *p++; + *z++ = *p++; + + if (*p == ':') { + *z++ = *p++; + + if (!(isdigit(p[0]) && isdigit(p[1]))) + return -1; + *z++ = *p++; + *z++ = *p++; + } + + *z = 0; + } + } + } + if (*p != 0) + return -1; + + if (must_parse_time && !ret->hour) + return -1; + + return 0; } -int toml_table_ntab(const toml_table_t* tab) -{ - return tab->ntab; -} - -const char* toml_table_key(const toml_table_t* tab) -{ - return tab ? tab->key : (const char*) NULL; -} - -toml_array_t* toml_array_at(const toml_array_t* arr, int idx) -{ - return (0 <= idx && idx < arr->nitem) ? arr->item[idx].arr : 0; -} - -toml_table_t* toml_table_at(const toml_array_t* arr, int idx) -{ - return (0 <= idx && idx < arr->nitem) ? arr->item[idx].tab : 0; -} - - -static int parse_millisec(const char* p, const char** endp); - -int toml_rtots(toml_raw_t src_, toml_timestamp_t* ret) -{ - if (! src_) return -1; - - const char* p = src_; - int must_parse_time = 0; - - memset(ret, 0, sizeof(*ret)); - - int* year = &ret->__buffer.year; - int* month = &ret->__buffer.month; - int* day = &ret->__buffer.day; - int* hour = &ret->__buffer.hour; - int* minute = &ret->__buffer.minute; - int* second = &ret->__buffer.second; - int* millisec = &ret->__buffer.millisec; - - /* parse date YYYY-MM-DD */ - if (0 == scan_date(p, year, month, day)) { - ret->year = year; - ret->month = month; - ret->day = day; - - p += 10; - if (*p) { - // parse the T or space separator - if (*p != 'T' && *p != ' ') return -1; - must_parse_time = 1; - p++; - } - } - - /* parse time HH:MM:SS */ - if (0 == scan_time(p, hour, minute, second)) { - ret->hour = hour; - ret->minute = minute; - ret->second = second; - - /* optionally, parse millisec */ - p += 8; - if (*p == '.') { - p++; /* skip '.' */ - const char* qq; - *millisec = parse_millisec(p, &qq); - ret->millisec = millisec; - p = qq; - } - - if (*p) { - /* parse and copy Z */ - char* z = ret->__buffer.z; - ret->z = z; - if (*p == 'Z' || *p == 'z') { - *z++ = 'Z'; p++; - *z = 0; - - } else if (*p == '+' || *p == '-') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - - if (*p == ':') { - *z++ = *p++; - - if (! (isdigit(p[0]) && isdigit(p[1]))) return -1; - *z++ = *p++; - *z++ = *p++; - } - - *z = 0; - } - } - } - if (*p != 0) - return -1; - - if (must_parse_time && !ret->hour) - return -1; - - return 0; -} - - /* Raw to boolean */ -int toml_rtob(toml_raw_t src, int* ret_) -{ - if (!src) return -1; - int dummy; - int* ret = ret_ ? ret_ : &dummy; +int toml_rtob(toml_raw_t src, int *ret_) { + if (!src) + return -1; + int dummy; + int *ret = ret_ ? ret_ : &dummy; - if (0 == strcmp(src, "true")) { - *ret = 1; - return 0; - } - if (0 == strcmp(src, "false")) { - *ret = 0; - return 0; - } - return -1; + if (0 == strcmp(src, "true")) { + *ret = 1; + return 0; + } + if (0 == strcmp(src, "false")) { + *ret = 0; + return 0; + } + return -1; } - /* Raw to integer */ -int toml_rtoi(toml_raw_t src, int64_t* ret_) -{ - if (!src) return -1; +int toml_rtoi(toml_raw_t src, int64_t *ret_) { + if (!src) + return -1; - char buf[100]; - char* p = buf; - char* q = p + sizeof(buf); - const char* s = src; - int base = 0; - int64_t dummy; - int64_t* ret = ret_ ? ret_ : &dummy; + char buf[100]; + char *p = buf; + char *q = p + sizeof(buf); + const char *s = src; + int base = 0; + int64_t dummy; + int64_t *ret = ret_ ? ret_ : &dummy; + /* allow +/- */ + if (s[0] == '+' || s[0] == '-') + *p++ = *s++; - /* allow +/- */ - if (s[0] == '+' || s[0] == '-') - *p++ = *s++; + /* disallow +_100 */ + if (s[0] == '_') + return -1; - /* disallow +_100 */ - if (s[0] == '_') - return -1; + /* if 0* ... */ + if ('0' == s[0]) { + switch (s[1]) { + case 'x': + base = 16; + s += 2; + break; + case 'o': + base = 8; + s += 2; + break; + case 'b': + base = 2; + s += 2; + break; + case '\0': + return *ret = 0, 0; + default: + /* ensure no other digits after it */ + if (s[1]) + return -1; + } + } - /* if 0* ... */ - if ('0' == s[0]) { - switch (s[1]) { - case 'x': base = 16; s += 2; break; - case 'o': base = 8; s += 2; break; - case 'b': base = 2; s += 2; break; - case '\0': return *ret = 0, 0; - default: - /* ensure no other digits after it */ - if (s[1]) return -1; - } - } + /* just strip underscores and pass to strtoll */ + while (*s && p < q) { + int ch = *s++; + if (ch == '_') { + // disallow '__' + if (s[0] == '_') + return -1; + // numbers cannot end with '_' + if (s[0] == '\0') + return -1; + continue; /* skip _ */ + } + *p++ = ch; + } - /* just strip underscores and pass to strtoll */ - while (*s && p < q) { - int ch = *s++; - if (ch == '_') { - // disallow '__' - if (s[0] == '_') return -1; - // numbers cannot end with '_' - if (s[0] == '\0') return -1; - continue; /* skip _ */ - } - *p++ = ch; - } + // if not at end-of-string or we ran out of buffer ... + if (*s || p == q) + return -1; - // if not at end-of-string or we ran out of buffer ... - if (*s || p == q) return -1; + /* cap with NUL */ + *p = 0; - /* cap with NUL */ - *p = 0; - - /* Run strtoll on buf to get the integer */ - char* endp; - errno = 0; - *ret = strtoll(buf, &endp, base); - return (errno || *endp) ? -1 : 0; + /* Run strtoll on buf to get the integer */ + char *endp; + errno = 0; + *ret = strtoll(buf, &endp, base); + return (errno || *endp) ? -1 : 0; } +int toml_rtod_ex(toml_raw_t src, double *ret_, char *buf, int buflen) { + if (!src) + return -1; -int toml_rtod_ex(toml_raw_t src, double* ret_, char* buf, int buflen) -{ - if (!src) return -1; + char *p = buf; + char *q = p + buflen; + const char *s = src; + double dummy; + double *ret = ret_ ? ret_ : &dummy; - char* p = buf; - char* q = p + buflen; - const char* s = src; - double dummy; - double* ret = ret_ ? ret_ : &dummy; + /* allow +/- */ + if (s[0] == '+' || s[0] == '-') + *p++ = *s++; + /* disallow +_1.00 */ + if (s[0] == '_') + return -1; - /* allow +/- */ - if (s[0] == '+' || s[0] == '-') - *p++ = *s++; + /* decimal point, if used, must be surrounded by at least one digit on each + * side */ + { + char *dot = strchr(s, '.'); + if (dot) { + if (dot == s || !isdigit(dot[-1]) || !isdigit(dot[1])) + return -1; + } + } - /* disallow +_1.00 */ - if (s[0] == '_') - return -1; + /* zero must be followed by . or 'e', or NUL */ + if (s[0] == '0' && s[1] && !strchr("eE.", s[1])) + return -1; - /* decimal point, if used, must be surrounded by at least one digit on each side */ - { - char* dot = strchr(s, '.'); - if (dot) { - if (dot == s || !isdigit(dot[-1]) || !isdigit(dot[1])) - return -1; - } - } + /* just strip underscores and pass to strtod */ + while (*s && p < q) { + int ch = *s++; + if (ch == '_') { + // disallow '__' + if (s[0] == '_') + return -1; + // disallow last char '_' + if (s[0] == 0) + return -1; + continue; /* skip _ */ + } + *p++ = ch; + } + if (*s || p == q) + return -1; /* reached end of string or buffer is full? */ - /* zero must be followed by . or 'e', or NUL */ - if (s[0] == '0' && s[1] && !strchr("eE.", s[1])) - return -1; + /* cap with NUL */ + *p = 0; - /* just strip underscores and pass to strtod */ - while (*s && p < q) { - int ch = *s++; - if (ch == '_') { - // disallow '__' - if (s[0] == '_') return -1; - // disallow last char '_' - if (s[0] == 0) return -1; - continue; /* skip _ */ - } - *p++ = ch; - } - if (*s || p == q) return -1; /* reached end of string or buffer is full? */ - - /* cap with NUL */ - *p = 0; - - /* Run strtod on buf to get the value */ - char* endp; - errno = 0; - *ret = strtod(buf, &endp); - return (errno || *endp) ? -1 : 0; + /* Run strtod on buf to get the value */ + char *endp; + errno = 0; + *ret = strtod(buf, &endp); + return (errno || *endp) ? -1 : 0; } -int toml_rtod(toml_raw_t src, double* ret_) -{ - char buf[100]; - return toml_rtod_ex(src, ret_, buf, sizeof(buf)); +int toml_rtod(toml_raw_t src, double *ret_) { + char buf[100]; + return toml_rtod_ex(src, ret_, buf, sizeof(buf)); } +int toml_rtos(toml_raw_t src, char **ret) { + int multiline = 0; + const char *sp; + const char *sq; + *ret = 0; + if (!src) + return -1; + int qchar = src[0]; + int srclen = strlen(src); + if (!(qchar == '\'' || qchar == '"')) { + return -1; + } -int toml_rtos(toml_raw_t src, char** ret) -{ - int multiline = 0; - const char* sp; - const char* sq; + // triple quotes? + if (qchar == src[1] && qchar == src[2]) { + multiline = 1; + sp = src + 3; + sq = src + srclen - 3; + /* last 3 chars in src must be qchar */ + if (!(sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) + return -1; - *ret = 0; - if (!src) return -1; + /* skip new line immediate after qchar */ + if (sp[0] == '\n') + sp++; + else if (sp[0] == '\r' && sp[1] == '\n') + sp += 2; - int qchar = src[0]; - int srclen = strlen(src); - if (! (qchar == '\'' || qchar == '"')) { - return -1; - } + } else { + sp = src + 1; + sq = src + srclen - 1; + /* last char in src must be qchar */ + if (!(sp <= sq && *sq == qchar)) + return -1; + } - // triple quotes? - if (qchar == src[1] && qchar == src[2]) { - multiline = 1; - sp = src + 3; - sq = src + srclen - 3; - /* last 3 chars in src must be qchar */ - if (! (sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) - return -1; + if (qchar == '\'') { + *ret = norm_lit_str(sp, sq - sp, multiline, 0, 0); + } else { + *ret = norm_basic_str(sp, sq - sp, multiline, 0, 0); + } - /* skip new line immediate after qchar */ - if (sp[0] == '\n') - sp++; - else if (sp[0] == '\r' && sp[1] == '\n') - sp += 2; - - } else { - sp = src + 1; - sq = src + srclen - 1; - /* last char in src must be qchar */ - if (! (sp <= sq && *sq == qchar)) - return -1; - } - - if (qchar == '\'') { - *ret = norm_lit_str(sp, sq - sp, - multiline, - 0, 0); - } else { - *ret = norm_basic_str(sp, sq - sp, - multiline, - 0, 0); - } - - return *ret ? 0 : -1; + return *ret ? 0 : -1; } - -toml_datum_t toml_string_at(const toml_array_t* arr, int idx) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtos(toml_raw_at(arr, idx), &ret.u.s)); - return ret; +toml_datum_t toml_string_at(const toml_array_t *arr, int idx) { + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + ret.ok = (0 == toml_rtos(toml_raw_at(arr, idx), &ret.u.s)); + return ret; } -toml_datum_t toml_bool_at(const toml_array_t* arr, int idx) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtob(toml_raw_at(arr, idx), &ret.u.b)); - return ret; +toml_datum_t toml_bool_at(const toml_array_t *arr, int idx) { + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + ret.ok = (0 == toml_rtob(toml_raw_at(arr, idx), &ret.u.b)); + return ret; } -toml_datum_t toml_int_at(const toml_array_t* arr, int idx) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtoi(toml_raw_at(arr, idx), &ret.u.i)); - return ret; +toml_datum_t toml_int_at(const toml_array_t *arr, int idx) { + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + ret.ok = (0 == toml_rtoi(toml_raw_at(arr, idx), &ret.u.i)); + return ret; } -toml_datum_t toml_double_at(const toml_array_t* arr, int idx) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtod(toml_raw_at(arr, idx), &ret.u.d)); - return ret; +toml_datum_t toml_double_at(const toml_array_t *arr, int idx) { + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + ret.ok = (0 == toml_rtod(toml_raw_at(arr, idx), &ret.u.d)); + return ret; } -toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx) -{ - toml_timestamp_t ts; - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtots(toml_raw_at(arr, idx), &ts)); - if (ret.ok) { - ret.ok = !!(ret.u.ts = MALLOC(sizeof(*ret.u.ts))); - if (ret.ok) { - *ret.u.ts = ts; - if (ret.u.ts->year) ret.u.ts->year = &ret.u.ts->__buffer.year; - if (ret.u.ts->month) ret.u.ts->month = &ret.u.ts->__buffer.month; - if (ret.u.ts->day) ret.u.ts->day = &ret.u.ts->__buffer.day; - if (ret.u.ts->hour) ret.u.ts->hour = &ret.u.ts->__buffer.hour; - if (ret.u.ts->minute) ret.u.ts->minute = &ret.u.ts->__buffer.minute; - if (ret.u.ts->second) ret.u.ts->second = &ret.u.ts->__buffer.second; - if (ret.u.ts->millisec) ret.u.ts->millisec = &ret.u.ts->__buffer.millisec; - if (ret.u.ts->z) ret.u.ts->z = ret.u.ts->__buffer.z; - } - } - return ret; +toml_datum_t toml_timestamp_at(const toml_array_t *arr, int idx) { + toml_timestamp_t ts; + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + ret.ok = (0 == toml_rtots(toml_raw_at(arr, idx), &ts)); + if (ret.ok) { + ret.ok = !!(ret.u.ts = MALLOC(sizeof(*ret.u.ts))); + if (ret.ok) { + *ret.u.ts = ts; + if (ret.u.ts->year) + ret.u.ts->year = &ret.u.ts->__buffer.year; + if (ret.u.ts->month) + ret.u.ts->month = &ret.u.ts->__buffer.month; + if (ret.u.ts->day) + ret.u.ts->day = &ret.u.ts->__buffer.day; + if (ret.u.ts->hour) + ret.u.ts->hour = &ret.u.ts->__buffer.hour; + if (ret.u.ts->minute) + ret.u.ts->minute = &ret.u.ts->__buffer.minute; + if (ret.u.ts->second) + ret.u.ts->second = &ret.u.ts->__buffer.second; + if (ret.u.ts->millisec) + ret.u.ts->millisec = &ret.u.ts->__buffer.millisec; + if (ret.u.ts->z) + ret.u.ts->z = ret.u.ts->__buffer.z; + } + } + return ret; } -toml_datum_t toml_string_in(const toml_table_t* arr, const char* key) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - toml_raw_t raw = toml_raw_in(arr, key); - if (raw) { - ret.ok = (0 == toml_rtos(raw, &ret.u.s)); - } - return ret; +toml_datum_t toml_string_in(const toml_table_t *arr, const char *key) { + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + toml_raw_t raw = toml_raw_in(arr, key); + if (raw) { + ret.ok = (0 == toml_rtos(raw, &ret.u.s)); + } + return ret; } -toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtob(toml_raw_in(arr, key), &ret.u.b)); - return ret; +toml_datum_t toml_bool_in(const toml_table_t *arr, const char *key) { + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + ret.ok = (0 == toml_rtob(toml_raw_in(arr, key), &ret.u.b)); + return ret; } -toml_datum_t toml_int_in(const toml_table_t* arr, const char* key) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtoi(toml_raw_in(arr, key), &ret.u.i)); - return ret; +toml_datum_t toml_int_in(const toml_table_t *arr, const char *key) { + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + ret.ok = (0 == toml_rtoi(toml_raw_in(arr, key), &ret.u.i)); + return ret; } -toml_datum_t toml_double_in(const toml_table_t* arr, const char* key) -{ - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtod(toml_raw_in(arr, key), &ret.u.d)); - return ret; +toml_datum_t toml_double_in(const toml_table_t *arr, const char *key) { + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + ret.ok = (0 == toml_rtod(toml_raw_in(arr, key), &ret.u.d)); + return ret; } -toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key) -{ - toml_timestamp_t ts; - toml_datum_t ret; - memset(&ret, 0, sizeof(ret)); - ret.ok = (0 == toml_rtots(toml_raw_in(arr, key), &ts)); - if (ret.ok) { - ret.ok = !!(ret.u.ts = MALLOC(sizeof(*ret.u.ts))); - if (ret.ok) { - *ret.u.ts = ts; - if (ret.u.ts->year) ret.u.ts->year = &ret.u.ts->__buffer.year; - if (ret.u.ts->month) ret.u.ts->month = &ret.u.ts->__buffer.month; - if (ret.u.ts->day) ret.u.ts->day = &ret.u.ts->__buffer.day; - if (ret.u.ts->hour) ret.u.ts->hour = &ret.u.ts->__buffer.hour; - if (ret.u.ts->minute) ret.u.ts->minute = &ret.u.ts->__buffer.minute; - if (ret.u.ts->second) ret.u.ts->second = &ret.u.ts->__buffer.second; - if (ret.u.ts->millisec) ret.u.ts->millisec = &ret.u.ts->__buffer.millisec; - if (ret.u.ts->z) ret.u.ts->z = ret.u.ts->__buffer.z; - } - } - return ret; +toml_datum_t toml_timestamp_in(const toml_table_t *arr, const char *key) { + toml_timestamp_t ts; + toml_datum_t ret; + memset(&ret, 0, sizeof(ret)); + ret.ok = (0 == toml_rtots(toml_raw_in(arr, key), &ts)); + if (ret.ok) { + ret.ok = !!(ret.u.ts = MALLOC(sizeof(*ret.u.ts))); + if (ret.ok) { + *ret.u.ts = ts; + if (ret.u.ts->year) + ret.u.ts->year = &ret.u.ts->__buffer.year; + if (ret.u.ts->month) + ret.u.ts->month = &ret.u.ts->__buffer.month; + if (ret.u.ts->day) + ret.u.ts->day = &ret.u.ts->__buffer.day; + if (ret.u.ts->hour) + ret.u.ts->hour = &ret.u.ts->__buffer.hour; + if (ret.u.ts->minute) + ret.u.ts->minute = &ret.u.ts->__buffer.minute; + if (ret.u.ts->second) + ret.u.ts->second = &ret.u.ts->__buffer.second; + if (ret.u.ts->millisec) + ret.u.ts->millisec = &ret.u.ts->__buffer.millisec; + if (ret.u.ts->z) + ret.u.ts->z = ret.u.ts->__buffer.z; + } + } + return ret; } - -static int parse_millisec(const char* p, const char** endp) -{ - int ret = 0; - int unit = 100; /* unit in millisec */ - for ( ; '0' <= *p && *p <= '9'; p++, unit /= 10) { - ret += (*p - '0') * unit; - } - *endp = p; - return ret; +static int parse_millisec(const char *p, const char **endp) { + int ret = 0; + int unit = 100; /* unit in millisec */ + for (; '0' <= *p && *p <= '9'; p++, unit /= 10) { + ret += (*p - '0') * unit; + } + *endp = p; + return ret; } diff --git a/toml.h b/toml.h index 03adcbe..82a81ce 100644 --- a/toml.h +++ b/toml.h @@ -25,10 +25,8 @@ #ifndef TOML_H #define TOML_H - -#include #include - +#include #ifdef __cplusplus #define TOML_EXTERN extern "C" @@ -44,134 +42,130 @@ typedef struct toml_datum_t toml_datum_t; /* Parse a file. Return a table on success, or 0 otherwise. * Caller must toml_free(the-return-value) after use. */ -TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, - char* errbuf, - int errbufsz); +TOML_EXTERN toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz); /* Parse a string containing the full config. * Return a table on success, or 0 otherwise. * Caller must toml_free(the-return-value) after use. */ -TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */ - char* errbuf, - int errbufsz); +TOML_EXTERN toml_table_t *toml_parse(char *conf, /* NUL terminated, please. */ + char *errbuf, int errbufsz); /* Free the table returned by toml_parse() or toml_parse_file(). Once * this function is called, any handles accessed through this tab * directly or indirectly are no longer valid. */ -TOML_EXTERN void toml_free(toml_table_t* tab); - +TOML_EXTERN void toml_free(toml_table_t *tab); /* Timestamp types. The year, month, day, hour, minute, second, z * fields may be NULL if they are not relevant. e.g. In a DATE * type, the hour, minute, second and z fields will be NULLs. */ struct toml_timestamp_t { - struct { /* internal. do not use. */ - int year, month, day; - int hour, minute, second, millisec; - char z[10]; - } __buffer; - int *year, *month, *day; - int *hour, *minute, *second, *millisec; - char* z; + struct { /* internal. do not use. */ + int year, month, day; + int hour, minute, second, millisec; + char z[10]; + } __buffer; + int *year, *month, *day; + int *hour, *minute, *second, *millisec; + char *z; }; - /*----------------------------------------------------------------- * Enhanced access methods */ struct toml_datum_t { - int ok; - union { - toml_timestamp_t* ts; /* ts must be freed after use */ - char* s; /* string value. s must be freed after use */ - int b; /* bool value */ - int64_t i; /* int value */ - double d; /* double value */ - } u; + int ok; + union { + toml_timestamp_t *ts; /* ts must be freed after use */ + char *s; /* string value. s must be freed after use */ + int b; /* bool value */ + int64_t i; /* int value */ + double d; /* double value */ + } u; }; /* on arrays: */ /* ... retrieve size of array. */ -TOML_EXTERN int toml_array_nelem(const toml_array_t* arr); +TOML_EXTERN int toml_array_nelem(const toml_array_t *arr); /* ... retrieve values using index. */ -TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t *arr, int idx); +TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t *arr, int idx); +TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t *arr, int idx); +TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t *arr, int idx); +TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t *arr, int idx); /* ... retrieve array or table using index. */ -TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx); -TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx); +TOML_EXTERN toml_array_t *toml_array_at(const toml_array_t *arr, int idx); +TOML_EXTERN toml_table_t *toml_table_at(const toml_array_t *arr, int idx); /* on tables: */ /* ... retrieve the key in table at keyidx. Return 0 if out of range. */ -TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx); +TOML_EXTERN const char *toml_key_in(const toml_table_t *tab, int keyidx); /* ... returns 1 if key exists in tab, 0 otherwise */ -TOML_EXTERN int toml_key_exists(const toml_table_t* tab, const char* key); +TOML_EXTERN int toml_key_exists(const toml_table_t *tab, const char *key); /* ... retrieve values using key. */ -TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t* arr, const char* key); -TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key); +TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t *arr, + const char *key); +TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t *arr, const char *key); +TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t *arr, const char *key); +TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t *arr, + const char *key); +TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t *arr, + const char *key); /* .. retrieve array or table using key. */ -TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab, - const char* key); -TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab, - const char* key); +TOML_EXTERN toml_array_t *toml_array_in(const toml_table_t *tab, + const char *key); +TOML_EXTERN toml_table_t *toml_table_in(const toml_table_t *tab, + const char *key); /*----------------------------------------------------------------- * lesser used */ /* Return the array kind: 't'able, 'a'rray, 'v'alue, 'm'ixed */ -TOML_EXTERN char toml_array_kind(const toml_array_t* arr); +TOML_EXTERN char toml_array_kind(const toml_array_t *arr); /* For array kind 'v'alue, return the type of values i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp, 'm'ixed 0 if unknown */ -TOML_EXTERN char toml_array_type(const toml_array_t* arr); +TOML_EXTERN char toml_array_type(const toml_array_t *arr); /* Return the key of an array */ -TOML_EXTERN const char* toml_array_key(const toml_array_t* arr); +TOML_EXTERN const char *toml_array_key(const toml_array_t *arr); /* Return the number of key-values in a table */ -TOML_EXTERN int toml_table_nkval(const toml_table_t* tab); +TOML_EXTERN int toml_table_nkval(const toml_table_t *tab); /* Return the number of arrays in a table */ -TOML_EXTERN int toml_table_narr(const toml_table_t* tab); +TOML_EXTERN int toml_table_narr(const toml_table_t *tab); /* Return the number of sub-tables in a table */ -TOML_EXTERN int toml_table_ntab(const toml_table_t* tab); +TOML_EXTERN int toml_table_ntab(const toml_table_t *tab); /* Return the key of a table*/ -TOML_EXTERN const char* toml_table_key(const toml_table_t* tab); +TOML_EXTERN const char *toml_table_key(const toml_table_t *tab); /*-------------------------------------------------------------- * misc */ -TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret); +TOML_EXTERN int toml_utf8_to_ucs(const char *orig, int len, int64_t *ret); TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]); -TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t), - void (*xxfree)(void*)); - +TOML_EXTERN void toml_set_memutil(void *(*xxmalloc)(size_t), + void (*xxfree)(void *)); /*-------------------------------------------------------------- * deprecated */ /* A raw value, must be processed by toml_rto* before using. */ -typedef const char* toml_raw_t; -TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key); -TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t* arr, int idx); -TOML_EXTERN int toml_rtos(toml_raw_t s, char** ret); -TOML_EXTERN int toml_rtob(toml_raw_t s, int* ret); -TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t* ret); -TOML_EXTERN int toml_rtod(toml_raw_t s, double* ret); -TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen); -TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret); - +typedef const char *toml_raw_t; +TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t *tab, const char *key); +TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t *arr, int idx); +TOML_EXTERN int toml_rtos(toml_raw_t s, char **ret); +TOML_EXTERN int toml_rtob(toml_raw_t s, int *ret); +TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t *ret); +TOML_EXTERN int toml_rtod(toml_raw_t s, double *ret); +TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double *ret, char *buf, int buflen); +TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t *ret); #endif /* TOML_H */ diff --git a/toml_cat.c b/toml_cat.c index 6203b5d..6fd5ec1 100644 --- a/toml_cat.c +++ b/toml_cat.c @@ -27,295 +27,296 @@ #undef NDEBUG #endif -#include -#include -#include -#include -#include -#include -#include -#include #include "toml.h" +#include +#include +#include +#include +#include +#include +#include +#include typedef struct node_t node_t; struct node_t { - const char* key; - toml_table_t* tab; + const char *key; + toml_table_t *tab; }; node_t stack[20]; int stacktop = 0; int indent = 0; -static void prindent() -{ - for (int i = 0; i < indent; i++) printf(" "); +static void prindent() { + for (int i = 0; i < indent; i++) + printf(" "); } +static void print_string(const char *s) { + int ok = 1; + for (const char *p = s; *p && ok; p++) { + int ch = *p; + ok = isprint(ch) && ch != '"' && ch != '\\'; + } -static void print_string(const char* s) -{ - int ok = 1; - for (const char* p = s; *p && ok; p++) { - int ch = *p; - ok = isprint(ch) && ch != '"' && ch != '\\'; - } + if (ok) { + printf("\"%s\"", s); + return; + } - if (ok) { - printf("\"%s\"", s); - return; - } + int len = strlen(s); - int len = strlen(s); + printf("\""); + for (; len; len--, s++) { + int ch = *s; + if (isprint(ch) && ch != '"' && ch != '\\') { + putchar(ch); + continue; + } - printf("\""); - for ( ; len; len--, s++) { - int ch = *s; - if (isprint(ch) && ch != '"' && ch != '\\') { - putchar(ch); - continue; - } - - switch (ch) { - case 0x8: printf("\\b"); continue; - case 0x9: printf("\\t"); continue; - case 0xa: printf("\\n"); continue; - case 0xc: printf("\\f"); continue; - case 0xd: printf("\\r"); continue; - case '"': printf("\\\""); continue; - case '\\': printf("\\\\"); continue; - default: printf("\\0x%02x", ch & 0xff); continue; - } - } - printf("\""); + switch (ch) { + case 0x8: + printf("\\b"); + continue; + case 0x9: + printf("\\t"); + continue; + case 0xa: + printf("\\n"); + continue; + case 0xc: + printf("\\f"); + continue; + case 0xd: + printf("\\r"); + continue; + case '"': + printf("\\\""); + continue; + case '\\': + printf("\\\\"); + continue; + default: + printf("\\0x%02x", ch & 0xff); + continue; + } + } + printf("\""); } +static void print_array(toml_array_t *arr); -static void print_array(toml_array_t* arr); - -static void print_timestamp(toml_datum_t d) -{ - if (d.u.ts->year) { - printf("%04d-%02d-%02d%s", *d.u.ts->year, *d.u.ts->month, *d.u.ts->day, - d.u.ts->hour ? "T" : ""); - } - if (d.u.ts->hour) { - printf("%02d:%02d:%02d", *d.u.ts->hour, *d.u.ts->minute, *d.u.ts->second); - if (d.u.ts->millisec) { - printf(".%03d", *d.u.ts->millisec); - } - if (d.u.ts->z) { - printf("%s", d.u.ts->z); - } - } +static void print_timestamp(toml_datum_t d) { + if (d.u.ts->year) { + printf("%04d-%02d-%02d%s", *d.u.ts->year, *d.u.ts->month, *d.u.ts->day, + d.u.ts->hour ? "T" : ""); + } + if (d.u.ts->hour) { + printf("%02d:%02d:%02d", *d.u.ts->hour, *d.u.ts->minute, *d.u.ts->second); + if (d.u.ts->millisec) { + printf(".%03d", *d.u.ts->millisec); + } + if (d.u.ts->z) { + printf("%s", d.u.ts->z); + } + } } +static void print_table(toml_table_t *curtab) { + toml_datum_t d; + int i; + const char *key; + toml_array_t *arr; + toml_table_t *tab; + for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { -static void print_table(toml_table_t* curtab) -{ - toml_datum_t d; - int i; - const char* key; - toml_array_t* arr; - toml_table_t* tab; + if (0 != (arr = toml_array_in(curtab, key))) { + prindent(); + printf("%s = [\n", key); + indent++; + print_array(arr); + indent--; + prindent(); + printf("],\n"); + continue; + } - for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { + if (0 != (tab = toml_table_in(curtab, key))) { + stack[stacktop].key = key; + stack[stacktop].tab = tab; + stacktop++; + prindent(); + printf("%s = {\n", key); + indent++; + print_table(tab); + indent--; + prindent(); + printf("},\n"); + stacktop--; + continue; + } - if (0 != (arr = toml_array_in(curtab, key))) { - prindent(); - printf("%s = [\n", key); - indent++; - print_array(arr); - indent--; - prindent(); - printf("],\n"); - continue; - } + d = toml_string_in(curtab, key); + if (d.ok) { + prindent(); + printf("%s = ", key); + print_string(d.u.s); + printf(",\n"); + free(d.u.s); + continue; + } - if (0 != (tab = toml_table_in(curtab, key))) { - stack[stacktop].key = key; - stack[stacktop].tab = tab; - stacktop++; - prindent(); - printf("%s = {\n", key); - indent++; - print_table(tab); - indent--; - prindent(); - printf("},\n"); - stacktop--; - continue; - } + d = toml_bool_in(curtab, key); + if (d.ok) { + prindent(); + printf("%s = %s,\n", key, d.u.b ? "true" : "false"); + continue; + } - d = toml_string_in(curtab, key); - if (d.ok) { - prindent(); - printf("%s = ", key); - print_string(d.u.s); - printf(",\n"); - free(d.u.s); - continue; - } + d = toml_int_in(curtab, key); + if (d.ok) { + prindent(); + printf("%s = %" PRId64 ",\n", key, d.u.i); + continue; + } - d = toml_bool_in(curtab, key); - if (d.ok) { - prindent(); - printf("%s = %s,\n", key, d.u.b ? "true" : "false"); - continue; - } + d = toml_double_in(curtab, key); + if (d.ok) { + prindent(); + printf("%s = %f,\n", key, d.u.d); + continue; + } - d = toml_int_in(curtab, key); - if (d.ok) { - prindent(); - printf("%s = %" PRId64 ",\n", key, d.u.i); - continue; - } + d = toml_timestamp_in(curtab, key); + if (d.ok) { + prindent(); + printf("%s = ", key); + print_timestamp(d); + printf(",\n"); + free(d.u.ts); + continue; + } - d = toml_double_in(curtab, key); - if (d.ok) { - prindent(); - printf("%s = %f,\n", key, d.u.d); - continue; - } - - d = toml_timestamp_in(curtab, key); - if (d.ok) { - prindent(); - printf("%s = ", key); - print_timestamp(d); - printf(",\n"); - free(d.u.ts); - continue; - } - - fflush(stdout); - fprintf(stderr, "ERROR: unable to decode value in table\n"); - exit(1); - } + fflush(stdout); + fprintf(stderr, "ERROR: unable to decode value in table\n"); + exit(1); + } } +static void print_array(toml_array_t *curarr) { + toml_datum_t d; + toml_array_t *arr; + toml_table_t *tab; + const int n = toml_array_nelem(curarr); -static void print_array(toml_array_t* curarr) -{ - toml_datum_t d; - toml_array_t* arr; - toml_table_t* tab; - const int n = toml_array_nelem(curarr); + for (int i = 0; i < n; i++) { - for (int i = 0; i < n; i++) { + if (0 != (arr = toml_array_at(curarr, i))) { + prindent(); + printf("[\n"); + indent++; + print_array(arr); + indent--; + prindent(); + printf("],\n"); + continue; + } - if (0 != (arr = toml_array_at(curarr, i))) { - prindent(); - printf("[\n"); - indent++; - print_array(arr); - indent--; - prindent(); - printf("],\n"); - continue; - } + if (0 != (tab = toml_table_at(curarr, i))) { + prindent(); + printf("{\n"); + indent++; + print_table(tab); + indent--; + prindent(); + printf("},\n"); + continue; + } - if (0 != (tab = toml_table_at(curarr, i))) { - prindent(); - printf("{\n"); - indent++; - print_table(tab); - indent--; - prindent(); - printf("},\n"); - continue; - } + d = toml_string_at(curarr, i); + if (d.ok) { + prindent(); + print_string(d.u.s); + printf(",\n"); + free(d.u.s); + continue; + } - d = toml_string_at(curarr, i); - if (d.ok) { - prindent(); - print_string(d.u.s); - printf(",\n"); - free(d.u.s); - continue; - } + d = toml_bool_at(curarr, i); + if (d.ok) { + prindent(); + printf("%s,\n", d.u.b ? "true" : "false"); + continue; + } - d = toml_bool_at(curarr, i); - if (d.ok) { - prindent(); - printf("%s,\n", d.u.b ? "true" : "false"); - continue; - } + d = toml_int_at(curarr, i); + if (d.ok) { + prindent(); + printf("%" PRId64 ",\n", d.u.i); + continue; + } - d = toml_int_at(curarr, i); - if (d.ok) { - prindent(); - printf("%" PRId64 ",\n", d.u.i); - continue; - } + d = toml_double_at(curarr, i); + if (d.ok) { + prindent(); + printf("%f,\n", d.u.d); + continue; + } - d = toml_double_at(curarr, i); - if (d.ok) { - prindent(); - printf("%f,\n", d.u.d); - continue; - } + d = toml_timestamp_at(curarr, i); + if (d.ok) { + prindent(); + print_timestamp(d); + printf(",\n"); + free(d.u.ts); + continue; + } - d = toml_timestamp_at(curarr, i); - if (d.ok) { - prindent(); - print_timestamp(d); - printf(",\n"); - free(d.u.ts); - continue; - } - - fflush(stdout); - fprintf(stderr, "ERROR: unable to decode value in array\n"); - exit(1); - } + fflush(stdout); + fprintf(stderr, "ERROR: unable to decode value in array\n"); + exit(1); + } } +static void cat(FILE *fp) { + char errbuf[200]; + toml_table_t *tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); + if (!tab) { + fprintf(stderr, "ERROR: %s\n", errbuf); + return; + } + stack[stacktop].tab = tab; + stack[stacktop].key = ""; + stacktop++; + printf("{\n"); + indent++; + print_table(tab); + indent--; + printf("}\n"); + stacktop--; -static void cat(FILE* fp) -{ - char errbuf[200]; - - toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); - if (!tab) { - fprintf(stderr, "ERROR: %s\n", errbuf); - return; - } - - stack[stacktop].tab = tab; - stack[stacktop].key = ""; - stacktop++; - printf("{\n"); - indent++; - print_table(tab); - indent--; - printf("}\n"); - stacktop--; - - toml_free(tab); + toml_free(tab); } +int main(int argc, const char *argv[]) { + int i; + if (argc == 1) { + cat(stdin); + } else { + for (i = 1; i < argc; i++) { -int main(int argc, const char* argv[]) -{ - int i; - if (argc == 1) { - cat(stdin); - } else { - for (i = 1; i < argc; i++) { - - FILE* fp = fopen(argv[i], "r"); - if (!fp) { - fprintf(stderr, "ERROR: cannot open %s: %s\n", - argv[i], strerror(errno)); - exit(1); - } - cat(fp); - fclose(fp); - } - } - return 0; + FILE *fp = fopen(argv[i], "r"); + if (!fp) { + fprintf(stderr, "ERROR: cannot open %s: %s\n", argv[i], + strerror(errno)); + exit(1); + } + cat(fp); + fclose(fp); + } + } + return 0; } diff --git a/toml_json.c b/toml_json.c index c2677d4..a939a23 100644 --- a/toml_json.c +++ b/toml_json.c @@ -26,189 +26,192 @@ #undef NDEBUG #endif -#include -#include -#include -#include -#include #include "toml.h" +#include +#include +#include +#include +#include - -static void print_escape_string(const char* s) -{ - for ( ; *s; s++) { - int ch = *s; - switch (ch) { - case '\b': printf("\\b"); break; - case '\t': printf("\\t"); break; - case '\n': printf("\\n"); break; - case '\f': printf("\\f"); break; - case '\r': printf("\\r"); break; - case '"': printf("\\\""); break; - case '\\': printf("\\\\"); break; - default: printf("%c", ch); break; - } - } +static void print_escape_string(const char *s) { + for (; *s; s++) { + int ch = *s; + switch (ch) { + case '\b': + printf("\\b"); + break; + case '\t': + printf("\\t"); + break; + case '\n': + printf("\\n"); + break; + case '\f': + printf("\\f"); + break; + case '\r': + printf("\\r"); + break; + case '"': + printf("\\\""); + break; + case '\\': + printf("\\\\"); + break; + default: + printf("%c", ch); + break; + } + } } -static void print_raw(const char* s) -{ - char* sval; - int64_t ival; - int bval; - double dval; - toml_timestamp_t ts; - char dbuf[100]; +static void print_raw(const char *s) { + char *sval; + int64_t ival; + int bval; + double dval; + toml_timestamp_t ts; + char dbuf[100]; - if (0 == toml_rtos(s, &sval)) { - printf("{\"type\":\"string\",\"value\":\""); - print_escape_string(sval); - printf("\"}"); - free(sval); - } else if (0 == toml_rtoi(s, &ival)) { - printf("{\"type\":\"integer\",\"value\":\"%" PRId64 "\"}", ival); - } else if (0 == toml_rtob(s, &bval)) { - printf("{\"type\":\"bool\",\"value\":\"%s\"}", bval ? "true" : "false"); - } else if (0 == toml_rtod_ex(s, &dval, dbuf, sizeof(dbuf))) { - printf("{\"type\":\"float\",\"value\":\"%s\"}", dbuf); - } else if (0 == toml_rtots(s, &ts)) { - char millisec[10]; - if (ts.millisec) - sprintf(millisec, ".%03d", *ts.millisec); - else - millisec[0] = 0; - if (ts.year && ts.hour) { - printf("{\"type\":\"datetime\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%s%s\"}", - *ts.year, *ts.month, *ts.day, *ts.hour, *ts.minute, *ts.second, - millisec, - (ts.z ? ts.z : "")); - } else if (ts.year) { - printf("{\"type\":\"date\",\"value\":\"%04d-%02d-%02d\"}", - *ts.year, *ts.month, *ts.day); - } else if (ts.hour) { - printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d%s\"}", - *ts.hour, *ts.minute, *ts.second, millisec); - } - } else { - fprintf(stderr, "unknown type\n"); - exit(1); - } + if (0 == toml_rtos(s, &sval)) { + printf("{\"type\":\"string\",\"value\":\""); + print_escape_string(sval); + printf("\"}"); + free(sval); + } else if (0 == toml_rtoi(s, &ival)) { + printf("{\"type\":\"integer\",\"value\":\"%" PRId64 "\"}", ival); + } else if (0 == toml_rtob(s, &bval)) { + printf("{\"type\":\"bool\",\"value\":\"%s\"}", bval ? "true" : "false"); + } else if (0 == toml_rtod_ex(s, &dval, dbuf, sizeof(dbuf))) { + printf("{\"type\":\"float\",\"value\":\"%s\"}", dbuf); + } else if (0 == toml_rtots(s, &ts)) { + char millisec[10]; + if (ts.millisec) + sprintf(millisec, ".%03d", *ts.millisec); + else + millisec[0] = 0; + if (ts.year && ts.hour) { + printf("{\"type\":\"datetime\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%" + "s%s\"}", + *ts.year, *ts.month, *ts.day, *ts.hour, *ts.minute, *ts.second, + millisec, (ts.z ? ts.z : "")); + } else if (ts.year) { + printf("{\"type\":\"date\",\"value\":\"%04d-%02d-%02d\"}", *ts.year, + *ts.month, *ts.day); + } else if (ts.hour) { + printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d%s\"}", *ts.hour, + *ts.minute, *ts.second, millisec); + } + } else { + fprintf(stderr, "unknown type\n"); + exit(1); + } } +static void print_array(toml_array_t *arr); +static void print_table(toml_table_t *curtab) { + int i; + const char *key; + const char *raw; + toml_array_t *arr; + toml_table_t *tab; -static void print_array(toml_array_t* arr); -static void print_table(toml_table_t* curtab) -{ - int i; - const char* key; - const char* raw; - toml_array_t* arr; - toml_table_t* tab; + printf("{"); + for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { + printf("%s\"", i > 0 ? "," : ""); + print_escape_string(key); + printf("\":"); - printf("{"); - for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) { - - printf("%s\"", i > 0 ? "," : ""); - print_escape_string(key); - printf("\":"); - - if (0 != (raw = toml_raw_in(curtab, key))) { - print_raw(raw); - } else if (0 != (arr = toml_array_in(curtab, key))) { - print_array(arr); - } else if (0 != (tab = toml_table_in(curtab, key))) { - print_table(tab); - } else { - abort(); - } - } - printf("}"); + if (0 != (raw = toml_raw_in(curtab, key))) { + print_raw(raw); + } else if (0 != (arr = toml_array_in(curtab, key))) { + print_array(arr); + } else if (0 != (tab = toml_table_in(curtab, key))) { + print_table(tab); + } else { + abort(); + } + } + printf("}"); } -static void print_table_array(toml_array_t* curarr) -{ - int i; - toml_table_t* tab; - - printf("["); - for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) { - printf("%s", i > 0 ? "," : ""); - print_table(tab); - } - printf("]"); +static void print_table_array(toml_array_t *curarr) { + int i; + toml_table_t *tab; + + printf("["); + for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) { + printf("%s", i > 0 ? "," : ""); + print_table(tab); + } + printf("]"); } -static void print_array(toml_array_t* curarr) -{ - toml_array_t* arr; - const char* raw; - int i; +static void print_array(toml_array_t *curarr) { + toml_array_t *arr; + const char *raw; + int i; - if (toml_array_kind(curarr) == 't') { - print_table_array(curarr); - return; - } + if (toml_array_kind(curarr) == 't') { + print_table_array(curarr); + return; + } - printf("{\"type\":\"array\",\"value\":["); - switch (toml_array_kind(curarr)) { + printf("{\"type\":\"array\",\"value\":["); + switch (toml_array_kind(curarr)) { - case 'v': - for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { - printf("%s", i > 0 ? "," : ""); - print_raw(raw); - } - break; + case 'v': + for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { + printf("%s", i > 0 ? "," : ""); + print_raw(raw); + } + break; - case 'a': - for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) { - printf("%s", i > 0 ? "," : ""); - print_array(arr); - } - break; + case 'a': + for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) { + printf("%s", i > 0 ? "," : ""); + print_array(arr); + } + break; - default: - break; - } - printf("]}"); + default: + break; + } + printf("]}"); } +static void cat(FILE *fp) { + char errbuf[200]; + toml_table_t *tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); + if (!tab) { + fprintf(stderr, "ERROR: %s\n", errbuf); + exit(1); + } -static void cat(FILE* fp) -{ - char errbuf[200]; - - toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf)); - if (!tab) { - fprintf(stderr, "ERROR: %s\n", errbuf); - exit(1); - } + print_table(tab); + printf("\n"); - print_table(tab); - printf("\n"); - - toml_free(tab); + toml_free(tab); } +int main(int argc, const char *argv[]) { + int i; + if (argc == 1) { + cat(stdin); + } else { + for (i = 1; i < argc; i++) { -int main(int argc, const char* argv[]) -{ - int i; - if (argc == 1) { - cat(stdin); - } else { - for (i = 1; i < argc; i++) { - - FILE* fp = fopen(argv[i], "r"); - if (!fp) { - fprintf(stderr, "ERROR: cannot open %s: %s\n", - argv[i], strerror(errno)); - exit(1); - } - cat(fp); - fclose(fp); - } - } - return 0; + FILE *fp = fopen(argv[i], "r"); + if (!fp) { + fprintf(stderr, "ERROR: cannot open %s: %s\n", argv[i], + strerror(errno)); + exit(1); + } + cat(fp); + fclose(fp); + } + } + return 0; } diff --git a/toml_sample.c b/toml_sample.c index f9b635b..a8c3b9d 100644 --- a/toml_sample.c +++ b/toml_sample.c @@ -1,62 +1,60 @@ -#include -#include -#include -#include #include "toml.h" +#include +#include +#include +#include -static void fatal(const char* msg, const char* msg1) -{ - fprintf(stderr, "ERROR: %s%s\n", msg, msg1?msg1:""); - exit(1); +static void fatal(const char *msg, const char *msg1) { + fprintf(stderr, "ERROR: %s%s\n", msg, msg1 ? msg1 : ""); + exit(1); } +int main() { + FILE *fp; + char errbuf[200]; -int main() -{ - FILE* fp; - char errbuf[200]; + // 1. Read and parse toml file + fp = fopen("sample.toml", "r"); + if (!fp) { + fatal("cannot open sample.toml - ", strerror(errno)); + } - // 1. Read and parse toml file - fp = fopen("sample.toml", "r"); - if (!fp) { - fatal("cannot open sample.toml - ", strerror(errno)); - } + toml_table_t *conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); + fclose(fp); - toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf)); - fclose(fp); + if (!conf) { + fatal("cannot parse - ", errbuf); + } - if (!conf) { - fatal("cannot parse - ", errbuf); - } + // 2. Traverse to a table. + toml_table_t *server = toml_table_in(conf, "server"); + if (!server) { + fatal("missing [server]", ""); + } - // 2. Traverse to a table. - toml_table_t* server = toml_table_in(conf, "server"); - if (!server) { - fatal("missing [server]", ""); - } + // 3. Extract values + toml_datum_t host = toml_string_in(server, "host"); + if (!host.ok) { + fatal("cannot read server.host", ""); + } - // 3. Extract values - toml_datum_t host = toml_string_in(server, "host"); - if (!host.ok) { - fatal("cannot read server.host", ""); - } + toml_array_t *portarray = toml_array_in(server, "port"); + if (!portarray) { + fatal("cannot read server.port", ""); + } - toml_array_t* portarray = toml_array_in(server, "port"); - if (!portarray) { - fatal("cannot read server.port", ""); - } + printf("host: %s\n", host.u.s); + printf("port: "); + for (int i = 0;; i++) { + toml_datum_t port = toml_int_at(portarray, i); + if (!port.ok) + break; + printf("%d ", (int)port.u.i); + } + printf("\n"); - printf("host: %s\n", host.u.s); - printf("port: "); - for (int i = 0; ; i++) { - toml_datum_t port = toml_int_at(portarray, i); - if (!port.ok) break; - printf("%d ", (int)port.u.i); - } - printf("\n"); - - // 4. Free memory - free(host.u.s); - toml_free(conf); - return 0; + // 4. Free memory + free(host.u.s); + toml_free(conf); + return 0; } From d3a4391ae98af9cc1096f73e81842dc8354621aa Mon Sep 17 00:00:00 2001 From: CK Tan Date: Wed, 5 Jan 2022 06:02:11 +0000 Subject: [PATCH 128/138] format --- Makefile | 13 +++---- unittest/t1.c | 106 +++++++++++++++++++++++++++++--------------------- 2 files changed, 66 insertions(+), 53 deletions(-) diff --git a/Makefile b/Makefile index 1ca63f2..b525b12 100644 --- a/Makefile +++ b/Makefile @@ -29,13 +29,7 @@ libtoml.a: toml.o libtoml.so.$(LIB_VERSION): toml.o $(CC) -shared -o $@ $^ -toml_json: toml_json.c $(LIB) - -toml_cat: toml_cat.c $(LIB) - -toml_sample: toml_sample.c $(LIB) - - +$(EXEC): $(LIB) install: all install -d ${prefix}/include ${prefix}/lib @@ -50,4 +44,7 @@ clean: rm -f *.o $(EXEC) $(LIB) $(LIB_SHARED) -.PHONY: all clean install +format: + clang-format -i $(shell find . -name '*.[ch]') + +.PHONY: all clean install format diff --git a/unittest/t1.c b/unittest/t1.c index 065ba0a..3da3901 100644 --- a/unittest/t1.c +++ b/unittest/t1.c @@ -1,57 +1,73 @@ -#include +#include "../toml.h" #include #include +#include #include -#include "../toml.h" +int main(int argc, const char *argv[]) { + char xxbuf[6], buf[6]; + int64_t xxcode, code; + int xxsize; + xxsize = 2, xxcode = 0x80; + memcpy(xxbuf, "\xc2\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); -int main(int argc, const char* argv[]) -{ - char xxbuf[6], buf[6]; - int64_t xxcode, code; - int xxsize; - - - xxsize = 2, xxcode = 0x80; memcpy(xxbuf, "\xc2\x80", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + xxsize = 2, xxcode = 0x7ff; + memcpy(xxbuf, "\xdf\xbf", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - xxsize = 2, xxcode = 0x7ff; memcpy(xxbuf, "\xdf\xbf", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + xxsize = 3, xxcode = 0x800; + memcpy(xxbuf, "\xe0\xa0\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - xxsize = 3, xxcode = 0x800; memcpy(xxbuf, "\xe0\xa0\x80", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - - xxsize = 3, xxcode = 0xfffd; memcpy(xxbuf, "\xef\xbf\xbd", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - - xxsize = 4, xxcode = 0x10000; memcpy(xxbuf, "\xf0\x90\x80\x80", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - - xxsize = 4, xxcode = 0x1fffff; memcpy(xxbuf, "\xf7\xbf\xbf\xbf", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + xxsize = 3, xxcode = 0xfffd; + memcpy(xxbuf, "\xef\xbf\xbd", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - xxsize = 5, xxcode = 0x200000; memcpy(xxbuf, "\xf8\x88\x80\x80\x80", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - - xxsize = 5, xxcode = 0x3ffffff; memcpy(xxbuf, "\xfb\xbf\xbf\xbf\xbf", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + xxsize = 4, xxcode = 0x10000; + memcpy(xxbuf, "\xf0\x90\x80\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - xxsize = 6, xxcode = 0x4000000; memcpy(xxbuf, "\xfc\x84\x80\x80\x80\x80", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + xxsize = 4, xxcode = 0x1fffff; + memcpy(xxbuf, "\xf7\xbf\xbf\xbf", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - xxsize = 6, xxcode = 0x7fffffff; memcpy(xxbuf, "\xfd\xbf\xbf\xbf\xbf\xbf", xxsize); - assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && 0 == memcmp(buf, xxbuf, xxsize)); - assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + xxsize = 5, xxcode = 0x200000; + memcpy(xxbuf, "\xf8\x88\x80\x80\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); - return 0; -} + xxsize = 5, xxcode = 0x3ffffff; + memcpy(xxbuf, "\xfb\xbf\xbf\xbf\xbf", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 6, xxcode = 0x4000000; + memcpy(xxbuf, "\xfc\x84\x80\x80\x80\x80", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + xxsize = 6, xxcode = 0x7fffffff; + memcpy(xxbuf, "\xfd\xbf\xbf\xbf\xbf\xbf", xxsize); + assert(toml_ucs_to_utf8(xxcode, buf) == xxsize && + 0 == memcmp(buf, xxbuf, xxsize)); + assert(toml_utf8_to_ucs(buf, xxsize, &code) == xxsize && code == xxcode); + + return 0; +} From 99c1e332226b4dfb02f5d7723c7843c912186bdd Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 28 Mar 2022 05:54:28 -0700 Subject: [PATCH 129/138] minor --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6715b5b..2c90c26 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ If you are looking for a C++ library, you might try this wrapper: [https://githu ## Usage -Please see the `toml.h` file for details. What follows is a simple example that +Please see the `toml.h` file for details. The following is a simple example that parses this config file: ```toml @@ -22,7 +22,7 @@ parses this config file: port = [ 8080, 8181, 8282 ] ``` -The steps for getting values from our file is usually : +These are the usual steps for getting values from a file: 1. Parse the TOML file. 2. Traverse and locate a table in TOML. From 8a863d1ec8e15c96d32de70eaf315b2939e2bbee Mon Sep 17 00:00:00 2001 From: Vladislav Laetansky <87545780+vlaetansky@users.noreply.github.com> Date: Mon, 4 Apr 2022 21:24:53 +0300 Subject: [PATCH 130/138] MSVC warnings fix (#72) --- toml.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/toml.c b/toml.c index 99baaf2..1deaac2 100644 --- a/toml.c +++ b/toml.c @@ -220,8 +220,8 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 110xxxxx 10xxxxxx */ if (code <= 0x000007FF) { - buf[0] = 0xc0 | (code >> 6); - buf[1] = 0x80 | (code & 0x3f); + buf[0] = (unsigned char) (0xc0 | (code >> 6)); + buf[1] = (unsigned char) (0x80 | (code & 0x3f)); return 2; } @@ -229,9 +229,9 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 1110xxxx 10xxxxxx 10xxxxxx */ if (code <= 0x0000FFFF) { - buf[0] = 0xe0 | (code >> 12); - buf[1] = 0x80 | ((code >> 6) & 0x3f); - buf[2] = 0x80 | (code & 0x3f); + buf[0] = (unsigned char) (0xe0 | (code >> 12)); + buf[1] = (unsigned char) (0x80 | ((code >> 6) & 0x3f)); + buf[2] = (unsigned char) (0x80 | (code & 0x3f)); return 3; } @@ -239,10 +239,10 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (code <= 0x001FFFFF) { - buf[0] = 0xf0 | (code >> 18); - buf[1] = 0x80 | ((code >> 12) & 0x3f); - buf[2] = 0x80 | ((code >> 6) & 0x3f); - buf[3] = 0x80 | (code & 0x3f); + buf[0] = (unsigned char) (0xf0 | (code >> 18)); + buf[1] = (unsigned char) (0x80 | ((code >> 12) & 0x3f)); + buf[2] = (unsigned char) (0x80 | ((code >> 6) & 0x3f)); + buf[3] = (unsigned char) (0x80 | (code & 0x3f)); return 4; } @@ -250,11 +250,11 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (code <= 0x03FFFFFF) { - buf[0] = 0xf8 | (code >> 24); - buf[1] = 0x80 | ((code >> 18) & 0x3f); - buf[2] = 0x80 | ((code >> 12) & 0x3f); - buf[3] = 0x80 | ((code >> 6) & 0x3f); - buf[4] = 0x80 | (code & 0x3f); + buf[0] = (unsigned char) (0xf8 | (code >> 24)); + buf[1] = (unsigned char) (0x80 | ((code >> 18) & 0x3f)); + buf[2] = (unsigned char) (0x80 | ((code >> 12) & 0x3f)); + buf[3] = (unsigned char) (0x80 | ((code >> 6) & 0x3f)); + buf[4] = (unsigned char) (0x80 | (code & 0x3f)); return 5; } @@ -262,12 +262,12 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (code <= 0x7FFFFFFF) { - buf[0] = 0xfc | (code >> 30); - buf[1] = 0x80 | ((code >> 24) & 0x3f); - buf[2] = 0x80 | ((code >> 18) & 0x3f); - buf[3] = 0x80 | ((code >> 12) & 0x3f); - buf[4] = 0x80 | ((code >> 6) & 0x3f); - buf[5] = 0x80 | (code & 0x3f); + buf[0] = (unsigned char) (0xfc | (code >> 30)); + buf[1] = (unsigned char) (0x80 | ((code >> 24) & 0x3f)); + buf[2] = (unsigned char) (0x80 | ((code >> 18) & 0x3f)); + buf[3] = (unsigned char) (0x80 | ((code >> 12) & 0x3f)); + buf[4] = (unsigned char) (0x80 | ((code >> 6) & 0x3f)); + buf[5] = (unsigned char) (0x80 | (code & 0x3f)); return 6; } @@ -1496,6 +1496,7 @@ toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz) { int n = fread(buf + off, 1, bufsz - off, fp); if (ferror(fp)) { snprintf(errbuf, errbufsz, "%s", + #pragma warning(suppress : 4996) errno ? strerror(errno) : "Error reading file"); xfree(buf); return 0; From 4e7b082ccc44316f212597ae5b09a35cf9329e69 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 4 Apr 2022 11:28:49 -0700 Subject: [PATCH 131/138] removed pragma that caused warning on gcc --- toml.c | 1 - 1 file changed, 1 deletion(-) diff --git a/toml.c b/toml.c index 1deaac2..fafe0da 100644 --- a/toml.c +++ b/toml.c @@ -1496,7 +1496,6 @@ toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz) { int n = fread(buf + off, 1, bufsz - off, fp); if (ferror(fp)) { snprintf(errbuf, errbufsz, "%s", - #pragma warning(suppress : 4996) errno ? strerror(errno) : "Error reading file"); xfree(buf); return 0; From 034b23ed3e4e5ee5345040eabed470f204d7f668 Mon Sep 17 00:00:00 2001 From: Vladislav Laetansky <87545780+vlaetansky@users.noreply.github.com> Date: Sun, 17 Apr 2022 23:09:01 +0300 Subject: [PATCH 132/138] msvc warning 4996 disable pragma (#73) --- toml.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/toml.h b/toml.h index 82a81ce..19dc3d2 100644 --- a/toml.h +++ b/toml.h @@ -25,6 +25,10 @@ #ifndef TOML_H #define TOML_H +#ifdef _MSC_VER +#pragma warning(disable: 4996) +#endif + #include #include From e4107c455491925b8982c22df1ce37c0ccb7d4e4 Mon Sep 17 00:00:00 2001 From: Kamil Giszczak Date: Wed, 27 Jul 2022 21:06:50 +0200 Subject: [PATCH 133/138] Allow to use 't' (lower case T) as a date-time delimiter (#76) as specified by TOML ABNF grammar: https://github.com/toml-lang/toml/blob/1.0.0/toml.abnf#L169 --- toml.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toml.c b/toml.c index fafe0da..2f4dc03 100644 --- a/toml.c +++ b/toml.c @@ -1768,7 +1768,7 @@ static int scan_string(context_t *ctx, char *p, int lineno, int dotisspecial) { /* check for timestamp without quotes */ if (0 == scan_date(p, 0, 0, 0) || 0 == scan_time(p, 0, 0, 0)) { // forward thru the timestamp - p += strspn(p, "0123456789.:+-T Z"); + p += strspn(p, "0123456789.:+-Tt Zz"); // squeeze out any spaces at end of string for (; p[-1] == ' '; p--) ; @@ -1984,7 +1984,7 @@ int toml_rtots(toml_raw_t src_, toml_timestamp_t *ret) { p += 10; if (*p) { // parse the T or space separator - if (*p != 'T' && *p != ' ') + if (*p != 'T' && *p != 't' && *p != ' ') return -1; must_parse_time = 1; p++; From 894902820a3ea2f1ec470cd7fe338bde54045cf5 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 12 Sep 2022 10:14:48 -0700 Subject: [PATCH 134/138] minor fix to CALLOC --- toml.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toml.c b/toml.c index 2f4dc03..67dd0f8 100644 --- a/toml.c +++ b/toml.c @@ -45,6 +45,7 @@ void toml_set_memutil(void *(*xxmalloc)(size_t), void (*xxfree)(void *)) { ppfree = xxfree; } +#define ALIGN8(sz) (((sz) + 7) & ~7) #define MALLOC(a) ppmalloc(a) #define FREE(a) ppfree(a) @@ -53,7 +54,7 @@ void toml_set_memutil(void *(*xxmalloc)(size_t), void (*xxfree)(void *)) { #define calloc(x, y) error - forbidden - use CALLOC instead static void *CALLOC(size_t nmemb, size_t sz) { - int nb = sz * nmemb; + int nb = ALIGN8(sz) * nmemb; void *p = MALLOC(nb); if (p) { memset(p, 0, nb); From d4c94500c4aca9f280b6b6ee01f337b12f6f7b75 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 29 May 2023 12:31:52 -0700 Subject: [PATCH 135/138] fix: make install fail when libtoml.pc does not exist --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index b525b12..599f7db 100644 --- a/Makefile +++ b/Makefile @@ -37,8 +37,11 @@ install: all install $(LIB) ${prefix}/lib install $(LIB_SHARED) ${prefix}/lib ifeq "$(prefix)" "/usr/local" +ifneq ("$(wildcard $(PCFILE))","") install $(PCFILE) /usr/local/lib/pkgconfig endif +endif + clean: rm -f *.o $(EXEC) $(LIB) $(LIB_SHARED) From 52e9c039c5418a100605c2db1282590511fa891b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlad-=C8=98tefan=20Harbuz?= <291640+vladh@users.noreply.github.com> Date: Mon, 29 May 2023 20:36:32 +0100 Subject: [PATCH 136/138] add missing null pointer checks (#80) The result of copying a null pointer is undefined. --- toml.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/toml.c b/toml.c index 67dd0f8..0502e49 100644 --- a/toml.c +++ b/toml.c @@ -412,8 +412,10 @@ static void *expand(void *p, int sz, int newsz) { if (!s) return 0; - memcpy(s, p, sz); - FREE(p); + if (p) { + memcpy(s, p, sz); + FREE(p); + } return s; } @@ -423,8 +425,10 @@ static void **expand_ptrarr(void **p, int n) { return 0; s[n] = 0; - memcpy(s, p, n * sizeof(void *)); - FREE(p); + if (p) { + memcpy(s, p, n * sizeof(void *)); + FREE(p); + } return s; } From 6fe7fee127c4d1ceea71e24405e62d01ce1f0840 Mon Sep 17 00:00:00 2001 From: CK Tan Date: Mon, 18 Sep 2023 20:28:16 -0700 Subject: [PATCH 137/138] format and comment only --- toml.c | 66 ++++++++++++++++++++++++++++++++-------------------------- toml.h | 2 +- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/toml.c b/toml.c index 0502e49..e7b878e 100644 --- a/toml.c +++ b/toml.c @@ -221,8 +221,8 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 110xxxxx 10xxxxxx */ if (code <= 0x000007FF) { - buf[0] = (unsigned char) (0xc0 | (code >> 6)); - buf[1] = (unsigned char) (0x80 | (code & 0x3f)); + buf[0] = (unsigned char)(0xc0 | (code >> 6)); + buf[1] = (unsigned char)(0x80 | (code & 0x3f)); return 2; } @@ -230,9 +230,9 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 1110xxxx 10xxxxxx 10xxxxxx */ if (code <= 0x0000FFFF) { - buf[0] = (unsigned char) (0xe0 | (code >> 12)); - buf[1] = (unsigned char) (0x80 | ((code >> 6) & 0x3f)); - buf[2] = (unsigned char) (0x80 | (code & 0x3f)); + buf[0] = (unsigned char)(0xe0 | (code >> 12)); + buf[1] = (unsigned char)(0x80 | ((code >> 6) & 0x3f)); + buf[2] = (unsigned char)(0x80 | (code & 0x3f)); return 3; } @@ -240,10 +240,10 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (code <= 0x001FFFFF) { - buf[0] = (unsigned char) (0xf0 | (code >> 18)); - buf[1] = (unsigned char) (0x80 | ((code >> 12) & 0x3f)); - buf[2] = (unsigned char) (0x80 | ((code >> 6) & 0x3f)); - buf[3] = (unsigned char) (0x80 | (code & 0x3f)); + buf[0] = (unsigned char)(0xf0 | (code >> 18)); + buf[1] = (unsigned char)(0x80 | ((code >> 12) & 0x3f)); + buf[2] = (unsigned char)(0x80 | ((code >> 6) & 0x3f)); + buf[3] = (unsigned char)(0x80 | (code & 0x3f)); return 4; } @@ -251,11 +251,11 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (code <= 0x03FFFFFF) { - buf[0] = (unsigned char) (0xf8 | (code >> 24)); - buf[1] = (unsigned char) (0x80 | ((code >> 18) & 0x3f)); - buf[2] = (unsigned char) (0x80 | ((code >> 12) & 0x3f)); - buf[3] = (unsigned char) (0x80 | ((code >> 6) & 0x3f)); - buf[4] = (unsigned char) (0x80 | (code & 0x3f)); + buf[0] = (unsigned char)(0xf8 | (code >> 24)); + buf[1] = (unsigned char)(0x80 | ((code >> 18) & 0x3f)); + buf[2] = (unsigned char)(0x80 | ((code >> 12) & 0x3f)); + buf[3] = (unsigned char)(0x80 | ((code >> 6) & 0x3f)); + buf[4] = (unsigned char)(0x80 | (code & 0x3f)); return 5; } @@ -263,12 +263,12 @@ int toml_ucs_to_utf8(int64_t code, char buf[6]) { 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (code <= 0x7FFFFFFF) { - buf[0] = (unsigned char) (0xfc | (code >> 30)); - buf[1] = (unsigned char) (0x80 | ((code >> 24) & 0x3f)); - buf[2] = (unsigned char) (0x80 | ((code >> 18) & 0x3f)); - buf[3] = (unsigned char) (0x80 | ((code >> 12) & 0x3f)); - buf[4] = (unsigned char) (0x80 | ((code >> 6) & 0x3f)); - buf[5] = (unsigned char) (0x80 | (code & 0x3f)); + buf[0] = (unsigned char)(0xfc | (code >> 30)); + buf[1] = (unsigned char)(0x80 | ((code >> 24) & 0x3f)); + buf[2] = (unsigned char)(0x80 | ((code >> 18) & 0x3f)); + buf[3] = (unsigned char)(0x80 | ((code >> 12) & 0x3f)); + buf[4] = (unsigned char)(0x80 | ((code >> 6) & 0x3f)); + buf[5] = (unsigned char)(0x80 | (code & 0x3f)); return 6; } @@ -2216,6 +2216,7 @@ int toml_rtos(toml_raw_t src, char **ret) { if (!src) return -1; + // for strings, first char must be a s-quote or d-quote int qchar = src[0]; int srclen = strlen(src); if (!(qchar == '\'' || qchar == '"')) { @@ -2224,12 +2225,14 @@ int toml_rtos(toml_raw_t src, char **ret) { // triple quotes? if (qchar == src[1] && qchar == src[2]) { - multiline = 1; - sp = src + 3; - sq = src + srclen - 3; - /* last 3 chars in src must be qchar */ - if (!(sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) + multiline = 1; // triple-quote implies multiline + sp = src + 3; // first char after quote + sq = src + srclen - 3; // first char of ending quote + + if (!(sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) { + // last 3 chars in src must be qchar return -1; + } /* skip new line immediate after qchar */ if (sp[0] == '\n') @@ -2238,13 +2241,18 @@ int toml_rtos(toml_raw_t src, char **ret) { sp += 2; } else { - sp = src + 1; - sq = src + srclen - 1; - /* last char in src must be qchar */ - if (!(sp <= sq && *sq == qchar)) + sp = src + 1; // first char after quote + sq = src + srclen - 1; // ending quote + if (!(sp <= sq && *sq == qchar)) { + /* last char in src must be qchar */ return -1; + } } + // at this point: + // sp points to first valid char after quote. + // sq points to one char beyond last valid char. + // string len is (sq - sp). if (qchar == '\'') { *ret = norm_lit_str(sp, sq - sp, multiline, 0, 0); } else { diff --git a/toml.h b/toml.h index 19dc3d2..c6aabd0 100644 --- a/toml.h +++ b/toml.h @@ -26,7 +26,7 @@ #define TOML_H #ifdef _MSC_VER -#pragma warning(disable: 4996) +#pragma warning(disable : 4996) #endif #include From 5221b3d3d66c25a1dc6f0372b4f824f1202fe398 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Sat, 30 Sep 2023 21:36:59 +0200 Subject: [PATCH 138/138] Fix toml_json.c output (#85) * Fix toml_json.c output There were two issues; partly related to changes in upstream toml-test: - Use appropriate type for local date and times. - The arrays would get printed as: {"type": "array", "value": [...the values...]} But this should just be: [...the values...] It also wouldn't print mixed arrays because 'm' was missing in the switch; I adapted this from toml_cat.c. Before: toml-test [./toml_json]: using embedded tests: 328 passed, 87 failed After: toml-test [./toml_json]: using embedded tests: 351 passed, 64 failed The remaining test failures look like a few minor issues in toml.c, rather than toml_json.c * Also fix the "test1" toml-test runner --- README.md | 6 +++--- test1/build.sh | 9 +++------ test1/run.sh | 6 +++--- test2/build.sh | 3 ++- test2/run.sh | 12 +++++++----- toml_json.c | 52 +++++++++++++++++++++++++++++--------------------- 6 files changed, 48 insertions(+), 40 deletions(-) mode change 100644 => 100755 test1/build.sh mode change 100644 => 100755 test1/run.sh mode change 100644 => 100755 test2/build.sh mode change 100644 => 100755 test2/run.sh diff --git a/README.md b/README.md index 2c90c26..956ef9b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ If you are looking for a C++ library, you might try this wrapper: [https://githu * Compatible with [TOML v1.0.0](https://toml.io/en/v1.0.0). * Tested with multiple test suites, including -[BurntSushi/toml-test](https://github.com/BurntSushi/toml-test) and +[toml-lang/toml-test](https://github.com/toml-lang/toml-test) and [iarna/toml-spec-tests](https://github.com/iarna/toml-spec-tests). * Provides very simple and intuitive interface. @@ -174,7 +174,7 @@ Alternatively, specify `make install prefix=/a/file/path` to install into ## Testing -To test against the standard test set provided by BurntSushi/toml-test: +To test against the standard test set provided by toml-lang/toml-test: ```sh % make @@ -191,4 +191,4 @@ To test against the standard test set provided by iarna/toml: % cd test2 % bash build.sh # do this once % bash run.sh # this will run the test suite -``` +``` \ No newline at end of file diff --git a/test1/build.sh b/test1/build.sh old mode 100644 new mode 100755 index 645a271..496806a --- a/test1/build.sh +++ b/test1/build.sh @@ -1,9 +1,6 @@ +#!/usr/bin/env bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -mkdir -p $DIR/goworkspace -export GOPATH=$DIR/goworkspace -go get github.com/BurntSushi/toml-test@latest # install test suite -go install github.com/BurntSushi/toml/cmd/toml-test-decoder@latest # e.g., install my parser -cp $GOPATH/bin/* . - +export GOBIN=$DIR +go install github.com/toml-lang/toml-test/cmd/toml-test@latest # install test suite \ No newline at end of file diff --git a/test1/run.sh b/test1/run.sh old mode 100644 new mode 100755 index 356a8cb..2e50ba4 --- a/test1/run.sh +++ b/test1/run.sh @@ -1,5 +1,5 @@ +#!/usr/bin/env bash + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -rm -f tests -ln -s ./goworkspace/pkg/mod/github.com/\!burnt\!sushi/toml-test@v0.1.0/tests -./toml-test ../toml_json +$DIR/toml-test $DIR/../toml_json diff --git a/test2/build.sh b/test2/build.sh old mode 100644 new mode 100755 index 74da4d0..1f25f8c --- a/test2/build.sh +++ b/test2/build.sh @@ -1,6 +1,7 @@ +#!/usr/bin/env bash + set -e DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" [ -d toml-spec-tests ] || git clone https://github.com/cktan/toml-spec-tests.git - diff --git a/test2/run.sh b/test2/run.sh old mode 100644 new mode 100755 index e1d93df..f67995a --- a/test2/run.sh +++ b/test2/run.sh @@ -1,4 +1,6 @@ -if ! (which jq >& /dev/null); then +#!/usr/bin/env bash + +if ! (which jq >& /dev/null); then echo "ERROR: please install the 'jq' utility" exit 1 fi @@ -12,11 +14,11 @@ for i in toml-spec-tests/values/*.toml; do fname="${fname%.*}" echo -n $fname ' ' res='[OK]' - if (../toml_json $fname.toml >& $fname.json.out); then + if (../toml_json $fname.toml >& $fname.json.out); then jq -S . $fname.json.out > t.json mv t.json $fname.json.out if [ -f $fname.json ]; then - if ! (diff $fname.json $fname.json.out >& /dev/null); then + if ! (diff $fname.json $fname.json.out >& /dev/null); then res='[FAILED]' else rm -f $fname.json.out @@ -32,10 +34,10 @@ done # # NEGATIVE tests # -for i in toml-spec-tests/errors/*.toml; do +for i in toml-spec-tests/errors/*.toml; do echo -n $i ' ' res='[OK]' - if (../toml_json $i >& $i.json.out); then + if (../toml_json $i >& $i.json.out); then res='[FAILED]' fi echo ... $res diff --git a/toml_json.c b/toml_json.c index a939a23..936252d 100644 --- a/toml_json.c +++ b/toml_json.c @@ -91,15 +91,16 @@ static void print_raw(const char *s) { else millisec[0] = 0; if (ts.year && ts.hour) { - printf("{\"type\":\"datetime\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%" + printf("{\"type\":\"%s\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%" "s%s\"}", + (ts.z ? "datetime" : "datetime-local"), *ts.year, *ts.month, *ts.day, *ts.hour, *ts.minute, *ts.second, millisec, (ts.z ? ts.z : "")); } else if (ts.year) { - printf("{\"type\":\"date\",\"value\":\"%04d-%02d-%02d\"}", *ts.year, + printf("{\"type\":\"date-local\",\"value\":\"%04d-%02d-%02d\"}", *ts.year, *ts.month, *ts.day); } else if (ts.hour) { - printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d%s\"}", *ts.hour, + printf("{\"type\":\"time-local\",\"value\":\"%02d:%02d:%02d%s\"}", *ts.hour, *ts.minute, *ts.second, millisec); } } else { @@ -149,36 +150,43 @@ static void print_table_array(toml_array_t *curarr) { } static void print_array(toml_array_t *curarr) { - toml_array_t *arr; - const char *raw; - int i; - if (toml_array_kind(curarr) == 't') { print_table_array(curarr); return; } - printf("{\"type\":\"array\",\"value\":["); - switch (toml_array_kind(curarr)) { + printf("["); - case 'v': - for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { - printf("%s", i > 0 ? "," : ""); - print_raw(raw); - } - break; + const char *raw; + toml_array_t *arr; + toml_table_t *tab; - case 'a': - for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) { - printf("%s", i > 0 ? "," : ""); + const int n = toml_array_nelem(curarr); + for (int i = 0; i < n; i++) { + printf("%s", i > 0 ? "," : ""); + + if (0 != (arr = toml_array_at(curarr, i))) { print_array(arr); + continue; } - break; - default: - break; + if (0 != (tab = toml_table_at(curarr, i))) { + print_table(tab); + continue; + } + + raw = toml_raw_at(curarr, i); + if (raw) { + print_raw(raw); + continue; + } + + fflush(stdout); + fprintf(stderr, "ERROR: unable to decode value in array\n"); + exit(1); } - printf("]}"); + + printf("]"); } static void cat(FILE *fp) {