Skip to content

Commit cedc9d1

Browse files
authored
Merge pull request #963 from ianpartridge/xdg-3.1
2 parents 4556745 + 8c5ed0a commit cedc9d1

File tree

11 files changed

+669
-19
lines changed

11 files changed

+669
-19
lines changed

CoreFoundation/Base.subproj/CFFileUtilities.c

Lines changed: 160 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,162 @@ 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] = CFSTR("/usr/local/share/");
1228+
defaultPath[1] = CFSTR("/usr/share/");
1229+
return CFArrayCreate(kCFAllocatorSystemDefault, (const void **)defaultPath, 2, &kCFTypeArrayCallBacks);
1230+
}
1231+
return _CFCreateCFArrayByTokenizingString(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] = CFSTR("/etc/xdg");
1245+
return CFArrayCreate(kCFAllocatorSystemDefault, (const void **)defaultPath, 1, &kCFTypeArrayCallBacks);
1246+
}
1247+
return _CFCreateCFArrayByTokenizingString(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 _CFCreateCFArrayByTokenizingString(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+
char* pathString = strdup(path);
1308+
CFStringRef dirPath = CFStringCreateWithCString(kCFAllocatorSystemDefault, pathString, _kCFXDGStringEncoding);
1309+
CFStringRef slash = CFSTR("/");
1310+
CFStringRef tilde = CFSTR("~");
1311+
// Check for absolutePath, if not ignore.
1312+
if (CFStringHasPrefix(dirPath, slash) || CFStringHasPrefix(dirPath, tilde) ) {
1313+
pathList[validPathCount++] = dirPath;
1314+
}
1315+
path = strtok(NULL, delimiterStr);
1316+
free(pathString);
1317+
}
1318+
free(copyDirPath);
1319+
CFArrayRef pathArray = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)pathList , validPathCount, &kCFTypeArrayCallBacks);
1320+
for(int i = 0; i < pathCount; i ++) {
1321+
CFRelease(pathList[i]);
1322+
}
1323+
return pathArray;
1324+
}
1325+
return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks);
1326+
}
1327+
1328+
#endif

CoreFoundation/Base.subproj/CFInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ CF_PRIVATE CFIndex _CFLengthAfterDeletingPathExtension2(CFStringRef path);
609609
CF_EXPORT CFIndex _CFStartOfPathExtension(UniChar *unichars, CFIndex length);
610610
CF_PRIVATE CFIndex _CFStartOfPathExtension2(CFStringRef path);
611611
CF_EXPORT CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars, CFIndex length);
612+
CF_PRIVATE CFArrayRef _CFCreateCFArrayByTokenizingString(const char *values, char delimiter);
612613

613614
#if __BLOCKS__
614615
#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
@@ -308,6 +308,29 @@ CF_EXPORT _Nullable CFErrorRef _CFReadStreamCopyError(CFReadStreamRef stream);
308308

309309
CF_EXPORT _Nullable CFErrorRef _CFWriteStreamCopyError(CFWriteStreamRef stream);
310310

311+
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
312+
// Version 0.8
313+
314+
// note: All paths set in these environment variables must be absolute.
315+
316+
/// 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.
317+
CF_EXPORT CFStringRef _CFXDGCreateDataHomePath(void);
318+
319+
/// 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.
320+
CF_EXPORT CFStringRef _CFXDGCreateConfigHomePath(void);
321+
322+
/// 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.
323+
CF_EXPORT CFArrayRef _CFXDGCreateDataDirectoriesPaths(void);
324+
325+
/// 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.
326+
CF_EXPORT CFArrayRef _CFXDGCreateConfigDirectoriesPaths(void);
327+
328+
/// 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.
329+
CF_EXPORT CFStringRef _CFXDGCreateCacheDirectoryPath(void);
330+
331+
/// 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.
332+
CF_EXPORT CFStringRef _CFXDGCreateRuntimeDirectoryPath(void);
333+
311334
_CF_EXPORT_SCOPE_END
312335

313336
#endif /* __COREFOUNDATION_FORSWIFTFOUNDATIONONLY__ */

Foundation.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
0383A1751D2E558A0052E5D1 /* TestNSStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0383A1741D2E558A0052E5D1 /* TestNSStream.swift */; };
1111
1520469B1D8AEABE00D02E36 /* HTTPServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1520469A1D8AEABE00D02E36 /* HTTPServer.swift */; };
12+
159884921DCC877700E3314C /* TestNSHTTPCookieStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159884911DCC877700E3314C /* TestNSHTTPCookieStorage.swift */; };
1213
231503DB1D8AEE5D0061694D /* TestNSDecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 231503DA1D8AEE5D0061694D /* TestNSDecimal.swift */; };
1314
294E3C1D1CC5E19300E4F44C /* TestNSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294E3C1C1CC5E19300E4F44C /* TestNSAttributedString.swift */; };
1415
2EBE67A51C77BF0E006583D5 /* TestNSDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBE67A31C77BF05006583D5 /* TestNSDateFormatter.swift */; };
@@ -464,6 +465,7 @@
464465
/* Begin PBXFileReference section */
465466
0383A1741D2E558A0052E5D1 /* TestNSStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSStream.swift; sourceTree = "<group>"; };
466467
1520469A1D8AEABE00D02E36 /* HTTPServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPServer.swift; sourceTree = "<group>"; };
468+
159884911DCC877700E3314C /* TestNSHTTPCookieStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestNSHTTPCookieStorage.swift; sourceTree = "<group>"; };
467469
22B9C1E01C165D7A00DECFF9 /* TestNSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSDate.swift; sourceTree = "<group>"; };
468470
231503DA1D8AEE5D0061694D /* TestNSDecimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSDecimal.swift; sourceTree = "<group>"; };
469471
294E3C1C1CC5E19300E4F44C /* TestNSAttributedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSAttributedString.swift; sourceTree = "<group>"; };
@@ -1334,6 +1336,7 @@
13341336
EA66F65A1BF1976100136161 /* Tests */ = {
13351337
isa = PBXGroup;
13361338
children = (
1339+
159884911DCC877700E3314C /* TestNSHTTPCookieStorage.swift */,
13371340
D4FE895A1D703D1100DA7986 /* TestURLRequest.swift */,
13381341
C93559281C12C49F009FD6A9 /* TestNSAffineTransform.swift */,
13391342
EA66F63C1BF1619600136161 /* TestNSArray.swift */,
@@ -2228,6 +2231,7 @@
22282231
isa = PBXSourcesBuildPhase;
22292232
buildActionMask = 2147483647;
22302233
files = (
2234+
159884921DCC877700E3314C /* TestNSHTTPCookieStorage.swift in Sources */,
22312235
5FE52C951D147D1C00F7D270 /* TestNSTextCheckingResult.swift in Sources */,
22322236
5B13B3451C582D4C00651CE2 /* TestNSString.swift in Sources */,
22332237
1520469B1D8AEABE00D02E36 /* HTTPServer.swift in Sources */,

0 commit comments

Comments
 (0)