fixed issue #51

This commit is contained in:
CK Tan 2021-03-06 23:54:24 -08:00
parent 1cfa8e42c4
commit 715fa54d45
55 changed files with 747 additions and 366 deletions

1
stdex/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/*.out

15
stdex/RUN.sh Normal file
View file

@ -0,0 +1,15 @@
rm -f *.out
for i in *.toml; do
echo -n $i
../toml_cat $i >& $i.out
if [ -f $i.res ]; then
if $(diff $i.out $i.res >& /dev/null); then
echo " [OK]"
else
echo " [FAILED]"
fi
else
echo " [??]"
fi
done

3
stdex/comment.toml Normal file
View file

@ -0,0 +1,3 @@
# This is a full-line comment
key = "value" # This is a comment at the end of a line
another = "# This is not a comment"

4
stdex/comment.toml.res Normal file
View file

@ -0,0 +1,4 @@
{
key = "value",
another = "# This is not a comment",
}

4
stdex/keys00.toml Normal file
View file

@ -0,0 +1,4 @@
key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value"

6
stdex/keys00.toml.res Normal file
View file

@ -0,0 +1,6 @@
{
key = "value",
bare_key = "value",
bare-key = "value",
1234 = "value",
}

5
stdex/keys01.toml Normal file
View file

@ -0,0 +1,5 @@
"127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value"

7
stdex/keys01.toml.res Normal file
View file

@ -0,0 +1,7 @@
{
127.0.0.1 = "value",
character encoding = "value",
ʎǝʞ = "value",
key2 = "value",
quoted "value" = "value",
}

1
stdex/keys02.toml Normal file
View file

@ -0,0 +1 @@
= "no key name" # INVALID

1
stdex/keys02.toml.res Normal file
View file

@ -0,0 +1 @@
ERROR: line 1: syntax error

1
stdex/keys03.toml Normal file
View file

@ -0,0 +1 @@
"" = "blank" # VALID but discouraged

3
stdex/keys03.toml.res Normal file
View file

@ -0,0 +1,3 @@
{
= "blank",
}

4
stdex/keys04.toml Normal file
View file

@ -0,0 +1,4 @@
name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true

10
stdex/keys04.toml.res Normal file
View file

@ -0,0 +1,10 @@
{
name = "Orange",
physical = {
color = "orange",
shape = "round",
},
site = {
google.com = true,
},
}

3
stdex/keys05.toml Normal file
View file

@ -0,0 +1,3 @@
fruit.name = "banana" # this is best practice
fruit. color = "yellow" # same as fruit.color
fruit . flavor = "banana" # same as fruit.flavor

7
stdex/keys05.toml.res Normal file
View file

@ -0,0 +1,7 @@
{
fruit = {
name = "banana",
color = "yellow",
flavor = "banana",
},
}

3
stdex/keys06.toml Normal file
View file

@ -0,0 +1,3 @@
# DO NOT DO THIS
name = "Tom"
name = "Pradyun"

1
stdex/keys06.toml.res Normal file
View file

@ -0,0 +1 @@
ERROR: line 3: key exists

3
stdex/keys07.toml Normal file
View file

@ -0,0 +1,3 @@
# THIS WILL NOT WORK
spelling = "favorite"
"spelling" = "favourite"

1
stdex/keys07.toml.res Normal file
View file

@ -0,0 +1 @@
ERROR: line 3: key exists

5
stdex/keys08.toml Normal file
View file

@ -0,0 +1,5 @@
# This makes the key "fruit" into a table.
fruit.apple.smooth = true
# So then you can add to the table "fruit" like so:
fruit.orange = 2

8
stdex/keys08.toml.res Normal file
View file

@ -0,0 +1,8 @@
{
fruit = {
orange = 2,
apple = {
smooth = true,
},
},
}

8
stdex/keys09.toml Normal file
View file

@ -0,0 +1,8 @@
# THE FOLLOWING IS INVALID
# This defines the value of fruit.apple to be an integer.
fruit.apple = 1
# But then this treats fruit.apple like it's a table.
# You can't turn an integer into a table.
fruit.apple.smooth = true

1
stdex/keys09.toml.res Normal file
View file

@ -0,0 +1 @@
ERROR: line 8: key exists

10
stdex/keys10.toml Normal file
View file

@ -0,0 +1,10 @@
# VALID BUT DISCOURAGED
apple.type = "fruit"
orange.type = "fruit"
apple.skin = "thin"
orange.skin = "thick"
apple.color = "red"
orange.color = "orange"

12
stdex/keys10.toml.res Normal file
View file

@ -0,0 +1,12 @@
{
apple = {
type = "fruit",
skin = "thin",
color = "red",
},
orange = {
type = "fruit",
skin = "thick",
color = "orange",
},
}

9
stdex/keys11.toml Normal file
View file

@ -0,0 +1,9 @@
# RECOMMENDED
apple.type = "fruit"
apple.skin = "thin"
apple.color = "red"
orange.type = "fruit"
orange.skin = "thick"
orange.color = "orange"

12
stdex/keys11.toml.res Normal file
View file

@ -0,0 +1,12 @@
{
apple = {
type = "fruit",
skin = "thin",
color = "red",
},
orange = {
type = "fruit",
skin = "thick",
color = "orange",
},
}

1
stdex/keys12.toml Normal file
View file

@ -0,0 +1 @@
3.14159 = "pi"

5
stdex/keys12.toml.res Normal file
View file

@ -0,0 +1,5 @@
{
3 = {
14159 = "pi",
},
}

1
stdex/kvpair0.toml Normal file
View file

@ -0,0 +1 @@
key = "value"

3
stdex/kvpair0.toml.res Normal file
View file

@ -0,0 +1,3 @@
{
key = "value",
}

1
stdex/kvpair1.toml Normal file
View file

@ -0,0 +1 @@
key = # INVALID

1
stdex/kvpair1.toml.res Normal file
View file

@ -0,0 +1 @@
ERROR: line 1: syntax error

1
stdex/kvpair2.toml Normal file
View file

@ -0,0 +1 @@
first = "Tom" last = "Preston-Werner" # INVALID

1
stdex/kvpair2.toml.res Normal file
View file

@ -0,0 +1 @@
ERROR: line 1: extra chars after value

1
stdex/string0.toml Normal file
View file

@ -0,0 +1 @@
str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."

3
stdex/string0.toml.res Normal file
View file

@ -0,0 +1,3 @@
{
str = "I'm a string. \"You can quote me\". Name\tJos\0xc3\0xa9\nLocation\tSF.",
}

9
stdex/string1.toml Normal file
View file

@ -0,0 +1,9 @@
str1 = """
Roses are red
Violets are blue"""
# On a Unix system, the above multi-line string will most likely be the same as:
str2 = "Roses are red\nViolets are blue"
# On a Windows system, it will most likely be equivalent to:
str3 = "Roses are red\r\nViolets are blue"

5
stdex/string1.toml.res Normal file
View file

@ -0,0 +1,5 @@
{
str1 = "Roses are red\nViolets are blue",
str2 = "Roses are red\nViolets are blue",
str3 = "Roses are red\r\nViolets are blue",
}

15
stdex/string3.toml Normal file
View file

@ -0,0 +1,15 @@
# The following strings are byte-for-byte equivalent:
str1 = "The quick brown fox jumps over the lazy dog."
str2 = """
The quick brown \
fox jumps over \
the lazy dog."""
str3 = """\
The quick brown \
fox jumps over \
the lazy dog.\
"""

5
stdex/string3.toml.res Normal file
View file

@ -0,0 +1,5 @@
{
str1 = "The quick brown fox jumps over the lazy dog.",
str2 = "The quick brown fox jumps over the lazy dog.",
str3 = "The quick brown fox jumps over the lazy dog.",
}

7
stdex/string4.toml Normal file
View file

@ -0,0 +1,7 @@
str4 = """Here are two quotation marks: "". Simple enough."""
# str5 = """Here are three quotation marks: """.""" # INVALID
str5 = """Here are three quotation marks: ""\"."""
str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
# "This," she said, "is just a pointless statement."
str7 = """"This," she said, "is just a pointless statement.""""

6
stdex/string4.toml.res Normal file
View file

@ -0,0 +1,6 @@
{
str4 = "Here are two quotation marks: \"\". Simple enough.",
str5 = "Here are three quotation marks: \"\"\".",
str6 = "Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".",
str7 = "\"This,\" she said, \"is just a pointless statement.\"",
}

5
stdex/string5.toml Normal file
View file

@ -0,0 +1,5 @@
# What you see is what you get.
winpath = 'C:\Users\nodejs\templates'
winpath2 = '\\ServerX\admin$\system32\'
quoted = 'Tom "Dubs" Preston-Werner'
regex = '<\i\c*\s*>'

6
stdex/string5.toml.res Normal file
View file

@ -0,0 +1,6 @@
{
winpath = "C:\\Users\\nodejs\\templates",
winpath2 = "\\\\ServerX\\admin$\\system32\\",
quoted = "Tom \"Dubs\" Preston-Werner",
regex = "<\\i\\c*\\s*>",
}

7
stdex/string6.toml Normal file
View file

@ -0,0 +1,7 @@
regex2 = '''I [dw]on't need \d{2} apples'''
lines = '''
The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
'''

4
stdex/string6.toml.res Normal file
View file

@ -0,0 +1,4 @@
{
regex2 = "I [dw]on't need \\d{2} apples",
lines = "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n",
}

4
stdex/string7.toml Normal file
View file

@ -0,0 +1,4 @@
quot15 = '''Here are fifteen quotation marks: """""""""""""""'''
# 'That,' she said, 'is still pointless.'
str = ''''That,' she said, 'is still pointless.''''

4
stdex/string7.toml.res Normal file
View file

@ -0,0 +1,4 @@
{
quot15 = "Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"",
str = "'That,' she said, 'is still pointless.'",
}

3
stdex/string8.toml Normal file
View file

@ -0,0 +1,3 @@
# apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID
apos15 = "Here are fifteen apostrophes: '''''''''''''''"

1
stdex/string8.toml.res Normal file
View file

@ -0,0 +1 @@
ERROR: line 2: triple-s-quote inside string lit

257
toml.c
View file

@ -2,7 +2,7 @@
MIT License
Copyright (c) 2017 - 2019 CK Tan
Copyright (c) 2017 - 2021 CK Tan
https://github.com/cktan/tomlc99
Permission is hereby granted, free of charge, to any person obtaining a copy
@ -268,18 +268,22 @@ struct toml_keyval_t {
const char* val; /* the raw value */
};
typedef struct toml_arritem_t toml_arritem_t;
struct toml_arritem_t {
int valtype; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */
char* val;
toml_array_t* arr;
toml_table_t* tab;
};
struct toml_array_t {
const char* key; /* key to this array */
int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */
int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp */
int kind; /* element kind: 'v'alue, 'a'rray, or 't'able, 'm'ixed */
int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp, 'm'ixed */
int nelem; /* number of elements */
union {
char** val;
toml_array_t** arr;
toml_table_t** tab;
} u;
int nitem; /* number of elements */
toml_arritem_t* item;
};
@ -408,6 +412,15 @@ static void** expand_ptrarr(void** p, int n)
return s;
}
static toml_arritem_t* expand_arritem(toml_arritem_t* p, int n)
{
toml_arritem_t* pp = expand(p, n*sizeof(*p), (n+1)*sizeof(*p));
if (!pp) return 0;
memset(&pp[n], 0, sizeof(pp[n]));
return pp;
}
static char* norm_lit_str(const char* src, int srclen,
int multiline,
@ -825,26 +838,41 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx,
return dest;
}
static toml_arritem_t* create_value_in_array(context_t* ctx,
toml_array_t* parent)
{
const int n = parent->nitem;
toml_arritem_t* base = expand_arritem(parent->item, n);
if (!base) {
e_outofmemory(ctx, FLINE);
return 0;
}
parent->item = base;
parent->nitem++;
return &parent->item[n];
}
/* Create an array in an array
*/
static toml_array_t* create_array_in_array(context_t* ctx,
toml_array_t* parent)
{
const int n = parent->nelem;
toml_array_t** base;
if (0 == (base = (toml_array_t**) expand_ptrarr((void**)parent->u.arr, n))) {
const int n = parent->nitem;
toml_arritem_t* base = expand_arritem(parent->item, n);
if (!base) {
e_outofmemory(ctx, FLINE);
return 0;
}
parent->u.arr = base;
parent->nelem++;
if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) {
toml_array_t* ret = (toml_array_t*) CALLOC(1, sizeof(toml_array_t));
if (!ret) {
e_outofmemory(ctx, FLINE);
return 0;
}
return parent->u.arr[n];
base[n].arr = ret;
parent->item = base;
parent->nitem++;
return ret;
}
/* Create a table in an array
@ -852,20 +880,21 @@ static toml_array_t* create_array_in_array(context_t* ctx,
static toml_table_t* create_table_in_array(context_t* ctx,
toml_array_t* parent)
{
int n = parent->nelem;
toml_table_t** base;
if (0 == (base = (toml_table_t**) expand_ptrarr((void**)parent->u.tab, n))) {
int n = parent->nitem;
toml_arritem_t* base = expand_arritem(parent->item, n);
if (!base) {
e_outofmemory(ctx, FLINE);
return 0;
}
parent->u.tab = base;
if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) {
toml_table_t* ret = (toml_table_t*) CALLOC(1, sizeof(toml_table_t));
if (!ret) {
e_outofmemory(ctx, FLINE);
return 0;
}
return parent->u.tab[parent->nelem++];
base[n].tab = ret;
parent->item = base;
parent->nitem++;
return ret;
}
@ -963,33 +992,30 @@ static int parse_array(context_t* ctx, toml_array_t* arr)
switch (ctx->tok.tok) {
case STRING:
{
/* set array kind if this will be the first entry */
if (arr->kind == 0)
arr->kind = 'v';
else if (arr->kind != 'v')
arr->kind = 'm';
char* val = ctx->tok.ptr;
int vlen = ctx->tok.len;
/* set array kind if this will be the first entry */
if (arr->kind == 0) arr->kind = 'v';
/* check array kind */
if (arr->kind != 'v')
return e_syntax(ctx, ctx->tok.lineno, "a string array can only contain strings");
/* make a new value in array */
char** tmp = (char**) expand_ptrarr((void**)arr->u.val, arr->nelem);
if (!tmp)
toml_arritem_t* newval = create_value_in_array(ctx, arr);
if (!newval)
return e_outofmemory(ctx, FLINE);
arr->u.val = tmp;
if (! (val = STRNDUP(val, vlen)))
if (! (newval->val = STRNDUP(val, vlen)))
return e_outofmemory(ctx, FLINE);
arr->u.val[arr->nelem++] = val;
newval->valtype = valtype(newval->val);
/* set array type if this is the first entry, or check that the types matched. */
if (arr->nelem == 1)
arr->type = valtype(arr->u.val[0]);
else if (arr->type != valtype(val)) {
return e_syntax(ctx, ctx->tok.lineno,
"array type mismatch while processing array of values");
}
/* set array type if this is the first entry */
if (arr->nitem == 1)
arr->type = newval->valtype;
else if (arr->type != newval->valtype)
arr->type = 'm'; /* mixed */
if (eat_token(ctx, STRING, 0, FLINE)) return -1;
break;
@ -998,12 +1024,11 @@ static int parse_array(context_t* ctx, toml_array_t* arr)
case LBRACKET:
{ /* [ [array], [array] ... ] */
/* set the array kind if this will be the first entry */
if (arr->kind == 0) arr->kind = 'a';
/* check array kind */
if (arr->kind != 'a') {
return e_syntax(ctx, ctx->tok.lineno,
"array type mismatch while processing array of arrays");
}
if (arr->kind == 0)
arr->kind = 'a';
else if (arr->kind != 'a')
arr->kind = 'm';
toml_array_t* subarr = create_array_in_array(ctx, arr);
if (!subarr) return -1;
if (parse_array(ctx, subarr)) return -1;
@ -1013,12 +1038,11 @@ static int parse_array(context_t* ctx, toml_array_t* arr)
case LBRACE:
{ /* [ {table}, {table} ... ] */
/* set the array kind if this will be the first entry */
if (arr->kind == 0) arr->kind = 't';
/* check array kind */
if (arr->kind != 't') {
return e_syntax(ctx, ctx->tok.lineno,
"array type mismatch while processing array of tables");
}
if (arr->kind == 0)
arr->kind = 't';
else if (arr->kind != 't')
arr->kind = 'm';
toml_table_t* subtab = create_table_in_array(ctx, arr);
if (!subtab) return -1;
if (parse_table(ctx, subtab)) return -1;
@ -1199,10 +1223,10 @@ static int walk_tabpath(context_t* ctx)
if (nextarr->kind != 't')
return e_internal(ctx, FLINE);
if (nextarr->nelem == 0)
if (nextarr->nitem == 0)
return e_internal(ctx, FLINE);
nexttab = nextarr->u.tab[nextarr->nelem-1];
nexttab = nextarr->item[nextarr->nitem-1].tab;
break;
case 'v':
@ -1294,20 +1318,13 @@ static int parse_select(context_t* ctx)
/* add to z[] */
toml_table_t* dest;
{
int n = arr->nelem;
toml_table_t** base = (toml_table_t**) expand_ptrarr((void**)arr->u.tab, n);
if (0 == base)
toml_table_t* t = create_table_in_array(ctx, arr);
if (!t) return -1;
if (0 == (t->key = STRDUP("__anon__")))
return e_outofmemory(ctx, FLINE);
arr->u.tab = base;
if (0 == (base[n] = CALLOC(1, sizeof(*base[n]))))
return e_outofmemory(ctx, FLINE);
if (0 == (base[n]->key = STRDUP("__anon__")))
return e_outofmemory(ctx, FLINE);
dest = arr->u.tab[arr->nelem++];
dest = t;
}
ctx->curtab = dest;
@ -1479,23 +1496,17 @@ static void xfree_arr(toml_array_t* p)
if (!p) return;
xfree(p->key);
switch (p->kind) {
case 'v':
for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]);
xfree(p->u.val);
break;
case 'a':
for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]);
xfree(p->u.arr);
break;
case 't':
for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]);
xfree(p->u.tab);
break;
const int n = p->nitem;
for (int i = 0; i < n; i++) {
toml_arritem_t* a = &p->item[i];
if (a->val)
xfree(a->val);
else if (a->arr)
xfree_arr(a->arr);
else if (a->tab)
xfree_tab(a->tab);
}
xfree(p->item);
xfree(p);
}
@ -1584,20 +1595,44 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial)
{
char* orig = p;
if (0 == strncmp(p, "'''", 3)) {
p = strstr(p + 3, "'''");
if (0 == p) {
char* q = p + 3;
while (1) {
q = strstr(q, "'''");
if (0 == q) {
return e_syntax(ctx, lineno, "unterminated triple-s-quote");
}
while (q[3] == '\'') q++;
break;
}
set_token(ctx, STRING, lineno, orig, p + 3 - orig);
set_token(ctx, STRING, lineno, orig, q + 3 - orig);
return 0;
}
if (0 == strncmp(p, "\"\"\"", 3)) {
char* q = p + 3;
while (1) {
q = strstr(q, "\"\"\"");
if (0 == q) {
return e_syntax(ctx, lineno, "unterminated triple-d-quote");
}
if (q[-1] == '\\') {
q++;
continue;
}
while (q[3] == '\"') q++;
break;
}
char* tsq = strstr(p, "\'\'\'");
// the string is [p+3, q-1]
int hexreq = 0; /* #hex required */
int escape = 0;
int qcnt = 0; /* count quote */
for (p += 3; *p && qcnt < 3; p++) {
for (p += 3; p < q; p++) {
if (escape) {
escape = 0;
if (strchr("btnfr\"\\", *p)) continue;
@ -1612,13 +1647,16 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial)
return e_syntax(ctx, lineno, "expect hex char");
}
if (*p == '\\') { escape = 1; continue; }
qcnt = (*p == '"') ? qcnt + 1 : 0;
}
if (qcnt != 3) {
return e_syntax(ctx, lineno, "unterminated triple-quote");
}
if (escape)
return e_syntax(ctx, lineno, "expect an escape char");
if (hexreq)
return e_syntax(ctx, lineno, "expected more hex char");
set_token(ctx, STRING, lineno, orig, p - orig);
if (tsq && tsq < q) {
return e_syntax(ctx, lineno, "triple-s-quote inside string lit");
}
set_token(ctx, STRING, lineno, orig, q + 3 - orig);
return 0;
}
@ -1633,6 +1671,7 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial)
}
if ('\"' == *p) {
char* tsq = strstr(p, "\'\'\'");
int hexreq = 0; /* #hex required */
int escape = 0;
for (p++; *p; p++) {
@ -1656,6 +1695,10 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial)
return e_syntax(ctx, lineno, "unterminated quote");
}
if (tsq && tsq < p) {
return e_syntax(ctx, lineno, "triple-s-quote inside string lit");
}
set_token(ctx, STRING, lineno, orig, p + 1 - orig);
return 0;
}
@ -1779,11 +1822,7 @@ toml_table_t* toml_table_in(const toml_table_t* tab, const char* key)
toml_raw_t toml_raw_at(const toml_array_t* arr, int idx)
{
if (arr->kind != 'v')
return 0;
if (! (0 <= idx && idx < arr->nelem))
return 0;
return arr->u.val[idx];
return (0 <= idx && idx < arr->nitem) ? arr->item[idx].val : 0;
}
char toml_array_kind(const toml_array_t* arr)
@ -1796,7 +1835,7 @@ char toml_array_type(const toml_array_t* arr)
if (arr->kind != 'v')
return 0;
if (arr->nelem == 0)
if (arr->nitem == 0)
return 0;
return arr->type;
@ -1805,7 +1844,7 @@ char toml_array_type(const toml_array_t* arr)
int toml_array_nelem(const toml_array_t* arr)
{
return arr->nelem;
return arr->nitem;
}
const char* toml_array_key(const toml_array_t* arr)
@ -1835,20 +1874,12 @@ const char* toml_table_key(const toml_table_t* tab)
toml_array_t* toml_array_at(const toml_array_t* arr, int idx)
{
if (arr->kind != 'a')
return 0;
if (! (0 <= idx && idx < arr->nelem))
return 0;
return arr->u.arr[idx];
return (0 <= idx && idx < arr->nitem) ? arr->item[idx].arr : 0;
}
toml_table_t* toml_table_at(const toml_array_t* arr, int idx)
{
if (arr->kind != 't')
return 0;
if (! (0 <= idx && idx < arr->nelem))
return 0;
return arr->u.tab[idx];
return (0 <= idx && idx < arr->nitem) ? arr->item[idx].tab : 0;
}

