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