NAME

libslack(prop) - program properties file module

SYNOPSIS

#include <slack/std.h>
#include <slack/prop.h>

const char *prop_get(const char *name);
const char *prop_get_or(const char *name, const char *default_value);
const char *prop_set(const char *name, const char *value);
int prop_get_int(const char *name);
int prop_get_int_or(const char *name, int default_value);
int prop_set_int(const char *name, int value);
double prop_get_double(const char *name);
double prop_get_double_or(const char *name, double default_value);
double prop_set_double(const char *name, double value);
int prop_get_bool(const char *name);
int prop_get_bool_or(const char *name, int default_value);
int prop_set_bool(const char *name, int value);
int prop_unset(const char *name);
int prop_save(void);
int prop_clear(void);
int prop_locker(Locker *locker);

DESCRIPTION

This module provides support for system-wide and user-specific (generic and program-specific) properties in "well-known" locations:

/etc/properties/app          - system-wide, generic properties
~/.properties/app            - user-defined, generic properties
/etc/properties/app.progname - system-wide, program-specific properties
~/.properties/app.progname   - user-defined, program-specific properties

Note that, depending on how libslack was installed, the system-wide /etc/properties directory might not be under /etc. It might be under another directory, such as /usr/local/etc or /opt/local/etc. If you aren't sure where it is expected, run libslack-config --cflags and look for the definition of ETC_DIR.

When the client first requests, sets, or unsets a property, all properties relevant to the current program are loaded from these files in the order given above. This order ensures that program-specific properties override generic properties and that user-defined properties override system-wide properties. The client can change properties at runtime and save the current properties back to disk (to the user-defined, program-specific properties file).

Program names (as returned by prog_name(3)) are converted into file name suffixes by replacing every occurrence of the file path separator ('/') with a '-'. Properties files consist of one property per line.

Each property is specified by its name, followed by '=' followed by its value. The name must not have a '=' in it unless it is quoted with a preceding '\'. Special characters are expressed in C string literal notation (e.g. \a\b\f\n\r\t\v\x1b). Spaces immediately before and after the '=' are stripped unless they are quoted with a preceding '\'. The properties files may also contain blank lines and comments ('#' until the end of the line).

Boolean property values can be expressed as 0 or 1, true or false, yes or no, on or off (case insensitive).

const char *prop_get(const char *name)

Returns the value of the property named name. Returns null if there is no such property. On error, returns null with errno set appropriately.

const char *prop_get_or(const char *name, const char *default_value)

Returns the value of the property named name. Returns default_value on error, or if there is no such property.

const char *prop_set(const char *name, const char *value)

Sets the property named name to a dynamically allocated copy of value. If prop_save(3) is called after a call to this function, the new property will be saved to disk, and will be available the next time this program is executed. On success, returns the copy of value. On error, returns null with errno set appropriately.

int prop_get_int(const char *name)

Returns the value of the property named name as an integer. Returns 0 on error, or if there is no such property, or if it is not interpretable as a decimal integer.

int prop_get_int_or(const char *name, int default_value)

Returns the value of the property named name as an integer. Returns default_value on error, or if there is no such property, or if it is not interpretable as a decimal integer.

int prop_set_int(const char *name, int value)

Sets the property named name to value. If prop_save(3) is called after a call to this function, the new property will be saved to disk and will be available the next time this program is executed. On success, returns value. On error, returns 0.

double prop_get_double(const char *name)

Returns the value of the property named name as a double. Returns 0.0 on error, or if there is no such property, or if it is not interpretable as a floating point number.

double prop_get_double_or(const char *name, double default_value)

Returns the value of the property named name as a double. Returns default_value on error, or if there is no such property, or if it is not interpretable as a floating point number.

double prop_set_double(const char *name, double value)

Sets the property named name to value. If prop_save(3) is called after a call to this function, the new property will be saved to disk and will be available the next time this program is executed. On success, returns value. On error, returns 0.0.

int prop_get_bool(const char *name)

Returns the value of the property named name as a boolean value. Returns 0 on error or if there is no such property. The values: "true", "yes", "on" and "1" are all interpreted as true. All other values are interpreted as false.

int prop_get_bool_or(const char *name, int default_value)

Returns the value of the property named name as a boolean value. Returns default_value on error, or if there is no such property, or if it is not interpretable as a boolean value. The values: "true", "yes", "on" and "1" are all interpreted as true. The values: "false", "no", "off" and "0" are all interpreted as false. All other values are disregarded and will cause default_value to be returned.

int prop_set_bool(const char *name, int value)

Sets the property named name to value. If prop_save(3) is called after a call to this function, the new property will be saved to disk and will be available the next time this program is executed. On success, returns value. On error, returns 0.

int prop_unset(const char *name)

Removes the property named name. Property removal is only saved to disk when prop_save(3) is called, if the property existed only in the user-defined, program-specific properties file, or was created by the program at runtime. On success, returns 0. On error, returns -1 with errno set appropriately.

int prop_save(void)

Saves the program's properties to disk. If the property named "save" is set to "false", "no", "off" or "0", nothing is written to disk. If no properties were added, removed or changed, nothing is written to disk. Only the user-defined, program-specific properties are saved. Generic and system-wide properties files must be edited by hand. Each program can only save its own properties. They are saved in the following file:

~/.properties/app.progname

Where progname is the name of the program after being translated as described at the top of the DESCRIPTION section.

The ~/.properties directory is created if necessary. On success, returns 0. On error, returns -1 with errno set appropriately.

int prop_clear(void)

Clears the properties as though they were never initialised. On success, returns 0. On error, returns -1 with errno set appropriately.

int prop_locker(Locker *locker)

Sets the locking strategy for the prop(3) module to locker. This is only needed in multi-threaded programs. It must only be called once, from the main thread. On success, returns 0. On error, returns -1 with errno set appropriately.

ERRORS

On error, errno is set either by an underlying function, or as follows:

EINVAL

When there is no prog_name or home directory, or when there is a parse error in a properties file, or if ~/.properties exists but is not a directory. prop_locker(3) sets this when an attempt is made to change the locker after one has already been set.

MT-Level

MT-Disciplined

FILES

/etc/properties/app
~/.properties/app
/etc/properties/app.*
~/.properties/app.*

EXAMPLE

#include <slack/std.h>
#include <slack/prog.h>
#include <slack/prop.h>
#include <slack/err.h>

int main(int ac, char **av)
{
    const char *s; int i; double d; int b;

    prog_init();
    prog_set_name(*av);

    s = prop_get("string");
    i = prop_get_int_or("int", 1);
    d = prop_get_double_or("double", 1.0);
    b = prop_get_bool("boolean");

    msg("s = '%s'\ni = %d\nd = %g\nb = %s\n", s, i, d, (b) ? "true" : "false");

    prop_set("string", "strung");
    prop_set_int("int", i += 4);
    prop_set_double("double", d *= 1.75);
    prop_set_bool("boolean", !b);
    prop_save();

    return EXIT_SUCCESS;
}

BUGS

This only provides coarse-grained persistence. If multiple instances of the same program are setting properties, the last to exit wins. This can be overcome by calling prop_save() after setting any property and prop_clear() before getting any property.

SEE ALSO

libslack(3), prog(3)

AUTHOR

20230824 raf <raf@raf.org>