~ubuntu-branches/ubuntu/karmic/gnustep-base/karmic

« back to all changes in this revision

Viewing changes to Source/Additions/GSObjCRuntime.m

  • Committer: Bazaar Package Importer
  • Author(s): Eric Heintzmann
  • Date: 2005-04-17 00:14:38 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050417001438-enf0y07c9tku85z1
Tags: 1.10.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** Implementation of ObjC runtime additions for GNUStep
 
2
   Copyright (C) 1995-2002 Free Software Foundation, Inc.
 
3
 
 
4
   Written by:  Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
 
5
   Date: Aug 1995
 
6
   Written by:  Richard Frith-Macdonald <rfm@gnu.org>
 
7
   Date: Nov 2002
 
8
   Written by:  Manuel Guesdon <mguesdon@orange-concept.com>
 
9
   Date: Nov 2002
 
10
 
 
11
   This file is part of the GNUstep Base Library.
 
12
 
 
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.
 
17
 
 
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.
 
22
 
 
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.
 
26
 
 
27
   <title>GSObjCRuntime function and macro reference</title>
 
28
   $Date: 2005/02/22 11:22:44 $ $Revision: 1.53 $
 
29
   */
 
30
 
 
31
#include "config.h"
 
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>
 
46
#else
 
47
#include <Foundation/Foundation.h>
 
48
#endif
 
49
#include "GNUstepBase/GSObjCRuntime.h"
 
50
#include "GNUstepBase/GNUstep.h"
 
51
#include "GNUstepBase/GSCategories.h"
 
52
 
 
53
#include <objc/Protocol.h>
 
54
 
 
55
#include <string.h>
 
56
 
 
57
@class  NSNull;
 
58
 
 
59
#ifdef NeXT_Foundation_LIBRARY
 
60
@interface NSObject (MissingFromMacOSX)
 
61
+ (IMP) methodForSelector: (SEL)aSelector;
 
62
@end
 
63
#endif
 
64
 
 
65
#define BDBGPrintf(format, args...) \
 
66
  do { if (behavior_debug) { fprintf(stderr, (format) , ## args); } } while (0)
 
67
 
 
68
static objc_mutex_t local_lock = NULL;
 
69
 
 
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 */
 
75
{
 
76
  Class isa;
 
77
}
 
78
+ (Class)class;
 
79
@end
 
80
@implementation _GSObjCRuntimeInitializer
 
81
+ (void)initialize
 
82
{
 
83
  if (local_lock == NULL)
 
84
    {
 
85
      local_lock = objc_mutex_allocate();
 
86
    }
 
87
}
 
88
+ (Class)class
 
89
{
 
90
  return self;
 
91
}
 
92
@end
 
93
 
 
94
void
 
95
GSAllocateMutexAt(objc_mutex_t *request)
 
96
{
 
97
  if (request == NULL)
 
98
    {
 
99
      /* This could be called very early in process
 
100
         initialization so many things may not have
 
101
         been setup correctly yet.  */
 
102
      fprintf(stderr,
 
103
              "Error: GSAllocateMutexAt() called with NULL pointer.\n");
 
104
      abort();
 
105
    }
 
106
 
 
107
  if (local_lock == NULL)
 
108
    {
 
109
      /* Initialize in a thread safe way.  */
 
110
      [_GSObjCRuntimeInitializer class];
 
111
    }
 
112
 
 
113
  objc_mutex_lock(local_lock);
 
114
  if (*request == NULL)
 
115
    {
 
116
      *request = objc_mutex_allocate();
 
117
    }
 
118
  objc_mutex_unlock(local_lock);
 
119
}
 
120
 
 
121
/**  Deprecated ... use GSObjCFindVariable() */
 
122
BOOL
 
123
GSFindInstanceVariable(id obj, const char *name,
 
124
                       const char **type, unsigned int *size, int *offset)
 
125
{
 
126
  return GSObjCFindVariable(obj, name, type, size, offset);
 
127
}
 
128
 
 
129
/**
 
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).
 
135
 */
 
136
BOOL
 
137
GSObjCFindVariable(id obj, const char *name,
 
138
                   const char **type, unsigned int *size, int *offset)
 
139
{
 
140
  Class                 class;
 
141
  struct objc_ivar_list *ivars;
 
142
  struct objc_ivar      *ivar = 0;
 
143
 
 
144
  if (obj == nil) return NO;
 
145
  class = GSObjCClass(obj);
 
146
  while (class != nil && ivar == 0)
 
147
    {
 
148
      ivars = class->ivars;
 
149
      class = class->super_class;
 
150
      if (ivars != 0)
 
151
        {
 
152
          int   i;
 
153
 
 
154
          for (i = 0; i < ivars->ivar_count; i++)
 
155
            {
 
156
              if (strcmp(ivars->ivar_list[i].ivar_name, name) == 0)
 
157
                {
 
158
                  ivar = &ivars->ivar_list[i];
 
159
                  break;
 
160
                }
 
161
            }
 
162
        }
 
163
    }
 
164
  if (ivar == 0)
 
165
    {
 
166
      return NO;
 
167
    }
 
168
 
 
169
  if (type)
 
170
    *type = ivar->ivar_type;
 
171
  if (size)
 
172
    *size = objc_sizeof_type(ivar->ivar_type);
 
173
  if (offset)
 
174
    *offset = ivar->ivar_offset;
 
175
  return YES;
 
176
}
 
177
 
 
178
/**
 
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.
 
184
 */
 
185
NSArray *
 
186
GSObjCMethodNames(id obj)
 
187
{
 
188
  NSMutableSet  *set;
 
189
  NSArray       *array;
 
190
  Class          class;
 
191
  GSMethodList   methods;
 
192
 
 
193
  if (obj == nil)
 
194
    {
 
195
      return nil;
 
196
    }
 
197
  /*
 
198
   * Add names to a set so methods declared in superclasses
 
199
   * and then overridden do not appear more than once.
 
200
   */
 
201
  set = [[NSMutableSet alloc] initWithCapacity: 32];
 
202
 
 
203
  class = GSObjCClass(obj);
 
204
 
 
205
  while (class != nil)
 
206
    {
 
207
      void *iterator = 0;
 
208
 
 
209
      while ((methods = class_nextMethodList(class, &iterator)))
 
210
        {
 
211
          int i;
 
212
 
 
213
          for (i = 0; i < methods->method_count; i++)
 
214
            {
 
215
              GSMethod method = &methods->method_list[i];
 
216
 
 
217
              if (method->method_name != 0)
 
218
                {
 
219
                  NSString      *name;
 
220
                  const char *cName;
 
221
 
 
222
                  cName = GSNameFromSelector(method->method_name);
 
223
                  name = [[NSString alloc] initWithUTF8String: cName];
 
224
                  [set addObject: name];
 
225
                  RELEASE(name);
 
226
                }
 
227
            }
 
228
        }
 
229
      class = class->super_class;
 
230
    }
 
231
 
 
232
  array = [set allObjects];
 
233
  RELEASE(set);
 
234
  return array;
 
235
}
 
236
 
 
237
/**
 
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.
 
242
 */
 
243
NSArray *
 
244
GSObjCVariableNames(id obj)
 
245
{
 
246
  NSMutableArray        *array;
 
247
  Class                 class;
 
248
  struct objc_ivar_list *ivars;
 
249
 
 
250
  if (obj == nil)
 
251
    {
 
252
      return nil;
 
253
    }
 
254
  array = [NSMutableArray arrayWithCapacity: 16];
 
255
  class = GSObjCClass(obj);
 
256
  while (class != nil)
 
257
    {
 
258
      ivars = class->ivars;
 
259
      if (ivars != 0)
 
260
        {
 
261
          int           i;
 
262
 
 
263
          for (i = 0; i < ivars->ivar_count; i++)
 
264
            {
 
265
              NSString  *name;
 
266
 
 
267
              name = [[NSString alloc] initWithUTF8String:
 
268
                ivars->ivar_list[i].ivar_name];
 
269
              [array addObject: name];
 
270
              RELEASE(name);
 
271
            }
 
272
        }
 
273
      class = class->super_class;
 
274
    }
 
275
  return array;
 
276
}
 
277
 
 
278
/**  Deprecated ... use GSObjCGetVariable() */
 
279
void
 
280
GSGetVariable(id obj, int offset, unsigned int size, void *data)
 
281
{
 
282
  GSObjCGetVariable(obj, offset, size, data);
 
283
}
 
284
/**
 
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.
 
289
 */
 
290
void
 
291
GSObjCGetVariable(id obj, int offset, unsigned int size, void *data)
 
292
{
 
293
  memcpy(data, ((void*)obj) + offset, size);
 
294
}
 
295
 
 
296
/**  Deprecated ... use GSObjCSetVariable() */
 
297
void
 
298
GSSetVariable(id obj, int offset, unsigned int size, const void *data)
 
299
{
 
300
  GSObjCSetVariable(obj, offset, size, data);
 
301
}
 
302
/**
 
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.
 
307
 */
 
308
void
 
309
GSObjCSetVariable(id obj, int offset, unsigned int size, const void *data)
 
310
{
 
311
  memcpy(((void*)obj) + offset, data, size);
 
312
}
 
313
 
 
314
GS_EXPORT unsigned int
 
315
GSClassList(Class *buffer, unsigned int max, BOOL clearCache)
 
316
{
 
317
#ifdef NeXT_RUNTIME
 
318
  int num;
 
319
 
 
320
  if (buffer != NULL)
 
321
    {
 
322
      memset(buffer, 0, sizeof(Class) * (max + 1));
 
323
    }
 
324
 
 
325
  num = objc_getClassList(buffer, max);
 
326
  num = (num < 0) ? 0 : num;
 
327
 
 
328
#else
 
329
  static Class *cache = 0;
 
330
  static unsigned cacheClassCount = 0;
 
331
  static volatile objc_mutex_t cache_lock = NULL;
 
332
  unsigned int num;
 
333
 
 
334
  if (cache_lock == NULL)
 
335
    {
 
336
      GSAllocateMutexAt((void*)&cache_lock);
 
337
    }
 
338
 
 
339
  objc_mutex_lock(cache_lock);
 
340
 
 
341
  if (clearCache)
 
342
    {
 
343
      if (cache)
 
344
        {
 
345
          objc_free(cache);
 
346
          cache = NULL;
 
347
        }
 
348
      cacheClassCount = 0;
 
349
    }
 
350
 
 
351
  if (cache == NULL)
 
352
    {
 
353
      void *iterator = 0;
 
354
      Class cls;
 
355
      unsigned int i;
 
356
 
 
357
      cacheClassCount = 0;
 
358
      while ((cls = objc_next_class(&iterator)))
 
359
        {
 
360
          cacheClassCount++;
 
361
        }
 
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))
 
367
        {
 
368
          cache[i] = cls;
 
369
        }
 
370
      cache[i] = NULL;
 
371
    }
 
372
 
 
373
  if (buffer == NULL)
 
374
    {
 
375
      num = cacheClassCount;
 
376
    }
 
377
  else
 
378
    {
 
379
      size_t       cpySize;
 
380
      unsigned int cpyCnt;
 
381
 
 
382
      cpyCnt = MIN(max, cacheClassCount);
 
383
      cpySize = sizeof(Class) * cpyCnt;
 
384
      memcpy(buffer, cache, cpySize);
 
385
      buffer[cpyCnt] = NULL;
 
386
 
 
387
      num = (max > cacheClassCount) ? 0 : (cacheClassCount - max);
 
388
    }
 
389
 
 
390
  objc_mutex_unlock(cache_lock);
 
391
 
 
392
#endif
 
393
 
 
394
  return num;
 
395
}
 
396
 
 
397
/** references:
 
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
 
402
**/
 
403
 
 
404
/**
 
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).
 
408
 * </p>
 
409
 * <p>The iVars dictionary lists the instance variable names and their types.
 
410
 * </p>
 
411
 */
 
412
NSValue *
 
413
GSObjCMakeClass(NSString *name, NSString *superName, NSDictionary *iVars)
 
414
{
 
415
  Class         newClass;
 
416
  Class         classSuperClass;
 
417
  const char    *classNameCString;
 
418
  const char    *superClassNameCString;
 
419
  Class         newMetaClass;
 
420
  Class         rootClass;
 
421
  unsigned int  iVarSize;
 
422
  char          *tmp;
 
423
 
 
424
  NSCAssert(name, @"no name");
 
425
  NSCAssert(superName, @"no superName");
 
426
 
 
427
  classSuperClass = NSClassFromString(superName);
 
428
 
 
429
  NSCAssert1(classSuperClass, @"No class named %@",superName);
 
430
  NSCAssert1(!NSClassFromString(name), @"A class %@ already exists", name);
 
431
 
 
432
  classNameCString = [name cString];
 
433
  tmp = objc_malloc(strlen(classNameCString) + 1);
 
434
  strcpy(tmp, classNameCString);
 
435
  classNameCString = tmp;
 
436
 
 
437
  superClassNameCString = [superName cString];
 
438
  tmp = objc_malloc(strlen(superClassNameCString) + 1);
 
439
  strcpy(tmp, superClassNameCString);
 
440
  superClassNameCString = tmp;
 
441
 
 
442
  rootClass = classSuperClass;
 
443
  while (rootClass->super_class != 0)
 
444
    {
 
445
      rootClass = rootClass->super_class;
 
446
    }
 
447
 
 
448
  /*
 
449
   * Create new class and meta class structure storage
 
450
   *
 
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
 
455
   * need to cast it.
 
456
   */
 
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
 
464
 
 
465
 
 
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
 
473
 
 
474
  // work on instances variables
 
475
  iVarSize = classSuperClass->instance_size; // super class ivar size
 
476
  if ([iVars count] > 0)
 
477
    {
 
478
      unsigned int      iVarsStructsSize;
 
479
      struct objc_ivar  *ivar = NULL;
 
480
      unsigned int      iVarsCount = [iVars count];
 
481
      NSEnumerator      *enumerator = [iVars keyEnumerator];
 
482
      NSString          *key;
 
483
 
 
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);
 
487
 
 
488
      // Allocate for all ivars
 
489
      newClass->ivars = (struct objc_ivar_list*)objc_malloc(iVarsStructsSize);
 
490
      memset(newClass->ivars, 0, iVarsStructsSize);
 
491
 
 
492
      // Set ivars count
 
493
      newClass->ivars->ivar_count = iVarsCount;
 
494
 
 
495
      // initialize each ivar
 
496
      ivar = newClass->ivars->ivar_list; // 1st one
 
497
      while ((key = [enumerator nextObject]) != nil)
 
498
        {
 
499
          const char    *iVarName = [key cString];
 
500
          const char    *iVarType = [[iVars objectForKey: key] cString];
 
501
 
 
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;
 
508
 
 
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
 
513
          ivar = ivar + 1;
 
514
        }
 
515
    }
 
516
 
 
517
  /*
 
518
   * Size in bytes of the class.  The sum of the class definition
 
519
   * and all super class definitions.
 
520
   */
 
521
  newClass->instance_size = iVarSize;
 
522
 
 
523
  // Meta Class instance size is superclass instance size.
 
524
  newMetaClass->instance_size = classSuperClass->class_pointer->instance_size;
 
525
 
 
526
  return [NSValue valueWithPointer: newClass];
 
527
}
 
