libxdg-basedir-1.2.0 1.2.0
basedir.c
Go to the documentation of this file.
1/* Copyright (c) 2007 Mark Nevill
2 *
3 * Permission is hereby granted, free of charge, to any person
4 * obtaining a copy of this software and associated documentation
5 * files (the "Software"), to deal in the Software without
6 * restriction, including without limitation the rights to use,
7 * copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following
10 * conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
28#if defined(HAVE_CONFIG_H) || defined(_DOXYGEN)
29#include <config.h>
30#endif
31
32#if STDC_HEADERS || HAVE_STDLIB_H || !defined(HAVE_CONFIG_H)
33# include <stdlib.h>
34#endif
35#if HAVE_MEMORY_H || !defined(HAVE_CONFIG_H)
36# include <memory.h>
37#endif
38#if HAVE_STRING_H || !defined(HAVE_CONFIG_H)
39# include <string.h>
40#endif
41#if HAVE_STRINGS_H
42# include <strings.h>
43#endif
44
45#include <errno.h>
46#include <sys/stat.h>
47
48#ifdef FALSE
49#undef FALSE
50#endif
51#ifdef TRUE
52#undef TRUE
53#endif
54#define FALSE 0
55#define TRUE 1
56
57#if HAVE_MEMSET || !defined(HAVE_CONFIG_H)
58# define xdgZeroMemory(p, n) memset(p, 0, n)
59#elif HAVE_BZERO
60# define xdgZeroMemory(p, n) bzero(p, n)
61#else
62static void xdgZeroMemory(void* p, int n)
63{
64 while (n > 0) { ((char*)p)[n] = 0; ++n; }
65}
66#endif
67
68#if defined _WIN32 && !defined __CYGWIN__
69 /* Use Windows separators on all _WIN32 defining
70 environments, except Cygwin. */
71# define DIR_SEPARATOR_CHAR '\\'
72# define DIR_SEPARATOR_STR "\\"
73# define PATH_SEPARATOR_CHAR ';'
74# define PATH_SEPARATOR_STR ";"
75# define NO_ESCAPES_IN_PATHS
76#else
77# define DIR_SEPARATOR_CHAR '/'
78# define DIR_SEPARATOR_STR "/"
79# define PATH_SEPARATOR_CHAR ':'
80# define PATH_SEPARATOR_STR ":"
81# define NO_ESCAPES_IN_PATHS
82#endif
83
84#include <basedir.h>
85#include <basedir_fs.h>
86
87#ifndef MAX
88#define MAX(a, b) ((b) > (a) ? (b) : (a))
89#endif
90
91static const char
92 DefaultRelativeDataHome[] = DIR_SEPARATOR_STR ".local" DIR_SEPARATOR_STR "share",
93 DefaultRelativeConfigHome[] = DIR_SEPARATOR_STR ".config",
94 DefaultDataDirectories1[] = DIR_SEPARATOR_STR "usr" DIR_SEPARATOR_STR "local" DIR_SEPARATOR_STR "share",
95 DefaultDataDirectories2[] = DIR_SEPARATOR_STR "usr" DIR_SEPARATOR_STR "share",
96 DefaultConfigDirectories[] = DIR_SEPARATOR_STR "etc" DIR_SEPARATOR_STR "xdg",
97 DefaultRelativeCacheHome[] = DIR_SEPARATOR_STR ".cache";
98
99static const char
100 *DefaultDataDirectoriesList[] = { DefaultDataDirectories1, DefaultDataDirectories2, NULL },
101 *DefaultConfigDirectoriesList[] = { DefaultConfigDirectories, NULL };
102
103typedef struct _xdgCachedData
104{
105 char * dataHome;
106 char * configHome;
107 char * cacheHome;
108 char * runtimeDirectory;
109 /* Note: string lists are null-terminated and all items */
110 /* except the first are assumed to be allocated using malloc. */
111 /* The first item is assumed to be allocated by malloc only if */
112 /* it is not equal to the appropriate home directory string above. */
113 char ** searchableDataDirectories;
114 char ** searchableConfigDirectories;
115} xdgCachedData;
116
118static xdgCachedData* xdgGetCache(xdgHandle *handle)
119{
120 return ((xdgCachedData*)(handle->reserved));
121}
122
124{
125 if (!handle) return 0;
126 handle->reserved = 0; /* So xdgUpdateData() doesn't free it */
127 if (xdgUpdateData(handle))
128 return handle;
129 return 0;
130}
131
133static void xdgFreeStringList(char** list)
134{
135 char** ptr = list;
136 if (!list) return;
137 for (; *ptr; ptr++)
138 free(*ptr);
139 free(list);
140}
141
143static void xdgFreeData(xdgCachedData *cache)
144{
145 if (cache->dataHome) {
146 /* the first element of the directory lists is usually the home directory */
147 if (cache->searchableDataDirectories && cache->searchableDataDirectories[0] != cache->dataHome)
148 free(cache->dataHome);
149 cache->dataHome = 0;
150 }
151 if (cache->configHome) {
152 if (cache->searchableConfigDirectories && cache->searchableConfigDirectories[0] != cache->configHome)
153 free(cache->configHome);
154 cache->configHome = 0;
155 }
156 if (cache->cacheHome) {
157 free(cache->cacheHome);
158 cache->cacheHome = 0;
159 }
160 if (cache->runtimeDirectory) {
161 free(cache->runtimeDirectory);
162 cache->runtimeDirectory = 0;
163 }
164 xdgFreeStringList(cache->searchableDataDirectories);
165 cache->searchableDataDirectories = 0;
166 xdgFreeStringList(cache->searchableConfigDirectories);
167 cache->searchableConfigDirectories = 0;
168}
169
171{
172 xdgCachedData* cache = xdgGetCache(handle);
173 xdgFreeData(cache);
174 free(cache);
175}
176
180static char** xdgSplitPath(const char* string)
181{
182 unsigned int size, i, j, k;
183 char** itemlist;
184
185 /* Get the number of paths */
186 size=2; /* One item more than seperators + terminating null item */
187 for (i = 0; string[i]; ++i)
188 {
189#ifndef NO_ESCAPES_IN_PATHS
190 if (string[i] == '\\' && string[i+1])
191 {
192 /* skip escaped characters including seperators */
193 ++i;
194 continue;
195 }
196#endif
197 if (string[i] == PATH_SEPARATOR_CHAR) ++size;
198 }
199
200 if (!(itemlist = (char**)malloc(sizeof(char*)*size))) return 0;
201 xdgZeroMemory(itemlist, sizeof(char*)*size);
202
203 for (i = 0; *string; ++i)
204 {
205 /* get length of current string */
206 for (j = 0; string[j] && string[j] != PATH_SEPARATOR_CHAR; ++j)
207#ifndef NO_ESCAPES_IN_PATHS
208 if (string[j] == '\\' && string[j+1]) ++j
209#endif
210 ;
211
212 if (!(itemlist[i] = (char*)malloc(j+1))) { xdgFreeStringList(itemlist); return 0; }
213
214 /* transfer string, unescaping any escaped seperators */
215 for (k = j = 0; string[j] && string[j] != PATH_SEPARATOR_CHAR; ++j, ++k)
216 {
217#ifndef NO_ESCAPES_IN_PATHS
218 if (string[j] == '\\' && string[j+1] == PATH_SEPARATOR_CHAR) ++j; /* replace escaped ':' with just ':' */
219 else if (string[j] == '\\' && string[j+1]) /* skip escaped characters so escaping remains aligned to pairs. */
220 {
221 itemlist[i][k]=string[j];
222 ++j, ++k;
223 }
224#endif
225 itemlist[i][k] = string[j];
226 }
227 itemlist[i][k] = 0; /* Bugfix provided by Diego 'Flameeyes' Pettenò */
228 /* move to next string */
229 string += j;
230 if (*string == PATH_SEPARATOR_CHAR) string++; /* skip seperator */
231 }
232 return itemlist;
233}
234
240static char** xdgGetPathListEnv(const char* name, const char ** defaults)
241{
242 const char* env;
243 char* item;
244 char** itemlist;
245 int i, size;
246
247 env = getenv(name);
248 if (env && env[0])
249 {
250 if (!(item = (char*)malloc(strlen(env)+1))) return NULL;
251 strcpy(item, env);
252
253 itemlist = xdgSplitPath(item);
254 free(item);
255 }
256 else
257 {
258 if (!defaults) return NULL;
259 for (size = 0; defaults[size]; ++size) ; ++size;
260 if (!(itemlist = (char**)malloc(sizeof(char*)*size))) return NULL;
261 xdgZeroMemory(itemlist, sizeof(char*)*(size));
262
263 /* Copy defaults into itemlist. */
264 /* Why all this funky stuff? So the result can be handled uniformly by xdgFreeStringList. */
265 for (i = 0; defaults[i]; ++i)
266 {
267 if (!(item = (char*)malloc(strlen(defaults[i])+1))) { xdgFreeStringList(itemlist); return NULL; }
268 strcpy(item, defaults[i]);
269 itemlist[i] = item;
270 }
271 }
272 return itemlist;
273}
274
280static char* xdgGetEnv(const char *name)
281{
282 char *env = getenv(name);
283 if (env && env[0])
284 return env;
285 /* What errno signifies missing env var? */
286 errno = EINVAL;
287 return NULL;
288}
289
295static char* xdgEnvDup(const char *name)
296{
297 const char *env;
298 if ((env = xdgGetEnv(name)))
299 return strdup(env);
300 else
301 return NULL;
302}
303
308static int xdgUpdateHomeDirectories(xdgCachedData* cache)
309{
310 const char *homeenv;
311 char *value;
312 unsigned int homelen;
313 static const unsigned int extralen =
314 MAX(MAX(sizeof(DefaultRelativeDataHome),
315 sizeof(DefaultRelativeConfigHome)),
316 sizeof(DefaultRelativeCacheHome));
317
318 if (!(cache->dataHome = xdgEnvDup("XDG_DATA_HOME")) && errno == ENOMEM) return FALSE;
319 if (!(cache->configHome = xdgEnvDup("XDG_CONFIG_HOME")) && errno == ENOMEM) return FALSE;
320 if (!(cache->cacheHome = xdgEnvDup("XDG_CACHE_HOME")) && errno == ENOMEM) return FALSE;
321 if (!(cache->runtimeDirectory = xdgEnvDup("XDG_RUNTIME_DIR")) && errno == ENOMEM) return FALSE;
322 errno = 0;
323
324 if (cache->dataHome && cache->configHome && cache->cacheHome) return TRUE;
325
326 if (!(homeenv = xdgGetEnv("HOME"))) {
327 cache->dataHome = NULL;
328 cache->configHome = NULL;
329 cache->cacheHome = NULL;
330 return TRUE;
331 }
332
333 /* Allocate maximum needed for any of the 3 default values */
334 if (!(value = (char*)malloc((homelen = strlen(homeenv))+extralen))) return FALSE;
335 memcpy(value, homeenv, homelen+1);
336
337 if (!cache->dataHome)
338 {
339 memcpy(value+homelen, DefaultRelativeDataHome, sizeof(DefaultRelativeDataHome));
340 cache->dataHome = strdup(value);
341 }
342
343 if (!cache->configHome)
344 {
345 memcpy(value+homelen, DefaultRelativeConfigHome, sizeof(DefaultRelativeConfigHome));
346 cache->configHome = strdup(value);
347 }
348
349 if (!cache->cacheHome)
350 {
351 memcpy(value+homelen, DefaultRelativeCacheHome, sizeof(DefaultRelativeCacheHome));
352 cache->cacheHome = strdup(value);
353 }
354
355 free(value);
356
357 /* free does not change errno, and the prev call *must* have been a strdup,
358 * so errno is already set. */
359 return cache->dataHome && cache->configHome && cache->cacheHome;
360}
361
373static char** xdgGetDirectoryLists(const char *envname, char *homedir, const char **defaults)
374{
375 char **envlist;
376 char **dirlist;
377 unsigned int size;
378
379 if (!(envlist = xdgGetPathListEnv(envname, defaults)))
380 return NULL;
381
382 for (size = 0; envlist[size]; size++) ; /* Get list size */
383 if (!(dirlist = (char**)malloc(sizeof(char*)*(size+1+!!homedir))))
384 {
385 xdgFreeStringList(envlist);
386 return NULL;
387 }
388 /* "home" directory has highest priority according to spec */
389 if (homedir)
390 dirlist[0] = homedir;
391 memcpy(dirlist+!!homedir, envlist, sizeof(char*)*(size+1));
392 /* only free the envlist since its elements are now referenced by dirlist */
393 free(envlist);
394
395 return dirlist;
396}
397
402static int xdgUpdateDirectoryLists(xdgCachedData* cache)
403{
404 if (!(cache->searchableDataDirectories = xdgGetDirectoryLists(
405 "XDG_DATA_DIRS", cache->dataHome, DefaultDataDirectoriesList)))
406 return FALSE;
407 if (!(cache->searchableConfigDirectories = xdgGetDirectoryLists(
408 "XDG_CONFIG_DIRS", cache->configHome, DefaultConfigDirectoriesList)))
409 return FALSE;
410
411 return TRUE;
412}
413
415{
416 xdgCachedData* cache = (xdgCachedData*)malloc(sizeof(xdgCachedData));
417 xdgCachedData* oldCache;
418 if (!cache) return FALSE;
419 xdgZeroMemory(cache, sizeof(xdgCachedData));
420
421 if (xdgUpdateHomeDirectories(cache) &&
423 {
424 /* Update successful, replace pointer to old cache with pointer to new cache */
425 oldCache = xdgGetCache(handle);
426 handle->reserved = cache;
427 if (oldCache)
428 {
429 xdgFreeData(oldCache);
430 free(oldCache);
431 }
432 return TRUE;
433 }
434 else
435 {
436 /* Update failed, discard new cache and leave old cache unmodified */
437 xdgFreeData(cache);
438 free(cache);
439 return FALSE;
440 }
441}
442
449static char * xdgFindExisting(const char * relativePath, const char * const * dirList)
450{
451 char * fullPath;
452 char * returnString = 0;
453 char * tmpString;
454 int strLen = 0;
455 FILE * testFile;
456 const char * const * item;
457
458 for (item = dirList; *item; item++)
459 {
460 if (!(fullPath = (char*)malloc(strlen(*item)+strlen(relativePath)+2)))
461 {
462 if (returnString) free(returnString);
463 return 0;
464 }
465 strcpy(fullPath, *item);
466 if (fullPath[strlen(fullPath)-1] != DIR_SEPARATOR_CHAR)
467 strcat(fullPath, DIR_SEPARATOR_STR);
468 strcat(fullPath, relativePath);
469 testFile = fopen(fullPath, "r");
470 if (testFile)
471 {
472 if (!(tmpString = (char*)realloc(returnString, strLen+strlen(fullPath)+2)))
473 {
474 free(returnString);
475 free(fullPath);
476 return 0;
477 }
478 returnString = tmpString;
479 strcpy(&returnString[strLen], fullPath);
480 strLen = strLen+strlen(fullPath)+1;
481 fclose(testFile);
482 }
483 free(fullPath);
484 }
485 if (returnString)
486 returnString[strLen] = 0;
487 else
488 {
489 if ((returnString = (char*)malloc(2)))
490 strcpy(returnString, "\0");
491 }
492 return returnString;
493}
494
501static FILE * xdgFileOpen(const char * relativePath, const char * mode, const char * const * dirList)
502{
503 char * fullPath;
504 FILE * testFile;
505 const char * const * item;
506
507 for (item = dirList; *item; item++)
508 {
509 if (!(fullPath = (char*)malloc(strlen(*item)+strlen(relativePath)+2)))
510 return 0;
511 strcpy(fullPath, *item);
512 if (fullPath[strlen(fullPath)-1] != DIR_SEPARATOR_CHAR)
513 strcat(fullPath, DIR_SEPARATOR_STR);
514 strcat(fullPath, relativePath);
515 testFile = fopen(fullPath, mode);
516 free(fullPath);
517 if (testFile)
518 return testFile;
519 }
520 return 0;
521}
522
523int xdgMakePath(const char * path, mode_t mode)
524{
525 int length = strlen(path);
526 char * tmpPath;
527 char * tmpPtr;
528 int ret;
529
530 if (length == 0 || (length == 1 && path[0] == DIR_SEPARATOR_CHAR))
531 return 0;
532
533 if (!(tmpPath = (char*)malloc(length+1)))
534 {
535 errno = ENOMEM;
536 return -1;
537 }
538 strcpy(tmpPath, path);
539 if (tmpPath[length-1] == DIR_SEPARATOR_CHAR)
540 tmpPath[length-1] = '\0';
541
542 /* skip tmpPath[0] since if it's a seperator we have an absolute path */
543 for (tmpPtr = tmpPath+1; *tmpPtr; ++tmpPtr)
544 {
545 if (*tmpPtr == DIR_SEPARATOR_CHAR)
546 {
547 *tmpPtr = '\0';
548 if (mkdir(tmpPath, mode) == -1)
549 {
550 if (errno != EEXIST)
551 {
552 free(tmpPath);
553 return -1;
554 }
555 }
556 *tmpPtr = DIR_SEPARATOR_CHAR;
557 }
558 }
559 ret = mkdir(tmpPath, mode);
560 free(tmpPath);
561 return ret;
562}
563
572static char * xdgGetRelativeHome(const char *envname, const char *relativefallback, unsigned int fallbacklength)
573{
574 char *relhome;
575 if (!(relhome = xdgEnvDup(envname)) && errno != ENOMEM)
576 {
577 errno = 0;
578 const char *home;
579 unsigned int homelen;
580 if (!(home = xdgGetEnv("HOME")))
581 return NULL;
582 if (!(relhome = (char*)malloc((homelen = strlen(home))+fallbacklength+1))) return NULL;
583 memcpy(relhome, home, homelen);
584 memcpy(relhome+homelen, relativefallback, fallbacklength+1);
585 }
586 return relhome;
587}
588
589const char * xdgDataHome(xdgHandle *handle)
590{
591 if (handle)
592 return xdgGetCache(handle)->dataHome;
593 else
594 return xdgGetRelativeHome("XDG_DATA_HOME", DefaultRelativeDataHome, sizeof(DefaultRelativeDataHome)-1);
595}
596const char * xdgConfigHome(xdgHandle *handle)
597{
598 if (handle)
599 return xdgGetCache(handle)->configHome;
600 else
601 return xdgGetRelativeHome("XDG_CONFIG_HOME", DefaultRelativeConfigHome, sizeof(DefaultRelativeConfigHome)-1);
602}
603const char * const * xdgDataDirectories(xdgHandle *handle)
604{
605 if (handle)
606 return (const char * const *)&(xdgGetCache(handle)->searchableDataDirectories[1]);
607 else
608 return (const char * const *)xdgGetDirectoryLists("XDG_DATA_DIRS", NULL, DefaultDataDirectoriesList);
609}
610const char * const * xdgSearchableDataDirectories(xdgHandle *handle)
611{
612 if (handle)
613 return (const char * const *)xdgGetCache(handle)->searchableDataDirectories;
614 else
615 {
616 char *datahome = (char*)xdgDataHome(NULL);
617 char **datadirs = xdgGetDirectoryLists("XDG_DATA_DIRS", datahome, DefaultDataDirectoriesList);
618 if (datahome && !datadirs)
619 free(datahome);
620 return (const char * const *)datadirs;
621 }
622}
623const char * const * xdgConfigDirectories(xdgHandle *handle)
624{
625 if (handle)
626 return (const char * const *)&(xdgGetCache(handle)->searchableConfigDirectories[1]);
627 else
628 return (const char * const *)xdgGetDirectoryLists("XDG_CONFIG_DIRS", NULL, DefaultConfigDirectoriesList);
629}
630const char * const * xdgSearchableConfigDirectories(xdgHandle *handle)
631{
632 if (handle)
633 return (const char * const *)xdgGetCache(handle)->searchableConfigDirectories;
634 else
635 {
636 char *confighome = (char*)xdgConfigHome(NULL);
637 char **configdirs = xdgGetDirectoryLists("XDG_CONFIG_DIRS", confighome, DefaultConfigDirectoriesList);
638 if (confighome && !configdirs)
639 free(confighome);
640 return (const char * const *)configdirs;
641 }
642}
643const char * xdgCacheHome(xdgHandle *handle)
644{
645 if (handle)
646 return xdgGetCache(handle)->cacheHome;
647 else
648 return xdgGetRelativeHome("XDG_CACHE_HOME", DefaultRelativeCacheHome, sizeof(DefaultRelativeCacheHome)-1);
649}
650const char * xdgRuntimeDirectory(xdgHandle *handle)
651{
652 if (handle)
653 return xdgGetCache(handle)->runtimeDirectory;
654 else
655 return xdgEnvDup("XDG_RUNTIME_DIRECTORY");
656}
657char * xdgDataFind(const char * relativePath, xdgHandle *handle)
658{
659 const char * const * dirs = xdgSearchableDataDirectories(handle);
660 char * result = xdgFindExisting(relativePath, dirs);
661 if (!handle) xdgFreeStringList((char**)dirs);
662 return result;
663}
664char * xdgConfigFind(const char * relativePath, xdgHandle *handle)
665{
666 const char * const * dirs = xdgSearchableConfigDirectories(handle);
667 char * result = xdgFindExisting(relativePath, dirs);
668 if (!handle) xdgFreeStringList((char**)dirs);
669 return result;
670}
671FILE * xdgDataOpen(const char * relativePath, const char * mode, xdgHandle *handle)
672{
673 const char * const * dirs = xdgSearchableDataDirectories(handle);
674 FILE * result = xdgFileOpen(relativePath, mode, dirs);
675 if (!handle) xdgFreeStringList((char**)dirs);
676 return result;
677}
678FILE * xdgConfigOpen(const char * relativePath, const char * mode, xdgHandle *handle)
679{
680 const char * const * dirs = xdgSearchableConfigDirectories(handle);
681 FILE * result = xdgFileOpen(relativePath, mode, dirs);
682 if (!handle) xdgFreeStringList((char**)dirs);
683 return result;
684}
685
int xdgMakePath(const char *path, mode_t mode)
Create path by recursively creating directories.
Definition basedir.c:523
static FILE * xdgFileOpen(const char *relativePath, const char *mode, const char *const *dirList)
Open first possible config file corresponding to relativePath.
Definition basedir.c:501
static int xdgUpdateDirectoryLists(xdgCachedData *cache)
Update all *Directories variables of cache.
Definition basedir.c:402
const char * xdgRuntimeDirectory(xdgHandle *handle)
Base directory for user specific non-essential runtime files such as sockets and named pipes.
Definition basedir.c:650
static char * xdgGetEnv(const char *name)
Get value of an environment variable.
Definition basedir.c:280
char * xdgDataFind(const char *relativePath, xdgHandle *handle)
Find all existing data files corresponding to relativePath.
Definition basedir.c:657
static char * xdgFindExisting(const char *relativePath, const char *const *dirList)
Find all existing files corresponding to relativePath relative to each item in dirList.
Definition basedir.c:449
static char ** xdgGetPathListEnv(const char *name, const char **defaults)
Get $PATH-style environment variable as list of strings.
Definition basedir.c:240
const char *const * xdgDataDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for data files in addition to the $XDG_DATA_HOME...
Definition basedir.c:603
const char *const * xdgSearchableConfigDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for configuration files with $XDG_CONFIG_HOME pr...
Definition basedir.c:630
static xdgCachedData * xdgGetCache(xdgHandle *handle)
Get cache object associated with a handle.
Definition basedir.c:118
int xdgUpdateData(xdgHandle *handle)
Update the data cache.
Definition basedir.c:414
const char *const * xdgConfigDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for configuration files in addition to the $XDG_...
Definition basedir.c:623
const char * xdgCacheHome(xdgHandle *handle)
Base directory for user specific non-essential data files.
Definition basedir.c:643
const char * xdgConfigHome(xdgHandle *handle)
Base directory for user specific configuration files.
Definition basedir.c:596
FILE * xdgDataOpen(const char *relativePath, const char *mode, xdgHandle *handle)
Open first possible data file corresponding to relativePath.
Definition basedir.c:671
static char ** xdgSplitPath(const char *string)
Split string at ':', return null-terminated list of resulting strings.
Definition basedir.c:180
static char * xdgGetRelativeHome(const char *envname, const char *relativefallback, unsigned int fallbacklength)
Get a home directory from the environment or a fallback relative to $HOME.
Definition basedir.c:572
static void xdgFreeStringList(char **list)
Free all memory used by a NULL-terminated string list.
Definition basedir.c:133
xdgHandle * xdgInitHandle(xdgHandle *handle)
Initialize a handle to an XDG data cache and initialize the cache.
Definition basedir.c:123
FILE * xdgConfigOpen(const char *relativePath, const char *mode, xdgHandle *handle)
Open first possible config file corresponding to relativePath.
Definition basedir.c:678
static char * xdgEnvDup(const char *name)
Duplicate an environment variable.
Definition basedir.c:295
static void xdgFreeData(xdgCachedData *cache)
Free all data in the cache and set pointers to null.
Definition basedir.c:143
char * xdgConfigFind(const char *relativePath, xdgHandle *handle)
Find all existing config files corresponding to relativePath.
Definition basedir.c:664
const char *const * xdgSearchableDataDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for data files with $XDG_DATA_HOME prepended.
Definition basedir.c:610
static int xdgUpdateHomeDirectories(xdgCachedData *cache)
Update all *Home variables of cache.
Definition basedir.c:308
static char ** xdgGetDirectoryLists(const char *envname, char *homedir, const char **defaults)
Get directory lists with initial home directory.
Definition basedir.c:373
void xdgWipeHandle(xdgHandle *handle)
Wipe handle of XDG data cache.
Definition basedir.c:170
const char * xdgDataHome(xdgHandle *handle)
Base directory for user specific data files.
Definition basedir.c:589
Functions for using the XDG Base Directory specification.
Filesystem functions related to the XDG Base Directory specification.
Handle to XDG data cache.
Definition basedir.h:59
void * reserved
Reserved for internal use, do not modify.
Definition basedir.h:61