/* Implementation of filesystem & path-related functions for GNUstep Copyright (C) 1996-2004 Free Software Foundation, Inc. Written by: Andrew Kachites McCallum Created: May 1996 Rewrite by: Sheldon Gill Date: Jan 2004 This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. NSPathUtilities function reference $Date: 2003/11/30 10:20:26 $ $Revision: 1.84 $ */ /* ======== NSPathUtilities function reference Path utilities provides functions to dynamically discover paths for the platform the application is running on. This avoids the need for hard coding paths, making porting easier and also allowing for places to change without breaking applications. (why do this? Well imagine we're running GNUstep 1 and the new wonderful GNUstep 2 becomes available but we're not sure of it yet. You could install /GNUstep/System2/ and have applications use which ever System you wanted at the time...)

On unix systems, the paths are initialised by reading a configuration file. Usually "/etc/GNUstep/GNUstep.conf". This provides the basic information required by the library to establish all locations required.

On windows, the paths are initialised by reading information from the windows registry.

HKEY_LOCAL_MACHINE\Software\GNU\GNUstep contains the machine wide definititions for system paths.
GNUSTEP_SYSTEM_ROOT GNUSTEP_NETWORK_ROOT GNUSTEP_LOCAL_ROOT See GNUstep File System Heirarchy document for more information and detailed descriptions.
===== end function reference ===== */ /* ==== GNUstep.conf

The master configuration file for GNUstep. System paths are defined by the following: GNUSTEP_SYSTEM_ROOT path in the file heirarchy for system/os things. GNUSTEP_NETWORK_ROOT path to network mounted resources. GNUSTEP_LOCAL_ROOT path for non-system resources for the specific machine.

Paths for each user are defined by the following: USER_GNUSTEP_DIR Path under user's home directory for user specific GNUstep resources (eg. 'GNUstep') USER_GNUSTEP_RC Name of user configuration file (eg. '.GNUsteprc') USER_GNUSTEP_DEFAULTS Name of directory in USER_GNUSTEP_DIR for user defaults files.

Support is provided to locate OS/PLATFORM directories. A conf file may provide the definitions below:
SYS_PREFS Place for system/os preferences (eg. '/etc') SYS_APPS Place for system/os applications (eg. '/bin') SYS_LIBS Place for system/os shared libraries (eg. '/lib') SYS_ADMIN Place for system administration tools (eg. '/sbin') PLATFORM_APPS Place for non-gnustep applications (eg. '/usr/bin') PLATFORM_LIBS Place for application shared libraries (eg. '/usr/lib') PLATFORM_RESOURCES Place for shared application resources (eg. '/usr/share') PLATFORM_ADMIN Place for non-critical administrative tools (eg. '/usr/sbin') PLATFORM_LOCAL_APPS Place for machine local applications (eg. '/usr/local/bin') PLATFORM_LOCAL_LIBS Place for machine local shared libraries (eg. '/usr/local/lib/') PLATFORM_LOCAL_RESOURCES Place for machine local resources. (eg. '/usr/local/share') These add to the path for NSSystemDomainMask, or NSLocalDomainMask as appropriate.

==== */ #include "config.h" #include "GNUstepBase/preface.h" #include "Foundation/NSObjCRuntime.h" #include "Foundation/NSString.h" #include "Foundation/NSPathUtilities.h" #include "Foundation/NSException.h" #include "Foundation/NSArray.h" #include "Foundation/NSDictionary.h" #include "Foundation/NSFileManager.h" #include "Foundation/NSProcessInfo.h" #include "Foundation/NSString.h" #include "Foundation/NSValue.h" #include "Foundation/NSLock.h" #include "Foundation/NSUserDefaults.h" #include "GNUstepBase/GSCategories.h" #include "GSPrivate.h" #ifdef HAVE_UNISTD_H #include // for getuid() #endif #ifdef HAVE_PWD_H #include // for getpwnam() #endif #include #include #ifdef HAVE_GETEUID #define get_user_id() geteuid() #else #define get_user_id() getuid() #endif /* HAVE_GETEUID */ #define lowlevelstringify(X) #X #define stringify(X) lowlevelstringify(X) #if defined(__Win32__) #include "Win32_Utilities.h" void Win32Initialise(void) { Win32InitialiseUtilities(void); } #else #define Win32Initialise() #endif NSDictionary *GSReadStepConfFile(NSString *name); #define PLATFORM_SUPPORT // for NSSearch to find platform specific things /* The global configuration file */ #define GNUSTEP_CONFIGURATION_FILE @"/etc/GNUstep/GNUstep.conf" /* The name of the user-specific configuration file */ #define DEFAULT_STEPRC_FILE @".GNUsteprc" /* The standard path for user Defaults files */ #define DEFAULT_DEFAULTS_PATH @"Defaults" /* The standard path to user GNUstep resources */ #define DEFAULT_USER_ROOT @"GNUstep" /* ------------------ */ /* Internal variables */ /* ------------------ */ static NSFileManager *file_mgr = 0; /* names for the environment or conf-file variables */ //static NSString *USER_ROOT = @"GNUSTEP_USER_ROOT"; static NSString *LOCAL_ROOT = @"GNUSTEP_LOCAL_ROOT"; static NSString *NETWORK_ROOT = @"GNUSTEP_NETWORK_ROOT"; static NSString *SYSTEM_ROOT = @"GNUSTEP_SYSTEM_ROOT"; #ifdef PLATFORM_SUPPORT static NSString *os_sys_prefs = nil; static NSString *os_sys_apps = nil; static NSString *os_sys_libs = nil; static NSString *os_sys_admin = nil; static NSString *platform_resources = nil; static NSString *platform_apps = nil; static NSString *platform_libs = nil; static NSString *platform_admin = nil; static NSString *local_resources = nil; static NSString *local_apps = nil; static NSString *local_libs = nil; /* Keys for Platform support in conf-file. */ #define SYS_APPS @"SYS_APPS" #define SYS_LIBS @"SYS_LIBS" #define SYS_PREFS @"SYS_PREFS" #define SYS_ADMIN @"SYS_ADMIN" #define SYS_RESOURCES @"SYS_RESOURCES" #define PLATFORM_APPS @"PLATFORM_APPS" #define PLATFORM_LIBS @"PLATFORM_LIBS" #define PLATFORM_ADMIN @"PLATFORM_ADMIN" #define PLATFORM_RESOURCES @"PLATFORM_RESOURCES" #define PLATFORM_LOCAL_APPS @"PLATFORM_LOCAL_APPS" #define PLATFORM_LOCAL_LIBS @"PLATFORM_LOCAL_LIBS" #define PLATFORM_LOCAL_ADMIN @"PLATFORM_LOCAL_ADMIN" #define PLATFORM_LOCAL_RESOURCES @"PLATFORM_LOCAL_RESOURCES" #endif /* We read these four paths only once */ static NSString *gnustep_user_root = nil; /* GNUSTEP_USER_ROOT path */ static NSString *gnustep_local_root = nil; /* GNUSTEP_LOCAL_ROOT path */ static NSString *gnustep_network_root = nil; /* GNUSTEP_NETWORK_ROOT path */ static NSString *gnustep_system_root = nil; /* GNUSTEP_SYSTEM_ROOT path */ static NSString *theUserName = nil; static NSString *gnustep_rc_filename = nil; /* .GNUsteprc file name */ static NSString *gnustep_defaultspath = nil; /* Defaults dir in home */ static NSString *gnustep_userpath = nil; /* dir in home for user */ /* Internal function prototypes. */ static NSString* internalise_path(NSString *s); static NSString* internalise_path_Cstring(const char *c); static void set_file_mgr(void); static void set_user_gnustep_path(void); void InitialisePathUtilities(void); void ShutdownPathUtilities(void); /* NOTE: Make the internalise_path() in-line */ /* make sure that the path 'path' is in internal format (unix-style) */ static inline NSString* internalise_path_Cstring(const char *path) { unsigned int len; if (file_mgr == nil) set_file_mgr(); NSCAssert(file_mgr != nil, @"No file manager!\n"); if (path == 0) { return nil; } len = strlen(path); return [file_mgr stringWithFileSystemRepresentation: path length: len]; } /* make sure that the path 's' is in internal format (unix-style) */ static inline NSString* internalise_path(NSString *s) { const char *ptr; unsigned int len; if (file_mgr == nil) set_file_mgr(); NSCAssert(file_mgr != nil, @"No file manager!\n"); if (s == nil) { return nil; } ptr = [s cString]; len = strlen(ptr); return [file_mgr stringWithFileSystemRepresentation: ptr length: len]; } /* Convenience MACRO to ease legibility and coding */ /* Conditionally assign lval to var */ #define test_assign( var, lval) \ if ((var == nil)&&(lval != nil)) \ { \ var = lval; \ } /* Get a path string from a dictionary */ static inline NSString * get_pathconfig(NSDictionary *dict, NSString *key) { NSString *path; NSCParameterAssert(dict!=nil); path = [dict objectForKey: key]; if (path != nil) { path = internalise_path(path); } TEST_RETAIN(path); return path; } /* Set up the file_mgr global. May be called by InitialisePathUtilities or by NSUserDirectory depending on what function is called first. */ static void set_file_mgr(void) { /* Set our file manager (and keep it around) */ file_mgr = [NSFileManager defaultManager]; RETAIN(file_mgr); if (file_mgr == nil) { [NSException raise: NSInternalInconsistencyException format: @"Unable to create default file manager!"]; } } /* Read .GNUsteprc file for user and set paths accordingly */ static void set_user_gnustep_path(void) { NSDictionary *dict; NSString *home; NSString *steprc_file; NSCAssert(file_mgr != nil, @"No file manager\n"); /* Look for rc file (".GNUsteprc") file in user's home directory */ home = NSHomeDirectory(); steprc_file = [home stringByAppendingPathComponent: gnustep_rc_filename]; if ([file_mgr fileExistsAtPath: steprc_file]) { dict = GSReadStepConfFile( steprc_file ); if (dict != nil) { test_assign( gnustep_defaultspath, [dict objectForKey: @"GNUSTEP_DEFAULTS_ROOT"]); test_assign( gnustep_userpath, [dict objectForKey: @"GNUSTEP_USER_ROOT"]); } [dict release]; } gnustep_user_root = [home stringByAppendingPathComponent: gnustep_userpath]; } /* Initialise all things required by this module */ void InitialisePathUtilities(void) { NSDictionary *env; NSDictionary *dict = nil; /* Set up our root paths */ NS_DURING { /* Initialise Win32 things if on that platform */ Win32Initialise(); // should be called by DLL_PROCESS_ATTACH [gnustep_global_lock lock]; /* Set the file manager */ if (file_mgr == nil) set_file_mgr(); /* First we look at the environment */ env = [[NSProcessInfo processInfo] environment]; test_assign(gnustep_system_root , [env objectForKey: SYSTEM_ROOT]); test_assign(gnustep_network_root, [env objectForKey: NETWORK_ROOT]); test_assign(gnustep_local_root , [env objectForKey: LOCAL_ROOT]); #if defined(__WIN32__) // { // HKEY regkey; // // regkey = Win32OpenRegistry(HKEY_LOCAL_MACHINE, // "\\Software\\GNU\\GNUstep"); // if (regkey != nil) // { // test_assign(gnustep_system_root, // Win32NSStringFromRegistry(regkey, SYSTEM_ROOT)); // test_assign(gnustep_network_root, // Win32NSStringFromRegistry(regkey, NETWORK_ROOT)); // test_assign(gnustep_local_root, // Win32NSStringFromRegistry(regkey, LOCAL_ROOT)); // RegCloseKey(regkey); // } // // platform_apps = Win32FindDirectory(CLSID_APPS); // platform_libs = Win32FindDirectory(CLSID_LIBS); // } #endif /* Now we source the configuration file */ dict = GSReadStepConfFile( GNUSTEP_CONFIGURATION_FILE ); if (dict != nil) { test_assign(gnustep_system_root , [dict objectForKey: SYSTEM_ROOT]); test_assign(gnustep_network_root, [dict objectForKey: NETWORK_ROOT]); test_assign(gnustep_local_root , [dict objectForKey: LOCAL_ROOT]); gnustep_rc_filename = [dict objectForKey: @"USER_GNUSTEP_RC"]; gnustep_defaultspath = [dict objectForKey: @"USER_GNUSTEP_DEFAULTS"]; gnustep_userpath = [dict objectForKey: @"USER_GNUSTEP_DIR"]; #ifdef PLATFORM_SUPPORT os_sys_prefs = get_pathconfig(dict, SYS_PREFS); os_sys_apps = get_pathconfig(dict, SYS_APPS ); os_sys_libs = get_pathconfig(dict, SYS_LIBS ); os_sys_admin = get_pathconfig(dict, SYS_ADMIN); platform_resources = get_pathconfig(dict, PLATFORM_RESOURCES); platform_apps = get_pathconfig(dict, PLATFORM_APPS ); platform_libs = get_pathconfig(dict, PLATFORM_LIBS ); platform_admin = get_pathconfig(dict, PLATFORM_ADMIN); local_resources = get_pathconfig(dict, PLATFORM_LOCAL_RESOURCES); local_apps = get_pathconfig(dict, PLATFORM_LOCAL_APPS); local_libs = get_pathconfig(dict, PLATFORM_LOCAL_LIBS); #endif // PLATFORM SUPPORT [dict release]; } test_assign( gnustep_rc_filename, DEFAULT_STEPRC_FILE); test_assign( gnustep_defaultspath, DEFAULT_DEFAULTS_PATH); test_assign( gnustep_userpath, DEFAULT_USER_ROOT); /* If the user has an rc file we need to source it */ set_user_gnustep_path(); /* Make sure that they're in path internal format */ internalise_path(gnustep_system_root); internalise_path(gnustep_network_root); internalise_path(gnustep_local_root); internalise_path(gnustep_user_root); // NSLog(@"System root is '%@'\n",gnustep_system_root); // NSLog(@"Network root is '%@'\n",gnustep_network_root); // NSLog(@"Local root is '%@'\n",gnustep_local_root); // NSLog(@"User root is '%@'\n",gnustep_user_root); /* Finally we check and report problems... */ if (gnustep_system_root == nil) { gnustep_system_root = internalise_path_Cstring( \ stringify(GNUSTEP_INSTALL_PREFIX)); fprintf (stderr, "Warning - GNUSTEP_SYSTEM_ROOT is not set " \ "- using %s\n", [gnustep_system_root lossyCString]); } /* We're keeping these strings... */ TEST_RETAIN(gnustep_system_root); TEST_RETAIN(gnustep_network_root); TEST_RETAIN(gnustep_local_root); TEST_RETAIN(gnustep_user_root); TEST_RETAIN(gnustep_rc_filename); TEST_RETAIN(gnustep_defaultspath); TEST_RETAIN(gnustep_userpath); [gnustep_global_lock unlock]; } NS_HANDLER { if (dict != nil) [dict release]; /* unlock then re-raise the exception */ [gnustep_global_lock unlock]; [localException raise]; } NS_ENDHANDLER } /* close down and release all things allocated. */ void ShutdownPathUtilities(void) { TEST_RELEASE(gnustep_system_root); TEST_RELEASE(gnustep_network_root); TEST_RELEASE(gnustep_local_root); TEST_RELEASE(gnustep_user_root); TEST_RELEASE(gnustep_rc_filename); TEST_RELEASE(gnustep_defaultspath); TEST_RELEASE(gnustep_userpath); #ifdef PLATFORM_SUPPORT TEST_RELEASE(os_sys_prefs); TEST_RELEASE(os_sys_apps); TEST_RELEASE(os_sys_libs); TEST_RELEASE(os_sys_admin); TEST_RELEASE(platform_resources); TEST_RELEASE(platform_apps); TEST_RELEASE(platform_libs); TEST_RELEASE(platform_admin); TEST_RELEASE(local_resources); TEST_RELEASE(local_apps); TEST_RELEASE(local_libs); #endif // PLATFORM SUPPORT TEST_RELEASE(theUserName); RELEASE(file_mgr); } /* ------+---------+---------+---------+---------+---------+---------+---------+ #pragma mark - #pragma mark -- ---------+---------+---------+---------+---------+---------+---------+------- */ /* !!DEPRICATED!! DELETED GS_EXPORT NSString *GSSystemRootDirectory(void); GS_EXPORT NSArray *GSStandardPathPrefixes(void); GSReadStepConfFile & GSFindNamedFile should be in Additions somewhere... */ /** * Reads a file and expects it to be in basic unix "conf" style format with * one key = value per line. Sometimes referred to as "strings" format.
* Creates a dictionary of the (key,value) pairs.
* Lines beginning with a hash '#' are deemed comment lines and ignored.
* The value is all characters from the first non-whitespace after the '=' * until the end of line '\n' which will include any internal spaces.
*/ NSDictionary * GSReadStepConfFile( NSString *fileName ) { NSMutableDictionary *dict; NSString *file; NSArray *lines; unsigned count; dict = [NSMutableDictionary new]; if (dict == nil) { return nil; // should throw an exception?? } file = [NSString stringWithContentsOfFile: fileName]; lines = [file componentsSeparatedByString: @"\n"]; count = [lines count]; while (count-- > 0) { NSRange r; NSString *line; NSString *key; NSString *val; line = [[lines objectAtIndex: count] stringByTrimmingSpaces]; if (([line length]) && ([line characterAtIndex: 0] != '#')) { r = [line rangeOfString: @"="]; if (r.length == 1) { key = [line substringToIndex: r.location]; val = [line substringFromIndex: NSMaxRange(r)]; key = [key stringByTrimmingSpaces]; val = [val stringByTrimmingSpaces]; if ([key length] > 0) [dict setObject: val forKey: key]; } else { key = [line stringByTrimmingSpaces]; val = nil; } } } return dict; } /* See NSPathUtilities.h for description. */ NSString * GSFindNamedFile(NSArray *paths, NSString *aName, NSString *anExtension) { NSFileManager *file_mgr = [NSFileManager defaultManager]; NSString *file_name, *file_path, *path; NSEnumerator *enumerator; NSCParameterAssert(aName != nil); NSCParameterAssert(paths != nil); /* make up the name with extension if given */ if (anExtension != nil) { file_name = [NSString stringWithFormat: @"%@.%@", aName,anExtension]; } else { file_name = aName; } enumerator = [paths objectEnumerator]; while ((path = [enumerator nextObject])) { file_path = [path stringByAppendingPathComponent: file_name ]; if ([file_mgr fileExistsAtPath: file_path] == YES) { return file_path; // Found it! } } return nil; } /* See NSPathUtilities.h for description */ void GSSetUserName(NSString *aName) { NSCParameterAssert([aName length] > 0); /* * Do nothing if it's not a different user. */ if ([theUserName isEqualToString: aName] == YES) { return; } /* * Release the memory */ [gnustep_global_lock lock]; ShutdownPathUtilities(); /* * Reset things as new user */ theUserName = [aName copy]; InitialisePathUtilities(); [NSUserDefaults resetStandardUserDefaults]; [gnustep_global_lock unlock]; } /** * Return the path of the defaults directory for userName.
* This examines the .GNUsteprc file in the home directory of the * user for the GNUSTEP_DEFAULTS_ROOT or the GNUSTEP_USER_ROOT * directory definitions. */ NSString * GSDefaultsRootForUser(NSString *userName) { NSString *home; NSCParameterAssert([userName length] > 0); if (gnustep_system_root == nil) InitialisePathUtilities(); /* * Defaults go into ~/(userpath)/(dafaultspath) */ home = NSHomeDirectoryForUser(userName); home = [home stringByAppendingPathComponent: gnustep_userpath]; home = [home stringByAppendingPathComponent: gnustep_defaultspath]; return internalise_path(home); } /* ------+---------+---------+---------+---------+---------+---------+---------+ #pragma mark - #pragma mark -- ---------+---------+---------+---------+---------+---------+---------+------- */ /** * Returns loginName's home directory as an NSString object. */ /* NOTE FOR DEVELOPERS. * If you change the behavior of this method you must also change * user_home.c in the makefiles package to match. */ NSString * NSHomeDirectoryForUser(NSString *loginName) { #if defined(__WIN32__) NSString *s = nil; s = Win32GetUserProfileDirectory(loginName); return internalise_path(s); #else NSString *s = nil; struct passwd *pw; NSCParameterAssert([loginName length] > 0); [gnustep_global_lock lock]; pw = getpwnam([loginName cString]); if (pw != 0) { s = internalise_path_Cstring(pw->pw_dir); } [gnustep_global_lock unlock]; return s; #endif } /** * Return the caller's home directory as an NSString object. * Calls NSHomeDirectoryForUser() to do this. */ NSString * NSHomeDirectory(void) { return NSHomeDirectoryForUser (NSUserName ()); } /** * Return the caller's login name as an NSString object.
* Under unix-like systems, the name associated with the current * effective user ID is used.
* Under ms-windows, the GetUserName() call is used to find the user name * falling back to the 'LOGNAME' environment.
*/ /* NOTE FOR DEVELOPERS. * If you change the behavior of this method you must also change * user_home.c in the makefiles package to match. */ NSString * NSUserName(void) { const char *loginName = 0; if (theUserName == nil) { #if defined(__WIN32__) char buf[1024]; DWORD n = 1024; /* GetUserName function returns the current user name */ if (GetUserName(buf, &n) != 0 && buf[0] != '\0') loginName = buf; else if (GetEnvironmentVariable("LOGNAME", buf, 1024) != 0 && buf[0] != '\0') loginName = buf; #else struct passwd *pwent; int uid; /* Try looking up the name of the effective user */ uid = get_user_id(); pwent = getpwuid (uid); loginName = pwent->pw_name; #endif /* defined(__Win32__) else */ if (loginName) theUserName = [[NSString alloc] initWithCString: loginName]; else [NSException raise: NSInternalInconsistencyException format: @"Unable to determine current user name"]; } return theUserName; } /** * Returns the full username of the current user. * If unable to determine this, returns the standard user name. */ NSString * NSFullUserName(void) { #if defined(__WIN32__) /* FIXME: Win32 way to get full user name */ return NSUserName(); #else #ifdef HAVE_PWD_H struct passwd *pw; pw = getpwnam([NSUserName() cString]); return [NSString stringWithCString: pw->pw_gecos]; #else NSLog(@"Warning: NSFullUserName not implemented\n"); return NSUserName(); #endif // HAVE_PWD_H #endif // defined(__Win32__) } /* ------+---------+---------+---------+---------+---------+---------+---------+ #pragma mark - #pragma mark -- ---------+---------+---------+---------+---------+---------+---------+------- */ /** * Returns the standard paths in which applications are stored and * should be searched for. Calls NSSearchPathForDirectoriesInDomains()
* Refer to the GNUstep File System Heirarchy documentation for more info. */ NSArray * NSStandardApplicationPaths(void) { return NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory, NSAllDomainsMask, YES); } /** * Returns the standard paths in which resources are stored and * should be searched for. Calls NSSearchPathForDirectoriesInDomains()
* Refer to the GNUstep File System Heirarchy documentation for more info. */ NSArray * NSStandardLibraryPaths(void) { return NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory, NSAllDomainsMask, YES); } /** * DEPRECATED! Don't assume that /System, /Network etc exist in this path!
* Refer to the GNUstep File System Heirarchy documentation for more info. */ NSString *NSOpenStepRootDirectory(void) { return @"/"; } /** * Returns the name of a directory in which temporary files can be stored.
* For unix-like systems this is usually '/tmp'.
* For MS-Windows systems this is the system temporary directory, often '%WINDIR%\TEMP\'.
*/ NSString *NSTemporaryDirectory(void) { NSString *tempDirName = nil; BOOL flag; NSDictionary *env; /* * If the user has supplied a directory name in the TEMP or TMP * environment variable we use that. */ env = [[NSProcessInfo processInfo] environment]; tempDirName = [env objectForKey: @"TEMP"]; if (tempDirName == nil) { tempDirName = [env objectForKey: @"TMP"]; } /* * Windows has a specific function call to find temp */ #if defined(__WIN32__) if (tempDirName == nil) { char buffer[MAX_PATH]; if (GetTempPath(MAX_PATH, buffer)) { tempDirName = internalise_path_Cstring(buffer); } } #endif /* * Fallback to unix standards otherwise. */ if (tempDirName == nil) { tempDirName = @"/tmp"; // standard unix FHS place } /* * Check that the directory exists ... if it doesn't we can't * go any further. */ if ([file_mgr fileExistsAtPath: tempDirName isDirectory: &flag] == NO || flag == NO) { NSLog(@"Temporary directory (%@) does not seem to exist", tempDirName); return nil; } /* * Check that the directory is writable */ if ([file_mgr isWritableFileAtPath: tempDirName] == NO) { NSLog(@"Temporary directory (%@) is not writable", tempDirName); return nil; } return tempDirName; } /** * Returns an array of search paths to look at for resources. */ NSArray * NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directoryKey, NSSearchPathDomainMask domainMask, BOOL expandTilde) { static NSString *adminDir = @"Administrator"; static NSString *appsDir = @"Applications"; static NSString *devDir = @"Developer"; static NSString *demosDir = @"Demos"; static NSString *libraryDir = @"Library"; static NSString *supportDir = @"ApplicationSupport"; static NSString *docDir = @"Documentation"; static NSString *fontsDir = @"Fonts"; static NSString *frameworkDir = @"Frameworks"; static NSString *libsDir = @"Libraries"; static NSString *toolsDir = @"Tools"; NSMutableArray *paths = [NSMutableArray new]; NSString *path; unsigned i; unsigned count; if (gnustep_system_root == nil) InitialisePathUtilities(); NSCAssert(gnustep_system_root != nil,@"Path utilities without initialisation!"); NSCAssert(gnustep_user_root != nil,@"Path utilities without user initialisation!"); NSCAssert(file_mgr != nil,@"Path utilities without file manager!"); /* * The order in which we return paths is important - user must come * first, followed by local, followed by network, followed by system. * The calling code can then loop on the returned paths, and stop as * soon as it finds something. So things in user automatically * override things in system etc. */ /* * FIXME - The following code will not respect this order for * NSAllApplicationsDirectory. This should be fixed I think. */ #define ADD_PATH(mask, base_dir, add_dir) \ if (domainMask & mask) \ { \ path = [base_dir stringByAppendingPathComponent: add_dir]; \ if (path != nil) \ [paths addObject: path]; \ } #ifdef PLATFORM_SUPPORT #define ADD_PLATFORM_PATH(mask, add_dir) \ if (domainMask & mask) \ { \ if (add_dir != nil) \ [paths addObject: add_dir]; \ } #else #define ADD_PLATFORM_PATH(mask, add_dir) #endif // PLATFORM_SUPPORT if (directoryKey == NSApplicationDirectory || directoryKey == NSAllApplicationsDirectory) { ADD_PATH(NSUserDomainMask, gnustep_user_root, appsDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, appsDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, appsDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, appsDir); ADD_PLATFORM_PATH(NSLocalDomainMask, local_apps); ADD_PLATFORM_PATH(NSSystemDomainMask, platform_apps); ADD_PLATFORM_PATH(NSSystemDomainMask, os_sys_apps); } if (directoryKey == NSDemoApplicationDirectory || directoryKey == NSAllApplicationsDirectory) { NSString *devDemosDir = [devDir stringByAppendingPathComponent: demosDir]; ADD_PATH(NSSystemDomainMask, gnustep_system_root, devDemosDir); } if (directoryKey == NSDeveloperApplicationDirectory || directoryKey == NSAllApplicationsDirectory) { NSString *devAppsDir = [devDir stringByAppendingPathComponent: appsDir]; ADD_PATH(NSUserDomainMask, gnustep_user_root, devAppsDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, devAppsDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, devAppsDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, devAppsDir); } if (directoryKey == NSAdminApplicationDirectory || directoryKey == NSAllApplicationsDirectory) { NSString *devAdminDir = [devDir stringByAppendingPathComponent: adminDir]; /* NSUserDomainMask - users have no Administrator directory */ ADD_PATH(NSLocalDomainMask, gnustep_local_root, devAdminDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, devAdminDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, devAdminDir); ADD_PLATFORM_PATH(NSSystemDomainMask, os_sys_admin); ADD_PLATFORM_PATH(NSSystemDomainMask, platform_admin); } if (directoryKey == NSLibraryDirectory || directoryKey == NSAllLibrariesDirectory) { ADD_PATH(NSUserDomainMask, gnustep_user_root, libraryDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, libraryDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, libraryDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, libraryDir); ADD_PLATFORM_PATH(NSLocalDomainMask, local_resources ); ADD_PLATFORM_PATH(NSSystemDomainMask, platform_resources ); } if (directoryKey == NSDeveloperDirectory) { ADD_PATH(NSUserDomainMask, gnustep_local_root, devDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, devDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, devDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, devDir); } if (directoryKey == NSUserDirectory) { if (domainMask & NSUserDomainMask) { [paths addObject: gnustep_user_root]; } } if (directoryKey == NSDocumentationDirectory) { NSString *gsdocDir = [libraryDir stringByAppendingPathComponent: docDir ]; ADD_PATH(NSUserDomainMask, gnustep_user_root, gsdocDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, gsdocDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, gsdocDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, gsdocDir); } /* Now the GNUstep additions */ if (directoryKey == GSApplicationSupportDirectory) { NSString *appSupDir = [libraryDir stringByAppendingPathComponent: supportDir]; ADD_PATH(NSUserDomainMask, gnustep_user_root, appSupDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, appSupDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, appSupDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, appSupDir); } if (directoryKey == GSFrameworksDirectory) { NSString *frameDir = [libraryDir stringByAppendingPathComponent: frameworkDir]; ADD_PATH(NSUserDomainMask, gnustep_user_root, frameDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, frameDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, frameDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, frameDir); } if (directoryKey == GSFontsDirectory) { NSString *fontDir = [libraryDir stringByAppendingPathComponent: fontsDir]; ADD_PATH(NSUserDomainMask, gnustep_user_root, fontDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, fontDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, fontDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, fontDir); } if (directoryKey == GSLibrariesDirectory) { NSString *gslibsDir = [libraryDir stringByAppendingPathComponent: libsDir ]; ADD_PATH(NSUserDomainMask, gnustep_user_root, gslibsDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, gslibsDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, gslibsDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, gslibsDir); ADD_PLATFORM_PATH(NSLocalDomainMask, local_libs); ADD_PLATFORM_PATH(NSSystemDomainMask, platform_libs); ADD_PLATFORM_PATH(NSSystemDomainMask, os_sys_libs); } if (directoryKey == GSToolsDirectory) { ADD_PATH(NSUserDomainMask, gnustep_user_root, toolsDir); ADD_PATH(NSLocalDomainMask, gnustep_local_root, toolsDir); ADD_PATH(NSNetworkDomainMask, gnustep_network_root, toolsDir); ADD_PATH(NSSystemDomainMask, gnustep_system_root, toolsDir); ADD_PLATFORM_PATH(NSLocalDomainMask, local_apps); ADD_PLATFORM_PATH(NSSystemDomainMask, platform_apps); ADD_PLATFORM_PATH(NSSystemDomainMask, os_sys_apps); ADD_PLATFORM_PATH(NSSystemDomainMask, platform_admin); ADD_PLATFORM_PATH(NSSystemDomainMask, os_sys_admin); } #undef ADD_PATH #undef ADD_PLATFORM_PATH count = [paths count]; for (i = 0; i < count; i++) { path = [paths objectAtIndex: i]; // NSLog(@"Path: '%@'\n",path); // remove bad paths if ([file_mgr fileExistsAtPath: path] == NO) { [paths removeObjectAtIndex: i]; i--; count--; } /* * this may look like a performance hit at first glance, but if these * string methods don't alter the string, they return the receiver */ else if (expandTilde == YES) { [paths replaceObjectAtIndex: i withObject: [path stringByExpandingTildeInPath]]; } else { [paths replaceObjectAtIndex: i withObject: [path stringByAbbreviatingWithTildeInPath]]; } } AUTORELEASE (paths); return paths; }