TOONc
A C library for parsing TOON (Token-Oriented Object Notation), a compact, human-readable encoding of the JSON data model optimized for LLM prompts.
Table of Contents
Introduction
TOON combines YAML’s indentation-based structure with CSV-style tabular layout for uniform arrays. It’s particularly efficient for representing structured data like:
- …
TOONc
A C library for parsing TOON (Token-Oriented Object Notation), a compact, human-readable encoding of the JSON data model optimized for LLM prompts.
Table of Contents
Introduction
TOON combines YAML’s indentation-based structure with CSV-style tabular layout for uniform arrays. It’s particularly efficient for representing structured data like:
- Configuration files
- Datasets with uniform records
- Nested hierarchical data
- LLM prompts with structured context
Installation
gcc -c toonc.c -o toonc.o
ar rcs libtoonc.a toonc.o
Include in your project:
#include "toonc.h"
Link with:
gcc your_program.c -L. -ltoonc -o your_program
Examples
The examples/ directory contains a comprehensive set of examples demonstrating various features of the library. You can compile and run all examples using the following command from the root directory of the project:
make run-examples
Here is a brief overview of the available examples:
- 01_basic_config.c: Shows how to parse a basic configuration file with nested objects and different value types.
- 02_array_processing.c: Demonstrates how to read and process simple arrays of strings and numbers.
- 03_tabular_data.c: Shows how to parse and query tabular data, where each row is an object.
- 04_programmatic_creation.c: Illustrates how to create a
toonObjecttree programmatically in memory. - 05_json_conversion.c: Shows how to convert a parsed TOON object into JSON format.
Data Structures
toonObject
The core data structure representing a TOON value:
typedef struct toonObject {
int kvtype; /* Type: KV_STRING, KV_INT, KV_BOOL, etc. */
int indent; /* Indentation level (0-based) */
char *key; /* Property name (NULL for array items) */
union {
struct toonStr str; /* String value */
int i; /* Integer value */
double d; /* Double value */
int boolean; /* Boolean value (0 or 1) */
struct { /* Array data */
struct toonObject **items;
size_t len;
size_t capacity;
} array;
};
struct toonObject *child; /* First child (for objects) */
struct toonObject *next; /* Next sibling */
} toonObject;
Value Types
KV_STRING- String valueKV_INT- Integer valueKV_DOUBLE- Floating-point valueKV_BOOL- Boolean value (true/false)KV_NULL- Null valueKV_OBJ- Object (nested structure)KV_LIST- Array/list
API Reference
Parsing
TOONc_parseFile
Parse a TOON file into a toonObject tree.
toonObject *TOONc_parseFile(FILE *fp);
Parameters:
fp- File pointer (will be closed by this function)
Returns:
- Root
toonObjectorNULLon error
Example:
FILE *fp = fopen("config.toon", "r");
if (!fp) {
perror("fopen");
return 1;
}
toonObject *root = TOONc_parseFile(fp);
if (!root) {
fprintf(stderr, "Failed to parse TOON file\n");
return 1;
}
/* Use the parsed object tree */
TOONc_printObject(root, 0);
/* Clean up */
TOONc_free(root);
Note: The file pointer is automatically closed by this function.
TOONc_parseString
Parse a TOON-formatted string into a toonObject tree.
toonObject *TOONc_parseString(const char *str);
Parameters:
str- TOON formatted string
Returns:
- Root
toonObjectorNULLon error
Example:
const char *toon_data =
"name: John Doe\n"
"age: 30\n"
"active: true\n";
toonObject *root = TOONc_parseString(toon_data);
if (!root) {
fprintf(stderr, "Failed to parse TOON string\n");
return 1;
}
/* Use the object */
toonObject *name = TOONc_get(root, "name");
printf("Name: %s\n", TOON_GET_STRING(name));
TOONc_free(root);
Memory Management
TOONc_malloc
Allocate memory with error handling.
void *TOONc_malloc(size_t size);
Parameters:
size- Number of bytes to allocate
Returns:
- Pointer to allocated memory (never returns NULL, exits on failure)
TOONc_calloc
Allocate and zero-initialize memory.
void *TOONc_calloc(size_t nmemb, size_t size);
Parameters:
nmemb- Number of elementssize- Size of each element
Returns:
- Pointer to allocated memory (never returns NULL, exits on failure)
TOONc_realloc
Reallocate memory block.
void *TOONc_realloc(void *ptr, size_t size);
Parameters:
ptr- Pointer to existing memory blocksize- New size in bytes
Returns:
- Pointer to reallocated memory (never returns NULL, exits on failure)
Object Creation
TOONc_newObject
Create a new TOON object of the specified type.
toonObject *TOONc_newObject(int kvtype);
Parameters:
kvtype- Type constant (KV_STRING, KV_INT, KV_OBJ, etc.)
Returns:
- New object with all fields zeroed
Example:
toonObject *obj = TOONc_newObject(KV_OBJ);
TOONc_newStringObj
Create a string object.
toonObject *TOONc_newStringObj(char *s, size_t len);
Parameters:
s- Pointer to string datalen- Length of string
Returns:
- New string object
Example:
toonObject *str = TOONc_newStringObj("Hello World", 11);
TOONc_newIntObj
Create an integer object.
toonObject *TOONc_newIntObj(int value);
Example:
toonObject *num = TOONc_newIntObj(42);
TOONc_newDoubleObj
Create a double-precision floating-point object.
toonObject *TOONc_newDoubleObj(double value);
Example:
toonObject *pi = TOONc_newDoubleObj(3.14159);
TOONc_newBoolObj
Create a boolean object.
toonObject *TOONc_newBoolObj(int value);
Example:
toonObject *flag = TOONc_newBoolObj(1); /* true */
TOONc_newNullObj
Create a null object.
toonObject *TOONc_newNullObj(void);
Example:
toonObject *null_val = TOONc_newNullObj();
TOONc_newListObj
Create an empty array/list object.
toonObject *TOONc_newListObj(void);
Example:
toonObject *arr = TOONc_newListObj();
TOONc_listPush(arr, TOONc_newIntObj(1));
TOONc_listPush(arr, TOONc_newIntObj(2));
TOONc_listPush(arr, TOONc_newIntObj(3));
TOONc_listPush
Add an item to an array.
void TOONc_listPush(toonObject *list, toonObject *item);
Parameters:
list- Array object (must beKV_LIST)item- Object to add
Example:
toonObject *numbers = TOONc_newListObj();
for (int i = 0; i < 10; i++) {
TOONc_listPush(numbers, TOONc_newIntObj(i));
}
Querying
TOONc_get
Get an object by path using dot notation.
toonObject *TOONc_get(toonObject *root, const char *path);
Parameters:
root- Root object to search frompath- Dot-separated path (e.g., "context.task")
Returns:
- Found object or
NULLif path doesn’t exist
Example:
/* Given TOON:
context:
task: Build a web server
priority: high
*/
toonObject *task = TOONc_get(root, "context.task");
if (task) {
printf("Task: %s\n", TOON_GET_STRING(task));
}
toonObject *priority = TOONc_get(root, "context.priority");
if (priority) {
printf("Priority: %s\n", TOON_GET_STRING(priority));
}
TOONc_getArrayItem
Access a specific element of an array by index.
toonObject *TOONc_getArrayItem(toonObject *arr, size_t index);
Parameters:
arr- Array objectindex- Zero-based index
Returns:
- Object at the specified index or
NULLif out of bounds
Example:
/* Given TOON:
friends[3]: alice,bob,charlie
*/
toonObject *friends = TOONc_get(root, "friends");
if (TOON_IS_LIST(friends)) {
toonObject *first = TOONc_getArrayItem(friends, 0);
printf("First friend: %s\n", TOON_GET_STRING(first));
toonObject *second = TOONc_getArrayItem(friends, 1);
printf("Second friend: %s\n", TOON_GET_STRING(second));
}
TOONc_getArrayLength
Get the number of elements in an array.
size_t TOONc_getArrayLength(toonObject *arr);
Parameters:
arr- Array object
Returns:
- Number of elements or 0 if not an array
Example:
toonObject *friends = TOONc_get(root, "friends");
if (TOON_IS_LIST(friends)) {
size_t count = TOONc_getArrayLength(friends);
printf("You have %zu friends\n", count);
for (size_t i = 0; i < count; i++) {
toonObject *friend = TOONc_getArrayItem(friends, i);
printf(" %zu: %s\n", i + 1, TOON_GET_STRING(friend));
}
}
TOONc_free
Recursively free a TOON object tree and all its children.
void TOONc_free(toonObject *obj);
Parameters:
obj- Object to free
Example:
toonObject *root = TOONc_parseFile(fp);
/* Use the object tree... */
/* Clean up everything */
TOONc_free(root);
Important: Always call TOONc_free() on the root object when done to prevent memory leaks.
Output & Debugging
TOONc_printObject
Recursively print a TOON object tree for debugging.
void TOONc_printObject(toonObject *o, int depth);
Parameters:
o- Object to printdepth- Initial indentation depth (usually 0)
Example:
toonObject *root = TOONc_parseFile(fp);
TOONc_printObject(root, 0);
Output:
context: { (object)
task: "Build a web server" (string)
priority: "high" (string)
}
friends: ["alice", "bob", "charlie"] (array)
TOONc_printRoot
Print from the root (skip the root object itself).
void TOONc_printRoot(toonObject *root);
Example:
TOONc_printRoot(root);
TOONc_toJSON
Convert a TOON object to JSON format.
void TOONc_toJSON(toonObject *obj, FILE *fp, int depth);
Parameters:
obj- Object to convertfp- Output file pointer (e.g.,stdout)depth- Initial indentation depth (usually 0)
Example:
toonObject *root = TOONc_parseFile(fp);
printf("JSON output:\n");
TOONc_toJSON(root, stdout, 0);
printf("\n");
/* Or write to file */
FILE *out = fopen("output.json", "w");
TOONc_toJSON(root, out, 0);
fclose(out);
Type Checking
Macros for checking object types:
TOON_IS_STRING(obj) /* Returns true if object is a string */
TOON_IS_INT(obj) /* Returns true if object is an integer */
TOON_IS_DOUBLE(obj) /* Returns true if object is a double */
TOON_IS_BOOL(obj) /* Returns true if object is a boolean */
TOON_IS_NULL(obj) /* Returns true if object is null */
TOON_IS_LIST(obj) /* Returns true if object is an array */
TOON_IS_OBJ(obj) /* Returns true if object is an object */
Example:
toonObject *value = TOONc_get(root, "age");
if (TOON_IS_INT(value)) {
printf("Age is an integer: %d\n", TOON_GET_INT(value));
} else if (TOON_IS_STRING(value)) {
printf("Age is a string: %s\n", TOON_GET_STRING(value));
}
Value Getters
Safe macros for extracting values:
TOON_GET_STRING(obj) /* Returns string pointer or NULL */
TOON_GET_INT(obj) /* Returns int value or 0 */
TOON_GET_DOUBLE(obj) /* Returns double value or 0.0 */
TOON_GET_BOOL(obj) /* Returns boolean value (0 or 1) */
Example:
toonObject *name = TOONc_get(root, "name");
const char *name_str = TOON_GET_STRING(name);
if (name_str) {
printf("Name: %s\n", name_str);
}
toonObject *age = TOONc_get(root, "age");
int age_val = TOON_GET_INT(age);
printf("Age: %d\n", age_val);
TOON Format
Basic Syntax
# Comments start with #
key: value
number: 42
floating: 3.14
boolean: true
null_value: null
quoted: "string with spaces"
Nested Objects
parent:
child1: value1
child2: value2
nested:
deep: value
Simple Arrays
numbers[3]: 1,2,3
names[4]: alice,bob,charlie,diana
mixed[2]: 42,hello
Tabular Data
users[3]{id,name,email,age}:
1,Alice,alice@example.com,25
2,Bob,bob@example.com,30
3,Charlie,charlie@example.com,28
Complete Example
# Application Configuration
app:
name: MyApp
version: 2.1.0
debug: false
database:
host: localhost
port: 5432
credentials:
username: admin
password: secret
servers[2]: web01.example.com,web02.example.com
users[3]{id,username,email,active}:
1,alice,alice@example.com,true
2,bob,bob@example.com,false
3,charlie,charlie@example.com,true
License
MIT License. See source files for details.
Author
Davide Usberti usbertibox@gmail.com