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) 56 #if HAVE_MEMSET || !defined(HAVE_CONFIG_H) 57 # define xdgZeroMemory(p, n) memset(p, 0, n) 59 # define xdgZeroMemory(p, n) bzero(p, n) 61 static void xdgZeroMemory(
void* p,
size_t n)
63 while (n > 0) { ((
char*)p)[n] = 0; ++n; }
67 #if defined _WIN32 && !defined __CYGWIN__ 70 # define DIR_SEPARATOR_CHAR '\\' 71 # define DIR_SEPARATOR_STR "\\" 72 # define PATH_SEPARATOR_CHAR ';' 73 # define PATH_SEPARATOR_STR ";" 74 # define NO_ESCAPES_IN_PATHS 76 # define DIR_SEPARATOR_CHAR '/' 77 # define DIR_SEPARATOR_STR "/" 78 # define PATH_SEPARATOR_CHAR ':' 79 # define PATH_SEPARATOR_STR ":" 80 # define NO_ESCAPES_IN_PATHS 87 #define MAX(a, b) ((b) > (a) ? (b) : (a)) 91 DefaultRelativeDataHome[] = DIR_SEPARATOR_STR
".local" DIR_SEPARATOR_STR
"share",
92 DefaultRelativeConfigHome[] = DIR_SEPARATOR_STR
".config",
93 DefaultDataDirectories1[] = DIR_SEPARATOR_STR
"usr" DIR_SEPARATOR_STR
"local" DIR_SEPARATOR_STR
"share",
94 DefaultDataDirectories2[] = DIR_SEPARATOR_STR
"usr" DIR_SEPARATOR_STR
"share",
95 DefaultConfigDirectories[] = DIR_SEPARATOR_STR
"etc" DIR_SEPARATOR_STR
"xdg",
96 DefaultRelativeCacheHome[] = DIR_SEPARATOR_STR
".cache";
99 *DefaultDataDirectoriesList[] = { DefaultDataDirectories1, DefaultDataDirectories2, NULL },
100 *DefaultConfigDirectoriesList[] = { DefaultConfigDirectories, NULL };
102 typedef struct _xdgCachedData
111 char ** searchableDataDirectories;
112 char ** searchableConfigDirectories;
118 return ((xdgCachedData*)(handle->
reserved));
123 if (!handle)
return 0;
143 if (cache->dataHome);
146 if (cache->searchableDataDirectories[0] != cache->dataHome)
147 free(cache->dataHome);
150 if (cache->configHome);
152 if (cache->searchableConfigDirectories[0] != cache->configHome)
153 free(cache->configHome);
154 cache->configHome = 0;
156 if (cache->cacheHome)
158 free(cache->cacheHome);
159 cache->cacheHome = 0;
162 cache->searchableDataDirectories = 0;
164 cache->searchableConfigDirectories = 0;
179 static char*
xdgGetEnv(
const char* name,
const char* defaultValue)
187 if (!(value = (
char*)malloc(strlen(env)+1)))
return 0;
192 if (!(value = (
char*)malloc(strlen(defaultValue)+1)))
return 0;
193 strcpy(value, defaultValue);
203 unsigned int size, i, j, k;
208 for (i = 0;
string[i]; ++i)
210 #ifndef NO_ESCAPES_IN_PATHS 211 if (
string[i] ==
'\\' &&
string[i+1])
218 if (
string[i] == PATH_SEPARATOR_CHAR) ++size;
221 if (!(itemlist = (
char**)malloc(
sizeof(
char*)*size)))
return 0;
222 xdgZeroMemory(itemlist,
sizeof(
char*)*size);
224 for (i = 0; *string; ++i)
227 for (j = 0;
string[j] &&
string[j] != PATH_SEPARATOR_CHAR; ++j)
228 #ifndef NO_ESCAPES_IN_PATHS
229 if (
string[j] ==
'\\' &&
string[j+1]) ++j
233 if (!(itemlist[i] = (
char*)malloc(j+1))) {
xdgFreeStringList(itemlist);
return 0; }
236 for (k = j = 0;
string[j] &&
string[j] != PATH_SEPARATOR_CHAR; ++j, ++k)
238 #ifndef NO_ESCAPES_IN_PATHS 239 if (
string[j] ==
'\\' &&
string[j+1] == PATH_SEPARATOR_CHAR) ++j;
240 else if (
string[j] ==
'\\' &&
string[j+1])
242 itemlist[i][k]=
string[j];
246 itemlist[i][k] =
string[j];
251 if (*
string == PATH_SEPARATOR_CHAR)
string++;
271 if (!(item = (
char*)malloc(strlen(env)+1)))
return NULL;
279 if (!strings)
return NULL;
280 for (size = 0; strings[size]; ++size) ; ++size;
281 if (!(itemlist = (
char**)malloc(
sizeof(
char*)*size)))
return NULL;
282 xdgZeroMemory(itemlist,
sizeof(
char*)*(size));
286 for (i = 0; strings[i]; ++i)
288 if (!(item = (
char*)malloc(strlen(strings[i])+1))) {
xdgFreeStringList(itemlist);
return NULL; }
289 strcpy(item, strings[i]);
305 env = getenv(
"HOME");
308 if (!(home = (
char*)malloc(strlen(env)+1)))
return FALSE;
312 defVal = (
char*)malloc(strlen(home)+
313 MAX(MAX(
sizeof(DefaultRelativeDataHome),
sizeof(DefaultRelativeConfigHome)),
sizeof(DefaultRelativeCacheHome)));
314 if (!defVal)
return FALSE;
316 strcpy(defVal, home);
317 strcat(defVal, DefaultRelativeDataHome);
318 if (!(cache->dataHome =
xdgGetEnv(
"XDG_DATA_HOME", defVal)))
return FALSE;
320 defVal[strlen(home)] = 0;
321 strcat(defVal, DefaultRelativeConfigHome);
322 if (!(cache->configHome =
xdgGetEnv(
"XDG_CONFIG_HOME", defVal)))
return FALSE;
324 defVal[strlen(home)] = 0;
325 strcat(defVal, DefaultRelativeCacheHome);
326 if (!(cache->cacheHome =
xdgGetEnv(
"XDG_CACHE_HOME", defVal)))
return FALSE;
345 if (!itemlist)
return FALSE;
346 for (size = 0; itemlist[size]; size++) ;
347 if (!(cache->searchableDataDirectories = (
char**)malloc(
sizeof(
char*)*(size+2))))
353 cache->searchableDataDirectories[0] = cache->dataHome;
354 memcpy(&(cache->searchableDataDirectories[1]), itemlist,
sizeof(
char*)*(size+1));
358 if (!itemlist)
return FALSE;
359 for (size = 0; itemlist[size]; size++) ;
360 if (!(cache->searchableConfigDirectories = (
char**)malloc(
sizeof(
char*)*(size+2))))
365 cache->searchableConfigDirectories[0] = cache->configHome;
366 memcpy(&(cache->searchableConfigDirectories[1]), itemlist,
sizeof(
char*)*(size+1));
374 xdgCachedData* cache = (xdgCachedData*)malloc(
sizeof(xdgCachedData));
375 xdgCachedData* oldCache;
376 if (!cache)
return FALSE;
377 xdgZeroMemory(cache,
sizeof(xdgCachedData));
407 static char *
xdgFindExisting(
const char * relativePath,
const char *
const * dirList)
410 char * returnString = 0;
414 const char *
const * item;
416 for (item = dirList; *item; item++)
418 if (!(fullPath = (
char*)malloc(strlen(*item)+strlen(relativePath)+2)))
420 if (returnString) free(returnString);
423 strcpy(fullPath, *item);
424 if (fullPath[strlen(fullPath)-1] != DIR_SEPARATOR_CHAR)
425 strcat(fullPath, DIR_SEPARATOR_STR);
426 strcat(fullPath, relativePath);
427 testFile = fopen(fullPath,
"r");
430 if (!(tmpString = (
char*)realloc(returnString, strLen+strlen(fullPath)+2)))
436 returnString = tmpString;
437 strcpy(&returnString[strLen], fullPath);
438 strLen = strLen+strlen(fullPath)+1;
444 returnString[strLen] = 0;
447 if ((returnString = (
char*)malloc(2)))
448 strcpy(returnString,
"\0");
459 static FILE *
xdgFileOpen(
const char * relativePath,
const char * mode,
const char *
const * dirList)
463 const char *
const * item;
465 for (item = dirList; *item; item++)
467 if (!(fullPath = (
char*)malloc(strlen(*item)+strlen(relativePath)+2)))
469 strcpy(fullPath, *item);
470 if (fullPath[strlen(fullPath)-1] != DIR_SEPARATOR_CHAR)
471 strcat(fullPath, DIR_SEPARATOR_STR);
472 strcat(fullPath, relativePath);
473 testFile = fopen(fullPath, mode);
483 int length = strlen(path);
488 if (length == 0 || (length == 1 && path[0] == DIR_SEPARATOR_CHAR))
491 if (!(tmpPath = (
char*)malloc(length+1)))
496 strcpy(tmpPath, path);
497 if (tmpPath[length-1] == DIR_SEPARATOR_CHAR)
498 tmpPath[length-1] =
'\0';
501 for (tmpPtr = tmpPath+1; *tmpPtr; ++tmpPtr)
503 if (*tmpPtr == DIR_SEPARATOR_CHAR)
506 if (mkdir(tmpPath, mode) == -1)
514 *tmpPtr = DIR_SEPARATOR_CHAR;
517 ret = mkdir(tmpPath, mode);
532 return (
const char *
const *)&(
xdgGetCache(handle)->searchableDataDirectories[1]);
536 return (
const char *
const *)
xdgGetCache(handle)->searchableDataDirectories;
540 return (
const char *
const *)&(
xdgGetCache(handle)->searchableConfigDirectories[1]);
544 return (
const char *
const *)
xdgGetCache(handle)->searchableConfigDirectories;
const char * xdgDataHome(xdgHandle *handle)
Base directory for user specific data files.
static int xdgUpdateDirectoryLists(xdgCachedData *cache)
Update all *Directories variables of cache.
const char *const * xdgConfigDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for configuration files in addition to the $XDG_...
void * reserved
Reserved for internal use, do not modify.
FILE * xdgDataOpen(const char *relativePath, const char *mode, xdgHandle *handle)
Open first possible data file corresponding to relativePath.
char * xdgConfigFind(const char *relativePath, xdgHandle *handle)
Find all existing config files corresponding to relativePath.
static xdgCachedData * xdgGetCache(xdgHandle *handle)
Get cache object associated with a handle.
Handle to XDG data cache.
static int xdgUpdateHomeDirectories(xdgCachedData *cache)
Update all *Home variables of cache.
int xdgUpdateData(xdgHandle *handle)
Update the data cache.
const char * xdgCacheHome(xdgHandle *handle)
Base directory for user specific non-essential data files.
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.
Filesystem functions related to the XDG Base Directory specification.
const char *const * xdgSearchableDataDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for data files with $XDG_DATA_HOME prepended...
char * xdgDataFind(const char *relativePath, xdgHandle *handle)
Find all existing data files corresponding to relativePath.
static char * xdgGetEnv(const char *name, const char *defaultValue)
Get value for environment variable $name, defaulting to "defaultValue".
Functions for using the XDG Base Directory specification.
void xdgWipeHandle(xdgHandle *handle)
Wipe handle of XDG data cache.
static char ** xdgGetPathListEnv(const char *name, const char **strings)
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 * xdgConfigHome(xdgHandle *handle)
Base directory for user specific configuration files.
static void xdgFreeStringList(char **list)
Free all memory used by a NULL-terminated string list.
static char ** xdgSplitPath(const char *string)
Split string at ':', return null-terminated list of resulting strings.
static void xdgFreeData(xdgCachedData *cache)
Free all data in the cache and set pointers to null.
static char * xdgFindExisting(const char *relativePath, const char *const *dirList)
Find all existing files corresponding to relativePath relative to each item in dirList.
FILE * xdgConfigOpen(const char *relativePath, const char *mode, xdgHandle *handle)
Open first possible config file corresponding to relativePath.
const char *const * xdgSearchableConfigDirectories(xdgHandle *handle)
Preference-ordered set of base directories to search for configuration files with $XDG_CONFIG_HOME pr...
xdgHandle * xdgInitHandle(xdgHandle *handle)
Initialize a handle to an XDG data cache and initialize the cache.