528
 
 
529
/**
 
530
 * The classes argument is an array of NSValue objects containing pointers
 
531
 * to classes previously created by the GSObjCMakeClass() function.
 
532
 */
 
533
#ifdef NeXT_RUNTIME
 
534
void
 
535
GSObjCAddClasses(NSArray *classes)
 
536
{
 
537
  unsigned int  numClasses = [classes count];
 
538
  unsigned int  i;
 
539
  for (i = 0; i < numClasses; i++)
 
540
    {
 
541
      objc_addClass((Class)[[classes objectAtIndex: i] pointerValue]);
 
542
    }
 
543
}
 
544
#else
 
545
/*
 
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.
 
549
 */
 
550
#define OBJC_VERSION    8
 
551
 
 
552
void
 
553
GSObjCAddClasses(NSArray *classes)
 
554
{
 
555
  void  __objc_exec_class (void* module);
 
556
  void  __objc_resolve_class_links ();
 
557
  Module_t      module;
 
558
  Symtab_t      symtab;
 
559
  unsigned int  numClasses = [classes count];
 
560
  unsigned int  i;
 
561
  Class         c;
 
562
 
 
563
  NSCAssert(numClasses > 0, @"No classes (array is NULL)");
 
564
 
 
565
  c = (Class)[[classes objectAtIndex: 0] pointerValue];
 
566
 
 
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 *));
 
575
 
 
576
  symtab = module->symtab;
 
577
  symtab->sel_ref_cnt = 0;
 
578
  symtab->refs = 0;
 
579
  symtab->cls_def_cnt = numClasses; // We are defining numClasses classes.
 
580
  symtab->cat_def_cnt = 0; // But no categories
 
581
 
 
582
  for (i = 0; i < numClasses; i++)
 
583
    {
 
584
      symtab->defs[i] = (Class)[[classes objectAtIndex: i] pointerValue];
 
585
    }
 
586
  symtab->defs[numClasses] = NULL; //null terminated list
 
587
 
 
588
  // Insert our new class into the runtime.
 
589
  __objc_exec_class (module);
 
590
  __objc_resolve_class_links();
 
591
}
 
592
#endif
 
593
 
 
594
 
 
595
static int behavior_debug = 0;
 
596
 
 
597
void
 
598
GSObjCBehaviorDebug(int i)
 
599
{
 
600
  behavior_debug = i;
 
601
}
 
602
 
 
603
#if NeXT_RUNTIME
 
604
 
 
605
static GSMethod search_for_method_in_class (Class cls, SEL op);
 
606
 
 
607
void
 
608
GSObjCAddMethods (Class cls, GSMethodList methods)
 
