aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: 4173770e5d5a1e125bf5d43b805e4ac51831e81a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
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 <stdlib.h>
#include <stdio.h>

#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