AxlConfig – Configuration

Unified configuration framework. Declare options once in a descriptor table, populate from command-line args or programmatic set calls, and retrieve with typed getters. Supports auto-apply via offsetof, callbacks for custom logic, and parent inheritance for cascading defaults.

Header: <axl/axl-config.h>

Overview

AxlConfig replaces ad-hoc key-value parsing with a declarative system. You define a table of option descriptors (name, type, default value), then set values from any source. Type validation happens automatically.

Defining Options

#include <axl.h>

typedef struct {
    size_t  port;
    bool    verbose;
    size_t  max_connections;
} ServerConfig;

static const AxlConfigDesc opts[] = {
    { "port",     AXL_CFG_UINT, "8080", 0, "Listen port",
      offsetof(ServerConfig, port), sizeof(size_t) },
    { "verbose",  AXL_CFG_BOOL, "false", 0, "Verbose output",
      offsetof(ServerConfig, verbose), sizeof(bool) },
    { "max.conn", AXL_CFG_UINT, "16", 0, "Max connections",
      offsetof(ServerConfig, max_connections), sizeof(size_t) },
    { 0 }
};

Creating and Querying

ServerConfig sc;
AXL_AUTOPTR(AxlConfig) cfg = axl_config_new(opts);

// Set the auto-apply target -- values are written directly
// into the struct fields via offsetof
axl_config_set_target(cfg, &sc);

// Set values (type-validated)
axl_config_set(cfg, "port", "9090");       // sc.port = 9090
axl_config_set(cfg, "verbose", "true");    // sc.verbose = true

// Query values
size_t port = axl_config_get_uint(cfg, "port");
const char *port_str = axl_config_get(cfg, "port");  // "9090"

Command-Line Integration

Parse -p 8080 --verbose directly into the config:

static const AxlOpt cli_opts[] = {
    { 'p', "--port",    AXL_OPT_VALUE, "PORT", "Listen port" },
    { 'v', "--verbose", AXL_OPT_FLAG,  NULL,   "Verbose" },
    { 0 }
};

// axl_config_parse_args maps short/long flags to config keys
axl_config_parse_args(cfg, argc, argv, cli_opts);

Multi-Value Options

For options that can be specified multiple times (e.g., -H "Name: Value"):

size_t count = axl_config_get_multi_count(cfg, "headers");
for (size_t i = 0; i < count; i++) {
    const char *hdr = axl_config_get_multi(cfg, "headers", i);
    axl_printf("  header: %s\n", hdr);
}

Parent Inheritance

Create a child config that inherits defaults from a parent:

AxlConfig *defaults = axl_config_new(opts);
axl_config_set(defaults, "port", "8080");

AxlConfig *override = axl_config_new_with_parent(opts, defaults);
// override inherits "port"="8080" until explicitly set

API Reference

Defines

AXL_CFG_BOOL

“true”/”false”/”1”/”0”

AXL_CFG_INT

signed integer

AXL_CFG_UINT

unsigned integer

AXL_CFG_STRING

arbitrary string

AXL_CFG_MULTI

repeatable string (array)

Typedefs

typedef struct AxlConfig AxlConfig
typedef int (*AxlConfigApplyFunc)(void *target, const char *key, const char *value)

Callback invoked when an option is set.

Called BEFORE descriptor lookup — handles dynamic keys (e.g. “header.*”) that aren’t in the descriptor table.

Return values:

  • 0: accepted, proceed with descriptor lookup + auto-apply

  • 1: handled by callback (value stored, auto-apply skipped)

  • -1: rejected (set returns -1)

Functions

AxlConfig *axl_config_new(const AxlConfigDesc *descs, AxlConfigApplyFunc apply_fn, void *target)

Create a config object from descriptors.

Defaults from descriptors are applied immediately. If target is non-NULL and descriptors have offset/field_size, defaults are written into the target struct.

Parameters:
  • descs – descriptor table (borrowed, not copied)

  • apply_fn – change callback (NULL for auto-only)

  • target – opaque pointer for apply_fn + auto-apply

Returns:

new config, or NULL on allocation failure.

void axl_config_free(AxlConfig *cfg)

