2002-11-27 12:52:29 +00:00
|
|
|
|
/** Implementation of ObjC runtime additions for GNUStep
|
2010-02-22 10:13:20 +00:00
|
|
|
|
Copyright (C) 1995-2010 Free Software Foundation, Inc.
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
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
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2002-11-27 12:52:29 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
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.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2002-11-27 12:52:29 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2007-11-29 20:53:26 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
|
Boston, MA 02111 USA.
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
<title>GSObjCRuntime function and macro reference</title>
|
|
|
|
|
$Date$ $Revision$
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
|
#import "common.h"
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "GNUstepBase/preface.h"
|
2003-02-03 04:15:27 +00:00
|
|
|
|
#ifndef NeXT_Foundation_LIBRARY
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "Foundation/NSArray.h"
|
|
|
|
|
#import "Foundation/NSAutoreleasePool.h"
|
|
|
|
|
#import "Foundation/NSData.h"
|
|
|
|
|
#import "Foundation/NSDictionary.h"
|
|
|
|
|
#import "Foundation/NSEnumerator.h"
|
|
|
|
|
#import "Foundation/NSException.h"
|
|
|
|
|
#import "Foundation/NSLock.h"
|
|
|
|
|
#import "Foundation/NSMethodSignature.h"
|
|
|
|
|
#import "Foundation/NSNull.h"
|
|
|
|
|
#import "Foundation/NSSet.h"
|
|
|
|
|
#import "Foundation/NSValue.h"
|
2003-02-03 04:15:27 +00:00
|
|
|
|
#else
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import <Foundation/Foundation.h>
|
2003-02-03 04:15:27 +00:00
|
|
|
|
#endif
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "GNUstepBase/GSObjCRuntime.h"
|
2004-05-09 19:29:16 +00:00
|
|
|
|
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "../GSPrivate.h"
|
2007-12-19 14:39:44 +00:00
|
|
|
|
|
2004-05-09 19:29:16 +00:00
|
|
|
|
#include <objc/Protocol.h>
|
|
|
|
|
|
2010-02-28 11:36:29 +00:00
|
|
|
|
#include <stdio.h>
|
2002-11-27 12:52:29 +00:00
|
|
|
|
#include <string.h>
|
2010-02-28 11:36:29 +00:00
|
|
|
|
#include <ctype.h>
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-01-23 17:00:13 +00:00
|
|
|
|
#ifndef NeXT_RUNTIME
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
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...) \
|
2004-06-06 20:28:57 +00:00
|
|
|
|
do { if (behavior_debug) { fprintf(stderr, (format) , ## args); } } while (0)
|
2004-06-04 13:42:13 +00:00
|
|
|
|
|
2010-02-22 10:13:20 +00:00
|
|
|
|
|
|
|
|
|
Class
|
|
|
|
|
GSObjCClass(id obj)
|
|
|
|
|
{
|
|
|
|
|
return object_getClass(obj);
|
|
|
|
|
}
|
|
|
|
|
Class GSObjCSuper(Class cls)
|
|
|
|
|
{
|
|
|
|
|
return class_getSuperclass(cls);
|
|
|
|
|
}
|
|
|
|
|
BOOL
|
|
|
|
|
GSObjCIsInstance(id obj)
|
|
|
|
|
{
|
|
|
|
|
Class c = object_getClass(obj);
|
|
|
|
|
|
|
|
|
|
if (c != Nil && class_isMetaClass(c) == NO)
|
|
|
|
|
return YES;
|
|
|
|
|
else
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
BOOL
|
|
|
|
|
GSObjCIsClass(Class cls)
|
|
|
|
|
{
|
|
|
|
|
if (class_isMetaClass(object_getClass(cls)))
|
|
|
|
|
return YES;
|
|
|
|
|
else
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
BOOL
|
|
|
|
|
GSObjCIsKindOf(Class cls, Class other)
|
|
|
|
|
{
|
|
|
|
|
while (cls != Nil)
|
|
|
|
|
{
|
|
|
|
|
if (cls == other)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
cls = class_getSuperclass(cls);
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
Class
|
|
|
|
|
GSClassFromName(const char *name)
|
|
|
|
|
{
|
|
|
|
|
return objc_lookUpClass(name);
|
|
|
|
|
}
|
|
|
|
|
const char *
|
|
|
|
|
GSNameFromClass(Class cls)
|
|
|
|
|
{
|
|
|
|
|
return class_getName(cls);
|
|
|
|
|
}
|
|
|
|
|
const char *
|
|
|
|
|
GSClassNameFromObject(id obj)
|
|
|
|
|
{
|
|
|
|
|
return class_getName(object_getClass(obj));
|
|
|
|
|
}
|
|
|
|
|
const char *
|
|
|
|
|
GSNameFromSelector(SEL sel)
|
|
|
|
|
{
|
|
|
|
|
return sel_getName(sel);
|
|
|
|
|
}
|
2010-02-25 05:07:34 +00:00
|
|
|
|
SEL
|
|
|
|
|
GSSelectorFromName(const char *name)
|
|
|
|
|
{
|
2010-02-28 11:17:49 +00:00
|
|
|
|
return sel_getUid(name);
|
2010-02-25 05:07:34 +00:00
|
|
|
|
}
|
|
|
|
|
SEL
|
|
|
|
|
GSSelectorFromNameAndTypes(const char *name, const char *types)
|
|
|
|
|
{
|
2010-02-28 11:17:49 +00:00
|
|
|
|
#if NeXT_RUNTIME
|
|
|
|
|
return sel_getUid(name);
|
|
|
|
|
#else
|
2010-02-25 05:07:34 +00:00
|
|
|
|
if (name == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SEL s;
|
|
|
|
|
|
|
|
|
|
if (types == 0)
|
|
|
|
|
{
|
|
|
|
|
s = sel_get_any_typed_uid(name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s = sel_get_typed_uid(name, types);
|
|
|
|
|
}
|
|
|
|
|
if (s == 0)
|
|
|
|
|
{
|
|
|
|
|
if (types == 0)
|
|
|
|
|
{
|
|
|
|
|
s = sel_register_name(name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s = sel_register_typed_name(name, types);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
2010-02-28 11:17:49 +00:00
|
|
|
|
#endif
|
2010-02-25 05:07:34 +00:00
|
|
|
|
}
|
|
|
|
|
const char *
|
|
|
|
|
GSTypesFromSelector(SEL sel)
|
|
|
|
|
{
|
|
|
|
|
#if NeXT_RUNTIME
|
|
|
|
|
return 0;
|
|
|
|
|
#else
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
return sel_get_type(sel);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
void
|
|
|
|
|
GSFlushMethodCacheForClass (Class cls)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-02-22 10:13:20 +00:00
|
|
|
|
int
|
|
|
|
|
GSObjCVersion(Class cls)
|
|
|
|
|
{
|
|
|
|
|
return class_getVersion(cls);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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,
|
2010-02-28 11:17:49 +00:00
|
|
|
|
const char **type, unsigned int *size, int *offset)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
2010-02-28 11:17:49 +00:00
|
|
|
|
Class class = object_getClass(obj);
|
2010-02-28 17:28:42 +00:00
|
|
|
|
Ivar ivar = class_getInstanceVariable(class, name);
|
2010-02-28 11:17:49 +00:00
|
|
|
|
|
|
|
|
|
if (ivar == 0)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const char *enc = ivar_getTypeEncoding(ivar);
|
|
|
|
|
|
|
|
|
|
if (type != 0)
|
|
|
|
|
{
|
|
|
|
|
*type = enc;
|
|
|
|
|
}
|
|
|
|
|
if (size != 0)
|
|
|
|
|
{
|
2010-02-28 11:51:59 +00:00
|
|
|
|
NSUInteger s;
|
|
|
|
|
NSUInteger a;
|
|
|
|
|
|
2010-03-01 10:34:35 +00:00
|
|
|
|
NSGetSizeAndAlignment(enc, &s, &a);
|
2010-02-28 11:51:59 +00:00
|
|
|
|
*size = s;
|
2010-02-28 11:17:49 +00:00
|
|
|
|
}
|
|
|
|
|
if (offset != 0)
|
|
|
|
|
{
|
|
|
|
|
*offset = ivar_getOffset(ivar);
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-03-02 10:17:24 +00:00
|
|
|
|
/**
|
2005-02-22 11:22:44 +00:00
|
|
|
|
* This method returns an array listing the names of all the
|
2003-03-02 10:17:24 +00:00
|
|
|
|
* 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 *
|
2010-03-05 05:24:43 +00:00
|
|
|
|
GSObjCMethodNames(id obj, BOOL recurse)
|
2003-03-02 10:17:24 +00:00
|
|
|
|
{
|
2004-06-05 21:11:00 +00:00
|
|
|
|
NSMutableSet *set;
|
|
|
|
|
NSArray *array;
|
|
|
|
|
Class class;
|
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];
|
|
|
|
|
|
2010-02-28 13:07:28 +00:00
|
|
|
|
class = object_getClass(obj);
|
2003-03-02 10:17:24 +00:00
|
|
|
|
|
2010-02-28 13:07:28 +00:00
|
|
|
|
while (class != Nil)
|
2003-03-02 10:17:24 +00:00
|
|
|
|
{
|
2010-02-28 13:07:28 +00:00
|
|
|
|
unsigned count;
|
|
|
|
|
Method *meth = class_copyMethodList(class, &count);
|
2003-03-02 10:17:24 +00:00
|
|
|
|
|
2010-02-28 13:07:28 +00:00
|
|
|
|
while (count-- > 0)
|
2003-03-02 10:17:24 +00:00
|
|
|
|
{
|
2010-02-28 13:07:28 +00:00
|
|
|
|
NSString *name;
|
2003-03-02 10:17:24 +00:00
|
|
|
|
|
2010-02-28 13:07:28 +00:00
|
|
|
|
name = [[NSString alloc] initWithFormat: @"%s",
|
|
|
|
|
method_getName(meth[count])];
|
|
|
|
|
[set addObject: name];
|
|
|
|
|
[name release];
|
2003-03-02 10:17:24 +00:00
|
|
|
|
}
|
2010-03-03 09:34:06 +00:00
|
|
|
|
if (meth != NULL)
|
|
|
|
|
{
|
|
|
|
|
free(meth);
|
|
|
|
|
}
|
2010-03-05 05:24:43 +00:00
|
|
|
|
if (NO == recurse)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-02-28 13:07:28 +00:00
|
|
|
|
class = class_getSuperclass(class);
|
2003-03-02 10:17:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
array = [set allObjects];
|
|
|
|
|
RELEASE(set);
|
|
|
|
|
return array;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2005-02-22 11:22:44 +00:00
|
|
|
|
* This method returns an array listing the names of all the
|
2003-03-02 10:17:24 +00:00
|
|
|
|
* 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 *
|
2010-03-05 05:24:43 +00:00
|
|
|
|
GSObjCVariableNames(id obj, BOOL recurse)
|
2003-03-02 10:17:24 +00:00
|
|
|
|
{
|
2010-02-28 13:11:02 +00:00
|
|
|
|
NSMutableSet *set;
|
|
|
|
|
NSArray *array;
|
|
|
|
|
Class class;
|
2003-03-02 10:17:24 +00:00
|
|
|
|
|
|
|
|
|
if (obj == nil)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2010-02-28 13:11:02 +00:00
|
|
|
|
/*
|
|
|
|
|
* Add names to a set so methods declared in superclasses
|
|
|
|
|
* and then overridden do not appear more than once.
|
|
|
|
|
*/
|
|
|
|
|
set = [[NSMutableSet alloc] initWithCapacity: 32];
|
|
|
|
|
|
2010-02-28 13:07:28 +00:00
|
|
|
|
class = object_getClass(obj);
|
2010-02-28 13:11:02 +00:00
|
|
|
|
|
|
|
|
|
while (class != Nil)
|
2003-03-02 10:17:24 +00:00
|
|
|
|
{
|
2010-02-28 13:11:02 +00:00
|
|
|
|
unsigned count;
|
|
|
|
|
Ivar *ivar = class_copyIvarList(class, &count);
|
2003-03-02 10:17:24 +00:00
|
|
|
|
|
2010-02-28 13:11:02 +00:00
|
|
|
|
while (count-- > 0)
|
|
|
|
|
{
|
|
|
|
|
NSString *name;
|
2003-03-02 10:17:24 +00:00
|
|
|
|
|
2010-02-28 13:11:02 +00:00
|
|
|
|
name = [[NSString alloc] initWithFormat: @"%s",
|
|
|
|
|
ivar_getName(ivar[count])];
|
|
|
|
|
[set addObject: name];
|
|
|
|
|
[name release];
|
2003-03-02 10:17:24 +00:00
|
|
|
|
}
|
2010-03-03 09:34:06 +00:00
|
|
|
|
if (ivar != NULL)
|
|
|
|
|
{
|
|
|
|
|
free(ivar);
|
|
|
|
|
}
|
2010-03-05 05:24:43 +00:00
|
|
|
|
if (NO == recurse)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-02-28 13:11:02 +00:00
|
|
|
|
class = class_getSuperclass(class);
|
2003-03-02 10:17:24 +00:00
|
|
|
|
}
|
2010-02-28 13:11:02 +00:00
|
|
|
|
|
|
|
|
|
array = [set allObjects];
|
|
|
|
|
RELEASE(set);
|
2003-03-02 10:17:24 +00:00
|
|
|
|
return array;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
2006-10-09 18:32:11 +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
|
|
|
|
|
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
|
|
|
|
/**
|
|
|
|
|
* 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)
|
|
|
|
|
{
|
|
|
|
|
int num;
|
|
|
|
|
|
|
|
|
|
if (buffer != NULL)
|
|
|
|
|
{
|
|
|
|
|
memset(buffer, 0, sizeof(Class) * (max + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
num = objc_getClassList(buffer, max);
|
|
|
|
|
num = (num < 0) ? 0 : num;
|
|
|
|
|
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)
|
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
Class newClass;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
Class classSuperClass;
|
|
|
|
|
const char *classNameCString;
|
|
|
|
|
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);
|
|
|
|
|
|
2010-03-03 09:34:06 +00:00
|
|
|
|
classNameCString = [name UTF8String];
|
|
|
|
|
tmp = malloc(strlen(classNameCString) + 1);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
strcpy(tmp, classNameCString);
|
|
|
|
|
classNameCString = tmp;
|
|
|
|
|
|
2010-03-03 09:34:06 +00:00
|
|
|
|
newClass = objc_allocateClassPair(classSuperClass, classNameCString, 0);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
if ([iVars count] > 0)
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *enumerator = [iVars keyEnumerator];
|
|
|
|
|
NSString *key;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
while ((key = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
2010-03-03 09:34:06 +00:00
|
|
|
|
const char *iVarName = [key UTF8String];
|
|
|
|
|
const char *iVarType = [[iVars objectForKey: key] UTF8String];
|
|
|
|
|
uint8_t iVarAlign = 0;
|
|
|
|
|
size_t iVarSize;
|
2010-02-28 11:51:59 +00:00
|
|
|
|
NSUInteger s;
|
2010-03-03 09:34:06 +00:00
|
|
|
|
NSUInteger a;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-03-03 09:34:06 +00:00
|
|
|
|
NSGetSizeAndAlignment(iVarType, &s, &a);
|
|
|
|
|
// Convert size to number of bitshifts needed for alignment.
|
|
|
|
|
iVarSize = 1;
|
|
|
|
|
while (iVarSize < s)
|
|
|
|
|
{
|
|
|
|
|
iVarSize <<= 1;
|
|
|
|
|
iVarAlign++;
|
|
|
|
|
}
|
|
|
|
|
// Record actual size
|
|
|
|
|
iVarSize = s;
|
|
|
|
|
if (NO
|
|
|
|
|
== class_addIvar(newClass, iVarName, iVarSize, iVarAlign, iVarType))
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Error adding ivar '%s' of type '%s'", iVarName, iVarType);
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [NSValue valueWithPointer: newClass];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The classes argument is an array of NSValue objects containing pointers
|
|
|
|
|
* to classes previously created by the GSObjCMakeClass() function.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
GSObjCAddClasses(NSArray *classes)
|
|
|
|
|
{
|
2010-03-04 08:15:08 +00:00
|
|
|
|
NSUInteger numClasses = [classes count];
|
|
|
|
|
NSUInteger i;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
for (i = 0; i < numClasses; i++)
|
|
|
|
|
{
|
2010-03-04 08:15:08 +00:00
|
|
|
|
objc_registerClassPair((Class)[[classes objectAtIndex: i] pointerValue]);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-03-04 08:15:08 +00:00
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
|
2010-03-08 09:27:48 +00:00
|
|
|
|
static BOOL behavior_debug = NO;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BOOL
|
2002-11-27 12:52:29 +00:00
|
|
|
|
GSObjCBehaviorDebug(int i)
|
|
|
|
|
{
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BOOL old = behavior_debug;
|
|
|
|
|
|
|
|
|
|
if (i == YES)
|
|
|
|
|
{
|
|
|
|
|
behavior_debug = YES;
|
|
|
|
|
}
|
|
|
|
|
else if (i == NO)
|
|
|
|
|
{
|
|
|
|
|
behavior_debug = NO;
|
|
|
|
|
}
|
|
|
|
|
return old;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
void
|
2010-03-05 05:24:43 +00:00
|
|
|
|
GSObjCAddMethods(Class cls, Method *list, BOOL replace)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
unsigned int index = 0;
|
2010-03-08 09:27:48 +00:00
|
|
|
|
char c;
|
2010-03-05 05:24:43 +00:00
|
|
|
|
Method m;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-03-05 05:24:43 +00:00
|
|
|
|
if (cls == 0 || list == 0)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
return;
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
2010-03-08 09:27:48 +00:00
|
|
|
|
c = class_isMetaClass(cls) ? '+' : '-';
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-03-05 05:24:43 +00:00
|
|
|
|
while ((m = list[index++]) != NULL)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
SEL n = method_getName(m);
|
|
|
|
|
IMP i = method_getImplementation(m);
|
|
|
|
|
const char *t = method_getTypeEncoding(m);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-03-05 05:24:43 +00:00
|
|
|
|
/* This will override a superclass method but will not replace a
|
|
|
|
|
* method which already exists in the class itsself.
|
|
|
|
|
*/
|
2010-03-08 08:09:49 +00:00
|
|
|
|
if (YES == class_addMethod(cls, n, i, t))
|
|
|
|
|
{
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BDBGPrintf(" added %c%s\n", c, sel_getName(n));
|
2010-03-08 08:09:49 +00:00
|
|
|
|
}
|
|
|
|
|
else if (YES == replace)
|
2002-11-27 12:52:29 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
/* If we want to replace an existing implemetation ...
|
|
|
|
|
*/
|
|
|
|
|
method_setImplementation(class_getInstanceMethod(cls, n), i);
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BDBGPrintf(" replaced %c%s\n", c, sel_getName(n));
|
2010-03-05 05:24:43 +00:00
|
|
|
|
}
|
2010-03-08 09:27:48 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BDBGPrintf(" skipped %c%s\n", c, sel_getName(n));
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
2003-03-25 09:49:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-06-22 08:45:48 +00:00
|
|
|
|
GSMethod
|
* Headers/Additions/GNUstepBase/GSObjCRuntime.h
* Source/Additions/GSObjCRuntime.m: Make ObjC++ safe.
(GSObjCSuper, GSObjCIsKindOf, GSNameFromClass)
(GSTypesFromSelector, GSGetMethod, GSFlushMethodCacheForClass)
(GSCGetInstanceVariableDefinition)
(GSObjCGetInstanceVariableDefinition)
(GSMethodListForSelector, GSAddMethodList, GSRemoveMethodList)
(GSObjCVersion, GSObjCName, GSObjCSelectorName)
(GSObjCSelectorTypes, GSGetInstanceMethod, GSGetClassMethod)
(GSGetInstanceMethodNotInherited, GSGetClassMethodNotInherited)
(search_for_method_in_class, GSObjCAddMethods): Replace class
and this with cls or sel.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@19790 72102866-910b-0410-8b05-ffd578937521
2004-07-29 12:55:05 +00:00
|
|
|
|
GSGetMethod(Class cls, SEL sel,
|
2010-03-05 05:24:43 +00:00
|
|
|
|
BOOL searchInstanceMethods,
|
|
|
|
|
BOOL searchSuperClasses)
|
2003-03-25 09:49:39 +00:00
|
|
|
|
{
|
* Headers/Additions/GNUstepBase/GSObjCRuntime.h
* Source/Additions/GSObjCRuntime.m: Make ObjC++ safe.
(GSObjCSuper, GSObjCIsKindOf, GSNameFromClass)
(GSTypesFromSelector, GSGetMethod, GSFlushMethodCacheForClass)
(GSCGetInstanceVariableDefinition)
(GSObjCGetInstanceVariableDefinition)
(GSMethodListForSelector, GSAddMethodList, GSRemoveMethodList)
(GSObjCVersion, GSObjCName, GSObjCSelectorName)
(GSObjCSelectorTypes, GSGetInstanceMethod, GSGetClassMethod)
(GSGetInstanceMethodNotInherited, GSGetClassMethodNotInherited)
(search_for_method_in_class, GSObjCAddMethods): Replace class
and this with cls or sel.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@19790 72102866-910b-0410-8b05-ffd578937521
2004-07-29 12:55:05 +00:00
|
|
|
|
if (cls == 0 || sel == 0)
|
2004-06-08 16:52:34 +00:00
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-03-25 09:49:39 +00:00
|
|
|
|
|
2004-06-08 16:52:34 +00:00
|
|
|
|
if (searchSuperClasses == NO)
|
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
unsigned int count;
|
|
|
|
|
Method method = NULL;
|
|
|
|
|
Method *methods;
|
|
|
|
|
|
2004-06-08 16:52:34 +00:00
|
|
|
|
if (searchInstanceMethods == NO)
|
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
methods = class_copyMethodList(object_getClass(cls), &count);
|
2004-06-08 16:52:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
methods = class_copyMethodList(cls, &count);
|
2004-06-08 16:52:34 +00:00
|
|
|
|
}
|
2010-03-05 05:24:43 +00:00
|
|
|
|
if (methods != NULL)
|
2004-06-08 16:52:34 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
unsigned int index = 0;
|
2004-06-05 13:54:26 +00:00
|
|
|
|
|
2010-03-05 05:24:43 +00:00
|
|
|
|
while ((method = methods[index++]) != NULL)
|
2004-06-05 13:54:26 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
if (sel_isEqual(sel, method_getName(method)))
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2004-06-05 13:54:26 +00:00
|
|
|
|
}
|
2010-03-05 05:24:43 +00:00
|
|
|
|
free(methods);
|
|
|
|
|
}
|
|
|
|
|
return method;
|
2004-06-05 13:54:26 +00:00
|
|
|
|
}
|
2010-03-05 05:24:43 +00:00
|
|
|
|
else
|
2004-06-05 13:54:26 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
if (searchInstanceMethods == NO)
|
2004-06-05 13:54:26 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
return class_getClassMethod(cls, sel);
|
2004-06-05 13:54:26 +00:00
|
|
|
|
}
|
2010-03-05 05:24:43 +00:00
|
|
|
|
else
|
2004-07-21 18:58:21 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
return class_getInstanceMethod(cls, sel);
|
2004-07-21 18:58:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-05 13:54:26 +00:00
|
|
|
|
|
2010-02-25 05:07:34 +00:00
|
|
|
|
static inline const char *
|
2004-08-19 16:19:48 +00:00
|
|
|
|
gs_skip_type_qualifier_and_layout_info (const char *types)
|
|
|
|
|
{
|
|
|
|
|
while (*types == '+'
|
2010-03-05 05:24:43 +00:00
|
|
|
|
|| *types == '-'
|
|
|
|
|
|| *types == _C_CONST
|
|
|
|
|
|| *types == _C_IN
|
|
|
|
|
|| *types == _C_INOUT
|
|
|
|
|
|| *types == _C_OUT
|
|
|
|
|
|| *types == _C_BYCOPY
|
|
|
|
|
|| *types == _C_BYREF
|
|
|
|
|
|| *types == _C_ONEWAY
|
|
|
|
|
|| *types == _C_GCINVISIBLE
|
|
|
|
|
|| isdigit ((unsigned char) *types))
|
2004-08-19 16:19:48 +00:00
|
|
|
|
{
|
|
|
|
|
types++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return types;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
GS_EXPORT BOOL
|
|
|
|
|
GSSelectorTypesMatch(const char *types1, const char *types2)
|
|
|
|
|
{
|
|
|
|
|
if (! types1 || ! types2)
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
|
|
while (*types1 && *types2)
|
|
|
|
|
{
|
|
|
|
|
types1 = gs_skip_type_qualifier_and_layout_info (types1);
|
|
|
|
|
types2 = gs_skip_type_qualifier_and_layout_info (types2);
|
|
|
|
|
|
2004-08-20 12:58:04 +00:00
|
|
|
|
/* Reached the end of the selector. */
|
2004-08-19 16:19:48 +00:00
|
|
|
|
if (! *types1 && ! *types2)
|
|
|
|
|
return YES;
|
|
|
|
|
|
2004-08-20 12:58:04 +00:00
|
|
|
|
/* Ignore structure name yet compare layout. */
|
|
|
|
|
if (*types1 == '{' && *types2 == '{')
|
|
|
|
|
{
|
2009-02-09 07:43:17 +00:00
|
|
|
|
while (*types1 != '=' && *types1 != '}')
|
2004-08-20 12:58:04 +00:00
|
|
|
|
types1++;
|
|
|
|
|
|
2009-02-09 07:43:17 +00:00
|
|
|
|
while (*types2 != '=' && *types2 != '}')
|
2004-08-20 12:58:04 +00:00
|
|
|
|
types2++;
|
|
|
|
|
}
|
|
|
|
|
|
2004-08-19 16:19:48 +00:00
|
|
|
|
if (*types1 != *types2)
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
|
|
types1++;
|
|
|
|
|
types2++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
types1 = gs_skip_type_qualifier_and_layout_info (types1);
|
|
|
|
|
types2 = gs_skip_type_qualifier_and_layout_info (types2);
|
|
|
|
|
|
|
|
|
|
return (! *types1 && ! *types2);
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-07 10:31:59 +00:00
|
|
|
|
/* See header for documentation. */
|
|
|
|
|
GSIVar
|
* Headers/Additions/GNUstepBase/GSObjCRuntime.h
* Source/Additions/GSObjCRuntime.m: Make ObjC++ safe.
(GSObjCSuper, GSObjCIsKindOf, GSNameFromClass)
(GSTypesFromSelector, GSGetMethod, GSFlushMethodCacheForClass)
(GSCGetInstanceVariableDefinition)
(GSObjCGetInstanceVariableDefinition)
(GSMethodListForSelector, GSAddMethodList, GSRemoveMethodList)
(GSObjCVersion, GSObjCName, GSObjCSelectorName)
(GSObjCSelectorTypes, GSGetInstanceMethod, GSGetClassMethod)
(GSGetInstanceMethodNotInherited, GSGetClassMethodNotInherited)
(search_for_method_in_class, GSObjCAddMethods): Replace class
and this with cls or sel.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@19790 72102866-910b-0410-8b05-ffd578937521
2004-07-29 12:55:05 +00:00
|
|
|
|
GSCGetInstanceVariableDefinition(Class cls, const char *name)
|
2003-07-07 10:31:59 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
return class_getInstanceVariable(cls, name);
|
2003-07-07 10:31:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GSIVar
|
* Headers/Additions/GNUstepBase/GSObjCRuntime.h
* Source/Additions/GSObjCRuntime.m: Make ObjC++ safe.
(GSObjCSuper, GSObjCIsKindOf, GSNameFromClass)
(GSTypesFromSelector, GSGetMethod, GSFlushMethodCacheForClass)
(GSCGetInstanceVariableDefinition)
(GSObjCGetInstanceVariableDefinition)
(GSMethodListForSelector, GSAddMethodList, GSRemoveMethodList)
(GSObjCVersion, GSObjCName, GSObjCSelectorName)
(GSObjCSelectorTypes, GSGetInstanceMethod, GSGetClassMethod)
(GSGetInstanceMethodNotInherited, GSGetClassMethodNotInherited)
(search_for_method_in_class, GSObjCAddMethods): Replace class
and this with cls or sel.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@19790 72102866-910b-0410-8b05-ffd578937521
2004-07-29 12:55:05 +00:00
|
|
|
|
GSObjCGetInstanceVariableDefinition(Class cls, NSString *name)
|
2003-07-07 10:31:59 +00:00
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
return class_getInstanceVariable(cls, [name UTF8String]);
|
2003-07-07 10:31:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-05-09 19:29:16 +00:00
|
|
|
|
|
2010-02-25 05:07:34 +00:00
|
|
|
|
static inline unsigned int
|
2004-05-09 19:29:16 +00:00
|
|
|
|
gs_string_hash(const char *s)
|
|
|
|
|
{
|
|
|
|
|
unsigned int val = 0;
|
|
|
|
|
while (*s != 0)
|
|
|
|
|
{
|
|
|
|
|
val = (val << 5) + val + *s++;
|
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#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"
|
2010-03-05 05:52:17 +00:00
|
|
|
|
#include <pthread.h>
|
2004-05-09 19:29:16 +00:00
|
|
|
|
|
|
|
|
|
static GSIMapTable_t protocol_by_name;
|
|
|
|
|
static BOOL protocol_by_name_init = NO;
|
2010-01-23 17:00:13 +00:00
|
|
|
|
static pthread_mutex_t protocol_by_name_lock = PTHREAD_MUTEX_INITIALIZER;
|
2004-05-09 19:29:16 +00:00
|
|
|
|
|
|
|
|
|
/* Not sure about the semantics of inlining
|
|
|
|
|
functions with static variables. */
|
|
|
|
|
static void
|
|
|
|
|
gs_init_protocol_lock(void)
|
|
|
|
|
{
|
2010-01-23 17:00:13 +00:00
|
|
|
|
pthread_mutex_lock(&protocol_by_name_lock);
|
|
|
|
|
if (protocol_by_name_init == NO)
|
|
|
|
|
{
|
2004-05-09 19:29:16 +00:00
|
|
|
|
GSIMapInitWithZoneAndCapacity (&protocol_by_name,
|
|
|
|
|
NSDefaultMallocZone(),
|
|
|
|
|
128);
|
|
|
|
|
protocol_by_name_init = YES;
|
|
|
|
|
}
|
2010-01-23 17:00:13 +00:00
|
|
|
|
pthread_mutex_unlock(&protocol_by_name_lock);
|
2004-05-09 19:29:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
GSRegisterProtocol(Protocol *proto)
|
|
|
|
|
{
|
|
|
|
|
if (protocol_by_name_init == NO)
|
|
|
|
|
{
|
|
|
|
|
gs_init_protocol_lock();
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-05-09 19:29:16 +00:00
|
|
|
|
if (proto != nil)
|
|
|
|
|
{
|
|
|
|
|
GSIMapNode node;
|
|
|
|
|
|
2010-01-23 17:00:13 +00:00
|
|
|
|
pthread_mutex_lock(&protocol_by_name_lock);
|
2010-03-05 05:52:17 +00:00
|
|
|
|
node = GSIMapNodeForKey(&protocol_by_name,
|
|
|
|
|
(GSIMapKey)protocol_getName(proto));
|
2004-05-09 19:29:16 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
GSIMapAddPairNoRetain(&protocol_by_name,
|
2010-03-05 05:52:17 +00:00
|
|
|
|
(GSIMapKey)(void*)protocol_getName(proto),
|
|
|
|
|
(GSIMapVal)(void*)proto);
|
2004-05-09 19:29:16 +00:00
|
|
|
|
}
|
2010-01-23 17:00:13 +00:00
|
|
|
|
pthread_mutex_unlock(&protocol_by_name_lock);
|
2004-05-09 19:29:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Protocol *
|
|
|
|
|
GSProtocolFromName(const char *name)
|
|
|
|
|
{
|
|
|
|
|
GSIMapNode node;
|
2010-02-24 10:23:47 +00:00
|
|
|
|
Protocol *p;
|
2004-05-09 19:29:16 +00:00
|
|
|
|
|
|
|
|
|
if (protocol_by_name_init == NO)
|
|
|
|
|
{
|
|
|
|
|
gs_init_protocol_lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
|
|
|
|
|
if (node)
|
|
|
|
|
{
|
|
|
|
|
p = node->value.ptr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-01-23 17:00:13 +00:00
|
|
|
|
pthread_mutex_lock(&protocol_by_name_lock);
|
2004-05-09 19:29:16 +00:00
|
|
|
|
node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
|
|
|
|
|
|
|
|
|
|
if (node)
|
|
|
|
|
{
|
|
|
|
|
p = node->value.ptr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-03-05 05:44:39 +00:00
|
|
|
|
p = objc_getProtocol(name);
|
2004-05-09 19:29:16 +00:00
|
|
|
|
if (p)
|
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
/* Use the protocol's name to save us from allocating
|
2004-05-09 19:29:16 +00:00
|
|
|
|
a copy of the parameter 'name'. */
|
2005-02-22 11:22:44 +00:00
|
|
|
|
GSIMapAddPairNoRetain(&protocol_by_name,
|
2010-03-05 05:52:17 +00:00
|
|
|
|
(GSIMapKey)(void*)protocol_getName(p),
|
|
|
|
|
(GSIMapVal)(void*)p);
|
2004-05-09 19:29:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-01-23 17:00:13 +00:00
|
|
|
|
pthread_mutex_unlock(&protocol_by_name_lock);
|
2004-05-09 19:29:16 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-24 10:23:47 +00:00
|
|
|
|
return p;
|
2004-05-09 19:29:16 +00:00
|
|
|
|
}
|
2003-07-07 10:31:59 +00:00
|
|
|
|
|
2003-03-25 09:49:39 +00:00
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
void
|
|
|
|
|
GSObjCAddClassBehavior(Class receiver, Class behavior)
|
|
|
|
|
{
|
2010-03-05 05:24:43 +00:00
|
|
|
|
unsigned int count;
|
|
|
|
|
Method *methods;
|
|
|
|
|
Class behavior_super_class = class_getSuperclass(behavior);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-03-05 08:39:41 +00:00
|
|
|
|
if (YES == class_isMetaClass(receiver))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Trying to add behavior (%s) to meta class (%s)\n",
|
|
|
|
|
class_getName(behavior), class_getName(receiver));
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
if (YES == class_isMetaClass(behavior))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Trying to add meta class as behavior (%s) to (%s)\n",
|
|
|
|
|
class_getName(behavior), class_getName(receiver));
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
if (class_getInstanceSize(receiver) < class_getInstanceSize(behavior))
|
|
|
|
|
{
|
|
|
|
|
const char *b = class_getName(behavior);
|
|
|
|
|
const char *r = class_getName(receiver);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-03-05 08:39:41 +00:00
|
|
|
|
#ifdef NeXT_Foundation_LIBRARY
|
|
|
|
|
fprintf(stderr, "Trying to add behavior (%s) with instance "
|
|
|
|
|
"size larger than class (%s)\n", b, r);
|
|
|
|
|
abort();
|
|
|
|
|
#else
|
|
|
|
|
/* As a special case we allow adding GSString/GSCString to the
|
|
|
|
|
* constant string class ... since we know the base library
|
|
|
|
|
* takes care not to access non-existent instance variables.
|
|
|
|
|
*/
|
|
|
|
|
if ((strcmp(b, "GSCString") && strcmp(b, "GSString"))
|
|
|
|
|
|| (strcmp(r, "NSConstantString") && strcmp(r, "NXConstantString")))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Trying to add behavior (%s) with instance "
|
|
|
|
|
"size larger than class (%s)\n", b, r);
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2010-03-05 05:24:43 +00:00
|
|
|
|
BDBGPrintf("Adding behavior to class %s\n", class_getName(receiver));
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
/* Add instance methods */
|
2010-03-05 05:24:43 +00:00
|
|
|
|
methods = class_copyMethodList(behavior, &count);
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BDBGPrintf(" instance methods from %s %u\n", class_getName(behavior), count);
|
2010-03-08 08:09:49 +00:00
|
|
|
|
if (methods == NULL)
|
|
|
|
|
{
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BDBGPrintf(" none.\n");
|
2010-03-08 08:09:49 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2010-03-05 05:24:43 +00:00
|
|
|
|
{
|
|
|
|
|
GSObjCAddMethods (receiver, methods, NO);
|
|
|
|
|
free(methods);
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
/* Add class methods */
|
2010-03-05 05:24:43 +00:00
|
|
|
|
methods = class_copyMethodList(object_getClass(behavior), &count);
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BDBGPrintf(" class methods from %s %u\n", class_getName(behavior), count);
|
2010-03-08 08:09:49 +00:00
|
|
|
|
if (methods == NULL)
|
|
|
|
|
{
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BDBGPrintf(" none.\n");
|
2010-03-08 08:09:49 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2010-03-05 05:24:43 +00:00
|
|
|
|
{
|
|
|
|
|
GSObjCAddMethods (object_getClass(receiver), methods, NO);
|
|
|
|
|
free(methods);
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
/* Add behavior's superclass, if not already there. */
|
|
|
|
|
if (!GSObjCIsKindOf(receiver, behavior_super_class))
|
|
|
|
|
{
|
|
|
|
|
GSObjCAddClassBehavior (receiver, behavior_super_class);
|
|
|
|
|
}
|
2004-06-06 13:49:02 +00:00
|
|
|
|
GSFlushMethodCacheForClass (receiver);
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-03-07 13:35:07 +00:00
|
|
|
|
void
|
|
|
|
|
GSObjCAddClassOverride(Class receiver, Class override)
|
|
|
|
|
{
|
|
|
|
|
unsigned int count;
|
|
|
|
|
Method *methods;
|
|
|
|
|
|
|
|
|
|
if (YES == class_isMetaClass(receiver))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Trying to add override (%s) to meta class (%s)\n",
|
|
|
|
|
class_getName(override), class_getName(receiver));
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
if (YES == class_isMetaClass(override))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Trying to add meta class as override (%s) to (%s)\n",
|
|
|
|
|
class_getName(override), class_getName(receiver));
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
if (class_getInstanceSize(receiver) < class_getInstanceSize(override))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Trying to add override (%s) with instance "
|
|
|
|
|
"size larger than class (%s)\n",
|
|
|
|
|
class_getName(override), class_getName(receiver));
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BDBGPrintf("Adding override to class %s\n", class_getName(receiver));
|
|
|
|
|
|
|
|
|
|
/* Add instance methods */
|
|
|
|
|
methods = class_copyMethodList(override, &count);
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BDBGPrintf(" instance methods from %s %u\n", class_getName(override), count);
|
|
|
|
|
if (methods == NULL)
|
|
|
|
|
{
|
|
|
|
|
BDBGPrintf(" none.\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
2010-03-07 13:35:07 +00:00
|
|
|
|
{
|
|
|
|
|
GSObjCAddMethods (receiver, methods, YES);
|
|
|
|
|
free(methods);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add class methods */
|
|
|
|
|
methods = class_copyMethodList(object_getClass(override), &count);
|
2010-03-08 09:27:48 +00:00
|
|
|
|
BDBGPrintf(" class methods from %s %u\n", class_getName(override), count);
|
|
|
|
|
if (methods == NULL)
|
|
|
|
|
{
|
|
|
|
|
BDBGPrintf(" none.\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
2010-03-07 13:35:07 +00:00
|
|
|
|
{
|
|
|
|
|
GSObjCAddMethods (object_getClass(receiver), methods, YES);
|
|
|
|
|
free(methods);
|
|
|
|
|
}
|
|
|
|
|
GSFlushMethodCacheForClass (receiver);
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-02-03 04:15:27 +00:00
|
|
|
|
#ifndef NeXT_Foundation_LIBRARY
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "Foundation/NSValue.h"
|
|
|
|
|
#import "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-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
|
2006-02-27 09:35:19 +00:00
|
|
|
|
GSObjCGetVal(NSObject *self, const char *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)
|
|
|
|
|
{
|
2006-02-27 09:35:19 +00:00
|
|
|
|
return [self valueForUndefinedKey: [NSString stringWithUTF8String: key]];
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
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];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
(*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = nil;
|
|
|
|
|
break;
|
|
|
|
|
|
2008-02-20 15:14:48 +00:00
|
|
|
|
case _C_STRUCT_B:
|
|
|
|
|
if (strcmp(@encode(NSPoint), type) == 0)
|
|
|
|
|
{
|
|
|
|
|
NSPoint v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy((char*)&v, ((char *)self + offset), sizeof(v));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSPoint (*imp)(id, SEL) =
|
|
|
|
|
(NSPoint (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSValue valueWithPoint: v];
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(@encode(NSRange), type) == 0)
|
|
|
|
|
{
|
|
|
|
|
NSRange v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy((char*)&v, ((char *)self + offset), sizeof(v));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSRange (*imp)(id, SEL) =
|
|
|
|
|
(NSRange (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSValue valueWithRange: v];
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(@encode(NSRect), type) == 0)
|
|
|
|
|
{
|
|
|
|
|
NSRect v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy((char*)&v, ((char *)self + offset), sizeof(v));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSRect (*imp)(id, SEL) =
|
|
|
|
|
(NSRect (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSValue valueWithRect: v];
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(@encode(NSSize), type) == 0)
|
|
|
|
|
{
|
|
|
|
|
NSSize v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy((char*)&v, ((char *)self + offset), sizeof(v));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSSize (*imp)(id, SEL) =
|
|
|
|
|
(NSSize (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSValue valueWithSize: v];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-08-19 07:04:21 +00:00
|
|
|
|
val = [self valueForUndefinedKey:
|
|
|
|
|
[NSString stringWithUTF8String: key]];
|
2008-02-20 15:14:48 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
default:
|
2009-08-19 07:04:21 +00:00
|
|
|
|
val = [self valueForUndefinedKey:
|
|
|
|
|
[NSString stringWithUTF8String: key]];
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-02-20 15:14:48 +00:00
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
/**
|
|
|
|
|
* Calls GSObjCGetVal()
|
|
|
|
|
*/
|
|
|
|
|
id
|
|
|
|
|
GSObjCGetValue(NSObject *self, NSString *key, SEL sel,
|
|
|
|
|
const char *type, unsigned size, int offset)
|
|
|
|
|
{
|
|
|
|
|
return GSObjCGetVal(self, [key UTF8String], 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
|
2006-02-27 09:35:19 +00:00
|
|
|
|
GSObjCSetVal(NSObject *self, const char *key, id val, SEL sel,
|
|
|
|
|
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)
|
|
|
|
|
{
|
2009-08-19 07:04:21 +00:00
|
|
|
|
[self setValue: val forUndefinedKey:
|
|
|
|
|
[NSString stringWithUTF8String: key]];
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
2003-03-23 07:06:27 +00:00
|
|
|
|
else if ((val == nil || val == null) && *type != _C_ID && *type != _C_CLASS)
|
|
|
|
|
{
|
2006-02-27 09:35:19 +00:00
|
|
|
|
[self setNilValueForKey: [NSString stringWithUTF8String: key]];
|
2003-03-23 07:06:27 +00:00
|
|
|
|
}
|
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;
|
|
|
|
|
|
2008-02-20 15:14:48 +00:00
|
|
|
|
case _C_STRUCT_B:
|
|
|
|
|
if (strcmp(@encode(NSPoint), type) == 0)
|
|
|
|
|
{
|
|
|
|
|
NSPoint v = [val pointValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
NSPoint *ptr = (NSPoint*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, NSPoint) =
|
|
|
|
|
(void (*)(id, SEL, NSPoint))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(@encode(NSRange), type) == 0)
|
|
|
|
|
{
|
|
|
|
|
NSRange v = [val rangeValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
NSRange *ptr = (NSRange*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, NSRange) =
|
|
|
|
|
(void (*)(id, SEL, NSRange))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(@encode(NSRect), type) == 0)
|
|
|
|
|
{
|
|
|
|
|
NSRect v = [val rectValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
NSRect *ptr = (NSRect*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, NSRect) =
|
|
|
|
|
(void (*)(id, SEL, NSRect))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(@encode(NSSize), type) == 0)
|
|
|
|
|
{
|
|
|
|
|
NSSize v = [val sizeValue];
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
NSSize *ptr = (NSSize*)((char *)self + offset);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL, NSSize) =
|
|
|
|
|
(void (*)(id, SEL, NSSize))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-08-19 07:04:21 +00:00
|
|
|
|
[self setValue: val forUndefinedKey:
|
|
|
|
|
[NSString stringWithUTF8String: key]];
|
2008-02-20 15:14:48 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
default:
|
2009-08-19 07:04:21 +00:00
|
|
|
|
[self setValue: val forUndefinedKey:
|
|
|
|
|
[NSString stringWithUTF8String: key]];
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-02-20 15:14:48 +00:00
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
/**
|
|
|
|
|
* Calls GSObjCSetVal()
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
GSObjCSetValue(NSObject *self, NSString *key, id val, SEL sel,
|
|
|
|
|
const char *type, unsigned size, int offset)
|
|
|
|
|
{
|
|
|
|
|
GSObjCSetVal(self, [key UTF8String], val, sel, type, size, offset);
|
|
|
|
|
}
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
2003-03-02 07:47:18 +00:00
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
/** Returns an autoreleased array of subclasses of Class cls, including
|
2004-10-17 23:22:41 +00:00
|
|
|
|
* subclasses of subclasses. */
|
|
|
|
|
NSArray *GSObjCAllSubclassesOfClass(Class cls)
|
|
|
|
|
{
|
|
|
|
|
if (!cls)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-30 07:30:27 +00:00
|
|
|
|
NSMutableArray *result;
|
|
|
|
|
Class *classes;
|
|
|
|
|
int numClasses;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
numClasses = objc_getClassList(NULL, 0);
|
|
|
|
|
classes = NSZoneMalloc(NSDefaultMallocZone(), numClasses*sizeof(Class));
|
2010-04-30 08:29:17 +00:00
|
|
|
|
objc_getClassList(classes, numClasses);
|
2010-04-30 07:30:27 +00:00
|
|
|
|
result = [NSMutableArray array];
|
|
|
|
|
for (i = 0; i < numClasses; i++)
|
2004-10-17 23:22:41 +00:00
|
|
|
|
{
|
2010-04-30 07:30:27 +00:00
|
|
|
|
Class c = classes[i];
|
|
|
|
|
|
|
|
|
|
if (YES == GSObjCIsKindOf(cls, c) && cls != c)
|
|
|
|
|
{
|
|
|
|
|
[result addObject: c];
|
|
|
|
|
}
|
2004-10-17 23:22:41 +00:00
|
|
|
|
}
|
2010-04-30 07:30:27 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), classes);
|
|
|
|
|
return result;
|
2004-10-17 23:22:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Returns an autoreleased array containing subclasses directly descendent of
|
|
|
|
|
* Class cls. */
|
|
|
|
|
NSArray *GSObjCDirectSubclassesOfClass(Class cls)
|
|
|
|
|
{
|
|
|
|
|
if (!cls)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-30 07:30:27 +00:00
|
|
|
|
NSMutableArray *result;
|
|
|
|
|
Class *classes;
|
|
|
|
|
int numClasses;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
numClasses = objc_getClassList(NULL, 0);
|
|
|
|
|
classes = NSZoneMalloc(NSDefaultMallocZone(), numClasses*sizeof(Class));
|
2010-04-30 08:29:17 +00:00
|
|
|
|
objc_getClassList(classes, numClasses);
|
2010-04-30 07:30:27 +00:00
|
|
|
|
result = [NSMutableArray array];
|
|
|
|
|
for (i = 0; i < numClasses; i++)
|
2004-10-17 23:22:41 +00:00
|
|
|
|
{
|
2010-04-30 07:30:27 +00:00
|
|
|
|
Class c = classes[i];
|
|
|
|
|
|
|
|
|
|
if (class_getSuperclass(c) == cls)
|
|
|
|
|
{
|
|
|
|
|
[result addObject: c];
|
|
|
|
|
}
|
2004-10-17 23:22:41 +00:00
|
|
|
|
}
|
2010-04-30 07:30:27 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), classes);
|
|
|
|
|
return result;
|
2004-10-17 23:22:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-03-31 07:41:34 +00:00
|
|
|
|
@interface GSAutoreleasedMemory : NSObject
|
|
|
|
|
@end
|
|
|
|
|
@implementation GSAutoreleasedMemory
|
|
|
|
|
@end
|
|
|
|
|
|
2003-03-02 07:47:18 +00:00
|
|
|
|
void *
|
|
|
|
|
GSAutoreleasedBuffer(unsigned size)
|
|
|
|
|
{
|
|
|
|
|
#if GS_WITH_GC
|
2009-01-19 11:00:33 +00:00
|
|
|
|
return NSAllocateCollectable(size, NSScannedOption);
|
2003-03-02 07:47:18 +00:00
|
|
|
|
#else
|
|
|
|
|
#ifdef ALIGN
|
|
|
|
|
#undef ALIGN
|
|
|
|
|
#endif
|
|
|
|
|
#define ALIGN __alignof__(double)
|
|
|
|
|
|
2006-03-31 07:41:34 +00:00
|
|
|
|
static Class buffer_class = 0;
|
2003-03-02 07:47:18 +00:00
|
|
|
|
static Class autorelease_class;
|
|
|
|
|
static SEL autorelease_sel;
|
|
|
|
|
static IMP autorelease_imp;
|
2010-02-24 10:23:47 +00:00
|
|
|
|
static int instance_size;
|
2003-03-02 07:47:18 +00:00
|
|
|
|
static int offset;
|
|
|
|
|
NSObject *o;
|
|
|
|
|
|
2006-03-31 07:41:34 +00:00
|
|
|
|
if (buffer_class == 0)
|
2003-03-02 07:47:18 +00:00
|
|
|
|
{
|
2006-03-31 07:41:34 +00:00
|
|
|
|
buffer_class = [GSAutoreleasedMemory class];
|
2010-02-24 10:23:47 +00:00
|
|
|
|
instance_size = class_getInstanceSize(buffer_class);
|
|
|
|
|
offset = instance_size % ALIGN;
|
2003-03-02 07:47:18 +00:00
|
|
|
|
autorelease_class = [NSAutoreleasePool class];
|
|
|
|
|
autorelease_sel = @selector(addObject:);
|
|
|
|
|
autorelease_imp = [autorelease_class methodForSelector: autorelease_sel];
|
|
|
|
|
}
|
2006-03-31 07:41:34 +00:00
|
|
|
|
o = (NSObject*)NSAllocateObject(buffer_class,
|
2003-03-02 07:47:18 +00:00
|
|
|
|
size + offset, NSDefaultMallocZone());
|
|
|
|
|
(*autorelease_imp)(autorelease_class, autorelease_sel, o);
|
2010-02-24 10:23:47 +00:00
|
|
|
|
return ((void*)o) + instance_size + offset;
|
2003-03-02 07:47:18 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-27 12:52:29 +00:00
|
|
|
|
|
|
|
|
|
|
2005-11-05 16:20:19 +00:00
|
|
|
|
/*
|
2007-12-19 14:39:44 +00:00
|
|
|
|
* Deprecated function.
|
2005-11-05 16:20:19 +00:00
|
|
|
|
*/
|
2002-11-27 12:52:29 +00:00
|
|
|
|
const char *
|
|
|
|
|
GSLastErrorStr(long error_id)
|
|
|
|
|
{
|
2007-12-19 14:39:44 +00:00
|
|
|
|
return [[[NSError _last] localizedDescription] cString];
|
2002-11-27 12:52:29 +00:00
|
|
|
|
}
|
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;
|
|
|
|
|
}
|