609
{
 
610
  static SEL initialize_sel = 0;
 
611
  GSMethodList mlist;
 
612
 
 
613
  if (!initialize_sel)
 
614
    initialize_sel = sel_register_name ("initialize");
 
615
 
 
616
  /* Add methods to cls->dtable and cls->methods */
 
617
  mlist = methods;
 
618
    {
 
619
      int counter;
 
620
      GSMethodList new_list;
 
621
 
 
622
      counter = mlist->method_count ? mlist->method_count - 1 : 1;
 
623
 
 
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;
 
630
 
 
631
      while (counter >= 0)
 
632
        {
 
633
          GSMethod method = &(mlist->method_list[counter]);
 
634
 
 
635
          BDBGPrintf("   processing method [%s] ... ",
 
636
                     GSNameFromSelector(method->method_name));
 
637
 
 
638
          if (!search_for_method_in_class(cls, method->method_name)
 
639
            && !sel_eq(method->method_name, initialize_sel))
 
640
            {
 
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)++;
 
646
 
 
647
              BDBGPrintf("added.\n");
 
648
            }
 
649
          else
 
650
            {
 
651
              BDBGPrintf("ignored.\n");
 
652
            }
 
653
          counter -= 1;
 
654
        }
 
655
      if (new_list->method_count)
 
656
        {
 
657
          class_add_method_list(cls, new_list);
 
658
        }
 
659
      else
 
660
        {
 
661
          OBJC_FREE(new_list);
 
662
        }
 
663
    }
 
664
}
 
665
 
 
666
/* Search for the named method's method structure.  Return a pointer
 
667
   to the method's method structure if found.  NULL otherwise. */
 
668
static GSMethod
 
669
search_for_method_in_class (Class cls, SEL op)
 
670
{
 
671
  void *iterator = 0;
 
672
  GSMethodList method_list;
 
673
 
 
674
  if (! sel_is_mapped (op))
 
675
    return NULL;
 
676
 
 
677
  /* If not found then we'll search the list.  */
 
678
  while ((method_list = class_nextMethodList(cls, &iterator)))
 
679
    {
 
680
      int i;
 
681
 
 
682
      /* Search the method list.  */
 
683
      for (i = 0; i < method_list->method_count; ++i)
 
684
        {
 
685
          GSMethod method = &method_list->method_list[i];
 
686
 
 
687
          if (method->method_name)
 
688
            {
 
689
              if (sel_eq(method->method_name, op))
 
690
                return method;
 
691
            }
 
692
        }
 
693
    }
 
694
 
 
695
  return NULL;
 
696
}
 
697
 
 
698
#else /* GNU runtime */
 
699
 
 
700
/*
 
701
 * The following two functions are implemented in the GNU objc runtime
 
702
 */
 
703
extern Method_t search_for_method_in_list(MethodList_t list, SEL op);
 
704
extern void class_add_method_list(Class, MethodList_t);
 
705
 
 
706
static Method_t search_for_method_in_class (Class cls, SEL op);
 
707
 
 
708
void
 
709
GSObjCAddMethods (Class cls, GSMethodList methods)
 
710
{
 
711
  static SEL initialize_sel = 0;
 
712
  GSMethodList mlist;
 
713
 
 
714
  if (initialize_sel == 0)
 
715
    {
 
716
      initialize_sel = sel_register_name ("initialize");
 
717
    }
 
718
 
 
719
  /* Add methods to class->dtable and class->methods */
 
720
  for (mlist = methods; mlist; mlist = mlist->method_next)
 
721
    {
 
722
      int counter;
 
723
      GSMethodList new_list;
 
724
 
 
725
      counter = mlist->method_count ? mlist->method_count - 1 : 1;
 
726
 
 
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;
 
734
 
 
735
      while (counter >= 0)
 
736
        {
 
737
          GSMethod method = &(mlist->method_list[counter]);
 
738
          const char *name = GSNameFromSelector(method->method_name);
 
739
 
 
740
          BDBGPrintf("   processing method [%s] ... ", name);
 
741
 
 
742
          if (!search_for_method_in_list(cls->methods, method->method_name)
 
743
            && !sel_eq(method->method_name, initialize_sel))
 
744
            {
 
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;
 
749
              /*
 
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
 
753
               * for that.
 
754
               */
 
755
              new_list->method_list[new_list->method_count].method_name
 
756
                = (SEL)name;
 
757
              (new_list->method_count)++;
 
758
 
 
759
              BDBGPrintf("added.\n");
 
760
            }
 
761
          else
 
762
            {
 
763
              BDBGPrintf("ignored.\n");
 
764
            }
 
765
          counter -= 1;
 
766
        }
 
767
      if (new_list->method_count)
 
768
        {
 
769
          class_add_method_list(cls, new_list);
 
770
        }
 
771
      else
 
772
        {
 
773
          OBJC_FREE(new_list);
 
774
        }
 
775
    }
 
776
}
 
777
 
 
778
static Method_t
 
779
search_for_method_in_class (Class cls, SEL op)
 
780
{
 
781
  return cls != NULL ? search_for_method_in_list(cls->methods, op) : NULL;
 
782
}
 
783
 
 
784
#endif /* NeXT runtime */
 
785
 
 
786
GSMethod
 
787
GSGetMethod(Class cls, SEL sel,
 
788
            BOOL searchInstanceMethods,
 
789
            BOOL searchSuperClasses)
 
790
{
 
791
  if (cls == 0 || sel == 0)
 
792
    {
 
793
      return 0;
 
794
    }
 
795
 
 
796
  if (searchSuperClasses == NO)
 
797
    {
 
798
      if (searchInstanceMethods == NO)
 
799
        {
 
800
          return search_for_method_in_class(cls->class_pointer, sel);
 
801
        }
 
802
      else
 
803
        {
 
804
          return search_for_method_in_class(cls, sel);
 
805
        }
 
806
    }
 
807
  else
 
808
    {
 
809
      if (searchInstanceMethods == NO)
 
810
        {
 
811
          /*
 
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().
 
816
          */
 
817
#ifdef NeXT_RUNTIME
 
818
          return class_getClassMethod(cls, sel);
 
819
#else
 
820
          return class_get_class_method(cls->class_pointer, sel);
 
821
#endif
 
822
        }
 
823
      else
 
824
        {
 
825
          return class_get_instance_method(cls, sel);
 
826
        }
 
827
    }
 
828
}
 
829
 
 
830
 
 
831
/* See header for documentation. */
 
832
GSMethodList
 
833
GSAllocMethodList (unsigned int count)
 
834
{
 
835
  GSMethodList list;
 
836
  size_t size;
 
837
 
 
838
  size = (sizeof (struct objc_method_list) +
 
839
          sizeof (struct objc_method[count]));
 
840
  list = objc_malloc (size);
 
841
  memset(list, 0, size);
 
842
 
 
843
  return list;
 
844
}
 
845
 
 
846
/* See header for documentation. */
 
847
void
 
848
GSAppendMethodToList (GSMethodList list,
 
849
                      SEL sel,
 
850
                      const char *types,
 
851
                      IMP imp,
 
852
                      BOOL isFree)
 
853
{
 
854
  unsigned int num;
 
855
 
 
856
  num = (list->method_count)++;
 
857
 
 
858
#ifdef GNU_RUNTIME
 
859
  /*
 
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.
 
865
   */
 
866
  sel = (SEL)GSNameFromSelector (sel);
 
867
 
 
868
  if (isFree == NO)
 
869
    {
 
870
      const char *sel_save = (const char *)sel;
 
871
 
 
872
      sel = sel_get_typed_uid (sel_save, types);
 
873
      if (sel == 0)
 
874
        {
 
875
          sel = sel_register_typed_name (sel_save, types);
 
876
        }
 
877
    }
 
878
#endif
 
879
 
 
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;
 
883
}
 
884
 
 
885
/* See header for documentation. */
 
886
BOOL
 
887
GSRemoveMethodFromList (GSMethodList list,
 
888
                        SEL sel,
 
889
                        BOOL isFree)
 
890
{
 
891
  int i;
 
892
 
 
893
#ifdef GNU_RUNTIME
 
894
  if (isFree == YES)
 
895
    {
 
896
      sel = (SEL)GSNameFromSelector (sel);
 
897
    }
 
898
#else
 
899
  /* Insure that we always use sel_eq on non GNU Runtimes.  */
 
900
  isFree = NO;
 
901
#endif
 
902
 
 
903
  for (i = 0; i < list->method_count; i++)
 
904
    {
 
905
      SEL  method_name = list->method_list[i].method_name;
 
906
 
 
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)))
 
911
        {
 
912
          /* Found the list.  Now fill up the gap.  */
 
913
          for ((list->method_count)--; i < list->method_count; i++)
 
914
            {
 
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;
 
921
            }
 
922
 
 
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;
 
930
 
 
931
          return YES;
 
932
        }
 
933
    }
 
934
  return NO;
 
935
}
 
936
 
 
937
/* See header for documentation. */
 
938
GSMethodList
 
939
GSMethodListForSelector(Class cls,
 
940
                        SEL selector,
 
941
                        void **iterator,
 
942
                        BOOL searchInstanceMethods)
 
