An embedded configuration and automation language library written in pure C99 with Python bindings. ConfigLang provides a simple, readable syntax for configuration files with support for variables, conditionals, and type safety.
- Pure C99 - No external dependencies
- Python Bindings - Easy integration with Python projects
- Type System - Integer and string types with type checking
- Const Variables - Immutable configuration values
- Conditionals - If logic for dynamic configuration
- Variable References - Copy values between variables
- Multiline Strings - Support for complex text values
- Comments - Single-line comments with
# - Save/Load - Persist configuration state to files
Important constraints to remember:
- Variables must be defined before use - You cannot reference a variable in a conditional before it has been declared with
set - Single statement per if block - Each if block can contain only ONE
setstatement - Closing brace on same line - The
}must appear on the same line as the statement inside the if block - No else clause - Use chained if statements instead of if-else
Set integer or string variables:
set x = 10
set name = "Hello World"
set count = 42
Create immutable variables:
const set max_users = 100
const set app_name = "MyApp"
Attempting to modify a const variable will raise an error.
Copy values from one variable to another:
set original = 42
set copy = original
set name = "Config"
set backup = name
CORRECT: Basic if statement with closing brace on same line:
set value = 60
if value > 50 { set value = 50 }
CORRECT: Variable must be defined before use in condition:
set debug = 0
set log_level = "info"
if debug == 1 { set log_level = "debug" }
CORRECT: Chained if statements for multiple conditions:
set environment = "production"
set timeout = 30
if environment == "development" { set timeout = 300 }
if environment == "staging" { set timeout = 100 }
if environment == "production" { set timeout = 30 }
CORRECT: Chained if statements (if-if pattern):
set x = 55
if x > 50 { set x = 50 } if x < 10 { set x = 10 }
INCORRECT: Closing brace on separate line:
# This will fail to parse!
if value > 50 {
set value = 50
}
INCORRECT: Multiple statements in if block:
# This will fail - only ONE set per if block!
if debug == 1 {
set verbose = 1
set trace = 1
}
INCORRECT: Variable used before definition:
# This will fail - x is not defined yet!
if x > 50 { set x = 50 }
set x = 55
All standard comparison operators are supported:
>- Greater than<- Less than>=- Greater than or equal<=- Less than or equal==- Equal to!=- Not equal to
Example:
set x = 10
if x >= 10 { set ready = 1 }
if x != 0 { set active = 1 }
For complex text content, use multiline delimiters:
set config = #%%%
line 1
line 2
line 3
%%%#
Single-line comments start with #:
# This is a comment
set x = 10 # Inline comment
Compile the C library:
# Linux/macOS
gcc -shared -fPIC -std=c99 -o libconfiglang.so configlang.c
# macOS (alternative)
gcc -shared -fPIC -std=c99 -o libconfiglang.dylib configlang.c
# Windows
gcc -shared -o configlang.dll configlang.cCompile the test program:
gcc -std=c99 -o test test.c configlang.c
./testInstall from source:
pip install .Or install in development mode:
pip install -e .#include "configlang.h"
#include <stdio.h>
int main(void) {
// Create instance
ConfigLang* cfg = cfg_create();
// Load configuration
const char* code =
"set port = 8080\n"
"set host = \"localhost\"\n"
"const set max_connections = 100\n"
"if port < 1024 { set port = 8080 }\n";
int result = cfg_load_string(cfg, code);
if (result != ERR_CFG_OK) {
fprintf(stderr, "Error: %s\n", cfg_get_error(cfg));
cfg_destroy(cfg);
return 1;
}
// Get values
int port;
const char* host;
cfg_get_int(cfg, "port", &port);
cfg_get_string(cfg, "host", &host);
printf("Server: %s:%d\n", host, port);
// Modify value
cfg_set_int(cfg, "port", 9000);
// Save configuration
cfg_save_file(cfg, "server.cfg");
// Cleanup
cfg_destroy(cfg);
return 0;
}from configlang import ConfigLang
# Create instance
cfg = ConfigLang()
# Load configuration
code = """
set debug = 0
set port = 8080
set host = "localhost"
const set max_connections = 100
if debug == 1 { set port = 3000 }
"""
cfg.load_string(code)
# Get values
print(f"Port: {cfg.get_int('port')}")
print(f"Host: {cfg.get_string('host')}")
# Modify value
cfg.set_int('port', 9000)
# Dictionary-style access
cfg['port'] = 3000
print(f"Port: {cfg['port']}")
# Save configuration
cfg.save_file('server.cfg')with ConfigLang() as cfg:
cfg.load_string('set x = 10\nset name = "Test"')
print(cfg.get_int('x'))
# Automatically cleaned up| Function | Description |
|---|---|
cfg_create() |
Create a new ConfigLang instance |
cfg_destroy(cfg) |
Destroy instance and free resources |
cfg_load_file(cfg, path) |
Load configuration from file |
cfg_load_string(cfg, code) |
Load configuration from string |
cfg_get_int(cfg, name, out) |
Get integer variable value |
cfg_get_string(cfg, name, out) |
Get string variable value |
cfg_set_int(cfg, name, value) |
Set integer variable value |
cfg_save_file(cfg, path) |
Save configuration to file |
cfg_get_error(cfg) |
Get last error message |
| Method | Description |
|---|---|
ConfigLang() |
Create new instance |
load_file(path) |
Load configuration from file |
load_string(code) |
Load configuration from string |
get_int(name) |
Get integer variable value |
get_string(name) |
Get string variable value |
set_int(name, value) |
Set integer variable value |
save_file(path) |
Save configuration to file |
get_error() |
Get last error message |
get(name) |
Auto-detect type and get value |
| Code | Constant | Description |
|---|---|---|
| 0 | ERR_CFG_OK |
Success |
| 1 | ERR_CFG_PARSE_ERROR |
Syntax error in configuration |
| 2 | ERR_CFG_FILE_ERROR |
File I/O error |
| 3 | ERR_CFG_VARIABLE_NOT_FOUND |
Variable doesn't exist |
| 4 | ERR_CFG_CONST_VIOLATION |
Attempted to modify const variable |
| 5 | ERR_CFG_TYPE_MISMATCH |
Variable type mismatch |
| 6 | ERR_CFG_NULL_POINTER |
NULL pointer passed |
| 7 | ERR_CFG_OUT_OF_MEMORY |
Memory allocation failed |
ConfigLangError- Base exception classParseError- Syntax error in configurationVariableNotFoundError- Variable doesn't existConstViolationError- Attempted to modify const variableTypeMismatchError- Variable type mismatch
# Application Configuration
const set app_name = "MyApplication"
const set version = "1.0.0"
# Server Settings
set debug = 0
set host = "0.0.0.0"
set port = 8080
# Apply production settings
if debug == 0 { set port = 80 }
if debug == 0 { set workers = 4 }
# Apply development settings
if debug == 1 { set port = 8080 }
if debug == 1 { set workers = 1 }
# Database Configuration
set db_host = "localhost"
set db_port = 5432
set db_name = "myapp"
# Limits
const set max_connections = 100
const set timeout = 30
# Multiline description
set description = #%%%
This is a multi-line
application description
that spans several lines.
%%%#
This example demonstrates all features with correct syntax:
# ============================================
# Complete ConfigLang Example
# ============================================
# Constants (immutable)
const set APP_NAME = "WebServer"
const set VERSION = "2.0.0"
const set MAX_USERS = 1000
# Environment variable
set environment = "production"
# Default values
set port = 8080
set host = "localhost"
set workers = 2
set timeout = 30
set log_level = "info"
# Production configuration
if environment == "production" { set port = 80 }
if environment == "production" { set host = "0.0.0.0" }
if environment == "production" { set workers = 8 }
if environment == "production" { set log_level = "warning" }
# Development configuration
if environment == "development" { set port = 3000 }
if environment == "development" { set host = "127.0.0.1" }
if environment == "development" { set workers = 1 }
if environment == "development" { set log_level = "debug" }
# Staging configuration
if environment == "staging" { set port = 8080 }
if environment == "staging" { set workers = 4 }
# Database settings
set db_enabled = 1
set db_host = "localhost"
set db_port = 5432
if db_enabled == 1 { set db_name = "production_db" }
if db_enabled == 0 { set db_name = "test_db" }
# Feature flags
set feature_cache = 1
set feature_logging = 1
if feature_cache == 1 { set cache_size = 1024 }
if feature_logging == 1 { set log_size = 100 }
# Variable references
set backup_host = host
set backup_port = port
# Multiline content
set welcome = #%%%
=========================================
Welcome to WebServer v2.0.0
Environment: production
Running on: 0.0.0.0:80
=========================================
%%%#
program → statement*
statement → comment | set_stmt | if_stmt
comment → '#' text '\n'
set_stmt → 'const'? 'set' identifier '=' value
if_stmt → 'if' condition '{' set_stmt '}' if_stmt?
condition → identifier operator value
operator → '>' | '<' | '>=' | '<=' | '==' | '!='
value → integer | string | identifier | multiline
integer → '-'? [0-9]+
string → '"' [^"]* '"'
multiline → '#%%%' .* '%%%#'
identifier → [a-zA-Z_][a-zA-Z0-9_]*
Key Grammar Notes:
if_stmtcan only contain ONEset_stmtinside the braces- The closing
}must be on the same line as theset_stmt - Chaining is done by following one
if_stmtwith anotherif_stmt - There is no separate
elsekeyword - use chainedifstatements
ConfigLang has a simple type system with two types:
- Integer - Signed integers (e.g.,
42,-10,0) - String - Text values (e.g.,
"Hello","Config")
Types are checked at runtime. Attempting to get or set a variable with the wrong type will result in a TYPE_MISMATCH error.
The C implementation defines these limits (configurable in source):
MAX_VARIABLES- 128 variables maximumMAX_VAR_NAME- 32 characters for variable namesMAX_STRING_VALUE- 1024 characters for string valuesMAX_LINE_LENGTH- 2048 characters per lineMAX_ERROR_MSG- 256 characters for error messages
- No floating-point numbers (integers only)
- No arithmetic operations (use for configuration, not computation)
- No loops (conditionals only)
- No functions or procedures
- No arrays or complex data structures
- String operations are limited to assignment
- Only one
setstatement perifblock - No
elsekeyword - use chainedifstatements instead - Closing brace must be on same line as the statement
- Variables must be declared before use in conditionals
ConfigLang is designed for:
- Application configuration files
- Build system configuration
- Environment-specific settings
- Feature flags and toggles
- Embedded system configuration
- Game settings and preferences
- Simple automation scripts
- Define variables before conditionals: Always declare variables with
setbefore using them inifconditions - Use chained if statements: Instead of if-else, use multiple if statements
- Keep conditionals simple: Each if block should modify only one variable
- Use const for fixed values: Mark configuration values that shouldn't change as
const - Group related settings: Use comments to organize your configuration into logical sections
- One line per if block: Keep the syntax compact with
if condition { set var = value }
set env = "production"
set port = 80
if env == "development" { set port = 3000 }
if env == "staging" { set port = 8080 }
if env == "production" { set port = 80 }
set feature_x = 1
set feature_y = 0
set module_x_enabled = 0
set module_y_enabled = 0
if feature_x == 1 { set module_x_enabled = 1 }
if feature_y == 1 { set module_y_enabled = 1 }
set mode = 1
set timeout = 30
if mode == 0 { set timeout = 10 }
if mode == 1 { set timeout = 30 }
if mode == 2 { set timeout = 60 }
MIT License - See LICENSE file for details
hejhdiss
- GitHub: https://github.com/hejhdiss/configlang
- Issues: https://github.com/hejhdiss/configlang/issues
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
- Initial release
- C library implementation
- Python bindings
- Full test suite
- Documentation