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)
62 static 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 };
103 typedef 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));
449 static char *
xdgFindExisting(
const char * relativePath,
const char *
const * dirList)
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");
501 static 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);
572 static 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);