Handle more test cases
This commit is contained in:
parent
b701a09579
commit
3bc235331f
3 changed files with 262 additions and 183 deletions
136
toml.c
136
toml.c
|
@ -774,7 +774,10 @@ static void parse_table(context_t* ctx, toml_table_t* tab)
|
||||||
EAT_TOKEN(ctx, LBRACE);
|
EAT_TOKEN(ctx, LBRACE);
|
||||||
|
|
||||||
for (;;) {
|
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 } */
|
/* until } */
|
||||||
if (ctx->tok.tok == RBRACE) break;
|
if (ctx->tok.tok == RBRACE) break;
|
||||||
|
@ -784,7 +787,11 @@ static void parse_table(context_t* ctx, toml_table_t* tab)
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
parse_keyval(ctx, tab);
|
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 */
|
/* on comma, continue to scan for next keyval */
|
||||||
if (ctx->tok.tok == COMMA) {
|
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]] */
|
/* handle lines like [x.y.z] or [[x.y.z]] */
|
||||||
static void parse_select(context_t* ctx)
|
static void parse_select(context_t* ctx)
|
||||||
{
|
{
|
||||||
int count_lbracket = 0;
|
assert(ctx->tok.tok == LBRACKET);
|
||||||
if (ctx->tok.tok != LBRACKET) {
|
|
||||||
e_internal_error(ctx, FLINE);
|
/* true if [[ */
|
||||||
return; /* not reached */
|
int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '[');
|
||||||
}
|
/* need to detect '[[' on our own because next_token() will skip whitespace,
|
||||||
count_lbracket++;
|
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 (ctx->tok.tok == LBRACKET) {
|
if (llb) {
|
||||||
count_lbracket++;
|
assert(ctx->tok.tok == LBRACKET);
|
||||||
next_token(ctx, 1 /* DOT IS SPECIAL */);
|
next_token(ctx, 1 /* DOT IS SPECIAL */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,9 +1142,10 @@ static void parse_select(context_t* ctx)
|
||||||
free(ctx->tpath.key[ctx->tpath.top-1]);
|
free(ctx->tpath.key[ctx->tpath.top-1]);
|
||||||
ctx->tpath.top--;
|
ctx->tpath.top--;
|
||||||
|
|
||||||
|
/* set up ctx->curtab */
|
||||||
walk_tabpath(ctx);
|
walk_tabpath(ctx);
|
||||||
|
|
||||||
if (count_lbracket == 1) {
|
if (! llb) {
|
||||||
/* [x.y.z] -> create z = {} in x.y */
|
/* [x.y.z] -> create z = {} in x.y */
|
||||||
ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z);
|
ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1183,15 +1193,15 @@ static void parse_select(context_t* ctx)
|
||||||
e_syntax_error(ctx, ctx->tok.lineno, "expects ]");
|
e_syntax_error(ctx, ctx->tok.lineno, "expects ]");
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
EAT_TOKEN(ctx, RBRACKET);
|
if (llb) {
|
||||||
|
if (! (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) {
|
||||||
if (count_lbracket == 2) {
|
|
||||||
if (ctx->tok.tok != RBRACKET) {
|
|
||||||
e_syntax_error(ctx, ctx->tok.lineno, "expects ]]");
|
e_syntax_error(ctx, ctx->tok.lineno, "expects ]]");
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
EAT_TOKEN(ctx, RBRACKET);
|
EAT_TOKEN(ctx, RBRACKET);
|
||||||
}
|
}
|
||||||
|
EAT_TOKEN(ctx, RBRACKET);
|
||||||
|
|
||||||
if (ctx->tok.tok != NEWLINE) {
|
if (ctx->tok.tok != NEWLINE) {
|
||||||
e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]");
|
e_syntax_error(ctx, ctx->tok.lineno, "extra chars after ] or ]]");
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
|
@ -1681,7 +1691,7 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret)
|
||||||
|
|
||||||
memset(ret, 0, sizeof(*ret));
|
memset(ret, 0, sizeof(*ret));
|
||||||
|
|
||||||
/* parse date */
|
/* parse date YYYY-MM-DD */
|
||||||
val = 0;
|
val = 0;
|
||||||
if (q - p > 4 && p[4] == '-') {
|
if (q - p > 4 && p[4] == '-') {
|
||||||
for (i = 0; i < 10; i++, p++) {
|
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;
|
if (q == p) return 0;
|
||||||
|
|
||||||
/* parse time */
|
/* parse time HH:MM:SS */
|
||||||
val = 0;
|
val = 0;
|
||||||
if (q - p < 8) return -1;
|
if (q - p < 8) return -1;
|
||||||
for (i = 0; i < 8; i++, p++) {
|
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->minute = val % 100; val /= 100;
|
||||||
*ret->hour = val;
|
*ret->hour = val;
|
||||||
|
|
||||||
/* skip fractional second */
|
/* parse millisec */
|
||||||
if (*p == '.') for (p++; '0' <= *p && *p <= '9'; p++);
|
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;
|
if (q == p) return 0;
|
||||||
|
|
||||||
/* parse and copy Z */
|
/* parse and copy Z */
|
||||||
|
@ -1792,11 +1816,15 @@ int toml_rtoi(const char* src, int64_t* ret_)
|
||||||
int64_t dummy;
|
int64_t dummy;
|
||||||
int64_t* ret = ret_ ? ret_ : &dummy;
|
int64_t* ret = ret_ ? ret_ : &dummy;
|
||||||
|
|
||||||
if (*s == '+')
|
|
||||||
*p++ = *s++;
|
/* allow +/- */
|
||||||
else if (*s == '-')
|
if (s[0] == '+' || s[0] == '-')
|
||||||
*p++ = *s++;
|
*p++ = *s++;
|
||||||
|
|
||||||
|
/* disallow +_100 */
|
||||||
|
if (s[0] == '_')
|
||||||
|
return -1;
|
||||||
|
|
||||||
/* if 0 ... */
|
/* if 0 ... */
|
||||||
if ('0' == s[0]) {
|
if ('0' == s[0]) {
|
||||||
switch (s[1]) {
|
switch (s[1]) {
|
||||||
|
@ -1813,10 +1841,21 @@ int toml_rtoi(const char* src, int64_t* ret_)
|
||||||
/* just strip underscores and pass to strtoll */
|
/* just strip underscores and pass to strtoll */
|
||||||
while (*s && p < q) {
|
while (*s && p < q) {
|
||||||
int ch = *s++;
|
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;
|
if (*s || p == q) return -1;
|
||||||
|
|
||||||
|
/* last char cannot be '_' */
|
||||||
|
if (s[-1] == '_') return -1;
|
||||||
|
|
||||||
/* cap with NUL */
|
/* cap with NUL */
|
||||||
*p = 0;
|
*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;
|
if (!src) return -1;
|
||||||
|
|
||||||
char buf[100];
|
|
||||||
char* p = buf;
|
char* p = buf;
|
||||||
char* q = p + sizeof(buf);
|
char* q = p + buflen;
|
||||||
const char* s = src;
|
const char* s = src;
|
||||||
double dummy;
|
double dummy;
|
||||||
double* ret = ret_ ? ret_ : &dummy;
|
double* ret = ret_ ? ret_ : &dummy;
|
||||||
|
|
||||||
/* check for special cases */
|
|
||||||
if (s[0] == '+' || s[0] == '-') *p++ = *s++;
|
/* allow +/- */
|
||||||
if (s[0] == '.') return -1; /* no leading zero */
|
if (s[0] == '+' || s[0] == '-')
|
||||||
if (s[0] == '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 */
|
/* zero must be followed by . or NUL */
|
||||||
if (s[1] && s[1] != '.') return -1;
|
if (s[0] == '0' && s[1] && s[1] != '.')
|
||||||
}
|
return -1;
|
||||||
|
|
||||||
/* just strip underscores and pass to strtod */
|
/* just strip underscores and pass to strtod */
|
||||||
while (*s && p < q) {
|
while (*s && p < q) {
|
||||||
int ch = *s++;
|
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;
|
||||||
}
|
}
|
||||||
if (*s || p == q) return -1;
|
*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 */
|
return -1; /* no trailing zero */
|
||||||
|
@ -1867,6 +1929,12 @@ int toml_rtod(const char* src, double* ret_)
|
||||||
return (errno || *endp) ? -1 : 0;
|
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)
|
static char* kill_line_ending_backslash(char* str)
|
||||||
{
|
{
|
||||||
|
|
6
toml.h
6
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. */
|
/* Raw to Double. Return 0 on success, -1 otherwise. */
|
||||||
TOML_EXTERN int toml_rtod(const char* s, double* ret);
|
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
|
/* Timestamp types. The year, month, day, hour, minute, second, z
|
||||||
* fields may be NULL if they are not relevant. e.g. In a DATE
|
* 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 toml_timestamp_t {
|
||||||
struct { /* internal. do not use. */
|
struct { /* internal. do not use. */
|
||||||
int year, month, day;
|
int year, month, day;
|
||||||
int hour, minute, second;
|
int hour, minute, second, millisec;
|
||||||
char z[10];
|
char z[10];
|
||||||
} __buffer;
|
} __buffer;
|
||||||
int *year, *month, *day;
|
int *year, *month, *day;
|
||||||
int *hour, *minute, *second;
|
int *hour, *minute, *second, *millisec;
|
||||||
char* z;
|
char* z;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
57
toml_json.c
57
toml_json.c
|
@ -1,26 +1,26 @@
|
||||||
/*
|
/*
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 CK Tan
|
Copyright (c) 2017 CK Tan
|
||||||
https://github.com/cktan/tomlc99
|
https://github.com/cktan/tomlc99
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in all
|
||||||
copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
|
@ -58,6 +58,7 @@ static void print_raw(const char* s)
|
||||||
int bval;
|
int bval;
|
||||||
double dval;
|
double dval;
|
||||||
toml_timestamp_t ts;
|
toml_timestamp_t ts;
|
||||||
|
char dbuf[100];
|
||||||
|
|
||||||
if (0 == toml_rtos(s, &sval)) {
|
if (0 == toml_rtos(s, &sval)) {
|
||||||
printf("{\"type\":\"string\",\"value\":\"");
|
printf("{\"type\":\"string\",\"value\":\"");
|
||||||
|
@ -68,19 +69,25 @@ static void print_raw(const char* s)
|
||||||
printf("{\"type\":\"integer\",\"value\":\"%" PRId64 "\"}", ival);
|
printf("{\"type\":\"integer\",\"value\":\"%" PRId64 "\"}", ival);
|
||||||
} else if (0 == toml_rtob(s, &bval)) {
|
} else if (0 == toml_rtob(s, &bval)) {
|
||||||
printf("{\"type\":\"bool\",\"value\":\"%s\"}", bval ? "true" : "false");
|
printf("{\"type\":\"bool\",\"value\":\"%s\"}", bval ? "true" : "false");
|
||||||
} else if (0 == toml_rtod(s, &dval)) {
|
} else if (0 == toml_rtod_ex(s, &dval, dbuf, sizeof(dbuf))) {
|
||||||
printf("{\"type\":\"float\",\"value\":\"%s\"}", s);
|
printf("{\"type\":\"float\",\"value\":\"%s\"}", dbuf);
|
||||||
} else if (0 == toml_rtots(s, &ts)) {
|
} 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) {
|
if (ts.year && ts.hour) {
|
||||||
printf("{\"type\":\"datetime\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%s\"}",
|
printf("{\"type\":\"datetime\",\"value\":\"%04d-%02d-%02dT%02d:%02d:%02d%s%s\"}",
|
||||||
*ts.year, *ts.month, *ts.day, *ts.hour, *ts.minute, *ts.second,
|
*ts.year, *ts.month, *ts.day, *ts.hour, *ts.minute, *ts.second,
|
||||||
|
millisec,
|
||||||
(ts.z ? ts.z : ""));
|
(ts.z ? ts.z : ""));
|
||||||
} else if (ts.year) {
|
} else if (ts.year) {
|
||||||
printf("{\"type\":\"date\",\"value\":\"%04d-%02d-%02d\"}",
|
printf("{\"type\":\"date\",\"value\":\"%04d-%02d-%02d\"}",
|
||||||
*ts.year, *ts.month, *ts.day);
|
*ts.year, *ts.month, *ts.day);
|
||||||
} else if (ts.hour) {
|
} else if (ts.hour) {
|
||||||
printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d\"}",
|
printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d%s\"}",
|
||||||
*ts.hour, *ts.minute, *ts.second);
|
*ts.hour, *ts.minute, *ts.second, millisec);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "unknown type\n");
|
fprintf(stderr, "unknown type\n");
|
||||||
|
@ -102,7 +109,9 @@ static void print_table(toml_table_t* curtab)
|
||||||
printf("{");
|
printf("{");
|
||||||
for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) {
|
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))) {
|
if (0 != (raw = toml_raw_in(curtab, key))) {
|
||||||
print_raw(raw);
|
print_raw(raw);
|
||||||
|
|
Loading…
Reference in a new issue