4
toml.h
View file

@ -124,11 +124,11 @@ TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab,
/*-----------------------------------------------------------------
* lesser used
*/
/* Return the array kind: 't'able, 'a'rray, 'v'alue */
/* Return the array kind: 't'able, 'a'rray, 'v'alue, 'm'ixed */
TOML_EXTERN char toml_array_kind(const toml_array_t* arr);
/* For array kind 'v'alue, return the type of values
i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp
i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp, 'm'ixed
0 if unknown
*/
TOML_EXTERN char toml_array_type(const toml_array_t* arr);

View file

@ -33,6 +33,8 @@ SOFTWARE.
#include <errno.h>
#include <stdint.h>
#include <assert.h>
#include <inttypes.h>
#include <ctype.h>
#include "toml.h"
typedef struct node_t node_t;
@ -43,114 +45,211 @@ struct node_t {
node_t stack[20];
int stacktop = 0;
int indent = 0;
static void print_table_title(const char* arrname)
static void prindent()
{
int i;
printf("%s", arrname ? "[[" : "[");
for (i = 1; i < stacktop; i++) {
printf("%s", stack[i].key);
if (i + 1 < stacktop)
printf(".");
}
if (arrname)
printf(".%s]]\n", arrname);
else
printf("]\n");
for (int i = 0; i < indent; i++) printf(" ");
}
static void print_string(const char* s)
{
int ok = 1;
for (const char* p = s; *p && ok; p++) {
int ch = *p;
ok = isprint(ch) && ch != '"' && ch != '\\';
}
if (ok) {
printf("\"%s\"", s);
return;
}
int len = strlen(s);
printf("\"");
for ( ; len; len--, s++) {
int ch = *s;
if (isprint(ch) && ch != '"' && ch != '\\') {
putchar(ch);
continue;
}
switch (ch) {
case 0x8: printf("\\b"); continue;
case 0x9: printf("\\t"); continue;
case 0xa: printf("\\n"); continue;
case 0xc: printf("\\f"); continue;
case 0xd: printf("\\r"); continue;
case '"': printf("\\\""); continue;
case '\\': printf("\\\\"); continue;
default: printf("\\0x%02x", ch & 0xff); continue;
}
}
printf("\"");
}
static void print_array_of_tables(toml_array_t* arr, const char* key);
static void print_array(toml_array_t* arr);
static void print_table(toml_table_t* curtab)
{
toml_datum_t d;
int i;
const char* key;
const char* raw;
toml_array_t* arr;
toml_table_t* tab;
for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) {
if (0 != (raw = toml_raw_in(curtab, key))) {
printf("%s = %s\n", key, raw);
} else if (0 != (arr = toml_array_in(curtab, key))) {
if (toml_array_kind(arr) == 't') {
print_array_of_tables(arr, key);
}
else {
if (0 != (arr = toml_array_in(curtab, key))) {
prindent();
printf("%s = [\n", key);
indent++;
print_array(arr);
printf(" ]\n");
indent--;
prindent();
printf("],\n");
continue;
}
} else if (0 != (tab = toml_table_in(curtab, key))) {
if (0 != (tab = toml_table_in(curtab, key))) {
stack[stacktop].key = key;
stack[stacktop].tab = tab;
stacktop++;
print_table_title(0);
prindent();
printf("%s = {\n", key);
indent++;
print_table(tab);
indent--;
prindent();
printf("},\n");
stacktop--;
} else {
abort();
}
}
continue;
}
static void print_array_of_tables(toml_array_t* arr, const char* key)
{
int i;
toml_table_t* tab;
printf("\n");
for (i = 0; 0 != (tab = toml_table_at(arr, i)); i++) {
print_table_title(key);
print_table(tab);
printf("\n");
d = toml_string_in(curtab, key);
if (d.ok) {
prindent();
printf("%s = ", key);
print_string(d.u.s);
printf(",\n");
free(d.u.s);
continue;
}
d = toml_bool_in(curtab, key);
if (d.ok) {
prindent();
printf("%s = %s,\n", key, d.u.b ? "true" : "false");
continue;
}
d = toml_int_in(curtab, key);
if (d.ok) {
prindent();
printf("%s = %" PRId64 ",\n", key, d.u.i);
continue;
}
d = toml_double_in(curtab, key);
if (d.ok) {
prindent();
printf("%s = %g,\n", key, d.u.d);
continue;
}
d = toml_timestamp_in(curtab, key);
if (d.ok) {
prindent();
printf(" %s = %s,\n", key, toml_raw_in(curtab, key));
free(d.u.ts);
continue;
}
abort();
}
}
static void print_array(toml_array_t* curarr)
{
toml_datum_t d;
toml_array_t* arr;
const char* raw;
toml_table_t* tab;
int i;
const int n = toml_array_nelem(curarr);
switch (toml_array_kind(curarr)) {
for (int i = 0; i < n; i++) {
case 'v':
for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) {
printf(" %d: %s,\n", i, raw);
}
break;
case 'a':
for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) {
printf(" %d: \n", i);
if (0 != (arr = toml_array_at(curarr, i))) {
prindent();
printf("[\n");
indent++;
print_array(arr);
indent--;
prindent();
printf("],\n");
continue;
}
break;
case 't':
for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) {
if (0 != (tab = toml_table_at(curarr, i))) {
prindent();
printf("{\n");
indent++;
print_table(tab);
indent--;
prindent();
printf("},\n");
continue;
}
printf("\n");
break;
case '\0':
break;
d = toml_string_at(curarr, i);
if (d.ok) {
prindent();
print_string(d.u.s);
printf(",\n");
free(d.u.s);
continue;
}
d = toml_bool_at(curarr, i);
if (d.ok) {
prindent();
printf("%s,\n", d.u.b ? "true" : "false");
continue;
}
d = toml_int_at(curarr, i);
if (d.ok) {
prindent();
printf("%" PRId64 ",\n", d.u.i);
continue;
}
d = toml_double_at(curarr, i);
if (d.ok) {
prindent();
printf("%g,\n", d.u.d);
continue;
}
d = toml_timestamp_at(curarr, i);
if (d.ok) {
prindent();
printf("%s,\n", toml_raw_at(curarr, i));
free(d.u.ts);
continue;
}
default:
abort();
}
}
static void cat(FILE* fp)
{
char errbuf[200];
@ -164,7 +263,11 @@ static void cat(FILE* fp)
stack[stacktop].tab = tab;
stack[stacktop].key = "";
stacktop++;
printf("{\n");
indent++;
print_table(tab);
indent--;
printf("}\n");
stacktop--;
toml_free(tab);