project created

This commit is contained in:
Timerix 2025-11-09 23:47:51 +05:00
commit a5aff56fb1
20 changed files with 2909 additions and 0 deletions

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# build results
bin/
obj/
# IDE files
.vs/
.vshistory/
.editorconfig
*.user
*.vcxproj.filters
# other files
.old*/
old/
tmp/
temp/
*.tmp
*.temp
logs/
log/
*.log

1
.vscode/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
settings.json

15
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "all",
"defines": [],
"includePath": [
"include",
"../tlibc/include",
"${default}"
],
"cStandard": "c99"
}
],
"version": 4
}

29
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "gdb_debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/tlibtoml",
"windows": { "program": "${workspaceFolder}/bin/tlibtoml.exe" },
"preLaunchTask": "build_exec_dbg",
"stopAtEntry": false,
"cwd": "${workspaceFolder}/bin",
"externalConsole": false,
"internalConsoleOptions": "neverOpen",
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"setupCommands": [
{
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}

31
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,31 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build_exec_dbg",
"detail": "build project with debug symbols",
"type": "cppbuild",
"command": "bash",
"args": [
"-c",
"cbuild build_exec_dbg"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": ["$gcc"],
"group": {
"kind": "build"
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false,
"clear": true
}
}
]
}

21
README.md Normal file
View File

