2002-11-27 12:52:29 +00:00
|
|
|
|
/** Implementation of ObjC runtime additions for GNUStep
|
|
|
|
|
Copyright (C) 1995-2002 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
|
|
|
|
Date: Aug 1995
|
|
|
|
|
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
|
Date: Nov 2002
|
|
|
|
|
Written by: Manuel Guesdon <mguesdon@orange-concept.com>
|
|
|
|
|
Date: Nov 2002
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
<title>GSObjCRuntime function and macro reference</title>
|
|
|
|
|
$Date$ $Revision$
|
|
|
|
|
*/
|
|
|
|
|
|
2003-01-26 19:38:42 +00:00
|
|
|
|
#include "config.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/preface.h"
|
2003-02-03 04:15:27 +00:00
|
|
|
|
#ifndef NeXT_Foundation_LIBRARY
|
2002-12-03 02:50:07 +00:00
|
|
|
|
#include <Foundation/NSArray.h>
|
2003-03-02 07:47:18 +00:00
|
|
|
|
#include <Foundation/NSAutoreleasePool.h>
|
2003-07-01 17:00:14 +00:00
|
|
|
|
#include <Foundation/NSData.h>
|
2002-12-03 02:50:07 +00:00
|
|
|
|
#include <Foundation/NSDictionary.h>
|
|
|
|
|
#include <Foundation/NSEnumerator.h>
|
2002-11-27 12:52:29 +00:00
|
|
|
|
#include <Foundation/NSException.h>
|
2003-07-01 17:00:14 +00:00
|
|
|
|
#include <Foundation/NSLock.h>
|
2002-12-03 02:50:07 +00:00
|
|
|
|
#include <Foundation/NSMethodSignature.h>
|
2002-11-27 12:52:29 +00:00
|
|
|
|
#include <Foundation/NSObjCRuntime.h>
|
2003-03-02 10:17:24 +00:00
|
|
|
|
#include <Foundation/NSSet.h>
|
2002-11-27 12:52:29 +00:00
|
|
|
|
#include <Foundation/NSString.h>
|
|
|
|
|
#include <Foundation/NSValue.h>
|
2003-02-03 04:15:27 +00:00
|
|
|
|
#else
|
|
|
|
|
#include <Foundation/Foundation.h>
|
|
|
|
|
#endif
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/GSObjCRuntime.h"
|
|
|
|
|
#include "GNUstepBase/GNUstep.h"
|
2003-09-13 22:42:50 +00:00
|
|
|
|
#include "GNUstepBase/GSCategories.h"
|
2004-05-09 19:29:16 +00:00
|
|
|
|
|
|
|
|
|
#include <objc/Protocol.h>
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2003-03-23 07:06:27 +00:00
|
|
|
|
@class NSNull;
|
|
|
|
|
|
2004-01-12 19:44:48 +00:00
|
|
|
|
#ifdef NeXT_Foundation_LIBRARY
|
2004-01-12 19:42:18 +00:00
|
|
|
|
@interface NSObject (MissingFromMacOSX)
|
2004-01-15 04:07:08 +00:00
|
|
|
|
+ (IMP) methodForSelector: (SEL)aSelector;
|
2004-01-12 19:42:18 +00:00
|
|
|
|
@end
|
2004-01-12 19:44:48 +00:00
|
|
|
|
#endif
|
2004-01-12 19:42:18 +00:00
|
|
|
|
|
2004-06-04 13:42:13 +00:00
|
|
|
|
#define BDBGPrintf(format, args...) \
|
|
|
|
|
do { if (behavior_debug) { fprintf(stderr, (format), ## args); } } while (0)
|
|
|
|
|
|
2004-05-06 15:25:01 +00:00
|
|
|
|
static objc_mutex_t local_lock = NULL;
|
|
|
|
|
|
|
|
|
|
/* This class it intended soley for thread safe / +load safe
|
|
|
|
|
initialization of the local lock.
|
|
|
|
|
It's a root class so it won't trigger the initialization
|
|
|
|
|
of any other class. */
|
|
|
|
|
@interface _GSObjCRuntimeInitializer /* Root Class */
|
|
|
|
|
{
|
|
|
|
|
Class isa;
|
|
|
|
|
}
|
|
|
|
|
+ (Class)class;
|
|
|
|
|
@end
|
|
|
|
|
@implementation _GSObjCRuntimeInitializer
|
|
|
|
|
+ (void)initialize
|
|
|
|
|
{
|
|
|
|
|
if (local_lock == NULL)
|
|
|
|
|
{
|
|
|
|
|
local_lock = objc_mutex_allocate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
+ (Class)class
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
GSAllocateMutexAt(objc_mutex_t *request)
|
|
|
|
|
{
|
|
|
|
|
if (request == NULL)
|
|
|
|
|
{
|
|
|
|
|
/* This could be called very early in process
|
|
|
|
|
initialization so many things may not have
|
|
|
|
|
been setup correctly yet. */
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"Error: GSAllocateMutexAt() called with NULL pointer.\n");
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (local_lock == NULL)
|
|
|
|
|
{
|
|
|
|
|
/* Initialize in a thread safe way. */
|
|
|
|
|
[_GSObjCRuntimeInitializer class];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
objc_mutex_lock(local_lock);
|
|
|
|
|
if (*request == NULL)
|
|
|
|
|
{
|
|
|
|
|
*request = objc_mutex_allocate();
|
|
|
|
|
}
|
|
|
|
|
objc_mutex_unlock(local_lock);
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-29 14:21:09 +00:00
|
|
|
|
/** Deprecated ... use GSObjCFindVariable() */
|
2002-11-27 18:52:53 +00:00
|
|
|
|
BOOL
|
|
|
|
|
GSFindInstanceVariable(id obj, const char *name,
|
2003-06-07 09:45:51 +00:00
|
|
|
|
const char **type, unsigned int *size, int *offset)
|
2002-11-27 18:52:53 +00:00
|
|
|
|
{
|
2002-11-29 14:21:09 +00:00
|
|
|
|
return GSObjCFindVariable(obj, name, type, size, offset);
|
2002-11-27 18:52:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* This function is used to locate information about the instance
|
|
|
|
|
* variable of obj called name. It returns YES if the variable
|
|
|
|
|
* was found, NO otherwise. If it returns YES, then the values
|
|
|
|
|
* pointed to by type, size, and offset will be set (except where
|
|
|
|
|
* they are null pointers).
|
|
|
|
|
*/
|
|
|
|
|
BOOL
|
2002-11-29 14:21:09 +00:00
|
|
|
|
GSObjCFindVariable(id obj, const char *name,
|
2003-06-07 09:45:51 +00:00
|
|
|
|
const char **type, unsigned int *size, int *offset)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
|
|
|
|
Class class;
|
|
|
|
|
struct objc_ivar_list *ivars;
|
|
|
|
|
struct objc_ivar *ivar = 0;
|
|
|
|
|
|
2003-03-02 10:17:24 +00:00
|
|
|
|
if (obj == nil) return NO;
|
|
|
|
|
class = GSObjCClass(obj);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
while (class != nil && ivar == 0)
|
|
|
|
|
{
|
|
|
|
|
ivars = class->ivars;
|
|
|
|
|
class = class->super_class;
|
|
|
|
|
if (ivars != 0)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ivars->ivar_count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp(ivars->ivar_list[i].ivar_name, name) == 0)
|
|
|
|
|
{
|
|
|
|
|
ivar = &ivars->ivar_list[i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ivar == 0)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type)
|
|
|
|
|
*type = ivar->ivar_type;
|
|
|
|
|
if (size)
|
|
|
|
|
*size = objc_sizeof_type(ivar->ivar_type);
|
|
|
|
|
if (offset)
|
|
|
|
|
*offset = ivar->ivar_offset;
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-02 10:17:24 +00:00
|
|
|
|
/**
|
|
|
|
|
* This method returns an array listing the names of all the
|
|
|
|
|
* instance methods available to obj, whether they
|
|
|
|
|
* belong to the class of obj or one of its superclasses.<br />
|
|
|
|
|
* If obj is a class, this returns the class methods.<br />
|
|
|
|
|
* Returns nil if obj is nil.
|
|
|
|
|
*/
|
2003-06-07 09:45:51 +00:00
|
|
|
|
NSArray *
|
2003-03-02 10:17:24 +00:00
|
|
|
|
GSObjCMethodNames(id obj)
|
|
|
|
|
{
|
2004-06-05 21:11:00 +00:00
|
|
|
|
NSMutableSet *set;
|
|
|
|
|
NSArray *array;
|
|
|
|
|
Class class;
|
|
|
|
|
GSMethodList methods;
|
2003-03-02 10:17:24 +00:00
|
|
|
|
|
|
|
|
|
if (obj == nil)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Add names to a set so methods declared in superclasses
|
|
|
|
|
* and then overridden do not appear more than once.
|
|
|
|
|
*/
|
|
|
|
|
set = [[NSMutableSet alloc] initWithCapacity: 32];
|
|
|
|
|
|
|
|
|
|
class = GSObjCClass(obj);
|
|
|
|
|
|
|
|
|
|
while (class != nil)
|
|
|
|
|
{
|
|
|
|
|
void *iterator = 0;
|
|
|
|
|
|
|
|
|
|
while ((methods = class_nextMethodList(class, &iterator)) )
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < methods->method_count; i++)
|
|
|
|
|
{
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSMethod method = &methods->method_list[i];
|
2003-03-02 10:17:24 +00:00
|
|
|
|
|
|
|
|
|
if (method->method_name != 0)
|
|
|
|
|
{
|
|
|
|
|
NSString *name;
|
2004-06-05 22:48:40 +00:00
|
|
|
|
const char *cName;
|
2003-03-02 10:17:24 +00:00
|
|
|
|
|
2004-06-05 22:48:40 +00:00
|
|
|
|
cName = GSNameFromSelector(method->method_name);
|
|
|
|
|
name = [[NSString alloc] initWithUTF8String: cName];
|
2003-03-02 10:17:24 +00:00
|
|
|
|
[set addObject: name];
|
|
|
|
|
RELEASE(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
class = class->super_class;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
array = [set allObjects];
|
|
|
|
|
RELEASE(set);
|
|
|
|
|
return array;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This method returns an array listing the names of all the
|
|
|
|
|
* instance variables present in the instance obj, whether they
|
|
|
|
|
* belong to the class of obj or one of its superclasses.<br />
|
|
|
|
|
* Returns nil if obj is nil.
|
|
|
|
|
*/
|
2003-06-07 09:45:51 +00:00
|
|
|
|
NSArray *
|
2003-03-02 10:17:24 +00:00
|
|
|
|
GSObjCVariableNames(id obj)
|
|
|
|
|
{
|
|
|
|
|
NSMutableArray *array;
|
|
|
|
|
Class class;
|
|
|
|
|
struct objc_ivar_list *ivars;
|
|
|
|
|
|
|
|
|
|
if (obj == nil)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
array = [NSMutableArray arrayWithCapacity: 16];
|
|
|
|
|
class = GSObjCClass(obj);
|
|
|
|
|
while (class != nil)
|
|
|
|
|
{
|
|
|
|
|
ivars = class->ivars;
|
|
|
|
|
if (ivars != 0)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ivars->ivar_count; i++)
|
|
|
|
|
{
|
|
|
|
|
NSString *name;
|
|
|
|
|
|
|
|
|
|
name = [[NSString alloc] initWithUTF8String:
|
|
|
|
|
ivars->ivar_list[i].ivar_name];
|
|
|
|
|
[array addObject: name];
|
|
|
|
|
RELEASE(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
class = class->super_class;
|
|
|
|
|
}
|
|
|
|
|
return array;
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-28 09:35:36 +00:00
|
|
|
|
/** Deprecated ... use GSObjCGetVariable() */
|
2002-11-27 12:52:29 +00:00
|
|
|
|
void
|
2002-11-29 14:31:23 +00:00
|
|
|
|
GSGetVariable(id obj, int offset, unsigned int size, void *data)
|
2002-11-27 18:52:53 +00:00
|
|
|
|
{
|
|
|
|
|
GSObjCGetVariable(obj, offset, size, data);
|
|
|
|
|
}
|
2002-11-28 09:35:36 +00:00
|
|
|
|
/**
|
|
|
|
|
* Gets the value from an instance variable in obj<br />
|
|
|
|
|
* This function performs no checking ... you should use it only where
|
2002-11-29 14:21:09 +00:00
|
|
|
|
* you are providing information from a call to GSFindVariable()
|
2002-11-28 09:35:36 +00:00
|
|
|
|
* and you know that the data area provided is the correct size.
|
|
|
|
|
*/
|
2002-11-27 18:52:53 +00:00
|
|
|
|
void
|
|
|
|
|
GSObjCGetVariable(id obj, int offset, unsigned int size, void *data)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
|
|
|
|
memcpy(data, ((void*)obj) + offset, size);
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-28 09:35:36 +00:00
|
|
|
|
/** Deprecated ... use GSObjCSetVariable() */
|
2002-11-27 12:52:29 +00:00
|
|
|
|
void
|
2002-11-29 14:31:23 +00:00
|
|
|
|
GSSetVariable(id obj, int offset, unsigned int size, const void *data)
|
2002-11-27 18:52:53 +00:00
|
|
|
|
{
|
|
|
|
|
GSObjCSetVariable(obj, offset, size, data);
|
|
|
|
|
}
|
2002-11-28 09:35:36 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets the value in an instance variable in obj<br />
|
|
|
|
|
* This function performs no checking ... you should use it only where
|
2002-11-29 14:21:09 +00:00
|
|
|
|
* you are providing information from a call to GSObjCFindVariable()
|
2002-11-28 09:35:36 +00:00
|
|
|
|
* and you know that the data area provided is the correct size.
|
|
|
|
|
*/
|
2002-11-27 18:52:53 +00:00
|
|
|
|
void
|
|
|
|
|
GSObjCSetVariable(id obj, int offset, unsigned int size, const void *data)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
|
|
|
|
memcpy(((void*)obj) + offset, data, size);
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-07 16:26:50 +00:00
|
|
|
|
GS_EXPORT unsigned int
|
|
|
|
|
GSClassList(Class *buffer, unsigned int max, BOOL clearCache)
|
|
|
|
|
{
|
|
|
|
|
#ifdef NeXT_RUNTIME
|
|
|
|
|
int num;
|
|
|
|
|
|
|
|
|
|
if (buffer != NULL)
|
|
|
|
|
{
|
|
|
|
|
memset(buffer, 0, sizeof(Class) * (max + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
num = objc_getClassList(buffer, max);
|
|
|
|
|
num = (num < 0) ? 0 : num;
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
static Class *cache = 0;
|
|
|
|
|
static unsigned cacheClassCount = 0;
|
|
|
|
|
static volatile objc_mutex_t cache_lock = NULL;
|
|
|
|
|
unsigned int num;
|
|
|
|
|
|
|
|
|
|
if (cache_lock == NULL)
|
|
|
|
|
{
|
|
|
|
|
GSAllocateMutexAt((void*)&cache_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
objc_mutex_lock(cache_lock);
|
|
|
|
|
|
|
|
|
|
if (clearCache)
|
|
|
|
|
{
|
|
|
|
|
if (cache)
|
|
|
|
|
{
|
|
|
|
|
objc_free(cache);
|
|
|
|
|
cache = NULL;
|
|
|
|
|
}
|
|
|
|
|
cacheClassCount = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cache == NULL)
|
|
|
|
|
{
|
|
|
|
|
void *iterator = 0;
|
|
|
|
|
Class cls;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
cacheClassCount = 0;
|
|
|
|
|
while ((cls = objc_next_class(&iterator)))
|
|
|
|
|
{
|
|
|
|
|
cacheClassCount++;
|
|
|
|
|
}
|
|
|
|
|
cache = objc_malloc(sizeof(Class) * (cacheClassCount + 1));
|
|
|
|
|
/* Be extra careful as another thread may be loading classes. */
|
|
|
|
|
for (i = 0, iterator = 0, cls = objc_next_class(&iterator);
|
|
|
|
|
i < cacheClassCount && cls != NULL;
|
|
|
|
|
i++, cls = objc_next_class(&iterator))
|
|
|
|
|
{
|
|
|
|
|
cache[i] = cls;
|
|
|
|
|
}
|
|
|
|
|
cache[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buffer == NULL)
|
|
|
|
|
{
|
|
|
|
|
num = cacheClassCount;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size_t cpySize;
|
|
|
|
|
unsigned int cpyCnt;
|
|
|
|
|
|
|
|
|
|
cpyCnt = MIN(max, cacheClassCount);
|
|
|
|
|
cpySize = sizeof(Class) * cpyCnt;
|
|
|
|
|
memcpy(buffer, cache, cpySize);
|
|
|
|
|
buffer[cpyCnt] = NULL;
|
|
|
|
|
|
|
|
|
|
num = (max > cacheClassCount) ? 0 : (cacheClassCount - max);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
objc_mutex_unlock(cache_lock);
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
/** references:
|
|
|
|
|
http://www.macdevcenter.com/pub/a/mac/2002/05/31/runtime_parttwo.html?page=1
|
2004-06-04 13:58:36 +00:00
|
|
|
|
http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/9objc_runtime_reference/chapter_5_section_1.html
|
|
|
|
|
http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/9objc_runtime_reference/chapter_5_section_21.html
|
2002-11-27 12:52:29 +00:00
|
|
|
|
ObjcRuntimeUtilities.m by Nicola Pero
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* <p>Create a Class structure for use by the ObjectiveC runtime and return
|
|
|
|
|
* an NSValue object pointing to it. The class will not be added to the
|
|
|
|
|
* runtime (you must do that later using the GSObjCAddClasses() function).
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>The iVars dictionary lists the instance variable names and their types.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
2003-06-07 09:45:51 +00:00
|
|
|
|
NSValue *
|
2002-11-27 12:52:29 +00:00
|
|
|
|
GSObjCMakeClass(NSString *name, NSString *superName, NSDictionary *iVars)
|
|
|
|
|
{
|
|
|
|
|
Class newClass;
|
|
|
|
|
Class classSuperClass;
|
|
|
|
|
const char *classNameCString;
|
|
|
|
|
const char *superClassNameCString;
|
|
|
|
|
Class newMetaClass;
|
|
|
|
|
Class rootClass;
|
|
|
|
|
unsigned int iVarSize;
|
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
|
|
NSCAssert(name, @"no name");
|
|
|
|
|
NSCAssert(superName, @"no superName");
|
|
|
|
|
|
|
|
|
|
classSuperClass = NSClassFromString(superName);
|
|
|
|
|
|
|
|
|
|
NSCAssert1(classSuperClass, @"No class named %@",superName);
|
|
|
|
|
NSCAssert1(!NSClassFromString(name), @"A class %@ already exists", name);
|
|
|
|
|
|
|
|
|
|
classNameCString = [name cString];
|
|
|
|
|
tmp = objc_malloc(strlen(classNameCString) + 1);
|
|
|
|
|
strcpy(tmp, classNameCString);
|
|
|
|
|
classNameCString = tmp;
|
|
|
|
|
|
|
|
|
|
superClassNameCString = [superName cString];
|
|
|
|
|
tmp = objc_malloc(strlen(superClassNameCString) + 1);
|
|
|
|
|
strcpy(tmp, superClassNameCString);
|
|
|
|
|
superClassNameCString = tmp;
|
|
|
|
|
|
|
|
|
|
rootClass = classSuperClass;
|
|
|
|
|
while (rootClass->super_class != 0)
|
|
|
|
|
{
|
|
|
|
|
rootClass = rootClass->super_class;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Create new class and meta class structure storage
|
|
|
|
|
*
|
|
|
|
|
* From Nicola: NB: There is a trick here.
|
|
|
|
|
* The runtime system will look up the name in the following string,
|
|
|
|
|
* and replace it with a pointer to the actual superclass structure.
|
|
|
|
|
* This also means the type of pointer will change, that's why we
|
|
|
|
|
* need to cast it.
|
|
|
|
|
*/
|
|
|
|
|
newMetaClass = objc_malloc(sizeof(struct objc_class));
|
|
|
|
|
memset(newMetaClass, 0, sizeof(struct objc_class));
|
|
|
|
|
newMetaClass->class_pointer = rootClass->class_pointer; // Points to root
|
|
|
|
|
newMetaClass->super_class = (Class)superClassNameCString;
|
|
|
|
|
newMetaClass->name = classNameCString;
|
|
|
|
|
newMetaClass->version = 0;
|
|
|
|
|
newMetaClass->info = _CLS_META; // this is a Meta Class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newClass = objc_malloc(sizeof(struct objc_class));
|
|
|
|
|
memset(newClass, 0, sizeof(struct objc_class));
|
|
|
|
|
newClass->class_pointer = newMetaClass; // Points to the class's meta class.
|
|
|
|
|
newClass->super_class = (Class)superClassNameCString;
|
|
|
|
|
newClass->name = classNameCString;
|
|
|
|
|
newClass->version = 0;
|
|
|
|
|
newClass->info = _CLS_CLASS; // this is a Class
|
|
|
|
|
|
|
|
|
|
// work on instances variables
|
|
|
|
|
iVarSize = classSuperClass->instance_size; // super class ivar size
|
|
|
|
|
if ([iVars count] > 0)
|
|
|
|
|
{
|
|
|
|
|
unsigned int iVarsStructsSize;
|
|
|
|
|
struct objc_ivar *ivar = NULL;
|
|
|
|
|
unsigned int iVarsCount = [iVars count];
|
|
|
|
|
NSEnumerator *enumerator = [iVars keyEnumerator];
|
|
|
|
|
NSString *key;
|
|
|
|
|
|
|
|
|
|
// ivars list is 1 objc_ivar_list followed by (iVarsCount-1) ivar_list
|
|
|
|
|
iVarsStructsSize = sizeof(struct objc_ivar_list)
|
|
|
|
|
+ (iVarsCount-1)*sizeof(struct objc_ivar);
|
|
|
|
|
|
|
|
|
|
// Allocate for all ivars
|
|
|
|
|
newClass->ivars = (struct objc_ivar_list*)objc_malloc(iVarsStructsSize);
|
|
|
|
|
memset(newClass->ivars, 0, iVarsStructsSize);
|
|
|
|
|
|
|
|
|
|
// Set ivars count
|
|
|
|
|
newClass->ivars->ivar_count = iVarsCount;
|
|
|
|
|
|
|
|
|
|
// initialize each ivar
|
|
|
|
|
ivar = newClass->ivars->ivar_list; // 1st one
|
|
|
|
|
while ((key = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
const char *iVarName = [key cString];
|
|
|
|
|
const char *iVarType = [[iVars objectForKey: key] cString];
|
|
|
|
|
|
|
|
|
|
tmp = objc_malloc(strlen(iVarName) + 1);
|
|
|
|
|
strcpy(tmp, iVarName);
|
|
|
|
|
ivar->ivar_name = tmp;
|
|
|
|
|
tmp = objc_malloc(strlen(iVarType) + 1);
|
|
|
|
|
strcpy(tmp, iVarType);
|
|
|
|
|
ivar->ivar_type = tmp;
|
|
|
|
|
|
|
|
|
|
// align the ivar (i.e. put it on the first aligned address
|
|
|
|
|
iVarSize = objc_aligned_size(ivar->ivar_type);
|
|
|
|
|
ivar->ivar_offset = iVarSize;
|
|
|
|
|
iVarSize += objc_sizeof_type(ivar->ivar_type); // add the ivar size
|
|
|
|
|
ivar = ivar + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Size in bytes of the class. The sum of the class definition
|
|
|
|
|
* and all super class definitions.
|
|
|
|
|
*/
|
|
|
|
|
newClass->instance_size = iVarSize;
|
|
|
|
|
|
|
|
|
|
// Meta Class instance size is superclass instance size.
|
|
|
|
|
newMetaClass->instance_size = classSuperClass->class_pointer->instance_size;
|
|
|
|
|
|
|
|
|
|
return [NSValue valueWithPointer: newClass];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The classes argument is an array of NSValue objects containing pointers
|
|
|
|
|
* to classes previously created by the GSObjCMakeClass() function.
|
|
|
|
|
*/
|
2002-12-03 02:50:07 +00:00
|
|
|
|
#ifdef NeXT_RUNTIME
|
|
|
|
|
void
|
|
|
|
|
GSObjCAddClasses(NSArray *classes)
|
|
|
|
|
{
|
|
|
|
|
unsigned int numClasses = [classes count];
|
|
|
|
|
unsigned int i;
|
|
|
|
|
for (i = 0; i < numClasses; i++)
|
|
|
|
|
{
|
|
|
|
|
objc_addClass((Class)[[classes objectAtIndex: i] pointerValue]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else
|
2004-06-04 13:58:36 +00:00
|
|
|
|
/*
|
|
|
|
|
* NOTE - OBJC_VERSION needs to be defined to be the version of the
|
|
|
|
|
* Objective-C runtime you are using. You can find this in the file
|
|
|
|
|
* 'init.c' in the GNU objective-C runtime source.
|
|
|
|
|
*/
|
|
|
|
|
#define OBJC_VERSION 8
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
void
|
|
|
|
|
GSObjCAddClasses(NSArray *classes)
|
|
|
|
|
{
|
2003-05-22 17:00:03 +00:00
|
|
|
|
void __objc_exec_class (void* module);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
void __objc_resolve_class_links ();
|
|
|
|
|
Module_t module;
|
|
|
|
|
Symtab_t symtab;
|
|
|
|
|
unsigned int numClasses = [classes count];
|
|
|
|
|
unsigned int i;
|
|
|
|
|
Class c;
|
|
|
|
|
|
|
|
|
|
NSCAssert(numClasses > 0, @"No classes (array is NULL)");
|
|
|
|
|
|
|
|
|
|
c = (Class)[[classes objectAtIndex: 0] pointerValue];
|
|
|
|
|
|
|
|
|
|
// Prepare a fake module containing only the new classes
|
|
|
|
|
module = objc_calloc (1, sizeof (Module));
|
|
|
|
|
module->version = OBJC_VERSION;
|
|
|
|
|
module->size = sizeof (Module);
|
|
|
|
|
module->name = objc_malloc (strlen(c->name) + 15);
|
|
|
|
|
strcpy ((char*)module->name, "GNUstep-Proxy-");
|
|
|
|
|
strcat ((char*)module->name, c->name);
|
|
|
|
|
module->symtab = objc_malloc(sizeof(Symtab) + numClasses * sizeof(void *));
|
|
|
|
|
|
|
|
|
|
symtab = module->symtab;
|
|
|
|
|
symtab->sel_ref_cnt = 0;
|
|
|
|
|
symtab->refs = 0;
|
|
|
|
|
symtab->cls_def_cnt = numClasses; // We are defining numClasses classes.
|
|
|
|
|
symtab->cat_def_cnt = 0; // But no categories
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < numClasses; i++)
|
|
|
|
|
{
|
|
|
|
|
symtab->defs[i] = (Class)[[classes objectAtIndex: i] pointerValue];
|
|
|
|
|
}
|
|
|
|
|
symtab->defs[numClasses] = NULL; //null terminated list
|
|
|
|
|
|
|
|
|
|
// Insert our new class into the runtime.
|
|
|
|
|
__objc_exec_class (module);
|
|
|
|
|
__objc_resolve_class_links();
|
|
|
|
|
}
|
2002-12-03 02:50:07 +00:00
|
|
|
|
#endif
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int behavior_debug = 0;
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
GSObjCBehaviorDebug(int i)
|
|
|
|
|
{
|
|
|
|
|
behavior_debug = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if NeXT_RUNTIME
|
|
|
|
|
|
2004-06-05 21:11:00 +00:00
|
|
|
|
static GSMethod search_for_method_in_class (Class class, SEL op);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
void
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSObjCAddMethods (Class class, GSMethodList methods)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
|
|
|
|
static SEL initialize_sel = 0;
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSMethodList mlist;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
if (!initialize_sel)
|
|
|
|
|
initialize_sel = sel_register_name ("initialize");
|
|
|
|
|
|
|
|
|
|
/* Add methods to class->dtable and class->methods */
|
|
|
|
|
mlist = methods;
|
|
|
|
|
{
|
|
|
|
|
int counter;
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSMethodList new_list;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
counter = mlist->method_count ? mlist->method_count - 1 : 1;
|
|
|
|
|
|
|
|
|
|
/* This is a little wasteful of memory, since not necessarily
|
|
|
|
|
all methods will go in here. */
|
2004-06-05 21:11:00 +00:00
|
|
|
|
new_list = (GSMethodList)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
objc_malloc (sizeof(struct objc_method_list) +
|
|
|
|
|
sizeof(struct objc_method[counter+1]));
|
|
|
|
|
new_list->method_count = 0;
|
|
|
|
|
|
|
|
|
|
while (counter >= 0)
|
|
|
|
|
{
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSMethod method = &(mlist->method_list[counter]);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2004-06-04 13:42:13 +00:00
|
|
|
|
BDBGPrintf(" processing method [%s] ... ",
|
|
|
|
|
GSNameFromSelector(method->method_name));
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2003-03-25 09:49:39 +00:00
|
|
|
|
if (!search_for_method_in_class(class,method->method_name)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
&& !sel_eq(method->method_name, initialize_sel))
|
|
|
|
|
{
|
|
|
|
|
/* As long as the method isn't defined in the CLASS,
|
|
|
|
|
put the BEHAVIOR method in there. Thus, behavior
|
|
|
|
|
methods override the superclasses' methods. */
|
|
|
|
|
new_list->method_list[new_list->method_count] = *method;
|
|
|
|
|
(new_list->method_count)++;
|
2004-06-04 13:42:13 +00:00
|
|
|
|
|
|
|
|
|
BDBGPrintf("added.\n");
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
2004-06-04 13:42:13 +00:00
|
|
|
|
else
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
2004-06-04 13:42:13 +00:00
|
|
|
|
BDBGPrintf("ignored.\n");
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
counter -= 1;
|
|
|
|
|
}
|
|
|
|
|
if (new_list->method_count)
|
|
|
|
|
{
|
|
|
|
|
class_add_method_list(class, new_list);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OBJC_FREE(new_list);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Search for the named method's method structure. Return a pointer
|
|
|
|
|
to the method's method structure if found. NULL otherwise. */
|
2004-06-05 21:11:00 +00:00
|
|
|
|
static GSMethod
|
2003-03-25 09:49:39 +00:00
|
|
|
|
search_for_method_in_class (Class class, SEL op)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
|
|
|
|
void *iterator = 0;
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSMethodList method_list;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
if (! sel_is_mapped (op))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* If not found then we'll search the list. */
|
|
|
|
|
while ( (method_list = class_nextMethodList(class, &iterator)) )
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* Search the method list. */
|
|
|
|
|
for (i = 0; i < method_list->method_count; ++i)
|
|
|
|
|
{
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSMethod method = &method_list->method_list[i];
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
if (method->method_name)
|
|
|
|
|
{
|
|
|
|
|
if (sel_eq(method->method_name, op))
|
|
|
|
|
return method;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else /* GNU runtime */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The following two functions are implemented in the GNU objc runtime
|
|
|
|
|
*/
|
|
|
|
|
extern Method_t search_for_method_in_list(MethodList_t list, SEL op);
|
|
|
|
|
extern void class_add_method_list(Class, MethodList_t);
|
|
|
|
|
|
2003-03-25 09:49:39 +00:00
|
|
|
|
static Method_t search_for_method_in_class (Class class, SEL op);
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
void
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSObjCAddMethods (Class class, GSMethodList methods)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
|
|
|
|
static SEL initialize_sel = 0;
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSMethodList mlist;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
if (initialize_sel == 0)
|
|
|
|
|
{
|
|
|
|
|
initialize_sel = sel_register_name ("initialize");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add methods to class->dtable and class->methods */
|
|
|
|
|
for (mlist = methods; mlist; mlist = mlist->method_next)
|
|
|
|
|
{
|
2004-06-05 21:11:00 +00:00
|
|
|
|
int counter;
|
|
|
|
|
GSMethodList new_list;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
counter = mlist->method_count ? mlist->method_count - 1 : 1;
|
|
|
|
|
|
|
|
|
|
/* This is a little wasteful of memory, since not necessarily
|
|
|
|
|
all methods will go in here. */
|
2004-06-05 21:11:00 +00:00
|
|
|
|
new_list = (GSMethodList)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
objc_malloc (sizeof(struct objc_method_list) +
|
|
|
|
|
sizeof(struct objc_method[counter+1]));
|
|
|
|
|
new_list->method_count = 0;
|
|
|
|
|
new_list->method_next = NULL;
|
|
|
|
|
|
|
|
|
|
while (counter >= 0)
|
|
|
|
|
{
|
2004-06-05 21:11:00 +00:00
|
|
|
|
GSMethod method = &(mlist->method_list[counter]);
|
|
|
|
|
const char *name = GSNameFromSelector(method->method_name);
|
2004-06-04 13:42:13 +00:00
|
|
|
|
|
|
|
|
|
BDBGPrintf(" processing method [%s] ... ", name);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
if (!search_for_method_in_list(class->methods, method->method_name)
|
|
|
|
|
&& !sel_eq(method->method_name, initialize_sel))
|
|
|
|
|
{
|
|
|
|
|
/* As long as the method isn't defined in the CLASS,
|
|
|
|
|
put the BEHAVIOR method in there. Thus, behavior
|
|
|
|
|
methods override the superclasses' methods. */
|
|
|
|
|
new_list->method_list[new_list->method_count] = *method;
|
|
|
|
|
/*
|
|
|
|
|
* HACK ... the GNU runtime implementation of
|
|
|
|
|
* class_add_method_list() expects the method names to be
|
|
|
|
|
* C-strings rather than selectors ... so we must allow
|
|
|
|
|
* for that.
|
|
|
|
|
*/
|
|
|
|
|
new_list->method_list[new_list->method_count].method_name
|
|
|
|
|
= (SEL)name;
|
|
|
|
|
(new_list->method_count)++;
|
2004-06-04 13:42:13 +00:00
|
|
|
|
|
|
|
|
|
BDBGPrintf("added.\n");
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
2004-06-04 13:42:13 +00:00
|
|
|
|
else
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
2004-06-04 13:42:13 +00:00
|
|
|
|
BDBGPrintf("ignored.\n");
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
counter -= 1;
|
|
|
|
|
}
|
|
|
|
|
if (new_list->method_count)
|
|
|
|
|
{
|
|
|
|
|
class_add_method_list(class, new_list);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OBJC_FREE(new_list);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-25 09:49:39 +00:00
|
|
|
|
static Method_t
|
|
|
|
|
search_for_method_in_class (Class class, SEL op)
|
|
|
|
|
{
|
2003-03-25 14:57:08 +00:00
|
|
|
|
return class != NULL ? search_for_method_in_list(class->methods, op) : NULL;
|
2003-03-25 09:49:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
#endif /* NeXT runtime */
|
|
|
|
|
|
2003-06-22 08:45:48 +00:00
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
GSMethod
|
|
|
|
|
GSGetInstanceMethodNotInherited (Class class, SEL sel)
|
2003-03-25 09:49:39 +00:00
|
|
|
|
{
|
2003-06-22 08:45:48 +00:00
|
|
|
|
return search_for_method_in_class (class, sel);
|
2003-03-25 09:49:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-06-22 08:45:48 +00:00
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
GSMethod
|
|
|
|
|
GSGetClassMethodNotInhertited (Class class, SEL sel)
|
2003-03-25 14:57:08 +00:00
|
|
|
|
{
|
2003-06-22 08:45:48 +00:00
|
|
|
|
return search_for_method_in_class (class->class_pointer, sel);
|
2003-03-25 14:57:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-05 13:54:26 +00:00
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
GSMethodList
|
|
|
|
|
GSAllocMethodList (unsigned int count)
|
|
|
|
|
{
|
|
|
|
|
GSMethodList list;
|
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
|
|
size = (sizeof (struct objc_method_list) +
|
|
|
|
|
sizeof (struct objc_method[count]));
|
|
|
|
|
list = objc_malloc (size);
|
|
|
|
|
memset(list, 0, size);
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
void
|
|
|
|
|
GSAppendMethodToList (GSMethodList list,
|
|
|
|
|
SEL sel,
|
|
|
|
|
const char *types,
|
|
|
|
|
IMP imp,
|
|
|
|
|
BOOL isFree)
|
|
|
|
|
{
|
|
|
|
|
unsigned int num;
|
|
|
|
|
|
|
|
|
|
num = (list->method_count)++;
|
|
|
|
|
|
|
|
|
|
#ifdef GNU_RUNTIME
|
|
|
|
|
/*
|
|
|
|
|
Deal with typed selectors: No matter what kind of selector we get
|
|
|
|
|
convert it into a c-string. Cache that c-string incase the
|
|
|
|
|
selector isn't found, then search for cooresponding typed selector.
|
|
|
|
|
If none is found use the cached name to register an new selector
|
|
|
|
|
with the cooresponding types.
|
|
|
|
|
*/
|
|
|
|
|
sel = (SEL)GSNameFromSelector (sel);
|
|
|
|
|
|
|
|
|
|
if (isFree == NO)
|
|
|
|
|
{
|
|
|
|
|
const char *sel_save = (const char *)sel;
|
|
|
|
|
|
|
|
|
|
sel = sel_get_typed_uid (sel_save, types);
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
sel = sel_register_typed_name (sel_save, types);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
list->method_list[num].method_name = sel;
|
|
|
|
|
list->method_list[num].method_types = types;
|
|
|
|
|
list->method_list[num].method_imp = imp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
BOOL
|
|
|
|
|
GSRemoveMethodFromList (GSMethodList list,
|
|
|
|
|
SEL sel,
|
|
|
|
|
BOOL isFree)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
#ifdef GNU_RUNTIME
|
|
|
|
|
if (isFree == YES)
|
|
|
|
|
{
|
|
|
|
|
sel = (SEL)GSNameFromSelector (sel);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
/* Insure that we always use sel_eq on non GNU Runtimes. */
|
|
|
|
|
isFree = NO;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < list->method_count; i++)
|
|
|
|
|
{
|
|
|
|
|
SEL method_name = list->method_list[i].method_name;
|
|
|
|
|
|
|
|
|
|
/* For the GNU runtime we have use strcmp instead of sel_eq
|
|
|
|
|
for free standing method lists. */
|
|
|
|
|
if ((isFree == YES && strcmp((char *)method_name, (char *)sel) == 0)
|
|
|
|
|
|| (isFree == NO && sel_eq(method_name, sel)))
|
|
|
|
|
{
|
|
|
|
|
/* Found the list. Now fill up the gap. */
|
|
|
|
|
for ((list->method_count)--; i < list->method_count; i++)
|
|
|
|
|
{
|
|
|
|
|
list->method_list[i].method_name
|
|
|
|
|
= list->method_list[i+1].method_name;
|
|
|
|
|
list->method_list[i].method_types
|
|
|
|
|
= list->method_list[i+1].method_types;
|
|
|
|
|
list->method_list[i].method_imp
|
|
|
|
|
= list->method_list[i+1].method_imp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear the last entry. */
|
|
|
|
|
list->method_list[i].method_name = 0;
|
|
|
|
|
list->method_list[i].method_types = 0;
|
|
|
|
|
list->method_list[i].method_imp = 0;
|
|
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
GSMethodList
|
|
|
|
|
GSMethodListForSelector(Class class,
|
|
|
|
|
SEL selector,
|
|
|
|
|
void **iterator,
|
|
|
|
|
BOOL searchInstanceMethods)
|
|
|
|
|
{
|
|
|
|
|
void *local_iterator = 0;
|
|
|
|
|
|
|
|
|
|
if (class == 0 || selector == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (searchInstanceMethods == NO)
|
|
|
|
|
{
|
|
|
|
|
class = class->class_pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(sel_is_mapped(selector))
|
|
|
|
|
{
|
|
|
|
|
void **iterator_pointer;
|
|
|
|
|
GSMethodList method_list;
|
|
|
|
|
|
|
|
|
|
iterator_pointer = (iterator == 0 ? &local_iterator : iterator);
|
|
|
|
|
while((method_list = class_nextMethodList(class, iterator_pointer)))
|
|
|
|
|
{
|
|
|
|
|
/* Search the method in the current list. */
|
|
|
|
|
if (GSMethodFromList(method_list, selector, NO) != 0)
|
|
|
|
|
{
|
|
|
|
|
return method_list;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
GSMethod
|
|
|
|
|
GSMethodFromList(GSMethodList list,
|
|
|
|
|
SEL sel,
|
|
|
|
|
BOOL isFree)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
#ifdef GNU_RUNTIME
|
|
|
|
|
if (isFree)
|
|
|
|
|
{
|
|
|
|
|
sel = (SEL)GSNameFromSelector (sel);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
isFree = NO;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < list->method_count; ++i)
|
|
|
|
|
{
|
|
|
|
|
GSMethod method = &list->method_list[i];
|
|
|
|
|
SEL method_name = method->method_name;
|
|
|
|
|
|
|
|
|
|
/* For the GNU runtime we have use strcmp instead of sel_eq
|
|
|
|
|
for free standing method lists. */
|
|
|
|
|
if ((isFree == YES && strcmp((char *)method_name, (char *)sel) == 0)
|
|
|
|
|
|| (isFree == NO && sel_eq(method_name, sel)))
|
|
|
|
|
{
|
|
|
|
|
return method;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
void
|
|
|
|
|
GSAddMethodList(Class class,
|
|
|
|
|
GSMethodList list,
|
|
|
|
|
BOOL toInstanceMethods)
|
|
|
|
|
{
|
|
|
|
|
if (class == 0 || list == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (toInstanceMethods == NO)
|
|
|
|
|
{
|
|
|
|
|
class = class->class_pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class_add_method_list(class, list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
void
|
|
|
|
|
GSRemoveMethodList(Class class,
|
|
|
|
|
GSMethodList list,
|
|
|
|
|
BOOL fromInstanceMethods)
|
|
|
|
|
{
|
|
|
|
|
if (class == 0 || list == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fromInstanceMethods == NO)
|
|
|
|
|
{
|
|
|
|
|
class = class->class_pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef NeXT_RUNTIME
|
|
|
|
|
class_removeMethods(class, list);
|
|
|
|
|
#else
|
|
|
|
|
if (list == class->methods)
|
|
|
|
|
{
|
|
|
|
|
class->methods = list->method_next;
|
|
|
|
|
list->method_next = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GSMethodList current_list;
|
|
|
|
|
for (current_list = class->methods;
|
|
|
|
|
current_list != 0;
|
|
|
|
|
current_list = current_list->method_next)
|
|
|
|
|
{
|
|
|
|
|
if (current_list->method_next == list)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
current_list->method_next = list->method_next;
|
|
|
|
|
list->method_next = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
The list has become "free standing".
|
|
|
|
|
Replace all selector references with selector names
|
|
|
|
|
so the runtime can convert them again
|
|
|
|
|
it the list gets reinserted.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < list->method_count; i++)
|
|
|
|
|
{
|
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
|
|
name = GSNameFromSelector(list->method_list[i].method_name);
|
|
|
|
|
list->method_list[i].method_name = (SEL)name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* NeXT_RUNTIME */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-07-07 10:31:59 +00:00
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
GSIVar
|
|
|
|
|
GSCGetInstanceVariableDefinition(Class class, const char *name)
|
|
|
|
|
{
|
|
|
|
|
struct objc_ivar_list *list;
|
|
|
|
|
int i;
|
2003-07-12 12:44:12 +00:00
|
|
|
|
|
|
|
|
|
if (class == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2003-07-07 10:31:59 +00:00
|
|
|
|
list = class->ivars;
|
2003-07-12 12:44:12 +00:00
|
|
|
|
for (i = 0; (list != 0) && i < list->ivar_count; i++)
|
2003-07-07 10:31:59 +00:00
|
|
|
|
{
|
|
|
|
|
if (strcmp (list->ivar_list[i].ivar_name, name) == 0)
|
|
|
|
|
return &(list->ivar_list[i]);
|
|
|
|
|
}
|
|
|
|
|
class = GSObjCSuper(class);
|
|
|
|
|
if (class != 0)
|
|
|
|
|
{
|
|
|
|
|
return GSCGetInstanceVariableDefinition(class, name);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GSIVar
|
|
|
|
|
GSObjCGetInstanceVariableDefinition(Class class, NSString *name)
|
|
|
|
|
{
|
|
|
|
|
return GSCGetInstanceVariableDefinition(class, [name cString]);
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-09 19:29:16 +00:00
|
|
|
|
typedef struct {
|
|
|
|
|
@defs(Protocol)
|
|
|
|
|
} *pcl;
|
|
|
|
|
|
|
|
|
|
GS_STATIC_INLINE unsigned int
|
|
|
|
|
gs_string_hash(const char *s)
|
|
|
|
|
{
|
|
|
|
|
unsigned int val = 0;
|
|
|
|
|
while (*s != 0)
|
|
|
|
|
{
|
|
|
|
|
val = (val << 5) + val + *s++;
|
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GS_STATIC_INLINE pcl
|
|
|
|
|
gs_find_protocol_named_in_protocol_list(const char *name,
|
|
|
|
|
struct objc_protocol_list *pcllist)
|
|
|
|
|
{
|
|
|
|
|
pcl p = NULL;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
while (pcllist != NULL)
|
|
|
|
|
{
|
|
|
|
|
for (i=0; i<pcllist->count; i++)
|
|
|
|
|
{
|
|
|
|
|
p = (pcl)pcllist->list[i];
|
|
|
|
|
if (strcmp(p->protocol_name, name) == 0)
|
|
|
|
|
{
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pcllist = pcllist->next;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GS_STATIC_INLINE pcl
|
|
|
|
|
gs_find_protocol_named(const char *name)
|
|
|
|
|
{
|
|
|
|
|
pcl p = NULL;
|
|
|
|
|
Class cls;
|
|
|
|
|
#ifdef NeXT_RUNTIME
|
|
|
|
|
Class *clsList, *clsListStart;
|
|
|
|
|
unsigned int num;
|
|
|
|
|
|
|
|
|
|
/* Setting the clearCache flag is a noop for the Apple runtime. */
|
|
|
|
|
num = GSClassList(NULL, 0, NO);
|
|
|
|
|
clsList = objc_malloc(sizeof(Class) * (num + 1));
|
|
|
|
|
GSClassList(clsList, num, NO);
|
|
|
|
|
|
|
|
|
|
clsListStart = clsList;
|
|
|
|
|
|
|
|
|
|
while(p == NULL && (cls = *clsList++))
|
|
|
|
|
{
|
|
|
|
|
p = gs_find_protocol_named_in_protocol_list(name, cls->protocols);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
objc_free(clsListStart);
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
void *iterator = NULL;
|
|
|
|
|
|
|
|
|
|
while(p == NULL && (cls = objc_next_class(&iterator)))
|
|
|
|
|
{
|
|
|
|
|
p = gs_find_protocol_named_in_protocol_list(name, cls->protocols);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define GSI_MAP_HAS_VALUE 1
|
|
|
|
|
#define GSI_MAP_RETAIN_KEY(M, X)
|
|
|
|
|
#define GSI_MAP_RETAIN_VAL(M, X)
|
|
|
|
|
#define GSI_MAP_RELEASE_KEY(M, X)
|
|
|
|
|
#define GSI_MAP_RELEASE_VAL(M, X)
|
|
|
|
|
#define GSI_MAP_HASH(M, X) (gs_string_hash(X.ptr))
|
|
|
|
|
#define GSI_MAP_EQUAL(M, X,Y) (strcmp(X.ptr, Y.ptr) == 0)
|
|
|
|
|
#define GSI_MAP_NOCLEAN 1
|
|
|
|
|
|
|
|
|
|
#define GSI_MAP_KTYPES GSUNION_PTR
|
|
|
|
|
#define GSI_MAP_VTYPES GSUNION_PTR
|
|
|
|
|
|
|
|
|
|
#include "GNUstepBase/GSIMap.h"
|
|
|
|
|
|
|
|
|
|
static GSIMapTable_t protocol_by_name;
|
|
|
|
|
static BOOL protocol_by_name_init = NO;
|
|
|
|
|
static volatile objc_mutex_t protocol_by_name_lock = NULL;
|
|
|
|
|
|
|
|
|
|
/* Not sure about the semantics of inlining
|
|
|
|
|
functions with static variables. */
|
|
|
|
|
static void
|
|
|
|
|
gs_init_protocol_lock(void)
|
|
|
|
|
{
|
|
|
|
|
if (protocol_by_name_lock == NULL)
|
|
|
|
|
{
|
|
|
|
|
GSAllocateMutexAt((void *)&protocol_by_name_lock);
|
|
|
|
|
objc_mutex_lock(protocol_by_name_lock);
|
|
|
|
|
if (protocol_by_name_init == NO)
|
|
|
|
|
{
|
|
|
|
|
GSIMapInitWithZoneAndCapacity (&protocol_by_name,
|
|
|
|
|
NSDefaultMallocZone(),
|
|
|
|
|
128);
|
|
|
|
|
protocol_by_name_init = YES;
|
|
|
|
|
}
|
|
|
|
|
objc_mutex_unlock(protocol_by_name_lock);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
GSRegisterProtocol(Protocol *proto)
|
|
|
|
|
{
|
|
|
|
|
if (protocol_by_name_init == NO)
|
|
|
|
|
{
|
|
|
|
|
gs_init_protocol_lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (proto != nil)
|
|
|
|
|
{
|
|
|
|
|
GSIMapNode node;
|
|
|
|
|
pcl p;
|
|
|
|
|
|
|
|
|
|
p = (pcl)proto;
|
|
|
|
|
objc_mutex_lock(protocol_by_name_lock);
|
|
|
|
|
node = GSIMapNodeForKey(&protocol_by_name,
|
|
|
|
|
(GSIMapKey) p->protocol_name);
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
GSIMapAddPairNoRetain(&protocol_by_name,
|
|
|
|
|
(GSIMapKey) (void *) p->protocol_name,
|
|
|
|
|
(GSIMapVal) (void *) p);
|
|
|
|
|
}
|
|
|
|
|
objc_mutex_unlock(protocol_by_name_lock);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Protocol *
|
|
|
|
|
GSProtocolFromName(const char *name)
|
|
|
|
|
{
|
|
|
|
|
GSIMapNode node;
|
|
|
|
|
pcl p;
|
|
|
|
|
|
|
|
|
|
if (protocol_by_name_init == NO)
|
|
|
|
|
{
|
|
|
|
|
gs_init_protocol_lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
|
|
|
|
|
if (node)
|
|
|
|
|
{
|
|
|
|
|
p = node->value.ptr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
objc_mutex_lock(protocol_by_name_lock);
|
|
|
|
|
node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
|
|
|
|
|
|
|
|
|
|
if (node)
|
|
|
|
|
{
|
|
|
|
|
p = node->value.ptr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p = gs_find_protocol_named(name);
|
|
|
|
|
if (p)
|
|
|
|
|
{
|
|
|
|
|
/* Use the protocol's name to save us from allocating
|
|
|
|
|
a copy of the parameter 'name'. */
|
|
|
|
|
GSIMapAddPairNoRetain(&protocol_by_name,
|
|
|
|
|
(GSIMapKey) (void *) p->protocol_name,
|
|
|
|
|
(GSIMapVal) (void *) p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
objc_mutex_unlock(protocol_by_name_lock);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (Protocol *)p;
|
|
|
|
|
}
|
2003-07-07 10:31:59 +00:00
|
|
|
|
|
2003-03-25 09:49:39 +00:00
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>A Behavior can be seen as a "Protocol with an implementation" or a
|
|
|
|
|
* "Class without any instance variables". A key feature of behaviors
|
|
|
|
|
* is that they give a degree of multiple inheritance.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>Behavior methods, when added to a class, override the class's
|
|
|
|
|
* superclass methods, but not the class's methods.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>It's not the case that a class adding behaviors from another class
|
|
|
|
|
* must have "no instance vars". The receiver class just has to have the
|
|
|
|
|
* same layout as the behavior class (optionally with some additional
|
|
|
|
|
* ivars after those of the behavior class).
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>This function provides Behaviors without adding any new syntax to
|
|
|
|
|
* the Objective C language. Simply define a class with the methods you
|
|
|
|
|
* want to add, then call this function with that class as the behavior
|
|
|
|
|
* argument.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>This function should be called in the +initialize method of the receiver.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>If you add several behaviors to a class, be aware that the order of
|
|
|
|
|
* the additions is significant.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
GSObjCAddClassBehavior(Class receiver, Class behavior)
|
|
|
|
|
{
|
|
|
|
|
Class behavior_super_class = GSObjCSuper(behavior);
|
|
|
|
|
|
|
|
|
|
NSCAssert(CLS_ISCLASS(receiver), NSInvalidArgumentException);
|
|
|
|
|
NSCAssert(CLS_ISCLASS(behavior), NSInvalidArgumentException);
|
|
|
|
|
|
2002-12-03 02:50:07 +00:00
|
|
|
|
/* If necessary, increase instance_size of CLASS. */
|
2002-11-27 12:52:29 +00:00
|
|
|
|
if (receiver->instance_size < behavior->instance_size)
|
|
|
|
|
{
|
2002-12-03 02:50:07 +00:00
|
|
|
|
#if NeXT_RUNTIME
|
2002-11-27 12:52:29 +00:00
|
|
|
|
NSCAssert2(receiver->instance_size >= behavior->instance_size,
|
2002-12-03 02:50:07 +00:00
|
|
|
|
@"Trying to add behavior (%s) with instance size larger than class (%s)",
|
|
|
|
|
class_get_class_name(behavior), class_get_class_name(receiver));
|
2002-11-27 12:52:29 +00:00
|
|
|
|
#else
|
|
|
|
|
NSCAssert(!receiver->subclass_list,
|
|
|
|
|
@"The behavior-addition code wants to increase the\n"
|
|
|
|
|
@"instance size of a class, but it cannot because you\n"
|
|
|
|
|
@"have subclassed the class. There are two solutions:\n"
|
|
|
|
|
@"(1) Don't subclass it; (2) Add placeholder instance\n"
|
|
|
|
|
@"variables to the class, so the behavior-addition code\n"
|
|
|
|
|
@"will not have to increase the instance size\n");
|
2002-12-03 02:50:07 +00:00
|
|
|
|
#endif
|
2002-11-27 12:52:29 +00:00
|
|
|
|
receiver->instance_size = behavior->instance_size;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-04 13:42:13 +00:00
|
|
|
|
BDBGPrintf("Adding behavior to class %s\n", receiver->name);
|
|
|
|
|
BDBGPrintf(" instance methods from %s\n", behavior->name);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
/* Add instance methods */
|
|
|
|
|
#if NeXT_RUNTIME
|
|
|
|
|
{
|
2004-06-05 21:11:00 +00:00
|
|
|
|
void *iterator = 0;
|
|
|
|
|
GSMethodList method_list;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
method_list = class_nextMethodList(behavior, &iterator);
|
|
|
|
|
while (method_list != 0)
|
|
|
|
|
{
|
|
|
|
|
GSObjCAddMethods (receiver, method_list);
|
|
|
|
|
method_list = class_nextMethodList(behavior, &iterator);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
GSObjCAddMethods (receiver, behavior->methods);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Add class methods */
|
2004-06-04 13:42:13 +00:00
|
|
|
|
BDBGPrintf("Adding class methods from %s\n",
|
|
|
|
|
behavior->class_pointer->name);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
#if NeXT_RUNTIME
|
|
|
|
|
{
|
2004-06-05 21:11:00 +00:00
|
|
|
|
void *iterator = 0;
|
|
|
|
|
GSMethodList method_list;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
method_list = class_nextMethodList(behavior->class_pointer, &iterator);
|
|
|
|
|
while (method_list != 0)
|
|
|
|
|
{
|
2002-12-03 02:50:07 +00:00
|
|
|
|
GSObjCAddMethods (receiver->class_pointer, method_list);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
method_list = class_nextMethodList(behavior->class_pointer, &iterator);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
GSObjCAddMethods (receiver->class_pointer, behavior->class_pointer->methods);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Add behavior's superclass, if not already there. */
|
|
|
|
|
if (!GSObjCIsKindOf(receiver, behavior_super_class))
|
|
|
|
|
{
|
|
|
|
|
GSObjCAddClassBehavior (receiver, behavior_super_class);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-02-03 04:15:27 +00:00
|
|
|
|
#ifndef NeXT_Foundation_LIBRARY
|
2002-11-27 12:52:29 +00:00
|
|
|
|
#include <Foundation/NSValue.h>
|
|
|
|
|
#include <Foundation/NSKeyValueCoding.h>
|
2003-02-03 04:15:27 +00:00
|
|
|
|
#endif
|
2002-11-28 09:35:36 +00:00
|
|
|
|
|
2003-05-22 17:00:03 +00:00
|
|
|
|
|
2002-11-28 09:35:36 +00:00
|
|
|
|
/** Deprecated ... use GSObjCGetValue() */
|
|
|
|
|
id
|
|
|
|
|
GSGetValue(NSObject *self, NSString *key, SEL sel,
|
2003-06-07 09:45:51 +00:00
|
|
|
|
const char *type, unsigned size, int offset)
|
2002-11-28 09:35:36 +00:00
|
|
|
|
{
|
|
|
|
|
return GSObjCGetValue(self, key, sel, type, size, offset);
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* This is used internally by the key-value coding methods, to get a
|
|
|
|
|
* value from an object either via an accessor method (if sel is
|
|
|
|
|
* supplied), or via direct access (if type, size, and offset are
|
|
|
|
|
* supplied).<br />
|
|
|
|
|
* Automatic conversion between NSNumber and C scalar types is performed.<br />
|
|
|
|
|
* If type is null and can't be determined from the selector, the
|
|
|
|
|
* [NSObject-handleQueryWithUnboundKey:] method is called to try
|
|
|
|
|
* to get a value.
|
|
|
|
|
*/
|
|
|
|
|
id
|
2002-11-28 09:35:36 +00:00
|
|
|
|
GSObjCGetValue(NSObject *self, NSString *key, SEL sel,
|
2003-06-07 09:45:51 +00:00
|
|
|
|
const char *type, unsigned size, int offset)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
|
|
|
|
if (sel != 0)
|
|
|
|
|
{
|
|
|
|
|
NSMethodSignature *sig = [self methodSignatureForSelector: sel];
|
|
|
|
|
|
|
|
|
|
if ([sig numberOfArguments] != 2)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"key-value get method has wrong number of args"];
|
|
|
|
|
}
|
|
|
|
|
type = [sig methodReturnType];
|
|
|
|
|
}
|
|
|
|
|
if (type == NULL)
|
|
|
|
|
{
|
|
|
|
|
return [self handleQueryWithUnboundKey: key];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
id val = nil;
|
|
|
|
|
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_ID:
|
|
|
|
|
case _C_CLASS:
|
|
|
|
|
{
|
|
|
|
|
id v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(id *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
id (*imp)(id, SEL) =
|
|
|
|
|
(id (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = v;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_CHR:
|
|
|
|
|
{
|
|
|
|
|
signed char v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(char *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
signed char (*imp)(id, SEL) =
|
|
|
|
|
(signed char (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithChar: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_UCHR:
|
|
|
|
|
{
|
|
|
|
|
unsigned char v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(unsigned char *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned char (*imp)(id, SEL) =
|
|
|
|
|
(unsigned char (*)(id, SEL))[self methodForSelector:
|
|
|
|
|
sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithUnsignedChar: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_SHT:
|
|
|
|
|
{
|
|
|
|
|
short v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(short *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
short (*imp)(id, SEL) =
|
|
|
|
|
(short (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithShort: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_USHT:
|
|
|
|
|
{
|
|
|
|
|
unsigned short v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(unsigned short *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned short (*imp)(id, SEL) =
|
|
|
|
|
(unsigned short (*)(id, SEL))[self methodForSelector:
|
|
|
|
|
sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithUnsignedShort: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_INT:
|
|
|
|
|
{
|
|
|
|
|
int v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(int *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int (*imp)(id, SEL) =
|
|
|
|
|
(int (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithInt: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_UINT:
|
|
|
|
|
{
|
|
|
|
|
unsigned int v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(unsigned int *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned int (*imp)(id, SEL) =
|
|
|
|
|
(unsigned int (*)(id, SEL))[self methodForSelector:
|
|
|
|
|
sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithUnsignedInt: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_LNG:
|
|
|
|
|
{
|
|
|
|
|
long v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(long *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
long (*imp)(id, SEL) =
|
|
|
|
|
(long (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithLong: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_ULNG:
|
|
|
|
|
{
|
|
|
|
|
unsigned long v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(unsigned long *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned long (*imp)(id, SEL) =
|
|
|
|
|
(unsigned long (*)(id, SEL))[self methodForSelector:
|
|
|
|
|
sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithUnsignedLong: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
#ifdef _C_LNG_LNG
|
|
|
|
|
case _C_LNG_LNG:
|
|
|
|
|
{
|
|
|
|
|
long long v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(long long *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
long long (*imp)(id, SEL) =
|
|
|
|
|
(long long (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithLongLong: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef _C_ULNG_LNG
|
|
|
|
|
case _C_ULNG_LNG:
|
|
|
|
|
{
|
|
|
|
|
unsigned long long v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(unsigned long long *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned long long (*imp)(id, SEL) =
|
|
|
|
|
(unsigned long long (*)(id, SEL))[self
|
|
|
|
|
methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithUnsignedLongLong: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
case _C_FLT:
|
|
|
|
|
{
|
|
|
|
|
float v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(float *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
float (*imp)(id, SEL) =
|
|
|
|
|
(float (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithFloat: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_DBL:
|
|
|
|
|
{
|
|
|
|
|
double v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
v = *(double *)((char *)self + offset);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
double (*imp)(id, SEL) =
|
|
|
|
|
(double (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithDouble: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_VOID:
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL) =
|
|
|
|
|
(void (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = nil;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"key-value get method has unsupported type"];
|
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-28 09:35:36 +00:00
|
|
|
|
/** Deprecated ... use GSObjCSetValue() */
|
|
|
|
|
void
|
|
|
|
|
GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
|
2003-06-07 09:45:51 +00:00
|
|
|
|
const char *type, unsigned size, int offset)
|
2002-11-28 09:35:36 +00:00
|
|
|
|
{
|
|
|
|
|
GSObjCSetValue(self, key, val, sel, type, size, offset);
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* This is used internally by the key-value coding methods, to set a
|
|
|
|
|
* value in an object either via an accessor method (if sel is
|
|
|
|
|
* supplied), or via direct access (if type, size, and offset are
|
|
|
|
|
* supplied).<br />
|
|
|
|
|
* Automatic conversion between NSNumber and C scalar types is performed.<br />
|
|
|
|
|
* If type is null and can't be determined from the selector, the
|
|
|
|
|
* [NSObject-handleTakeValue:forUnboundKey:] method is called to try
|
|
|
|
|
* to set a value.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2002-11-28 09:35:36 +00:00
|
|
|
|
GSObjCSetValue(NSObject *self, NSString *key, id val, SEL sel,
|
2003-06-07 09:45:51 +00:00
|
|
|
|
const char *type, unsigned size, int offset)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
2003-03-23 07:06:27 +00:00
|
|
|
|
static NSNull *null = nil;
|
|
|
|
|
|
|
|
|
|
if (null == nil)
|
|
|
|
|
{
|
|
|
|
|
null = [NSNull new];
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
if (sel != 0)
|
|
|
|
|
{
|
|
|
|
|
NSMethodSignature *sig = [self methodSignatureForSelector: sel];
|
|
|
|
|
|
|
|
|
|
if ([sig numberOfArguments] != 3)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"key-value set method has wrong number of args"];
|
|
|
|
|
}
|
|
|
|
|
type = [sig getArgumentTypeAtIndex: 2];
|
|
|
|
|
}
|
|
|
|
|
if (type == NULL)
|
|
|
|
|
{
|
|
|
|
|
[self handleTakeValue: val forUnboundKey: key];
|
|
|
|
|
}
|
2003-03-23 07:06:27 +00:00
|
|
|
|
else if ((val == nil || val == null) && *type != _C_ID && *type != _C_CLASS)
|
|
|
|
|
{
|
|
|
|
|
[self unableToSetNilForKey: key];
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_ID:
|
|
|
|
|
case _C_CLASS:
|
|
|
|
|
{
|
|
|
|
|
id v = val;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
id *ptr = (id *)((char *)self + offset);
|
|
|
|
|
|
2003-03-23 07:06:27 +00:00
|
|
|
|
ASSIGN(*ptr, v);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, id) =
|
|
|
|
|
(void (*)(id, SEL, id))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_CHR:
|
|
|
|
|
{
|
|
|
|
|
char v = [val charValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
char *ptr = (char *)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, char) =
|
|
|
|
|
(void (*)(id, SEL, char))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_UCHR:
|
|
|
|
|
{
|
|
|
|
|
unsigned char v = [val unsignedCharValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *ptr = (unsigned char*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, unsigned char) =
|
|
|
|
|
(void (*)(id, SEL, unsigned char))[self methodForSelector:
|
|
|
|
|
sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_SHT:
|
|
|
|
|
{
|
|
|
|
|
short v = [val shortValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
short *ptr = (short*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, short) =
|
|
|
|
|
(void (*)(id, SEL, short))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_USHT:
|
|
|
|
|
{
|
|
|
|
|
unsigned short v = [val unsignedShortValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
unsigned short *ptr;
|
|
|
|
|
|
|
|
|
|
ptr = (unsigned short*)((char *)self + offset);
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, unsigned short) =
|
|
|
|
|
(void (*)(id, SEL, unsigned short))[self methodForSelector:
|
|
|
|
|
sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_INT:
|
|
|
|
|
{
|
|
|
|
|
int v = [val intValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
int *ptr = (int*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, int) =
|
|
|
|
|
(void (*)(id, SEL, int))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_UINT:
|
|
|
|
|
{
|
|
|
|
|
unsigned int v = [val unsignedIntValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
unsigned int *ptr = (unsigned int*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, unsigned int) =
|
|
|
|
|
(void (*)(id, SEL, unsigned int))[self methodForSelector:
|
|
|
|
|
sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_LNG:
|
|
|
|
|
{
|
|
|
|
|
long v = [val longValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
long *ptr = (long*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, long) =
|
|
|
|
|
(void (*)(id, SEL, long))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_ULNG:
|
|
|
|
|
{
|
|
|
|
|
unsigned long v = [val unsignedLongValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
unsigned long *ptr = (unsigned long*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, unsigned long) =
|
|
|
|
|
(void (*)(id, SEL, unsigned long))[self methodForSelector:
|
|
|
|
|
sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
#ifdef _C_LNG_LNG
|
|
|
|
|
case _C_LNG_LNG:
|
|
|
|
|
{
|
|
|
|
|
long long v = [val longLongValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
long long *ptr = (long long*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, long long) =
|
|
|
|
|
(void (*)(id, SEL, long long))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef _C_ULNG_LNG
|
|
|
|
|
case _C_ULNG_LNG:
|
|
|
|
|
{
|
|
|
|
|
unsigned long long v = [val unsignedLongLongValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
unsigned long long *ptr = (unsigned long long*)((char*)self +
|
|
|
|
|
offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, unsigned long long) =
|
|
|
|
|
(void (*)(id, SEL, unsigned long long))[self
|
|
|
|
|
methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
case _C_FLT:
|
|
|
|
|
{
|
|
|
|
|
float v = [val floatValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
float *ptr = (float*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, float) =
|
|
|
|
|
(void (*)(id, SEL, float))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_DBL:
|
|
|
|
|
{
|
|
|
|
|
double v = [val doubleValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
double *ptr = (double*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, double) =
|
|
|
|
|
(void (*)(id, SEL, double))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"key-value set method has unsupported type"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-02 07:47:18 +00:00
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
GSAutoreleasedBuffer(unsigned size)
|
|
|
|
|
{
|
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
return GC_malloc(size);
|
|
|
|
|
#else
|
|
|
|
|
#ifdef ALIGN
|
|
|
|
|
#undef ALIGN
|
|
|
|
|
#endif
|
|
|
|
|
#define ALIGN __alignof__(double)
|
|
|
|
|
|
|
|
|
|
static Class nsobject_class = 0;
|
|
|
|
|
static Class autorelease_class;
|
|
|
|
|
static SEL autorelease_sel;
|
|
|
|
|
static IMP autorelease_imp;
|
|
|
|
|
static int offset;
|
|
|
|
|
NSObject *o;
|
|
|
|
|
|
|
|
|
|
if (nsobject_class == 0)
|
|
|
|
|
{
|
|
|
|
|
nsobject_class = [NSObject class];
|
|
|
|
|
offset = nsobject_class->instance_size % ALIGN;
|
|
|
|
|
autorelease_class = [NSAutoreleasePool class];
|
|
|
|
|
autorelease_sel = @selector(addObject:);
|
|
|
|
|
autorelease_imp = [autorelease_class methodForSelector: autorelease_sel];
|
|
|
|
|
}
|
|
|
|
|
o = (NSObject*)NSAllocateObject(nsobject_class,
|
|
|
|
|
size + offset, NSDefaultMallocZone());
|
|
|
|
|
(*autorelease_imp)(autorelease_class, autorelease_sel, o);
|
|
|
|
|
return ((void*)&o[1]) + offset;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Getting a system error message on a variety of systems */
|
|
|
|
|
#ifdef __MINGW__
|
|
|
|
|
LPTSTR GetErrorMsg(DWORD msgId)
|
|
|
|
|
{
|
|
|
|
|
LPVOID lpMsgBuf;
|
|
|
|
|
|
|
|
|
|
FormatMessage(
|
|
|
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
|
NULL, msgId,
|
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
|
|
|
|
(LPTSTR)&lpMsgBuf, 0, NULL);
|
|
|
|
|
|
|
|
|
|
return (LPTSTR)lpMsgBuf;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
#ifndef HAVE_STRERROR
|
2003-06-07 09:45:51 +00:00
|
|
|
|
const char *
|
2002-11-27 12:52:29 +00:00
|
|
|
|
strerror(int eno)
|
|
|
|
|
{
|
2003-06-07 09:45:51 +00:00
|
|
|
|
extern char *sys_errlist[];
|
2002-11-27 12:52:29 +00:00
|
|
|
|
extern int sys_nerr;
|
|
|
|
|
|
|
|
|
|
if (eno < 0 || eno >= sys_nerr)
|
|
|
|
|
{
|
|
|
|
|
return("unknown error number");
|
|
|
|
|
}
|
|
|
|
|
return(sys_errlist[eno]);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif /* __MINGW__ */
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
GSLastErrorStr(long error_id)
|
|
|
|
|
{
|
|
|
|
|
#ifdef __MINGW__
|
|
|
|
|
return GetErrorMsg(GetLastError());
|
|
|
|
|
#else
|
|
|
|
|
return strerror(error_id);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2003-07-01 17:00:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
|
GSPrintf (FILE *fptr, NSString* format, ...)
|
|
|
|
|
{
|
|
|
|
|
static Class stringClass = 0;
|
|
|
|
|
static NSStringEncoding enc;
|
|
|
|
|
CREATE_AUTORELEASE_POOL(arp);
|
|
|
|
|
va_list ap;
|
|
|
|
|
NSString *message;
|
|
|
|
|
NSData *data;
|
|
|
|
|
BOOL ok = NO;
|
|
|
|
|
|
|
|
|
|
if (stringClass == 0)
|
|
|
|
|
{
|
2003-10-30 13:44:55 +00:00
|
|
|
|
stringClass = [NSString class];
|
|
|
|
|
enc = [stringClass defaultCStringEncoding];
|
2003-07-01 17:00:14 +00:00
|
|
|
|
}
|
|
|
|
|
message = [stringClass allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
va_start (ap, format);
|
|
|
|
|
message = [message initWithFormat: format locale: nil arguments: ap];
|
|
|
|
|
va_end (ap);
|
|
|
|
|
data = [message dataUsingEncoding: enc];
|
|
|
|
|
if (data == nil)
|
|
|
|
|
{
|
|
|
|
|
data = [message dataUsingEncoding: NSUTF8StringEncoding];
|
|
|
|
|
}
|
|
|
|
|
RELEASE(message);
|
|
|
|
|
|
|
|
|
|
if (data != nil)
|
|
|
|
|
{
|
|
|
|
|
unsigned int length = [data length];
|
|
|
|
|
|
|
|
|
|
if (length == 0 || fwrite([data bytes], 1, length, fptr) == length)
|
|
|
|
|
{
|
|
|
|
|
ok = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
RELEASE(arp);
|
|
|
|
|
return ok;
|
|
|
|
|
}
|