Skip to content

Commit c013c5c

Browse files
author
Mamatha Busi
committed
Implementation of XDG File specification.
1 parent ba5134d commit c013c5c

File tree

4 files changed

+186
-0
lines changed

4 files changed

+186
-0
lines changed

CoreFoundation/Base.subproj/CFFileUtilities.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <errno.h>
1616
#include <string.h>
1717
#include <stdio.h>
18+
#include <assert.h>
1819

1920
#if DEPLOYMENT_TARGET_WINDOWS
2021
#include <io.h>
@@ -1166,3 +1167,155 @@ CF_PRIVATE void _CFIterateDirectory(CFStringRef directoryPath, Boolean appendSla
11661167
#endif
11671168
}
11681169

1170+
#if DEPLOYMENT_RUNTIME_SWIFT
1171+
1172+
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
1173+
// Version 0.8
1174+
1175+
// This may not be safe to assume
1176+
#define _kCFXDGStringEncoding kCFStringEncodingUTF8
1177+
1178+
// All paths set in these environment variables must be absolute. If an implementation encounters a relative path in any of these variables it should consider the path invalid and ignore it.
1179+
static CFStringRef _CFXDGCreateHome(void) {
1180+
const char *home = __CFgetenv("HOME");
1181+
if (home && strnlen(home, CFMaxPathSize) > 0) {
1182+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, home, _kCFXDGStringEncoding);
1183+
} else {
1184+
return CFRetain(CFSTR(""));
1185+
}
1186+
}
1187+
1188+
/// a single base directory relative to which user-specific data files should be written. This directory is defined by the environment variable $XDG_DATA_HOME.
1189+
CF_SWIFT_EXPORT
1190+
CFStringRef _CFXDGCreateDataHomePath(void) {
1191+
// $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored. If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used.
1192+
const char *dataHome = __CFgetenv("XDG_DATA_HOME");
1193+
if (dataHome && strnlen(dataHome, CFMaxPathSize) > 1 && dataHome[0] == '/') {
1194+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, dataHome, _kCFXDGStringEncoding);
1195+
} else {
1196+
CFStringRef home = _CFXDGCreateHome();
1197+
CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@/.local/share"), home);
1198+
CFRelease(home);
1199+
return result;
1200+
}
1201+
}
1202+
1203+
/// a single base directory relative to which user-specific configuration files should be written. This directory is defined by the environment variable $XDG_CONFIG_HOME.
1204+
CF_SWIFT_EXPORT
1205+
CFStringRef _CFXDGCreateConfigHomePath(void) {
1206+
// $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored. If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used.
1207+
const char *configHome = __CFgetenv("XDG_CONFIG_HOME");
1208+
if (configHome && strnlen(configHome, CFMaxPathSize) > 1 && configHome[0] == '/') {
1209+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, configHome, _kCFXDGStringEncoding);
1210+
} else {
1211+
CFStringRef home = _CFXDGCreateHome();
1212+
CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@/.config"), home);
1213+
CFRelease(home);
1214+
return result;
1215+
}
1216+
}
1217+
1218+
/// a set of preference ordered base directories relative to which data files should be searched. This set of directories is defined by the environment variable $XDG_DATA_DIRS.
1219+
CF_SWIFT_EXPORT
1220+
CFArrayRef _CFXDGCreateDataDirectoriesPaths(void) {
1221+
// $XDG_DATA_DIRS defines the preference-ordered set of base directories to search for data files in addition to the $XDG_DATA_HOME base directory. The directories in $XDG_DATA_DIRS should be seperated with a colon ':'.
1222+
// If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used.
1223+
const char *dataDirectoriesPaths = __CFgetenv("XDG_DATA_DIRS");
1224+
if ((dataDirectoriesPaths == NULL) || (dataDirectoriesPaths[0] == '\0')) {
1225+
// Environmental variable not set. Return default value.
1226+
CFStringRef defaultPath[2];
1227+
defaultPath[0] = CFStringCreateWithCString(kCFAllocatorSystemDefault, "/usr/local/share/", _kCFXDGStringEncoding);
1228+
defaultPath[1] = CFStringCreateWithCString(kCFAllocatorSystemDefault, "/usr/share/", _kCFXDGStringEncoding);
1229+
return CFArrayCreate(kCFAllocatorSystemDefault, (const void **)defaultPath, 2, &kCFTypeArrayCallBacks);
1230+
}
1231+
return _CFTokenizeStringToCFArrayOfCFStrings(dataDirectoriesPaths, ':');
1232+
}
1233+
1234+
1235+
/// a set of preference ordered base directories relative to which configuration files should be searched. This set of directories is defined by the environment variable $XDG_CONFIG_DIRS.
1236+
CF_SWIFT_EXPORT
1237+
CFArrayRef _CFXDGCreateConfigDirectoriesPaths(void) {
1238+
// $XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for configuration files in addition to the $XDG_CONFIG_HOME base directory. The directories in $XDG_CONFIG_DIRS should be seperated with a colon ':'.
1239+
// If $XDG_CONFIG_DIRS is either not set or empty, a value equal to /etc/xdg should be used.
1240+
const char *configDirectoriesPaths = __CFgetenv("XDG_CONFIG_DIRS");
1241+
if ((configDirectoriesPaths == NULL) || (configDirectoriesPaths[0] == '\0')) {
1242+
//Environmental variable not set. Return default value.
1243+
CFStringRef defaultPath[1];
1244+
defaultPath[0] = CFStringCreateWithCString(kCFAllocatorSystemDefault, "/etc/xdg", _kCFXDGStringEncoding);
1245+
return CFArrayCreate(kCFAllocatorSystemDefault, (const void **)defaultPath, 1, &kCFTypeArrayCallBacks);
1246+
}
1247+
return _CFTokenizeStringToCFArrayOfCFStrings(configDirectoriesPaths, ':');
1248+
}
1249+
1250+
/// a single base directory relative to which user-specific non-essential (cached) data should be written. This directory is defined by the environment variable $XDG_CACHE_HOME.
1251+
CF_SWIFT_EXPORT
1252+
CFStringRef _CFXDGCreateCacheDirectoryPath(void) {
1253+
//$XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored. If $XDG_CACHE_HOME is either not set or empty, a default equal to $HOME/.cache should be used.
1254+
const char *cacheHome = __CFgetenv("XDG_CACHE_HOME");
1255+
const char *path = __CFgetenv("PATH");
1256+
if (cacheHome && strnlen(cacheHome, CFMaxPathSize) > 1 && cacheHome[0] == '/') {
1257+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, cacheHome, _kCFXDGStringEncoding);
1258+
} else {
1259+
CFStringRef home = _CFXDGCreateHome();
1260+
CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@/.cache"), home);
1261+
CFRelease(home);
1262+
return result;
1263+
}
1264+
}
1265+
1266+
/// a single base directory relative to which user-specific runtime files and other file objects should be placed. This directory is defined by the environment variable $XDG_RUNTIME_DIR.
1267+
CF_SWIFT_EXPORT
1268+
CFStringRef _CFXDGCreateRuntimeDirectoryPath(void) {
1269+
const char *runtimeDir = __CFgetenv("XDG_RUNTIME_DIR");
1270+
if (runtimeDir && strnlen(runtimeDir, CFMaxPathSize) > 1 && runtimeDir[0] == '/') {
1271+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, runtimeDir, _kCFXDGStringEncoding);
1272+
} else {
1273+
// If $XDG_RUNTIME_DIR is not set applications should fall back to a replacement directory with similar capabilities and print a warning message.
1274+
return CFStringCreateWithCString(kCFAllocatorSystemDefault, "", _kCFXDGStringEncoding);
1275+
}
1276+
}
1277+
1278+
1279+
CF_PRIVATE CFArrayRef _CFTokenizeStringToCFArrayOfCFStrings(const char *values, char delimiter) {
1280+
size_t pathCount = 0;
1281+
char* tmpDirectoriesPaths = (char*)values;
1282+
char* last_colon = 0;
1283+
// Count how many paths will be extracted.
1284+
while (*tmpDirectoriesPaths)
1285+
{
1286+
if (*tmpDirectoriesPaths == delimiter)
1287+
{
1288+
pathCount++;
1289+
last_colon = tmpDirectoriesPaths;
1290+
}
1291+
tmpDirectoriesPaths++;
1292+
}
1293+
// Add count for trailing path unless ending with colon.
1294+
pathCount += last_colon < (values + strlen(values) - 1);
1295+
if (pathCount > 0)
1296+
{
1297+
size_t validPathCount = 0;
1298+
CFStringRef pathList[pathCount];
1299+
char* copyDirPath = strdup(values);
1300+
char delimiterStr[2];
1301+
delimiterStr[0] = delimiter;
1302+
delimiterStr[1] = '\0';
1303+
char* path = strtok(copyDirPath, delimiterStr);
1304+
while (path)
1305+
{
1306+
assert(validPathCount < pathCount);
1307+
CFStringRef dirPath = CFStringCreateWithCString(kCFAllocatorSystemDefault, strdup(path), _kCFXDGStringEncoding);
1308+
CFStringRef slash = CFSTR("/");
1309+
CFStringRef tilde = CFSTR("~");
1310+
// Check for absolutePath, if not ignore.
1311+
if (CFStringHasPrefix(dirPath, slash) || CFStringHasPrefix(dirPath, tilde) ) {
1312+
pathList[validPathCount++] = dirPath;
1313+
}
1314+
path = strtok(0, delimiterStr);
1315+
}
1316+
return CFArrayCreate(kCFAllocatorSystemDefault, (const void **)pathList, validPathCount, &kCFTypeArrayCallBacks);
1317+
}
1318+
return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks);
1319+
}
1320+
1321+
#endif