943
{
 
944
  void *local_iterator = 0;
 
945
 
 
946
  if (cls == 0 || selector == 0)
 
947
    {
 
948
      return 0;
 
949
    }
 
950
 
 
951
  if (searchInstanceMethods == NO)
 
952
    {
 
953
      cls = cls->class_pointer;
 
954
    }
 
955
 
 
956
  if (sel_is_mapped(selector))
 
957
    {
 
958
      void **iterator_pointer;
 
959
      GSMethodList method_list;
 
960
 
 
961
      iterator_pointer = (iterator == 0 ? &local_iterator : iterator);
 
962
      while ((method_list = class_nextMethodList(cls, iterator_pointer)))
 
963
        {
 
964
          /* Search the method in the current list.  */
 
965
          if (GSMethodFromList(method_list, selector, NO) != 0)
 
966
            {
 
967
              return method_list;
 
968
            }
 
969
        }
 
970
    }
 
971
 
 
972
  return 0;
 
973
}
 
974
 
 
975
/* See header for documentation. */
 
976
GSMethod
 
977
GSMethodFromList(GSMethodList list,
 
978
                 SEL sel,
 
979
                 BOOL isFree)
 
980
{
 
981
  unsigned i;
 
982
 
 
983
#ifdef GNU_RUNTIME
 
984
  if (isFree)
 
985
    {
 
986
      sel = (SEL)GSNameFromSelector (sel);
 
987
    }
 
988
#else
 
989
  isFree = NO;
 
990
#endif
 
991
 
 
992
  for (i = 0; i < list->method_count; ++i)
 
993
    {
 
994
      GSMethod method = &list->method_list[i];
 
995
      SEL  method_name = method->method_name;
 
996
 
 
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)))
 
1001
        {
 
1002
          return method;
 
1003
        }
 
1004
    }
 
1005
  return 0;
 
1006
}
 
1007
 
 
1008
/* See header for documentation. */
 
1009
void
 
1010
GSAddMethodList(Class cls,
 
1011
                GSMethodList list,
 
1012
                BOOL toInstanceMethods)
 
1013
{
 
1014
  if (cls == 0 || list == 0)
 
1015
    {
 
1016
      return;
 
1017
    }
 
1018
 
 
1019
  if (toInstanceMethods == NO)
 
1020
    {
 
1021
      cls = cls->class_pointer;
 
1022
    }
 
1023
 
 
1024
  class_add_method_list(cls, list);
 
1025
}
 
1026
 
 
1027
GS_STATIC_INLINE void
 
1028
gs_revert_selector_names_in_list(GSMethodList list)
 
1029
{
 
1030
  int i;
 
1031
  const char *name;
 
1032
 
 
1033
  for (i = 0; i < list->method_count; i++)
 
1034
    {
 
1035
      name  = GSNameFromSelector(list->method_list[i].method_name);
 
1036
      if (name)
 
1037
        {
 
1038
          list->method_list[i].method_name = (SEL)name;
 
1039
        }
 
1040
    }
 
1041
}
 
1042
 
 
1043
/* See header for documentation. */
 
1044
void
 
1045
GSRemoveMethodList(Class cls,
 
1046
                   GSMethodList list,
 
1047
                   BOOL fromInstanceMethods)
 
1048
{
 
1049
  if (cls == 0 || list == 0)
 
1050
    {
 
1051
      return;
 
1052
    }
 
1053
 
 
1054
  if (fromInstanceMethods == NO)
 
1055
    {
 
1056
      cls = cls->class_pointer;
 
1057
    }
 
1058
 
 
1059
#ifdef NeXT_RUNTIME
 
1060
  class_removeMethods(cls, list);
 
1061
#else
 
1062
  if (list == cls->methods)
 
1063
    {
 
1064
      cls->methods = list->method_next;
 
1065
      list->method_next = 0;
 
1066
 
 
1067
      /*
 
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.
 
1072
      */
 
1073
      gs_revert_selector_names_in_list(list);
 
1074
    }
 
1075
  else
 
1076
    {
 
1077
      GSMethodList current_list;
 
1078
      for (current_list = cls->methods;
 
1079
           current_list != 0;
 
1080
           current_list = current_list->method_next)
 
1081
        {
 
1082
          if (current_list->method_next == list)
 
1083
            {
 
1084
              current_list->method_next = list->method_next;
 
1085
              list->method_next = 0;
 
1086
 
 
1087
              /*
 
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.
 
1092
              */
 
1093
              gs_revert_selector_names_in_list(list);
 
1094
            }
 
1095
        }
 
1096
    }
 
1097
#endif /* NeXT_RUNTIME */
 
1098
}
 
1099
 
 
1100
 
 
1101
GS_STATIC_INLINE const char *
 
1102
gs_skip_type_qualifier_and_layout_info (const char *types)
 
1103
{
 
1104
  while (*types == '+'
 
1105
         || *types == '-'
 
1106
         || *types == _C_CONST
 
1107
         || *types == _C_IN
 
1108
         || *types == _C_INOUT
 
1109
         || *types == _C_OUT
 
1110
         || *types == _C_BYCOPY
 
1111
         || *types == _C_BYREF
 
1112
         || *types == _C_ONEWAY
 
1113
         || *types == _C_GCINVISIBLE
 
1114
         || isdigit ((unsigned char) *types))
 
1115
    {
 
1116
      types++;
 
1117
    }
 
1118
 
 
1119
  return types;
 
1120
}
 
1121
 
 
1122
/* See header for documentation. */
 
1123
GS_EXPORT BOOL
 
1124
GSSelectorTypesMatch(const char *types1, const char *types2)
 
1125
{
 
1126
  if (! types1 || ! types2)
 
1127
    return NO;
 
1128
 
 
1129
  while (*types1 && *types2)
 
1130
    {
 
1131
      types1 = gs_skip_type_qualifier_and_layout_info (types1);
 
1132
      types2 = gs_skip_type_qualifier_and_layout_info (types2);
 
1133
 
 
1134
      /* Reached the end of the selector.  */
 
1135
      if (! *types1 && ! *types2)
 
1136
        return YES;
 
1137
 
 
1138
      /* Ignore structure name yet compare layout.  */
 
1139
      if (*types1 == '{' && *types2 == '{')
 
1140
        {
 
1141
          while (*types1 != '=')
 
1142
            types1++;
 
1143
 
 
1144
          while (*types2 != '=')
 
1145
            types2++;
 
1146
        }
 
1147
 
 
1148
      if (*types1 != *types2)
 
1149
        return NO;
 
1150
 
 
1151
      types1++;
 
1152
      types2++;
 
1153
    }
 
1154
 
 
1155
  types1 = gs_skip_type_qualifier_and_layout_info (types1);
 
1156
  types2 = gs_skip_type_qualifier_and_layout_info (types2);
 
1157
 
 
1158
  return (! *types1 && ! *types2);
 
1159
}
 
1160
 
 
1161
/* See header for documentation. */
 
1162
GSIVar
 
1163
GSCGetInstanceVariableDefinition(Class cls, const char *name)
 
1164
{
 
1165
  struct objc_ivar_list *list;
 
1166
  int i;
 
1167
 
 
1168
  if (cls == 0)
 
1169
    return 0;
 
1170
 
 
1171
  list = cls->ivars;
 
1172
  for (i = 0; (list != 0) && i < list->ivar_count; i++)
 
1173
    {
 
1174
      if (strcmp (list->ivar_list[i].ivar_name, name) == 0)
 
1175
        return &(list->ivar_list[i]);
 
1176
    }
 
1177
  cls = GSObjCSuper(cls);
 
1178
  if (cls != 0)
 
1179
    {
 
1180
      return GSCGetInstanceVariableDefinition(cls, name);
 
1181
    }
 
1182
  return 0;
 
1183
}
 
1184
 
 
1185
GSIVar
 
1186
GSObjCGetInstanceVariableDefinition(Class cls, NSString *name)
 
1187
{
 
1188
  return GSCGetInstanceVariableDefinition(cls, [name cString]);
 
1189
}
 
1190
 
 
1191
typedef struct {
 
1192
  @defs(Protocol)
 
1193
} *pcl;
 
1194
 
 
1195
GS_STATIC_INLINE unsigned int
 
1196
gs_string_hash(const char *s)
 
1197
{
 
1198
  unsigned int val = 0;
 
1199
  while (*s != 0)
 
1200
    {
 
1201
      val = (val << 5) + val + *s++;
 
1202
    }
 
1203
  return val;
 
1204
}
 
1205
 
 
1206
GS_STATIC_INLINE pcl
 
1207
gs_find_protocol_named_in_protocol_list(const char *name,
 
1208
                                        struct objc_protocol_list *pcllist)
 
1209
{
 
1210
  pcl p = NULL;
 
1211
  size_t i;
 
1212
 
 
1213
  while (pcllist != NULL)
 
1214
    {
 
1215
      for (i=0; i<pcllist->count; i++)
 
1216
        {
 
1217
          p = (pcl)pcllist->list[i];
 
1218
          if (strcmp(p->protocol_name, name) == 0)
 
1219
            {
 
1220
              return p;
 
1221
            }
 
1222
        }
 
1223
      pcllist = pcllist->next;
 
1224
    }
 
1225
  return NULL;
 
1226
}
 
