1
/** Implementation of ObjC runtime additions for GNUStep
2
Copyright (C) 1995-2002 Free Software Foundation, Inc.
4
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
6
Written by: Richard Frith-Macdonald <rfm@gnu.org>
8
Written by: Manuel Guesdon <mguesdon@orange-concept.com>
11
This file is part of the GNUstep Base Library.
13
This library is free software; you can redistribute it and/or
14
modify it under the terms of the GNU Library General Public
15
License as published by the Free Software Foundation; either
16
version 2 of the License, or (at your option) any later version.
18
This library is distributed in the hope that it will be useful,
19
but WITHOUT ANY WARRANTY; without even the implied warranty of
20
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21
Library General Public License for more details.
23
You should have received a copy of the GNU Library General Public
24
License along with this library; if not, write to the Free
25
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
27
<title>GSObjCRuntime function and macro reference</title>
28
$Date: 2005/02/22 11:22:44 $ $Revision: 1.53 $
32
#include "GNUstepBase/preface.h"
33
#ifndef NeXT_Foundation_LIBRARY
34
#include <Foundation/NSArray.h>
35
#include <Foundation/NSAutoreleasePool.h>
36
#include <Foundation/NSData.h>
37
#include <Foundation/NSDictionary.h>
38
#include <Foundation/NSEnumerator.h>
39
#include <Foundation/NSException.h>
40
#include <Foundation/NSLock.h>
41
#include <Foundation/NSMethodSignature.h>
42
#include <Foundation/NSObjCRuntime.h>
43
#include <Foundation/NSSet.h>
44
#include <Foundation/NSString.h>
45
#include <Foundation/NSValue.h>
47
#include <Foundation/Foundation.h>
49
#include "GNUstepBase/GSObjCRuntime.h"
50
#include "GNUstepBase/GNUstep.h"
51
#include "GNUstepBase/GSCategories.h"
53
#include <objc/Protocol.h>
59
#ifdef NeXT_Foundation_LIBRARY
60
@interface NSObject (MissingFromMacOSX)
61
+ (IMP) methodForSelector: (SEL)aSelector;
65
#define BDBGPrintf(format, args...) \
66
do { if (behavior_debug) { fprintf(stderr, (format) , ## args); } } while (0)
68
static objc_mutex_t local_lock = NULL;
70
/* This class it intended soley for thread safe / +load safe
71
initialization of the local lock.
72
It's a root class so it won't trigger the initialization
73
of any other class. */
74
@interface _GSObjCRuntimeInitializer /* Root Class */
80
@implementation _GSObjCRuntimeInitializer
83
if (local_lock == NULL)
85
local_lock = objc_mutex_allocate();
95
GSAllocateMutexAt(objc_mutex_t *request)
99
/* This could be called very early in process
100
initialization so many things may not have
101
been setup correctly yet. */
103
"Error: GSAllocateMutexAt() called with NULL pointer.\n");
107
if (local_lock == NULL)
109
/* Initialize in a thread safe way. */
110
[_GSObjCRuntimeInitializer class];
113
objc_mutex_lock(local_lock);
114
if (*request == NULL)
116
*request = objc_mutex_allocate();
118
objc_mutex_unlock(local_lock);
121
/** Deprecated ... use GSObjCFindVariable() */
123
GSFindInstanceVariable(id obj, const char *name,
124
const char **type, unsigned int *size, int *offset)
126
return GSObjCFindVariable(obj, name, type, size, offset);
130
* This function is used to locate information about the instance
131
* variable of obj called name. It returns YES if the variable
132
* was found, NO otherwise. If it returns YES, then the values
133
* pointed to by type, size, and offset will be set (except where
134
* they are null pointers).
137
GSObjCFindVariable(id obj, const char *name,
138
const char **type, unsigned int *size, int *offset)
141
struct objc_ivar_list *ivars;
142
struct objc_ivar *ivar = 0;
144
if (obj == nil) return NO;
145
class = GSObjCClass(obj);
146
while (class != nil && ivar == 0)
148
ivars = class->ivars;
149
class = class->super_class;
154
for (i = 0; i < ivars->ivar_count; i++)
156
if (strcmp(ivars->ivar_list[i].ivar_name, name) == 0)
158
ivar = &ivars->ivar_list[i];
170
*type = ivar->ivar_type;
172
*size = objc_sizeof_type(ivar->ivar_type);
174
*offset = ivar->ivar_offset;
179
* This method returns an array listing the names of all the
180
* instance methods available to obj, whether they
181
* belong to the class of obj or one of its superclasses.<br />
182
* If obj is a class, this returns the class methods.<br />
183
* Returns nil if obj is nil.
186
GSObjCMethodNames(id obj)
191
GSMethodList methods;
198
* Add names to a set so methods declared in superclasses
199
* and then overridden do not appear more than once.
201
set = [[NSMutableSet alloc] initWithCapacity: 32];
203
class = GSObjCClass(obj);
209
while ((methods = class_nextMethodList(class, &iterator)))
213
for (i = 0; i < methods->method_count; i++)
215
GSMethod method = &methods->method_list[i];
217
if (method->method_name != 0)
222
cName = GSNameFromSelector(method->method_name);
223
name = [[NSString alloc] initWithUTF8String: cName];
224
[set addObject: name];
229
class = class->super_class;
232
array = [set allObjects];
238
* This method returns an array listing the names of all the
239
* instance variables present in the instance obj, whether they
240
* belong to the class of obj or one of its superclasses.<br />
241
* Returns nil if obj is nil.
244
GSObjCVariableNames(id obj)
246
NSMutableArray *array;
248
struct objc_ivar_list *ivars;
254
array = [NSMutableArray arrayWithCapacity: 16];
255
class = GSObjCClass(obj);
258
ivars = class->ivars;
263
for (i = 0; i < ivars->ivar_count; i++)
267
name = [[NSString alloc] initWithUTF8String:
268
ivars->ivar_list[i].ivar_name];
269
[array addObject: name];
273
class = class->super_class;
278
/** Deprecated ... use GSObjCGetVariable() */
280
GSGetVariable(id obj, int offset, unsigned int size, void *data)
282
GSObjCGetVariable(obj, offset, size, data);
285
* Gets the value from an instance variable in obj<br />
286
* This function performs no checking ... you should use it only where
287
* you are providing information from a call to GSFindVariable()
288
* and you know that the data area provided is the correct size.
291
GSObjCGetVariable(id obj, int offset, unsigned int size, void *data)
293
memcpy(data, ((void*)obj) + offset, size);
296
/** Deprecated ... use GSObjCSetVariable() */
298
GSSetVariable(id obj, int offset, unsigned int size, const void *data)
300
GSObjCSetVariable(obj, offset, size, data);
303
* Sets the value in an instance variable in obj<br />
304
* This function performs no checking ... you should use it only where
305
* you are providing information from a call to GSObjCFindVariable()
306
* and you know that the data area provided is the correct size.
309
GSObjCSetVariable(id obj, int offset, unsigned int size, const void *data)
311
memcpy(((void*)obj) + offset, data, size);
314
GS_EXPORT unsigned int
315
GSClassList(Class *buffer, unsigned int max, BOOL clearCache)
322
memset(buffer, 0, sizeof(Class) * (max + 1));
325
num = objc_getClassList(buffer, max);
326
num = (num < 0) ? 0 : num;
329
static Class *cache = 0;
330
static unsigned cacheClassCount = 0;
331
static volatile objc_mutex_t cache_lock = NULL;
334
if (cache_lock == NULL)
336
GSAllocateMutexAt((void*)&cache_lock);
339
objc_mutex_lock(cache_lock);
358
while ((cls = objc_next_class(&iterator)))
362
cache = objc_malloc(sizeof(Class) * (cacheClassCount + 1));
363
/* Be extra careful as another thread may be loading classes. */
364
for (i = 0, iterator = 0, cls = objc_next_class(&iterator);
365
i < cacheClassCount && cls != NULL;
366
i++, cls = objc_next_class(&iterator))
375
num = cacheClassCount;
382
cpyCnt = MIN(max, cacheClassCount);
383
cpySize = sizeof(Class) * cpyCnt;
384
memcpy(buffer, cache, cpySize);
385
buffer[cpyCnt] = NULL;
387
num = (max > cacheClassCount) ? 0 : (cacheClassCount - max);
390
objc_mutex_unlock(cache_lock);
398
http://www.macdevcenter.com/pub/a/mac/2002/05/31/runtime_parttwo.html?page=1
399
http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/9objc_runtime_reference/chapter_5_section_1.html
400
http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/9objc_runtime_reference/chapter_5_section_21.html
401
ObjcRuntimeUtilities.m by Nicola Pero
405
* <p>Create a Class structure for use by the ObjectiveC runtime and return
406
* an NSValue object pointing to it. The class will not be added to the
407
* runtime (you must do that later using the GSObjCAddClasses() function).
409
* <p>The iVars dictionary lists the instance variable names and their types.
413
GSObjCMakeClass(NSString *name, NSString *superName, NSDictionary *iVars)
416
Class classSuperClass;
417
const char *classNameCString;
418
const char *superClassNameCString;
421
unsigned int iVarSize;
424
NSCAssert(name, @"no name");
425
NSCAssert(superName, @"no superName");
427
classSuperClass = NSClassFromString(superName);
429
NSCAssert1(classSuperClass, @"No class named %@",superName);
430
NSCAssert1(!NSClassFromString(name), @"A class %@ already exists", name);
432
classNameCString = [name cString];
433
tmp = objc_malloc(strlen(classNameCString) + 1);
434
strcpy(tmp, classNameCString);
435
classNameCString = tmp;
437
superClassNameCString = [superName cString];
438
tmp = objc_malloc(strlen(superClassNameCString) + 1);
439
strcpy(tmp, superClassNameCString);
440
superClassNameCString = tmp;
442
rootClass = classSuperClass;
443
while (rootClass->super_class != 0)
445
rootClass = rootClass->super_class;
449
* Create new class and meta class structure storage
451
* From Nicola: NB: There is a trick here.
452
* The runtime system will look up the name in the following string,
453
* and replace it with a pointer to the actual superclass structure.
454
* This also means the type of pointer will change, that's why we
457
newMetaClass = objc_malloc(sizeof(struct objc_class));
458
memset(newMetaClass, 0, sizeof(struct objc_class));
459
newMetaClass->class_pointer = rootClass->class_pointer; // Points to root
460
newMetaClass->super_class = (Class)superClassNameCString;
461
newMetaClass->name = classNameCString;
462
newMetaClass->version = 0;
463
newMetaClass->info = _CLS_META; // this is a Meta Class
466
newClass = objc_malloc(sizeof(struct objc_class));
467
memset(newClass, 0, sizeof(struct objc_class));
468
newClass->class_pointer = newMetaClass; // Points to the class's meta class.
469
newClass->super_class = (Class)superClassNameCString;
470
newClass->name = classNameCString;
471
newClass->version = 0;
472
newClass->info = _CLS_CLASS; // this is a Class
474
// work on instances variables
475
iVarSize = classSuperClass->instance_size; // super class ivar size
476
if ([iVars count] > 0)
478
unsigned int iVarsStructsSize;
479
struct objc_ivar *ivar = NULL;
480
unsigned int iVarsCount = [iVars count];
481
NSEnumerator *enumerator = [iVars keyEnumerator];
484
// ivars list is 1 objc_ivar_list followed by (iVarsCount-1) ivar_list
485
iVarsStructsSize = sizeof(struct objc_ivar_list)
486
+ (iVarsCount-1)*sizeof(struct objc_ivar);
488
// Allocate for all ivars
489
newClass->ivars = (struct objc_ivar_list*)objc_malloc(iVarsStructsSize);
490
memset(newClass->ivars, 0, iVarsStructsSize);
493
newClass->ivars->ivar_count = iVarsCount;
495
// initialize each ivar
496
ivar = newClass->ivars->ivar_list; // 1st one
497
while ((key = [enumerator nextObject]) != nil)
499
const char *iVarName = [key cString];
500
const char *iVarType = [[iVars objectForKey: key] cString];
502
tmp = objc_malloc(strlen(iVarName) + 1);
503
strcpy(tmp, iVarName);
504
ivar->ivar_name = tmp;
505
tmp = objc_malloc(strlen(iVarType) + 1);
506
strcpy(tmp, iVarType);
507
ivar->ivar_type = tmp;
509
// align the ivar (i.e. put it on the first aligned address
510
iVarSize = objc_aligned_size(ivar->ivar_type);
511
ivar->ivar_offset = iVarSize;
512
iVarSize += objc_sizeof_type(ivar->ivar_type); // add the ivar size
518
* Size in bytes of the class. The sum of the class definition
519
* and all super class definitions.
521
newClass->instance_size = iVarSize;
523
// Meta Class instance size is superclass instance size.
524
newMetaClass->instance_size = classSuperClass->class_pointer->instance_size;
526
return [NSValue valueWithPointer: newClass];
530
* The classes argument is an array of NSValue objects containing pointers
531
* to classes previously created by the GSObjCMakeClass() function.
535
GSObjCAddClasses(NSArray *classes)
537
unsigned int numClasses = [classes count];
539
for (i = 0; i < numClasses; i++)
541
objc_addClass((Class)[[classes objectAtIndex: i] pointerValue]);
546
* NOTE - OBJC_VERSION needs to be defined to be the version of the
547
* Objective-C runtime you are using. You can find this in the file
548
* 'init.c' in the GNU objective-C runtime source.
550
#define OBJC_VERSION 8
553
GSObjCAddClasses(NSArray *classes)
555
void __objc_exec_class (void* module);
556
void __objc_resolve_class_links ();
559
unsigned int numClasses = [classes count];
563
NSCAssert(numClasses > 0, @"No classes (array is NULL)");
565
c = (Class)[[classes objectAtIndex: 0] pointerValue];
567
// Prepare a fake module containing only the new classes
568
module = objc_calloc (1, sizeof (Module));
569
module->version = OBJC_VERSION;
570
module->size = sizeof (Module);
571
module->name = objc_malloc (strlen(c->name) + 15);
572
strcpy ((char*)module->name, "GNUstep-Proxy-");
573
strcat ((char*)module->name, c->name);
574
module->symtab = objc_malloc(sizeof(Symtab) + numClasses * sizeof(void *));
576
symtab = module->symtab;
577
symtab->sel_ref_cnt = 0;
579
symtab->cls_def_cnt = numClasses; // We are defining numClasses classes.
580
symtab->cat_def_cnt = 0; // But no categories
582
for (i = 0; i < numClasses; i++)
584
symtab->defs[i] = (Class)[[classes objectAtIndex: i] pointerValue];
586
symtab->defs[numClasses] = NULL; //null terminated list
588
// Insert our new class into the runtime.
589
__objc_exec_class (module);
590
__objc_resolve_class_links();
595
static int behavior_debug = 0;
598
GSObjCBehaviorDebug(int i)
605
static GSMethod search_for_method_in_class (Class cls, SEL op);
608
GSObjCAddMethods (Class cls, GSMethodList methods)
610
static SEL initialize_sel = 0;
614
initialize_sel = sel_register_name ("initialize");
616
/* Add methods to cls->dtable and cls->methods */
620
GSMethodList new_list;
622
counter = mlist->method_count ? mlist->method_count - 1 : 1;
624
/* This is a little wasteful of memory, since not necessarily
625
all methods will go in here. */
626
new_list = (GSMethodList)
627
objc_malloc (sizeof(struct objc_method_list) +
628
sizeof(struct objc_method[counter+1]));
629
new_list->method_count = 0;
633
GSMethod method = &(mlist->method_list[counter]);
635
BDBGPrintf(" processing method [%s] ... ",
636
GSNameFromSelector(method->method_name));
638
if (!search_for_method_in_class(cls, method->method_name)
639
&& !sel_eq(method->method_name, initialize_sel))
641
/* As long as the method isn't defined in the CLASS,
642
put the BEHAVIOR method in there. Thus, behavior
643
methods override the superclasses' methods. */
644
new_list->method_list[new_list->method_count] = *method;
645
(new_list->method_count)++;
647
BDBGPrintf("added.\n");
651
BDBGPrintf("ignored.\n");
655
if (new_list->method_count)
657
class_add_method_list(cls, new_list);
666
/* Search for the named method's method structure. Return a pointer
667
to the method's method structure if found. NULL otherwise. */
669
search_for_method_in_class (Class cls, SEL op)
672
GSMethodList method_list;
674
if (! sel_is_mapped (op))
677
/* If not found then we'll search the list. */
678
while ((method_list = class_nextMethodList(cls, &iterator)))
682
/* Search the method list. */
683
for (i = 0; i < method_list->method_count; ++i)
685
GSMethod method = &method_list->method_list[i];
687
if (method->method_name)
689
if (sel_eq(method->method_name, op))
698
#else /* GNU runtime */
701
* The following two functions are implemented in the GNU objc runtime
703
extern Method_t search_for_method_in_list(MethodList_t list, SEL op);
704
extern void class_add_method_list(Class, MethodList_t);
706
static Method_t search_for_method_in_class (Class cls, SEL op);
709
GSObjCAddMethods (Class cls, GSMethodList methods)
711
static SEL initialize_sel = 0;
714
if (initialize_sel == 0)
716
initialize_sel = sel_register_name ("initialize");
719
/* Add methods to class->dtable and class->methods */
720
for (mlist = methods; mlist; mlist = mlist->method_next)
723
GSMethodList new_list;
725
counter = mlist->method_count ? mlist->method_count - 1 : 1;
727
/* This is a little wasteful of memory, since not necessarily
728
all methods will go in here. */
729
new_list = (GSMethodList)
730
objc_malloc (sizeof(struct objc_method_list) +
731
sizeof(struct objc_method[counter+1]));
732
new_list->method_count = 0;
733
new_list->method_next = NULL;
737
GSMethod method = &(mlist->method_list[counter]);
738
const char *name = GSNameFromSelector(method->method_name);
740
BDBGPrintf(" processing method [%s] ... ", name);
742
if (!search_for_method_in_list(cls->methods, method->method_name)
743
&& !sel_eq(method->method_name, initialize_sel))
745
/* As long as the method isn't defined in the CLASS,
746
put the BEHAVIOR method in there. Thus, behavior
747
methods override the superclasses' methods. */
748
new_list->method_list[new_list->method_count] = *method;
750
* HACK ... the GNU runtime implementation of
751
* class_add_method_list() expects the method names to be
752
* C-strings rather than selectors ... so we must allow
755
new_list->method_list[new_list->method_count].method_name
757
(new_list->method_count)++;
759
BDBGPrintf("added.\n");
763
BDBGPrintf("ignored.\n");
767
if (new_list->method_count)
769
class_add_method_list(cls, new_list);
779
search_for_method_in_class (Class cls, SEL op)
781
return cls != NULL ? search_for_method_in_list(cls->methods, op) : NULL;
784
#endif /* NeXT runtime */
787
GSGetMethod(Class cls, SEL sel,
788
BOOL searchInstanceMethods,
789
BOOL searchSuperClasses)
791
if (cls == 0 || sel == 0)
796
if (searchSuperClasses == NO)
798
if (searchInstanceMethods == NO)
800
return search_for_method_in_class(cls->class_pointer, sel);
804
return search_for_method_in_class(cls, sel);
809
if (searchInstanceMethods == NO)
812
We do not rely on the mapping supplied in objc_gnu2next.h
813
because we want to be explicit about the fact
814
that the expected parameters are different.
815
Therefor we refrain from simply using class_getClassMethod().
818
return class_getClassMethod(cls, sel);
820
return class_get_class_method(cls->class_pointer, sel);
825
return class_get_instance_method(cls, sel);
831
/* See header for documentation. */
833
GSAllocMethodList (unsigned int count)
838
size = (sizeof (struct objc_method_list) +
839
sizeof (struct objc_method[count]));
840
list = objc_malloc (size);
841
memset(list, 0, size);
846
/* See header for documentation. */
848
GSAppendMethodToList (GSMethodList list,
856
num = (list->method_count)++;
860
Deal with typed selectors: No matter what kind of selector we get
861
convert it into a c-string. Cache that c-string incase the
862
selector isn't found, then search for cooresponding typed selector.
863
If none is found use the cached name to register an new selector
864
with the cooresponding types.
866
sel = (SEL)GSNameFromSelector (sel);
870
const char *sel_save = (const char *)sel;
872
sel = sel_get_typed_uid (sel_save, types);
875
sel = sel_register_typed_name (sel_save, types);
880
list->method_list[num].method_name = sel;
881
list->method_list[num].method_types = strdup(types);
882
list->method_list[num].method_imp = imp;
885
/* See header for documentation. */
887
GSRemoveMethodFromList (GSMethodList list,
896
sel = (SEL)GSNameFromSelector (sel);
899
/* Insure that we always use sel_eq on non GNU Runtimes. */
903
for (i = 0; i < list->method_count; i++)
905
SEL method_name = list->method_list[i].method_name;
907
/* For the GNU runtime we have use strcmp instead of sel_eq
908
for free standing method lists. */
909
if ((isFree == YES && strcmp((char *)method_name, (char *)sel) == 0)
910
|| (isFree == NO && sel_eq(method_name, sel)))
912
/* Found the list. Now fill up the gap. */
913
for ((list->method_count)--; i < list->method_count; i++)
915
list->method_list[i].method_name
916
= list->method_list[i+1].method_name;
917
list->method_list[i].method_types
918
= list->method_list[i+1].method_types;
919
list->method_list[i].method_imp
920
= list->method_list[i+1].method_imp;
923
/* Clear the last entry. */
924
/* NB: We may leak the types if they were previously
925
set by GSAppendMethodFromList. Yet as we can not
926
determine the origin, we shall leak. */
927
list->method_list[i].method_name = 0;
928
list->method_list[i].method_types = 0;
929
list->method_list[i].method_imp = 0;
937
/* See header for documentation. */
939
GSMethodListForSelector(Class cls,
942
BOOL searchInstanceMethods)
944
void *local_iterator = 0;
946
if (cls == 0 || selector == 0)
951
if (searchInstanceMethods == NO)
953
cls = cls->class_pointer;
956
if (sel_is_mapped(selector))
958
void **iterator_pointer;
959
GSMethodList method_list;
961
iterator_pointer = (iterator == 0 ? &local_iterator : iterator);
962
while ((method_list = class_nextMethodList(cls, iterator_pointer)))
964
/* Search the method in the current list. */
965
if (GSMethodFromList(method_list, selector, NO) != 0)
975
/* See header for documentation. */
977
GSMethodFromList(GSMethodList list,
986
sel = (SEL)GSNameFromSelector (sel);
992
for (i = 0; i < list->method_count; ++i)
994
GSMethod method = &list->method_list[i];
995
SEL method_name = method->method_name;
997
/* For the GNU runtime we have use strcmp instead of sel_eq
998
for free standing method lists. */
999
if ((isFree == YES && strcmp((char *)method_name, (char *)sel) == 0)
1000
|| (isFree == NO && sel_eq(method_name, sel)))
1008
/* See header for documentation. */
1010
GSAddMethodList(Class cls,
1012
BOOL toInstanceMethods)
1014
if (cls == 0 || list == 0)
1019
if (toInstanceMethods == NO)
1021
cls = cls->class_pointer;
1024
class_add_method_list(cls, list);
1027
GS_STATIC_INLINE void
1028
gs_revert_selector_names_in_list(GSMethodList list)
1033
for (i = 0; i < list->method_count; i++)
1035
name = GSNameFromSelector(list->method_list[i].method_name);
1038
list->method_list[i].method_name = (SEL)name;
1043
/* See header for documentation. */
1045
GSRemoveMethodList(Class cls,
1047
BOOL fromInstanceMethods)
1049
if (cls == 0 || list == 0)
1054
if (fromInstanceMethods == NO)
1056
cls = cls->class_pointer;
1060
class_removeMethods(cls, list);
1062
if (list == cls->methods)
1064
cls->methods = list->method_next;
1065
list->method_next = 0;
1068
The list has become "free standing".
1069
Replace all selector references with selector names
1070
so the runtime can convert them again
1071
it the list gets reinserted.
1073
gs_revert_selector_names_in_list(list);
1077
GSMethodList current_list;
1078
for (current_list = cls->methods;
1080
current_list = current_list->method_next)
1082
if (current_list->method_next == list)
1084
current_list->method_next = list->method_next;
1085
list->method_next = 0;
1088
The list has become "free standing".
1089
Replace all selector references with selector names
1090
so the runtime can convert them again
1091
it the list gets reinserted.
1093
gs_revert_selector_names_in_list(list);
1097
#endif /* NeXT_RUNTIME */
1101
GS_STATIC_INLINE const char *
1102
gs_skip_type_qualifier_and_layout_info (const char *types)
1104
while (*types == '+'
1106
|| *types == _C_CONST
1108
|| *types == _C_INOUT
1110
|| *types == _C_BYCOPY
1111
|| *types == _C_BYREF
1112
|| *types == _C_ONEWAY
1113
|| *types == _C_GCINVISIBLE
1114
|| isdigit ((unsigned char) *types))
1122
/* See header for documentation. */
1124
GSSelectorTypesMatch(const char *types1, const char *types2)
1126
if (! types1 || ! types2)
1129
while (*types1 && *types2)
1131
types1 = gs_skip_type_qualifier_and_layout_info (types1);
1132
types2 = gs_skip_type_qualifier_and_layout_info (types2);
1134
/* Reached the end of the selector. */
1135
if (! *types1 && ! *types2)
1138
/* Ignore structure name yet compare layout. */
1139
if (*types1 == '{' && *types2 == '{')
1141
while (*types1 != '=')
1144
while (*types2 != '=')
1148
if (*types1 != *types2)
1155
types1 = gs_skip_type_qualifier_and_layout_info (types1);
1156
types2 = gs_skip_type_qualifier_and_layout_info (types2);
1158
return (! *types1 && ! *types2);
1161
/* See header for documentation. */
1163
GSCGetInstanceVariableDefinition(Class cls, const char *name)
1165
struct objc_ivar_list *list;
1172
for (i = 0; (list != 0) && i < list->ivar_count; i++)
1174
if (strcmp (list->ivar_list[i].ivar_name, name) == 0)
1175
return &(list->ivar_list[i]);
1177
cls = GSObjCSuper(cls);
1180
return GSCGetInstanceVariableDefinition(cls, name);
1186
GSObjCGetInstanceVariableDefinition(Class cls, NSString *name)
1188
return GSCGetInstanceVariableDefinition(cls, [name cString]);
1195
GS_STATIC_INLINE unsigned int
1196
gs_string_hash(const char *s)
1198
unsigned int val = 0;
1201
val = (val << 5) + val + *s++;
1206
GS_STATIC_INLINE pcl
1207
gs_find_protocol_named_in_protocol_list(const char *name,
1208
struct objc_protocol_list *pcllist)
1213
while (pcllist != NULL)
1215
for (i=0; i<pcllist->count; i++)
1217
p = (pcl)pcllist->list[i];
1218
if (strcmp(p->protocol_name, name) == 0)
1223
pcllist = pcllist->next;
1228
GS_STATIC_INLINE pcl
1229
gs_find_protocol_named(const char *name)
1234
Class *clsList, *clsListStart;
1237
/* Setting the clearCache flag is a noop for the Apple runtime. */
1238
num = GSClassList(NULL, 0, NO);
1239
clsList = objc_malloc(sizeof(Class) * (num + 1));
1240
GSClassList(clsList, num, NO);
1242
clsListStart = clsList;
1244
while (p == NULL && (cls = *clsList++))
1246
p = gs_find_protocol_named_in_protocol_list(name, cls->protocols);
1249
objc_free(clsListStart);
1252
void *iterator = NULL;
1254
while (p == NULL && (cls = objc_next_class(&iterator)))
1256
p = gs_find_protocol_named_in_protocol_list(name, cls->protocols);
1263
#define GSI_MAP_HAS_VALUE 1
1264
#define GSI_MAP_RETAIN_KEY(M, X)
1265
#define GSI_MAP_RETAIN_VAL(M, X)
1266
#define GSI_MAP_RELEASE_KEY(M, X)
1267
#define GSI_MAP_RELEASE_VAL(M, X)
1268
#define GSI_MAP_HASH(M, X) (gs_string_hash(X.ptr))
1269
#define GSI_MAP_EQUAL(M, X,Y) (strcmp(X.ptr, Y.ptr) == 0)
1270
#define GSI_MAP_NOCLEAN 1
1272
#define GSI_MAP_KTYPES GSUNION_PTR
1273
#define GSI_MAP_VTYPES GSUNION_PTR
1275
#include "GNUstepBase/GSIMap.h"
1277
static GSIMapTable_t protocol_by_name;
1278
static BOOL protocol_by_name_init = NO;
1279
static volatile objc_mutex_t protocol_by_name_lock = NULL;
1281
/* Not sure about the semantics of inlining
1282
functions with static variables. */
1284
gs_init_protocol_lock(void)
1286
if (protocol_by_name_lock == NULL)
1288
GSAllocateMutexAt((void *)&protocol_by_name_lock);
1289
objc_mutex_lock(protocol_by_name_lock);
1290
if (protocol_by_name_init == NO)
1292
GSIMapInitWithZoneAndCapacity (&protocol_by_name,
1293
NSDefaultMallocZone(),
1295
protocol_by_name_init = YES;
1297
objc_mutex_unlock(protocol_by_name_lock);
1302
GSRegisterProtocol(Protocol *proto)
1304
if (protocol_by_name_init == NO)
1306
gs_init_protocol_lock();
1315
objc_mutex_lock(protocol_by_name_lock);
1316
node = GSIMapNodeForKey(&protocol_by_name,
1317
(GSIMapKey) p->protocol_name);
1320
GSIMapAddPairNoRetain(&protocol_by_name,
1321
(GSIMapKey) (void *) p->protocol_name,
1322
(GSIMapVal) (void *) p);
1324
objc_mutex_unlock(protocol_by_name_lock);
1329
GSProtocolFromName(const char *name)
1334
if (protocol_by_name_init == NO)
1336
gs_init_protocol_lock();
1339
node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
1342
p = node->value.ptr;
1346
objc_mutex_lock(protocol_by_name_lock);
1347
node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
1351
p = node->value.ptr;
1355
p = gs_find_protocol_named(name);
1358
/* Use the protocol's name to save us from allocating
1359
a copy of the parameter 'name'. */
1360
GSIMapAddPairNoRetain(&protocol_by_name,
1361
(GSIMapKey) (void *) p->protocol_name,
1362
(GSIMapVal) (void *) p);
1365
objc_mutex_unlock(protocol_by_name_lock);
1369
return (Protocol *)p;
1374
* <p>A Behavior can be seen as a "Protocol with an implementation" or a
1375
* "Class without any instance variables". A key feature of behaviors
1376
* is that they give a degree of multiple inheritance.
1378
* <p>Behavior methods, when added to a class, override the class's
1379
* superclass methods, but not the class's methods.
1381
* <p>It's not the case that a class adding behaviors from another class
1382
* must have "no instance vars". The receiver class just has to have the
1383
* same layout as the behavior class (optionally with some additional
1384
* ivars after those of the behavior class).
1386
* <p>This function provides Behaviors without adding any new syntax to
1387
* the Objective C language. Simply define a class with the methods you
1388
* want to add, then call this function with that class as the behavior
1391
* <p>This function should be called in the +initialize method of the receiver.
1393
* <p>If you add several behaviors to a class, be aware that the order of
1394
* the additions is significant.
1398
GSObjCAddClassBehavior(Class receiver, Class behavior)
1400
Class behavior_super_class = GSObjCSuper(behavior);
1402
NSCAssert(CLS_ISCLASS(receiver), NSInvalidArgumentException);
1403
NSCAssert(CLS_ISCLASS(behavior), NSInvalidArgumentException);
1405
/* If necessary, increase instance_size of CLASS. */
1406
if (receiver->instance_size < behavior->instance_size)
1409
NSCAssert2(receiver->instance_size >= behavior->instance_size,
1410
@"Trying to add behavior (%s) with instance size larger than class (%s)",
1411
class_get_class_name(behavior), class_get_class_name(receiver));
1413
NSCAssert(!receiver->subclass_list,
1414
@"The behavior-addition code wants to increase the\n"
1415
@"instance size of a class, but it cannot because you\n"
1416
@"have subclassed the class. There are two solutions:\n"
1417
@"(1) Don't subclass it; (2) Add placeholder instance\n"
1418
@"variables to the class, so the behavior-addition code\n"
1419
@"will not have to increase the instance size\n");
1421
receiver->instance_size = behavior->instance_size;
1424
BDBGPrintf("Adding behavior to class %s\n", receiver->name);
1425
BDBGPrintf(" instance methods from %s\n", behavior->name);
1427
/* Add instance methods */
1431
GSMethodList method_list;
1433
method_list = class_nextMethodList(behavior, &iterator);
1434
while (method_list != 0)
1436
GSObjCAddMethods (receiver, method_list);
1437
method_list = class_nextMethodList(behavior, &iterator);
1441
GSObjCAddMethods (receiver, behavior->methods);
1444
/* Add class methods */
1445
BDBGPrintf("Adding class methods from %s\n",
1446
behavior->class_pointer->name);
1450
GSMethodList method_list;
1452
method_list = class_nextMethodList(behavior->class_pointer, &iterator);
1453
while (method_list != 0)
1455
GSObjCAddMethods (receiver->class_pointer, method_list);
1456
method_list = class_nextMethodList(behavior->class_pointer, &iterator);
1460
GSObjCAddMethods (receiver->class_pointer, behavior->class_pointer->methods);
1463
/* Add behavior's superclass, if not already there. */
1464
if (!GSObjCIsKindOf(receiver, behavior_super_class))
1466
GSObjCAddClassBehavior (receiver, behavior_super_class);
1468
GSFlushMethodCacheForClass (receiver);
1474
#ifndef NeXT_Foundation_LIBRARY
1475
#include <Foundation/NSValue.h>
1476
#include <Foundation/NSKeyValueCoding.h>
1480
/** Deprecated ... use GSObjCGetValue() */
1482
GSGetValue(NSObject *self, NSString *key, SEL sel,
1483
const char *type, unsigned size, int offset)
1485
return GSObjCGetValue(self, key, sel, type, size, offset);
1488
* This is used internally by the key-value coding methods, to get a
1489
* value from an object either via an accessor method (if sel is
1490
* supplied), or via direct access (if type, size, and offset are
1492
* Automatic conversion between NSNumber and C scalar types is performed.<br />
1493
* If type is null and can't be determined from the selector, the
1494
* [NSObject-handleQueryWithUnboundKey:] method is called to try
1498
GSObjCGetValue(NSObject *self, NSString *key, SEL sel,
1499
const char *type, unsigned size, int offset)
1503
NSMethodSignature *sig = [self methodSignatureForSelector: sel];
1505
if ([sig numberOfArguments] != 2)
1507
[NSException raise: NSInvalidArgumentException
1508
format: @"key-value get method has wrong number of args"];
1510
type = [sig methodReturnType];
1514
return [self handleQueryWithUnboundKey: key];
1529
v = *(id *)((char *)self + offset);
1533
id (*imp)(id, SEL) =
1534
(id (*)(id, SEL))[self methodForSelector: sel];
1536
v = (*imp)(self, sel);
1548
v = *(char *)((char *)self + offset);
1552
signed char (*imp)(id, SEL) =
1553
(signed char (*)(id, SEL))[self methodForSelector: sel];
1555
v = (*imp)(self, sel);
1557
val = [NSNumber numberWithChar: v];
1567
v = *(unsigned char *)((char *)self + offset);
1571
unsigned char (*imp)(id, SEL) =
1572
(unsigned char (*)(id, SEL))[self methodForSelector:
1575
v = (*imp)(self, sel);
1577
val = [NSNumber numberWithUnsignedChar: v];
1587
v = *(short *)((char *)self + offset);
1591
short (*imp)(id, SEL) =
1592
(short (*)(id, SEL))[self methodForSelector: sel];
1594
v = (*imp)(self, sel);
1596
val = [NSNumber numberWithShort: v];
1606
v = *(unsigned short *)((char *)self + offset);
1610
unsigned short (*imp)(id, SEL) =
1611
(unsigned short (*)(id, SEL))[self methodForSelector:
1614
v = (*imp)(self, sel);
1616
val = [NSNumber numberWithUnsignedShort: v];
1626
v = *(int *)((char *)self + offset);
1630
int (*imp)(id, SEL) =
1631
(int (*)(id, SEL))[self methodForSelector: sel];
1633
v = (*imp)(self, sel);
1635
val = [NSNumber numberWithInt: v];
1645
v = *(unsigned int *)((char *)self + offset);
1649
unsigned int (*imp)(id, SEL) =
1650
(unsigned int (*)(id, SEL))[self methodForSelector:
1653
v = (*imp)(self, sel);
1655
val = [NSNumber numberWithUnsignedInt: v];
1665
v = *(long *)((char *)self + offset);
1669
long (*imp)(id, SEL) =
1670
(long (*)(id, SEL))[self methodForSelector: sel];
1672
v = (*imp)(self, sel);
1674
val = [NSNumber numberWithLong: v];
1684
v = *(unsigned long *)((char *)self + offset);
1688
unsigned long (*imp)(id, SEL) =
1689
(unsigned long (*)(id, SEL))[self methodForSelector:
1692
v = (*imp)(self, sel);
1694
val = [NSNumber numberWithUnsignedLong: v];
1705
v = *(long long *)((char *)self + offset);
1709
long long (*imp)(id, SEL) =
1710
(long long (*)(id, SEL))[self methodForSelector: sel];
1712
v = (*imp)(self, sel);
1714
val = [NSNumber numberWithLongLong: v];
1722
unsigned long long v;
1726
v = *(unsigned long long *)((char *)self + offset);
1730
unsigned long long (*imp)(id, SEL) =
1731
(unsigned long long (*)(id, SEL))[self
1732
methodForSelector: sel];
1734
v = (*imp)(self, sel);
1736
val = [NSNumber numberWithUnsignedLongLong: v];
1747
v = *(float *)((char *)self + offset);
1751
float (*imp)(id, SEL) =
1752
(float (*)(id, SEL))[self methodForSelector: sel];
1754
v = (*imp)(self, sel);
1756
val = [NSNumber numberWithFloat: v];
1766
v = *(double *)((char *)self + offset);
1770
double (*imp)(id, SEL) =
1771
(double (*)(id, SEL))[self methodForSelector: sel];
1773
v = (*imp)(self, sel);
1775
val = [NSNumber numberWithDouble: v];
1781
void (*imp)(id, SEL) =
1782
(void (*)(id, SEL))[self methodForSelector: sel];
1790
[NSException raise: NSInvalidArgumentException
1791
format: @"key-value get method has unsupported type"];
1797
/** Deprecated ... use GSObjCSetValue() */
1799
GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
1800
const char *type, unsigned size, int offset)
1802
GSObjCSetValue(self, key, val, sel, type, size, offset);
1805
* This is used internally by the key-value coding methods, to set a
1806
* value in an object either via an accessor method (if sel is
1807
* supplied), or via direct access (if type, size, and offset are
1809
* Automatic conversion between NSNumber and C scalar types is performed.<br />
1810
* If type is null and can't be determined from the selector, the
1811
* [NSObject-handleTakeValue:forUnboundKey:] method is called to try
1815
GSObjCSetValue(NSObject *self, NSString *key, id val, SEL sel,
1816
const char *type, unsigned size, int offset)
1818
static NSNull *null = nil;
1822
null = [NSNull new];
1826
NSMethodSignature *sig = [self methodSignatureForSelector: sel];
1828
if ([sig numberOfArguments] != 3)
1830
[NSException raise: NSInvalidArgumentException
1831
format: @"key-value set method has wrong number of args"];
1833
type = [sig getArgumentTypeAtIndex: 2];
1837
[self handleTakeValue: val forUnboundKey: key];
1839
else if ((val == nil || val == null) && *type != _C_ID && *type != _C_CLASS)
1841
[self unableToSetNilForKey: key];
1854
id *ptr = (id *)((char *)self + offset);
1860
void (*imp)(id, SEL, id) =
1861
(void (*)(id, SEL, id))[self methodForSelector: sel];
1863
(*imp)(self, sel, val);
1870
char v = [val charValue];
1874
char *ptr = (char *)((char *)self + offset);
1880
void (*imp)(id, SEL, char) =
1881
(void (*)(id, SEL, char))[self methodForSelector: sel];
1883
(*imp)(self, sel, v);
1890
unsigned char v = [val unsignedCharValue];
1894
unsigned char *ptr = (unsigned char*)((char *)self + offset);
1900
void (*imp)(id, SEL, unsigned char) =
1901
(void (*)(id, SEL, unsigned char))[self methodForSelector:
1904
(*imp)(self, sel, v);
1911
short v = [val shortValue];
1915
short *ptr = (short*)((char *)self + offset);
1921
void (*imp)(id, SEL, short) =
1922
(void (*)(id, SEL, short))[self methodForSelector: sel];
1924
(*imp)(self, sel, v);
1931
unsigned short v = [val unsignedShortValue];
1935
unsigned short *ptr;
1937
ptr = (unsigned short*)((char *)self + offset);
1942
void (*imp)(id, SEL, unsigned short) =
1943
(void (*)(id, SEL, unsigned short))[self methodForSelector:
1946
(*imp)(self, sel, v);
1953
int v = [val intValue];
1957
int *ptr = (int*)((char *)self + offset);
1963
void (*imp)(id, SEL, int) =
1964
(void (*)(id, SEL, int))[self methodForSelector: sel];
1966
(*imp)(self, sel, v);
1973
unsigned int v = [val unsignedIntValue];
1977
unsigned int *ptr = (unsigned int*)((char *)self + offset);
1983
void (*imp)(id, SEL, unsigned int) =
1984
(void (*)(id, SEL, unsigned int))[self methodForSelector:
1987
(*imp)(self, sel, v);
1994
long v = [val longValue];
1998
long *ptr = (long*)((char *)self + offset);
2004
void (*imp)(id, SEL, long) =
2005
(void (*)(id, SEL, long))[self methodForSelector: sel];
2007
(*imp)(self, sel, v);
2014
unsigned long v = [val unsignedLongValue];
2018
unsigned long *ptr = (unsigned long*)((char *)self + offset);
2024
void (*imp)(id, SEL, unsigned long) =
2025
(void (*)(id, SEL, unsigned long))[self methodForSelector:
2028
(*imp)(self, sel, v);
2036
long long v = [val longLongValue];
2040
long long *ptr = (long long*)((char *)self + offset);
2046
void (*imp)(id, SEL, long long) =
2047
(void (*)(id, SEL, long long))[self methodForSelector: sel];
2049
(*imp)(self, sel, v);
2058
unsigned long long v = [val unsignedLongLongValue];
2062
unsigned long long *ptr = (unsigned long long*)((char*)self +
2069
void (*imp)(id, SEL, unsigned long long) =
2070
(void (*)(id, SEL, unsigned long long))[self
2071
methodForSelector: sel];
2073
(*imp)(self, sel, v);
2081
float v = [val floatValue];
2085
float *ptr = (float*)((char *)self + offset);
2091
void (*imp)(id, SEL, float) =
2092
(void (*)(id, SEL, float))[self methodForSelector: sel];
2094
(*imp)(self, sel, v);
2101
double v = [val doubleValue];
2105
double *ptr = (double*)((char *)self + offset);
2111
void (*imp)(id, SEL, double) =
2112
(void (*)(id, SEL, double))[self methodForSelector: sel];
2114
(*imp)(self, sel, v);
2120
[NSException raise: NSInvalidArgumentException
2121
format: @"key-value set method has unsupported type"];
2127
/** Returns an autoreleased array of subclasses of Class cls, including
2128
* subclasses of subclasses. */
2129
NSArray *GSObjCAllSubclassesOfClass(Class cls)
2138
NSMutableArray *result = [[NSMutableArray alloc] init];
2141
for (aClass = cls->subclass_list; aClass; aClass=aClass->sibling_class)
2143
if (CLS_ISMETA(aClass))
2145
[result addObject:aClass];
2146
[result addObjectsFromArray: GSObjCAllSubclassesOfClass(aClass)];
2149
#warning not implemented for the NeXT_RUNTIME
2151
return AUTORELEASE(result);
2155
/** Returns an autoreleased array containing subclasses directly descendent of
2157
NSArray *GSObjCDirectSubclassesOfClass(Class cls)
2165
NSMutableArray *result=[[NSMutableArray alloc] init];
2169
for (aClass = cls->subclass_list;aClass;aClass=aClass->sibling_class)
2171
if (CLS_ISMETA(aClass))
2173
[result addObject:aClass];
2176
#warning not implemented for the NeXT_RUNTIME
2178
return AUTORELEASE(result);
2183
GSAutoreleasedBuffer(unsigned size)
2186
return GC_malloc(size);
2191
#define ALIGN __alignof__(double)
2193
static Class nsobject_class = 0;
2194
static Class autorelease_class;
2195
static SEL autorelease_sel;
2196
static IMP autorelease_imp;
2200
if (nsobject_class == 0)
2202
nsobject_class = [NSObject class];
2203
offset = nsobject_class->instance_size % ALIGN;
2204
autorelease_class = [NSAutoreleasePool class];
2205
autorelease_sel = @selector(addObject:);
2206
autorelease_imp = [autorelease_class methodForSelector: autorelease_sel];
2208
o = (NSObject*)NSAllocateObject(nsobject_class,
2209
size + offset, NSDefaultMallocZone());
2210
(*autorelease_imp)(autorelease_class, autorelease_sel, o);
2211
return ((void*)&o[1]) + offset;
2217
/* Getting a system error message on a variety of systems */
2219
LPTSTR GetErrorMsg(DWORD msgId)
2224
FORMAT_MESSAGE_ALLOCATE_BUFFER |
2225
FORMAT_MESSAGE_FROM_SYSTEM |
2226
FORMAT_MESSAGE_IGNORE_INSERTS,
2228
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
2229
(LPTSTR)&lpMsgBuf, 0, NULL);
2231
return (LPTSTR)lpMsgBuf;
2234
#ifndef HAVE_STRERROR
2238
extern char *sys_errlist[];
2239
extern int sys_nerr;
2241
if (eno < 0 || eno >= sys_nerr)
2243
return("unknown error number");
2245
return(sys_errlist[eno]);
2248
#endif /* __MINGW__ */
2251
GSLastErrorStr(long error_id)
2254
return GetErrorMsg(GetLastError());
2256
return strerror(error_id);
2263
GSPrintf (FILE *fptr, NSString* format, ...)
2265
static Class stringClass = 0;
2266
static NSStringEncoding enc;
2267
CREATE_AUTORELEASE_POOL(arp);
2273
if (stringClass == 0)
2275
stringClass = [NSString class];
2276
enc = [stringClass defaultCStringEncoding];
2278
message = [stringClass allocWithZone: NSDefaultMallocZone()];
2279
va_start (ap, format);
2280
message = [message initWithFormat: format locale: nil arguments: ap];
2282
data = [message dataUsingEncoding: enc];
2285
data = [message dataUsingEncoding: NSUTF8StringEncoding];
2291
unsigned int length = [data length];
2293
if (length == 0 || fwrite([data bytes], 1, length, fptr) == length)