Handle more test cases
This commit is contained in:
parent
b701a09579
commit
3bc235331f
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);
|
||||
|
||||
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 */);
|
||||
}
|
||||
|
||||
|
@ -1133,9 +1142,10 @@ static void parse_select(context_t* ctx)
|
|||
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);
|
||||
}
|
||||
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,11 +1816,15 @@ 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 == '-')
|
||||
|
||||
/* allow +/- */
|
||||
if (s[0] == '+' || s[0] == '-')
|
||||
*p++ = *s++;
|
||||
|
||||
/* disallow +_100 */
|
||||
if (s[0] == '_')
|
||||
return -1;
|
||||
|
||||
/* if 0 ... */
|
||||
if ('0' == s[0]) {
|
||||
switch (s[1]) {
|
||||
|
@ -1813,10 +1841,21 @@ 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') {
|
||||
|
||||
/* 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[1] && s[1] != '.') return -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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] == '.')
|
||||
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)
|
||||
{
|
||||
|
|
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. */
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
57
toml_json.c
57
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
|
||||
|
@ -58,6 +58,7 @@ static void print_raw(const char* s)
|
|||
int bval;
|
||||
double dval;
|
||||
toml_timestamp_t ts;
|
||||
char dbuf[100];
|
||||
|
||||
if (0 == toml_rtos(s, &sval)) {
|
||||
printf("{\"type\":\"string\",\"value\":\"");
|
||||
|
@ -68,19 +69,25 @@ static void print_raw(const char* s)
|
|||
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_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\"}",
|
||||
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\"}",
|
||||
*ts.hour, *ts.minute, *ts.second);
|
||||
printf("{\"type\":\"time\",\"value\":\"%02d:%02d:%02d%s\"}",
|
||||
*ts.hour, *ts.minute, *ts.second, millisec);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "unknown type\n");
|
||||
|
@ -102,7 +109,9 @@ static void print_table(toml_table_t* curtab)
|
|||
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);
|
||||
|
|
Loading…
Reference in New Issue