2002-12-03 02:50:07 +00:00
|
|
|
/* GSCompatibility - Extra definitions for compiling on MacOSX
|
|
|
|
|
|
|
|
Copyright (C) 2002 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Written by: Adam Fedor <fedor@gnu.org>
|
2003-01-31 18:25:41 +00:00
|
|
|
Written by: Stephane Corthesy on Sat Nov 16 2002.
|
2002-12-03 02:50:07 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
#include "config.h"
|
2003-01-31 18:25:41 +00:00
|
|
|
#include <objc/objc-class.h>
|
2002-12-03 02:50:07 +00:00
|
|
|
#include "GSCompatibility.h"
|
2003-02-03 15:59:58 +00:00
|
|
|
#include "gnustep/base/GSCategories.h"
|
2003-04-01 04:27:18 +00:00
|
|
|
#include "gnustep/base/GCObject.h"
|
2002-12-03 02:50:07 +00:00
|
|
|
|
|
|
|
/* FIXME: Need to initialize this */
|
|
|
|
NSRecursiveLock *gnustep_global_lock = NULL;
|
|
|
|
|
2003-01-26 19:38:42 +00:00
|
|
|
NSString *GetEncodingName(NSStringEncoding availableEncodingValue)
|
2003-04-01 04:27:18 +00:00
|
|
|
{
|
2003-04-02 17:09:52 +00:00
|
|
|
// Deprecated
|
|
|
|
return GSEncodingName(availableEncodingValue);
|
2003-04-01 04:27:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NSString *GSEncodingName(NSStringEncoding availableEncodingValue)
|
2003-01-26 19:38:42 +00:00
|
|
|
{
|
2003-04-02 17:09:52 +00:00
|
|
|
return (NSString *)CFStringGetNameOfEncoding(CFStringConvertNSStringEncodingToEncoding(availableEncodingValue));
|
2003-01-26 19:38:42 +00:00
|
|
|
}
|
|
|
|
|
2003-03-31 02:59:56 +00:00
|
|
|
NSMutableDictionary *GSCurrentThreadDictionary()
|
|
|
|
{
|
|
|
|
return [[NSThread currentThread] threadDictionary];
|
|
|
|
}
|
|
|
|
|
2003-01-31 18:25:41 +00:00
|
|
|
NSArray *NSStandardLibraryPaths()
|
|
|
|
{
|
|
|
|
return NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory, NSAllDomainsMask, YES);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Defined in NSDebug.m
|
|
|
|
NSString*
|
|
|
|
GSDebugMethodMsg(id obj, SEL sel, const char *file, int line, NSString *fmt)
|
|
|
|
{
|
|
|
|
NSString *message;
|
|
|
|
Class cls = (Class)obj;
|
|
|
|
char c = '+';
|
|
|
|
|
|
|
|
if ([obj isInstance] == YES)
|
|
|
|
{
|
|
|
|
c = '-';
|
|
|
|
cls = [obj class];
|
|
|
|
}
|
|
|
|
message = [NSString stringWithFormat: @"File %s: %d. In [%@ %c%@] %@",
|
|
|
|
file, line, NSStringFromClass(cls), c, NSStringFromSelector(sel), fmt];
|
|
|
|
return message;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString*
|
|
|
|
GSDebugFunctionMsg(const char *func, const char *file, int line, NSString *fmt)
|
|
|
|
{
|
|
|
|
NSString *message;
|
|
|
|
|
|
|
|
message = [NSString stringWithFormat: @"File %s: %d. In %s %@",
|
|
|
|
file, line, func, fmt];
|
|
|
|
return message;
|
|
|
|
}
|
|
|
|
|
2002-12-03 02:50:07 +00:00
|
|
|
@implementation NSArray (GSCompatibility)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the receiver with the contents of array.
|
|
|
|
* The order of array is preserved.<br />
|
|
|
|
* If shouldCopy is YES then the objects are copied
|
|
|
|
* rather than simply retained.<br />
|
|
|
|
* Invokes -initWithObjects:count:
|
|
|
|
*/
|
|
|
|
- (id) initWithArray: (NSArray*)array copyItems: (BOOL)shouldCopy
|
|
|
|
{
|
|
|
|
unsigned c = [array count];
|
|
|
|
id objects[c];
|
|
|
|
|
|
|
|
[array getObjects: objects];
|
|
|
|
if (shouldCopy == YES)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
objects[i] = [objects[i] copy];
|
|
|
|
}
|
|
|
|
self = [self initWithObjects: objects count: c];
|
|
|
|
#if GS_WITH_GC == 0
|
|
|
|
while (i > 0)
|
|
|
|
{
|
|
|
|
[objects[--i] release];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
self = [self initWithObjects: objects count: c];
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2003-01-31 18:25:41 +00:00
|
|
|
|
2003-03-31 02:59:56 +00:00
|
|
|
@interface NSDistantObject (GSCategoriesRevealed)
|
|
|
|
// This method is implemented in MacOS X 10.2.4, but is not public
|
|
|
|
+ (void) _enableLogging:(BOOL)flag;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSDistantObject (GSCompatibility)
|
|
|
|
|
|
|
|
+ (void) setDebug: (int)val
|
|
|
|
{
|
|
|
|
if([self respondsToSelector:@selector(_enableLogging:)])
|
|
|
|
[self _enableLogging:!!val];
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
@implementation NSFileHandle(GSCompatibility)
|
|
|
|
// From GSFileHandle.m
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|
|
|
{
|
|
|
|
const char *proto = "tcp";
|
|
|
|
struct servent *sp;
|
|
|
|
|
|
|
|
if (pcl)
|
|
|
|
{
|
|
|
|
proto = [pcl lossyCString];
|
|
|
|
}
|
|
|
|
memset(sin, '\0', sizeof(*sin));
|
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we were given a hostname, we use any address for that host.
|
|
|
|
* Otherwise we expect the given name to be an address unless it is
|
|
|
|
* a null (any address).
|
|
|
|
*/
|
|
|
|
if (name)
|
|
|
|
{
|
|
|
|
NSHost* host = [NSHost hostWithName: name];
|
|
|
|
|
|
|
|
if (host != nil)
|
|
|
|
{
|
|
|
|
name = [host address];
|
|
|
|
}
|
|
|
|
#ifndef HAVE_INET_ATON
|
|
|
|
sin->sin_addr.s_addr = inet_addr([name lossyCString]);
|
|
|
|
if (sin->sin_addr.s_addr == INADDR_NONE)
|
|
|
|
#else
|
|
|
|
if (inet_aton([name lossyCString], &sin->sin_addr) == 0)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sin->sin_addr.s_addr = NSSwapHostIntToBig(INADDR_ANY);
|
|
|
|
}
|
|
|
|
if (svc == nil)
|
|
|
|
{
|
|
|
|
sin->sin_port = 0;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
else if ((sp = getservbyname([svc lossyCString], proto)) == 0)
|
|
|
|
{
|
|
|
|
const char* ptr = [svc lossyCString];
|
|
|
|
int val = atoi(ptr);
|
|
|
|
|
|
|
|
while (isdigit(*ptr))
|
|
|
|
{
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
if (*ptr == '\0' && val <= 0xffff)
|
|
|
|
{
|
|
|
|
unsigned short v = val;
|
|
|
|
|
|
|
|
sin->sin_port = NSSwapHostShortToBig(v);
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
else if (strcmp(ptr, "gdomap") == 0)
|
|
|
|
{
|
|
|
|
unsigned short v;
|
|
|
|
#ifdef GDOMAP_PORT_OVERRIDE
|
|
|
|
v = GDOMAP_PORT_OVERRIDE;
|
|
|
|
#else
|
|
|
|
v = 538; // IANA allocated port
|
|
|
|
#endif
|
|
|
|
sin->sin_port = NSSwapHostShortToBig(v);
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sin->sin_port = sp->s_port;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initAsServerAtAddress: (NSString*)a
|
|
|
|
service: (NSString*)s
|
|
|
|
protocol: (NSString*)p
|
|
|
|
{
|
|
|
|
#ifndef BROKEN_SO_REUSEADDR
|
|
|
|
int status = 1;
|
|
|
|
#endif
|
|
|
|
int net;
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
int size = sizeof(sin);
|
|
|
|
|
|
|
|
if (getAddr(a, s, p, &sin) == NO)
|
|
|
|
{
|
|
|
|
RELEASE(self);
|
|
|
|
NSLog(@"bad address-service-protocol combination");
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((net = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0)
|
|
|
|
{
|
|
|
|
NSLog(@"unable to create socket - %s", GSLastErrorStr(errno));
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef BROKEN_SO_REUSEADDR
|
|
|
|
/*
|
|
|
|
* Under decent systems, SO_REUSEADDR means that the port can be reused
|
|
|
|
* immediately that this process exits. Under some it means
|
|
|
|
* that multiple processes can serve the same port simultaneously.
|
|
|
|
* We don't want that broken behavior!
|
|
|
|
*/
|
|
|
|
setsockopt(net, SOL_SOCKET, SO_REUSEADDR, (char *)&status, sizeof(status));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (bind(net, (struct sockaddr *)&sin, sizeof(sin)) < 0)
|
|
|
|
{
|
|
|
|
NSLog(@"unable to bind to port %s:%d - %s", inet_ntoa(sin.sin_addr),
|
|
|
|
NSSwapBigShortToHost(sin.sin_port), GSLastErrorStr(errno));
|
|
|
|
(void) close(net);
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (listen(net, 5) < 0)
|
|
|
|
{
|
|
|
|
NSLog(@"unable to listen on port - %s", GSLastErrorStr(errno));
|
|
|
|
(void) close(net);
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getsockname(net, (struct sockaddr*)&sin, &size) < 0)
|
|
|
|
{
|
|
|
|
NSLog(@"unable to get socket name - %s", GSLastErrorStr(errno));
|
|
|
|
(void) close(net);
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
self = [self initWithFileDescriptor: net closeOnDealloc: YES];
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (id) fileHandleAsServerAtAddress: (NSString*)address
|
|
|
|
service: (NSString*)service
|
|
|
|
protocol: (NSString*)protocol
|
|
|
|
{
|
|
|
|
id o = [self allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
|
|
|
return AUTORELEASE([o initAsServerAtAddress: address
|
|
|
|
service: service
|
|
|
|
protocol: protocol]);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) socketAddress
|
|
|
|
{
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
int size = sizeof(sin);
|
|
|
|
|
|
|
|
if (getsockname([self fileDescriptor], (struct sockaddr*)&sin, &size) < 0)
|
|
|
|
{
|
|
|
|
NSLog(@"unable to get socket name - %s", GSLastErrorStr(errno));
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
return [[[NSString alloc] initWithCString: (char*)inet_ntoa(sin.sin_addr)]
|
|
|
|
autorelease];
|
2003-04-02 17:09:52 +00:00
|
|
|
}
|
|
|
|
|
2003-03-31 02:59:56 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
|
2003-02-03 04:15:27 +00:00
|
|
|
@implementation NSProcessInfo(GSCompatibility)
|
2003-01-31 18:25:41 +00:00
|
|
|
|
|
|
|
static NSMutableSet *_debug_set = nil;
|
|
|
|
|
|
|
|
BOOL GSDebugSet(NSString *level)
|
|
|
|
// From GNUStep's
|
|
|
|
{
|
|
|
|
static IMP debugImp = 0;
|
|
|
|
static SEL debugSel;
|
|
|
|
|
|
|
|
if (debugImp == 0)
|
|
|
|
{
|
|
|
|
debugSel = @selector(member:);
|
|
|
|
if (_debug_set == nil)
|
|
|
|
{
|
|
|
|
[[NSProcessInfo processInfo] debugSet];
|
|
|
|
}
|
|
|
|
debugImp = [_debug_set methodForSelector: debugSel];
|
|
|
|
}
|
|
|
|
if ((*debugImp)(_debug_set, debugSel, level) == nil)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSMutableSet *) debugSet
|
|
|
|
// Derived from GNUStep's
|
|
|
|
{
|
|
|
|
if(_debug_set == nil){
|
|
|
|
int argc = [[self arguments] count];
|
|
|
|
NSMutableSet *mySet;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
mySet = [NSMutableSet new];
|
|
|
|
for (i = 0; i < argc; i++)
|
|
|
|
{
|
|
|
|
NSString *str = [[self arguments] objectAtIndex:i];
|
|
|
|
|
|
|
|
if ([str hasPrefix: @"--GNU-Debug="])
|
|
|
|
[mySet addObject: [str substringFromIndex: 12]];
|
|
|
|
}
|
|
|
|
_debug_set = mySet;
|
|
|
|
}
|
|
|
|
|
|
|
|
return _debug_set;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2003-02-03 04:15:27 +00:00
|
|
|
@implementation NSString(GSCompatibility)
|
2003-01-31 18:25:41 +00:00
|
|
|
|
|
|
|
// From GNUStep
|
|
|
|
/**
|
|
|
|
* If the string consists of the words 'true' or 'yes' (case insensitive)
|
|
|
|
* or begins with a non-zero numeric value, return YES, otherwise return
|
|
|
|
* NO.
|
|
|
|
*/
|
|
|
|
- (BOOL) boolValue
|
|
|
|
{
|
|
|
|
if ([self caseInsensitiveCompare: @"YES"] == NSOrderedSame)
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if ([self caseInsensitiveCompare: @"true"] == NSOrderedSame)
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
return [self intValue] != 0 ? YES : NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2003-02-03 04:15:27 +00:00
|
|
|
@implementation NSInvocation(GSCompatibility)
|
2003-01-31 18:25:41 +00:00
|
|
|
- (retval_t) returnFrame:(arglist_t)args
|
|
|
|
{
|
|
|
|
#warning (stephane@sente.ch) Not implemented
|
|
|
|
return (retval_t)[self notImplemented:_cmd];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithArgframe:(arglist_t)args selector:(SEL)selector
|
|
|
|
{
|
|
|
|
#warning (stephane@sente.ch) Not implemented
|
|
|
|
return [self notImplemented:_cmd];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2003-02-03 04:15:27 +00:00
|
|
|
@implementation NSObject(GSCompatibility)
|
2003-01-31 18:25:41 +00:00
|
|
|
|
|
|
|
+ (id) notImplemented:(SEL)selector
|
|
|
|
{
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
format: @"method %s not implemented in %s(class)",
|
|
|
|
selector ? sel_get_name(selector) : "(null)",
|
|
|
|
object_get_class_name(self)];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
// In NSObject.m, category GNU
|
|
|
|
- (BOOL) isInstance
|
|
|
|
{
|
|
|
|
return GSObjCIsInstance(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2003-04-02 17:09:52 +00:00
|
|
|
|
|
|
|
@implementation NSBundle(GSCompatibility)
|
|
|
|
|
|
|
|
// In NSBundle.m
|
|
|
|
+ (NSString *) pathForGNUstepResource: (NSString *)name
|
|
|
|
ofType: (NSString *)ext
|
|
|
|
inDirectory: (NSString *)bundlePath
|
|
|
|
{
|
|
|
|
NSString *path = nil;
|
|
|
|
NSString *bundle_path = nil;
|
|
|
|
NSArray *paths;
|
|
|
|
NSBundle *bundle;
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
|
|
|
/* Gather up the paths */
|
|
|
|
// Originally, looks up in GSLibrariesDirectory, i.e. "Libraries"
|
|
|
|
paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
|
|
|
NSAllDomainsMask, YES);
|
|
|
|
|
|
|
|
enumerator = [paths objectEnumerator];
|
|
|
|
while ((path == nil) && (bundle_path = [enumerator nextObject]))
|
|
|
|
{
|
|
|
|
bundle = [self bundleWithPath: bundle_path];
|
|
|
|
path = [bundle pathForResource: name
|
|
|
|
ofType: ext
|
|
|
|
inDirectory: bundlePath];
|
|
|
|
}
|
|
|
|
|
|
|
|
// New for OSX: looks in gnustep framework
|
|
|
|
if(path == nil){
|
|
|
|
if([bundlePath hasPrefix:@"Resources/"])
|
|
|
|
bundlePath = [bundlePath substringFromIndex:10];
|
|
|
|
path = [[NSBundle bundleForClass:[GCObject class]] pathForResource: name
|
|
|
|
ofType: ext
|
|
|
|
inDirectory: bundlePath];
|
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|