v0.5 compliant
This commit is contained in:
parent
63793f92ef
commit
c32a6e92f1
13 changed files with 1592 additions and 1444 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
*~
|
||||||
|
|
||||||
# Object files
|
# Object files
|
||||||
*.o
|
*.o
|
||||||
*.ko
|
*.ko
|
||||||
|
|
12
README.md
12
README.md
|
@ -93,9 +93,17 @@ To test against the standard test set provided by BurntSushi/toml-test:
|
||||||
|
|
||||||
```
|
```
|
||||||
% make
|
% make
|
||||||
% cd test
|
% cd test1
|
||||||
% bash build.sh # do this once
|
% bash build.sh # do this once
|
||||||
% bash run.sh # this will run the test suite
|
% 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
|
||||||
|
```
|
||||||
|
|
0
test/.gitignore → test1/.gitignore
vendored
0
test/.gitignore → test1/.gitignore
vendored
|
@ -2,7 +2,7 @@
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
mkdir -p $DIR/goworkspace
|
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-test # install test suite
|
||||||
go get github.com/BurntSushi/toml/cmd/toml-test-decoder # e.g., install my parser
|
go get github.com/BurntSushi/toml/cmd/toml-test-decoder # e.g., install my parser
|
||||||
cp $GOPATH/bin/* .
|
cp $GOPATH/bin/* .
|
1
test2/.gitignore
vendored
Normal file
1
test2/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/toml-spec-tests
|
6
test2/build.sh
Normal file
6
test2/build.sh
Normal file
|
@ -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
|
||||||
|
|
31
test2/run.sh
Normal file
31
test2/run.sh
Normal file
|
@ -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
|
436
toml.c
436
toml.c
|
@ -58,7 +58,7 @@ void toml_set_memutil(void* (*xxmalloc)(size_t),
|
||||||
#define CALLOC(a,b) ppcalloc(a,b)
|
#define CALLOC(a,b) ppcalloc(a,b)
|
||||||
#define REALLOC(a,b) pprealloc(a,b)
|
#define REALLOC(a,b) pprealloc(a,b)
|
||||||
|
|
||||||
static char* STRDUP(const char* s)
|
char* STRDUP(const char* s)
|
||||||
{
|
{
|
||||||
int len = strlen(s);
|
int len = strlen(s);
|
||||||
char* p = MALLOC(len+1);
|
char* p = MALLOC(len+1);
|
||||||
|
@ -69,7 +69,7 @@ static char* STRDUP(const char* s)
|
||||||
return p;
|
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);
|
size_t len = strnlen(s, n);
|
||||||
char* p = MALLOC(len+1);
|
char* p = MALLOC(len+1);
|
||||||
|
@ -390,29 +390,16 @@ static int e_noimpl(context_t* ctx, const char* feature)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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,
|
snprintf(ctx->errbuf, ctx->errbufsz,
|
||||||
"line %d: key %s exists", keytok.lineno, buf);
|
"line %d: key %s exists", lineno, key);
|
||||||
longjmp(ctx->jmp, 1);
|
longjmp(ctx->jmp, 1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char* norm_lit_str(const char* src, int srclen,
|
||||||
|
int multiline,
|
||||||
/*
|
|
||||||
* 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* errbuf, int errbufsz)
|
||||||
{
|
{
|
||||||
char* dst = 0; /* will write to dst[] and return it */
|
char* dst = 0; /* will write to dst[] and return it */
|
||||||
|
@ -425,7 +412,60 @@ static char* normalize_string(const char* src, int srclen,
|
||||||
/* scan forward on src */
|
/* scan forward on src */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (off >= max - 10) { /* have some slack for misc stuff */
|
if (off >= max - 10) { /* have some slack for misc stuff */
|
||||||
char* x = REALLOC(dst, max += 100);
|
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* 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 */
|
||||||
|
char* x = REALLOC(dst, max += 50);
|
||||||
if (!x) {
|
if (!x) {
|
||||||
xfree(dst);
|
xfree(dst);
|
||||||
snprintf(errbuf, errbufsz, "out of memory");
|
snprintf(errbuf, errbufsz, "out of memory");
|
||||||
|
@ -439,6 +479,17 @@ static char* normalize_string(const char* src, int srclen,
|
||||||
|
|
||||||
ch = *sp++;
|
ch = *sp++;
|
||||||
if (ch != '\\') {
|
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
|
// a plain copy suffice
|
||||||
dst[off++] = ch;
|
dst[off++] = ch;
|
||||||
continue;
|
continue;
|
||||||
|
@ -451,10 +502,11 @@ static char* normalize_string(const char* src, int srclen,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we want to kill line-ending-backslash ... */
|
/* for multi-line, we want to kill line-ending-backslash ... */
|
||||||
if (kill_line_ending_backslash) {
|
if (multiline) {
|
||||||
/* if this is a newline immediately following the backslash ... */
|
|
||||||
if (*sp == '\n' || (*sp == '\r' && sp[1] == '\n')) {
|
// if there is only whitespace after the backslash ...
|
||||||
|
if (sp[strspn(sp, " \t\r")] == '\n') {
|
||||||
/* skip all the following whitespaces */
|
/* skip all the following whitespaces */
|
||||||
sp += strspn(sp, " \t\r\n");
|
sp += strspn(sp, " \t\r\n");
|
||||||
continue;
|
continue;
|
||||||
|
@ -530,8 +582,11 @@ static char* normalize_key(context_t* ctx, token_t strtok)
|
||||||
/* handle quoted string */
|
/* handle quoted string */
|
||||||
if (ch == '\'' || ch == '\"') {
|
if (ch == '\'' || ch == '\"') {
|
||||||
/* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */
|
/* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */
|
||||||
if (sp[1] == ch && sp[2] == ch)
|
int multiline = 0;
|
||||||
|
if (sp[1] == ch && sp[2] == ch) {
|
||||||
sp += 3, sq -= 3;
|
sp += 3, sq -= 3;
|
||||||
|
multiline = 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
sp++, sq--;
|
sp++, sq--;
|
||||||
|
|
||||||
|
@ -543,7 +598,7 @@ static char* normalize_key(context_t* ctx, token_t strtok)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* for double quote, we need to normalize */
|
/* for double quote, we need to normalize */
|
||||||
ret = normalize_string(sp, sq - sp, 0, ebuf, sizeof(ebuf));
|
ret = norm_basic_str(sp, sq - sp, multiline, ebuf, sizeof(ebuf));
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf);
|
snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, ebuf);
|
||||||
longjmp(ctx->jmp, 1);
|
longjmp(ctx->jmp, 1);
|
||||||
|
@ -617,6 +672,12 @@ static int check_key(toml_table_t* tab, const char* key,
|
||||||
return 0;
|
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.
|
/* Create a keyval in the table.
|
||||||
*/
|
*/
|
||||||
static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, token_t keytok)
|
static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab, token_t keytok)
|
||||||
|
@ -628,9 +689,9 @@ static toml_keyval_t* create_keyval_in_table(context_t* ctx, toml_table_t* tab,
|
||||||
|
|
||||||
/* if key exists: error out. */
|
/* if key exists: error out. */
|
||||||
toml_keyval_t* dest = 0;
|
toml_keyval_t* dest = 0;
|
||||||
if (check_key(tab, newkey, 0, 0, 0)) {
|
if (key_kind(tab, newkey)) {
|
||||||
xfree(newkey);
|
xfree(newkey);
|
||||||
e_key_exists_error(ctx, keytok);
|
e_key_exists_error(ctx, keytok.lineno, newkey);
|
||||||
return 0; /* not reached */
|
return 0; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,7 +738,7 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab,
|
||||||
dest->implicit = 0;
|
dest->implicit = 0;
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
e_key_exists_error(ctx, keytok);
|
e_key_exists_error(ctx, keytok.lineno, newkey);
|
||||||
return 0; /* not reached */
|
return 0; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,7 +770,7 @@ static toml_table_t* create_keytable_in_table(context_t* ctx, toml_table_t* tab,
|
||||||
static toml_array_t* create_keyarray_in_table(context_t* ctx,
|
static toml_array_t* create_keyarray_in_table(context_t* ctx,
|
||||||
toml_table_t* tab,
|
toml_table_t* tab,
|
||||||
token_t keytok,
|
token_t keytok,
|
||||||
int skip_if_exist)
|
char kind)
|
||||||
{
|
{
|
||||||
/* first, normalize the key to be used for lookup.
|
/* first, normalize the key to be used for lookup.
|
||||||
* remember to free it if we error out.
|
* remember to free it if we error out.
|
||||||
|
@ -717,14 +778,9 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx,
|
||||||
char* newkey = normalize_key(ctx, keytok);
|
char* newkey = normalize_key(ctx, keytok);
|
||||||
|
|
||||||
/* if key exists: error out */
|
/* if key exists: error out */
|
||||||
toml_array_t* dest = 0;
|
if (key_kind(tab, newkey)) {
|
||||||
if (check_key(tab, newkey, 0, &dest, 0)) {
|
|
||||||
xfree(newkey); /* don't need this anymore */
|
xfree(newkey); /* don't need this anymore */
|
||||||
|
e_key_exists_error(ctx, keytok.lineno, newkey);
|
||||||
/* special case skip if exists? */
|
|
||||||
if (skip_if_exist) return dest;
|
|
||||||
|
|
||||||
e_key_exists_error(ctx, keytok);
|
|
||||||
return 0; /* not reached */
|
return 0; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,10 +799,11 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx,
|
||||||
e_outofmemory(ctx, FLINE);
|
e_outofmemory(ctx, FLINE);
|
||||||
return 0; /* not reached */
|
return 0; /* not reached */
|
||||||
}
|
}
|
||||||
dest = tab->arr[tab->narr++];
|
toml_array_t* dest = tab->arr[tab->narr++];
|
||||||
|
|
||||||
/* save the key in the new array struct */
|
/* save the key in the new array struct */
|
||||||
dest->key = newkey;
|
dest->key = newkey;
|
||||||
|
dest->kind = kind;
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,9 +850,9 @@ 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 SKIP_NEWLINES(ctx, isdotspecial) while (ctx->tok.tok == NEWLINE) next_token(ctx, isdotspecial)
|
||||||
#define EAT_TOKEN(ctx, typ) \
|
#define EAT_TOKEN(ctx, typ, isdotspecial) \
|
||||||
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, isdotspecial)
|
||||||
|
|
||||||
|
|
||||||
static void parse_keyval(context_t* ctx, toml_table_t* tab);
|
static void parse_keyval(context_t* ctx, toml_table_t* tab);
|
||||||
|
@ -806,7 +863,7 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab);
|
||||||
*/
|
*/
|
||||||
static void parse_table(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) {
|
if (ctx->tok.tok == NEWLINE) {
|
||||||
|
@ -830,7 +887,7 @@ static void parse_table(context_t* ctx, toml_table_t* tab)
|
||||||
|
|
||||||
/* 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) {
|
||||||
EAT_TOKEN(ctx, COMMA);
|
EAT_TOKEN(ctx, COMMA, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -841,7 +898,7 @@ static void parse_table(context_t* ctx, toml_table_t* tab)
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
EAT_TOKEN(ctx, RBRACE);
|
EAT_TOKEN(ctx, RBRACE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int valtype(const char* val)
|
static int valtype(const char* val)
|
||||||
|
@ -863,10 +920,10 @@ static int valtype(const char* val)
|
||||||
/* We are at '[...]' */
|
/* We are at '[...]' */
|
||||||
static void parse_array(context_t* ctx, toml_array_t* arr)
|
static void parse_array(context_t* ctx, toml_array_t* arr)
|
||||||
{
|
{
|
||||||
EAT_TOKEN(ctx, LBRACKET);
|
EAT_TOKEN(ctx, LBRACKET, 0);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
SKIP_NEWLINES(ctx);
|
SKIP_NEWLINES(ctx, 0);
|
||||||
|
|
||||||
/* until ] */
|
/* until ] */
|
||||||
if (ctx->tok.tok == RBRACKET) break;
|
if (ctx->tok.tok == RBRACKET) break;
|
||||||
|
@ -903,11 +960,12 @@ static void parse_array(context_t* ctx, toml_array_t* arr)
|
||||||
if (arr->nelem == 1)
|
if (arr->nelem == 1)
|
||||||
arr->type = valtype(arr->u.val[0]);
|
arr->type = valtype(arr->u.val[0]);
|
||||||
else if (arr->type != valtype(val)) {
|
else if (arr->type != valtype(val)) {
|
||||||
e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch");
|
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);
|
EAT_TOKEN(ctx, STRING, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -917,7 +975,8 @@ static void parse_array(context_t* ctx, toml_array_t* arr)
|
||||||
if (arr->kind == 0) arr->kind = 'a';
|
if (arr->kind == 0) arr->kind = 'a';
|
||||||
/* check array kind */
|
/* check array kind */
|
||||||
if (arr->kind != 'a') {
|
if (arr->kind != 'a') {
|
||||||
e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch");
|
e_syntax_error(ctx, ctx->tok.lineno,
|
||||||
|
"array type mismatch while processing array of arrays");
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
parse_array(ctx, create_array_in_array(ctx, arr));
|
parse_array(ctx, create_array_in_array(ctx, arr));
|
||||||
|
@ -930,7 +989,8 @@ static void parse_array(context_t* ctx, toml_array_t* arr)
|
||||||
if (arr->kind == 0) arr->kind = 't';
|
if (arr->kind == 0) arr->kind = 't';
|
||||||
/* check array kind */
|
/* check array kind */
|
||||||
if (arr->kind != 't') {
|
if (arr->kind != 't') {
|
||||||
e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch");
|
e_syntax_error(ctx, ctx->tok.lineno,
|
||||||
|
"array type mismatch while processing array of tables");
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
parse_table(ctx, create_table_in_array(ctx, arr));
|
parse_table(ctx, create_table_in_array(ctx, arr));
|
||||||
|
@ -942,11 +1002,11 @@ static void parse_array(context_t* ctx, toml_array_t* arr)
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
SKIP_NEWLINES(ctx);
|
SKIP_NEWLINES(ctx, 0);
|
||||||
|
|
||||||
/* on comma, continue to scan for next element */
|
/* on comma, continue to scan for next element */
|
||||||
if (ctx->tok.tok == COMMA) {
|
if (ctx->tok.tok == COMMA) {
|
||||||
EAT_TOKEN(ctx, COMMA);
|
EAT_TOKEN(ctx, COMMA, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -957,11 +1017,10 @@ static void parse_array(context_t* ctx, toml_array_t* arr)
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
EAT_TOKEN(ctx, RBRACKET);
|
EAT_TOKEN(ctx, RBRACKET, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* handle lines like these:
|
/* handle lines like these:
|
||||||
key = "value"
|
key = "value"
|
||||||
key = [ array ]
|
key = [ array ]
|
||||||
|
@ -969,20 +1028,35 @@ static void parse_array(context_t* ctx, toml_array_t* arr)
|
||||||
*/
|
*/
|
||||||
static void parse_keyval(context_t* ctx, toml_table_t* tab)
|
static void parse_keyval(context_t* ctx, toml_table_t* tab)
|
||||||
{
|
{
|
||||||
if (ctx->tok.tok != STRING) {
|
token_t key = ctx->tok;
|
||||||
e_internal_error(ctx, FLINE);
|
EAT_TOKEN(ctx, STRING, 1);
|
||||||
return; /* not reached */
|
|
||||||
|
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;
|
|
||||||
|
|
||||||
EAT_TOKEN(ctx, STRING);
|
|
||||||
if (ctx->tok.tok != EQUAL) {
|
if (ctx->tok.tok != EQUAL) {
|
||||||
e_syntax_error(ctx, ctx->tok.lineno, "missing =");
|
e_syntax_error(ctx, ctx->tok.lineno, "missing =");
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
EAT_TOKEN(ctx, EQUAL);
|
next_token(ctx, 0);
|
||||||
|
|
||||||
switch (ctx->tok.tok) {
|
switch (ctx->tok.tok) {
|
||||||
case STRING:
|
case STRING:
|
||||||
|
@ -996,7 +1070,7 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab)
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
EAT_TOKEN(ctx, STRING);
|
next_token(ctx, 1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1112,7 +1186,7 @@ static void walk_tabpath(context_t* ctx)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
e_key_exists_error(ctx, ctx->tpath.tok[i]);
|
e_key_exists_error(ctx, ctx->tpath.tok[i].lineno, key);
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1163,10 +1237,10 @@ static void parse_select(context_t* ctx)
|
||||||
and '[ [' would be taken as '[[', which is wrong. */
|
and '[ [' would be taken as '[[', which is wrong. */
|
||||||
|
|
||||||
/* eat [ or [[ */
|
/* eat [ or [[ */
|
||||||
next_token(ctx, 1 /* DOT IS SPECIAL */);
|
EAT_TOKEN(ctx, LBRACKET, 1);
|
||||||
if (llb) {
|
if (llb) {
|
||||||
assert(ctx->tok.tok == LBRACKET);
|
assert(ctx->tok.tok == LBRACKET);
|
||||||
next_token(ctx, 1 /* DOT IS SPECIAL */);
|
EAT_TOKEN(ctx, LBRACKET, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fill_tabpath(ctx);
|
fill_tabpath(ctx);
|
||||||
|
@ -1185,13 +1259,19 @@ static void parse_select(context_t* ctx)
|
||||||
ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z);
|
ctx->curtab = create_keytable_in_table(ctx, ctx->curtab, z);
|
||||||
} else {
|
} else {
|
||||||
/* [[x.y.z]] -> create z = [] in x.y */
|
/* [[x.y.z]] -> create z = [] in x.y */
|
||||||
toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z,
|
toml_array_t* arr = 0;
|
||||||
1 /*skip_if_exist*/);
|
{
|
||||||
|
char* zstr = normalize_key(ctx, z);
|
||||||
|
arr = toml_array_in(ctx->curtab, zstr);
|
||||||
|
xfree(zstr);
|
||||||
|
}
|
||||||
if (!arr) {
|
if (!arr) {
|
||||||
e_syntax_error(ctx, z.lineno, "key exists");
|
arr = create_keyarray_in_table(ctx, ctx->curtab, z, 't');
|
||||||
|
if (!arr) {
|
||||||
|
e_internal_error(ctx, FLINE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (arr->kind == 0) arr->kind = 't';
|
}
|
||||||
if (arr->kind != 't') {
|
if (arr->kind != 't') {
|
||||||
e_syntax_error(ctx, z.lineno, "array mismatch");
|
e_syntax_error(ctx, z.lineno, "array mismatch");
|
||||||
return; /* not reached */
|
return; /* not reached */
|
||||||
|
@ -1233,9 +1313,9 @@ 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);
|
EAT_TOKEN(ctx, RBRACKET, 1);
|
||||||
}
|
}
|
||||||
EAT_TOKEN(ctx, RBRACKET);
|
EAT_TOKEN(ctx, RBRACKET, 1);
|
||||||
|
|
||||||
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 ]]");
|
||||||
|
@ -1302,7 +1382,7 @@ toml_table_t* toml_parse(char* conf,
|
||||||
return 0; /* not reached */
|
return 0; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
EAT_TOKEN(&ctx, NEWLINE);
|
EAT_TOKEN(&ctx, NEWLINE, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */
|
case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */
|
||||||
|
@ -1453,6 +1533,41 @@ static tokentype_t ret_eof(context_t* ctx, int lineno)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspecial)
|
||||||
{
|
{
|
||||||
char* orig = p;
|
char* orig = p;
|
||||||
|
@ -1476,7 +1591,7 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe
|
||||||
if (strchr("btnfr\"\\", *p)) continue;
|
if (strchr("btnfr\"\\", *p)) continue;
|
||||||
if (*p == 'u') { hexreq = 4; continue; }
|
if (*p == 'u') { hexreq = 4; continue; }
|
||||||
if (*p == 'U') { hexreq = 8; continue; }
|
if (*p == 'U') { hexreq = 8; continue; }
|
||||||
if (*p == '\n') continue; /* allow for line ending backslash */
|
if (p[strspn(p, " \t\r")] == '\n') continue; /* allow for line ending backslash */
|
||||||
e_syntax_error(ctx, lineno, "bad escape char");
|
e_syntax_error(ctx, lineno, "bad escape char");
|
||||||
return 0; /* not reached */
|
return 0; /* not reached */
|
||||||
}
|
}
|
||||||
|
@ -1537,13 +1652,23 @@ static tokentype_t scan_string(context_t* ctx, char* p, int lineno, int dotisspe
|
||||||
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)) {
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* literals */
|
||||||
for ( ; *p && *p != '\n'; p++) {
|
for ( ; *p && *p != '\n'; p++) {
|
||||||
int ch = *p;
|
int ch = *p;
|
||||||
if (ch == '.' && dotisspecial) break;
|
if (ch == '.' && dotisspecial) break;
|
||||||
if ('A' <= ch && ch <= 'Z') continue;
|
if ('A' <= ch && ch <= 'Z') continue;
|
||||||
if ('a' <= ch && ch <= 'z') continue;
|
if ('a' <= ch && ch <= 'z') continue;
|
||||||
if ('0' <= ch && ch <= '9') continue;
|
if (strchr("0123456789+-_.", ch)) continue;
|
||||||
if (strchr("+-_.:", ch)) continue;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1720,85 +1845,66 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret)
|
||||||
if (! src_) return -1;
|
if (! src_) return -1;
|
||||||
|
|
||||||
const char* p = src_;
|
const char* p = src_;
|
||||||
const char* q = src_ + strlen(src_);
|
int must_parse_time = 0;
|
||||||
int64_t val;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
memset(ret, 0, sizeof(*ret));
|
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 */
|
/* parse date YYYY-MM-DD */
|
||||||
val = 0;
|
if (0 == scan_date(p, year, month, day)) {
|
||||||
if (q - p > 4 && p[4] == '-') {
|
ret->year = year;
|
||||||
for (i = 0; i < 10; i++, p++) {
|
ret->month = month;
|
||||||
int xx = *p;
|
ret->day = day;
|
||||||
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;
|
|
||||||
|
|
||||||
|
p += 10;
|
||||||
if (*p) {
|
if (*p) {
|
||||||
// parse the T or space separator
|
// parse the T or space separator
|
||||||
if (*p != 'T' && *p != ' ') return -1;
|
if (*p != 'T' && *p != ' ') return -1;
|
||||||
|
must_parse_time = 1;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (q == p) return 0;
|
|
||||||
|
|
||||||
/* parse time HH:MM:SS */
|
/* parse time HH:MM:SS */
|
||||||
val = 0;
|
if (0 == scan_time(p, hour, minute, second)) {
|
||||||
if (q - p < 8) return -1;
|
ret->hour = hour;
|
||||||
for (i = 0; i < 8; i++, p++) {
|
ret->minute = minute;
|
||||||
int xx = *p;
|
ret->second = second;
|
||||||
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;
|
/* optionally, parse millisec */
|
||||||
*ret->minute = val % 100; val /= 100;
|
p += 8;
|
||||||
*ret->hour = val;
|
|
||||||
|
|
||||||
/* parse millisec */
|
|
||||||
if (*p == '.') {
|
if (*p == '.') {
|
||||||
val = 0;
|
char* qq;
|
||||||
p++;
|
p++;
|
||||||
if ('0' <= *p && *p <= '9') {
|
errno = 0;
|
||||||
val = (*p++ - '0') * 100;
|
*millisec = strtol(p, &qq, 0);
|
||||||
if ('0' <= *p && *p <= '9') {
|
if (errno) {
|
||||||
val += (*p++ - '0') * 10;
|
return -1;
|
||||||
if ('0' <= *p && *p <= '9') {
|
|
||||||
val += (*p++ - '0');
|
|
||||||
}
|
}
|
||||||
|
while (*millisec > 999) {
|
||||||
|
*millisec /= 10;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ret->millisec = &ret->__buffer.millisec;
|
|
||||||
*ret->millisec = val;
|
|
||||||
}
|
|
||||||
if (q == p) return 0;
|
|
||||||
|
|
||||||
/* parse and copy Z */
|
ret->millisec = millisec;
|
||||||
ret->z = ret->__buffer.z;
|
p = qq;
|
||||||
char* z = ret->z;
|
|
||||||
if (*p == 'Z') {
|
|
||||||
*z++ = *p++;
|
|
||||||
*z = 0;
|
|
||||||
return (p == q) ? 0 : -1;
|
|
||||||
}
|
}
|
||||||
if (*p == '+' || *p == '-') {
|
|
||||||
|
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++;
|
*z++ = *p++;
|
||||||
|
|
||||||
if (! (isdigit(p[0]) && isdigit(p[1]))) return -1;
|
if (! (isdigit(p[0]) && isdigit(p[1]))) return -1;
|
||||||
|
@ -1815,7 +1921,15 @@ int toml_rtots(const char* src_, toml_timestamp_t* ret)
|
||||||
|
|
||||||
*z = 0;
|
*z = 0;
|
||||||
}
|
}
|
||||||
return (p == q) ? 0 : -1;
|
}
|
||||||
|
}
|
||||||
|
if (*p != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (must_parse_time && !ret->hour)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1925,8 +2039,8 @@ int toml_rtod_ex(const char* src, double* ret_, char* buf, int buflen)
|
||||||
if (s[0] == '.')
|
if (s[0] == '.')
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* zero must be followed by . or NUL */
|
/* zero must be followed by . or 'e', or NUL */
|
||||||
if (s[0] == '0' && s[1] && s[1] != '.')
|
if (s[0] == '0' && s[1] && !strchr("eE.", s[1]))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* just strip underscores and pass to strtod */
|
/* just strip underscores and pass to strtod */
|
||||||
|
@ -1971,31 +2085,15 @@ 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)
|
int toml_rtos(const char* src, char** ret)
|
||||||
{
|
{
|
||||||
|
char dummy_errbuf[1];
|
||||||
|
int multiline = 0;
|
||||||
|
const char* sp;
|
||||||
|
const char* sq;
|
||||||
|
|
||||||
if (!src) return -1;
|
if (!src) return -1;
|
||||||
if (*src != '\'' && *src != '"') return -1;
|
if (*src != '\'' && *src != '"') return -1;
|
||||||
|
|
||||||
|
@ -2003,8 +2101,9 @@ int toml_rtos(const char* src, char** ret)
|
||||||
int srclen = strlen(src);
|
int srclen = strlen(src);
|
||||||
if (*src == '\'') {
|
if (*src == '\'') {
|
||||||
if (0 == strncmp(src, "'''", 3)) {
|
if (0 == strncmp(src, "'''", 3)) {
|
||||||
const char* sp = src + 3;
|
multiline = 1;
|
||||||
const char* sq = src + srclen - 3;
|
sp = src + 3;
|
||||||
|
sq = src + srclen - 3;
|
||||||
/* last 3 chars in src must be ''' */
|
/* last 3 chars in src must be ''' */
|
||||||
if (! (sp <= sq && 0 == strcmp(sq, "'''")))
|
if (! (sp <= sq && 0 == strcmp(sq, "'''")))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2015,22 +2114,24 @@ int toml_rtos(const char* src, char** ret)
|
||||||
else if (sp[0] == '\r' && sp[1] == '\n')
|
else if (sp[0] == '\r' && sp[1] == '\n')
|
||||||
sp += 2;
|
sp += 2;
|
||||||
|
|
||||||
*ret = kill_line_ending_backslash(STRNDUP(sp, sq - sp));
|
|
||||||
} else {
|
} else {
|
||||||
const char* sp = src + 1;
|
sp = src + 1;
|
||||||
const char* sq = src + srclen - 1;
|
sq = src + srclen - 1;
|
||||||
/* last char in src must be ' */
|
/* last char in src must be ' */
|
||||||
if (! (sp <= sq && *sq == '\''))
|
if (! (sp <= sq && *sq == '\''))
|
||||||
return -1;
|
return -1;
|
||||||
/* copy from sp to p */
|
/* copy from sp to p */
|
||||||
*ret = STRNDUP(sp, sq - sp);
|
*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;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* sp;
|
|
||||||
const char* sq;
|
|
||||||
if (0 == strncmp(src, "\"\"\"", 3)) {
|
if (0 == strncmp(src, "\"\"\"", 3)) {
|
||||||
|
multiline = 1;
|
||||||
sp = src + 3;
|
sp = src + 3;
|
||||||
sq = src + srclen - 3;
|
sq = src + srclen - 3;
|
||||||
if (! (sp <= sq && 0 == strcmp(sq, "\"\"\"")))
|
if (! (sp <= sq && 0 == strcmp(sq, "\"\"\"")))
|
||||||
|
@ -2048,9 +2149,8 @@ int toml_rtos(const char* src, char** ret)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char dummy_errbuf[1];
|
*ret = norm_basic_str(sp, sq - sp,
|
||||||
*ret = normalize_string(sp, sq - sp,
|
multiline,
|
||||||
1, // flag kill_line_ending_backslash
|
|
||||||
dummy_errbuf, sizeof(dummy_errbuf));
|
dummy_errbuf, sizeof(dummy_errbuf));
|
||||||
return *ret ? 0 : -1;
|
return *ret ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue