cfgsafe is a fast, lightweight C library and code generator that translates a programmer‑defined schema into a strongly-typed C struct, complete with a zero-allocation INI parser and rigorous validation constraints.
You define the shape of your configuration in a specialized .schema file. cfgsafe handles parsing, defaults, environment variable overrides, constraint checking (regex, lengths, ranges), and memory cleanup. It generates a single-file header library (STB-style) you drop directly into any C or C++ project.
Stop writing boilerplate string-to-int parsing code. Stop silently ignoring invalid config values. Stop crashing on null pointers from unvalidated environment variables.
- Zero Dependencies: Pure C99 implementation. No external regex engines or complex build steps required.
- Type Safety: Forget
void*dictionaries. Your schema is compiled directly into standard Cstructs, allowing you to access configuration fields naturally (e.g.,cfg.listen_port,cfg.database.host) with the correct native C types (int64_t,double,bool, arrays, andenums) automatically inferred. - Deep Validation: First-class support for numeric
ranges, stringmin_length/max_length, regexpatternmatching, and fileexistschecks. - Conditional Logic: Complex cross-field validation out of the box (e.g.,
required_if: enable_tls == true). - Single-Header Output: Generates one
.hfile containing both the data structures and the implementation logic. - Environment Variables: Native 12-factor app support. Seamlessly override file configuration keys with environment variables.
Define your configuration structure, validation rules, and defaults in a clean, readable syntax:
schema DatabaseConfig {
driver: enum(postgres, mysql, sqlite) {
default: postgres
}
host: string {
default: "localhost"
env: "DB_HOST"
}
port: int {
default: 5432
range: 1..65535
}
}
schema ApiGateway {
service_name: string {
min_length: 3
pattern: "^[a-z0-9-]+$"
default: "edge-gateway"
}
bind_address: ipv4 {
default: "0.0.0.0"
env: "BIND_ADDR"
}
enable_tls: bool {
default: false
}
cert_path: path {
required_if: enable_tls == true
exists: true
}
// Embed the Database schema from above
database: DatabaseConfig {}
// Group fields natively
section caching {
enabled: bool { default: false }
// Array types
nodes: string[] {
min_length: 1
required_if: enabled == true
}
// Deeply nested section
section redis {
pool_size: int { default: 10 }
}
}
}The runtime parser consumes standard INI file syntax mapping logically to the structures you defined. For nested sections or embedded schemas, cfgsafe uses dot-notation [parent.child] for headers.
service_name = edge-gateway
bind_address = 127.0.0.1
enable_tls = false
[database]
driver = postgres
host = db.local
port = 5432
[caching]
enabled = true
nodes = cache-1.local,cache-2.local
[caching.redis]
pool_size = 20Compile your schema into a C header file using the cfgsafe generator:
cfg-gen config.schema
# Outputs -> config.hInclude the generated header. Define CONFIG_IMPLEMENTATION in exactly one C file to compile the implementation logic. Load an INI file (e.g. config.ini).
#define CONFIG_IMPLEMENTATION
#include "config.h"
#include <stdio.h>
int main(void) {
ApiGateway_t cfg;
cfg_error_t err;
printf("--- Loading Configuration ---\n");
// Load from INI file, apply env overrides, and run all validations
cfg_status_t status = ApiGateway_load(&cfg, "config.ini", &err);
if (status == CFG_SUCCESS) {
printf("Service Name: %s\n", cfg.service_name);
printf("Database Host: %s\n", cfg.database.host);
printf("Database Port: %d\n", (int)cfg.database.port);
// Free dynamically allocated memory (strings, arrays)
ApiGateway_free(&cfg);
} else {
// Detailed error reporting tells you exactly what failed
fprintf(stderr, "Config Status: FAILURE (code %d)\n", (int)status);
fprintf(stderr, "Error: %s\n", err.message);
fprintf(stderr, "Field: %s\n", err.field);
if (err.line > 0) fprintf(stderr, "Line: %zu\n", err.line);
return 1;
}
return 0;
}To see a fully working example including error recovery, environment override testing, and complex data models, check out the examples/ directory in our repository:
examples/config.schema: The comprehensive test schemaexamples/config.ini: The mock configuration dataexamples/test_loader.c: An implementation demonstrating safe extraction
Comprehensive documentation has been split into detailed guides. Please refer to them for advanced usage:
- Schema Definition Guide - Learn how to define schemas, built-in types, nesting, and validation rules.
- C API Reference - Learn about memory management, error handling structure, and C integration.
The code generator (cfg-gen) runs locally to read your schema and emit the C header.
git clone https://github.com/your-username/cfgsafe.git
cd cfgsafe/tools
makeEnsure the output binary is in your system PATH. Use the executable to generate headers alongside your standard build process (e.g. inside your Makefile or CMakeLists.txt).
Contributions are always welcome. Please submit pull requests or open issues for bugs, feature requests, or documentation improvements.