1227
 
 
1228
GS_STATIC_INLINE pcl
 
1229
gs_find_protocol_named(const char *name)
 
1230
{
 
1231
  pcl p = NULL;
 
1232
  Class cls;
 
1233
#ifdef NeXT_RUNTIME
 
1234
  Class *clsList, *clsListStart;
 
1235
  unsigned int num;
 
1236
 
 
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);
 
1241
 
 
1242
  clsListStart = clsList;
 
1243
 
 
1244
  while (p == NULL && (cls = *clsList++))
 
1245
    {
 
1246
      p = gs_find_protocol_named_in_protocol_list(name, cls->protocols);
 
1247
    }
 
1248
 
 
1249
  objc_free(clsListStart);
 
1250
 
 
1251
#else
 
1252
  void *iterator = NULL;
 
1253
 
 
1254
  while (p == NULL && (cls = objc_next_class(&iterator)))
 
1255
    {
 
1256
      p = gs_find_protocol_named_in_protocol_list(name, cls->protocols);
 
1257
    }
 
1258
 
 
1259
#endif
 
1260
  return p;
 
1261
}
 
1262
 
 
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
 
1271
 
 
1272
#define GSI_MAP_KTYPES GSUNION_PTR
 
1273
#define GSI_MAP_VTYPES GSUNION_PTR
 
1274
 
 
1275
#include "GNUstepBase/GSIMap.h"
 
1276
 
 
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;
 
1280
 
 
1281
/* Not sure about the semantics of inlining
 
1282
   functions with static variables.  */
 
1283
static void
 
1284
gs_init_protocol_lock(void)
 
1285
{
 
1286
  if (protocol_by_name_lock == NULL)
 
1287
    {
 
1288
      GSAllocateMutexAt((void *)&protocol_by_name_lock);
 
1289
      objc_mutex_lock(protocol_by_name_lock);
 
1290
      if (protocol_by_name_init == NO)
 
1291
        {
 
1292
          GSIMapInitWithZoneAndCapacity (&protocol_by_name,
 
1293
                                         NSDefaultMallocZone(),
 
1294
                                         128);
 
1295
          protocol_by_name_init = YES;
 
1296
        }
 
1297
      objc_mutex_unlock(protocol_by_name_lock);
 
1298
    }
 
1299
}
 
1300
 
 
1301
void
 
1302
GSRegisterProtocol(Protocol *proto)
 
1303
{
 
1304
  if (protocol_by_name_init == NO)
 
1305
    {
 
1306
      gs_init_protocol_lock();
 
1307
    }
 
1308
 
 
1309
  if (proto != nil)
 
1310
    {
 
1311
      GSIMapNode node;
 
1312
      pcl p;
 
1313
 
 
1314
      p = (pcl)proto;
 
1315
      objc_mutex_lock(protocol_by_name_lock);
 
1316
      node = GSIMapNodeForKey(&protocol_by_name,
 
1317
                              (GSIMapKey) p->protocol_name);
 
1318
      if (node == 0)
 
1319
        {
 
1320
          GSIMapAddPairNoRetain(&protocol_by_name,
 
1321
                                (GSIMapKey) (void *) p->protocol_name,
 
1322
                                (GSIMapVal) (void *) p);
 
1323
        }
 
1324
      objc_mutex_unlock(protocol_by_name_lock);
 
1325
    }
 
1326
}
 
1327
 
 
1328
Protocol *
 
1329
GSProtocolFromName(const char *name)
 
1330
{
 
1331
  GSIMapNode node;
 
1332
  pcl p;
 
1333
 
 
1334
  if (protocol_by_name_init == NO)
 
1335
    {
 
1336
      gs_init_protocol_lock();
 
1337
    }
 
1338
 
 
1339
  node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
 
1340
  if (node)
 
1341
    {
 
1342
      p = node->value.ptr;
 
1343
    }
 
1344
  else
 
1345
    {
 
1346
      objc_mutex_lock(protocol_by_name_lock);
 
1347
      node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
 
1348
 
 
1349
      if (node)
 
1350
        {
 
1351
          p = node->value.ptr;
 
1352
        }
 
1353
      else
 
1354
        {
 
1355
          p = gs_find_protocol_named(name);
 
1356
          if (p)
 
1357
            {
 
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);
 
1363
            }
 
1364
        }
 
1365
      objc_mutex_unlock(protocol_by_name_lock);
 
1366
 
 
1367
    }
 
1368
 
 
1369
  return (Protocol *)p;
 
1370
}
 
1371
 
 
1372
 
 
1373
/**
 
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.
 
1377
 * </p>
 
1378
 * <p>Behavior methods, when added to a class, override the class's
 
1379
 * superclass methods, but not the class's methods.
 
1380
 * </p>
 
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).
 
1385
 * </p>
 
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
 
1389
 * argument.
 
1390
 * </p>
 
1391
 * <p>This function should be called in the +initialize method of the receiver.
 
1392
 * </p>
 
1393
 * <p>If you add several behaviors to a class, be aware that the order of
 
1394
 * the additions is significant.
 
1395
 * </p>
 
1396
 */
 
1397
void
 
1398
GSObjCAddClassBehavior(Class receiver, Class behavior)
 
1399
{
 
1400
  Class behavior_super_class = GSObjCSuper(behavior);
 
1401
 
 
1402
  NSCAssert(CLS_ISCLASS(receiver), NSInvalidArgumentException);
 
1403
  NSCAssert(CLS_ISCLASS(behavior), NSInvalidArgumentException);
 
1404
 
 
1405
  /* If necessary, increase instance_size of CLASS. */
 
1406
  if (receiver->instance_size < behavior->instance_size)
 
1407
    {
 
1408
#if NeXT_RUNTIME
 
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));
 
1412
#else
 
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");
 
1420
#endif
 
1421
      receiver->instance_size = behavior->instance_size;
 
1422
    }
 
1423
 
 
1424
  BDBGPrintf("Adding behavior to class %s\n", receiver->name);
 
1425
  BDBGPrintf("  instance methods from %s\n", behavior->name);
 
1426
 
 
1427
  /* Add instance methods */
 
1428
#if NeXT_RUNTIME
 
1429
  {
 
1430
    void         *iterator = 0;
 
1431
    GSMethodList  method_list;
 
1432
 
 
1433
    method_list = class_nextMethodList(behavior, &iterator);
 
1434
    while (method_list != 0)
 
1435
      {
 
1436
        GSObjCAddMethods (receiver, method_list);
 
1437
        method_list = class_nextMethodList(behavior, &iterator);
 
1438
      }
 
1439
  }
 
1440
#else
 
1441
  GSObjCAddMethods (receiver, behavior->methods);
 
1442
#endif
 
1443
 
 
1444
  /* Add class methods */
 
1445
  BDBGPrintf("Adding class methods from %s\n",
 
1446
             behavior->class_pointer->name);
 
1447
#if NeXT_RUNTIME
 
1448
  {
 
1449
    void         *iterator = 0;
 
1450
    GSMethodList  method_list;
 
1451
 
 
1452
    method_list = class_nextMethodList(behavior->class_pointer, &iterator);
 
1453
    while (method_list != 0)
 
1454
      {
 
1455
        GSObjCAddMethods (receiver->class_pointer, method_list);
 
1456
        method_list = class_nextMethodList(behavior->class_pointer, &iterator);
 
1457
      }
 
1458
  }
 
1459
#else
 
1460
  GSObjCAddMethods (receiver->class_pointer, behavior->class_pointer->methods);
 
1461
#endif
 
1462
 
 
1463
  /* Add behavior's superclass, if not already there. */
 
1464
  if (!GSObjCIsKindOf(receiver, behavior_super_class))
 
1465
    {
 
1466
      GSObjCAddClassBehavior (receiver, behavior_super_class);
 
1467
    }
 
1468
  GSFlushMethodCacheForClass (receiver);
 
1469
}
 
1470
 
 
1471
 
 
1472
 
 
1473
 
 
1474
#ifndef NeXT_Foundation_LIBRARY
 
1475
#include        <Foundation/NSValue.h>
 
1476
#include        <Foundation/NSKeyValueCoding.h>
 
1477
#endif
 
1478
 
 
1479
 
 
1480
/**  Deprecated ... use GSObjCGetValue() */
 
1481
id
 
1482
GSGetValue(NSObject *self, NSString *key, SEL sel,
 
1483
           const char *type, unsigned size, int offset)
 
1484
{
 
1485
  return GSObjCGetValue(self, key, sel, type, size, offset);
 
1486
}
 
1487
/**
 
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
 
1491
 * supplied).<br />
 
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
 
1495
 * to get a value.
 
1496
 */
 
1497
id
 
1498
GSObjCGetValue(NSObject *self, NSString *key, SEL sel,
 
1499
               const char *type, unsigned size, int offset)
 