@ -0,0 +1,21 @@
# tlibtoml
A fork of [libtoml](https://github.com/brglng/libtoml) rewritten to use [tlibc](https://timerix.ddns.net/git/Timerix/tlibtoml) instead of its own (worse) implementation of collections and strings. For example, Table from libtoml is just an array of key-value pairs, where search happens by calling `strcmp()` on each element. Such inefficient code hurts my mind, so i have no other choise than to rewrite this library.
## Build
1. Clone the repository.
```
git clone https://timerix.ddns.net/git/Timerix/tlibtoml.git
```
2. Install [cbuild](https://timerix.ddns.net/git/Timerix/cbuild.git).
3. Clone [tlibc](https://timerix.ddns.net/git/Timerix/tlibtoml). By default
`dependencies/tlibc.config` expects that `tlibc/` is present in the same directory as `tlibtoml/`.
If you cloned it to another directory, change `DEPENDENCIES_DIR` in `tlibtoml/project.user.config`.
```
git clone https://timerix.ddns.net/git/Timerix/tlibc.git
```
4. Build and run tests
```
cd tlibtoml
cbuild build_exec exec
```
5. To build library use tasks `build_static_lib[_dbg]` or `build_shared_lib[_dbg]`

19
dependencies/tlibc.config vendored Normal file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
# This is a dependency config.
# You can copy it to another project to add tlibc dependency.
DEP_WORKING_DIR="$DEPENDENCIES_DIR/tlibc"
if [[ "$TASK" = *_dbg ]]; then
dep_build_target="build_static_lib_dbg"
else
dep_build_target="build_static_lib"
fi
DEP_PRE_BUILD_COMMAND="setup_user_config"
DEP_BUILD_COMMAND="cbuild $dep_build_target"
DEP_POST_BUILD_COMMAND=""
DEP_CLEAN_COMMAND="cbuild clean"
DEP_DYNAMIC_OUT_FILES=""
DEP_STATIC_OUT_FILES="bin/tlibc.a"
DEP_OTHER_OUT_FILES=""
PRESERVE_OUT_DIRECTORY_STRUCTURE=false

190
include/tlibtoml/toml.h Normal file
View File

@ -0,0 +1,190 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "tlibc/std.h"
#include <time.h>
#if defined(__cplusplus) && __cplusplus >= 201103L
#define ATTRIBUTE_THREAD_LOCAL thread_local
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define ATTRIBUTE_THREAD_LOCAL _Thread_local
#elif defined(_MSC_VER)
#define ATTRIBUTE_THREAD_LOCAL __declspec(thread)
#else
#define ATTRIBUTE_THREAD_LOCAL __thread
#endif
#define TOML_FALSE 0
#define TOML_TRUE 1
typedef enum {
TOML_OK,
TOML_ERR,
TOML_ERR_OS,
TOML_ERR_NOMEM,
TOML_ERR_SYNTAX,
TOML_ERR_UNICODE
} TomlErrCode;
typedef struct {
TomlErrCode code;
char* message;
int _is_literal;
} TomlErr;
typedef struct {
char* str;
size_t len;
size_t _capacity;
} TomlString;
typedef struct _TomlValue TomlValue;
typedef struct {
TomlValue** elements;
size_t len;
size_t _capacity;
} TomlArray;
typedef struct _TomlKeyValue TomlKeyValue;
typedef struct {
size_t _capacity;
size_t len;
TomlKeyValue* _keyvals;
} TomlTable;
typedef struct {
TomlTable* _table;
TomlKeyValue* _keyval;
} TomlTableIter;
typedef enum {
TOML_TABLE,
TOML_ARRAY,
TOML_STRING,
TOML_INTEGER,
TOML_FLOAT,
TOML_DATETIME,
TOML_BOOLEAN,
} TomlType;
struct _TomlValue {
TomlType type;
union {
TomlTable* table;
TomlArray* array;
TomlString* string;
#if defined(_MSC_VER) || defined(__APPLE__)
long long integer;
#else
long integer;
#endif
double float_;
struct tm datetime;
int boolean;
} value;
};
struct _TomlKeyValue {
TomlString* key;
TomlValue* value;
};
typedef struct {
void* (*malloc)(void *context, size_t size);
void* (*realloc)(void *context, void *p, size_t size);
void (*free)(void *context, void *p);
} TomlAllocFuncs;
void toml_set_allocator(void *context, const TomlAllocFuncs *funcs);
void* toml_malloc(size_t size);
void* toml_realloc(void *p, size_t size);
void toml_free(void *p);
char* toml_strdup(const char *str);
char* toml_strndup(const char *str, size_t n);
int toml_vasprintf(char **str, const char *format, va_list args);
int toml_asprintf(char **str, const char *format, ...);
const TomlErr* toml_err(void);
void toml_err_clear(void);
TomlString* toml_string_new(void);
TomlString* toml_string_from_str(const char *str);
TomlString* toml_string_from_nstr(const char *str, size_t len);
void toml_string_append_char(TomlString *self, char ch);
void toml_string_append_str(TomlString *self, const char *str);
void toml_string_append_nstr(TomlString *self, const char *str, size_t len);
TomlString* toml_string_clone(const TomlString *self);
void toml_string_free(TomlString *self);
int toml_string_equals(const TomlString *self, const TomlString *other);
TomlTable* toml_table_new(void);
void toml_table_free(TomlTable *self);
void toml_table_set_by_string(TomlTable *self, TomlString *key, TomlValue *value);
TomlValue *toml_table_get_by_string(const TomlTable *self, const TomlString *key);
void toml_table_set(TomlTable *self, const char *key, TomlValue *value);
void toml_table_setn(TomlTable *self, const char *key, size_t key_len, TomlValue *value);
TomlValue* toml_table_get(const TomlTable *self, const char *key);
TomlTable* toml_table_get_as_table(const TomlTable *self, const char *key);
TomlArray* toml_table_get_as_array(const TomlTable *self, const char *key);
TomlString* toml_table_get_as_string(const TomlTable *self, const char *key);
#if defined(_MSC_VER) || defined(__APPLE__)
long long toml_table_get_as_integer(const TomlTable *self, const char *key);
#else
long toml_table_get_as_integer(const TomlTable *self, const char *key);
#endif
double toml_table_get_as_float(const TomlTable *self, const char *key);
const struct tm* toml_table_get_as_datetime(const TomlTable *self, const char *key);
int toml_table_get_as_boolean(const TomlTable *self, const char *key);
TomlValue* toml_table_getn(const TomlTable *self, const char *key, size_t key_len);
TomlTableIter toml_table_iter_new(TomlTable *table);
TomlKeyValue* toml_table_iter_get(TomlTableIter *self);
int toml_table_iter_has_next(TomlTableIter *self);
void toml_table_iter_next(TomlTableIter *self);
TomlArray* toml_array_new(void);
void toml_array_free(TomlArray *self);
void toml_array_append(TomlArray *self, TomlValue *value);
TomlValue* toml_value_new(TomlType type);
TomlValue* toml_value_new_string(TomlType type);
TomlValue* toml_value_new_table(void);
TomlValue* toml_value_new_array(void);
#if defined(_MSC_VER) || defined(__APPLE__)
TomlValue *toml_value_new_integer(long long integer);
#else
TomlValue *toml_value_new_integer(long integer);
#endif
TomlValue* toml_value_new_float(double flt);
TomlValue* toml_value_new_datetime(void);
TomlValue* toml_value_new_boolean(int boolean);
TomlValue* toml_value_from_str(const char *str);
TomlValue* toml_value_from_nstr(const char *str, size_t len);
void toml_value_free(TomlValue *self);
TomlTable* toml_load_str(const char *str);
TomlTable* toml_load_nstr(const char *str, size_t len);
TomlTable* toml_load_file(FILE *file);
TomlTable* toml_load_filename(const char *filename);
/* TODO: implement dump functions
char *toml_dump_str(const TomlTable *self, TomlErr *err);
TomlString *toml_dump_nstr(const TomlTable *self, TomlErr *err);
void toml_dump_file(const TomlTable *self, FILE *file, TomlErr *err);
*/
#ifdef __cplusplus
}
#endif

208
project.config Normal file
View File

@ -0,0 +1,208 @@
#!/usr/bin/env bash
CBUILD_VERSION=2.3.0
PROJECT="tlibtoml"
CMP_C="gcc"
CMP_CPP="g++"
STD_C="c99"
STD_CPP="c++11"
WARN_C="-Wall -Wextra
-Wduplicated-branches
-Wduplicated-cond
-Wformat=2
-Wmissing-include-dirs
-Wshadow
-Werror=return-type
-Werror=pointer-arith
-Werror=init-self
-Werror=incompatible-pointer-types"
WARN_CPP="$WARN_C"
SRC_C="$(find src -name '*.c')"
SRC_CPP="$(find src -name '*.cpp')"
TESTS_C="$(find tests -name '*.c')"
TESTS_CPP="$(find tests -name '*.cpp')"
# Directory with dependency configs.
# See cbuild/example_dependency_configs
DEPENDENCY_CONFIGS_DIR='dependencies'
# List of dependency config files in DEPENDENCY_CONFIGS_DIR separated by space.
ENABLED_DEPENDENCIES='tlibc'
# OBJDIR structure:
# ├── objects/ - Compiled object files. Cleans on each call of build task
# ├── static_libs/ - Symbolic links to static libraries used by linker. Cleans on each call of build task.
# ├── static_libs/ - Symbolic links to dynamic libraries used by linker. Cleans on each call of build task.
# └── profile/ - gcc *.gcda profiling info files
OBJDIR="obj"
OUTDIR="bin"
STATIC_LIB_FILE="$PROJECT.a"
INCLUDE="-I./include -I../tlibc/include"
# OS-specific options
case "$OS" in
WINDOWS)
EXEC_FILE="test.exe"
SHARED_LIB_FILE="$PROJECT.dll"
INCLUDE="$INCLUDE "
# example: "-lSDL2 -lSDL2_image"
LINKER_LIBS=""
;;
LINUX)
EXEC_FILE="test"
SHARED_LIB_FILE="$PROJECT.so"
INCLUDE="$INCLUDE "
LINKER_LIBS=""
;;
*)
error "operating system $OS has no configuration variants"
;;
esac
# TASKS
case "$TASK" in
# creates executable using profiling info if it exists
build_exec)
SRC_C="$SRC_C $TESTS_C"
SRC_CPP="$SRC_CPP $TESTS_CPP"
# -flto applies more optimizations across object files
# -flto=auto is needed to multithreaded copilation
# -fuse-linker-plugin is required to use static libs with lto
# -fprofile-use enables compiler to use profiling info files to optimize executable
# -fprofile-prefix-path sets path where profiling info about objects are be saved
# -fdata-sections -ffunction-sections -Wl,--gc-sections removes unused code
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-use -fprofile-prefix-path=$(realpath $OBJDIR)/objects -fdata-sections -ffunction-sections -Wl,--gc-sections"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
POST_TASK_SCRIPT=""
;;
# creates executable with debug info and no optimizations
build_exec_dbg)
SRC_C="$SRC_C $TESTS_C"
SRC_CPP="$SRC_CPP $TESTS_CPP"
C_ARGS="-O0 -g3"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
POST_TASK_SCRIPT=""
;;
# creates shared library
build_shared_lib)
C_ARGS="-O2 -fpic -flto -shared"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
POST_TASK_SCRIPT=""
;;
# creates shared library with debug symbols and no optimizations
build_shared_lib_dbg)
C_ARGS="-O0 -g3 -fpic -shared"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
POST_TASK_SCRIPT=""
;;
# creates static library
build_static_lib)
C_ARGS="-O2 -fpic -fdata-sections -ffunction-sections"
CPP_ARGS="$C_ARGS"
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
POST_TASK_SCRIPT=""
;;
# creates static library with debug symbols and no optimizations
build_static_lib_dbg)
C_ARGS="-O0 -g3"
CPP_ARGS="$C_ARGS"
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
POST_TASK_SCRIPT=""
;;
# executes $EXEC_FILE
exec)
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
;;
# executes $EXEC_FILE with valgrind memory checker
valgrind)
VALGRIND_ARGS="-s --read-var-info=yes --track-origins=yes --fullpath-after=$(pwd)/ --leak-check=full --show-leak-kinds=all"
TASK_SCRIPT="@cbuild/default_tasks/valgrind.sh"
;;
# generates profiling info
profile)
OUTDIR="$OUTDIR/profile"
# -flto applies more optimizations across object files
# -flto=auto is needed to multithreaded copilation
# -fuse-linker-plugin is required to use static libs with lto
# -pg adds code to executable, that generates file containing function call info (gmon.out)
# -fprofile-generate generates executable with profiling code
# -fprofile-prefix-path sets path where profiling info about objects will be saved
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/profile.sh"
POST_TASK_SCRIPT=""
;;
# compiles program with -pg and runs it with gprof
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
# requires graphviz (https://www.graphviz.org/download/source/)
gprof)
OUTDIR="$OUTDIR/gprof"
# arguments that emit some call counter code and disable optimizations to see function names
# https://github.com/msys2/MINGW-packages/issues/8503#issuecomment-1365475205
C_ARGS="-O0 -g -pg -no-pie -fno-omit-frame-pointer
-fno-inline-functions -fno-inline-functions-called-once
-fno-optimize-sibling-calls -fopenmp"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/gprof.sh"
POST_TASK_SCRIPT=""
;;
# compiles program and runs it with callgrind (part of valgrind)
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
# requires graphviz (https://www.graphviz.org/download/source/)
# P.S. detailed results can be viewed in KCacheGrind
callgrind)
OUTDIR="$OUTDIR/callgrind"
# -pg adds code to executable, that generates file containing function call info (gmon.out)
C_ARGS="-O2 -flto=auto -fuse-linker-plugin"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/callgrind.sh"
POST_TASK_SCRIPT=""
;;
# compiles executable with sanitizers and executes it to find errors and warnings
sanitize)
OUTDIR="$OUTDIR/sanitize"
C_ARGS="-O0 -g3 -fsanitize=undefined,address"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
POST_TASK_SCRIPT=""
;;
# rebuilds specified dependencies
# EXAMPLE: `cbuild rebuild_dependencies=libexample1,fonts`
# 'all' can be specified to rebuild all dependencies
rebuild_dependencies)
TASK_SCRIPT="@cbuild/default_tasks/rebuild_dependencies.sh"
;;
# deletes generated files
clean)
TASK_SCRIPT="@cbuild/default_tasks/clean.sh"
;;
# nothing to do
"" | no_task)
;;
# unknown task
*)
error "task <$PROJECT/$TASK> not found"
;;
esac

