Myrddin: libinifile

Summary

Ini files are a common, simple, well known format. They are restrictive, but in many cases a complicated configuration is overkill.

pkg inifile =
    type error = union
        `Fileerr
        `Parseerr int
        `Dupkey int
    ;;

    type inifile =
    ;;

    /* reading */
    const load  : (path : byte[:]   -> std.result(inifile#, error))
    const loadf : (file : std.fd    -> std.result(inifile#, error))
    const free  : (ini : inifile#   -> void)

    /* writing */
    const write : (ini : inifile#, path : byte[:]   -> bool)

    /* key getting/setting */
    const get   : (ini : inifile#, sect : byte[:], key : byte[:]    -> std.option(byte[:]))
    const getv  : (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:] -> byte[:])
    const has   : (ini : inifile#, sect : byte[:], key : byte[:] -> bool)
    const put   : (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:] -> void)
;;

Overview

Libinifile is a simple ini file parser. It does little interpretation of the data, and provides little in the way of convenience features. Loading will read the file into memory, and will not reflect changes of the on-disk data.

Functions

const load  : (path : byte[:]   -> std.result(inifile#, error))

Load will read a file from disk, parsing it, and returning either a pointer to an inifile data structure, or an error reporting the problem parsing it, and if applicable, the line that the error occurred on.

This data structure must be freed with inifile.free().

const loadf : (file : std.fd    -> std.result(inifile#, error))

This is identical to inifile.load, only it reads from a std.fd that has already been opened in read mode, instead of a path.

const free  : (ini : inifile#   -> void)

Releases all storage associated with an inifile data structure.

const write : (ini : inifile#, path : byte[:]   -> bool)

Write will take the content of an infile, and serialize it to disk. Comments from the original ini file are not currently preserved.

const get   : (ini : inifile#, sect : byte[:], key : byte[:]    -> std.option(byte[:]))
const getv  : (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:] -> byte[:])

Get and getv act like std.hget and std.htgetv. They will retrieve an entry from the ini file.

Htget will return `std.Some val if the key is present in the given section, or `std.None if there is no value present in the ini file. Htgetv will return the default value val passed to it if the key is not found.

For a key that is outside of a section, the empty string ("") should be passed for the section name.

const has   : (ini : inifile#, sect : byte[:], key : byte[:] -> bool)

Queries whether a key is present in the ini file. Returns true if the key is present, or false if it is not.

const put   : (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:] -> void)

Places a key value pair into the in-memory representation of the .ini file. This key value pair added if it is not present, and replaced if it is. The key and value are both copied, and ownership is not taken. The responsibility for freeing the previous value lies with the ini file implementation.

Supported Syntax

The dialect that it supports allows for a list of zero or more key-value pairs before any sections are declared, followed by a list of sections containing more key value pairs.

Keys are any sequence of characters, excluding an '=' sign. Values are any sequence of characters. For both of these, both leading and trailing white space is ignored.

Sections are lists of characters started by [ and end by ]. The only character disallowed within a section name is ]. Leading and trailing whitespace is stripped from a section.

Keys within a file must be unique, otherwise this is an error.

Section declarations may repeat throughout the file, but this will merely switch back into the old section.

Example

Assuming that an file named demo.ini exists, and contains the following text:

toplev = hey, there's a value!
[section]
    key = wait, there's another

Then the following program will read it and show the values of the keys:

use std
use inifile

const main = {
    var ini

    ini = std.try(inifile.load("demo.ini"))
    std.put("{}\n", inifile.getv(ini, "", "toplev", "not present")
    std.put("{}\n", inifile.getv(ini, "section", "key", "not present")
    inifile.free(ini)
}