1500
{
 
1501
  if (sel != 0)
 
1502
    {
 
1503
      NSMethodSignature *sig = [self methodSignatureForSelector: sel];
 
1504
 
 
1505
      if ([sig numberOfArguments] != 2)
 
1506
        {
 
1507
          [NSException raise: NSInvalidArgumentException
 
1508
                      format: @"key-value get method has wrong number of args"];
 
1509
        }
 
1510
      type = [sig methodReturnType];
 
1511
    }
 
1512
  if (type == NULL)
 
1513
    {
 
1514
      return [self handleQueryWithUnboundKey: key];
 
1515
    }
 
1516
  else
 
1517
    {
 
1518
      id        val = nil;
 
1519
 
 
1520
      switch (*type)
 
1521
        {
 
1522
          case _C_ID:
 
1523
          case _C_CLASS:
 
1524
            {
 
1525
              id        v;
 
1526
 
 
1527
              if (sel == 0)
 
1528
                {
 
1529
                  v = *(id *)((char *)self + offset);
 
1530
                }
 
1531
              else
 
1532
                {
 
1533
                  id    (*imp)(id, SEL) =
 
1534
                    (id (*)(id, SEL))[self methodForSelector: sel];
 
1535
 
 
1536
                  v = (*imp)(self, sel);
 
1537
                }
 
1538
              val = v;
 
1539
            }
 
1540
            break;
 
1541
 
 
1542
          case _C_CHR:
 
1543
            {
 
1544
              signed char       v;
 
1545
 
 
1546
              if (sel == 0)
 
1547
                {
 
1548
                  v = *(char *)((char *)self + offset);
 
1549
                }
 
1550
              else
 
1551
                {
 
1552
                  signed char   (*imp)(id, SEL) =
 
1553
                    (signed char (*)(id, SEL))[self methodForSelector: sel];
 
1554
 
 
1555
                  v = (*imp)(self, sel);
 
1556
                }
 
1557
              val = [NSNumber numberWithChar: v];
 
1558
            }
 
1559
            break;
 
1560
 
 
1561
          case _C_UCHR:
 
1562
            {
 
1563
              unsigned char     v;
 
1564
 
 
1565
              if (sel == 0)
 
1566
                {
 
1567
                  v = *(unsigned char *)((char *)self + offset);
 
1568
                }
 
1569
              else
 
1570
                {
 
1571
                  unsigned char (*imp)(id, SEL) =
 
1572
                    (unsigned char (*)(id, SEL))[self methodForSelector:
 
1573
                    sel];
 
1574
 
 
1575
                  v = (*imp)(self, sel);
 
1576
                }
 
1577
              val = [NSNumber numberWithUnsignedChar: v];
 
1578
            }
 
1579
            break;
 
1580
 
 
1581
          case _C_SHT:
 
1582
            {
 
1583
              short     v;
 
1584
 
 
1585
              if (sel == 0)
 
1586
                {
 
1587
                  v = *(short *)((char *)self + offset);
 
1588
                }
 
1589
              else
 
1590
                {
 
1591
                  short (*imp)(id, SEL) =
 
1592
                    (short (*)(id, SEL))[self methodForSelector: sel];
 
1593
 
 
1594
                  v = (*imp)(self, sel);
 
1595
                }
 
1596
              val = [NSNumber numberWithShort: v];
 
1597
            }
 
1598
            break;
 
1599
 
 
1600
          case _C_USHT:
 
1601
            {
 
1602
              unsigned short    v;
 
1603
 
 
1604
              if (sel == 0)
 
1605
                {
 
1606
                  v = *(unsigned short *)((char *)self + offset);
 
1607
                }
 
1608
              else
 
1609
                {
 
1610
                  unsigned short        (*imp)(id, SEL) =
 
1611
                    (unsigned short (*)(id, SEL))[self methodForSelector:
 
1612
                    sel];
 
1613
 
 
1614
                  v = (*imp)(self, sel);
 
1615
                }
 
1616
              val = [NSNumber numberWithUnsignedShort: v];
 
1617
            }
 
1618
            break;
 
1619
 
 
1620
          case _C_INT:
 
1621
            {
 
1622
              int       v;
 
1623
 
 
1624
              if (sel == 0)
 
1625
                {
 
1626
                  v = *(int *)((char *)self + offset);
 
1627
                }
 
1628
              else
 
1629
                {
 
1630
                  int   (*imp)(id, SEL) =
 
1631
                    (int (*)(id, SEL))[self methodForSelector: sel];
 
1632
 
 
1633
                  v = (*imp)(self, sel);
 
1634
                }
 
1635
              val = [NSNumber numberWithInt: v];
 
1636
            }
 
1637
            break;
 
1638
 
 
1639
          case _C_UINT:
 
1640
            {
 
1641
              unsigned int      v;
 
1642
 
 
1643
              if (sel == 0)
 
1644
                {
 
1645
                  v = *(unsigned int *)((char *)self + offset);
 
1646
                }
 
1647
              else
 
1648
                {
 
1649
                  unsigned int  (*imp)(id, SEL) =
 
1650
                    (unsigned int (*)(id, SEL))[self methodForSelector:
 
1651
                    sel];
 
1652
 
 
1653
                  v = (*imp)(self, sel);
 
1654
                }
 
1655
              val = [NSNumber numberWithUnsignedInt: v];
 
1656
            }
 
1657
            break;
 
1658
 
 
1659
          case _C_LNG:
 
1660
            {
 
1661
              long      v;
 
1662
 
 
1663
              if (sel == 0)
 
1664
                {
 
1665
                  v = *(long *)((char *)self + offset);
 
1666
                }
 
1667
              else
 
1668
                {
 
1669
                  long  (*imp)(id, SEL) =
 
1670
                    (long (*)(id, SEL))[self methodForSelector: sel];
 
1671
 
 
1672
                  v = (*imp)(self, sel);
 
1673
                }
 
1674
              val = [NSNumber numberWithLong: v];
 
1675
            }
 
1676
            break;
 
1677
 
 
1678
          case _C_ULNG:
 
1679
            {
 
1680
              unsigned long     v;
 
1681
 
 
1682
              if (sel == 0)
 
1683
                {
 
1684
                  v = *(unsigned long *)((char *)self + offset);
 
1685
                }
 
1686
              else
 
1687
                {
 
1688
                  unsigned long (*imp)(id, SEL) =
 
1689
                    (unsigned long (*)(id, SEL))[self methodForSelector:
 
1690
                    sel];
 
1691
 
 
1692
                  v = (*imp)(self, sel);
 
1693
                }
 
1694
              val = [NSNumber numberWithUnsignedLong: v];
 
1695
            }
 
1696
            break;
 
1697
 
 
1698
#ifdef  _C_LNG_LNG
 
1699
          case _C_LNG_LNG:
 
1700
            {
 
1701
              long long v;
 
1702
 
 
1703
              if (sel == 0)
 
1704
                {
 
1705
                  v = *(long long *)((char *)self + offset);
 
1706
                }
 
1707
              else
 
1708
                {
 
1709
                   long long    (*imp)(id, SEL) =
 
1710
                    (long long (*)(id, SEL))[self methodForSelector: sel];
 
1711
 
 
1712
                  v = (*imp)(self, sel);
 
1713
                }
 
1714
              val = [NSNumber numberWithLongLong: v];
 
1715
            }
 
1716
            break;
 
1717
#endif
 
1718
 
 
1719
#ifdef  _C_ULNG_LNG
 
1720
          case _C_ULNG_LNG:
 
1721
            {
 
1722
              unsigned long long        v;
 
1723
 
 
1724
              if (sel == 0)
 
1725
                {
 
1726
                  v = *(unsigned long long *)((char *)self + offset);
 
1727
                }
 
1728
              else
 
1729
                {
 
1730
                  unsigned long long    (*imp)(id, SEL) =
 
1731
                    (unsigned long long (*)(id, SEL))[self
 
1732
                    methodForSelector: sel];
 
1733
 
 
1734
                  v = (*imp)(self, sel);
 
1735
                }
 
1736
              val = [NSNumber numberWithUnsignedLongLong: v];
 
1737
            }
 
1738
            break;
 
1739
#endif
 
1740
 
 
1741
          case _C_FLT:
 
1742
            {
 
1743
              float     v;
 
1744
 
 
1745
              if (sel == 0)
 
1746
                {
 
1747
                  v = *(float *)((char *)self + offset);
 
1748
                }
 
1749
              else
 
1750
                {
 
1751
                  float (*imp)(id, SEL) =
 
1752
                    (float (*)(id, SEL))[self methodForSelector: sel];
 
1753
 
 
1754
                  v = (*imp)(self, sel);
 
1755
                }
 
1756
              val = [NSNumber numberWithFloat: v];
 
1757
            }
 
1758
            break;
 
1759
 
 
1760
          case _C_DBL:
 
1761
            {
 
1762
              double    v;
 
1763
 
 
1764
              if (sel == 0)
 
1765
                {
 
1766
                  v = *(double *)((char *)self + offset);
 
1767
                }
 
1768
              else
 
1769
                {
 
1770
                  double        (*imp)(id, SEL) =
 
1771
                    (double (*)(id, SEL))[self methodForSelector: sel];
 
1772
 
 
1773
                  v = (*imp)(self, sel);
 
1774
                }
 
1775
              val = [NSNumber numberWithDouble: v];
 
1776
            }
 
1777
            break;
 
1778
 
 
1779
          case _C_VOID:
 
1780
            {
 
1781
              void        (*imp)(id, SEL) =
 
1782
                (void (*)(id, SEL))[self methodForSelector: sel];
 
1783
 
 
1784
              (*imp)(self, sel);
 
1785
            }
 
1786
            val = nil;
 
1787
            break;
 
1788
 
 
1789
          default:
 
1790
            [NSException raise: NSInvalidArgumentException
 
1791
                        format: @"key-value get method has unsupported type"];
 
1792
        }
 
1793
      return val;
 
1794
    }
 
1795
}
 
