Configuration Tool
Advanced example demonstrating collections, environment variables, and complex validation.
Complete Example​
config_tool.c
#include <argus.h>
#include <stdio.h>
ARGUS_OPTIONS(
options,
HELP_OPTION(),
VERSION_OPTION(),
// Arrays
OPTION_ARRAY_STRING('t', "tags", HELP("Resource tags"),
FLAGS(FLAG_UNIQUE | FLAG_SORTED),
VALIDATOR(V_COUNT(1, 10))),
OPTION_ARRAY_INT('p', "ports", HELP("Port numbers (supports ranges)"),
VALIDATOR(V_COUNT(1, 5))),
// Maps
OPTION_MAP_STRING('e', "env", HELP("Environment variables"),
ENV_VAR("CONFIG_ENV"), FLAGS(FLAG_SORTED_KEY)),
OPTION_MAP_BOOL('f', "features", HELP("Feature toggles"),
FLAGS(FLAG_SORTED_KEY)),
// Environment integration
OPTION_STRING('n', "name", HELP("Service name"),
ENV_VAR("SERVICE_NAME"), FLAGS(FLAG_REQUIRED)),
OPTION_STRING('h', "host", HELP("Host address"),
ENV_VAR("HOST"), DEFAULT("localhost")),
OPTION_INT('P', "port", HELP("Main port"),
ENV_VAR("PORT"), VALIDATOR(V_RANGE(1, 65535)), DEFAULT(8080)),
// Email validation
OPTION_STRING('c', "contact", HELP("Contact email"),
VALIDATOR(V_REGEX(ARGUS_RE_EMAIL))),
// Optional output
POSITIONAL_STRING("output", HELP("Output file"), FLAGS(FLAG_OPTIONAL)),
)
void print_array_strings(argus_t argus, const char *name)
{
if (!argus_is_set(&argus, name)) return;
printf("%s:\n", name);
argus_array_it_t it = argus_array_it(&argus, name);
while (argus_array_next(&it))
printf(" - %s\n", it.value.as_string);
}
void print_array_ints(argus_t argus, const char *name)
{
if (!argus_is_set(&argus, name)) return;
printf("%s:\n", name);
argus_array_it_t it = argus_array_it(&argus, name);
while (argus_array_next(&it))
printf(" - %d\n", it.value.as_int);
}
void print_map_strings(argus_t argus, const char *name)
{
if (!argus_is_set(&argus, name)) return;
printf("%s:\n", name);
argus_map_it_t it = argus_map_it(&argus, name);
while (argus_map_next(&it))
printf(" %s = %s\n", it.key, it.value.as_string);
}
void print_map_bools(argus_t argus, const char *name)
{
if (!argus_is_set(&argus, name)) return;
printf("%s:\n", name);
argus_map_it_t it = argus_map_it(&argus, name);
while (argus_map_next(&it))
printf(" %s = %s\n", it.key, it.value.as_bool ? "true" : "false");
}
int main(int argc, char **argv)
{
argus_t argus = argus_init(options, "config_tool", "2.0.0");
argus.description = "Configuration management with collections and environment support";
argus.env_prefix = "CONFIG";
if (argus_parse(&argus, argc, argv) != ARGUS_SUCCESS)
return 1;
// Basic values
const char *name = argus_get(&argus, "name").as_string;
const char *host = argus_get(&argus, "host").as_string;
int port = argus_get(&argus, "port").as_int;
printf("=== Service Configuration ===\n");
printf("Name: %s\n", name);
printf("Host: %s:%d\n", host, port);
if (argus_is_set(&argus, "contact"))
printf("Contact: %s\n", argus_get(&argus, "contact").as_string);
printf("\n");
// Collections
print_array_strings(argus, "tags");
print_array_ints(argus, "ports");
print_map_strings(argus, "env");
print_map_bools(argus, "features");
// Generate config file
const char *output = "config.json";
if (argus_is_set(&argus, "output")) {
output = argus_get(&argus, "output").as_string;
}
FILE *config = fopen(output, "w");
if (!config) {
fprintf(stderr, "Error: Cannot create config file '%s'\n", output);
return 1;
}
fprintf(config, "{\n");
fprintf(config, " \"name\": \"%s\",\n", name);
fprintf(config, " \"host\": \"%s\",\n", host);
fprintf(config, " \"port\": %d", port);
if (argus_is_set(&argus, "contact")) {
fprintf(config, ",\n \"contact\": \"%s\"", argus_get(&argus, "contact").as_string);
}
// Add arrays
if (argus_is_set(&argus, "tags")) {
fprintf(config, ",\n \"tags\": [");
argus_array_it_t it = argus_array_it(&argus, "tags");
bool first = true;
while (argus_array_next(&it)) {
if (!first) fprintf(config, ", ");
fprintf(config, "\"%s\"", it.value.as_string);
first = false;
}
fprintf(config, "]");
}
if (argus_is_set(&argus, "ports")) {
fprintf(config, ",\n \"ports\": [");
argus_array_it_t it = argus_array_it(&argus, "ports");
bool first = true;
while (argus_array_next(&it)) {
if (!first) fprintf(config, ", ");
fprintf(config, "%d", it.value.as_int);
first = false;
}
fprintf(config, "]");
}
// Add maps
if (argus_is_set(&argus, "env")) {
fprintf(config, ",\n \"environment\": {");
argus_map_it_t it = argus_map_it(&argus, "env");
bool first = true;
while (argus_map_next(&it)) {
if (!first) fprintf(config, ", ");
fprintf(config, "\n \"%s\": \"%s\"", it.key, it.value.as_string);
first = false;
}
if (!first) fprintf(config, "\n ");
fprintf(config, "}");
}
if (argus_is_set(&argus, "features")) {
fprintf(config, ",\n \"features\": {");
argus_map_it_t it = argus_map_it(&argus, "features");
bool first = true;
while (argus_map_next(&it)) {
if (!first) fprintf(config, ", ");
fprintf(config, "\n \"%s\": %s", it.key, it.value.as_bool ? "true" : "false");
first = false;
}
if (!first) fprintf(config, "\n ");
fprintf(config, "}");
}
fprintf(config, "\n}\n");
fclose(config);
printf("Configuration written to: %s\n", output);
argus_free(&argus);
return 0;
}
Usage Examples​
Command Line​
# Build
gcc config_tool.c -o config_tool -largus
# Basic usage
./config_tool --name myservice
# With collections
./config_tool --name api \
--tags=web,backend,api \
--ports=8080,8443,9000 \
--env=DEBUG=true,LOG_LEVEL=info \
--features=cache=true,metrics=false
# Range expansion for ports
./config_tool --name worker --ports=8000-8005,9000
# Custom output
./config_tool --name db --output database.json
Environment Variables​
# Set environment variables
export CONFIG_SERVICE_NAME=production-api
export CONFIG_HOST=api.company.com
export CONFIG_PORT=443
export CONFIG_CONFIG_ENV=DEPLOY_ENV=prod,VERSION=2.1.0
# Run with environment
./config_tool --tags=production,api
# Environment overrides CLI (for some options)
./config_tool --name dev-service # Uses CONFIG_SERVICE_NAME instead
Generated Help​
config_tool v2.0.0
Configuration management with collections and environment support
Usage: config_tool [OPTIONS] [output]
Arguments:
[output] - Output file (optional)
Options:
-h, --help - Display this help message (exit)
-V, --version - Display version information (exit)
-t, --tags <STR,...> - Resource tags (count: 1-10) (sorted, unique)
-p, --ports <NUM,...> - Port numbers (supports ranges) (count: 1-5)
-e, --env <KEY=VAL,...>
- Environment variables (env: CONFIG_CONFIG_ENV)
(sorted by key)
-f, --features <KEY=BOOL,...>
- Feature toggles (sorted by key)
-n, --name <STR> - Service name (env: CONFIG_SERVICE_NAME) (required)
-h, --host <STR> - Host address (env: CONFIG_HOST) (default:
"localhost")
-P, --port <1-65535> - Main port (env: CONFIG_PORT) (default: 8080)
-c, --contact <STR> - Contact email
Advanced Features​
Collection Processing​
# Arrays with flags
--tags=web,api,web,backend # Becomes: api,backend,web (unique + sorted)
# Integer ranges
--ports=8000-8003,9000 # Becomes: 8000,8001,8002,8003,9000
# Maps with sorting
--env=ZEBRA=last,ALPHA=first # Sorted by key: ALPHA=first,ZEBRA=last
Environment Integration​
# Multiple approaches
CONFIG_SERVICE_NAME=myapp ./config_tool --tags=web
./config_tool --name myapp --tags=web # Same result
# Complex environment
export CONFIG_CONFIG_ENV="DB_HOST=localhost,DB_PORT=5432,DEBUG=true"
./config_tool --name myapp # Automatically loads env map
Validation Examples​
# Array count validation
./config_tool --name test --tags=a,b,c,d,e,f,g,h,i,j,k
# Error: Values count 11 is out of [1, 10]
# Email validation
./config_tool --name test --contact=invalid-email
# Error: Invalid value 'invalid-email': Enter email: user@example.com
# Port range validation
./config_tool --name test --port=99999
# Error: Value 99999 is out of range [1, 65535]
Generated Config​
{
"name": "api",
"host": "localhost",
"port": 8080,
"contact": "admin@company.com",
"tags": ["api", "backend", "web"],
"ports": [8080, 8443, 9000],
"environment": {
"DEBUG": "true",
"LOG_LEVEL": "info"
},
"features": {
"cache": true,
"metrics": false
}
}
Key Features Demonstrated​
- String arrays with unique/sorted flags
- Integer arrays with range expansion (8000-8003)
- String maps for key-value configuration
- Boolean maps for feature toggles
- Environment variables with prefix support
- Email validation using regex patterns
- Count validation for collections
- Optional positional arguments
- JSON output generation from parsed data