1995-03-18 17:15:15 +00:00
|
|
|
/* Implementation of NSBundle class
|
1997-01-09 17:01:14 +00:00
|
|
|
Copyright (C) 1993,1994,1995, 1996, 1997 Free Software Foundation, Inc.
|
1995-04-03 20:07:18 +00:00
|
|
|
|
|
|
|
Written by: Adam Fedor <fedor@boulder.colorado.edu>
|
|
|
|
Date: May 1993
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
This file is part of the GNUstep Base Library.
|
1995-04-03 20:07:18 +00:00
|
|
|
|
|
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
#include <config.h>
|
1998-12-20 21:27:47 +00:00
|
|
|
#include <base/preface.h>
|
1995-04-17 21:13:20 +00:00
|
|
|
#include <Foundation/objc-load.h>
|
|
|
|
#include <Foundation/NSBundle.h>
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
#include <Foundation/NSString.h>
|
|
|
|
#include <Foundation/NSArray.h>
|
1998-08-04 10:45:43 +00:00
|
|
|
#include <Foundation/NSDebug.h>
|
1997-01-06 22:30:33 +00:00
|
|
|
#include <Foundation/NSDictionary.h>
|
1996-01-21 01:36:47 +00:00
|
|
|
#include <Foundation/NSProcessInfo.h>
|
1997-01-06 22:30:33 +00:00
|
|
|
#include <Foundation/NSObjCRuntime.h>
|
|
|
|
#include <Foundation/NSUserDefaults.h>
|
|
|
|
#include <Foundation/NSNotification.h>
|
|
|
|
#include <Foundation/NSLock.h>
|
|
|
|
#include <Foundation/NSMapTable.h>
|
1997-10-28 14:34:49 +00:00
|
|
|
#include <Foundation/NSAutoreleasePool.h>
|
1999-04-13 21:56:03 +00:00
|
|
|
#include <Foundation/NSFileManager.h>
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-09 17:01:14 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#ifndef __WIN32__
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/param.h> /* Needed by sys/stat */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* For DIR and diropen() */
|
1997-01-06 22:30:33 +00:00
|
|
|
#if HAVE_DIRENT_H
|
|
|
|
# include <dirent.h>
|
|
|
|
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
|
|
|
#else
|
|
|
|
# define dirent direct
|
|
|
|
# define NAMLEN(dirent) (dirent)->d_namlen
|
|
|
|
# if HAVE_SYS_NDIR_H
|
|
|
|
# include <sys/ndir.h>
|
|
|
|
# endif
|
|
|
|
# if HAVE_SYS_DIR_H
|
|
|
|
# include <sys/dir.h>
|
|
|
|
# endif
|
|
|
|
# if HAVE_NDIR_H
|
|
|
|
# include <ndir.h>
|
|
|
|
# endif
|
1995-03-18 17:15:15 +00:00
|
|
|
#endif
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
typedef enum {
|
|
|
|
NSBUNDLE_BUNDLE = 1, NSBUNDLE_APPLICATION, NSBUNDLE_LIBRARY
|
|
|
|
} bundle_t;
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* Class variables - We keep track of all the bundles */
|
|
|
|
static NSBundle* _mainBundle = nil;
|
|
|
|
static NSMapTable* _bundles = NULL;
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1999-04-23 13:56:22 +00:00
|
|
|
/*
|
|
|
|
* An empty strings file table for use when localization files can't be found.
|
|
|
|
*/
|
|
|
|
static NSDictionary *_emptyTable = nil;
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* This is for bundles that we can't unload, so they shouldn't be
|
|
|
|
dealloced. This is true for all bundles right now */
|
|
|
|
static NSMapTable* _releasedBundles = NULL;
|
1995-03-18 17:15:15 +00:00
|
|
|
|
|
|
|
/* When we are linking in an object file, objc_load_modules calls our
|
1995-04-03 20:07:18 +00:00
|
|
|
callback routine for every Class and Category loaded. The following
|
1995-03-18 17:15:15 +00:00
|
|
|
variable stores the bundle that is currently doing the loading so we know
|
1995-04-03 20:07:18 +00:00
|
|
|
where to store the class names.
|
1995-03-18 17:15:15 +00:00
|
|
|
*/
|
1997-01-06 22:30:33 +00:00
|
|
|
static NSBundle* _loadingBundle = nil;
|
1999-04-22 21:26:10 +00:00
|
|
|
static NSBundle* _gnustep_bundle = nil;
|
1998-05-13 19:25:38 +00:00
|
|
|
static NSRecursiveLock* load_lock = nil;
|
1997-01-06 22:30:33 +00:00
|
|
|
static BOOL _strip_after_loading = NO;
|
|
|
|
|
1997-10-16 23:56:27 +00:00
|
|
|
static NSString* gnustep_target_dir =
|
|
|
|
#ifdef GNUSTEP_TARGET_DIR
|
|
|
|
@GNUSTEP_TARGET_DIR;
|
|
|
|
#else
|
|
|
|
nil;
|
|
|
|
#endif
|
1997-10-30 22:23:50 +00:00
|
|
|
static NSString* gnustep_target_cpu =
|
|
|
|
#ifdef GNUSTEP_TARGET_CPU
|
|
|
|
@GNUSTEP_TARGET_CPU;
|
|
|
|
#else
|
|
|
|
nil;
|
|
|
|
#endif
|
|
|
|
static NSString* gnustep_target_os =
|
|
|
|
#ifdef GNUSTEP_TARGET_OS
|
|
|
|
@GNUSTEP_TARGET_OS;
|
|
|
|
#else
|
|
|
|
nil;
|
|
|
|
#endif
|
1997-10-16 23:56:27 +00:00
|
|
|
static NSString* library_combo =
|
|
|
|
#ifdef LIBRARY_COMBO
|
|
|
|
@LIBRARY_COMBO;
|
|
|
|
#else
|
|
|
|
nil;
|
|
|
|
#endif
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1996-01-21 01:36:47 +00:00
|
|
|
/* Declaration from find_exec.c */
|
|
|
|
extern char *objc_find_executable(const char *name);
|
|
|
|
|
|
|
|
/* This function is provided for objc-load.c, although I'm not sure it
|
|
|
|
really needs it (So far only needed if using GNU dld library) */
|
|
|
|
const char *
|
|
|
|
objc_executable_location( void )
|
|
|
|
{
|
|
|
|
return [[[NSBundle mainBundle] bundlePath] cString];
|
|
|
|
}
|
|
|
|
|
1995-03-18 17:15:15 +00:00
|
|
|
/* Get the object file that should be located in the bundle of the same name */
|
|
|
|
static NSString *
|
1997-01-06 22:30:33 +00:00
|
|
|
bundle_object_name(NSString *path, NSString* executable)
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1999-04-13 21:56:03 +00:00
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
NSString *name, *path0, *path1, *path2;
|
|
|
|
|
|
|
|
if (executable)
|
|
|
|
{
|
|
|
|
NSString *exepath;
|
|
|
|
|
|
|
|
name = [executable lastPathComponent];
|
|
|
|
exepath = [executable stringByDeletingLastPathComponent];
|
|
|
|
if ([exepath isEqualToString: @""] == NO)
|
|
|
|
{
|
|
|
|
if ([exepath isAbsolutePath] == YES)
|
|
|
|
path = exepath;
|
|
|
|
else
|
|
|
|
path = [path stringByAppendingPathComponent: exepath];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = [[path lastPathComponent] stringByDeletingPathExtension];
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
|
|
|
}
|
|
|
|
path0 = [path stringByAppendingPathComponent: name];
|
|
|
|
path = [path stringByAppendingPathComponent: gnustep_target_dir];
|
|
|
|
path1 = [path stringByAppendingPathComponent: name];
|
|
|
|
path = [path stringByAppendingPathComponent: library_combo];
|
|
|
|
path2 = [path stringByAppendingPathComponent: executable];
|
|
|
|
|
|
|
|
if ([mgr isReadableFileAtPath: path2] == YES)
|
|
|
|
return path2;
|
|
|
|
else if ([mgr isReadableFileAtPath: path1] == YES)
|
|
|
|
return path1;
|
|
|
|
else if ([mgr isReadableFileAtPath: path0] == YES)
|
|
|
|
return path0;
|
|
|
|
return path2;
|
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* Construct a path from components */
|
1995-03-18 17:15:15 +00:00
|
|
|
static NSString *
|
1997-01-06 22:30:33 +00:00
|
|
|
_bundle_resource_path(NSString *primary, NSString* bundlePath, NSString *lang)
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
if (bundlePath)
|
|
|
|
primary = [primary stringByAppendingPathComponent: bundlePath];
|
|
|
|
if (lang)
|
|
|
|
primary = [primary stringByAppendingPathComponent:
|
|
|
|
[NSString stringWithFormat: @"%@.lproj", lang]];
|
|
|
|
return primary;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the first directory entry with a given name (with any extension) */
|
|
|
|
static NSString *
|
|
|
|
_bundle_path_for_name(NSString* path, NSString* name)
|
|
|
|
{
|
1997-09-13 17:52:31 +00:00
|
|
|
#ifdef __WIN32__
|
|
|
|
return nil;
|
|
|
|
#else
|
1997-01-06 22:30:33 +00:00
|
|
|
DIR *thedir;
|
|
|
|
struct dirent *entry;
|
|
|
|
NSString *fullname;
|
|
|
|
|
|
|
|
fullname = NULL;
|
|
|
|
thedir = opendir([path cString]);
|
|
|
|
if(thedir)
|
|
|
|
{
|
|
|
|
while ((entry = readdir(thedir)))
|
|
|
|
{
|
1997-01-09 17:01:14 +00:00
|
|
|
if (*(entry->d_name) != '.'
|
1997-01-06 22:30:33 +00:00
|
|
|
&& strncmp([name cString], entry->d_name, [name length]) == 0)
|
|
|
|
{
|
|
|
|
fullname = [NSString stringWithCString: entry->d_name];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(thedir);
|
1995-08-02 16:58:51 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
if (!fullname)
|
|
|
|
return nil;
|
1995-04-03 20:07:18 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
return [path stringByAppendingPathComponent: fullname];
|
1997-09-13 17:52:31 +00:00
|
|
|
#endif
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
@interface NSBundle (Private)
|
|
|
|
- (NSArray *) _bundleClasses;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSBundle (Private)
|
|
|
|
- (NSArray *) _bundleClasses
|
|
|
|
{
|
|
|
|
return _bundleClasses;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
1995-03-18 17:15:15 +00:00
|
|
|
void
|
1995-04-03 21:20:29 +00:00
|
|
|
_bundle_load_callback(Class theClass, Category *theCategory)
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1998-11-19 21:26:27 +00:00
|
|
|
NSCAssert(_loadingBundle, NSInternalInconsistencyException);
|
1997-01-06 22:30:33 +00:00
|
|
|
/* Don't store categories */
|
|
|
|
if (!theCategory)
|
|
|
|
[(NSMutableArray *)[_loadingBundle _bundleClasses] addObject: (id)theClass];
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@implementation NSBundle
|
|
|
|
|
1998-05-13 19:25:38 +00:00
|
|
|
+ (void)initialize
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1998-05-13 19:25:38 +00:00
|
|
|
if (self == [NSBundle class])
|
|
|
|
{
|
1998-08-12 14:41:20 +00:00
|
|
|
NSDictionary *env;
|
|
|
|
|
1999-04-23 13:56:22 +00:00
|
|
|
_emptyTable = RETAIN([NSDictionary dictionary]);
|
|
|
|
|
1998-05-13 19:25:38 +00:00
|
|
|
/* Need to make this recursive since both mainBundle and initWithPath:
|
|
|
|
want to lock the thread */
|
1998-05-15 21:01:11 +00:00
|
|
|
load_lock = [NSRecursiveLock new];
|
1998-08-12 14:41:20 +00:00
|
|
|
env = [[NSProcessInfo processInfo] environment];
|
|
|
|
if (env)
|
|
|
|
{
|
1999-04-22 21:26:10 +00:00
|
|
|
NSMutableString *system;
|
|
|
|
NSString *str;
|
1998-08-12 14:41:20 +00:00
|
|
|
|
1998-08-12 15:07:03 +00:00
|
|
|
if ((str = [env objectForKey: @"GNUSTEP_TARGET_DIR"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_dir = RETAIN(str);
|
1998-08-12 15:07:03 +00:00
|
|
|
else if ((str = [env objectForKey: @"GNUSTEP_HOST_DIR"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_dir = RETAIN(str);
|
1998-08-12 14:41:20 +00:00
|
|
|
|
1998-08-12 15:07:03 +00:00
|
|
|
if ((str = [env objectForKey: @"GNUSTEP_TARGET_CPU"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_cpu = RETAIN(str);
|
1998-08-12 15:07:03 +00:00
|
|
|
else if ((str = [env objectForKey: @"GNUSTEP_HOST_CPU"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_cpu = RETAIN(str);
|
1998-08-12 14:41:20 +00:00
|
|
|
|
1998-08-12 15:07:03 +00:00
|
|
|
if ((str = [env objectForKey: @"GNUSTEP_TARGET_OS"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_os = RETAIN(str);
|
1998-08-12 15:07:03 +00:00
|
|
|
else if ((str = [env objectForKey: @"GNUSTEP_HOST_OS"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_os = RETAIN(str);
|
1998-08-12 14:41:20 +00:00
|
|
|
|
1998-08-12 15:07:03 +00:00
|
|
|
if ((str = [env objectForKey: @"LIBRARY_COMBO"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
library_combo = RETAIN(str);
|
1999-04-22 21:26:10 +00:00
|
|
|
|
1999-04-23 13:56:22 +00:00
|
|
|
system = AUTORELEASE([[env objectForKey: @"GNUSTEP_SYSTEM_ROOT"]
|
|
|
|
mutableCopy]);
|
1999-04-22 21:26:10 +00:00
|
|
|
[system appendString: @"/Libraries"];
|
|
|
|
|
1999-05-11 10:11:48 +00:00
|
|
|
_gnustep_bundle = RETAIN([NSBundle bundleWithPath: system]);
|
1998-08-12 14:41:20 +00:00
|
|
|
}
|
1998-05-13 19:25:38 +00:00
|
|
|
}
|
|
|
|
}
|
1995-08-02 16:58:51 +00:00
|
|
|
|
1998-11-16 19:36:51 +00:00
|
|
|
+ (NSArray *) allBundles
|
|
|
|
{
|
1999-04-14 08:48:32 +00:00
|
|
|
NSMapEnumerator enumerate;
|
|
|
|
NSMutableArray *array = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
void *key;
|
|
|
|
NSBundle *bundle;
|
|
|
|
|
|
|
|
enumerate = NSEnumerateMapTable(_bundles);
|
|
|
|
while (NSNextMapEnumeratorPair(&enumerate, &key, (void **)&bundle))
|
|
|
|
{
|
|
|
|
if ([array indexOfObjectIdenticalTo: bundle] == NSNotFound)
|
|
|
|
{
|
|
|
|
/* FIXME - must ignore frameworks here */
|
|
|
|
[array addObject: bundle];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return array;
|
1998-11-16 19:36:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) allFrameworks
|
|
|
|
{
|
|
|
|
return [self notImplemented: _cmd];
|
|
|
|
}
|
|
|
|
|
1998-05-13 19:25:38 +00:00
|
|
|
+ (NSBundle *)mainBundle
|
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock lock];
|
|
|
|
if ( !_mainBundle )
|
|
|
|
{
|
|
|
|
char *output;
|
1997-10-30 22:23:50 +00:00
|
|
|
NSString *path, *s;
|
1997-01-06 22:30:33 +00:00
|
|
|
|
1999-09-03 08:59:07 +00:00
|
|
|
path = [[[NSProcessInfo processInfo] arguments] objectAtIndex: 0];
|
1997-01-06 22:30:33 +00:00
|
|
|
output = objc_find_executable([path cString]);
|
1998-11-19 21:26:27 +00:00
|
|
|
NSAssert(output, NSInternalInconsistencyException);
|
1997-01-06 22:30:33 +00:00
|
|
|
path = [NSString stringWithCString: output];
|
|
|
|
OBJC_FREE(output);
|
|
|
|
|
|
|
|
/* Strip off the name of the program */
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-10-30 22:23:50 +00:00
|
|
|
/* The executable may not lie in the main bundle directory
|
|
|
|
so we need to chop off the extra subdirectories, the library
|
|
|
|
combo and the target cpu/os if they exist. The executable and
|
|
|
|
this library should match so that is why we can use the
|
|
|
|
compiled-in settings. */
|
|
|
|
/* library combo */
|
|
|
|
s = [path lastPathComponent];
|
|
|
|
if ([s isEqual: library_combo])
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
|
|
|
/* target os */
|
|
|
|
s = [path lastPathComponent];
|
|
|
|
if ([s isEqual: gnustep_target_os])
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
|
|
|
/* target cpu */
|
|
|
|
s = [path lastPathComponent];
|
|
|
|
if ([s isEqual: gnustep_target_cpu])
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
1998-09-03 14:35:49 +00:00
|
|
|
/* object dir */
|
|
|
|
s = [path lastPathComponent];
|
|
|
|
if ([s hasSuffix: @"_obj"])
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
1997-10-30 22:23:50 +00:00
|
|
|
|
1999-03-11 11:07:21 +00:00
|
|
|
NSDebugMLLog(@"NSBundle", @"Found main in %@\n", path);
|
1997-01-06 22:30:33 +00:00
|
|
|
/* We do alloc and init separately so initWithPath: knows
|
|
|
|
we are the _mainBundle */
|
|
|
|
_mainBundle = [NSBundle alloc];
|
|
|
|
_mainBundle = [_mainBundle initWithPath:path];
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
|
|
|
|
[load_lock unlock];
|
|
|
|
return _mainBundle;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* Due to lazy evaluation, we will not find a class if either classNamed: or
|
1995-03-18 17:15:15 +00:00
|
|
|
principalClass has not been called on the particular bundle that contains
|
|
|
|
the class. (FIXME)
|
|
|
|
*/
|
1997-01-06 22:30:33 +00:00
|
|
|
+ (NSBundle *) bundleForClass: (Class)aClass
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
void* key;
|
|
|
|
NSBundle* bundle;
|
|
|
|
NSMapEnumerator enumerate;
|
|
|
|
if (!aClass)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
bundle = nil;
|
|
|
|
enumerate = NSEnumerateMapTable(_bundles);
|
|
|
|
while (NSNextMapEnumeratorPair(&enumerate, &key, (void **)&bundle))
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
j = [[bundle _bundleClasses] indexOfObject: aClass];
|
|
|
|
if (j != NSNotFound && [bundle _bundleClasses])
|
|
|
|
break;
|
|
|
|
bundle = nil;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
if (!bundle)
|
|
|
|
{
|
|
|
|
/* Is it in the main bundle? */
|
|
|
|
if (class_is_class(aClass))
|
|
|
|
bundle = [NSBundle mainBundle];
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
return bundle;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSBundle *)bundleWithPath:(NSString *)path
|
|
|
|
{
|
1999-04-23 13:56:22 +00:00
|
|
|
return AUTORELEASE([[NSBundle alloc] initWithPath: path]);
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- initWithPath:(NSString *)path;
|
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
struct stat statbuf;
|
|
|
|
[super init];
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
if (!path || [path length] == 0)
|
|
|
|
{
|
|
|
|
NSLog(@"No path specified for bundle");
|
|
|
|
return nil;
|
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* Check if we were already initialized for this directory */
|
|
|
|
if (_bundles)
|
|
|
|
{
|
|
|
|
NSBundle* bundle = (NSBundle *)NSMapGet(_bundles, path);
|
|
|
|
if (bundle)
|
|
|
|
{
|
|
|
|
[self dealloc];
|
1999-04-23 13:56:22 +00:00
|
|
|
return RETAIN(bundle); /* retain - look as if we were alloc'ed */
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_releasedBundles)
|
|
|
|
{
|
|
|
|
NSBundle* loaded = (NSBundle *)NSMapGet(_releasedBundles, path);
|
|
|
|
if (loaded)
|
|
|
|
{
|
|
|
|
NSMapInsert(_bundles, path, loaded);
|
|
|
|
NSMapRemove(_releasedBundles, path);
|
|
|
|
[self dealloc];
|
1999-04-23 13:56:22 +00:00
|
|
|
return RETAIN(loaded); /* retain - look as if we were alloc'ed */
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
if (stat([path cString], &statbuf) != 0)
|
|
|
|
{
|
1999-03-11 11:07:21 +00:00
|
|
|
NSDebugMLLog(@"NSBundle", @"Could not access path %s for bundle", [path cString]);
|
1997-09-01 21:59:51 +00:00
|
|
|
//[self dealloc];
|
|
|
|
//return nil;
|
1995-09-21 17:42:46 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock lock];
|
|
|
|
if (!_bundles)
|
|
|
|
{
|
|
|
|
_bundles = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
_releasedBundles = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock unlock];
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
_path = [path copy];
|
|
|
|
_bundleType = (unsigned int)NSBUNDLE_BUNDLE;
|
|
|
|
if (self == _mainBundle)
|
|
|
|
_bundleType = (unsigned int)NSBUNDLE_APPLICATION;
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
NSMapInsert(_bundles, _path, self);
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Some bundles should not be dealloced, such as the main bundle. So we
|
|
|
|
keep track of our own retain count to avoid this.
|
|
|
|
Currently, the objc runtime can't unload modules, so we actually
|
1999-05-07 13:51:37 +00:00
|
|
|
avoid deallocating any bundle with code loaded */
|
1997-01-06 22:30:33 +00:00
|
|
|
- (oneway void) release
|
|
|
|
{
|
1999-05-07 13:51:37 +00:00
|
|
|
if (_codeLoaded == YES || self == _mainBundle || self == _gnustep_bundle)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
1999-05-11 10:11:48 +00:00
|
|
|
if ([self retainCount] == 1)
|
1999-05-07 12:20:35 +00:00
|
|
|
{
|
1999-05-07 13:51:37 +00:00
|
|
|
if (self == NSMapGet(_releasedBundles, _path))
|
|
|
|
{
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
format: @"Bundle for path %@ released too many times", _path];
|
|
|
|
}
|
|
|
|
|
|
|
|
NSMapRemove(_bundles, _path);
|
|
|
|
NSMapInsert(_releasedBundles, _path, self);
|
|
|
|
return;
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
|
|
|
}
|
1997-10-28 14:34:49 +00:00
|
|
|
[super release];
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
if (_path)
|
|
|
|
{
|
|
|
|
NSMapRemove(_bundles, _path);
|
|
|
|
RELEASE(_path);
|
|
|
|
}
|
1999-05-11 10:11:48 +00:00
|
|
|
TEST_RELEASE(_bundleClasses);
|
|
|
|
TEST_RELEASE(_infoDict);
|
|
|
|
TEST_RELEASE(_localizations);
|
1997-01-06 22:30:33 +00:00
|
|
|
[super dealloc];
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (NSString *) bundlePath
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
return _path;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (Class) classNamed: (NSString *)className
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
int j;
|
|
|
|
Class theClass = Nil;
|
|
|
|
if (!_codeLoaded)
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
if (self != _mainBundle && ![self load])
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
|
|
|
NSLog(@"No classes in bundle");
|
|
|
|
return Nil;
|
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
if (self == _mainBundle)
|
|
|
|
{
|
|
|
|
theClass = NSClassFromString(className);
|
|
|
|
if (theClass && [[self class] bundleForClass:theClass] != _mainBundle)
|
|
|
|
theClass = Nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
j = [_bundleClasses indexOfObject: NSClassFromString(className)];
|
|
|
|
if (j != NSNotFound)
|
|
|
|
theClass = [_bundleClasses objectAtIndex: j];
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
|
|
|
|
return theClass;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (Class) principalClass
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
NSString* class_name;
|
|
|
|
|
|
|
|
if (_principalClass)
|
|
|
|
return _principalClass;
|
|
|
|
|
|
|
|
class_name = [[self infoDictionary] objectForKey: @"NSPrincipalClass"];
|
|
|
|
|
|
|
|
if (self == _mainBundle)
|
|
|
|
{
|
|
|
|
_codeLoaded = YES;
|
|
|
|
if (class_name)
|
|
|
|
_principalClass = NSClassFromString(class_name);
|
|
|
|
return _principalClass;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
if ([self load] == NO)
|
|
|
|
return Nil;
|
|
|
|
|
|
|
|
if (class_name)
|
|
|
|
_principalClass = NSClassFromString(class_name);
|
|
|
|
else if ([_bundleClasses count])
|
|
|
|
_principalClass = [_bundleClasses objectAtIndex:0];
|
|
|
|
return _principalClass;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) load
|
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock lock];
|
|
|
|
if (!_codeLoaded)
|
|
|
|
{
|
|
|
|
NSString* object;
|
|
|
|
object = [[self infoDictionary] objectForKey: @"NSExecutable"];
|
|
|
|
object = bundle_object_name(_path, object);
|
|
|
|
_loadingBundle = self;
|
1999-04-23 13:56:22 +00:00
|
|
|
_bundleClasses = RETAIN([NSMutableArray arrayWithCapacity: 2]);
|
1997-01-06 22:30:33 +00:00
|
|
|
if (objc_load_module([object cString],
|
1997-09-01 21:59:51 +00:00
|
|
|
stderr, _bundle_load_callback, NULL, NULL))
|
|
|
|
{
|
|
|
|
[load_lock unlock];
|
|
|
|
return NO;
|
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
_codeLoaded = YES;
|
|
|
|
_loadingBundle = nil;
|
1999-05-07 13:51:37 +00:00
|
|
|
[load_lock unlock];
|
1997-01-06 22:30:33 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
postNotificationName: NSBundleDidLoadNotification
|
|
|
|
object: self
|
|
|
|
userInfo: [NSDictionary dictionaryWithObjects: &_bundleClasses
|
|
|
|
forKeys: &NSLoadedClasses count: 1]];
|
1999-05-07 13:51:37 +00:00
|
|
|
return YES;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock unlock];
|
1997-09-01 21:59:51 +00:00
|
|
|
return YES;
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* This method is the backbone of the resource searching for NSBundle. It
|
|
|
|
constructs an array of paths, where each path is a possible location
|
|
|
|
for a resource in the bundle. The current algorithm for searching goes:
|
|
|
|
|
|
|
|
<main bundle>/Resources/<bundlePath>
|
|
|
|
<main bundle>/Resources/<bundlePath>/<language.lproj>
|
|
|
|
<main bundle>/<bundlePath>
|
|
|
|
<main bundle>/<bundlePath>/<language.lproj>
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
+ (NSArray *) _bundleResourcePathsWithRootPath: (NSString *)rootPath
|
|
|
|
subPath: (NSString *)bundlePath
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
|
|
|
NSString* primary;
|
|
|
|
NSString* language;
|
|
|
|
NSArray* languages;
|
|
|
|
NSMutableArray* array;
|
|
|
|
NSEnumerator* enumerate;
|
|
|
|
|
1997-05-03 17:24:31 +00:00
|
|
|
array = [NSMutableArray arrayWithCapacity: 8];
|
1997-01-06 22:30:33 +00:00
|
|
|
languages = [NSUserDefaults userLanguages];
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
primary = [rootPath stringByAppendingPathComponent: @"Resources"];
|
1997-01-06 22:30:33 +00:00
|
|
|
[array addObject: _bundle_resource_path(primary, bundlePath, nil)];
|
|
|
|
enumerate = [languages objectEnumerator];
|
|
|
|
while ((language = [enumerate nextObject]))
|
|
|
|
[array addObject: _bundle_resource_path(primary, bundlePath, language)];
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
primary = rootPath;
|
1997-01-06 22:30:33 +00:00
|
|
|
[array addObject: _bundle_resource_path(primary, bundlePath, nil)];
|
|
|
|
enumerate = [languages objectEnumerator];
|
|
|
|
while ((language = [enumerate nextObject]))
|
|
|
|
[array addObject: _bundle_resource_path(primary, bundlePath, language)];
|
1997-05-03 17:24:31 +00:00
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
return array;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-05-03 17:17:08 +00:00
|
|
|
+ (NSString *) pathForResource: (NSString *)name
|
1997-01-06 22:30:33 +00:00
|
|
|
ofType: (NSString *)ext
|
1997-09-01 21:59:51 +00:00
|
|
|
inRootPath: (NSString *)rootPath
|
1997-01-06 22:30:33 +00:00
|
|
|
inDirectory: (NSString *)bundlePath
|
1997-09-01 21:59:51 +00:00
|
|
|
withVersion: (int)version
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
NSString *path;
|
|
|
|
NSArray* paths;
|
|
|
|
NSEnumerator* enumerate;
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
if (!name || [name length] == 0)
|
|
|
|
{
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
format: @"No resource name specified."];
|
|
|
|
/* NOT REACHED */
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
paths = [NSBundle _bundleResourcePathsWithRootPath: rootPath
|
|
|
|
subPath: bundlePath];
|
1997-01-06 22:30:33 +00:00
|
|
|
enumerate = [paths objectEnumerator];
|
|
|
|
while((path = [enumerate nextObject]))
|
|
|
|
{
|
|
|
|
NSString* fullpath = nil;
|
|
|
|
|
|
|
|
if (ext && [ext length] != 0)
|
|
|
|
{
|
|
|
|
struct stat statbuf;
|
|
|
|
fullpath = [path stringByAppendingPathComponent:
|
|
|
|
[NSString stringWithFormat: @"%@.%@", name, ext]];
|
|
|
|
if ( stat([fullpath cString], &statbuf) == 0)
|
|
|
|
{
|
1997-11-06 18:26:51 +00:00
|
|
|
if (gnustep_target_os)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
|
|
|
NSString* platpath;
|
|
|
|
platpath = [path stringByAppendingPathComponent:
|
|
|
|
[NSString stringWithFormat: @"%@-%@.%@",
|
1997-11-06 18:26:51 +00:00
|
|
|
name, gnustep_target_os, ext]];
|
1997-01-06 22:30:33 +00:00
|
|
|
if ( stat([platpath cString], &statbuf) == 0)
|
|
|
|
fullpath = platpath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fullpath = nil;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
else
|
|
|
|
{
|
1997-10-18 19:49:50 +00:00
|
|
|
struct stat statbuf;
|
|
|
|
fullpath = [path stringByAppendingPathComponent:
|
|
|
|
[NSString stringWithFormat: @"%@", name]];
|
|
|
|
if ( stat([fullpath cString], &statbuf) == 0)
|
|
|
|
{
|
1997-11-06 18:26:51 +00:00
|
|
|
if (gnustep_target_os)
|
1997-10-18 19:49:50 +00:00
|
|
|
{
|
|
|
|
NSString* platpath;
|
|
|
|
platpath = [path stringByAppendingPathComponent:
|
|
|
|
[NSString stringWithFormat: @"%@-%@",
|
1997-11-06 18:26:51 +00:00
|
|
|
name, gnustep_target_os]];
|
1997-10-18 19:49:50 +00:00
|
|
|
if ( stat([platpath cString], &statbuf) == 0)
|
|
|
|
fullpath = platpath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
1997-10-18 19:49:50 +00:00
|
|
|
fullpath = _bundle_path_for_name(path, name);
|
1997-11-06 18:26:51 +00:00
|
|
|
if (fullpath && gnustep_target_os)
|
1997-10-18 19:49:50 +00:00
|
|
|
{
|
|
|
|
NSString* platpath;
|
|
|
|
platpath = _bundle_path_for_name(path,
|
|
|
|
[NSString stringWithFormat: @"%@-%@",
|
1997-11-06 18:26:51 +00:00
|
|
|
name, gnustep_target_os]);
|
1997-10-18 19:49:50 +00:00
|
|
|
if (platpath)
|
|
|
|
fullpath = platpath;
|
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
if (fullpath)
|
|
|
|
return fullpath;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
+ (NSString *) pathForResource: (NSString *)name
|
|
|
|
ofType: (NSString *)ext
|
|
|
|
inDirectory: (NSString *)bundlePath
|
|
|
|
withVersion: (int) version
|
|
|
|
{
|
|
|
|
return [self pathForResource: name
|
|
|
|
ofType: ext
|
|
|
|
inRootPath: bundlePath
|
|
|
|
inDirectory: nil
|
|
|
|
withVersion: version];
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString *) pathForResource: (NSString *)name
|
|
|
|
ofType: (NSString *)ext
|
|
|
|
inDirectory: (NSString *)bundlePath
|
|
|
|
{
|
|
|
|
return [self pathForResource: name
|
|
|
|
ofType: ext
|
|
|
|
inRootPath: bundlePath
|
|
|
|
inDirectory: nil
|
|
|
|
withVersion: 0];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) pathForResource: (NSString *)name
|
|
|
|
ofType: (NSString *)ext;
|
|
|
|
{
|
|
|
|
return [self pathForResource: name
|
|
|
|
ofType: ext
|
|
|
|
inDirectory: nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) pathForResource: (NSString *)name
|
|
|
|
ofType: (NSString *)ext
|
|
|
|
inDirectory: (NSString *)bundlePath;
|
|
|
|
{
|
|
|
|
return [NSBundle pathForResource: name
|
|
|
|
ofType: ext
|
|
|
|
inRootPath: [self bundlePath]
|
|
|
|
inDirectory: bundlePath
|
|
|
|
withVersion: _version];
|
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (NSArray *) pathsForResourcesOfType: (NSString *)extension
|
1999-04-22 21:01:38 +00:00
|
|
|
inDirectory: (NSString *)bundlePath
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
|
|
|
NSString *path;
|
|
|
|
NSArray* paths;
|
|
|
|
NSMutableArray* resources;
|
|
|
|
NSEnumerator* enumerate;
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
paths = [NSBundle _bundleResourcePathsWithRootPath: [self bundlePath]
|
|
|
|
subPath: bundlePath];
|
1997-01-06 22:30:33 +00:00
|
|
|
enumerate = [paths objectEnumerator];
|
|
|
|
resources = [NSMutableArray arrayWithCapacity: 2];
|
1997-09-13 17:52:31 +00:00
|
|
|
#ifdef __WIN32__
|
|
|
|
#else
|
1997-01-06 22:30:33 +00:00
|
|
|
while((path = [enumerate nextObject]))
|
|
|
|
{
|
|
|
|
DIR *thedir;
|
|
|
|
struct dirent *entry;
|
|
|
|
|
|
|
|
thedir = opendir([path cString]);
|
|
|
|
if (thedir)
|
|
|
|
{
|
|
|
|
while ((entry = readdir(thedir)))
|
|
|
|
{
|
|
|
|
if (*entry->d_name != '.')
|
|
|
|
{
|
|
|
|
char* ext;
|
|
|
|
ext = strrchr(entry->d_name, '.');
|
|
|
|
if (!extension || [extension length] == 0
|
|
|
|
|| (ext && strcmp(++ext, [extension cString]) == 0))
|
|
|
|
[resources addObject:
|
|
|
|
[path stringByAppendingPathComponent:
|
|
|
|
[NSString stringWithCString: entry->d_name]]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(thedir);
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
}
|
1997-09-13 17:52:31 +00:00
|
|
|
#endif
|
1997-01-06 22:30:33 +00:00
|
|
|
return resources;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (NSString *) localizedStringForKey: (NSString *)key
|
1999-04-22 21:01:38 +00:00
|
|
|
value: (NSString *)value
|
|
|
|
table: (NSString *)tableName
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1999-04-22 21:01:38 +00:00
|
|
|
NSDictionary *table;
|
|
|
|
NSString *newString;
|
1997-01-06 22:30:33 +00:00
|
|
|
|
1999-04-23 13:56:22 +00:00
|
|
|
if (_localizations == nil)
|
|
|
|
_localizations = [[NSMutableDictionary alloc] initWithCapacity: 1];
|
|
|
|
|
1999-04-22 21:01:38 +00:00
|
|
|
if (tableName == nil || [tableName isEqualToString: @""] == YES)
|
|
|
|
{
|
|
|
|
tableName = @"Localizable";
|
1999-04-23 13:56:22 +00:00
|
|
|
table = [_localizations objectForKey: tableName];
|
1999-04-22 21:01:38 +00:00
|
|
|
}
|
1999-04-23 13:56:22 +00:00
|
|
|
else if ((table = [_localizations objectForKey: tableName]) == nil
|
|
|
|
&& [@"strings" isEqual: [tableName pathExtension]] == YES)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
1999-04-22 21:01:38 +00:00
|
|
|
tableName = [tableName stringByDeletingPathExtension];
|
1999-04-23 13:56:22 +00:00
|
|
|
table = [_localizations objectForKey: tableName];
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1999-04-22 21:01:38 +00:00
|
|
|
if (table == nil)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
1999-04-23 13:56:22 +00:00
|
|
|
NSString *tablePath;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure we have an empty table in place in case anything
|
|
|
|
* we do somehow causes recursion. The recusive call will look
|
|
|
|
* up the string in the empty table.
|
|
|
|
*/
|
|
|
|
[_localizations setObject: _emptyTable forKey: tableName];
|
1999-04-22 21:01:38 +00:00
|
|
|
|
|
|
|
tablePath = [self pathForResource: tableName ofType: @"strings"];
|
|
|
|
if (tablePath)
|
|
|
|
{
|
|
|
|
NSString *tableContent;
|
|
|
|
|
|
|
|
tableContent = [NSString stringWithContentsOfFile: tablePath];
|
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
table = [tableContent propertyListFromStringsFileFormat];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Failed to parse strings file %@ - %@",
|
|
|
|
tablePath, localException);
|
|
|
|
table = nil;
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
}
|
|
|
|
else
|
|
|
|
NSLog(@"Failed to locate strings file %@", tablePath);
|
|
|
|
|
|
|
|
/*
|
1999-04-23 13:56:22 +00:00
|
|
|
* If we couldn't found and parsed the strings table, we put it in
|
|
|
|
* the cache of strings tables in this bundle, otherwise we will just
|
|
|
|
* be keeping the empty table in the cache so we don't keep retrying.
|
1999-04-22 21:01:38 +00:00
|
|
|
*/
|
1999-04-23 13:56:22 +00:00
|
|
|
if (table != nil)
|
|
|
|
[_localizations setObject: table forKey: tableName];
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1999-04-22 21:01:38 +00:00
|
|
|
|
|
|
|
if (key == nil || (newString = [table objectForKey: key]) == nil)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
1999-04-22 21:01:38 +00:00
|
|
|
NSString *show = [[NSUserDefaults standardUserDefaults]
|
1997-01-06 22:30:33 +00:00
|
|
|
objectForKey: NSShowNonLocalizedStrings];
|
1999-08-01 06:21:15 +00:00
|
|
|
if (show && [show isEqual: @"YES"])
|
1999-04-23 02:54:45 +00:00
|
|
|
{
|
|
|
|
/* It would be bad to localize this string! */
|
|
|
|
NSLog(@"Non-localized string: %@\n", newString);
|
|
|
|
newString = [key uppercaseString];
|
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
else
|
1999-04-22 21:01:38 +00:00
|
|
|
{
|
|
|
|
newString = value;
|
|
|
|
if (newString == nil || [newString isEqualToString: @""] == YES)
|
|
|
|
newString = key;
|
|
|
|
}
|
|
|
|
if (newString == nil)
|
|
|
|
newString = @"";
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
|
|
|
|
1999-04-22 21:01:38 +00:00
|
|
|
return newString;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
+ (void) stripAfterLoading: (BOOL)flag
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
_strip_after_loading = flag;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (NSString *) resourcePath
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
return [_path stringByAppendingPathComponent: @"Resources"];
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (NSDictionary *) infoDictionary
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
NSString* path;
|
1995-04-03 20:07:18 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
if (_infoDict)
|
|
|
|
return _infoDict;
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1998-11-24 03:46:21 +00:00
|
|
|
path = [self pathForResource: @"Info-gnustep" ofType: @"plist"];
|
1997-01-06 22:30:33 +00:00
|
|
|
if (path)
|
|
|
|
_infoDict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
|
|
|
else
|
1999-04-13 21:56:03 +00:00
|
|
|
{
|
|
|
|
path = [self pathForResource: @"Info" ofType: @"plist"];
|
|
|
|
if (path)
|
|
|
|
_infoDict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
|
|
|
else
|
1999-04-23 13:56:22 +00:00
|
|
|
_infoDict = RETAIN([NSDictionary dictionary]);
|
1999-04-13 21:56:03 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
return _infoDict;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-05-03 19:22:17 +00:00
|
|
|
- (unsigned)bundleVersion
|
|
|
|
{
|
|
|
|
return _version;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Since I don't know how version numbers should behave - the version
|
|
|
|
number is not used. (FIXME)
|
|
|
|
*/
|
|
|
|
- (void)setBundleVersion:(unsigned)version
|
|
|
|
{
|
|
|
|
_version = version;
|
|
|
|
}
|
|
|
|
|
1995-03-18 17:15:15 +00:00
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1997-10-18 19:49:50 +00:00
|
|
|
@implementation NSBundle (GNUstep)
|
|
|
|
|
1999-04-22 21:26:10 +00:00
|
|
|
/* These are convenience methods for searching for resource files
|
1997-10-18 19:49:50 +00:00
|
|
|
within the GNUstep directory structure specified by the environment
|
|
|
|
variables. */
|
|
|
|
|
1999-04-22 21:26:10 +00:00
|
|
|
+ (NSBundle *) gnustepBundle
|
|
|
|
{
|
|
|
|
return _gnustep_bundle;
|
|
|
|
}
|
|
|
|
|
1997-10-18 19:49:50 +00:00
|
|
|
+ (NSString *) pathForGNUstepResource: (NSString *)name
|
|
|
|
ofType: (NSString *)ext
|
|
|
|
inDirectory: (NSString *)bundlePath;
|
|
|
|
{
|
1999-04-22 21:26:10 +00:00
|
|
|
NSString *path;
|
|
|
|
NSBundle *user_bundle = nil, *local_bundle = nil;
|
1997-10-18 19:49:50 +00:00
|
|
|
NSProcessInfo *pInfo;
|
|
|
|
NSDictionary *env;
|
1999-04-22 21:26:10 +00:00
|
|
|
NSMutableString *user, *local;
|
1997-10-18 19:49:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
The path of where to search for the resource files
|
|
|
|
is based upon environment variables.
|
|
|
|
GNUSTEP_USER_ROOT
|
|
|
|
GNUSTEP_LOCAL_ROOT
|
|
|
|
GNUSTEP_SYSTEM_ROOT
|
|
|
|
*/
|
|
|
|
pInfo = [NSProcessInfo processInfo];
|
|
|
|
env = [pInfo environment];
|
1999-05-11 10:11:48 +00:00
|
|
|
user = AUTORELEASE([[env objectForKey: @"GNUSTEP_USER_ROOT"] mutableCopy]);
|
1997-10-18 19:49:50 +00:00
|
|
|
[user appendString: @"/Libraries"];
|
1999-05-11 10:11:48 +00:00
|
|
|
local = AUTORELEASE([[env objectForKey: @"GNUSTEP_LOCAL_ROOT"] mutableCopy]);
|
1997-10-18 19:49:50 +00:00
|
|
|
[local appendString: @"/Libraries"];
|
|
|
|
|
|
|
|
if (user)
|
|
|
|
user_bundle = [NSBundle bundleWithPath: user];
|
|
|
|
if (local)
|
|
|
|
local_bundle = [NSBundle bundleWithPath: local];
|
|
|
|
|
|
|
|
/* Gather up the paths */
|
|
|
|
|
|
|
|
/* Search user first */
|
1999-04-22 21:26:10 +00:00
|
|
|
path = [user_bundle pathForResource: name
|
1997-10-18 19:49:50 +00:00
|
|
|
ofType: ext
|
|
|
|
inDirectory: bundlePath];
|
1999-04-22 21:26:10 +00:00
|
|
|
if (path)
|
|
|
|
return path;
|
1997-10-18 19:49:50 +00:00
|
|
|
|
|
|
|
/* Search local second */
|
1999-04-22 21:26:10 +00:00
|
|
|
path = [local_bundle pathForResource: name
|
1997-10-18 19:49:50 +00:00
|
|
|
ofType: ext
|
|
|
|
inDirectory: bundlePath];
|
1999-04-22 21:26:10 +00:00
|
|
|
if (path)
|
|
|
|
return path;
|
1997-10-18 19:49:50 +00:00
|
|
|
|
|
|
|
/* Search system last */
|
1999-04-22 21:26:10 +00:00
|
|
|
path = [_gnustep_bundle pathForResource: name
|
1997-10-18 19:49:50 +00:00
|
|
|
ofType: ext
|
|
|
|
inDirectory: bundlePath];
|
1999-04-22 21:26:10 +00:00
|
|
|
if (path)
|
|
|
|
return path;
|
1997-10-18 19:49:50 +00:00
|
|
|
|
|
|
|
/* Didn't find it */
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-04-14 10:34:56 +00:00
|
|
|
+ (NSString*) _gnustep_target_cpu
|
|
|
|
{
|
|
|
|
return gnustep_target_cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString*) _gnustep_target_dir
|
|
|
|
{
|
|
|
|
return gnustep_target_dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString*) _gnustep_target_os
|
|
|
|
{
|
|
|
|
return gnustep_target_os;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString*) _library_combo
|
|
|
|
{
|
|
|
|
return library_combo;
|
|
|
|
}
|
|
|
|
|
1997-10-18 19:49:50 +00:00
|
|
|
@end
|
1999-04-14 10:34:56 +00:00
|
|
|
|