1796
 
 
1797
/**  Deprecated ... use GSObjCSetValue() */
 
1798
void
 
1799
GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
 
1800
           const char *type, unsigned size, int offset)
 
1801
{
 
1802
  GSObjCSetValue(self, key, val, sel, type, size, offset);
 
1803
}
 
1804
/**
 
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
 
1808
 * supplied).<br />
 
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
 
1812
 * to set a value.
 
1813
 */
 
1814
void
 
1815
GSObjCSetValue(NSObject *self, NSString *key, id val, SEL sel,
 
1816
               const char *type, unsigned size, int offset)
 
1817
{
 
1818
  static NSNull *null = nil;
 
1819
 
 
1820
  if (null == nil)
 
1821
    {
 
1822
      null = [NSNull new];
 
1823
    }
 
1824
  if (sel != 0)
 
1825
    {
 
1826
      NSMethodSignature *sig = [self methodSignatureForSelector: sel];
 
1827
 
 
1828
      if ([sig numberOfArguments] != 3)
 
1829
        {
 
1830
          [NSException raise: NSInvalidArgumentException
 
1831
                      format: @"key-value set method has wrong number of args"];
 
1832
        }
 
1833
      type = [sig getArgumentTypeAtIndex: 2];
 
1834
    }
 
1835
  if (type == NULL)
 
1836
    {
 
1837
      [self handleTakeValue: val forUnboundKey: key];
 
1838
    }
 
1839
  else if ((val == nil || val == null) && *type != _C_ID && *type != _C_CLASS)
 
1840
    {
 
1841
      [self unableToSetNilForKey: key];
 
1842
    }
 
1843
  else
 
1844
    {
 
1845
      switch (*type)
 
1846
        {
 
1847
          case _C_ID:
 
1848
          case _C_CLASS:
 
1849
            {
 
1850
              id        v = val;
 
1851
 
 
1852
              if (sel == 0)
 
1853
                {
 
1854
                  id *ptr = (id *)((char *)self + offset);
 
1855
 
 
1856
                  ASSIGN(*ptr, v);
 
1857
                }
 
1858
              else
 
1859
                {
 
1860
                  void  (*imp)(id, SEL, id) =
 
1861
                    (void (*)(id, SEL, id))[self methodForSelector: sel];
 
1862
 
 
1863
                  (*imp)(self, sel, val);
 
1864
                }
 
1865
            }
 
1866
            break;
 
1867
 
 
1868
          case _C_CHR:
 
1869
            {
 
1870
              char      v = [val charValue];
 
1871
 
 
1872
              if (sel == 0)
 
1873
                {
 
1874
                  char *ptr = (char *)((char *)self + offset);
 
1875
 
 
1876
                  *ptr = v;
 
1877
                }
 
1878
              else
 
1879
                {
 
1880
                  void  (*imp)(id, SEL, char) =
 
1881
                    (void (*)(id, SEL, char))[self methodForSelector: sel];
 
1882
 
 
1883
                  (*imp)(self, sel, v);
 
1884
                }
 
1885
            }
 
1886
            break;
 
1887
 
 
1888
          case _C_UCHR:
 
1889
            {
 
1890
              unsigned char     v = [val unsignedCharValue];
 
1891
 
 
1892
              if (sel == 0)
 
1893
                {
 
1894
                  unsigned char *ptr = (unsigned char*)((char *)self + offset);
 
1895
 
 
1896
                  *ptr = v;
 
1897
                }
 
1898
              else
 
1899
                {
 
1900
                  void  (*imp)(id, SEL, unsigned char) =
 
1901
                    (void (*)(id, SEL, unsigned char))[self methodForSelector:
 
1902
                    sel];
 
1903
 
 
1904
                  (*imp)(self, sel, v);
 
1905
                }
 
1906
            }
 
1907
            break;
 
1908
 
 
1909
          case _C_SHT:
 
1910
            {
 
1911
              short     v = [val shortValue];
 
1912
 
 
1913
              if (sel == 0)
 
1914
                {
 
1915
                  short *ptr = (short*)((char *)self + offset);
 
1916
 
 
1917
                  *ptr = v;
 
1918
                }
 
1919
              else
 
1920
                {
 
1921
                  void  (*imp)(id, SEL, short) =
 
1922
                    (void (*)(id, SEL, short))[self methodForSelector: sel];
 
1923
 
 
1924
                  (*imp)(self, sel, v);
 
1925
                }
 
1926
            }
 
1927
            break;
 
1928
 
 
1929
          case _C_USHT:
 
1930
            {
 
1931
              unsigned short    v = [val unsignedShortValue];
 
1932
 
 
1933
              if (sel == 0)
 
1934
                {
 
1935
                  unsigned short *ptr;
 
1936
 
 
1937
                  ptr = (unsigned short*)((char *)self + offset);
 
1938
                  *ptr = v;
 
1939
                }
 
1940
              else
 
1941
                {
 
1942
                  void  (*imp)(id, SEL, unsigned short) =
 
1943
                    (void (*)(id, SEL, unsigned short))[self methodForSelector:
 
1944
                    sel];
 
1945
 
 
1946
                  (*imp)(self, sel, v);
 
1947
                }
 
1948
            }
 
1949
            break;
 
1950
 
 
1951
          case _C_INT:
 
1952
            {
 
1953
              int       v = [val intValue];
 
1954
 
 
1955
              if (sel == 0)
 
1956
                {
 
1957
                  int *ptr = (int*)((char *)self + offset);
 
1958
 
 
1959
                  *ptr = v;
 
1960
                }
 
1961
              else
 
1962
                {
 
1963
                  void  (*imp)(id, SEL, int) =
 
1964
                    (void (*)(id, SEL, int))[self methodForSelector: sel];
 
1965
 
 
1966
                  (*imp)(self, sel, v);
 
1967
                }
 
1968
            }
 
1969
            break;
 
1970
 
 
1971
          case _C_UINT:
 
1972
            {
 
1973
              unsigned int      v = [val unsignedIntValue];
 
1974
 
 
1975
              if (sel == 0)
 
1976
                {
 
1977
                  unsigned int *ptr = (unsigned int*)((char *)self + offset);
 
1978
 
 
1979
                  *ptr = v;
 
1980
                }
 
1981
              else
 
1982
                {
 
1983
                  void  (*imp)(id, SEL, unsigned int) =
 
1984
                    (void (*)(id, SEL, unsigned int))[self methodForSelector:
 
1985
                    sel];
 
1986
 
 
1987
                  (*imp)(self, sel, v);
 
1988
                }
 
1989
            }
 
1990
            break;
 
1991
 
 
1992
          case _C_LNG:
 
1993
            {
 
1994
              long      v = [val longValue];
 
1995
 
 
1996
              if (sel == 0)
 
1997
                {
 
1998
                  long *ptr = (long*)((char *)self + offset);
 
1999
 
 
2000
                  *ptr = v;
 
2001
                }
 
2002
              else
 
2003
                {
 
2004
                  void  (*imp)(id, SEL, long) =
 
2005
                    (void (*)(id, SEL, long))[self methodForSelector: sel];
 
2006
 
 
2007
                  (*imp)(self, sel, v);
 
2008
                }
 
2009
            }
 
2010
            break;
 
2011
 
 
2012
          case _C_ULNG:
 
2013
            {
 
2014
              unsigned long     v = [val unsignedLongValue];
 
2015
 
 
2016
              if (sel == 0)
 
2017
                {
 
2018
                  unsigned long *ptr = (unsigned long*)((char *)self + offset);
 
2019
 
 
2020
                  *ptr = v;
 
2021
                }
 
2022
              else
 
2023
                {
 
2024
                  void  (*imp)(id, SEL, unsigned long) =
 
2025
                    (void (*)(id, SEL, unsigned long))[self methodForSelector:
 
2026
                    sel];
 
2027
 
 
2028
                  (*imp)(self, sel, v);
 
2029
                }
 
2030
            }
 
2031
            break;
 
2032
 
 
2033
#ifdef  _C_LNG_LNG
 
2034
          case _C_LNG_LNG:
 
2035
            {
 
2036
              long long v = [val longLongValue];
 
2037
 
 
2038
              if (sel == 0)
 
2039
                {
 
2040
                  long long *ptr = (long long*)((char *)self + offset);
 
2041
 
 
2042
                  *ptr = v;
 
2043
                }
 
2044
              else
 
2045
                {
 
2046
                  void  (*imp)(id, SEL, long long) =
 
2047
                    (void (*)(id, SEL, long long))[self methodForSelector: sel];
 
2048
 
 
2049
                  (*imp)(self, sel, v);
 
2050
                }
 
2051
            }
 
2052
            break;
 
2053
#endif
 
2054
 
 
2055
#ifdef  _C_ULNG_LNG
 
2056
          case _C_ULNG_LNG:
 
2057
            {
 
2058
              unsigned long long        v = [val unsignedLongLongValue];
 
2059
 
 
2060
              if (sel == 0)
 
2061
                {
 
2062
                  unsigned long long *ptr = (unsigned long long*)((char*)self +
 
2063
                                                                  offset);
 
2064
 
 
2065
                  *ptr = v;
 
2066
                }
 
2067
              else
 
2068
                {
 
2069
                  void  (*imp)(id, SEL, unsigned long long) =
 
2070
                    (void (*)(id, SEL, unsigned long long))[self
 
2071
                    methodForSelector: sel];
 
2072
 
 
2073
                  (*imp)(self, sel, v);
 
2074
                }
 
2075
            }
 
2076
            break;
 
2077
#endif
 
2078
 
 
2079
          case _C_FLT:
 
2080
            {
 
2081
              float     v = [val floatValue];
 
2082
 
 
2083
              if (sel == 0)
 
2084
                {
 
2085
                  float *ptr = (float*)((char *)self + offset);
 
2086
 
 
2087
                  *ptr = v;
 
2088
                }
 
2089
              else
 
2090
                {
 
2091
                  void  (*imp)(id, SEL, float) =
 
2092
                    (void (*)(id, SEL, float))[self methodForSelector: sel];
 
2093
 
 
2094
                  (*imp)(self, sel, v);
 
2095
                }
 
2096
            }
 
2097
            break;
 
2098
 
 
2099
          case _C_DBL:
 
2100
            {
 
2101
              double    v = [val doubleValue];
 
2102
 
 
2103
              if (sel == 0)
 
2104
                {
 
2105
                  double *ptr = (double*)((char *)self + offset);
 
2106
 
 
2107
                  *ptr = v;
 
2108
                }
 
2109
              else
 
2110
                {
 
2111
                  void  (*imp)(id, SEL, double) =
 
2112
                    (void (*)(id, SEL, double))[self methodForSelector: sel];
 
2113
 
 
2114
                  (*imp)(self, sel, v);
 
2115
                }
 
2116
            }
 
2117
            break;
 
2118
 
 
2119
          default:
 
2120
            [NSException raise: NSInvalidArgumentException
 
2121
                        format: @"key-value set method has unsupported type"];
 
2122
        }
 
2123
    }
 
2124
}
 