View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Project user config is ignored by git.
# Here you can add variables that users might want to change
# on their local machine, without commiting to the repository.
# Directory where you install dependencies.
# Do not confuse with DEPENDENCY_CONFIGS_DIR
# Example:
# libexample source code is at `../libexample`, and dependency config
# that specifies how to build this lib is at `dependencies/libexample.config`
DEPENDENCIES_DIR=".."

1786
src/toml.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
[a]
aa = 1
[[a.b]]
bb = 2
[[a.b]]
cc = 3
[a.c]
dd = 4
[a.c.d]
ee = 5
[[a.c.d.e]]
ff = 6
[[a.c.d.e]]
gg = 7
[a.c.d.e.f]
hh = 8
[[b]]
ii = 9
[[b]]
jj = 10
[b.a]
kk = 11
[this.is-a."complex" . 'table' . name]
ok = true

47
tests/example.toml Normal file
View File

@ -0,0 +1,47 @@
# This is a TOML document. Boom.
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
organization = "GitHub"
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
# dob = 1979-05-27T07:32:00Z # First class dates? Why not?
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# You can indent as you please. Tabs or spaces. TOML don't care.
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
country = "中国" # This should be parsed as UTF-8
[clients]
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]
# Products
[[products]]
name = "Hammer"
sku = 738594937
[[products]]
name = "Nail"
sku = 284758393
color = "gray"

