28#if defined(HAVE_CONFIG_H) || defined(_DOXYGEN)
32#if STDC_HEADERS || HAVE_STDLIB_H || !defined(HAVE_CONFIG_H)
35#if HAVE_MEMORY_H || !defined(HAVE_CONFIG_H)
38#if HAVE_STRING_H || !defined(HAVE_CONFIG_H)
57#if HAVE_MEMSET || !defined(HAVE_CONFIG_H)
58# define xdgZeroMemory(p, n) memset(p, 0, n)
60# define xdgZeroMemory(p, n) bzero(p, n)
62static void xdgZeroMemory(
void* p,
int n)
64 while (n > 0) { ((
char*)p)[n] = 0; ++n; }
68#if defined _WIN32 && !defined __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
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
88#define MAX(a, b) ((b) > (a) ? (b) : (a))
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";
100 *DefaultDataDirectoriesList[] = { DefaultDataDirectories1, DefaultDataDirectories2, NULL },
101 *DefaultConfigDirectoriesList[] = { DefaultConfigDirectories, NULL };
103typedef struct _xdgCachedData
108 char * runtimeDirectory;
113 char ** searchableDataDirectories;
114 char ** searchableConfigDirectories;
120 return ((xdgCachedData*)(handle->
reserved));
125 if (!handle)
return 0;
145 if (cache->dataHome) {
147 if (cache->searchableDataDirectories && cache->searchableDataDirectories[0] != cache->dataHome)
148 free(cache->dataHome);
151 if (cache->configHome) {
152 if (cache->searchableConfigDirectories && cache->searchableConfigDirectories[0] != cache->configHome)
153 free(cache->configHome);
154 cache->configHome = 0;
156 if (cache->cacheHome) {
157 free(cache->cacheHome);
158 cache->cacheHome = 0;
160 if (cache->runtimeDirectory) {
161 free(cache->runtimeDirectory);
162 cache->runtimeDirectory = 0;
165 cache->searchableDataDirectories = 0;
167 cache->searchableConfigDirectories = 0;
182 unsigned int size, i, j, k;
187 for (i = 0;
string[i]; ++i)
189#ifndef NO_ESCAPES_IN_PATHS
190 if (
string[i] ==
'\\' &&
string[i+1])
197 if (
string[i] == PATH_SEPARATOR_CHAR) ++size;
200 if (!(itemlist = (
char**)malloc(
sizeof(
char*)*size)))
return 0;
201 xdgZeroMemory(itemlist,
sizeof(
char*)*size);
203 for (i = 0; *string; ++i)
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
212 if (!(itemlist[i] = (
char*)malloc(j+1))) {
xdgFreeStringList(itemlist);
return 0; }
215 for (k = j = 0;
string[j] &&
string[j] != PATH_SEPARATOR_CHAR; ++j, ++k)
217#ifndef NO_ESCAPES_IN_PATHS
218 if (
string[j] ==
'\\' &&
string[j+1] == PATH_SEPARATOR_CHAR) ++j;
219 else if (
string[j] ==
'\\' &&
string[j+1])
221 itemlist[i][k]=
string[j];
225 itemlist[i][k] =
string[j];
230 if (*
string == PATH_SEPARATOR_CHAR)
string++;
250 if (!(item = (
char*)malloc(strlen(env)+1)))
return NULL;
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));
265 for (i = 0; defaults[i]; ++i)
267 if (!(item = (
char*)malloc(strlen(defaults[i])+1))) {
xdgFreeStringList(itemlist);
return NULL; }
268 strcpy(item, defaults[i]);
282 char *env = getenv(name);
312 unsigned int homelen;
313 static const unsigned int extralen =
314 MAX(MAX(
sizeof(DefaultRelativeDataHome),
315 sizeof(DefaultRelativeConfigHome)),
316 sizeof(DefaultRelativeCacheHome));
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;
324 if (cache->dataHome && cache->configHome && cache->cacheHome)
return TRUE;
327 cache->dataHome = NULL;
328 cache->configHome = NULL;
329 cache->cacheHome = NULL;
334 if (!(value = (
char*)malloc((homelen = strlen(homeenv))+extralen)))
return FALSE;
335 memcpy(value, homeenv, homelen+1);
337 if (!cache->dataHome)
339 memcpy(value+homelen, DefaultRelativeDataHome,
sizeof(DefaultRelativeDataHome));
340 cache->dataHome = strdup(value);
343 if (!cache->configHome)
345 memcpy(value+homelen, DefaultRelativeConfigHome,
sizeof(DefaultRelativeConfigHome));
346 cache->configHome = strdup(value);
349 if (!cache->cacheHome)
351 memcpy(value+homelen, DefaultRelativeCacheHome,
sizeof(DefaultRelativeCacheHome));
352 cache->cacheHome = strdup(value);
359 return cache->dataHome && cache->configHome && cache->cacheHome;
382 for (size = 0; envlist[size]; size++) ;
383 if (!(dirlist = (
char**)malloc(
sizeof(
char*)*(size+1+!!homedir))))
390 dirlist[0] = homedir;
391 memcpy(dirlist+!!homedir, envlist,
sizeof(
char*)*(size+1));
405 "XDG_DATA_DIRS", cache->dataHome, DefaultDataDirectoriesList)))
408 "XDG_CONFIG_DIRS", cache->configHome, DefaultConfigDirectoriesList)))
416 xdgCachedData* cache = (xdgCachedData*)malloc(
sizeof(xdgCachedData));
417 xdgCachedData* oldCache;
418 if (!cache)
return FALSE;
419 xdgZeroMemory(cache,
sizeof(xdgCachedData));
452 char * returnString = 0;
456 const char *
const * item;
458 for (item = dirList; *item; item++)
460 if (!(fullPath = (
char*)malloc(strlen(*item)+strlen(relativePath)+2)))
462 if (returnString) free(returnString);
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");
472 if (!(tmpString = (
char*)realloc(returnString, strLen+strlen(fullPath)+2)))
478 returnString = tmpString;
479 strcpy(&returnString[strLen], fullPath);
480 strLen = strLen+strlen(fullPath)+1;
486 returnString[strLen] = 0;
489 if ((returnString = (
char*)malloc(2)))
490 strcpy(returnString,
"\0");
501static FILE *
xdgFileOpen(
const char * relativePath,
const char * mode,
const char *
const * dirList)
505 const char *
const * item;
507 for (item = dirList; *item; item++)
509 if (!(fullPath = (
char*)malloc(strlen(*item)+strlen(relativePath)+2)))
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);
525 int length = strlen(path);
530 if (length == 0 || (length == 1 && path[0] == DIR_SEPARATOR_CHAR))
533 if (!(tmpPath = (
char*)malloc(length+1)))
538 strcpy(tmpPath, path);
539 if (tmpPath[length-1] == DIR_SEPARATOR_CHAR)
540 tmpPath[length-1] =
'\0';
543 for (tmpPtr = tmpPath+1; *tmpPtr; ++tmpPtr)
545 if (*tmpPtr == DIR_SEPARATOR_CHAR)
548 if (mkdir(tmpPath, mode) == -1)
556 *tmpPtr = DIR_SEPARATOR_CHAR;
559 ret = mkdir(tmpPath, mode);
572static char *
xdgGetRelativeHome(
const char *envname,
const char *relativefallback,
unsigned int fallbacklength)
575 if (!(relhome =
xdgEnvDup(envname)) && errno != ENOMEM)
579 unsigned int homelen;
582 if (!(relhome = (
char*)malloc((homelen = strlen(home))+fallbacklength+1)))
return NULL;
583 memcpy(relhome, home, homelen);
584 memcpy(relhome+homelen, relativefallback, fallbacklength+1);
594 return xdgGetRelativeHome(
"XDG_DATA_HOME", DefaultRelativeDataHome,
sizeof(DefaultRelativeDataHome)-1);
601 return xdgGetRelativeHome(
"XDG_CONFIG_HOME", DefaultRelativeConfigHome,
sizeof(DefaultRelativeConfigHome)-1);
606 return (
const char *
const *)&(
xdgGetCache(handle)->searchableDataDirectories[1]);
608 return (
const char *
const *)
xdgGetDirectoryLists(
"XDG_DATA_DIRS", NULL, DefaultDataDirectoriesList);
613 return (
const char *
const *)
xdgGetCache(handle)->searchableDataDirectories;
618 if (datahome && !datadirs)
620 return (
const char *
const *)datadirs;
626 return (
const char *
const *)&(
xdgGetCache(handle)->searchableConfigDirectories[1]);
628 return (
const char *
const *)
xdgGetDirectoryLists(
"XDG_CONFIG_DIRS", NULL, DefaultConfigDirectoriesList);
633 return (
const char *
const *)
xdgGetCache(handle)->searchableConfigDirectories;
637 char **configdirs =
xdgGetDirectoryLists(
"XDG_CONFIG_DIRS", confighome, DefaultConfigDirectoriesList);
638 if (confighome && !configdirs)
640 return (
const char *
const *)configdirs;
648 return xdgGetRelativeHome(
"XDG_CACHE_HOME", DefaultRelativeCacheHome,
sizeof(DefaultRelativeCacheHome)-1);
655 return xdgEnvDup(
"XDG_RUNTIME_DIRECTORY");
674 FILE * result =
xdgFileOpen(relativePath, mode, dirs);
681 FILE * result =
xdgFileOpen(relativePath, mode, dirs);
int xdgMakePath(const char *path, mode_t mode)
Create path by recursively creating directories.
static FILE * xdgFileOpen(const char *relativePath, const char *mode, const char *const *dirList)
Open first possible config file corresponding to relativePath.
static int xdgUpdateDirectoryLists(xdgCachedData *cache)
Update all *Directories variables of cache.
const char * xdgRuntimeDirectory(xdgHandle *handle)
Base directory for user specific non-essential runtime files such as sockets and named pipes.
static char * xdgGetEnv(const char *name)
Get value of an environment variable.
char * xdgDataFind(const char *relativePath, xdgHandle *handle)
Find all existing data files corresponding to relativePath.
static char * xdgFindExisting(const char *relativePath, const char *const *dirList)
Find all existing files corresponding to relativePath relative to each item in dirList.
static char ** xdgGetPathListEnv(const char *name, const char **defaults)
Get $PATH-style environment variable as list of strings.
const char *const * xdgDataDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for data files in addition to the $XDG_DATA_HOME...
const char *const * xdgSearchableConfigDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for configuration files with $XDG_CONFIG_HOME pr...
static xdgCachedData * xdgGetCache(xdgHandle *handle)
Get cache object associated with a handle.
int xdgUpdateData(xdgHandle *handle)
Update the data cache.
const char *const * xdgConfigDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for configuration files in addition to the $XDG_...
const char * xdgCacheHome(xdgHandle *handle)
Base directory for user specific non-essential data files.
const char * xdgConfigHome(xdgHandle *handle)
Base directory for user specific configuration files.
FILE * xdgDataOpen(const char *relativePath, const char *mode, xdgHandle *handle)
Open first possible data file corresponding to relativePath.
static char ** xdgSplitPath(const char *string)
Split string at ':', return null-terminated list of resulting strings.
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.
static void xdgFreeStringList(char **list)
Free all memory used by a NULL-terminated string list.
xdgHandle * xdgInitHandle(xdgHandle *handle)
Initialize a handle to an XDG data cache and initialize the cache.
FILE * xdgConfigOpen(const char *relativePath, const char *mode, xdgHandle *handle)
Open first possible config file corresponding to relativePath.
static char * xdgEnvDup(const char *name)
Duplicate an environment variable.
static void xdgFreeData(xdgCachedData *cache)
Free all data in the cache and set pointers to null.
char * xdgConfigFind(const char *relativePath, xdgHandle *handle)
Find all existing config files corresponding to relativePath.
const char *const * xdgSearchableDataDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for data files with $XDG_DATA_HOME prepended.
static int xdgUpdateHomeDirectories(xdgCachedData *cache)
Update all *Home variables of cache.
static char ** xdgGetDirectoryLists(const char *envname, char *homedir, const char **defaults)
Get directory lists with initial home directory.
void xdgWipeHandle(xdgHandle *handle)
Wipe handle of XDG data cache.
const char * xdgDataHome(xdgHandle *handle)
Base directory for user specific data files.
Functions for using the XDG Base Directory specification.
Filesystem functions related to the XDG Base Directory specification.
Handle to XDG data cache.
void * reserved
Reserved for internal use, do not modify.