2125
 
 
2126
 
 
2127
/** Returns an autoreleased array of subclasses of Class cls, including
 
2128
 *  subclasses of subclasses. */
 
2129
NSArray *GSObjCAllSubclassesOfClass(Class cls)
 
2130
{
 
2131
  if (!cls)
 
2132
    {
 
2133
      return nil;
 
2134
    }
 
2135
  else
 
2136
    {
 
2137
      Class aClass;
 
2138
      NSMutableArray *result = [[NSMutableArray alloc] init];
 
2139
 
 
2140
#ifdef GNU_RUNTIME
 
2141
      for (aClass = cls->subclass_list; aClass; aClass=aClass->sibling_class)
 
2142
        {
 
2143
          if (CLS_ISMETA(aClass))
 
2144
            continue;
 
2145
          [result addObject:aClass];
 
2146
          [result addObjectsFromArray: GSObjCAllSubclassesOfClass(aClass)];
 
2147
        }
 
2148
#else
 
2149
#warning not implemented for the NeXT_RUNTIME
 
2150
#endif
 
2151
      return AUTORELEASE(result);
 
2152
    }
 
2153
}
 
2154
 
 
2155
/** Returns an autoreleased array containing subclasses directly descendent of
 
2156
 *  Class cls. */
 
2157
NSArray *GSObjCDirectSubclassesOfClass(Class cls)
 
2158
{
 
2159
  if (!cls)
 
2160
    {
 
2161
      return nil;
 
2162
    }
 
2163
  else
 
2164
    {
 
2165
      NSMutableArray *result=[[NSMutableArray alloc] init];
 
2166
      Class aClass;
 
2167
 
 
2168
#ifdef GNU_RUNTIME
 
2169
      for (aClass = cls->subclass_list;aClass;aClass=aClass->sibling_class)
 
2170
        {
 
2171
          if (CLS_ISMETA(aClass))
 
2172
            continue;
 
2173
          [result addObject:aClass];
 
2174
        }
 
2175
#else
 
2176
#warning not implemented for the NeXT_RUNTIME
 
2177
#endif
 
2178
      return AUTORELEASE(result);
 
2179
    }
 
2180
}
 
2181
 
 
2182
void *
 
2183
GSAutoreleasedBuffer(unsigned size)
 
2184
{
 
2185
#if GS_WITH_GC
 
2186
  return GC_malloc(size);
 
2187
#else
 
2188
#ifdef ALIGN
 
2189
#undef ALIGN
 
2190
#endif
 
2191
#define ALIGN __alignof__(double)
 
2192
 
 
2193
  static Class  nsobject_class = 0;
 
2194
  static Class  autorelease_class;
 
2195
  static SEL    autorelease_sel;
 
2196
  static IMP    autorelease_imp;
 
2197
  static int    offset;
 
2198
  NSObject      *o;
 
2199
 
 
2200
  if (nsobject_class == 0)
 
2201
    {
 
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];
 
2207
    }
 
2208
  o = (NSObject*)NSAllocateObject(nsobject_class,
 
2209
    size + offset, NSDefaultMallocZone());
 
2210
  (*autorelease_imp)(autorelease_class, autorelease_sel, o);
 
2211
  return ((void*)&o[1]) + offset;
 
2212
#endif
 
2213
}
 
2214
 
 
2215
 
 
2216
 
 
2217
/* Getting a system error message on a variety of systems */
 
2218
#ifdef __MINGW__
 
2219
LPTSTR GetErrorMsg(DWORD msgId)
 
2220
{
 
2221
  LPVOID lpMsgBuf;
 
2222
 
 
2223
  FormatMessage(
 
2224
    FORMAT_MESSAGE_ALLOCATE_BUFFER |
 
2225
    FORMAT_MESSAGE_FROM_SYSTEM |
 
2226
    FORMAT_MESSAGE_IGNORE_INSERTS,
 
2227
    NULL, msgId,
 
2228
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
 
2229
    (LPTSTR)&lpMsgBuf, 0, NULL);
 
2230
 
 
2231
  return (LPTSTR)lpMsgBuf;
 
2232
}
 
2233
#else
 
2234
#ifndef HAVE_STRERROR
 
2235
const char *
 
2236
strerror(int eno)
 
2237
{
 
2238
  extern char  *sys_errlist[];
 
2239
  extern int    sys_nerr;
 
2240
 
 
2241
  if (eno < 0 || eno >= sys_nerr)
 
2242
    {
 
2243
      return("unknown error number");
 
2244
    }
 
2245
  return(sys_errlist[eno]);
 
2246
}
 
2247
#endif
 
2248
#endif /* __MINGW__ */
 
2249
 
 
2250
const char *
 
2251
GSLastErrorStr(long error_id)
 
2252
{
 
2253
#ifdef __MINGW__
 
2254
  return GetErrorMsg(GetLastError());
 
2255
#else
 
2256
  return strerror(error_id);
 
2257
#endif
 
2258
}
 
2259
 
 
2260
 
 
2261
 
 
2262
BOOL
 
2263
GSPrintf (FILE *fptr, NSString* format, ...)
 
2264
{
 
2265
  static Class                  stringClass = 0;
 
2266
  static NSStringEncoding       enc;
 
2267
  CREATE_AUTORELEASE_POOL(arp);
 
2268
  va_list       ap;
 
2269
  NSString      *message;
 
2270
  NSData        *data;
 
2271
  BOOL          ok = NO;
 
2272
 
 
2273
  if (stringClass == 0)
 
2274
    {
 
2275
      stringClass = [NSString class];
 
2276
      enc = [stringClass defaultCStringEncoding];
 
2277
    }
 
2278
  message = [stringClass allocWithZone: NSDefaultMallocZone()];
 
2279
  va_start (ap, format);
 
2280
  message = [message initWithFormat: format locale: nil arguments: ap];
 
2281
  va_end (ap);
 
2282
  data = [message dataUsingEncoding: enc];
 
2283
  if (data == nil)
 
2284
    {
 
2285
      data = [message dataUsingEncoding: NSUTF8StringEncoding];
 
2286
    }
 
2287
  RELEASE(message);
 
2288
 
 
2289
  if (data != nil)
 
2290
    {
 
2291
      unsigned int      length = [data length];
 
2292
 
 
2293
      if (length == 0 || fwrite([data bytes], 1, length, fptr) == length)
 
2294
        {
 
2295
          ok = YES;
 
2296
        }
 
2297
    }
 
2298
  RELEASE(arp);
 
2299
  return ok;
 
2300
}