13
tests/fruit.toml Normal file
View File

@ -0,0 +1,13 @@
[[fruit.blah]]
name = "apple"
[fruit.blah.physical]
color = "red"
shape = "round"
[[fruit.blah]]
name = "banana"
[fruit.blah.physical]
color = "yellow"
shape = "bent"

33
tests/hard_example.toml Normal file
View File

@ -0,0 +1,33 @@
# Test file for TOML
# Only this one tries to emulate a TOML file written by a user of the kind of parser writers probably hate
# This part you'll really hate
[the]
test_string = "You'll hate me after this - #" # " Annoying, isn't it?
[the.hard]
test_array = [ "] ", " # "] # ] There you go, parse this!
test_array2 = [ "Test #11 ]proved that", "Experiment #9 was a success" ]
# You didn't think it'd as easy as chucking out the last #, did you?
another_test_string = " Same thing, but with a string #"
harder_test_string = " And when \"'s are in the string, along with # \"" # "and comments are there too"
# Things will get harder
[the.hard."bit#"]
"what?" = "You don't think some user won't do that?"
multi_line_array = [
"]",
# ] Oh yes I did
]
# Each of the following keygroups/key value pairs should produce an error. Uncomment to them to test
#[error] if you didn't catch this, your parser is broken
#string = "Anything other than tabs, spaces and newline after a keygroup or key value pair has ended should produce an error unless it is a comment" like this
#array = [
# "This might most likely happen in multiline arrays",
# Like here,
# "or here,
# and here"
# ] End of array comment, forgot the #
#number = 3.14 pi <--again forgot the #

