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
This commit is contained in:
CK Tan 2017-08-07 14:47:59 -07:00
parent e6a6db8bda
commit a0b45225e2
3 changed files with 213 additions and 98 deletions

View file

@ -5,7 +5,7 @@ CFLAGS = -std=c99 -Wall -Wextra
CFLAGS += -O2 -DNDEBUG CFLAGS += -O2 -DNDEBUG
#CFLAGS += -O0 -g #CFLAGS += -O0 -g
EXEC = toml_json EXEC = toml_json toml_cat
LIB = libtoml.a LIB = libtoml.a
@ -17,6 +17,8 @@ libtoml.a: toml.o
toml_json: toml_json.c $(LIB) toml_json: toml_json.c $(LIB)
toml_cat: toml_cat.c $(LIB)
prefix ?= /usr/local prefix ?= /usr/local
install: all install: all

299
toml.c
View file

@ -311,24 +311,33 @@ struct context_t {
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x) #define TOSTRING(x) STRINGIFY(x)
#define FLINE __FILE__ ":" TOSTRING(__LINE__) #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 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); snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline);
longjmp(ctx->jmp, 1); longjmp(ctx->jmp, 1);
return -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); snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg);
longjmp(ctx->jmp, 1); longjmp(ctx->jmp, 1);
return -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); snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno);
longjmp(ctx->jmp, 1); 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); snprintf(ctx->errbuf, ctx->errbufsz, "not implemented: %s", feature);
longjmp(ctx->jmp, 1); 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]; char buf[100];
int i; int i;
@ -491,7 +500,10 @@ static char* normalize_key(context_t* ctx, token_t strtok)
if (ch == '\'') { if (ch == '\'') {
/* for single quote, take it verbatim. */ /* 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 { } 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 = 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 */ /* newlines are not allowed in keys */
if (strchr(ret, '\n')) { if (strchr(ret, '\n')) {
free(ret); free(ret);
bad_key_error(ctx, lineno); e_bad_key_error(ctx, lineno);
return 0; /* not reached */
} }
return ret; return ret;
} }
@ -515,11 +528,15 @@ static char* normalize_key(context_t* ctx, token_t strtok)
int k = *xp; int k = *xp;
if (isalnum(k)) continue; if (isalnum(k)) continue;
if (k == '_' || 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 */ /* 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; 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; toml_keyval_t* dest = 0;
if (check_key(tab, newkey, 0, 0, 0)) { if (check_key(tab, newkey, 0, 0, 0)) {
free(newkey); free(newkey);
key_exists_error(ctx, keytok); e_key_exists_error(ctx, keytok);
return 0; /* not reached */
} }
/* make a new entry */ /* 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; toml_keyval_t** base;
if (0 == (base = (toml_keyval_t**) realloc(tab->kval, (n+1) * sizeof(*base)))) { if (0 == (base = (toml_keyval_t**) realloc(tab->kval, (n+1) * sizeof(*base)))) {
free(newkey); free(newkey);
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
tab->kval = base; tab->kval = base;
if (0 == (base[n] = (toml_keyval_t*) calloc(1, sizeof(*base[n])))) { if (0 == (base[n] = (toml_keyval_t*) calloc(1, sizeof(*base[n])))) {
free(newkey); free(newkey);
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
dest = tab->kval[tab->nkval++]; 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; dest->implicit = 0;
return dest; return dest;
} }
key_exists_error(ctx, keytok); e_key_exists_error(ctx, keytok);
return 0; /* not reached */
} }
/* create a new table entry */ /* 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; toml_table_t** base;
if (0 == (base = (toml_table_t**) realloc(tab->tab, (n+1) * sizeof(*base)))) { if (0 == (base = (toml_table_t**) realloc(tab->tab, (n+1) * sizeof(*base)))) {
free(newkey); free(newkey);
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
tab->tab = base; tab->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])))) {
free(newkey); free(newkey);
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
dest = tab->tab[tab->ntab++]; 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? */ /* special case skip if exists? */
if (skip_if_exist) return dest; 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 */ /* make a new array entry */
@ -672,13 +696,15 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx,
toml_array_t** base; toml_array_t** base;
if (0 == (base = (toml_array_t**) realloc(tab->arr, (n+1) * sizeof(*base)))) { if (0 == (base = (toml_array_t**) realloc(tab->arr, (n+1) * sizeof(*base)))) {
free(newkey); free(newkey);
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
tab->arr = base; tab->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])))) {
free(newkey); free(newkey);
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
dest = tab->arr[tab->narr++]; dest = tab->arr[tab->narr++];
@ -695,12 +721,14 @@ static toml_array_t* create_array_in_array(context_t* ctx,
int n = parent->nelem; int n = parent->nelem;
toml_array_t** base; 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)))) {
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
parent->u.arr = base; 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])))) {
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
return parent->u.arr[parent->nelem++]; 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; int n = parent->nelem;
toml_table_t** base; 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)))) {
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
parent->u.tab = base; 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])))) {
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return 0; /* not reached */
} }
return parent->u.tab[parent->nelem++]; 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 SKIP_NEWLINES(ctx) while (ctx->tok.tok == NEWLINE) next_token(ctx, 0)
#define EAT_TOKEN(ctx, typ) \ #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); 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 } */ /* until } */
if (ctx->tok.tok == RBRACE) break; if (ctx->tok.tok == RBRACE) break;
switch (ctx->tok.tok) { if (ctx->tok.tok != STRING) {
case STRING: parse_keyval(ctx, tab); break; e_syntax_error(ctx, ctx->tok.lineno, "syntax error");
default: 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 */ /* on comma, continue to scan for next keyval */
@ -762,8 +792,10 @@ static void parse_table(context_t* ctx, toml_table_t* tab)
break; break;
} }
if (ctx->tok.tok != RBRACE) if (ctx->tok.tok != RBRACE) {
syntax_error(ctx, ctx->tok.lineno, "syntax error"); e_syntax_error(ctx, ctx->tok.lineno, "syntax error");
return; /* not reached */
}
EAT_TOKEN(ctx, RBRACE); 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'; if (arr->kind == 0) arr->kind = 'v';
/* check array kind */ /* check array kind */
if (arr->kind != 'v') { if (arr->kind != 'v') {
syntax_error(ctx, ctx->tok.lineno, e_syntax_error(ctx, ctx->tok.lineno,
"a string array can only contain strings"); "a string array can only contain strings");
return; /* not reached */
} }
/* make a new value in array */ /* 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) outofmemory(ctx, FLINE); if (!tmp) {
e_outofmemory(ctx, FLINE);
return; /* not reached */
}
arr->u.val = tmp; 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; arr->u.val[arr->nelem++] = val;
/* set array type if this is the first entry, or check that the types matched. */ /* set array type if this is the first entry, or check that the types matched. */
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)) {
syntax_error(ctx, ctx->tok.lineno, "array type mismatch"); e_syntax_error(ctx, ctx->tok.lineno, "array type mismatch");
return; /* not reached */
}
EAT_TOKEN(ctx, STRING); EAT_TOKEN(ctx, STRING);
break; break;
@ -832,7 +873,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') {
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)); parse_array(ctx, create_array_in_array(ctx, arr));
break; break;
@ -844,14 +886,16 @@ 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') {
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)); parse_table(ctx, create_table_in_array(ctx, arr));
break; break;
} }
default: default:
syntax_error(ctx, ctx->tok.lineno, "syntax error"); e_syntax_error(ctx, ctx->tok.lineno, "syntax error");
return; /* not reached */
} }
SKIP_NEWLINES(ctx); SKIP_NEWLINES(ctx);
@ -864,8 +908,10 @@ static void parse_array(context_t* ctx, toml_array_t* arr)
break; break;
} }
if (ctx->tok.tok != RBRACKET) if (ctx->tok.tok != RBRACKET) {
syntax_error(ctx, ctx->tok.lineno, "syntax error"); e_syntax_error(ctx, ctx->tok.lineno, "syntax error");
return; /* not reached */
}
EAT_TOKEN(ctx, RBRACKET); 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) static void parse_keyval(context_t* ctx, toml_table_t* tab)
{ {
if (ctx->tok.tok != STRING) if (ctx->tok.tok != STRING) {
internal_error(ctx, FLINE); e_internal_error(ctx, FLINE);
return; /* not reached */
}
token_t key = ctx->tok; token_t key = ctx->tok;
EAT_TOKEN(ctx, STRING); EAT_TOKEN(ctx, STRING);
if (ctx->tok.tok != EQUAL) if (ctx->tok.tok != EQUAL) {
syntax_error(ctx, ctx->tok.lineno, "missing ="); e_syntax_error(ctx, ctx->tok.lineno, "missing =");
return; /* not reached */
}
EAT_TOKEN(ctx, EQUAL); EAT_TOKEN(ctx, EQUAL);
@ -897,7 +947,10 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab)
token_t val = ctx->tok; token_t val = ctx->tok;
assert(keyval->val == 0); assert(keyval->val == 0);
keyval->val = strndup(val.ptr, val.len); 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); EAT_TOKEN(ctx, STRING);
@ -919,7 +972,8 @@ static void parse_keyval(context_t* ctx, toml_table_t* tab)
} }
default: 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; ctx->tpath.top = 0;
for (;;) { for (;;) {
if (ctx->tpath.top >= 10) if (ctx->tpath.top >= 10) {
syntax_error(ctx, lineno, "table path is too deep; max allowed is 10."); e_syntax_error(ctx, lineno, "table path is too deep; max allowed is 10.");
return; /* not reached */
}
if (ctx->tok.tok != STRING) if (ctx->tok.tok != STRING) {
syntax_error(ctx, lineno, "invalid or missing key"); e_syntax_error(ctx, lineno, "invalid or missing key");
return; /* not reached */
}
ctx->tpath.tok[ctx->tpath.top] = ctx->tok; 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] = 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 == RBRACKET) break;
if (ctx->tok.tok != DOT) if (ctx->tok.tok != DOT) {
syntax_error(ctx, lineno, "invalid key"); e_syntax_error(ctx, lineno, "invalid key");
return; /* not reached */
}
next_token(ctx, 1); next_token(ctx, 1);
} }
if (ctx->tpath.top <= 0) { 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': case 'a':
/* found an array. nexttab is the last table in the array. */ /* found an array. nexttab is the last table in the array. */
if (nextarr->kind != 't') internal_error(ctx, FLINE); if (nextarr->kind != 't') {
if (nextarr->nelem == 0) internal_error(ctx, FLINE); 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]; nexttab = nextarr->u.tab[nextarr->nelem-1];
break; break;
case 'v': case 'v':
key_exists_error(ctx, ctx->tpath.tok[i]); e_key_exists_error(ctx, ctx->tpath.tok[i]);
break; return; /* not reached */
default: default:
{ /* Not found. Let's create an implicit table. */ { /* Not found. Let's create an implicit table. */
int n = curtab->ntab; 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) outofmemory(ctx, FLINE); if (0 == base) {
e_outofmemory(ctx, FLINE);
return; /* not reached */
}
curtab->tab = base; 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])))) {
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return; /* not reached */
}
if (0 == (base[n]->key = strdup(key))) if (0 == (base[n]->key = strdup(key))) {
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return; /* not reached */
}
nexttab = curtab->tab[curtab->ntab++]; nexttab = curtab->tab[curtab->ntab++];
@ -1038,7 +1112,10 @@ static void walk_tabpath(context_t* ctx)
static void parse_select(context_t* ctx) static void parse_select(context_t* ctx)
{ {
int count_lbracket = 0; 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++; count_lbracket++;
next_token(ctx, 1 /* DOT IS SPECIAL */); next_token(ctx, 1 /* DOT IS SPECIAL */);
if (ctx->tok.tok == LBRACKET) { 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, toml_array_t* arr = create_keyarray_in_table(ctx, ctx->curtab, z,
1 /*skip_if_exist*/); 1 /*skip_if_exist*/);
if (arr->kind == 0) arr->kind = 't'; 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[] */ /* add to z[] */
toml_table_t* dest; toml_table_t* dest;
{ {
int n = arr->nelem; 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) outofmemory(ctx, FLINE); if (0 == base) {
e_outofmemory(ctx, FLINE);
return; /* not reached */
}
arr->u.tab = base; arr->u.tab = base;
if (0 == (base[n] = calloc(1, sizeof(*base[n])))) if (0 == (base[n] = calloc(1, sizeof(*base[n])))) {
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return; /* not reached */
}
if (0 == (base[n]->key = strdup("__anon__"))) if (0 == (base[n]->key = strdup("__anon__"))) {
outofmemory(ctx, FLINE); e_outofmemory(ctx, FLINE);
return; /* not reached */
}
dest = arr->u.tab[arr->nelem++]; dest = arr->u.tab[arr->nelem++];
} }
@ -1086,14 +1173,23 @@ static void parse_select(context_t* ctx)
ctx->curtab = dest; 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); EAT_TOKEN(ctx, RBRACKET);
if (count_lbracket == 2) { 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); 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,7 +1220,8 @@ toml_table_t* toml_parse(char* conf,
// make a root table // make a root table
if (0 == (ctx.root = calloc(1, sizeof(*ctx.root)))) { if (0 == (ctx.root = calloc(1, sizeof(*ctx.root)))) {
outofmemory(&ctx, FLINE); /* do not call outofmemory() here... setjmp not done yet */
snprintf(ctx.errbuf, ctx.errbufsz, "ERROR: out of memory (%s)", FLINE);
return 0; return 0;
} }
@ -1149,8 +1246,10 @@ toml_table_t* toml_parse(char* conf,
case STRING: case STRING:
parse_keyval(&ctx, ctx.curtab); parse_keyval(&ctx, ctx.curtab);
if (ctx.tok.tok != NEWLINE) if (ctx.tok.tok != NEWLINE) {
syntax_error(&ctx, ctx.tok.lineno, "extra chars after value"); e_syntax_error(&ctx, ctx.tok.lineno, "extra chars after value");
return 0; /* not reached */
}
EAT_TOKEN(&ctx, NEWLINE); EAT_TOKEN(&ctx, NEWLINE);
break; break;
@ -1179,9 +1278,16 @@ toml_table_t* toml_parse_file(FILE* fp,
char* buf = 0; char* buf = 0;
int off = 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 */ /* read from fp into buf */
while (! feof(fp)) { while (! feof(fp)) {
bufsz += 100; bufsz += 1000;
/* Allocate 1 extra byte because we will tag on a NUL */ /* Allocate 1 extra byte because we will tag on a NUL */
char* x = realloc(buf, bufsz + 1); 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; char* orig = p;
if (0 == strncmp(p, "'''", 3)) { if (0 == strncmp(p, "'''", 3)) {
p = strstr(p + 3, "'''"); p = strstr(p + 3, "'''");
if (0 == p) if (0 == p) {
syntax_error(ctx, lineno, "unterminated triple-s-quote"); 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);
} }
@ -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 = 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 == '\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) { if (hexreq) {
hexreq--; hexreq--;
if (strchr("0123456789ABCDEF", *p)) continue; 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 == '\\') { escape = 1; continue; }
qcnt = (*p == '"') ? qcnt + 1 : 0; qcnt = (*p == '"') ? qcnt + 1 : 0;
} }
if (qcnt != 3) if (qcnt != 3) {
syntax_error(ctx, lineno, "unterminated triple-quote"); 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) { if ('\'' == *p) {
for (p++; *p && *p != '\n' && *p != '\''; p++); for (p++; *p && *p != '\n' && *p != '\''; p++);
if (*p != '\'') if (*p != '\'') {
syntax_error(ctx, lineno, "unterminated s-quote"); 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);
} }
@ -1351,19 +1465,23 @@ 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; }
syntax_error(ctx, lineno, "bad escape char"); e_syntax_error(ctx, lineno, "bad escape char");
return 0; /* not reached */
} }
if (hexreq) { if (hexreq) {
hexreq--; hexreq--;
if (strchr("0123456789ABCDEF", *p)) continue; 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 == '\\') { escape = 1; continue; }
if (*p == '\n') break; if (*p == '\n') break;
if (*p == '"') break; if (*p == '"') break;
} }
if (*p != '"') if (*p != '"') {
syntax_error(ctx, lineno, "unterminated quote"); 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);
} }
@ -1425,11 +1543,6 @@ static tokentype_t next_token(context_t* ctx, int dotisspecial)
return ret_eof(ctx, lineno); 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) const char* toml_key_in(toml_table_t* tab, int keyidx)
{ {

View file

@ -78,7 +78,7 @@ static void print_table(toml_table_t* curtab)
if (0 != (raw = toml_raw_in(curtab, key))) { if (0 != (raw = toml_raw_in(curtab, key))) {
printf("%s = %s\n", key, raw); printf("%s = %s\n", key, raw);
} else if (0 != (arr = toml_array_in(curtab, key))) { } 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); print_array_of_tables(arr, key);
} }
else { else {
@ -119,7 +119,7 @@ static void print_array(toml_array_t* curarr)
toml_table_t* tab; toml_table_t* tab;
int i; int i;
switch (toml_array_typ(curarr)) { switch (toml_array_kind(curarr)) {
case 'v': case 'v':
for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) { for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) {