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
62 static 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 
91 static 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 
99 static const char
100  *DefaultDataDirectoriesList[] = { DefaultDataDirectories1, DefaultDataDirectories2, NULL },
101  *DefaultConfigDirectoriesList[] = { DefaultConfigDirectories, NULL };
102 
103 typedef 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 
118 static 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 
133 static 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 
143 static 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 
180 static 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 
240 static 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 
280 static 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 
295 static 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 
308 static 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 
373 static 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 
402 static 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 
449 static 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 
501 static 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 
523 int 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 
572 static 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 
589 const 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 }
596 const 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 }
603 const 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 }
610 const 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 }
623 const 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 }
630 const 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 }
643 const 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 }
650 const char * xdgRuntimeDirectory(xdgHandle *handle)
651 {
652  if (handle)
653  return xdgGetCache(handle)->runtimeDirectory;
654  else
655  return xdgEnvDup("XDG_RUNTIME_DIRECTORY");
656 }
657 char * 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 }
664 char * 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 }
671 FILE * 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 }
678 FILE * 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 
xdgFindExisting
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
xdgEnvDup
static char * xdgEnvDup(const char *name)
Duplicate an environment variable.
Definition: basedir.c:295
xdgDataHome
const char * xdgDataHome(xdgHandle *handle)
Base directory for user specific data files.
Definition: basedir.c:589
xdgSearchableConfigDirectories
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
xdgUpdateData
int xdgUpdateData(xdgHandle *handle)
Update the data cache.
Definition: basedir.c:414
xdgConfigDirectories
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
xdgDataOpen
FILE * xdgDataOpen(const char *relativePath, const char *mode, xdgHandle *handle)
Open first possible data file corresponding to relativePath.
Definition: basedir.c:671
xdgHandle
Handle to XDG data cache.
Definition: basedir.h:59
xdgConfigFind
char * xdgConfigFind(const char *relativePath, xdgHandle *handle)
Find all existing config files corresponding to relativePath.
Definition: basedir.c:664
xdgGetDirectoryLists
static char ** xdgGetDirectoryLists(const char *envname, char *homedir, const char **defaults)
Get directory lists with initial home directory.
Definition: basedir.c:373
xdgGetCache
static xdgCachedData * xdgGetCache(xdgHandle *handle)
Get cache object associated with a handle.
Definition: basedir.c:118
xdgGetRelativeHome
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
basedir_fs.h
xdgUpdateHomeDirectories
static int xdgUpdateHomeDirectories(xdgCachedData *cache)
Update all *Home variables of cache.
Definition: basedir.c:308
xdgFileOpen
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
xdgDataDirectories
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
xdgCacheHome
const char * xdgCacheHome(xdgHandle *handle)
Base directory for user specific non-essential data files.
Definition: basedir.c:643
xdgWipeHandle
void xdgWipeHandle(xdgHandle *handle)
Wipe handle of XDG data cache.
Definition: basedir.c:170
xdgConfigHome
const char * xdgConfigHome(xdgHandle *handle)
Base directory for user specific configuration files.
Definition: basedir.c:596
xdgSearchableDataDirectories
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
xdgMakePath
int xdgMakePath(const char *path, mode_t mode)
Create path by recursively creating directories.
Definition: basedir.c:523
xdgRuntimeDirectory
const char * xdgRuntimeDirectory(xdgHandle *handle)
Base directory for user specific non-essential runtime files such as sockets and named pipes.
Definition: basedir.c:650
xdgGetPathListEnv
static char ** xdgGetPathListEnv(const char *name, const char **defaults)
Get $PATH-style environment variable as list of strings.
Definition: basedir.c:240
xdgDataFind
char * xdgDataFind(const char *relativePath, xdgHandle *handle)
Find all existing data files corresponding to relativePath.
Definition: basedir.c:657
xdgFreeStringList
static void xdgFreeStringList(char **list)
Free all memory used by a NULL-terminated string list.
Definition: basedir.c:133
xdgSplitPath
static char ** xdgSplitPath(const char *string)
Split string at ':', return null-terminated list of resulting strings.
Definition: basedir.c:180
basedir.h
xdgGetEnv
static char * xdgGetEnv(const char *name)
Get value of an environment variable.
Definition: basedir.c:280
xdgHandle::reserved
void * reserved
Reserved for internal use, do not modify.
Definition: basedir.h:61
xdgInitHandle
xdgHandle * xdgInitHandle(xdgHandle *handle)
Initialize a handle to an XDG data cache and initialize the cache.
Definition: basedir.c:123
xdgUpdateDirectoryLists
static int xdgUpdateDirectoryLists(xdgCachedData *cache)
Update all *Directories variables of cache.
Definition: basedir.c:402
xdgConfigOpen
FILE * xdgConfigOpen(const char *relativePath, const char *mode, xdgHandle *handle)
Open first possible config file corresponding to relativePath.
Definition: basedir.c:678
xdgFreeData
static void xdgFreeData(xdgCachedData *cache)
Free all data in the cache and set pointers to null.
Definition: basedir.c:143