View File

@ -0,0 +1,36 @@
# Tèƨƭ ƒïℓè ƒôř TÓM£
# Óñℓ¥ ƭλïƨ ôñè ƭřïèƨ ƭô è₥úℓáƭè á TÓM£ ƒïℓè ωřïƭƭèñ β¥ á úƨèř ôƒ ƭλè ƙïñδ ôƒ ƥářƨèř ωřïƭèřƨ ƥřôβáβℓ¥ λáƭè
# Tλïƨ ƥářƭ ¥ôú' řèáℓℓ¥ λáƭè
[the]
test_string = "Ýôú' λáƭè ₥è áƒƭèř ƭλïƨ - #" # " Âññô¥ïñϱ, ïƨñ'ƭ ïƭ?
[the.hard]
test_array = [ "] ", " # "] # ] Tλèřè ¥ôú ϱô, ƥářƨè ƭλïƨ!
test_array2 = [ "Tèƨƭ #11 ]ƥřôƲèδ ƭλáƭ", "Éжƥèřï₥èñƭ #9 ωáƨ á ƨúççèƨƨ" ]
# Ýôú δïδñ'ƭ ƭλïñƙ ïƭ'δ áƨ èáƨ¥ áƨ çλúçƙïñϱ ôúƭ ƭλè ℓáƨƭ #, δïδ ¥ôú?
another_test_string = "§á₥è ƭλïñϱ, βúƭ ωïƭλ á ƨƭřïñϱ #"
harder_test_string = " Âñδ ωλèñ \"'ƨ ářè ïñ ƭλè ƨƭřïñϱ, áℓôñϱ ωïƭλ # \"" # "áñδ çô₥₥èñƭƨ ářè ƭλèřè ƭôô"
# Tλïñϱƨ ωïℓℓ ϱèƭ λářδèř
[the.hard."βïƭ#"]
"ωλáƭ?" = "Ýôú δôñ'ƭ ƭλïñƙ ƨô₥è úƨèř ωôñ'ƭ δô ƭλáƭ?"
multi_line_array = [
"]",
# ] Óλ ¥èƨ Ì δïδ
]
# Each of the following keygroups/key value pairs should produce an error. Uncomment to them to test
#[error] ïƒ ¥ôú δïδñ'ƭ çáƭçλ ƭλïƨ, ¥ôúř ƥářƨèř ïƨ βřôƙèñ
#string = "Âñ¥ƭλïñϱ ôƭλèř ƭλáñ ƭáβƨ, ƨƥáçèƨ áñδ ñèωℓïñè áƒƭèř á ƙè¥ϱřôúƥ ôř ƙè¥ Ʋáℓúè ƥáïř λáƨ èñδèδ ƨλôúℓδ ƥřôδúçè áñ èřřôř úñℓèƨƨ ïƭ ïƨ á çô₥₥èñƭ" ℓïƙè ƭλïƨ
#array = [
# "Tλïƨ ₥ïϱλƭ ₥ôƨƭ ℓïƙèℓ¥ λáƥƥèñ ïñ ₥úℓƭïℓïñè ářřá¥ƨ",
# £ïƙè λèřè,
# "ôř λèřè,
# áñδ λèřè"
# ] Éñδ ôƒ ářřᥠçô₥₥èñƭ, ƒôřϱôƭ ƭλè #
#number = 3.14 ƥï <--áϱáïñ ƒôřϱôƭ ƭλè #

115
tests/key-values.toml Normal file
View File

