# 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

20210220 raf <raf@raf.org>