Environment Variables
argus can configure options through environment variables, providing flexibility for containerized applications, CI/CD pipelines, and system-wide configurations.
Basic Concepts
Overview
Environment variables support in argus allows you to:
- Associate options with environment variables
- Optionally use a prefix for variable namespacing
- Configure whether variables provide defaults or override command-line arguments
- Use either explicit variable names or auto-generated ones
Setting Up Environment Variables Support
Setting the Application Prefix (Optional)
You can configure an environment variable prefix in your argus context:
argus_t argus = argus_init(options, "my_program", "1.0.0");
argus.env_prefix = "APP"; // Optional: prefix env vars with APP_
This prefix helps namespace your environment variables to avoid conflicts with other applications. If you don't set a prefix, argus will use the environment variable names exactly as specified.
Prefix is Optional
The environment prefix is completely optional. If you don't set argus.env_prefix, argus will still work with environment variables but won't add any prefix.
Associating Options with Environment Variables
1. Explicit Environment Variable Name
2. Auto-generated Environment Variable Name
When using FLAG_AUTO_ENV, argus automatically generates a variable name:
- Converts the option name to uppercase
- Replaces dashes with underscores
- Adds the environment prefix (if set)
3. Non-prefixed Environment Variable
Use FLAG_NO_ENV_PREFIX for standard system variables that shouldn't have your application's prefix.
4. Auto-generated Name Without Prefix
Combine FLAG_AUTO_ENV with FLAG_NO_ENV_PREFIX to auto-generate a name without the application prefix.
Controlling Environment Variables Precedence
Default Behavior: Environment as Fallback
By default, environment variables provide fallback values when command-line options aren't specified:
Override Behavior: Environment Takes Priority
Use FLAG_ENV_OVERRIDE to make environment variables override command-line options:
- If environment variable is set: use that value (even if command-line specifies differently)
- If no environment variable but
--timeout=30is provided: value is 30 - If neither is provided but a default value is set: use the default
This is useful for system-wide configurations that should not be overridden by individual users.
Type Conversion
Environment variables are always strings, but argus automatically converts them to the appropriate type:
| Option Type | Environment Value | Conversion |
|---|---|---|
OPTION_STRING |
Any text | Used as-is |
OPTION_INT |
"123" | Parsed as integer 123 |
OPTION_FLOAT |
"3.14" | Parsed as float 3.14 |
OPTION_BOOL |
"1", "true", "yes", "on", "y" | Converted to true |
| "0", "false", "no", "off", "n" | Converted to false |
|
| Collections | "value1,value2,value3" | Parsed as comma-separated values |
Boolean Value Support
For boolean options (OPTION_BOOL), the environment variables support true/false values in various formats (case-insensitive):
- True values: "1", "true", "yes", "on", "y"
- False values: "0", "false", "no", "off", "n"
Best Practices for Environment Variables
Naming Conventions
Follow these naming conventions for clarity and consistency:
- Use UPPER_SNAKE_CASE for environment variable names
- Choose a short, unique prefix related to your application name (if using a prefix)
- Use consistent naming patterns throughout your application
- Document environment variables in your application's help and docs
Document Environment Variables
Clearly document the environment variables your application supports:
// Help text explicitly mentions environment variable
OPTION_STRING('H', "host", HELP("Server hostname (env: APP_HOST)"),
ENV_VAR("HOST"))
Complete Example
Here's a complete example showing various environment variable configurations:
#include "argus.h"
#include <stdio.h>
#include <stdlib.h>
ARGUS_OPTIONS(
options,
HELP_OPTION(),
VERSION_OPTION(),
// Option 1: Explicit environment variable with optional prefix
// Will look for APP_HOST if prefix is set, or HOST if no prefix
OPTION_STRING('H', "host", HELP("Server hostname"),
DEFAULT("localhost"),
ENV_VAR("HOST")),
// Option 2: Auto-generated environment variable name
// Will generate APP_PORT or PORT from the option name
OPTION_INT('p', "port", HELP("Server port"),
DEFAULT(8080),
FLAGS(FLAG_AUTO_ENV)),
// Option 3: Explicit environment variable without prefix
// Will look for DATABASE_URL exactly as specified
OPTION_STRING('d', "database", HELP("Database connection string"),
ENV_VAR("DATABASE_URL"),
FLAGS(FLAG_NO_ENV_PREFIX)),
// Option 4: Auto-generated name without prefix
// Will generate VERBOSE from the option name
OPTION_FLAG('v', "verbose", HELP("Enable verbose output"),
FLAGS(FLAG_AUTO_ENV | FLAG_NO_ENV_PREFIX)),
// Option 5: Environment variable that can override command line
// Even if --timeout is specified, FORCE_TIMEOUT will take precedence
OPTION_INT('t', "timeout", HELP("Connection timeout in seconds"),
DEFAULT(30),
ENV_VAR("FORCE_TIMEOUT"),
FLAGS(FLAG_ENV_OVERRIDE)),
// Option 6: Debug flag with prefix (if set)
OPTION_FLAG('\0', "debug", HELP("Enable debug mode"),
ENV_VAR("DEBUG"))
)
int main(int argc, char **argv)
{
// Initialize argus and optionally set environment prefix
argus_t argus = argus_init(options, "env_variables", "1.0.0");
argus.description = "Example of environment variables usage";
argus.env_prefix = "APP"; // Optional: set a prefix for env vars
int status = argus_parse(&argus, argc, argv);
if (status != ARGUS_SUCCESS)
return status;
// Access option values as usual
const char* host = argus_get(argus, "host").as_string;
int port = argus_get(argus, "port").as_int;
const char* database = argus_get(argus, "database").as_string;
bool verbose = argus_get(argus, "verbose").as_bool;
int timeout = argus_get(argus, "timeout").as_int;
bool debug = argus_get(argus, "debug").as_bool;
// Display configuration
printf("Server Configuration:\n");
printf(" Host: %s\n", host);
printf(" Port: %d\n", port);
printf(" Database: %s\n", database ? database : "(not set)");
printf(" Timeout: %d seconds\n", timeout);
printf("\nDebug Settings:\n");
printf(" Verbose: %s\n", verbose ? "enabled" : "disabled");
printf(" Debug: %s\n", debug ? "enabled" : "disabled");
// Show environment variable mappings
printf("\nEnvironment Variables:\n");
printf(" APP_HOST - Maps to --host\n");
printf(" APP_PORT - Maps to --port\n");
printf(" DATABASE_URL - Maps to --database\n");
printf(" VERBOSE - Maps to --verbose\n");
printf(" APP_FORCE_TIMEOUT - Maps to --timeout (with override)\n");
printf(" APP_DEBUG - Maps to --debug\n");
argus_free(&argus);
return 0;
}
Implementation Details
Behind the scenes, argus follows this process for environment variables:
- Parse command-line arguments first with
parse_args() - Load environment variables with
load_env_vars() - For options with
FLAG_ENV_OVERRIDE, environment values replace command-line values - For options without override flag, environment values are used only if the option wasn't set from command line
- Run validation on all values with
post_parse_validation()
Testing Environment Variables
Shell Environment
# Set environment variables
export APP_HOST=env-server.example.com
export APP_PORT=9000
export DATABASE_URL=postgres://user:pass@localhost/db
export VERBOSE=1
export APP_FORCE_TIMEOUT=60
export APP_DEBUG=true
# Run your program
./my_program
Docker Container
FROM alpine:latest
COPY ./my_program /app/my_program
ENV APP_HOST=container-host
ENV APP_PORT=9000
ENV DATABASE_URL=postgres://user:pass@db/app
ENV APP_FORCE_TIMEOUT=60
WORKDIR /app
CMD ["./my_program"]
For a complete example, see examples/env_vars.c.