@ -0,0 +1,115 @@
# All kinds of keys and string values
key1-bare-with-dash = "basic string 1"
key2-bare_with_underscore = 'literal string 2'
3-key-start-with-digit = "basic string \b 3 with \t space \f and\"escapes \\\u05d0\n"
"key 4 double quoted\n" = "basic string \rbasic string with carriage return"
'key 5 single quoted' = """multi line basic string"""
'key 6 multi-line basic string strip beginning new line' = """
There should be no new line, but two leading spaces."""
'key 7 line ending backslash' = """
lines with \
ending backslash \
should be concatenated into a single line and \
new lines and spaces after the line ending backslash should be stripped."""
'key 8 multi-line basic string with escapes' = """
Escapes \b
should\t
also \f
work \"
in \\
multi-line \nbasic string."""
'key 9 multi-line literal string' = '''
The first newline is
trimmed in raw strings.
All other whitespace or [(*&%$@!/\~`^#)]
is preserved.
'''
# Numbers, copied from README.md on https://github.com/toml-lang/toml
int1 = +99
int2 = 42
int3 = 0
int4 = -17
int5 = 1_000
int6 = 5_349_221
int7 = 1_2_3_4_5 # VALID but discouraged
# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef
# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions
oct3 = 0o0123_4567
oct4 = 0o7_5_5
# binary with prefix `0b`
bin1 = 0b11010110
bin2 = 0b1101_0110
# fractional
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01
# exponent
flt4 = 5e+22
flt5 = 1e6
flt6 = -2E-2
# both
flt7 = 6.626e-34
flt8 = 9_224_617.445_991_228_313
# 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
# Boolean
bool1 = true
bool2 = false
# Array
arr1 = [ 1, 2, 3 ]
arr2 = [ "red", "yellow", "green" ]
arr3 = [ [ 1, 2 ], [3, 4, 5] ]
arr4 = [ "all", 'strings', """are the same""", '''type''']
arr5 = [ [ 1, 2 ], ["a", "b", "c"] ]
#arr6 = [ 1, 2.0 ] # INVALID
arr7 = [
1, 2, 3
]
arr8 = [
1,
2, # this is ok
]
# Inline tables
name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ]

132
tests/long_config.toml Normal file
View File

