Merge commit 'e8bd3328273ed3df505b9cd7175710319c21b8a8' as 'tomlc99'

master
Daniel Ziltener 9 months ago
commit f4d951fac5

@ -0,0 +1,14 @@
root = true
[*]
end_of_line = lf
insert_final_newline = false
trim_trailing_whitespace = true
[*.{c,h}]
indent_style = space
indent_size = 2
[Makefile]
indent_style = tab
indent_size = 4

38
tomlc99/.gitignore vendored

@ -0,0 +1,38 @@
*~
# Object files
*.o
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
toml_cat
toml_json
toml_sample
# Debug files
*.dSYM/
*.su

@ -0,0 +1,22 @@
MIT License
Copyright (c) CK Tan
https://github.com/cktan/tomlc99
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,50 @@
prefix ?= /usr/local
HFILES = toml.h
CFILES = toml.c
OBJ = $(CFILES:.c=.o)
EXEC = toml_json toml_cat toml_sample
PCFILE = libtoml.pc
CFLAGS = -std=c99 -Wall -Wextra -fpic
LIB_VERSION = 1.0
LIB = libtoml.a
LIB_SHARED = libtoml.so.$(LIB_VERSION)
# to compile for debug: make DEBUG=1
# to compile for no debug: make
ifdef DEBUG
CFLAGS += -O0 -g
else
CFLAGS += -O2 -DNDEBUG
endif
all: $(LIB) $(LIB_SHARED) $(EXEC)
*.o: $(HFILES)
libtoml.a: toml.o
ar -rcs $@ $^
libtoml.so.$(LIB_VERSION): toml.o
$(CC) -shared -o $@ $^
$(EXEC): $(LIB)
install: all
install -d ${prefix}/include ${prefix}/lib
install toml.h ${prefix}/include
install $(LIB) ${prefix}/lib
install $(LIB_SHARED) ${prefix}/lib
ifeq "$(prefix)" "/usr/local"
install $(PCFILE) /usr/local/lib/pkgconfig
endif
clean:
rm -f *.o $(EXEC) $(LIB) $(LIB_SHARED)
format:
clang-format -i $(shell find . -name '*.[ch]')
.PHONY: all clean install format

