Fugu

Fugu::Config(3p) Perl Library Manual Fugu::Config(3p)

Fugu::Config - the OpenBSD-style configuration grammar

    use Fugu::Config;
    my $config = Fugu::Config->new(file => '/etc/mydaemon.conf');
    $config->load or die $config->error . "\n";
    my $port = $config->get('port', 8080);
    for my $device ($config->blocks('device')) {
        say $device->{settings}{name};
    }
    my $vm = $config->block('vm', 'default');

Fugu::Config parses the configuration grammar that OpenBSD daemons use. A file holds top-level settings and blocks:

    log_level debug
    hap_port = 51827
    device tasmota thermostat bedroom {
        name = "Bedroom Thermostat"
        topic = tasmota_AABBCC
    }

Both "key value" and "key = value" parse. A double-quoted value loses its quotes. A "#" starts a comment that runs to the end of the line.

A block header is a type, then one or more arguments, then an opening brace. Blocks nest one level; a block inside a block is an error.

The parser keeps the blocks of each type in file order, and also addresses each one by its name, which is the last argument of the header. Thus a caller that wants an ordered list of accessories and a caller that wants the machine called "default" read the same parse.

A malformed line is an error with a file and a line number. The module never skips a line it did not understand. A typo that a parser ignores is a setting that silently does not apply, and the operator finds out from the behavior of the daemon weeks later.

new(%args) creates a parser for one file. The method does not read the file. Call load().

This is the argument:

"file"
The configuration file. This argument is necessary.

load() reads and parses the file. A second call starts over, so a setting that the file no longer holds is gone.

An unreadable file is an error. A caller for whom an absent file is normal tests for the file first. A daemon that silently runs on defaults after a typo in a path is worse than one that refuses to start.

file() returns the path that this object parses.

error() returns the most recent failure, with its file and line.

"get($key, $default)" returns a top-level setting, or the default.

setting_names() returns the names of the top-level settings, sorted.

"parse_bool($value, $default)" parses a value as a switch. A setting inside a block comes through here.

The accepted spellings are "yes", "true", "on" and 1, and their opposites "no", "false", "off" and 0. The comparison ignores case.

Any other value returns the default and records an error. Thus a caller that checks gets told, and a caller that does not still gets a defined answer instead of the opposite of what the file said.

blocks($type) returns every block of the type, in file order.

Each entry is a hash reference with these keys:

"type"
The block type.
"args"
The header arguments, in order, as an array reference.
"name"
The last header argument.
"settings"
The settings inside the block, as a hash reference.
"order"
The position of the block in the file, counted from zero over every block of every type. A caller that reads two block types and wants them interleaved as the file wrote them sorts on it.

"block($type, $name)" returns the block of the type whose name matches, or "undef". When two blocks share a name, the last one in the file wins, as an assignment does.

find_project_root($marker) walks up from the working directory to the first directory that holds $marker. The method returns that directory, or "undef" when the walk reaches the root without a match.

load() returns the object on success. It returns "undef" when the file does not open or holds a line that the grammar does not accept, with the reason in error().

get(), file() and error() return a string or "undef". parse_bool() returns 1 or 0. blocks() and setting_names() return a list. block() returns a hash reference or "undef".

This example loads a file that may not exist yet:

    my $config = Fugu::Config->new(file => $path);
    if (-f $path) {
        $config->load or die $config->error . "\n";
    }
    my $port = $config->get('port', 8080);

new() dies when "file" is absent or empty, and find_project_root() dies without a marker. Both are programming errors.

No other method dies. load() reports every parse failure through its return value and error().

Fugu::File, Fugu::StateFile

Dick Olsson <hi@senzilla.io>

The grammar has no escape for the comment character. A value cannot hold a "#", even inside quotes.

Every value is a string. The module does not convert a number, and 0 as a string is true in Perl. Use parse_bool() for a switch.

A key with no value is not a setting, and the parser rejects the line. The grammar has no flag form.

2026-10-16 OpenBSD