]> err.no Git - sope/blob - sope-core/NGExtensions/NGObjCRuntime.m
julianNumber <-> date conversion
[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 @implementation NSObject(NGObjCRuntime)
78
79 static NSArray *emptyArray = nil;
80
81 static unsigned countMethodSpecs(SEL _selector, va_list *va)
82      __attribute__((unused));
83
84 static unsigned countMethodSpecs(SEL _selector, va_list *va) {
85   SEL      selector;
86   NSString *signature;
87   IMP      imp;
88   unsigned count;
89   
90   selector  = _selector;
91   signature = nil;
92   imp       = NULL;
93   if (selector)  signature = va_arg(*va, id);
94   if (signature) imp       = va_arg(*va, IMP);
95   
96   count = 0;
97   while ((selector != NULL) && (signature != nil) && (imp != NULL)) {
98     count++;
99     
100     if ((selector  = va_arg(*va, SEL))            == NULL) break;
101     if ((signature = (id)va_arg(*va, NSString *)) == nil)  break;
102     if ((imp       = (IMP)va_arg(*va, IMP))       == NULL) break;
103   }
104   return count;
105 }
106
107 static void
108 fillMethodListWithSpecs(MethodList_t methods, SEL _selector, va_list *va)
109 {
110   /* takes triple: SEL, signature, IMP */
111   SEL      selector;
112   NSString *signature;
113   IMP      imp;
114   unsigned count;
115   
116   selector  = _selector;
117   signature = selector  ? va_arg(*va, NSString *) : nil;
118   imp       = signature ? va_arg(*va, IMP) : NULL;
119   count     = 0;
120   while ((selector != NULL) && (signature != nil) && (imp != NULL)) {
121     unsigned   len;
122     char       *types;
123 #if GNU_RUNTIME
124     const char *selname;
125 #endif
126     
127     /* allocate signature buffer */
128     len = [signature cStringLength];
129     types = malloc(len + 4);
130     [signature getCString:types];
131     types[len] = 0;
132     
133 #if APPLE_RUNTIME || NeXT_RUNTIME
134     count = methods->method_count;
135     methods->method_list[count].method_name  = selector;
136     methods->method_list[count].method_types = types;
137     methods->method_list[count].method_imp   = imp;
138     methods->method_count++;
139 #else
140     /* determine selector name */
141     selname  = sel_get_name(selector);
142
143     /* fill structure */
144     methods->method_list[count].method_name  = (SEL)selname;
145     methods->method_list[count].method_types = types;
146     methods->method_list[count].method_imp   = imp;
147     count++;
148 #endif
149     
150     /* go to next method spec */
151     if ((selector  = va_arg(*va, SEL))        == NULL) break;
152     if ((signature = va_arg(*va, NSString *)) == nil)  break;
153     if ((imp       = va_arg(*va, IMP))        == NULL) break;
154   }
155 #if GNU_RUNTIME
156   methods->method_count = count;
157   methods->method_next  = NULL;
158 #endif
159 }
160
161 + (unsigned)instanceSize {
162   return ((Class)self)->instance_size;
163 }
164
165 /* adding methods */
166
167 + (void)addMethodList:(MethodList_t)_methods {
168   if (_methods == NULL)            return;
169   if (_methods->method_count == 0) return;
170
171 #if NeXT_RUNTIME
172   class_addMethods(self, _methods);
173 #else
174   {
175     extern void class_add_method_list (Class class, MethodList_t list);
176     class_add_method_list(self, _methods);
177   }
178 #endif
179 }
180
181 + (void)addClassMethodList:(MethodList_t)_methods {
182   if (_methods == NULL)            return;
183   if (_methods->method_count == 0) return;
184 #if NeXT_RUNTIME
185   class_addMethods(((Class)self)->isa, _methods);
186 #else
187   {
188     extern void class_add_method_list (Class class, MethodList_t list);
189     class_add_method_list(((Class)self)->class_pointer, _methods);
190   }
191 #endif
192 }
193
194 + (void)addMethods:(SEL)_selector, ... {
195   /* takes triples (sel, type, imp) finished by nil */
196   MethodList_t methods;
197   va_list      va;
198   unsigned     count;
199   
200   va_start(va, _selector);
201   count = countMethodSpecs(_selector, &va);
202   va_end(va);
203   if (count == 0) return;
204
205 #if NeXT_RUNTIME || APPLE_RUNTIME
206   methods = malloc(sizeof(struct objc_method_list) +
207                    ((count + 1) * sizeof(struct objc_method)));
208   methods->method_count = 0;
209
210   va_start(va, _selector);
211   fillMethodListWithSpecs(methods, _selector, &va);
212   va_end(va);
213   
214   [self addMethodList:methods];
215 #else
216   methods = malloc(sizeof(MethodList) + (count + 2) * sizeof(Method));
217   NSAssert(methods, @"could not allocate methodlist");
218   
219   va_start(va, _selector);
220   fillMethodListWithSpecs(methods, _selector, &va);
221   va_end(va);
222   
223   [self addMethodList:methods];
224 #endif
225 }
226
227 + (void)addClassMethods:(SEL)_selector, ... {
228   /* takes triples finished by nil */
229   MethodList_t methods;
230   va_list      va;
231   unsigned     count;
232   
233   va_start(va, _selector);
234   count = countMethodSpecs(_selector, &va);
235   va_end(va);
236   if (count == 0) return;
237   
238 #if NeXT_RUNTIME
239   methods = malloc(sizeof(struct objc_method_list) +
240                    ((count + 1) * sizeof(struct objc_method)));
241   methods->method_count = 0;
242
243   va_start(va, _selector);
244   fillMethodListWithSpecs(methods, _selector, &va);
245   va_end(va);
246   
247   [self addClassMethodList:methods];
248 #else
249   methods = malloc(sizeof(MethodList) + count * sizeof(Method));
250   NSAssert(methods, @"couldn't allocate methodlist");
251   
252   va_start(va, _selector);
253   fillMethodListWithSpecs(methods, _selector, &va);
254   va_end(va);
255   
256   [self addClassMethodList:methods];
257 #endif
258 }
259
260 + (NSEnumerator *)methodNameEnumerator {
261   return [[[_NGMethodNameEnumerator alloc]
262                                     initWithClass:self
263                                     includeSuperclassMethods:NO]
264                                     autorelease];
265 }
266 + (NSEnumerator *)hierachyMethodNameEnumerator {
267   return [[[_NGMethodNameEnumerator alloc]
268                                     initWithClass:self
269                                     includeSuperclassMethods:YES]
270                                     autorelease];
271 }
272
273 /* subclassing */
274
275 + (Class)subclass:(NSString *)_className
276   ivarsList:(IvarList_t)_ivars
277 {
278 #if NeXT_RUNTIME
279   [(NSObject *)self doesNotRecognizeSelector:_cmd];
280   return Nil;
281 #else
282   // TODO: do we really need a symtab? PyObjC does not seem to require that
283   Module_t module;
284   Class    newMetaClass, newClass;
285   unsigned nameLen;
286   char     *name, *moduleName, *metaName;
287   int      instanceSize, i;
288   
289   /* define names */
290   
291   nameLen = [_className cStringLength];
292   name    = malloc(nameLen + 3);
293   [_className getCString:name];
294   
295   moduleName = name;
296   metaName   = name;
297
298   /* calc instance size */
299
300   // printf("calc isize ..\n");
301
302   for (i = 0, instanceSize = ((Class)self)->instance_size;
303        i < _ivars->ivar_count; i++) {
304     unsigned typeAlign, typeLen;
305     
306     // printf("ivar %s\n", _ivars->ivar_list[i].ivar_name);
307     // printf("  type %s\n", _ivars->ivar_list[i].ivar_type);
308     
309     typeAlign = objc_alignof_type(_ivars->ivar_list[i].ivar_type);
310     typeLen   = objc_sizeof_type(_ivars->ivar_list[i].ivar_type);
311     
312     /* check if offset is aligned */
313     if ((instanceSize % typeAlign) != 0) {
314       /* add alignment size */
315       instanceSize += (typeAlign - (instanceSize % typeAlign));
316     }
317     instanceSize += typeLen;
318   }
319   
320   /* allocate structures */
321   
322   newMetaClass = malloc(sizeof(struct objc_class));
323   newClass     = malloc(sizeof(struct objc_class));
324   NSCAssert(newMetaClass, @"could not allocate new meta class structure");
325   NSCAssert(newClass,     @"could not allocate new class structure");
326   
327   // printf("setup meta ..\n");
328   
329   /* init meta class */
330   newMetaClass->super_class    = (Class)((Class)self)->class_pointer->name;
331   newMetaClass->class_pointer  = newMetaClass->super_class->class_pointer;
332   newMetaClass->name           = metaName;
333   newMetaClass->version        = 0;
334   newMetaClass->info           = _CLS_META;
335   newMetaClass->instance_size  = newMetaClass->super_class->instance_size;
336   newMetaClass->methods        = NULL;
337   newMetaClass->dtable         = NULL;
338   newMetaClass->subclass_list  = NULL;
339   newMetaClass->sibling_class  = NULL;
340   newMetaClass->protocols      = NULL;
341   newMetaClass->gc_object_type = NULL;
342   
343   // printf("setup class ..\n");
344   /* init class */
345   newClass->super_class    = (Class)((Class)self)->name;
346   newClass->class_pointer  = newMetaClass;
347   newClass->name           = name;
348   newClass->version        = 0;
349   newClass->info           = _CLS_CLASS;
350   newClass->instance_size  = instanceSize;
351   newClass->methods        = NULL;
352   newClass->dtable         = NULL;
353   newClass->subclass_list  = NULL;
354   newClass->sibling_class  = NULL;
355   newClass->protocols      = NULL;
356   newClass->gc_object_type = NULL;
357   newClass->ivars          = _ivars;
358   
359   /* allocate module */
360   
361   module = malloc(sizeof(Module));
362   NSCAssert(module, @"could not allocate module !");
363   memset(module, 0, sizeof(Module));
364   module->version = 8;
365   module->size    = sizeof(Module);
366   module->name    = moduleName;
367
368   /* allocate symtab with one entry */
369   module->symtab = malloc(sizeof(Symtab) + (2 * sizeof(void *)));
370   module->symtab->sel_ref_cnt = 0;
371   module->symtab->refs        = 0; // ptr to array of 'struct objc_selector'
372   module->symtab->cls_def_cnt = 1;
373   module->symtab->cat_def_cnt = 0;
374   module->symtab->defs[0] = newClass;
375   module->symtab->defs[1] = NULL;
376
377   /* execute module */
378   {
379 #if GCC_VERSION < 30400
380     extern void __objc_exec_class(Module_t module); // is thread-safe
381     extern void __objc_resolve_class_links();
382 #else
383     void __objc_exec_class(void* module);
384     void __objc_resolve_class_links();
385 #endif
386     
387     //printf("execute class\n");
388     __objc_exec_class(module);
389     //printf("resolve links\n");
390     __objc_resolve_class_links();
391   }
392   
393   return NSClassFromString(_className);
394 #endif
395 }
396
397 + (Class)subclass:(NSString *)_className
398   ivars:(NSString *)_name1,...
399 {
400   va_list    va;
401   unsigned   ivarCount, currentSize;
402   NSString   *n, *t;
403   
404   currentSize = ((Class)self)->instance_size;
405   
406   va_start(va, _name1);
407   for (n = _name1, t = va_arg(va, NSString *), ivarCount = 0;
408        (n != nil && t != nil);
409        n = va_arg(va, NSString *), t = va_arg(va, NSString *))
410     ivarCount++;
411   va_end(va);
412   
413 #if NeXT_RUNTIME || APPLE_RUNTIME
414   {
415     /* some tricks for Apple inspired by PyObjC, long live OpenSource ;-) */
416     IvarList_t        ivars;
417     struct objc_class *clazz;
418     struct objc_class *metaClazz;
419     struct objc_class *rootClazz;
420     
421     /* build ivars */
422     
423     ivars = NULL;
424     if (ivarCount > 0) {
425       ivars = calloc(sizeof(struct objc_ivar_list) +
426                      (ivarCount) * sizeof(struct objc_ivar), sizeof(char));
427       
428       va_start(va, _name1);
429       for (n = _name1, t = va_arg(va, NSString *), ivarCount = 0;
430            (n != nil && t != nil);
431            n = va_arg(va, NSString *), t=va_arg(va, NSString *), ivarCount++) {
432         Ivar     var;
433         char     *ivarName, *ivarType;
434         int      ivarOffset;
435         unsigned len, typeAlign, typeLen;
436         
437         len = [n cStringLength];
438         ivarName = malloc(len + 2);
439         [n getCString:ivarName];
440         ivarName[len] = '\0';
441         
442         len = [t cStringLength];
443         ivarType = malloc(len + 2);
444         [t getCString:ivarType];
445         ivarType[len] = '\0';
446         
447         /* calc ivarOffset */
448         typeAlign = 0; // TODO: alignment?!
449         // TODO: add more types ...
450         switch (*ivarType) { 
451           /* the Apple runtime has no func to calc a type size ?! */
452         case '@': typeLen = sizeof(id);    break;
453         case ':': typeLen = sizeof(SEL);   break;
454         case 'c': typeLen = sizeof(signed char);  break;
455         case 's': typeLen = sizeof(signed short); break;
456         case 'i': typeLen = sizeof(signed int);   break;
457         case 'C': typeLen = sizeof(unsigned char);  break;
458         case 'S': typeLen = sizeof(unsigned short); break;
459         case 'I': typeLen = sizeof(unsigned int);   break;
460         default:
461           NSAssert1(NO, @"does not support ivars of type '%s'", ivarType);
462           break;
463         }
464         ivarOffset = currentSize;
465
466         var = ivars->ivar_list + ivars->ivar_count;
467         ivars->ivar_count++;
468         
469         var->ivar_name   = ivarName;
470         var->ivar_offset = ivarOffset;
471         var->ivar_type   = ivarType;
472         
473         /* adjust current size */
474         currentSize = ivarOffset + typeLen;
475       }
476       va_end(va);
477     }
478     
479     // TODO: move the following to a subclass method
480     
481     /* determine root class */
482     
483     for (rootClazz = self; rootClazz->super_class != NULL; )
484       rootClazz = rootClazz->super_class;
485
486     /* setup meta class */
487     
488     metaClazz = calloc(1, sizeof(struct objc_class));
489     metaClazz->isa           = rootClazz->isa; // root-meta is the metameta
490     metaClazz->name          = strdup([_className cString]);
491     metaClazz->info          = CLS_META;
492     metaClazz->super_class   = ((struct objc_class *)self)->isa;
493     metaClazz->instance_size = ((struct objc_class *)self)->isa->instance_size;
494     metaClazz->ivars         = NULL;
495     metaClazz->protocols     = NULL;
496     
497     /* setup class */
498     
499     clazz = calloc(1, sizeof(struct objc_class));
500     clazz->isa           = metaClazz; /* hook up meta class */
501     clazz->name          = strdup([_className cString]);
502     clazz->info          = CLS_CLASS;
503     clazz->super_class   = self;
504     clazz->instance_size = currentSize;
505     clazz->ivars         = ivars;
506     clazz->protocols     = NULL;
507
508 #if 0
509     NSLog(@"instance size: %d, ivar-count: %d",
510           currentSize, ivars->ivar_count);
511 #endif
512     
513     /* setup method lists */
514     
515     metaClazz->methodLists = calloc(1, sizeof(struct objc_method_list *));
516     clazz->methodLists     = calloc(1, sizeof(struct objc_method_list *));
517     
518     /* Note: MacOSX specific, Radar #3317376, hint taken from PyObjC */
519     metaClazz->methodLists[0] = (struct objc_method_list *)-1;
520     clazz->methodLists[0]     = (struct objc_method_list *)-1;
521     
522     /* add to runtime (according to PyObjC not reversible?) */
523     objc_addClass(clazz);
524     return NSClassFromString(_className);
525   }
526 #else
527   {
528   IvarList_t ivars;
529   
530   ivars = malloc(sizeof(IvarList) + (sizeof(struct objc_ivar) * ivarCount));
531   ivars->ivar_count = ivarCount;
532   
533   va_start(va, _name1);
534   for (n = _name1, t = va_arg(va, NSString *), ivarCount = 0;
535        (n != nil && t != nil);
536        n = va_arg(va, NSString *), t = va_arg(va, NSString *), ivarCount++) {
537     char     *ivarName, *ivarType;
538     int      ivarOffset;
539     unsigned len, typeAlign, typeLen;
540     
541     len = [n cStringLength];
542     ivarName = malloc(len + 2);
543     [n getCString:ivarName];
544     ivarName[len] = '\0';
545     
546     len = [t cStringLength];
547     ivarType = malloc(len + 2);
548     [t getCString:ivarType];
549     ivarType[len] = '\0';
550     
551     /* calc ivarOffset */
552     typeAlign  = objc_alignof_type(ivarType);
553     typeLen    = objc_sizeof_type(ivarType);
554     ivarOffset = currentSize;
555     
556     /* check if offset is aligned */
557     if ((ivarOffset % typeAlign) != 0) {
558       /* align offset */
559       len = (typeAlign - (ivarOffset % typeAlign));
560       ivarOffset += len;
561     }
562
563     /* adjust current size */
564     currentSize = ivarOffset + typeLen;
565     
566     ivars->ivar_list[ivarCount].ivar_name   = ivarName;
567     ivars->ivar_list[ivarCount].ivar_type   = ivarType;
568     ivars->ivar_list[ivarCount].ivar_offset = ivarOffset;
569   }
570   va_end(va);
571   
572   return [self subclass:_className ivarsList:ivars];
573   }
574 #endif
575 }
576
577 /* instance variables */
578
579 + (NSArray *)instanceVariableNames {
580   NSArray  *result;
581   NSString **names;
582   int i;
583   
584   if (((Class)self)->ivars == NULL || ((Class)self)->ivars->ivar_count == 0) {
585     if (emptyArray == nil) emptyArray = [[NSArray alloc] init];
586     return emptyArray;
587   }
588
589   names = calloc(((Class)self)->ivars->ivar_count + 2, sizeof(NSString *));
590   
591   for (i = 0; i < ((Class)self)->ivars->ivar_count; i++) {
592     register unsigned char *ivarName;
593     
594     ivarName = (void *)(((Class)self)->ivars->ivar_list[i].ivar_name);
595     if (ivarName == NULL) {
596       NSLog(@"WARNING(%s): ivar without name! (idx=%d)", 
597             __PRETTY_FUNCTION__, i);
598       continue;
599     }
600     
601 #if !LIB_FOUNDATION_LIBRARY
602     names[i] = [NSString stringWithCString:ivarName];
603 #else
604     names[i] = [NSString stringWithCStringNoCopy:ivarName freeWhenDone:NO];
605 #endif
606   }
607   
608   result = [NSArray arrayWithObjects:names
609                     count:((Class)self)->ivars->ivar_count];
610   if (names) free(names);
611   return result;
612 }
613 + (NSArray *)allInstanceVariableNames {
614   NSMutableArray *varNames;
615   Class c;
616
617   varNames = [NSMutableArray arrayWithCapacity:32];
618   for (c = self; c != Nil; c = [c superclass])
619     [varNames addObjectsFromArray:[c instanceVariableNames]];
620
621   return [[varNames copy] autorelease];
622 }
623
624 + (BOOL)hasInstanceVariableWithName:(NSString *)_ivarName {
625   Class    c;
626   unsigned len = [_ivarName cStringLength];
627   char     *ivarName;
628   
629   if (len == 0)
630     return NO;
631   
632   ivarName = malloc(len + 1);
633   [_ivarName getCString:ivarName]; ivarName[len] = '\0';
634   
635   for (c = self; c != Nil; c = [c superclass]) {
636     int i;
637     
638     for (i = 0; i < c->ivars->ivar_count; i++) {
639       if (strcmp(ivarName, c->ivars->ivar_list[i].ivar_name) == 0) {
640         free(ivarName);
641         return YES;
642       }
643     }
644   }
645   free(ivarName);
646   return NO;
647 }
648
649 + (NSString *)signatureOfInstanceVariableWithName:(NSString *)_ivarName {
650   Class    c;
651   unsigned len = [_ivarName cStringLength];
652   char     *ivarName;
653   
654   if (len == 0)
655     return nil;
656
657   ivarName = malloc(len + 1);
658   [_ivarName getCString:ivarName]; ivarName[len] = '\0';
659   
660   for (c = self; c != Nil; c = [c superclass]) {
661     int i;
662
663     for (i = 0; i < c->ivars->ivar_count; i++) {
664       if (strcmp(ivarName, c->ivars->ivar_list[i].ivar_name) == 0) {
665         /* found matching ivar name */
666         if (ivarName) free(ivarName);
667 #if !LIB_FOUNDATION_LIBRARY
668         return [NSString stringWithCString:
669                            (char *)(c->ivars->ivar_list[i].ivar_type)];
670 #else
671         return [NSString stringWithCStringNoCopy:
672                            (char *)(c->ivars->ivar_list[i].ivar_type)
673                          freeWhenDone:NO];
674 #endif
675       }
676     }
677   }
678   if (ivarName) free(ivarName);
679   return nil;
680 }
681
682
683 + (unsigned)offsetOfInstanceVariableWithName:(NSString *)_ivarName {
684   Class    c;
685   unsigned len = [_ivarName cStringLength];
686   char     *ivarName;
687   
688   if (len == 0)
689     return NSNotFound;
690
691   ivarName = malloc(len + 3);
692   [_ivarName getCString:ivarName]; ivarName[len] = '\0';
693   
694   for (c = self; c != Nil; c = [c superclass]) {
695     int i;
696
697     for (i = 0; i < c->ivars->ivar_count; i++) {
698       if (strcmp(ivarName, c->ivars->ivar_list[i].ivar_name) == 0) {
699         /* found matching ivar name */
700         free(ivarName);
701         return c->ivars->ivar_list[i].ivar_offset;
702       }
703     }
704   }
705   free(ivarName);
706   return NSNotFound;
707 }
708
709 @end /* NSObject(NGObjCRuntime) */
710
711 @implementation _NGMethodNameEnumerator
712
713 - (id)initWithClass:(Class)_clazz includeSuperclassMethods:(BOOL)_flag {
714   if (_clazz == Nil) {
715     [self release];
716     return nil;
717   }
718
719   self->names = [[NSMutableSet alloc] initWithCapacity:200];
720   self->clazz                    = _clazz;
721   self->includeSuperclassMethods = _flag;
722
723 #if NeXT_RUNTIME
724   self->iter    = 0;
725   self->methods = class_nextMethodList(self->clazz, &(self->iter));
726 #else
727   self->methods = _clazz->methods;
728   self->i       = 0;
729 #endif
730   return self;
731 }
732
733 - (void)dealloc {
734   [self->names release];
735   [super dealloc];
736 }
737
738 - (id)nextObject {
739   if (self->clazz == nil)
740     return nil;
741
742   if (self->methods == NULL) {
743     /* methods of current class are done .. */
744     if (!self->includeSuperclassMethods)
745       return nil;
746
747     /* loop, maybe there are classes without a method-list ? */
748     while (self->methods == NULL) {
749       if ((self->clazz = [self->clazz superclass]) == Nil)
750         /* no more superclasses */
751         return nil;
752       
753 #if NeXT_RUNTIME
754       self->iter = 0;
755       self->methods = class_nextMethodList(self->clazz, &(self->iter));
756 #else
757       self->methods = self->clazz->methods;
758 #endif
759     }
760     self->i = 0;
761   }
762   
763 #if DEBUG
764   NSAssert(self->methods, @"missing method-list !");
765 #endif
766   
767   while (self->i >= (unsigned)self->methods->method_count) {
768 #if NeXT_RUNTIME || APPLE_RUNTIME
769     self->methods = class_nextMethodList(self->clazz, &(self->iter));
770 #else
771     self->methods = self->methods->method_next;
772 #endif
773     if (self->methods == NULL)
774       break;
775     self->i = 0;
776   }
777   
778   if (self->methods == NULL) {
779     /* recurse to next super class */
780     return self->includeSuperclassMethods
781       ? [self nextObject]
782       : nil;
783   }
784
785   /* get name .. */
786   {
787     Method_t m;
788     NSString *name;
789
790     m = &(self->methods->method_list[self->i]);
791     self->i++;
792     
793     NSAssert(m, @"missing method structure !");
794     name = NSStringFromSelector(m->method_name);
795     NSAssert(name, @"couldn't get method name !");
796     
797     if ([self->names containsObject:name]) {
798       /* this name was already delivered from a subclass, take next */
799       return [self nextObject];
800     }
801
802     [self->names addObject:name];
803     
804     return name;
805   }
806 }
807
808 @end /* _NGMethodNameEnumerator */
809
810 #if GNU_RUNTIME
811
812 @interface NGObjCClassEnumerator : NSEnumerator
813 {
814   void *state;
815 }
816 @end
817
818 @implementation NGObjCClassEnumerator
819
820 - (id)nextObject {
821   return objc_next_class(&(self->state));
822 }
823
824 @end /* NGObjCClassEnumerator */
825
826 #endif /* GNU_RUNTIME */