simple-xdg-bdirs ================ [simple-xdg-bdirs.h](simple-xdg-bdirs.h) is a single header file which implements calculating file paths according to the [XDG Base Directory Specification][1]. brief summary ------------- the XDG Base Directory Specification is a popular specification which defines predictable locations for programs to store their config, runtime, cache, and data files. these locations are calculated based on specially named environment variables, with certain directories defined as default fallbacks. this single-header library provides a couple of simple functions to calculate those locations at runtime, as well as functions to build file paths against them. example ------- the following example file is available as [example.c](doc/example.c), which you can compile and play with yourself. ```C #include #include #include "../simple-xdg-bdirs.h" /* a simple example which attempts to read a value from a configuration file * and write it back to a cache file */ int main(int argc, char *argv[]) { char *s, *wdir, **rdirs, **cur; /* alloc a null-terminated array of directories in which to search for * configuration files */ rdirs = simple_xdg_bdirs_read_dirs(SIMPLE_XDG_BDIRS_CONFIG); /* in case of error, errno is set, so perror works */ if (rdirs == NULL) { perror(NULL); return 1; } /* search in the config directories for the given relative path. if not * found in the first, the second will be checked as a fallback etc */ s = simple_xdg_bdirs_fullpath_read("xdg_bdirs_test/config.conf", rdirs); /* element strings of rdirs must also be freed */ for (cur = rdirs; *cur != NULL; cur++) free(*cur); free(rdirs); /* check for errors again */ if (s == NULL) { perror(NULL); return 1; } /* print the fullpath of the file that was found */ puts(s); free(s); /* locate the directory into which runtime files should be written * (things like sockets or lock files) */ wdir = simple_xdg_bdirs_write_dir(SIMPLE_XDG_BDIRS_RUNTIME); if (wdir == NULL) { perror(NULL); return 1; } /* a convenience function that builds a fullpath from a relative path and * write directory */ s = simple_xdg_bdirs_fullpath_write("xdg_bdirs_test.lock", wdir); free(wdir); if (s == NULL) { perror(NULL); return 1; } puts(s); free(s); return 0; } ``` basically, each function returns either a string or `NULL`, in which case `errno` will also be set. simple! interface --------- ```C enum simple_xdg_bdirs_ftype { SIMPLE_XDG_BDIRS_DATA, SIMPLE_XDG_BDIRS_CONFIG, SIMPLE_XDG_BDIRS_CACHE, SIMPLE_XDG_BDIRS_RUNTIME, }; ``` one of these types is passed to each of the functions below, denoting the category of file to which the functions actions ought to correspond. - `SIMPLE_XDG_BDIRS_DATA` is used for persistent data created by a program - `SIMPLE_XDG_BDIRS_CONFIG` is used for a program's configuration files - `SIMPLE_XDG_BDIRS_CACHE` is used for transient data which may be deleted without warning by the system - `SIMPLE_XDG_BDIRS_RUNTIME` is used for "runtime files", such as lock files or sockets ```C static char* simple_xdg_bdirs_write_dir(enum simple_xdg_bdirs_ftype type) ``` this function finds and returns a single string that is the path of a directory into which all files of type `type` ought to be written. because the location of this directory is determined at runtime, and in particular because it relies on the state of the filesystem and environment variables, it is possible that no good candidate directory will be found, in which case `NULL` will be returned. if a string is returned, it is guaranteed to always have a trailing '/', meaning that a relative path can be appended directly without fear of unintended results, like '/etx/xdgherbstluftwm' errors: - `ENOENT`: no candidate dir found - `EINVAL`: bad argument - `EOVERFLOW`: extremely-large string encountered (unlikely) - `ENOMEM`: malloc err ```C static char** simple_xdg_bdirs_read_dirs(enum simple_xdg_bdirs_ftype type) ``` this function finds and returns a null-terminated array of strings that are the paths, in order, where one ought to search for files of type `type` when reading. because some filetypes have only a single, environment-determined read dir, it's possible that none will be found, in which case `NULL` will be returned. returned strings are guaranteed to always have a trailing '/', meaning that a relative path can be appended directly without fear of unintended results, like '/etx/xdgherbstluftwm' errors: - `ENOENT`: no candidate dirs found - `EINVAL`: bad argument - `EOVERFLOW`: extremely-large string encountered (unlikely) - `ENOMEM`: malloc err ```C static char* simple_xdg_bdirs_fullpath_read(const char *rel_path, char **read_dirs) ``` take a relative path and set of directories returned from `simple_xdg_bdirs_read_dirs` and return either a full path to an existing file or, on error, NULL errors - `ENOENT`: target file not found or readable - `EINVAL`: bad argument - `EOVERFLOW`: extremely-large string encountered (unlikely) - `ENOMEM`: malloc err ```C static char* simple_xdg_bdirs_fullpath_write(const char *rel_path, char *write_dir) ``` take a relative path and a write directory returned from `simple_xdg_bdirs_write_dir` and return either a full path to the targeted write path or, on error, NULL errors - `ENOENT`: write_dir is not found or not write accessible - `EINVAL`: bad argument - `EOVERFLOW`: extremely-large string encountered (unlikely) - `ENOMEM`: malloc err [1]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html