Configuration files are the backbone of modern software development. Whether you're deploying a web server, configuring a database, or setting up environment-specific variables, you need a way to store and manage settings that's both human-readable and programmatically accessible. Enter ConfigLang—a pure C99 embedded configuration language that brings simplicity and type safety to your configuration workflow.
Why Another Configuration Language?
The configuration landscape is crowded with options like JSON, YAML, TOML, and INI files. So why ConfigLang? The answer lies in its unique combination of features: it's written in pure C99 with zero external dependencies, offers a clean C API for easy integration, and includes programming constructs like conditionals and immutable variables that traditional configuration formats lack.
ConfigLang occupies a sweet spot between static configuration files and full programming languages. It gives you just enough logic to handle environment-specific settings without the complexity of a scripting language.
Core Features at a Glance
ConfigLang's syntax is refreshingly simple. Variables are declared with the set keyword, and you can make them immutable using const set. The language supports two fundamental types: integers and strings.
set port = 8080
set host = "localhost"
const set max_connections = 100
What sets ConfigLang apart is its support for conditional logic. You can apply different configurations based on runtime conditions using if statements with standard comparison operators.
Important syntax rules:
- Variables must be defined before they are referenced in conditional expressions
- If blocks allow only one
setstatement - The closing brace
}must appear on the same line as the statement
set debug = 0
set log_level = "info"
if debug == 0 { set log_level = "error" }
if debug == 1 { set log_level = "debug" }
This feature makes ConfigLang powerful for managing development, staging, and production environments within a single configuration file.
Supported Comparison Operators
ConfigLang supports the following comparison operators in if statements:
-
==- Equal to -
!=- Not equal to -
>- Greater than -
<- Less than -
>=- Greater than or equal to -
<=- Less than or equal to
All comparisons work with both integers and strings (string comparison is lexicographic).
Syntax Rules and Constraints
ConfigLang enforces several key syntax rules:
Variable Declaration Order
Variables must be declared with set before they can be used in conditional expressions.
# Correct - variable defined first
set mode = "prod"
if mode == "prod" { set port = 80 }
# Incorrect - would cause an error
if mode == "prod" { set port = 80 }
set mode = "prod"
Single Statement Per If Block
Each if block can contain exactly one set statement. This keeps conditional logic simple and prevents complex nested logic.
# Correct
if debug == 1 { set verbose = 1 }
# Incorrect - multiple statements not allowed
if debug == 1 {
set verbose = 1
set trace = 1
}
Inline Closing Braces
The closing brace } must appear on the same line as the set statement within the if block.
# Correct
if production == 0 { set ssl = 0 }
# Incorrect - brace on separate line
if production == 0 { set ssl = 0
}
Chained Conditionals
You can chain multiple if statements without else clauses:
set environment = "production"
set timeout = 30
if environment == "development" { set timeout = 300 }
if environment == "staging" { set timeout = 100 }
if environment == "production" { set timeout = 30 }
Type Safety and Immutability
ConfigLang enforces type safety at runtime. Attempting to retrieve an integer variable as a string—or vice versa—results in a clear type mismatch error. The const keyword prevents accidental modification of critical configuration values, catching bugs before they reach production.
Error codes:
-
ERR_CFG_OK(0) - Success -
ERR_CFG_PARSE_ERROR(1) - Syntax error during parsing -
ERR_CFG_FILE_ERROR(2) - File I/O error -
ERR_CFG_VARIABLE_NOT_FOUND(3) - Variable doesn't exist -
ERR_CFG_CONST_VIOLATION(4) - Attempted to modify const variable -
ERR_CFG_TYPE_MISMATCH(5) - Type mismatch (int vs string) -
ERR_CFG_NULL_POINTER(6) - NULL pointer passed to API -
ERR_CFG_OUT_OF_MEMORY(7) - Memory allocation failed
C API Reference
The C API is straightforward and minimal:
#include "configlang.h"
// Create and destroy
ConfigLang* cfg_create(void);
void cfg_destroy(ConfigLang* cfg);
// Load configuration
int cfg_load_string(ConfigLang* cfg, const char* code);
int cfg_load_file(ConfigLang* cfg, const char* path);
// Get values (type-safe)
int cfg_get_int(ConfigLang* cfg, const char* name, int* out);
int cfg_get_string(ConfigLang* cfg, const char* name, const char** out);
// Set values (runtime modification)
int cfg_set_int(ConfigLang* cfg, const char* name, int value);
// Save configuration
int cfg_save_file(ConfigLang* cfg, const char* path);
// Error handling
const char* cfg_get_error(ConfigLang* cfg);
Basic Usage Example
ConfigLang* cfg = cfg_create();
// Load from string
const char* config =
"set port = 8080\n"
"set host = \"localhost\"\n"
"const set max_connections = 100\n";
if (cfg_load_string(cfg, config) != ERR_CFG_OK) {
fprintf(stderr, "Error: %s\n", cfg_get_error(cfg));
cfg_destroy(cfg);
return 1;
}
// Retrieve values
int port;
const char* host;
int max_conn;
cfg_get_int(cfg, "port", &port);
cfg_get_string(cfg, "host", &host);
cfg_get_int(cfg, "max_connections", &max_conn);
printf("Server: %s:%d (max connections: %d)\n", host, port, max_conn);
// Modify non-const value
cfg_set_int(cfg, "port", 9000);
// Save to file
cfg_save_file(cfg, "server.cfg");
cfg_destroy(cfg);
Advanced Features
Variable References
Copy values between variables:
set base_port = 8080
set app_port = base_port
Multiline Strings
Support complex text content using the #%%% delimiter:
set welcome_message = #%%%
Welcome to our application!
This is a multiline message.
%%%#
Comments
Use # for single-line comments:
# This is a comment
set port = 8080 # inline comments not supported
Practical Configuration Example
# Application Configuration
const set app_name = "WebService"
const set version = "1.0.0"
# Environment settings (must be defined before use)
set environment = "production"
set debug = 0
# Port configuration based on environment
set port = 8080
if environment == "production" { set port = 80 }
if environment == "development" { set port = 3000 }
# Debug-dependent settings
set log_level = "info"
if debug == 1 { set log_level = "debug" }
# Connection settings
set max_connections = 100
if environment == "development" { set max_connections = 10 }
# Host configuration
set host = "0.0.0.0"
if debug == 1 { set host = "localhost" }
# Multiline configuration
set startup_banner = #%%%
=================================
WebService v1.0.0
Starting on port 80
=================================
%%%#
When to Use ConfigLang
ConfigLang shines in scenarios where traditional configuration formats fall short:
- Application configuration files with environment-specific settings
- Build systems managing compiler flags across platforms
- Feature flags and toggles with type safety
- Embedded systems (zero-dependency C99 implementation)
- Game settings requiring runtime validation
- Simple automation needing configuration with basic logic
Understanding the Limitations
ConfigLang is deliberately constrained to keep it focused on configuration:
- No floating-point numbers - only integers
- No arithmetic operations - do calculations in application code
- No loops - configuration is declarative
- No arrays or complex data structures - use multiple variables
- Limited string operations - assignment only
- Single statement per if block - keeps logic simple
- No else clauses - use chained if statements instead
These aren't oversights—they're design decisions. ConfigLang isn't trying to replace scripting languages. It's a configuration language that's more powerful than JSON but simpler than a full programming language.
Building and Installation
Compile the Library
gcc -std=c99 -fPIC -shared -o libconfiglang.so configlang.c
Link to Your Application
gcc -o myapp myapp.c -L. -lconfiglang
Or compile directly:
gcc -std=c99 -o myapp myapp.c configlang.c
Configuration Limits
The implementation defines the following limits (configurable in source):
-
MAX_VARIABLES- 128 variables maximum -
MAX_VAR_NAME- 32 characters for variable names -
MAX_STRING_VALUE- 1024 characters for string values -
MAX_LINE_LENGTH- 2048 characters per line -
MAX_ERROR_MSG- 256 characters for error messages
The Bigger Picture
ConfigLang represents a philosophy: configuration should be simple, safe, and just powerful enough. By combining type safety, immutability, and conditional logic in a minimal syntax with strict constraints, it addresses real pain points in configuration management without introducing unnecessary complexity.
For developers tired of wrestling with YAML indentation errors, JSON's lack of comments, or the complexity of embedding a full scripting language for simple configuration needs, ConfigLang offers a refreshing alternative. It's a tool that does one thing well—managing configuration with just enough logic to be useful and just enough constraints to stay maintainable.
Whether you're building a web service, an embedded system, or a desktop application, ConfigLang gives you the configuration power you need without the complexity you don't.
License
MIT License - suitable for both open-source and commercial projects.
Learn More
- GitHub: github.com/hejhdiss/configlang
- License: MIT
Top comments (0)