@ -0,0 +1,132 @@
[voice-5band-compressor]
input = "voice_44k_16bit_1ch.wav"
output = "voice_44k_16bit_2ch_5band_compressor.wav"
sidechain = "WhiteNoiseChange_44.1k_16bit_1ch.wav"
block-size = 256
out-channels = 2
bandnum = 5
enabled = [true, true, true, true, true]
threshold = [-60.0, -10.0, -10.0, -10.0, -10.0]
ratio = [1.5, 1.5, 1.5, 1.5, 1.5]
attack-time = [30, 40, 50, 60, 70]
release-time = [100, 110, 120, 130, 140]
averaging-time = [30, 40, 50, 60, 70]
crossover_fc = [500.0, 1000.0, 4000.0, 10000.0]
saturation-threshold = [-1.0, -1.0, -1.0, -1.0, -1.0]
input-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
output-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
side_chain_enabled = [true, true, true, true, true]
[MultibandCompressor-SweepLevelChange-5Bands-LR-32k]
input = "SweepLevelChange_32k_LR_2ch.wav"
output = "MultibandCompressor_SweepLevelChange_5Bands_LR_32k.wav"
sidechain = "WhiteNoiseChange_44.1k_16bit_1ch.wav"
block-size = 256
out-channels = 2
bandnum = 5
enabled = [true, true, true, true, true]
threshold = [-60.0, -10.0, -10.0, -10.0, -10.0]
ratio = [1.5, 1.5, 1.5, 1.5, 1.5]
attack-time = [30, 40, 50, 60, 70]
release-time = [100, 110, 120, 130, 140]
averaging-time = [30, 40, 50, 60, 70]
crossover_fc = [500.0, 1000.0, 4000.0, 10000.0]
saturation-threshold = [-1.0, -1.0, -1.0, -1.0, -1.0]
input-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
output-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
side_chain_enabled = [true, true, true, true, true]
[MultibandCompressor-SweepLevelChange-5Bands-LR-44k]
input = "SweepLevelChange_44k_LR_2ch.wav"
output = "MultibandCompressor_SweepLevelChange_5Bands_LR_44k.wav"
sidechain = "WhiteNoiseChange_44.1k_16bit_1ch.wav"
block-size = 256
out-channels = 2
bandnum = 5
enabled = [true, true, true, true, true]
threshold = [-60.0, -10.0, -10.0, -10.0, -10.0]
ratio = [1.5, 1.5, 1.5, 1.5, 1.5]
attack-time = [30, 40, 50, 60, 70]
release-time = [100, 110, 120, 130, 140]
averaging-time = [30, 40, 50, 60, 70]
crossover_fc = [500.0, 1000.0, 4000.0, 10000.0]
saturation-threshold = [-1.0, -1.0, -1.0, -1.0, -1.0]
input-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
output-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
side_chain_enabled = [true, true, true, true, true]
[MultibandCompressor-SweepLevelChange-5Bands-LR-48k]
input = "SweepLevelChange_48k_LR_2ch.wav"
output = "MultibandCompressor_SweepLevelChange_5Bands_LR_48k.wav"
sidechain = "WhiteNoiseChange_44.1k_16bit_1ch.wav"
block-size = 256
out-channels = 2
bandnum = 5
enabled = [true, true, true, true, true]
threshold = [-60.0, -10.0, -10.0, -10.0, -10.0]
ratio = [1.5, 1.5, 1.5, 1.5, 1.5]
attack-time = [30, 40, 50, 60, 70]
release-time = [100, 110, 120, 130, 140]
averaging-time = [30, 40, 50, 60, 70]
crossover_fc = [500.0, 1000.0, 4000.0, 10000.0]
saturation-threshold = [-1.0, -1.0, -1.0, -1.0, -1.0]
input-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
output-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
side_chain_enabled = [true, true, true, true, true]
[MultibandCompressor-SweepLevelChange-5Bands-1BandBypass-LR-32k]
input = "SweepLevelChange_32k_LR_2ch.wav"
output = "MultibandCompressor_SweepLevelChange_5Bands_1BandBypass_LR_32k.wav"
sidechain = "WhiteNoiseChange_44.1k_16bit_1ch.wav"
block-size = 256
out-channels = 2
bandnum = 5
enabled = [true, true, true, false, true]
threshold = [-60.0, -10.0, -10.0, -10.0, -10.0]
ratio = [1.5, 1.5, 1.5, 1.5, 1.5]
attack-time = [30, 40, 50, 60, 70]
release-time = [100, 110, 120, 130, 140]
averaging-time = [30, 40, 50, 60, 70]
crossover_fc = [500.0, 1000.0, 4000.0, 10000.0]
saturation-threshold = [-1.0, -1.0, -1.0, -1.0, -1.0]
input-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
output-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
side_chain_enabled = [true, true, true, true, true]
[MultibandCompressor-SweepLevelChange-5Bands-1BandBypass-LR-44k]
input = "SweepLevelChange_44k_LR_2ch.wav"
output = "MultibandCompressor_SweepLevelChange_5Bands_1BandBypass_LR_44k.wav"
sidechain = "WhiteNoiseChange_44.1k_16bit_1ch.wav"
block-size = 256
out-channels = 2
bandnum = 5
enabled = [true, true, true, false, true]
threshold = [-60.0, -10.0, -10.0, -10.0, -10.0]
ratio = [1.5, 1.5, 1.5, 1.5, 1.5]
attack-time = [30, 40, 50, 60, 70]
release-time = [100, 110, 120, 130, 140]
averaging-time = [30, 40, 50, 60, 70]
crossover_fc = [500.0, 1000.0, 4000.0, 10000.0]
saturation-threshold = [-1.0, -1.0, -1.0, -1.0, -1.0]
input-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
output-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
side_chain_enabled = [true, true, true, true, true]
[MultibandCompressor-SweepLevelChange-5Bands-1BandBypass-LR-48k]
input = "SweepLevelChange_48k_LR_2ch.wav"
output = "MultibandCompressor_SweepLevelChange_5Bands_1BandBypass_LR_48k.wav"
sidechain = "WhiteNoiseChange_44.1k_16bit_1ch.wav"
block-size = 256
out-channels = 2
bandnum = 5
enabled = [true, true, true, false, true]
threshold = [-60.0, -10.0, -10.0, -10.0, -10.0]
ratio = [1.5, 1.5, 1.5, 1.5, 1.5]
attack-time = [30, 40, 50, 60, 70]
release-time = [100, 110, 120, 130, 140]
averaging-time = [30, 40, 50, 60, 70]
crossover_fc = [500.0, 1000.0, 4000.0, 10000.0]
saturation-threshold = [-1.0, -1.0, -1.0, -1.0, -1.0]
input-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
output-gain = [1.0, 1.0, 1.0, 1.0, 1.0]
side_chain_enabled = [true, true, true, true, true]

