Index: src/OFSystemInfo.h ================================================================== --- src/OFSystemInfo.h +++ src/OFSystemInfo.h @@ -14,10 +14,12 @@ * file. */ #import "OFObject.h" +@class OFString; + /*! * @class OFSystemInfo OFSystemInfo.h ObjFW/OFSystemInfo.h * * @brief A class for querying information about the system. */ @@ -35,6 +37,32 @@ * A CPU with multiple cores counts as multiple CPUs. * * @return The number of CPUs installed in the system */ + (size_t)numberOfCPUs; + +/*! + * @brief Returns the path where user data for the application can be stored. + * + * On Unix systems, this adheres to the XDG Base Directory specification.@n + * On Mac OS X and iOS, it uses the `NSApplicationSupportDirectory` directory.@n + * On Windows, it uses the `APPDATA` environment variable.@n + * On Haiku, it uses the `B_USER_SETTINGS_DIRECTORY` directory. + * + * @return The path where user data for the application can be stored + */ ++ (OFString*)userDataPath; + +/*! + * @brief Returns the path where user configuration for the application can be + * stored. + * + * On Unix systems, this adheres to the XDG Base Directory specification.@n + * On Mac OS X and iOS, it uses the `Preferences` directory inside of + * `NSLibraryDirectory` directory.@n + * On Windows, it uses the `APPDATA` environment variable.@n + * On Haiku, it uses the `B_USER_SETTINGS_DIRECTORY` directory. + * + * @return The path where user configuration for the application can be stored + */ ++ (OFString*)userConfigPath; @end Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -16,23 +16,38 @@ #define __NO_EXT_QNX #include "config.h" -#import "OFSystemInfo.h" - #include -#ifdef __QNX__ -# include +#import "OFSystemInfo.h" +#import "OFString.h" +#import "OFArray.h" +#import "OFDictionary.h" +#import "OFApplication.h" + +#import "OFNotImplementedException.h" + +#import "autorelease.h" +#import "macros.h" + +#ifdef __APPLE__ +# include #endif #ifdef _WIN32 # include #endif -#import "macros.h" +#ifdef __HAIKU__ +# include +#endif + +#ifdef __QNX__ +# include +#endif static size_t pageSize; static size_t numberOfCPUs; @implementation OFSystemInfo @@ -74,6 +89,165 @@ + (size_t)numberOfCPUs { return numberOfCPUs; } + ++ (OFString*)userDataPath +{ +#if defined(__APPLE__) + void *pool = objc_autoreleasePoolPush(); + char pathC[PATH_MAX]; + NSSearchPathEnumerationState state; + OFMutableString *path; + OFString *home; + + state = NSStartSearchPathEnumeration(NSApplicationSupportDirectory, + NSUserDomainMask); + if (NSGetNextSearchPathEnumeration(state, pathC) == 0) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + path = [OFMutableString stringWithUTF8String: pathC]; + if ([path hasPrefix: @"~"]) { + OFDictionary *env = [OFApplication environment]; + + if ((home = [env objectForKey: @"HOME"]) == nil) + @throw [OFNotImplementedException + exceptionWithSelector: _cmd + object: self]; + + [path deleteCharactersInRange: of_range(0, 1)]; + [path prependString: home]; + } + + [path makeImmutable]; + + [path retain]; + objc_autoreleasePoolPop(pool); + return [path autorelease]; +#elif defined(_WIN32) + void *pool = objc_autoreleasePoolPush(); + OFDictionary *env = [OFApplication environment]; + OFString *appData; + + if ((appData = [env objectForKey: @"APPDATA"]) == nil) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + [appData retain]; + objc_autoreleasePoolPop(pool); + return [appData autorelease]; +#elif defined(__HAIKU__) + char pathC[PATH_MAX]; + + if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, + pathC, PATH_MAX) != B_OK) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + return [OFString stringWithUTF8String: pathC]; +#else + void *pool = objc_autoreleasePoolPush(); + OFDictionary *env = [OFApplication environment]; + OFString *var; + + if ((var = [env objectForKey: @"XDG_DATA_HOME"]) != nil && + [var length] > 0) { + [var retain]; + objc_autoreleasePoolPop(pool); + return [dataHome autorelease]; + } + + if ((var = [env objectForKey: @"HOME"]) == nil) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + var = [OFString pathWithComponents: [OFArray arrayWithObjects: + var, @".local", @"share", nil]]; + + [var retain]; + objc_autoreleasePoolPop(pool); + return [var autorelease]; +#endif +} + ++ (OFString*)userConfigPath +{ +#if defined(__APPLE__) + void *pool = objc_autoreleasePoolPush(); + char pathC[PATH_MAX]; + NSSearchPathEnumerationState state; + OFMutableString *path; + OFString *home; + + state = NSStartSearchPathEnumeration(NSLibraryDirectory, + NSUserDomainMask); + if (NSGetNextSearchPathEnumeration(state, pathC) == 0) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + path = [OFMutableString stringWithUTF8String: pathC]; + if ([path hasPrefix: @"~"]) { + OFDictionary *env = [OFApplication environment]; + + if ((home = [env objectForKey: @"HOME"]) == nil) + @throw [OFNotImplementedException + exceptionWithSelector: _cmd + object: self]; + + [path deleteCharactersInRange: of_range(0, 1)]; + [path prependString: home]; + } + + [path appendString: @"/Preferences"]; + + [path makeImmutable]; + + [path retain]; + objc_autoreleasePoolPop(pool); + return [path autorelease]; +#elif defined(_WIN32) + void *pool = objc_autoreleasePoolPush(); + OFDictionary *env = [OFApplication environment]; + OFString *appData; + + if ((appData = [env objectForKey: @"APPDATA"]) == nil) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + [appData retain]; + objc_autoreleasePoolPop(pool); + return [appData autorelease]; +#elif defined(__HAIKU__) + char pathC[PATH_MAX]; + + if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, + pathC, PATH_MAX) != B_OK) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + return [OFString stringWithUTF8String: pathC]; +#else + void *pool = objc_autoreleasePoolPush(); + OFDictionary *env = [OFApplication environment]; + OFString *var; + + if ((var = [env objectForKey: @"XDG_CONFIG_HOME"]) != nil && + [var length] > 0) { + [var retain]; + objc_autoreleasePoolPop(pool); + return [var autorelease]; + } + + if ((var = [env objectForKey: @"HOME"]) == nil) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + var = [var stringByAppendingPathComponent: @".config"]; + + [var retain]; + objc_autoreleasePoolPop(pool); + return [var autorelease]; +#endif +} @end