@ -0,0 +1,194 @@
# tomlc99
TOML in c99; v1.0 compliant.
If you are looking for a C++ library, you might try this wrapper: [https://github.com/cktan/tomlcpp](https://github.com/cktan/tomlcpp).
* Compatible with [TOML v1.0.0](https://toml.io/en/v1.0.0).
* Tested with multiple test suites, including
[BurntSushi/toml-test](https://github.com/BurntSushi/toml-test) and
[iarna/toml-spec-tests](https://github.com/iarna/toml-spec-tests).
* Provides very simple and intuitive interface.
## Usage
Please see the `toml.h` file for details. The following is a simple example that
parses this config file:
```toml
[server]
host = "www.example.com"
port = [ 8080, 8181, 8282 ]
```
These are the usual steps for getting values from a file:
1. Parse the TOML file.
2. Traverse and locate a table in TOML.
3. Extract values from the table.
4. Free up allocated memory.
Below is an example of parsing the values from the example table.
```c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include "toml.h"
static void error(const char* msg, const char* msg1)
{
fprintf(stderr, "ERROR: %s%s\n", msg, msg1?msg1:"");
exit(1);
}
int main()
{
FILE* fp;
char errbuf[200];
// 1. Read and parse toml file
fp = fopen("sample.toml", "r");
if (!fp) {
error("cannot open sample.toml - ", strerror(errno));
}
toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf));
fclose(fp);
if (!conf) {
error("cannot parse - ", errbuf);
}
// 2. Traverse to a table.
toml_table_t* server = toml_table_in(conf, "server");
if (!server) {
error("missing [server]", "");
}
// 3. Extract values
toml_datum_t host = toml_string_in(server, "host");
if (!host.ok) {
error("cannot read server.host", "");
}
toml_array_t* portarray = toml_array_in(server, "port");
if (!portarray) {
error("cannot read server.port", "");
}
printf("host: %s\n", host.u.s);
printf("port: ");
for (int i = 0; ; i++) {
toml_datum_t port = toml_int_at(portarray, i);
if (!port.ok) break;
printf("%d ", (int)port.u.i);
}
printf("\n");
// 4. Free memory
free(host.u.s);
toml_free(conf);
return 0;
}
```
#### Accessing Table Content
TOML tables are dictionaries where lookups are done using string keys. In
general, all access functions on tables are named `toml_*_in(...)`.
In the normal case, you know the key and its content type, and retrievals can be done
using one of these functions:
```c
toml_string_in(tab, key);
toml_bool_in(tab, key);
toml_int_in(tab, key);
toml_double_in(tab, key);
toml_timestamp_in(tab, key);
toml_table_in(tab, key);
toml_array_in(tab, key);
```
You can also interrogate the keys in a table using an integer index:
```c
toml_table_t* tab = toml_parse_file(...);
for (int i = 0; ; i++) {
const char* key = toml_key_in(tab, i);
if (!key) break;
printf("key %d: %s\n", i, key);
}
```
#### Accessing Array Content
TOML arrays can be deref-ed using integer indices. In general, all access methods on arrays are named `toml_*_at()`.
To obtain the size of an array:
```c
int size = toml_array_nelem(arr);
```
To obtain the content of an array, use a valid index and call one of these functions:
```c
toml_string_at(arr, idx);
toml_bool_at(arr, idx);
toml_int_at(arr, idx);
toml_double_at(arr, idx);
toml_timestamp_at(arr, idx);
toml_table_at(arr, idx);
toml_array_at(arr, idx);
```
#### toml_datum_t
Some `toml_*_at` and `toml_*_in` functions return a toml_datum_t
structure. The `ok` flag in the structure indicates if the function
call was successful. If so, you may proceed to read the value
corresponding to the type of the content.
For example:
```
toml_datum_t host = toml_string_in(tab, "host");
if (host.ok) {
printf("host: %s\n", host.u.s);
free(host.u.s); /* FREE applies to string and timestamp types only */
}
```
** IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. **
## Building and installing
A normal *make* suffices. You can also simply include the
`toml.c` and `toml.h` files in your project.
Invoking `make install` will install the header and library files into
/usr/local/{include,lib}.
Alternatively, specify `make install prefix=/a/file/path` to install into
/a/file/path/{include,lib}.
## Testing
To test against the standard test set provided by BurntSushi/toml-test:
```sh
% make
% cd test1
% bash build.sh # do this once
% bash run.sh # this will run the test suite
```
To test against the standard test set provided by iarna/toml:
```sh
% make
% cd test2
% bash build.sh # do this once
% bash run.sh # this will run the test suite
```

@ -0,0 +1,11 @@
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: libtoml
URL: https://github.com/cktan/tomlc99/
Description: TOML C library in c99.
Version: v1.0
Libs: -L${libdir} -ltoml
Cflags: -I${includedir}

@ -0,0 +1,3 @@
[server]
host = "example.com"
port = [ 8080, 8181, 8282 ]

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

@ -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

@ -0,0 +1,13 @@
integers = [ 1, 2, 3 ]
colors = [ "red", "yellow", "green" ]
nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ]
nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
string_array = [ "all", 'strings', """are the same""", '''type''' ]
# Mixed-type arrays are allowed
numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
contributors = [
"Foo Bar <foo@example.com>",
{ name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
]

@ -0,0 +1,56 @@
{
integers = [
1,
2,
3,
],
colors = [
"red",
"yellow",
"green",
],
nested_arrays_of_ints = [
[
1,
2,
],
[
3,
4,
5,
],
],
nested_mixed_array = [
[
1,
2,
],
[
"a",
"b",
"c",
],
],
string_array = [
"all",
"strings",
"are the same",
"type",
],
numbers = [
0.100000,
0.200000,
0.500000,
1,
2,
5,
],
contributors = [
"Foo Bar <foo@example.com>",
{
name = "Baz Qux",
email = "bazqux@example.com",
url = "https://example.com/bazqux",
},
],
}

@ -0,0 +1,8 @@
integers2 = [
1, 2, 3
]
integers3 = [
1,
2, # this is ok
]

@ -0,0 +1,11 @@
{
integers2 = [
1,
2,
3,
],
integers3 = [
1,
2,
],
}

@ -0,0 +1,11 @@
[[products]]
name = "Hammer"
sku = 738594937
[[products]] # empty table within the array
[[products]]
name = "Nail"
sku = 284758393
color = "gray"

@ -0,0 +1,15 @@
{
products = [
{
name = "Hammer",
sku = 738594937,
},
{
},
{
name = "Nail",
sku = 284758393,
color = "gray",
},
],
}

@ -0,0 +1,19 @@
[[fruits]]
name = "apple"
[fruits.physical] # subtable
color = "red"
shape = "round"
[[fruits.varieties]] # nested array of tables
name = "red delicious"
[[fruits.varieties]]
name = "granny smith"
[[fruits]]
name = "banana"
[[fruits.varieties]]
name = "plantain"

@ -0,0 +1,27 @@
{
fruits = [
{
name = "apple",
varieties = [
{
name = "red delicious",
},
{
name = "granny smith",
},
],
physical = {
color = "red",
shape = "round",
},
},
{
name = "banana",
varieties = [
{
name = "plantain",
},
],
},
],
}

@ -0,0 +1,8 @@
# INVALID TOML DOC
[fruit.physical] # subtable, but to which parent element should it belong?
color = "red"
shape = "round"
[[fruit]] # parser must throw an error upon discovering that "fruit" is
# an array rather than a table
name = "apple"

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

@ -0,0 +1,4 @@
# INVALID TOML DOC
fruits = []
[[fruits]] # Not allowed

@ -0,0 +1 @@
ERROR: line 4: array mismatch

@ -0,0 +1,11 @@
# INVALID TOML DOC
[[fruits]]
name = "apple"
[[fruits.varieties]]
name = "red delicious"
# INVALID: This table conflicts with the previous array of tables
[fruits.varieties]
name = "granny smith"

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

@ -0,0 +1,14 @@
# INVALID TOML DOC
[[fruits]]
name = "apple"
[[fruits.varieties]]
name = "red delicious"
[fruits.physical]
color = "red"
shape = "round"
# INVALID: This array of tables conflicts with the previous table
[[fruits.physical]]
color = "green"

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

@ -0,0 +1,3 @@
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ]

@ -0,0 +1,19 @@
{
points = [
{
x = 1,
y = 2,
z = 3,
},
{
x = 7,
y = 8,
z = 9,
},
{
x = 2,
y = 4,
z = 8,
},
],
}

@ -0,0 +1,3 @@
bool1 = true
bool2 = false

@ -0,0 +1,4 @@
{
bool1 = true,
bool2 = false,
}

@ -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"

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

@ -0,0 +1,13 @@
# fractional
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01
# exponent
flt4 = 5e+22
flt5 = 1e06
flt6 = -2E-2
# both
flt7 = 6.626e-34

@ -0,0 +1,9 @@
{
flt1 = 1.000000,
flt2 = 3.141500,
flt3 = -0.010000,
flt4 = 49999999999999995805696.000000,
flt5 = 1000000.000000,
flt6 = -0.020000,
flt7 = 0.000000,
}

@ -0,0 +1 @@
invalid_float_1 = .7

@ -0,0 +1,2 @@
{
ERROR: unable to decode value in table

@ -0,0 +1,2 @@
invalid_float_2 = 7.

@ -0,0 +1,2 @@
{
ERROR: unable to decode value in table

@ -0,0 +1 @@
invalid_float_3 = 3.e+20

@ -0,0 +1,2 @@
{
ERROR: unable to decode value in table

@ -0,0 +1 @@
flt8 = 224_617.445_991_228

@ -0,0 +1,3 @@
{
flt8 = 224617.445991,
}

@ -0,0 +1,10 @@
# infinity
sf1 = inf # positive infinity
sf2 = +inf # positive infinity
sf3 = -inf # negative infinity
# not a number
sf4 = nan # actual sNaN/qNaN encoding is implementation-specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation-specific

@ -0,0 +1,8 @@
{
sf1 = inf,
sf2 = inf,
sf3 = -inf,
sf4 = nan,
sf5 = nan,
sf6 = nan,
}

@ -0,0 +1,3 @@
name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" }

@ -0,0 +1,15 @@
{
name = {
first = "Tom",
last = "Preston-Werner",
},
point = {
x = 1,
y = 2,
},
animal = {
type = {
name = "pug",
},
},
}

@ -0,0 +1,3 @@
[product]
type = { name = "Nail" }
type.edible = false # INVALID

@ -0,0 +1 @@
ERROR: line 3: cannot insert new entry into existing table

@ -0,0 +1,3 @@
[product]
type.name = "Nail"
type = { edible = false } # INVALID

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

@ -0,0 +1,9 @@
int1 = +99
int2 = 42
int3 = 0
int4 = -17
int5 = 1_000
int6 = 5_349_221
int7 = 53_49_221 # Indian number system grouping
int8 = 1_2_3_4_5 # VALID but discouraged

@ -0,0 +1,10 @@
{
int1 = 99,
int2 = 42,
int3 = 0,
int4 = -17,
int5 = 1000,
int6 = 5349221,
int7 = 5349221,
int8 = 12345,
}

@ -0,0 +1,12 @@
# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef
# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions
# binary with prefix `0b`
bin1 = 0b11010110

@ -0,0 +1,8 @@
{
hex1 = 3735928559,
hex2 = 3735928559,
hex3 = 3735928559,
oct1 = 342391,
oct2 = 493,
bin1 = 214,
}

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

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

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

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

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

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

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

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

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

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

@ -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

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

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

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

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

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

@ -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

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

@ -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

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

@ -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"

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

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

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

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

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

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

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

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

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

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

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

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

@ -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"

@ -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",
}

@ -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.\
"""

@ -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.",
}

@ -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.""""

@ -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.\"",
}

@ -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*>'

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

@ -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.
'''

@ -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",
}

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

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

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

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save