Free a config object. NULL-safe.

Parameters:
  • cfg – config to free

int axl_config_set(AxlConfig *cfg, const char *key, const char *value)

Set a config option.

Validates type, calls apply_fn (if set), then auto-applies via offsetof (if descriptor has offset). Stores the string value internally for later retrieval.

Parameters:
  • cfg – config

  • key – option key

  • value – value as string

Returns:

0 on success, -1 on unknown key, type mismatch, or callback rejection.

int axl_config_setv(AxlConfig *cfg, ...)

Set multiple options in one call.

Accepts key/value string pairs terminated by NULL. Stops at the first failure and returns -1.

axl_config_setv(cfg,
    "port", "8080",
    "verbose", "true",
    NULL);
Parameters:
  • cfg – config

Param :

key, value pairs terminated by NULL

Returns:

0 on success, -1 on first error.

const char *axl_config_get(AxlConfig *cfg, const char *key)

Get an option value as string.

Parameters:
  • cfg – config

  • key – option key

Returns:

stored value, default, or NULL if unknown key.

bool axl_config_get_bool(AxlConfig *cfg, const char *key)

Get a boolean option.

Accepts “true”/”1”/”yes” as true, everything else as false.

Parameters:
  • cfg – config

  • key – option key

int64_t axl_config_get_int(AxlConfig *cfg, const char *key)

Get a signed integer option.

Parameters:
  • cfg – config

  • key – option key

Returns:

parsed value, or 0 if unset or not a number.

uint64_t axl_config_get_uint(AxlConfig *cfg, const char *key)

Get an unsigned integer option.

Parameters:
  • cfg – config

  • key – option key

Returns:

parsed value, or 0 if unset or not a number.

size_t axl_config_get_multi_count(AxlConfig *cfg, const char *key)

Get the count of values for a MULTI option.

Parameters:
  • cfg – config

  • key – option key

const char *axl_config_get_multi(AxlConfig *cfg, const char *key, size_t index)

Get a value from a MULTI option by index.

Parameters:
  • cfg – config

  • key – option key

  • index – 0-based index

Returns:

value string, or NULL if index out of range.

int axl_config_parse_args(AxlConfig *cfg, int argc, char **argv)

Parse command-line arguments into config.

Maps short flags and long options (key names) to config values. Flags without values are treated as boolean “true”. Supports -k, --key, --key=value, and -- to stop parsing. Unrecognized args are collected as positional arguments.

Parameters:
  • cfg – config

  • argc – argument count

  • argv – argument vector (argv[0] is program name)

Returns:

0 on success, -1 on error (unknown flag).

const char *axl_config_pos(AxlConfig *cfg, int index)

Get positional argument by index.

Parameters:
  • cfg – config

  • index – 0-based index

Returns:

argument string, or NULL if index out of range.

int axl_config_pos_count(AxlConfig *cfg)

Get count of positional arguments.

Parameters:
  • cfg – config

void axl_config_usage(AxlConfig *cfg, const char *program, const char *synopsis)

Print usage from descriptors.

Outputs formatted help to stdout: “Usage: PROGRAM SYNOPSIS” followed by option descriptions from the descriptor table.

Parameters:
  • cfg – config (for descriptors)

  • program – program name

  • synopsis – usage synopsis (e.g. “[options] FILE”)

void axl_config_set_parent(AxlConfig *cfg, AxlConfig *parent)

Set a parent config for cascading defaults.

When axl_config_get finds no value for a key, it falls through to the parent. Useful for per-connection configs that inherit server-level defaults.

Parameters:
  • cfg – child config

  • parent – parent config (borrowed, not owned)

struct AxlConfigDesc
#include <axl-config.h>

Option descriptor. Define a static array terminated by {0}.

Public Members

const char *key

dotted name (e.g. “timeout.ms”)

int type

AXL_CFG_BOOL, _INT, _UINT, _STRING, _MULTI.

const char *default_value

default as string (NULL = no default)

char short_flag

single-char CLI flag (0 = none)

const char *description

help text

size_t offset

offsetof into target struct

size_t field_size

sizeof the target field (0 = no auto-apply)