libslack(prop) - program properties file module
#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);
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.
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-Disciplined
/etc/properties/app
~/.properties/app
/etc/properties/app.*
~/.properties/app.*
#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;
}
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.
libslack(3), prog(3)
20230824 raf <raf@raf.org>