]> err.no Git - sope/blob - sope-core/NGExtensions/NGObjCRuntime.m
Drop apache 1 build-dependency
[sope] / sope-core / NGExtensions / NGObjCRuntime.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "NGObjCRuntime.h"
23 #include "NGMemoryAllocation.h"
24 #include <objc/objc.h>
25 #include <objc/objc-api.h>
26 #include <stdlib.h>
27 #include "common.h"
28
29 #if NeXT_RUNTIME || APPLE_RUNTIME
30 #  include <objc/objc-class.h>
31 #  include <objc/objc-runtime.h>
32 typedef struct objc_method_list *MethodList_t;
33 typedef struct objc_ivar_list   *IvarList_t;
34 typedef struct objc_method      *Method_t;
35 #else
36 #  include <objc/encoding.h>
37 #endif
38
39 #import <Foundation/NSObject.h>
40 #import <Foundation/NSException.h>
41 #import <Foundation/NSString.h>
42 #import <Foundation/NSSet.h>
43 #import <Foundation/NSEnumerator.h>
44
45 #define GCC_VERSION (__GNUC__ * 10000 \
46                      + __GNUC_MINOR__ * 100 \
47                      + __GNUC_PATCHLEVEL__)
48
49 #if GNUSTEP_BASE_LIBRARY
50 /* this is a hack for the extensions 0.8.6 library */
51
52 void class_add_behavior(Class class, Class behavior) {
53   extern void behavior_class_add_class (Class class, Class behavior);
54   behavior_class_add_class(class, behavior);
55 }
56
57 #endif
58
59 @interface _NGMethodNameEnumerator : NSEnumerator
60 {
61   Class        clazz;
62   BOOL         includeSuperclassMethods;
63   NSMutableSet *names;
64
65   struct objc_method_list *methods; // current method list
66   unsigned i; // current index in current method list
67 #if APPLE_RUNTIME || NeXT_RUNTIME
68   void     *iter; // runtime iterator
69 #endif
70 }
71
72 - (id)initWithClass:(Class)_clazz includeSuperclassMethods:(BOOL)_flag;
73 - (id)nextObject;
74
75 @end
76
77 #if NeXT_RUNTIME || APPLE_RUNTIME
78
79 static __inline__ unsigned NGGetSizeOfType(char *ivarType) {
80   // TODO: add more types ...
81   switch (*ivarType) { 
82     /* the Apple runtime has no func to calc a type size ?! */
83   case '@': return sizeof(id);
84   case ':': return sizeof(SEL);
85   case 'c': return sizeof(signed char);
86   case 's': return sizeof(signed short);
87   case 'i': return sizeof(signed int);
88   case 'C': return sizeof(unsigned char);
89   case 'S': return sizeof(unsigned short);
90   case 'I': return sizeof(unsigned int);
91   default:  return 0xDEAFBEAF;
92   }
93 }
94
95 #endif
96
97 @implementation NSObject(NGObjCRuntime)
98
99 static NSArray *emptyArray = nil;
100
101 static unsigned countMethodSpecs(SEL _selector, va_list *va)
102      __attribute__((unused));
103
104 static unsigned countMethodSpecs(SEL _selector, va_list *va) {
105   SEL      selector;
106   NSString *signature;
107   IMP      imp;
108   unsigned count;
109   
110   selector  = _selector;
111   signature = nil;
112   imp       = NULL;
113   if (selector)  signature = va_arg(*va, id);
114   if (signature) imp       = va_arg(*va, IMP);
115   
116   count = 0;
117   while ((selector != NULL) && (signature != nil) && (imp != NULL)) {
118     count++;
119     
120     if ((selector  = va_arg(*va, SEL))            == NULL) break;
121     if ((signature = (id)va_arg(*va, NSString *)) == nil)  break;
122     if ((imp       = (IMP)va_arg(*va, IMP))       == NULL) break;
123   }
124   return count;
125 }
126
127 static void
128 fillMethodListWithSpecs(MethodList_t methods, SEL _selector, va_list *va)
129 {
130   /* takes triple: SEL, signature, IMP */
131   SEL      selector;
132   NSString *signature;
133   IMP      imp;
134   unsigned count;
135   
136   selector  = _selector;
137   signature = selector  ? va_arg(*va, NSString *) : (NSString *)nil;
138   imp       = signature ? va_arg(*va, IMP) : NULL;
139   count     = 0;
140   while ((selector != NULL) && (signature != nil) && (imp != NULL)) {
141     unsigned   len;
142     char       *types;
143 #if GNU_RUNTIME
144     const char *selname;
145 #endif
146     
147     /* allocate signature buffer */
148     len = [signature cStringLength];
149     types = malloc(len + 4);
150     [signature getCString:types];
151     types[len] = 0;
152     
153 #if APPLE_RUNTIME || NeXT_RUNTIME
154     count = methods->method_count;
155     methods->method_list[count].method_name  = selector;
156     methods->method_list[count].method_types = types;
157     methods->method_list[count].method_imp   = imp;
158     methods->method_count++;
159 #else
160     /* determine selector name */
161     selname  = sel_get_name(selector);
162
163     /* fill structure */
164     methods->method_list[count].method_name  = (SEL)selname;
165     methods->method_list[count].method_types = types;
166     methods->method_list[count].method_imp   = imp;
167     count++;
168 #endif
169     
170     /* go to next method spec */
171     if ((selector  = va_arg(*va, SEL))        == NULL) break;
172     if ((signature = va_arg(*va, NSString *)) == nil)  break;
173     if ((imp       = va_arg(*va, IMP))        == NULL) break;
174   }
175 #if GNU_RUNTIME
176   methods->method_count = count;
177   methods->method_next  = NULL;
178 #endif
179 }
180
181 + (unsigned)instanceSize {
182   return ((Class)self)->instance_size;
183 }
184
185 /* adding methods */
186
187 + (void)addMethodList:(MethodList_t)_methods {
188   if (_methods == NULL)            return;
189   if (_methods->method_count == 0) return;
190
191 #if NeXT_RUNTIME
192   class_addMethods(self, _methods);
193 #else
194   {
195     extern void class_add_method_list (Class class, MethodList_t list);
196     class_add_method_list(self, _methods);
197   }
198 #endif
199 }
200
201 + (void)addClassMethodList:(MethodList_t)_methods {
202   if (_methods == NULL)            return;
203   if (_methods->method_count == 0) return;
204 #if NeXT_RUNTIME
205   class_addMethods(((Class)self)->isa, _methods);
206 #else
207   {
208     extern void class_add_method_list (Class class, MethodList_t list);
209     class_add_method_list(((Class)self)->class_pointer, _methods);
210   }
211 #endif
212 }
213
214 + (void)addMethods:(SEL)_selector, ... {
215   /* takes triples (sel, type, imp) finished by nil */
216   MethodList_t methods;
217   va_list      va;
218   unsigned     count;
219   
220   va_start(va, _selector);
221   count = countMethodSpecs(_selector, &va);
222   va_end(va);
223   if (count == 0) return;
224
225 #if NeXT_RUNTIME || APPLE_RUNTIME
226   methods = malloc(sizeof(struct objc_method_list) +
227                    ((count + 1) * sizeof(struct objc_method)));
228   methods->method_count = 0;
229
230   va_start(va, _selector);
231   fillMethodListWithSpecs(methods, _selector, &va);
232   va_end(va);
233   
234   [self addMethodList:methods];
235 #else
236   methods = malloc(sizeof(MethodList) + (count + 2) * sizeof(Method));
237   NSAssert(methods, @"could not allocate methodlist");
238   
239   va_start(va, _selector);
240   fillMethodListWithSpecs(methods, _selector, &va);
241   va_end(va);
242   
243   [self addMethodList:methods];
244 #endif
245 }
246
247 + (void)addClassMethods:(SEL)_selector, ... {
248   /* takes triples finished by nil */
249   MethodList_t methods;
250   va_list      va;
251   unsigned     count;
252   
253   va_start(va, _selector);
254   count = countMethodSpecs(_selector, &va);
255   va_end(va);
256   if (count == 0) return;
257   
258 #if NeXT_RUNTIME
259   methods = malloc(sizeof(struct objc_method_list) +
260                    ((count + 1) * sizeof(struct objc_method)));
261   methods->method_count = 0;
262
263   va_start(va, _selector);
264   fillMethodListWithSpecs(methods, _selector, &va);
265   va_end(va);
266   
267   [self addClassMethodList:methods];
268 #else
269   methods = malloc(sizeof(MethodList) + count * sizeof(Method));
270   NSAssert(methods, @"couldn't allocate methodlist");
271   
272   va_start(va, _selector);
273   fillMethodListWithSpecs(methods, _selector, &va);
274   va_end(va);
275   
276   [self addClassMethodList:methods];
277 #endif
278 }
279
280 + (NSEnumerator *)methodNameEnumerator {
281   return [[[_NGMethodNameEnumerator alloc]
282                                     initWithClass:self
283                                     includeSuperclassMethods:NO]
284                                     autorelease];
285 }
286 + (NSEnumerator *)hierachyMethodNameEnumerator {
287   return [[[_NGMethodNameEnumerator alloc]
288                                     initWithClass:self
289                                     includeSuperclassMethods:YES]
290                                     autorelease];
291 }
292
293 /* subclassing */
294
295 + (Class)subclass:(NSString *)_className
296   ivarsList:(IvarList_t)_ivars
297 {
298 #if NeXT_RUNTIME
299   [(NSObject *)self doesNotRecognizeSelector:_cmd];
300   return Nil;
301 #else
302   // TODO: do we really need a symtab? PyObjC does not seem to require that
303   Module_t module;
304   Class    newMetaClass, newClass;
305   unsigned nameLen;
306   char     *name, *moduleName, *metaName;
307   int      instanceSize, i;
308   
309   /* define names */
310   
311   nameLen = [_className cStringLength];
312   name    = malloc(nameLen + 3);
313   [_className getCString:name];
314   
315   moduleName = name;
316   metaName   = name;
317
318   /* calc instance size */
319
320   // printf("calc isize ..\n");
321
322   for (i = 0, instanceSize = ((Class)self)->instance_size;
323        i < _ivars->ivar_count; i++) {
324     unsigned typeAlign, typeLen;
325     
326     // printf("ivar %s\n", _ivars->ivar_list[i].ivar_name);
327     // printf("  type %s\n", _ivars->ivar_list[i].ivar_type);
328     
329     typeAlign = objc_alignof_type(_ivars->ivar_list[i].ivar_type);
330     typeLen   = objc_sizeof_type(_ivars->ivar_list[i].ivar_type);
331     
332     /* check if offset is aligned */
333     if ((instanceSize % typeAlign) != 0) {
334       /* add alignment size */
335       instanceSize += (typeAlign - (instanceSize % typeAlign));
336     }
337     instanceSize += typeLen;
338   }
339   
340   /* allocate structures */
341   
342   newMetaClass = malloc(sizeof(struct objc_class));
343   newClass     = malloc(sizeof(struct objc_class));
344   NSCAssert(newMetaClass, @"could not allocate new meta class structure");
345   NSCAssert(newClass,     @"could not allocate new class structure");
346   
347   // printf("setup meta ..\n");
348   
349   /* init meta class */
350   newMetaClass->super_class    = (Class)((Class)self)->class_pointer->name;
351   newMetaClass->class_pointer  = newMetaClass->super_class->class_pointer;
352   newMetaClass->name           = metaName;
353   newMetaClass->version        = 0;
354   newMetaClass->info           = _CLS_META;
355   newMetaClass->instance_size  = newMetaClass->super_class->instance_size;
356   newMetaClass->methods        = NULL;
357   newMetaClass->dtable         = NULL;
358   newMetaClass->subclass_list  = NULL;
359   newMetaClass->sibling_class  = NULL;
360   newMetaClass->protocols      = NULL;
361   newMetaClass->gc_object_type = NULL;
362   
363   // printf("setup class ..\n");
364   /* init class */
365   newClass->super_class    = (Class)((Class)self)->name;
366   newClass->class_pointer  = newMetaClass;
367   newClass->name           = name;
368   newClass->version        = 0;
369   newClass->info           = _CLS_CLASS;
370   newClass->instance_size  = instanceSize;
371   newClass->methods        = NULL;
372   newClass->dtable         = NULL;
373   newClass->subclass_list  = NULL;
374   newClass->sibling_class  = NULL;
375   newClass->protocols      = NULL;
376   newClass->gc_object_type = NULL;
377   newClass->ivars          = _ivars;
378   
379   /* allocate module */
380   
381   module = malloc(sizeof(Module));
382   NSCAssert(module, @"could not allocate module !");
383   memset(module, 0, sizeof(Module));
384   module->version = 8;
385   module->size    = sizeof(Module);
386   module->name    = moduleName;
387
388   /* allocate symtab with one entry */
389   module->symtab = malloc(sizeof(Symtab) + (2 * sizeof(void *)));
390   module->symtab->sel_ref_cnt = 0;
391   module->symtab->refs        = 0; // ptr to array of 'struct objc_selector'
392   module->symtab->cls_def_cnt = 1;
393   module->symtab->cat_def_cnt = 0;
394   module->symtab->defs[0] = newClass;
395   module->symtab->defs[1] = NULL;
396
397   /* execute module */
398   {
399 #if GCC_VERSION < 30400
400     extern void __objc_exec_class(Module_t module); // is thread-safe
401     extern void __objc_resolve_class_links();
402 #else
403     void __objc_exec_class(void* module);
404     void __objc_resolve_class_links();
405 #endif
406     
407     /*
408       This is the main entry function in the GNU runtime. It does a LOT of
409       work, including the setup of global hashes if missing. Some things (like
410       the global hashes) are not relevant for us, since the runtime itself is
411       already up.
412       This function uses the internal lock for runtime modifications.
413
414       The method does with the runtime lock applied (2.95.3):
415       - setup globals
416       - registers typed selectors for symtab->refs
417       - walks over all classes
418         - adds the class to the hash
419         - registers the selectors of the class
420         - registers the selectors of the metaclass
421         - install dtable's (just assigns NULL?)
422         - registers instance methods as class methods for root classes
423         - inits protocols
424         - add superclasses to unresolved-classes
425       - walks over all categories
426       - register uninitialized statics
427       - walk over unclaimed categories
428       - walk over unclaimed protocols
429       - send the +load message
430       
431       Actually this function just calls __objc_exec_module(), don't know why
432       we call this one instead.
433     */
434     // printf("execute class\n");
435     __objc_exec_class(module);
436     
437     //printf("resolve links\n");
438     __objc_resolve_class_links();
439   }
440   
441   return NSClassFromString(_className);
442 #endif
443 }
444
445 + (Class)subclass:(NSString *)_className
446   ivarNames:(NSString **)_ivarNames
447   ivarTypes:(NSString **)_ivarTypes
448   ivarCount:(unsigned)ivarCount
449 {
450   unsigned currentSize;
451   
452   currentSize = ((Class)self)->instance_size;
453   
454 #if NeXT_RUNTIME || APPLE_RUNTIME
455   {
456     /* some tricks for Apple inspired by PyObjC, long live OpenSource ;-) */
457     IvarList_t        ivars;
458     struct objc_class *clazz;
459     struct objc_class *metaClazz;
460     struct objc_class *rootClazz;
461     
462     /* build ivars */
463     
464     ivars = NULL;
465     if (ivarCount > 0) {
466       unsigned i;
467       
468       ivars = calloc(sizeof(struct objc_ivar_list) +
469                      (ivarCount) * sizeof(struct objc_ivar), sizeof(char));
470       
471       for (i = 0; i < ivarCount; i++) {
472         NSString *n, *t;
473         Ivar     var;
474         char     *ivarName, *ivarType;
475         int      ivarOffset;
476         unsigned len, typeAlign, typeLen;
477
478         n = _ivarNames[i];
479         t = _ivarTypes[i];
480         
481         len = [n cStringLength];
482         ivarName = malloc(len + 2);
483         [n getCString:ivarName];
484         ivarName[len] = '\0';
485         
486         len = [t cStringLength];
487         ivarType = malloc(len + 2);
488         [t getCString:ivarType];
489         ivarType[len] = '\0';
490         
491         /* calc ivarOffset */
492         typeAlign = 0; // TODO: alignment?!
493         
494         typeLen = NGGetSizeOfType(ivarType);
495         NSAssert1(typeLen != 0xDEAFBEAF, 
496                   @"does not support ivars of type '%s'", ivarType);
497         ivarOffset = currentSize;
498         
499         var  = ivars->ivar_list + ivars->ivar_count;
500         ivars->ivar_count++;
501         
502         var->ivar_name   = ivarName;
503         var->ivar_offset = ivarOffset;
504         var->ivar_type   = ivarType;
505         
506         /* adjust current size */
507         currentSize = ivarOffset + typeLen;
508       }
509     }
510   
511     // TODO: move the following to a subclass method
512     
513     /* determine root class */
514     
515     for (rootClazz = self; rootClazz->super_class != NULL; )
516       rootClazz = rootClazz->super_class;
517
518     /* setup meta class */
519     
520     metaClazz = calloc(1, sizeof(struct objc_class));
521     metaClazz->isa           = rootClazz->isa; // root-meta is the metameta
522     metaClazz->name          = strdup([_className cString]);
523     metaClazz->info          = CLS_META;
524     metaClazz->super_class   = ((struct objc_class *)self)->isa;
525     metaClazz->instance_size = ((struct objc_class *)self)->isa->instance_size;
526     metaClazz->ivars         = NULL;
527     metaClazz->protocols     = NULL;
528     
529     /* setup class */
530     
531     clazz = calloc(1, sizeof(struct objc_class));
532     clazz->isa           = metaClazz; /* hook up meta class */
533     clazz->name          = strdup([_className cString]);
534     clazz->info          = CLS_CLASS;
535     clazz->super_class   = self;
536     clazz->instance_size = currentSize;
537     clazz->ivars         = ivars;
538     clazz->protocols     = NULL;
539
540 #if 0
541     NSLog(@"instance size: %d, ivar-count: %d",
542           currentSize, ivars->ivar_count);
543 #endif
544     
545     /* setup method lists */
546     
547     metaClazz->methodLists = calloc(1, sizeof(struct objc_method_list *));
548     clazz->methodLists     = calloc(1, sizeof(struct objc_method_list *));
549     
550     /* Note: MacOSX specific, Radar #3317376, hint taken from PyObjC */
551     metaClazz->methodLists[0] = (struct objc_method_list *)-1;
552     clazz->methodLists[0]     = (struct objc_method_list *)-1;
553     
554     /* add to runtime (according to PyObjC not reversible?) */
555     objc_addClass(clazz);
556     return NSClassFromString(_className);
557   }
558 #else
559   {
560     unsigned i;
561     IvarList_t ivars;
562   
563     ivars = malloc(sizeof(IvarList) + (sizeof(struct objc_ivar) * ivarCount));
564     ivars->ivar_count = ivarCount;
565     
566     for (i = 0; i < ivarCount; i++) {
567       NSString *n, *t;
568       char     *ivarName, *ivarType;
569       int      ivarOffset;
570       unsigned len, typeAlign, typeLen;
571
572       n = _ivarNames[i];
573       t = _ivarTypes[i];
574     
575       len = [n cStringLength];
576       ivarName = malloc(len + 2);
577       [n getCString:ivarName];
578       ivarName[len] = '\0';
579     
580       len = [t cStringLength];
581       ivarType = malloc(len + 2);
582       [t getCString:ivarType];
583       ivarType[len] = '\0';
584     
585       /* calc ivarOffset */
586       typeAlign  = objc_alignof_type(ivarType);
587       typeLen    = objc_sizeof_type(ivarType);
588       ivarOffset = currentSize;
589     
590       /* check if offset is aligned */
591       if ((ivarOffset % typeAlign) != 0) {
592         /* align offset */
593         len = (typeAlign - (ivarOffset % typeAlign));
594         ivarOffset += len;
595       }
596
597       /* adjust current size */
598       currentSize = ivarOffset + typeLen;
599     
600       ivars->ivar_list[ivarCount].ivar_name   = ivarName;
601       ivars->ivar_list[ivarCount].ivar_type   = ivarType;
602       ivars->ivar_list[ivarCount].ivar_offset = ivarOffset;
603     }
604   
605     return [self subclass:_className ivarsList:ivars];
606   }
607 #endif
608 }
609
610 + (Class)subclass:(NSString *)_className
611   ivars:(NSString *)_name1,...
612 {
613   va_list  va; /* contains: name1, type1, name2, type2, ... */
614   unsigned ivarCount;
615   NSString *n, *t;
616   NSString **ivarNames = NULL;
617   NSString **ivarTypes = NULL;
618   Class    clazz;
619   
620   /* determine number of args */
621   
622   va_start(va, _name1);
623   for (n = _name1, t = va_arg(va, NSString *), ivarCount = 0;
624        (n != nil && t != nil);
625        n = va_arg(va, NSString *), t = va_arg(va, NSString *))
626     ivarCount++;
627   va_end(va);
628   
629   /* collect args */
630   
631   if (ivarCount > 0) {
632     ivarNames = calloc(ivarCount, sizeof(NSString *));
633     ivarTypes = calloc(ivarCount, sizeof(NSString *));
634     va_start(va, _name1);
635     for (n = _name1, t = va_arg(va, NSString *), ivarCount = 0;
636          (n != nil && t != nil);
637          n = va_arg(va, NSString *), t = va_arg(va, NSString *)) {
638       ivarNames[ivarCount] = n;
639       ivarTypes[ivarCount] = t;
640       ivarCount++;
641     }
642     va_end(va);
643   }
644   
645   /* call primary method */
646   
647   clazz = [self subclass:_className 
648                 ivarNames:ivarNames ivarTypes:ivarTypes ivarCount:ivarCount];
649   
650   if (ivarNames != NULL) free(ivarNames);
651   if (ivarTypes != NULL) free(ivarTypes);
652   return clazz;
653 }
654
655 /* instance variables */
656
657 + (NSArray *)instanceVariableNames {
658   NSArray  *result;
659   NSString **names;
660   int i;
661   
662   if (((Class)self)->ivars == NULL || ((Class)self)->ivars->ivar_count == 0) {
663     if (emptyArray == nil) emptyArray = [[NSArray alloc] init];
664     return emptyArray;
665   }
666
667   names = calloc(((Class)self)->ivars->ivar_count + 2, sizeof(NSString *));
668   
669   for (i = 0; i < ((Class)self)->ivars->ivar_count; i++) {
670     register unsigned char *ivarName;
671     
672     ivarName = (void *)(((Class)self)->ivars->ivar_list[i].ivar_name);
673     if (ivarName == NULL) {
674       NSLog(@"WARNING(%s): ivar without name! (idx=%d)", 
675             __PRETTY_FUNCTION__, i);
676       continue;
677     }
678     
679 #if !LIB_FOUNDATION_LIBRARY
680     names[i] = [NSString stringWithCString:(char *)ivarName];
681 #else
682     names[i] = [NSString stringWithCStringNoCopy:(char *)ivarName
683                          freeWhenDone:NO];
684 #endif
685   }
686   
687   result = [NSArray arrayWithObjects:names
688                     count:((Class)self)->ivars->ivar_count];
689   if (names) free(names);
690   return result;
691 }
692 + (NSArray *)allInstanceVariableNames {
693   NSMutableArray *varNames;
694   Class c;
695
696   varNames = [NSMutableArray arrayWithCapacity:32];
697   for (c = self; c != Nil; c = [c superclass])
698     [varNames addObjectsFromArray:[c instanceVariableNames]];
699
700   return [[varNames copy] autorelease];
701 }
702
703 + (BOOL)hasInstanceVariableWithName:(NSString *)_ivarName {
704   Class    c;
705   unsigned len = [_ivarName cStringLength];
706   char     *ivarName;
707   
708   if (len == 0)
709     return NO;
710   
711   ivarName = malloc(len + 1);
712   [_ivarName getCString:ivarName]; ivarName[len] = '\0';
713   
714   for (c = self; c != Nil; c = [c superclass]) {
715     int i;
716     
717     for (i = 0; i < c->ivars->ivar_count; i++) {
718       if (strcmp(ivarName, c->ivars->ivar_list[i].ivar_name) == 0) {
719         free(ivarName);
720         return YES;
721       }
722     }
723   }
724   free(ivarName);
725   return NO;
726 }
727
728 + (NSString *)signatureOfInstanceVariableWithName:(NSString *)_ivarName {
729   Class    c;
730   unsigned len = [_ivarName cStringLength];
731   char     *ivarName;
732   
733   if (len == 0)
734     return nil;
735
736   ivarName = malloc(len + 1);
737   [_ivarName getCString:ivarName]; ivarName[len] = '\0';
738   
739   for (c = self; c != Nil; c = [c superclass]) {
740     int i;
741
742     for (i = 0; i < c->ivars->ivar_count; i++) {
743       if (strcmp(ivarName, c->ivars->ivar_list[i].ivar_name) == 0) {
744         /* found matching ivar name */
745         if (ivarName) free(ivarName);
746 #if !LIB_FOUNDATION_LIBRARY
747         return [NSString stringWithCString:
748                            (char *)(c->ivars->ivar_list[i].ivar_type)];
749 #else
750         return [NSString stringWithCStringNoCopy:
751                            (char *)(c->ivars->ivar_list[i].ivar_type)
752                          freeWhenDone:NO];
753 #endif
754       }
755     }
756   }
757   if (ivarName) free(ivarName);
758   return nil;
759 }
760
761
762 + (unsigned)offsetOfInstanceVariableWithName:(NSString *)_ivarName {
763   Class    c;
764   unsigned len = [_ivarName cStringLength];
765   char     *ivarName;
766   
767   if (len == 0)
768     return NSNotFound;
769
770   ivarName = malloc(len + 3);
771   [_ivarName getCString:ivarName]; ivarName[len] = '\0';
772   
773   for (c = self; c != Nil; c = [c superclass]) {
774     int i;
775
776     for (i = 0; i < c->ivars->ivar_count; i++) {
777       if (strcmp(ivarName, c->ivars->ivar_list[i].ivar_name) == 0) {
778         /* found matching ivar name */
779         free(ivarName);
780         return c->ivars->ivar_list[i].ivar_offset;
781       }
782     }
783   }
784   free(ivarName);
785   return NSNotFound;
786 }
787
788 @end /* NSObject(NGObjCRuntime) */
789
790 @implementation _NGMethodNameEnumerator
791
792 - (id)initWithClass:(Class)_clazz includeSuperclassMethods:(BOOL)_flag {
793   if (_clazz == Nil) {
794     [self release];
795     return nil;
796   }
797
798   self->names = [[NSMutableSet alloc] initWithCapacity:200];
799   self->clazz                    = _clazz;
800   self->includeSuperclassMethods = _flag;
801
802 #if NeXT_RUNTIME
803   self->iter    = 0;
804   self->methods = class_nextMethodList(self->clazz, &(self->iter));
805 #else
806   self->methods = _clazz->methods;
807   self->i       = 0;
808 #endif
809   return self;
810 }
811
812 - (void)dealloc {
813   [self->names release];
814   [super dealloc];
815 }
816
817 - (id)nextObject {
818   if (self->clazz == nil)
819     return nil;
820
821   if (self->methods == NULL) {
822     /* methods of current class are done .. */
823     if (!self->includeSuperclassMethods)
824       return nil;
825
826     /* loop, maybe there are classes without a method-list ? */
827     while (self->methods == NULL) {
828       if ((self->clazz = [self->clazz superclass]) == Nil)
829         /* no more superclasses */
830         return nil;
831       
832 #if NeXT_RUNTIME
833       self->iter = 0;
834       self->methods = class_nextMethodList(self->clazz, &(self->iter));
835 #else
836       self->methods = self->clazz->methods;
837 #endif
838     }
839     self->i = 0;
840   }
841   
842 #if DEBUG
843   NSAssert(self->methods, @"missing method-list !");
844 #endif
845   
846   while (self->i >= (unsigned)self->methods->method_count) {
847 #if NeXT_RUNTIME || APPLE_RUNTIME
848     self->methods = class_nextMethodList(self->clazz, &(self->iter));
849 #else
850     self->methods = self->methods->method_next;
851 #endif
852     if (self->methods == NULL)
853       break;
854     self->i = 0;
855   }
856   
857   if (self->methods == NULL) {
858     /* recurse to next super class */
859     return self->includeSuperclassMethods
860       ? [self nextObject]
861       : nil;
862   }
863
864   /* get name .. */
865   {
866     Method_t m;
867     NSString *name;
868
869     m = &(self->methods->method_list[self->i]);
870     self->i++;
871     
872     NSAssert(m, @"missing method structure !");
873     name = NSStringFromSelector(m->method_name);
874     NSAssert(name, @"couldn't get method name !");
875     
876     if ([self->names containsObject:name]) {
877       /* this name was already delivered from a subclass, take next */
878       return [self nextObject];
879     }
880
881     [self->names addObject:name];
882     
883     return name;
884   }
885 }
886
887 @end /* _NGMethodNameEnumerator */
888
889 #if GNU_RUNTIME
890
891 @interface NGObjCClassEnumerator : NSEnumerator
892 {
893   void *state;
894 }
895 @end
896
897 @implementation NGObjCClassEnumerator
898
899 - (id)nextObject {
900   return objc_next_class(&(self->state));
901 }
902
903 @end /* NGObjCClassEnumerator */
904
905 #endif /* GNU_RUNTIME */