139
tests/main.c Normal file
View File

@ -0,0 +1,139 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <inttypes.h>
#include "tlibtoml/toml.h"
#ifndef PROJECT_SOURCE_DIR
#define PROJECT_SOURCE_DIR ".."
#endif
void print_table(const TomlTable *table);
void print_value(const TomlValue *value);
void print_array(const TomlArray *array)
{
printf("[");
for (size_t i = 0; i < array->len; i++) {
if (i > 0) {
printf(", ");
}
print_value(array->elements[i]);
}
printf("]");
}
void print_value(const TomlValue *value)
{
switch (value->type) {
case TOML_TABLE:
print_table(value->value.table);
break;
case TOML_ARRAY:
print_array(value->value.array);
break;
case TOML_STRING:
printf("\"%s\"", value->value.string->str);
break;
case TOML_INTEGER:
printf("%" PRId64, value->value.integer);
break;
case TOML_FLOAT:
printf("%f", value->value.float_);
break;
case TOML_DATETIME:
printf("(datetime)");
break;
case TOML_BOOLEAN:
printf("%s", value->value.boolean ? "true" : "false");
break;
}
}
void print_keyval(const TomlKeyValue *keyval)
{
printf("\"%s\": ", keyval->key->str);
print_value(keyval->value);
}
void print_table(const TomlTable *table)
{
TomlTableIter it = toml_table_iter_new((TomlTable *)table);
printf("{");
size_t i = 0;
while (toml_table_iter_has_next(&it)) {
TomlKeyValue *keyval = toml_table_iter_get(&it);
if (i > 0) {
printf(", ");
}
print_keyval(keyval);
toml_table_iter_next(&it);
i++;
}
printf("}");
}
int test_run(const char *filename)
{
TomlTable *table = NULL;
int rc = 0;
table = toml_load_filename(filename);
if (table == NULL)
goto cleanup;
print_table(table);
printf("\n");
cleanup:
toml_table_free(table);
if (toml_err()->code != TOML_OK) {
fprintf(stderr, "%s\n", toml_err()->message);
rc = (int)toml_err()->code;
}
toml_err_clear();
return rc;
}
int main(void)
{
static const char *const filenames[] = {
/* should parse */
PROJECT_SOURCE_DIR "/tests/key-values.toml",
PROJECT_SOURCE_DIR "/tests/complex-structure.toml",
PROJECT_SOURCE_DIR "/tests/long_config.toml",
/* should not parse */
/* tests from https://github.com/toml-lang/toml */
PROJECT_SOURCE_DIR "/tests/example.toml",
PROJECT_SOURCE_DIR "/tests/fruit.toml",
PROJECT_SOURCE_DIR "/tests/hard_example.toml",
PROJECT_SOURCE_DIR "/tests/hard_example_unicode.toml"
};
int total_tests = sizeof(filenames) / sizeof(char *);
int num_passed = 0;
int num_failed = 0;
for (int i = 0; i < total_tests; i++) {
int rc = test_run(filenames[i]);
if (rc == 0) {
printf("test %d success\n", i);
num_passed++;
} else {
printf("test %d returned %d\n", i, rc);
num_failed++;
}
}
printf("total %d tests, %d passed, %d failed\n",
total_tests, num_passed, num_failed);
return num_failed;
}

27
tlibtoml.config Normal file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
# This is a dependency config.
# You can copy it to another project to add tlibtoml dependency.
DEP_WORKING_DIR="$DEPENDENCIES_DIR/tlibtoml"
function setup_user_config(){
local user_config_path="project.config.user"
local absolute_dep_dir=$(realpath "$DEPENDENCIES_DIR")
file_copy_default_if_not_present "$user_config_path" "$user_config_path.default"
replace_var_value_in_script "$user_config_path" "DEPENDENCIES_DIR" "$absolute_dep_dir"
}
if [[ "$TASK" = *_dbg ]]; then
dep_build_target="build_static_lib_dbg"
else
dep_build_target="build_static_lib"
fi
DEP_PRE_BUILD_COMMAND="setup_user_config"
DEP_BUILD_COMMAND="cbuild $dep_build_target"
DEP_POST_BUILD_COMMAND=""
DEP_CLEAN_COMMAND="cbuild clean"
DEP_DYNAMIC_OUT_FILES=""
DEP_STATIC_OUT_FILES="bin/tlibtoml.a"
DEP_OTHER_OUT_FILES=""
PRESERVE_OUT_DIRECTORY_STRUCTURE=false