CoreFoundation/Base.subproj/CFInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ CF_PRIVATE CFIndex _CFLengthAfterDeletingPathExtension2(CFStringRef path);
602602
CF_EXPORT CFIndex _CFStartOfPathExtension(UniChar *unichars, CFIndex length);
603603
CF_PRIVATE CFIndex _CFStartOfPathExtension2(CFStringRef path);
604604
CF_EXPORT CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars, CFIndex length);
605+
CF_PRIVATE CFArrayRef _CFTokenizeStringToCFArrayOfCFStrings(const char *values, char delimiter);
605606

606607
#if __BLOCKS__
607608
#if DEPLOYMENT_TARGET_WINDOWS

CoreFoundation/Base.subproj/CFRuntime.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,15 @@ static struct {
907907
{"CFNumberDisableCache", NULL},
908908
{"__CFPREFERENCES_AVOID_DAEMON", NULL},
909909
{"APPLE_FRAMEWORKS_ROOT", NULL},
910+
#if DEPLOYMENT_RUNTIME_SWIFT
911+
{"HOME", NULL},
912+
{"XDG_DATA_HOME", NULL},
913+
{"XDG_CONFIG_HOME", NULL},
914+
{"XDG_DATA_DIRS", NULL},
915+
{"XDG_CONFIG_DIRS", NULL},
916+
{"XDG_CACHE_HOME", NULL},
917+
{"XDG_RUNTIME_DIR", NULL},
918+
#endif
910919
{NULL, NULL}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before
911920
};
912921

CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,29 @@ CF_EXPORT _Nullable CFErrorRef _CFReadStreamCopyError(CFReadStreamRef stream);
318318

319319
CF_EXPORT _Nullable CFErrorRef _CFWriteStreamCopyError(CFWriteStreamRef stream);
320320

321+
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
322+
// Version 0.8
323+
324+
// note: All paths set in these environment variables must be absolute.
325+
326+
/// a single base directory relative to which user-specific data files should be written. This directory is defined by the environment variable $XDG_DATA_HOME.
327+
CF_EXPORT CFStringRef _CFXDGCreateDataHomePath(void);
328+
329+
/// a single base directory relative to which user-specific configuration files should be written. This directory is defined by the environment variable $XDG_CONFIG_HOME.
330+
CF_EXPORT CFStringRef _CFXDGCreateConfigHomePath(void);
331+
332+
/// a set of preference ordered base directories relative to which data files should be searched. This set of directories is defined by the environment variable $XDG_DATA_DIRS.
333+
CF_EXPORT CFArrayRef _CFXDGCreateDataDirectoriesPaths(void);
334+
335+
/// a set of preference ordered base directories relative to which configuration files should be searched. This set of directories is defined by the environment variable $XDG_CONFIG_DIRS.
336+
CF_EXPORT CFArrayRef _CFXDGCreateConfigDirectoriesPaths(void);
337+
338+
/// a single base directory relative to which user-specific non-essential (cached) data should be written. This directory is defined by the environment variable $XDG_CACHE_HOME.
339+
CF_EXPORT CFStringRef _CFXDGCreateCacheDirectoryPath(void);
340+
341+
/// a single base directory relative to which user-specific runtime files and other file objects should be placed. This directory is defined by the environment variable $XDG_RUNTIME_DIR.
342+
CF_EXPORT CFStringRef _CFXDGCreateRuntimeDirectoryPath(void);
343+
321344
_CF_EXPORT_SCOPE_END
322345

323346
#endif /* __COREFOUNDATION_FORSWIFTFOUNDATIONONLY__ */

0 commit comments

Comments
 (0)