fixed issue #51
This commit is contained in:
parent
1cfa8e42c4
commit
715fa54d45
55 changed files with 747 additions and 366 deletions
1
stdex/.gitignore
vendored
Normal file
1
stdex/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/*.out
|
15
stdex/RUN.sh
Normal file
15
stdex/RUN.sh
Normal 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
3
stdex/comment.toml
Normal 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
4
stdex/comment.toml.res
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
key = "value",
|
||||||
|
another = "# This is not a comment",
|
||||||
|
}
|
4
stdex/keys00.toml
Normal file
4
stdex/keys00.toml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
key = "value"
|
||||||
|
bare_key = "value"
|
||||||
|
bare-key = "value"
|
||||||
|
1234 = "value"
|
6
stdex/keys00.toml.res
Normal file
6
stdex/keys00.toml.res
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
key = "value",
|
||||||
|
bare_key = "value",
|
||||||
|
bare-key = "value",
|
||||||
|
1234 = "value",
|
||||||
|
}
|
5
stdex/keys01.toml
Normal file
5
stdex/keys01.toml
Normal 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
7
stdex/keys01.toml.res
Normal 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
1
stdex/keys02.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
= "no key name" # INVALID
|
1
stdex/keys02.toml.res
Normal file
1
stdex/keys02.toml.res
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ERROR: line 1: syntax error
|
1
stdex/keys03.toml
Normal file
1
stdex/keys03.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
"" = "blank" # VALID but discouraged
|
3
stdex/keys03.toml.res
Normal file
3
stdex/keys03.toml.res
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
= "blank",
|
||||||
|
}
|
4
stdex/keys04.toml
Normal file
4
stdex/keys04.toml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
name = "Orange"
|
||||||
|
physical.color = "orange"
|
||||||
|
physical.shape = "round"
|
||||||
|
site."google.com" = true
|
10
stdex/keys04.toml.res
Normal file
10
stdex/keys04.toml.res
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
name = "Orange",
|
||||||
|
physical = {
|
||||||
|
color = "orange",
|
||||||
|
shape = "round",
|
||||||
|
},
|
||||||
|
site = {
|
||||||
|
google.com = true,
|
||||||
|
},
|
||||||
|
}
|
3
stdex/keys05.toml
Normal file
3
stdex/keys05.toml
Normal 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
7
stdex/keys05.toml.res
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
fruit = {
|
||||||
|
name = "banana",
|
||||||
|
color = "yellow",
|
||||||
|
flavor = "banana",
|
||||||
|
},
|
||||||
|
}
|
3
stdex/keys06.toml
Normal file
3
stdex/keys06.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# DO NOT DO THIS
|
||||||
|
name = "Tom"
|
||||||
|
name = "Pradyun"
|
1
stdex/keys06.toml.res
Normal file
1
stdex/keys06.toml.res
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ERROR: line 3: key exists
|
3
stdex/keys07.toml
Normal file
3
stdex/keys07.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# THIS WILL NOT WORK
|
||||||
|
spelling = "favorite"
|
||||||
|
"spelling" = "favourite"
|
1
stdex/keys07.toml.res
Normal file
1
stdex/keys07.toml.res
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ERROR: line 3: key exists
|
5
stdex/keys08.toml
Normal file
5
stdex/keys08.toml
Normal 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
8
stdex/keys08.toml.res
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
fruit = {
|
||||||
|
orange = 2,
|
||||||
|
apple = {
|
||||||
|
smooth = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
8
stdex/keys09.toml
Normal file
8
stdex/keys09.toml
Normal 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
1
stdex/keys09.toml.res
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ERROR: line 8: key exists
|
10
stdex/keys10.toml
Normal file
10
stdex/keys10.toml
Normal 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
12
stdex/keys10.toml.res
Normal 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
9
stdex/keys11.toml
Normal 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
12
stdex/keys11.toml.res
Normal 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
1
stdex/keys12.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
3.14159 = "pi"
|
5
stdex/keys12.toml.res
Normal file
5
stdex/keys12.toml.res
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
3 = {
|
||||||
|
14159 = "pi",
|
||||||
|
},
|
||||||
|
}
|
1
stdex/kvpair0.toml
Normal file
1
stdex/kvpair0.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
key = "value"
|
3
stdex/kvpair0.toml.res
Normal file
3
stdex/kvpair0.toml.res
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
key = "value",
|
||||||
|
}
|
1
stdex/kvpair1.toml
Normal file
1
stdex/kvpair1.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
key = # INVALID
|
1
stdex/kvpair1.toml.res
Normal file
1
stdex/kvpair1.toml.res
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ERROR: line 1: syntax error
|
1
stdex/kvpair2.toml
Normal file
1
stdex/kvpair2.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
first = "Tom" last = "Preston-Werner" # INVALID
|
1
stdex/kvpair2.toml.res
Normal file
1
stdex/kvpair2.toml.res
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ERROR: line 1: extra chars after value
|
1
stdex/string0.toml
Normal file
1
stdex/string0.toml
Normal 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
3
stdex/string0.toml.res
Normal 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
9
stdex/string1.toml
Normal 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
5
stdex/string1.toml.res
Normal 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
15
stdex/string3.toml
Normal 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
5
stdex/string3.toml.res
Normal 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
7
stdex/string4.toml
Normal 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
6
stdex/string4.toml.res
Normal 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
5
stdex/string5.toml
Normal 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
6
stdex/string5.toml.res
Normal 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
7
stdex/string6.toml
Normal 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
4
stdex/string6.toml.res
Normal 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
4
stdex/string7.toml
Normal 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
4
stdex/string7.toml.res
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
quot15 = "Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"",
|
||||||
|
str = "'That,' she said, 'is still pointless.'",
|
||||||
|
}
|
3
stdex/string8.toml
Normal file
3
stdex/string8.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID
|
||||||
|
apos15 = "Here are fifteen apostrophes: '''''''''''''''"
|
||||||
|
|
1
stdex/string8.toml.res
Normal file
1
stdex/string8.toml.res
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ERROR: line 2: triple-s-quote inside string lit
|
259
toml.c
259
toml.c
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 - 2019 CK Tan
|
Copyright (c) 2017 - 2021 CK Tan
|
||||||
https://github.com/cktan/tomlc99
|
https://github.com/cktan/tomlc99
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
@ -268,18 +268,22 @@ struct toml_keyval_t {
|
||||||
const char* val; /* the raw value */
|
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 {
|
struct toml_array_t {
|
||||||
const char* key; /* key to this array */
|
const char* key; /* key to this array */
|
||||||
int kind; /* element kind: 'v'alue, 'a'rray, or 't'able */
|
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 */
|
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 */
|
int nitem; /* number of elements */
|
||||||
union {
|
toml_arritem_t* item;
|
||||||
char** val;
|
|
||||||
toml_array_t** arr;
|
|
||||||
toml_table_t** tab;
|
|
||||||
} u;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -408,6 +412,15 @@ static void** expand_ptrarr(void** p, int n)
|
||||||
return s;
|
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,
|
static char* norm_lit_str(const char* src, int srclen,
|
||||||
int multiline,
|
int multiline,
|
||||||
|
@ -825,26 +838,41 @@ static toml_array_t* create_keyarray_in_table(context_t* ctx,
|
||||||
return dest;
|
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
|
/* Create an array in an array
|
||||||
*/
|
*/
|
||||||
static toml_array_t* create_array_in_array(context_t* ctx,
|
static toml_array_t* create_array_in_array(context_t* ctx,
|
||||||
toml_array_t* parent)
|
toml_array_t* parent)
|
||||||
{
|
{
|
||||||
const int n = parent->nelem;
|
const int n = parent->nitem;
|
||||||
toml_array_t** base;
|
toml_arritem_t* base = expand_arritem(parent->item, n);
|
||||||
if (0 == (base = (toml_array_t**) expand_ptrarr((void**)parent->u.arr, n))) {
|
if (!base) {
|
||||||
e_outofmemory(ctx, FLINE);
|
e_outofmemory(ctx, FLINE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
parent->u.arr = base;
|
toml_array_t* ret = (toml_array_t*) CALLOC(1, sizeof(toml_array_t));
|
||||||
parent->nelem++;
|
if (!ret) {
|
||||||
|
|
||||||
if (0 == (base[n] = (toml_array_t*) CALLOC(1, sizeof(*base[n])))) {
|
|
||||||
e_outofmemory(ctx, FLINE);
|
e_outofmemory(ctx, FLINE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
base[n].arr = ret;
|
||||||
return parent->u.arr[n];
|
parent->item = base;
|
||||||
|
parent->nitem++;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a table in an array
|
/* 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,
|
static toml_table_t* create_table_in_array(context_t* ctx,
|
||||||
toml_array_t* parent)
|
toml_array_t* parent)
|
||||||
{
|
{
|
||||||
int n = parent->nelem;
|
int n = parent->nitem;
|
||||||
toml_table_t** base;
|
toml_arritem_t* base = expand_arritem(parent->item, n);
|
||||||
if (0 == (base = (toml_table_t**) expand_ptrarr((void**)parent->u.tab, n))) {
|
if (!base) {
|
||||||
e_outofmemory(ctx, FLINE);
|
e_outofmemory(ctx, FLINE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
parent->u.tab = base;
|
toml_table_t* ret = (toml_table_t*) CALLOC(1, sizeof(toml_table_t));
|
||||||
|
if (!ret) {
|
||||||
if (0 == (base[n] = (toml_table_t*) CALLOC(1, sizeof(*base[n])))) {
|
|
||||||
e_outofmemory(ctx, FLINE);
|
e_outofmemory(ctx, FLINE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
base[n].tab = ret;
|
||||||
return parent->u.tab[parent->nelem++];
|
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) {
|
switch (ctx->tok.tok) {
|
||||||
case STRING:
|
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;
|
char* val = ctx->tok.ptr;
|
||||||
int vlen = ctx->tok.len;
|
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 */
|
/* make a new value in array */
|
||||||
char** tmp = (char**) expand_ptrarr((void**)arr->u.val, arr->nelem);
|
toml_arritem_t* newval = create_value_in_array(ctx, arr);
|
||||||
if (!tmp)
|
if (!newval)
|
||||||
return e_outofmemory(ctx, FLINE);
|
return e_outofmemory(ctx, FLINE);
|
||||||
|
|
||||||
arr->u.val = tmp;
|
if (! (newval->val = STRNDUP(val, vlen)))
|
||||||
if (! (val = STRNDUP(val, vlen)))
|
|
||||||
return e_outofmemory(ctx, FLINE);
|
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. */
|
/* set array type if this is the first entry */
|
||||||
if (arr->nelem == 1)
|
if (arr->nitem == 1)
|
||||||
arr->type = valtype(arr->u.val[0]);
|
arr->type = newval->valtype;
|
||||||
else if (arr->type != valtype(val)) {
|
else if (arr->type != newval->valtype)
|
||||||
return e_syntax(ctx, ctx->tok.lineno,
|
arr->type = 'm'; /* mixed */
|
||||||
"array type mismatch while processing array of values");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eat_token(ctx, STRING, 0, FLINE)) return -1;
|
if (eat_token(ctx, STRING, 0, FLINE)) return -1;
|
||||||
break;
|
break;
|
||||||
|
@ -998,12 +1024,11 @@ static int parse_array(context_t* ctx, toml_array_t* arr)
|
||||||
case LBRACKET:
|
case LBRACKET:
|
||||||
{ /* [ [array], [array] ... ] */
|
{ /* [ [array], [array] ... ] */
|
||||||
/* set the array kind if this will be the first entry */
|
/* set the array kind if this will be the first entry */
|
||||||
if (arr->kind == 0) arr->kind = 'a';
|
if (arr->kind == 0)
|
||||||
/* check array kind */
|
arr->kind = 'a';
|
||||||
if (arr->kind != 'a') {
|
else if (arr->kind != 'a')
|
||||||
return e_syntax(ctx, ctx->tok.lineno,
|
arr->kind = 'm';
|
||||||
"array type mismatch while processing array of arrays");
|
|
||||||
}
|
|
||||||
toml_array_t* subarr = create_array_in_array(ctx, arr);
|
toml_array_t* subarr = create_array_in_array(ctx, arr);
|
||||||
if (!subarr) return -1;
|
if (!subarr) return -1;
|
||||||
if (parse_array(ctx, 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:
|
case LBRACE:
|
||||||
{ /* [ {table}, {table} ... ] */
|
{ /* [ {table}, {table} ... ] */
|
||||||
/* set the array kind if this will be the first entry */
|
/* set the array kind if this will be the first entry */
|
||||||
if (arr->kind == 0) arr->kind = 't';
|
if (arr->kind == 0)
|
||||||
/* check array kind */
|
arr->kind = 't';
|
||||||
if (arr->kind != 't') {
|
else if (arr->kind != 't')
|
||||||
return e_syntax(ctx, ctx->tok.lineno,
|
arr->kind = 'm';
|
||||||
"array type mismatch while processing array of tables");
|
|
||||||
}
|
|
||||||
toml_table_t* subtab = create_table_in_array(ctx, arr);
|
toml_table_t* subtab = create_table_in_array(ctx, arr);
|
||||||
if (!subtab) return -1;
|
if (!subtab) return -1;
|
||||||
if (parse_table(ctx, 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')
|
if (nextarr->kind != 't')
|
||||||
return e_internal(ctx, FLINE);
|
return e_internal(ctx, FLINE);
|
||||||
|
|
||||||
if (nextarr->nelem == 0)
|
if (nextarr->nitem == 0)
|
||||||
return e_internal(ctx, FLINE);
|
return e_internal(ctx, FLINE);
|
||||||
|
|
||||||
nexttab = nextarr->u.tab[nextarr->nelem-1];
|
nexttab = nextarr->item[nextarr->nitem-1].tab;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
|
@ -1294,20 +1318,13 @@ static int parse_select(context_t* ctx)
|
||||||
/* add to z[] */
|
/* add to z[] */
|
||||||
toml_table_t* dest;
|
toml_table_t* dest;
|
||||||
{
|
{
|
||||||
int n = arr->nelem;
|
toml_table_t* t = create_table_in_array(ctx, arr);
|
||||||
toml_table_t** base = (toml_table_t**) expand_ptrarr((void**)arr->u.tab, n);
|
if (!t) return -1;
|
||||||
if (0 == base)
|
|
||||||
|
if (0 == (t->key = STRDUP("__anon__")))
|
||||||
return e_outofmemory(ctx, FLINE);
|
return e_outofmemory(ctx, FLINE);
|
||||||
|
|
||||||
arr->u.tab = base;
|
dest = t;
|
||||||
|
|
||||||
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++];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->curtab = dest;
|
ctx->curtab = dest;
|
||||||
|
@ -1479,23 +1496,17 @@ static void xfree_arr(toml_array_t* p)
|
||||||
if (!p) return;
|
if (!p) return;
|
||||||
|
|
||||||
xfree(p->key);
|
xfree(p->key);
|
||||||
switch (p->kind) {
|
const int n = p->nitem;
|
||||||
case 'v':
|
for (int i = 0; i < n; i++) {
|
||||||
for (int i = 0; i < p->nelem; i++) xfree(p->u.val[i]);
|
toml_arritem_t* a = &p->item[i];
|
||||||
xfree(p->u.val);
|
if (a->val)
|
||||||
break;
|
xfree(a->val);
|
||||||
|
else if (a->arr)
|
||||||
case 'a':
|
xfree_arr(a->arr);
|
||||||
for (int i = 0; i < p->nelem; i++) xfree_arr(p->u.arr[i]);
|
else if (a->tab)
|
||||||
xfree(p->u.arr);
|
xfree_tab(a->tab);
|
||||||
break;
|
|
||||||
|
|
||||||
case 't':
|
|
||||||
for (int i = 0; i < p->nelem; i++) xfree_tab(p->u.tab[i]);
|
|
||||||
xfree(p->u.tab);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
xfree(p->item);
|
||||||
xfree(p);
|
xfree(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1584,20 +1595,44 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial)
|
||||||
{
|
{
|
||||||
char* orig = p;
|
char* orig = p;
|
||||||
if (0 == strncmp(p, "'''", 3)) {
|
if (0 == strncmp(p, "'''", 3)) {
|
||||||
p = strstr(p + 3, "'''");
|
char* q = p + 3;
|
||||||
if (0 == p) {
|
|
||||||
return e_syntax(ctx, lineno, "unterminated triple-s-quote");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == strncmp(p, "\"\"\"", 3)) {
|
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 hexreq = 0; /* #hex required */
|
||||||
int escape = 0;
|
int escape = 0;
|
||||||
int qcnt = 0; /* count quote */
|
for (p += 3; p < q; p++) {
|
||||||
for (p += 3; *p && qcnt < 3; p++) {
|
|
||||||
if (escape) {
|
if (escape) {
|
||||||
escape = 0;
|
escape = 0;
|
||||||
if (strchr("btnfr\"\\", *p)) continue;
|
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");
|
return e_syntax(ctx, lineno, "expect hex char");
|
||||||
}
|
}
|
||||||
if (*p == '\\') { escape = 1; continue; }
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1633,6 +1671,7 @@ static int scan_string(context_t* ctx, char* p, int lineno, int dotisspecial)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('\"' == *p) {
|
if ('\"' == *p) {
|
||||||
|
char* tsq = strstr(p, "\'\'\'");
|
||||||
int hexreq = 0; /* #hex required */
|
int hexreq = 0; /* #hex required */
|
||||||
int escape = 0;
|
int escape = 0;
|
||||||
for (p++; *p; p++) {
|
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");
|
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);
|
set_token(ctx, STRING, lineno, orig, p + 1 - orig);
|
||||||
return 0;
|
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)
|
toml_raw_t toml_raw_at(const toml_array_t* arr, int idx)
|
||||||
{
|
{
|
||||||
if (arr->kind != 'v')
|
return (0 <= idx && idx < arr->nitem) ? arr->item[idx].val : 0;
|
||||||
return 0;
|
|
||||||
if (! (0 <= idx && idx < arr->nelem))
|
|
||||||
return 0;
|
|
||||||
return arr->u.val[idx];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char toml_array_kind(const toml_array_t* arr)
|
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')
|
if (arr->kind != 'v')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (arr->nelem == 0)
|
if (arr->nitem == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return arr->type;
|
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)
|
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)
|
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)
|
toml_array_t* toml_array_at(const toml_array_t* arr, int idx)
|
||||||
{
|
{
|
||||||
if (arr->kind != 'a')
|
return (0 <= idx && idx < arr->nitem) ? arr->item[idx].arr : 0;
|
||||||
return 0;
|
|
||||||
if (! (0 <= idx && idx < arr->nelem))
|
|
||||||
return 0;
|
|
||||||
return arr->u.arr[idx];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toml_table_t* toml_table_at(const toml_array_t* arr, int idx)
|
toml_table_t* toml_table_at(const toml_array_t* arr, int idx)
|
||||||
{
|
{
|
||||||
if (arr->kind != 't')
|
return (0 <= idx && idx < arr->nitem) ? arr->item[idx].tab : 0;
|
||||||
return 0;
|
|
||||||
if (! (0 <= idx && idx < arr->nelem))
|
|
||||||
return 0;
|
|
||||||
return arr->u.tab[idx];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
4
toml.h
4
toml.h
|
@ -124,11 +124,11 @@ TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab,
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
* lesser used
|
* 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);
|
TOML_EXTERN char toml_array_kind(const toml_array_t* arr);
|
||||||
|
|
||||||
/* For array kind 'v'alue, return the type of values
|
/* 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
|
0 if unknown
|
||||||
*/
|
*/
|
||||||
TOML_EXTERN char toml_array_type(const toml_array_t* arr);
|
TOML_EXTERN char toml_array_type(const toml_array_t* arr);
|
||||||
|
|
317
toml_cat.c
317
toml_cat.c
|
@ -1,26 +1,26 @@
|
||||||
/*
|
/*
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 CK Tan
|
Copyright (c) 2017 CK Tan
|
||||||
https://github.com/cktan/tomlc99
|
https://github.com/cktan/tomlc99
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in all
|
||||||
copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
|
@ -33,6 +33,8 @@ SOFTWARE.
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include "toml.h"
|
#include "toml.h"
|
||||||
|
|
||||||
typedef struct node_t node_t;
|
typedef struct node_t node_t;
|
||||||
|
@ -43,128 +45,229 @@ struct node_t {
|
||||||
|
|
||||||
node_t stack[20];
|
node_t stack[20];
|
||||||
int stacktop = 0;
|
int stacktop = 0;
|
||||||
|
int indent = 0;
|
||||||
|
|
||||||
|
static void prindent()
|
||||||
static void print_table_title(const char* arrname)
|
|
||||||
{
|
{
|
||||||
int i;
|
for (int i = 0; i < indent; i++) printf(" ");
|
||||||
printf("%s", arrname ? "[[" : "[");
|
}
|
||||||
for (i = 1; i < stacktop; i++) {
|
|
||||||
printf("%s", stack[i].key);
|
|
||||||
if (i + 1 < stacktop)
|
static void print_string(const char* s)
|
||||||
printf(".");
|
{
|
||||||
}
|
int ok = 1;
|
||||||
if (arrname)
|
for (const char* p = s; *p && ok; p++) {
|
||||||
printf(".%s]]\n", arrname);
|
int ch = *p;
|
||||||
else
|
ok = isprint(ch) && ch != '"' && ch != '\\';
|
||||||
printf("]\n");
|
}
|
||||||
|
|
||||||
|
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_array(toml_array_t* arr);
|
||||||
|
|
||||||
|
|
||||||
static void print_table(toml_table_t* curtab)
|
static void print_table(toml_table_t* curtab)
|
||||||
{
|
{
|
||||||
|
toml_datum_t d;
|
||||||
int i;
|
int i;
|
||||||
const char* key;
|
const char* key;
|
||||||
const char* raw;
|
|
||||||
toml_array_t* arr;
|
toml_array_t* arr;
|
||||||
toml_table_t* tab;
|
toml_table_t* tab;
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; 0 != (key = toml_key_in(curtab, i)); i++) {
|
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 {
|
|
||||||
printf("%s = [\n", key);
|
|
||||||
print_array(arr);
|
|
||||||
printf(" ]\n");
|
|
||||||
}
|
|
||||||
} else if (0 != (tab = toml_table_in(curtab, key))) {
|
|
||||||
stack[stacktop].key = key;
|
|
||||||
stack[stacktop].tab = tab;
|
|
||||||
stacktop++;
|
|
||||||
print_table_title(0);
|
|
||||||
print_table(tab);
|
|
||||||
stacktop--;
|
|
||||||
} else {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_array_of_tables(toml_array_t* arr, const char* key)
|
if (0 != (arr = toml_array_in(curtab, key))) {
|
||||||
{
|
prindent();
|
||||||
int i;
|
printf("%s = [\n", key);
|
||||||
toml_table_t* tab;
|
indent++;
|
||||||
printf("\n");
|
print_array(arr);
|
||||||
for (i = 0; 0 != (tab = toml_table_at(arr, i)); i++) {
|
indent--;
|
||||||
print_table_title(key);
|
prindent();
|
||||||
print_table(tab);
|
printf("],\n");
|
||||||
printf("\n");
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != (tab = toml_table_in(curtab, key))) {
|
||||||
|
stack[stacktop].key = key;
|
||||||
|
stack[stacktop].tab = tab;
|
||||||
|
stacktop++;
|
||||||
|
prindent();
|
||||||
|
printf("%s = {\n", key);
|
||||||
|
indent++;
|
||||||
|
print_table(tab);
|
||||||
|
indent--;
|
||||||
|
prindent();
|
||||||
|
printf("},\n");
|
||||||
|
stacktop--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
static void print_array(toml_array_t* curarr)
|
||||||
{
|
{
|
||||||
|
toml_datum_t d;
|
||||||
toml_array_t* arr;
|
toml_array_t* arr;
|
||||||
const char* raw;
|
|
||||||
toml_table_t* tab;
|
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':
|
if (0 != (arr = toml_array_at(curarr, i))) {
|
||||||
for (i = 0; 0 != (raw = toml_raw_at(curarr, i)); i++) {
|
prindent();
|
||||||
printf(" %d: %s,\n", i, raw);
|
printf("[\n");
|
||||||
|
indent++;
|
||||||
|
print_array(arr);
|
||||||
|
indent--;
|
||||||
|
prindent();
|
||||||
|
printf("],\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != (tab = toml_table_at(curarr, i))) {
|
||||||
|
prindent();
|
||||||
|
printf("{\n");
|
||||||
|
indent++;
|
||||||
|
print_table(tab);
|
||||||
|
indent--;
|
||||||
|
prindent();
|
||||||
|
printf("},\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case 'a':
|
|
||||||
for (i = 0; 0 != (arr = toml_array_at(curarr, i)); i++) {
|
|
||||||
printf(" %d: \n", i);
|
|
||||||
print_array(arr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 't':
|
|
||||||
for (i = 0; 0 != (tab = toml_table_at(curarr, i)); i++) {
|
|
||||||
print_table(tab);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\0':
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void cat(FILE* fp)
|
static void cat(FILE* fp)
|
||||||
{
|
{
|
||||||
char errbuf[200];
|
char errbuf[200];
|
||||||
|
|
||||||
toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
toml_table_t* tab = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
||||||
if (!tab) {
|
if (!tab) {
|
||||||
fprintf(stderr, "ERROR: %s\n", errbuf);
|
fprintf(stderr, "ERROR: %s\n", errbuf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack[stacktop].tab = tab;
|
stack[stacktop].tab = tab;
|
||||||
stack[stacktop].key = "";
|
stack[stacktop].key = "";
|
||||||
stacktop++;
|
stacktop++;
|
||||||
|
printf("{\n");
|
||||||
|
indent++;
|
||||||
print_table(tab);
|
print_table(tab);
|
||||||
|
indent--;
|
||||||
|
printf("}\n");
|
||||||
stacktop--;
|
stacktop--;
|
||||||
|
|
||||||
toml_free(tab);
|
toml_free(tab);
|
||||||
|
@ -175,19 +278,19 @@ int main(int argc, const char* argv[])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
cat(stdin);
|
cat(stdin);
|
||||||
} else {
|
} else {
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
|
|
||||||
FILE* fp = fopen(argv[i], "r");
|
FILE* fp = fopen(argv[i], "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
fprintf(stderr, "ERROR: cannot open %s: %s\n",
|
fprintf(stderr, "ERROR: cannot open %s: %s\n",
|
||||||
argv[i], strerror(errno));
|
argv[i], strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
cat(fp);
|
cat(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue