1/** Implementation of ObjC runtime additions for GNUStep
2   Copyright (C) 1995-2010 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 Lesser 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 Lesser General Public
24   License along with this library; if not, write to the Free
25   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26   Boston, MA 02111 USA.
27
28   <title>GSObjCRuntime function and macro reference</title>
29   $Date$ $Revision$
30   */
31
32#import "common.h"
33#ifndef NeXT_Foundation_LIBRARY
34#import "Foundation/NSArray.h"
35#import "Foundation/NSAutoreleasePool.h"
36#import "Foundation/NSData.h"
37#import "Foundation/NSDictionary.h"
38#import "Foundation/NSEnumerator.h"
39#import "Foundation/NSException.h"
40#import "Foundation/NSInvocation.h"
41#import "Foundation/NSLock.h"
42#import "Foundation/NSMethodSignature.h"
43#import "Foundation/NSNull.h"
44#import "Foundation/NSSet.h"
45#import "Foundation/NSValue.h"
46#endif
47#import "GNUstepBase/GSObjCRuntime.h"
48#import "GNUstepBase/NSObject+GNUstepBase.h"
49
50#import "../GSPrivate.h"
51
52#include <objc/Protocol.h>
53
54#include <stdio.h>
55#include <ctype.h>
56
57#ifndef NeXT_RUNTIME
58#include <pthread.h>
59#endif
60#ifdef __GNUSTEP_RUNTIME__
61extern struct objc_slot	*objc_get_slot(Class, SEL);
62#endif
63
64#ifdef NeXT_Foundation_LIBRARY
65@interface NSObject (MissingFromMacOSX)
66+ (IMP) methodForSelector: (SEL)aSelector;
67@end
68#endif
69
70#define BDBGPrintf(format, args...) \
71  do { if (behavior_debug) { fprintf(stderr, (format) , ## args); } } while (0)
72
73Class
74GSObjCClass(id obj)
75{
76  return object_getClass(obj);
77}
78Class GSObjCSuper(Class cls)
79{
80  return class_getSuperclass(cls);
81}
82BOOL
83GSObjCIsInstance(id obj)
84{
85  Class	c = object_getClass(obj);
86
87  if (c != Nil && class_isMetaClass(c) == NO)
88    return YES;
89  else
90    return NO;
91}
92BOOL
93GSObjCIsClass(Class cls)
94{
95  if (class_isMetaClass(object_getClass(cls)))
96    return YES;
97  else
98    return NO;
99}
100BOOL
101GSObjCIsKindOf(Class cls, Class other)
102{
103  while (cls != Nil)
104    {
105      if (cls == other)
106	{
107	  return YES;
108	}
109      cls = class_getSuperclass(cls);
110    }
111  return NO;
112}
113Class
114GSClassFromName(const char *name)
115{
116  return objc_lookUpClass(name);
117}
118const char *
119GSNameFromClass(Class cls)
120{
121  return class_getName(cls);
122}
123const char *
124GSClassNameFromObject(id obj)
125{
126  return class_getName(object_getClass(obj));
127}
128const char *
129GSNameFromSelector(SEL sel)
130{
131  return sel_getName(sel);
132}
133SEL
134GSSelectorFromName(const char *name)
135{
136  return sel_getUid(name);
137}
138
139#if defined (__GNU_LIBOBJC__) && (__GNU_LIBOBJC__ < 20110608)
140/* Don't use sel_registerTypedName() ... it's broken when first introduced
141 * into gcc (fails to correctly check for multiple registrations with same
142 * types but different layout info).
143 * Later versions of the runtime should be OK though.
144 * Hack - need to provide these function declarations
145 * for gcc 4.6 libobjc. They're called below, and they're declared
146 * in objc-api.h, but we're using runtime.h, so objc-api.h can't be imported.
147 */
148SEL sel_get_any_typed_uid(const char *name);
149SEL sel_get_typed_uid(const char *name, const char*);
150SEL sel_register_name(const char *name);
151SEL sel_register_typed_name(const char *name, const char*type);
152#endif
153
154SEL
155GSSelectorFromNameAndTypes(const char *name, const char *types)
156{
157#if NeXT_RUNTIME
158  return sel_getUid(name);
159#elif defined (__GNU_LIBOBJC__) && (__GNU_LIBOBJC__ >= 20110608)
160  return sel_registerTypedName(name, types);
161#elif defined (__GNUSTEP_RUNTIME__)
162  return sel_registerTypedName_np(name, types);
163#else
164extern SEL sel_get_any_typed_uid(const char*);
165extern SEL sel_get_typed_uid(const char*, const char*);
166extern SEL sel_register_name(const char*);
167extern SEL sel_register_typed_name(const char*, const char*);
168
169  if (name == 0)
170    {
171      return 0;
172    }
173  else
174    {
175      SEL s;
176
177      if (types == 0)
178	{
179	  s = sel_get_any_typed_uid(name);
180	}
181      else
182	{
183	  s = sel_get_typed_uid(name, types);
184	}
185      if (s == 0)
186	{
187	  if (types == 0)
188	    {
189	      s = sel_register_name(name);
190	    }
191	  else
192	    {
193	      s = sel_register_typed_name(name, types);
194	    }
195	}
196      return s;
197    }
198#endif
199}
200
201const char *
202GSTypesFromSelector(SEL sel)
203{
204#if NeXT_RUNTIME
205  return 0;
206#elif defined (__GNU_LIBOBJC__)
207  return sel_getTypeEncoding(sel);
208#elif defined (__GNUSTEP_RUNTIME__)
209  return sel_getType_np(sel);
210#else
211  if (sel == 0)
212    {
213      return 0;
214    }
215  else
216    {
217      return sel_get_type(sel);
218    }
219#endif
220}
221
222void
223GSFlushMethodCacheForClass (Class cls)
224{
225  return;
226}
227int
228GSObjCVersion(Class cls)
229{
230  return class_getVersion(cls);
231}
232
233
234/**
235 * This function is used to locate information about the instance
236 * variable of obj called name.  It returns YES if the variable
237 * was found, NO otherwise.  If it returns YES, then the values
238 * pointed to by type, size, and offset will be set (except where
239 * they are null pointers).
240 */
241BOOL
242GSObjCFindVariable(id obj, const char *name,
243  const char **type, unsigned int *size, int *offset)
244{
245  Class		class = object_getClass(obj);
246  Ivar		ivar = class_getInstanceVariable(class, name);
247
248  if (ivar == 0)
249    {
250      return NO;
251    }
252  else
253    {
254      const char	*enc = ivar_getTypeEncoding(ivar);
255
256      if (type != 0)
257	{
258	  *type = enc;
259	}
260      if (size != 0)
261	{
262	  NSUInteger	s;
263	  NSUInteger	a;
264
265	  NSGetSizeAndAlignment(enc, &s, &a);
266	  *size = s;
267	}
268      if (offset != 0)
269	{
270	  *offset = ivar_getOffset(ivar);
271	}
272      return YES;
273    }
274}
275
276/**
277 * This method returns an array listing the names of all the
278 * instance methods available to obj, whether they
279 * belong to the class of obj or one of its superclasses.<br />
280 * If obj is a class, this returns the class methods.<br />
281 * Returns nil if obj is nil.
282 */
283NSArray *
284GSObjCMethodNames(id obj, BOOL recurse)
285{
286  NSMutableSet	*set;
287  NSArray	*array;
288  Class		 class;
289
290  if (obj == nil)
291    {
292      return nil;
293    }
294  /*
295   * Add names to a set so methods declared in superclasses
296   * and then overridden do not appear more than once.
297   */
298  set = [[NSMutableSet alloc] initWithCapacity: 32];
299
300  class = object_getClass(obj);
301
302  while (class != Nil)
303    {
304      unsigned	count;
305      Method	*meth = class_copyMethodList(class, &count);
306
307      while (count-- > 0)
308	{
309	  NSString	*name;
310
311	  name = [[NSString alloc] initWithFormat: @"%s",
312	    sel_getName(method_getName(meth[count]))];
313	  [set addObject: name];
314	  [name release];
315	}
316      if (meth != NULL)
317	{
318          free(meth);
319        }
320      if (NO == recurse)
321	{
322	  break;
323	}
324      class = class_getSuperclass(class);
325    }
326
327  array = [set allObjects];
328  RELEASE(set);
329  return array;
330}
331
332/**
333 * This method returns an array listing the names of all the
334 * instance variables present in the instance obj, whether they
335 * belong to the class of obj or one of its superclasses.<br />
336 * Returns nil if obj is nil.
337 */
338NSArray *
339GSObjCVariableNames(id obj, BOOL recurse)
340{
341  NSMutableSet	*set;
342  NSArray	*array;
343  Class		 class;
344
345  if (obj == nil)
346    {
347      return nil;
348    }
349  /*
350   * Add names to a set so methods declared in superclasses
351   * and then overridden do not appear more than once.
352   */
353  set = [[NSMutableSet alloc] initWithCapacity: 32];
354
355  class = object_getClass(obj);
356
357  while (class != Nil)
358    {
359      unsigned	count;
360      Ivar	*ivar = class_copyIvarList(class, &count);
361
362      while (count-- > 0)
363	{
364	  NSString	*name;
365
366	  name = [[NSString alloc] initWithFormat: @"%s",
367	    ivar_getName(ivar[count])];
368	  [set addObject: name];
369	  [name release];
370	}
371      if (ivar != NULL)
372	{
373          free(ivar);
374	}
375      if (NO == recurse)
376	{
377	  break;
378	}
379      class = class_getSuperclass(class);
380    }
381
382  array = [set allObjects];
383  RELEASE(set);
384  return array;
385}
386
387/**
388 * Gets the value from an instance variable in obj<br />
389 * This function performs no checking ... you should use it only where
390 * you are providing information from a call to GSObjCFindVariable()
391 * and you know that the data area provided is the correct size.
392 */
393void
394GSObjCGetVariable(id obj, int offset, unsigned int size, void *data)
395{
396  memcpy(data, ((void*)obj) + offset, size);
397}
398
399/**
400 * Sets the value in an instance variable in obj<br />
401 * This function performs no checking ... you should use it only where
402 * you are providing information from a call to GSObjCFindVariable()
403 * and you know that the data area provided is the correct size.
404 */
405void
406GSObjCSetVariable(id obj, int offset, unsigned int size, const void *data)
407{
408  memcpy(((void*)obj) + offset, data, size);
409}
410
411GS_EXPORT unsigned int
412GSClassList(Class *buffer, unsigned int max, BOOL clearCache)
413{
414  int num;
415
416  if (buffer != NULL)
417    {
418      memset(buffer, 0, sizeof(Class) * (max + 1));
419    }
420
421  num = objc_getClassList(buffer, max);
422  num = (num < 0) ? 0 : num;
423  return num;
424}
425
426/** references:
427http://www.macdevcenter.com/pub/a/mac/2002/05/31/runtime_parttwo.html?page=1
428http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/9objc_runtime_reference/chapter_5_section_1.html
429http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/9objc_runtime_reference/chapter_5_section_21.html
430ObjcRuntimeUtilities.m by Nicola Pero
431**/
432
433/**
434 * <p>Create a Class structure for use by the ObjectiveC runtime and return
435 * an NSValue object pointing to it.  The class will not be added to the
436 * runtime (you must do that later using the GSObjCAddClasses() function).
437 * </p>
438 * <p>The iVars dictionary lists the instance variable names and their types.
439 * </p>
440 */
441NSValue *
442GSObjCMakeClass(NSString *name, NSString *superName, NSDictionary *iVars)
443{
444  Class		newClass;
445  Class		classSuperClass;
446  const char	*classNameCString;
447
448  NSCAssert(name, @"no name");
449  NSCAssert(superName, @"no superName");
450
451  classSuperClass = NSClassFromString(superName);
452
453  NSCAssert1(classSuperClass, @"No class named %@",superName);
454  NSCAssert1(!NSClassFromString(name), @"A class %@ already exists", name);
455
456  classNameCString = [name UTF8String];
457  newClass = objc_allocateClassPair(classSuperClass, classNameCString, 0);
458  if ([iVars count] > 0)
459    {
460      NSEnumerator	*enumerator = [iVars keyEnumerator];
461      NSString		*key;
462
463      while ((key = [enumerator nextObject]) != nil)
464        {
465          const	char	*iVarName = [key UTF8String];
466          const char	*iVarType = [[iVars objectForKey: key] UTF8String];
467	  uint8_t	iVarAlign = 0;
468	  size_t	iVarSize;
469	  NSUInteger	s;
470	  NSUInteger	a;
471
472	  NSGetSizeAndAlignment(iVarType, &s, &a);
473	  // Convert size to number of bitshifts needed for alignment.
474	  iVarSize = 1;
475	  while (iVarSize < s)
476	    {
477	      iVarSize <<= 1;
478	      iVarAlign++;
479	    }
480	  // Record actual size
481	  iVarSize = s;
482	  if (NO
483	    == class_addIvar(newClass, iVarName, iVarSize, iVarAlign, iVarType))
484	    {
485	      NSLog(@"Error adding ivar '%s' of type '%s'", iVarName, iVarType);
486	    }
487	}
488    }
489
490  return [NSValue valueWithPointer: newClass];
491}
492
493/**
494 * The classes argument is an array of NSValue objects containing pointers
495 * to classes previously created by the GSObjCMakeClass() function.
496 */
497void
498GSObjCAddClasses(NSArray *classes)
499{
500  NSUInteger	numClasses = [classes count];
501  NSUInteger	i;
502
503  for (i = 0; i < numClasses; i++)
504    {
505      objc_registerClassPair((Class)[[classes objectAtIndex: i] pointerValue]);
506    }
507}
508
509
510
511static BOOL behavior_debug = NO;
512
513BOOL
514GSObjCBehaviorDebug(int setget)
515{
516  BOOL	old = behavior_debug;
517
518  if (setget == 1)
519    {
520      behavior_debug = YES;
521    }
522  else if (setget == 0)
523    {
524      behavior_debug = NO;
525    }
526  return old;
527}
528
529void
530GSObjCAddMethods(Class cls, Method *list, BOOL replace)
531{
532  unsigned int	index = 0;
533  char		c;
534  Method	m;
535
536  if (cls == 0 || list == 0)
537    {
538      return;
539    }
540  c = class_isMetaClass(cls) ? '+' : '-';
541
542  while ((m = list[index++]) != NULL)
543    {
544      SEL		n = method_getName(m);
545      IMP		i = method_getImplementation(m);
546      const char	*t = method_getTypeEncoding(m);
547
548      /* This will override a superclass method but will not replace a
549       * method which already exists in the class itsself.
550       */
551      if (YES == class_addMethod(cls, n, i, t))
552	{
553          BDBGPrintf("    added %c%s\n", c, sel_getName(n));
554	}
555      else if (YES == replace)
556	{
557	  /* If we want to replace an existing implemetation ...
558	   */
559	  method_setImplementation(class_getInstanceMethod(cls, n), i);
560          BDBGPrintf("    replaced %c%s\n", c, sel_getName(n));
561	}
562      else
563	{
564          BDBGPrintf("    skipped %c%s\n", c, sel_getName(n));
565	}
566    }
567}
568
569GSMethod
570GSGetMethod(Class cls, SEL sel,
571  BOOL searchInstanceMethods,
572  BOOL searchSuperClasses)
573{
574  if (cls == 0 || sel == 0)
575    {
576      return 0;
577    }
578
579  if (searchSuperClasses == NO)
580    {
581      unsigned int	count;
582      Method		method = NULL;
583      Method		*methods;
584
585      if (searchInstanceMethods == NO)
586	{
587	  methods = class_copyMethodList(object_getClass(cls), &count);
588	}
589      else
590	{
591	  methods = class_copyMethodList(cls, &count);
592	}
593      if (methods != NULL)
594	{
595	  unsigned int	index = 0;
596
597	  while ((method = methods[index++]) != NULL)
598	    {
599	      if (sel_isEqual(sel, method_getName(method)))
600		{
601		  break;
602		}
603	    }
604	  free(methods);
605	}
606      return method;
607    }
608  else
609    {
610      if (searchInstanceMethods == NO)
611	{
612	  return class_getClassMethod(cls, sel);
613	}
614      else
615	{
616	  return class_getInstanceMethod(cls, sel);
617	}
618    }
619}
620
621
622GS_EXPORT const char *
623GSSkipTypeQualifierAndLayoutInfo(const char *types)
624{
625  while (*types == '+'
626    || *types == '-'
627    || *types == _C_CONST
628    || *types == _C_IN
629    || *types == _C_INOUT
630    || *types == _C_OUT
631    || *types == _C_BYCOPY
632    || *types == _C_BYREF
633    || *types == _C_ONEWAY
634    || *types == _C_GCINVISIBLE
635    || isdigit ((unsigned char) *types))
636    {
637      types++;
638    }
639
640  return types;
641}
642
643/* See header for documentation. */
644GS_EXPORT BOOL
645GSSelectorTypesMatch(const char *types1, const char *types2)
646{
647  if (! types1 || ! types2)
648    {
649      return NO;        // Nul pointers never match
650    }
651  if (types1 == types2)
652    {
653      return YES;
654    }
655  while (*types1 && *types2)
656    {
657      types1 = GSSkipTypeQualifierAndLayoutInfo (types1);
658      types2 = GSSkipTypeQualifierAndLayoutInfo (types2);
659
660      /* Reached the end of the selector.  */
661      if (! *types1 && ! *types2)
662        {
663          return YES;
664        }
665
666      /* Ignore structure name yet compare layout.  */
667      if (*types1 == '{' && *types2 == '{')
668	{
669	  while (*types1 != '=' && *types1 != '}')
670            {
671              types1++;
672            }
673	  while (*types2 != '=' && *types2 != '}')
674            {
675              types2++;
676            }
677	}
678
679      if (*types1 != *types2)
680        {
681          return NO;
682        }
683      types1++;
684      types2++;
685    }
686
687  types1 = GSSkipTypeQualifierAndLayoutInfo (types1);
688  types2 = GSSkipTypeQualifierAndLayoutInfo (types2);
689
690  return (! *types1 && ! *types2) ? YES : NO;
691}
692
693/* See header for documentation. */
694GSIVar
695GSCGetInstanceVariableDefinition(Class cls, const char *name)
696{
697  return class_getInstanceVariable(cls, name);
698}
699
700GSIVar
701GSObjCGetInstanceVariableDefinition(Class cls, NSString *name)
702{
703  return class_getInstanceVariable(cls, [name UTF8String]);
704}
705
706
707static inline unsigned int
708gs_string_hash(const char *s)
709{
710  unsigned int val = 0;
711  while (*s != 0)
712    {
713      val = (val << 5) + val + *s++;
714    }
715  return val;
716}
717
718#define GSI_MAP_HAS_VALUE 1
719#define GSI_MAP_RETAIN_KEY(M, X)
720#define GSI_MAP_RETAIN_VAL(M, X)
721#define GSI_MAP_RELEASE_KEY(M, X)
722#define GSI_MAP_RELEASE_VAL(M, X)
723#define GSI_MAP_HASH(M, X)    (gs_string_hash(X.ptr))
724#define GSI_MAP_EQUAL(M, X,Y) (strcmp(X.ptr, Y.ptr) == 0)
725#define GSI_MAP_NOCLEAN 1
726
727#define GSI_MAP_KTYPES GSUNION_PTR
728#define GSI_MAP_VTYPES GSUNION_PTR
729
730#include "GNUstepBase/GSIMap.h"
731#include <pthread.h>
732
733static GSIMapTable_t protocol_by_name;
734static BOOL protocol_by_name_init = NO;
735static pthread_mutex_t protocol_by_name_lock = PTHREAD_MUTEX_INITIALIZER;
736
737/* Not sure about the semantics of inlining
738   functions with static variables.  */
739static void
740gs_init_protocol_lock(void)
741{
742  pthread_mutex_lock(&protocol_by_name_lock);
743  if (protocol_by_name_init == NO)
744  	{
745	  GSIMapInitWithZoneAndCapacity (&protocol_by_name,
746					 NSDefaultMallocZone(),
747					 128);
748	  protocol_by_name_init = YES;
749	}
750  pthread_mutex_unlock(&protocol_by_name_lock);
751}
752
753void
754GSRegisterProtocol(Protocol *proto)
755{
756  if (protocol_by_name_init == NO)
757    {
758      gs_init_protocol_lock();
759    }
760
761  if (proto != nil)
762    {
763      GSIMapNode node;
764
765      pthread_mutex_lock(&protocol_by_name_lock);
766      node = GSIMapNodeForKey(&protocol_by_name,
767	(GSIMapKey)protocol_getName(proto));
768      if (node == 0)
769	{
770	  GSIMapAddPairNoRetain(&protocol_by_name,
771	    (GSIMapKey)(void*)protocol_getName(proto),
772	    (GSIMapVal)(void*)proto);
773	}
774      pthread_mutex_unlock(&protocol_by_name_lock);
775    }
776}
777
778Protocol *
779GSProtocolFromName(const char *name)
780{
781  GSIMapNode node;
782  Protocol *p;
783
784  if (protocol_by_name_init == NO)
785    {
786      gs_init_protocol_lock();
787    }
788
789  node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
790  if (node)
791    {
792      p = node->value.ptr;
793    }
794  else
795    {
796      pthread_mutex_lock(&protocol_by_name_lock);
797      node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
798
799      if (node)
800	{
801	  p = node->value.ptr;
802	}
803      else
804	{
805	  p = objc_getProtocol(name);
806	  if (p)
807	    {
808	      /* Use the protocol's name to save us from allocating
809		 a copy of the parameter 'name'.  */
810	      GSIMapAddPairNoRetain(&protocol_by_name,
811	        (GSIMapKey)(void*)protocol_getName(p),
812		(GSIMapVal)(void*)p);
813	    }
814	}
815      pthread_mutex_unlock(&protocol_by_name_lock);
816
817    }
818
819  return p;
820}
821
822struct objc_method_description
823GSProtocolGetMethodDescriptionRecursive(Protocol *aProtocol, SEL aSel, BOOL isRequired, BOOL isInstance)
824{
825  struct objc_method_description desc;
826
827  desc = protocol_getMethodDescription(aProtocol, aSel, isRequired, isInstance);
828  if (desc.name == NULL && desc.types == NULL)
829    {
830      Protocol **list;
831      unsigned int count;
832
833      list = protocol_copyProtocolList(aProtocol, &count);
834      if (list != NULL)
835        {
836          unsigned int i;
837
838          for (i = 0; i < count; i++)
839            {
840              desc = GSProtocolGetMethodDescriptionRecursive(list[i],
841                aSel, isRequired, isInstance);
842              if (desc.name != NULL || desc.types != NULL)
843                {
844                  break;
845                }
846            }
847          free(list);
848        }
849    }
850
851  return desc;
852}
853
854void
855GSObjCAddClassBehavior(Class receiver, Class behavior)
856{
857  unsigned int	count;
858  Method	*methods;
859  Class behavior_super_class = class_getSuperclass(behavior);
860
861  if (YES == class_isMetaClass(receiver))
862    {
863      fprintf(stderr, "Trying to add behavior (%s) to meta class (%s)\n",
864	class_getName(behavior), class_getName(receiver));
865      abort();
866    }
867  if (YES == class_isMetaClass(behavior))
868    {
869      fprintf(stderr, "Trying to add meta class as behavior (%s) to (%s)\n",
870	class_getName(behavior), class_getName(receiver));
871      abort();
872    }
873  if (class_getInstanceSize(receiver) < class_getInstanceSize(behavior))
874    {
875      const char *b = class_getName(behavior);
876      const char *r = class_getName(receiver);
877
878#ifdef NeXT_Foundation_LIBRARY
879      fprintf(stderr, "Trying to add behavior (%s) with instance "
880	"size larger than class (%s)\n", b, r);
881      abort();
882#else
883      /* As a special case we allow adding GSString/GSCString to the
884       * constant string class ... since we know the base library
885       * takes care not to access non-existent instance variables.
886       */
887      if ((strcmp(b, "GSCString") && strcmp(b, "GSString"))
888        || (strcmp(r, "NSConstantString") && strcmp(r, "NXConstantString")))
889	{
890	  fprintf(stderr, "Trying to add behavior (%s) with instance "
891	    "size larger than class (%s)\n", b, r);
892          abort();
893	}
894#endif
895    }
896
897  BDBGPrintf("Adding behavior to class %s\n", class_getName(receiver));
898
899  /* Add instance methods */
900  methods = class_copyMethodList(behavior, &count);
901  BDBGPrintf("  instance methods from %s %u\n", class_getName(behavior), count);
902  if (methods == NULL)
903    {
904      BDBGPrintf("    none.\n");
905    }
906  else
907    {
908      GSObjCAddMethods (receiver, methods, NO);
909      free(methods);
910    }
911
912  /* Add class methods */
913  methods = class_copyMethodList(object_getClass(behavior), &count);
914  BDBGPrintf("  class methods from %s %u\n", class_getName(behavior), count);
915  if (methods == NULL)
916    {
917      BDBGPrintf("    none.\n");
918    }
919  else
920    {
921      GSObjCAddMethods (object_getClass(receiver), methods, NO);
922      free(methods);
923    }
924
925  /* Add behavior's superclass, if not already there. */
926  if (!GSObjCIsKindOf(receiver, behavior_super_class))
927    {
928      GSObjCAddClassBehavior (receiver, behavior_super_class);
929    }
930  GSFlushMethodCacheForClass (receiver);
931}
932
933void
934GSObjCAddClassOverride(Class receiver, Class override)
935{
936  unsigned int	count;
937  Method	*methods;
938
939  if (YES == class_isMetaClass(receiver))
940    {
941      fprintf(stderr, "Trying to add override (%s) to meta class (%s)\n",
942	class_getName(override), class_getName(receiver));
943      abort();
944    }
945  if (YES == class_isMetaClass(override))
946    {
947      fprintf(stderr, "Trying to add meta class as override (%s) to (%s)\n",
948	class_getName(override), class_getName(receiver));
949      abort();
950    }
951  if (class_getInstanceSize(receiver) < class_getInstanceSize(override))
952    {
953      fprintf(stderr, "Trying to add override (%s) with instance "
954	"size larger than class (%s)\n",
955	class_getName(override), class_getName(receiver));
956      abort();
957    }
958
959  BDBGPrintf("Adding override to class %s\n", class_getName(receiver));
960
961  /* Add instance methods */
962  methods = class_copyMethodList(override, &count);
963  BDBGPrintf("  instance methods from %s %u\n", class_getName(override), count);
964  if (methods == NULL)
965    {
966      BDBGPrintf("    none.\n");
967    }
968  else
969    {
970      GSObjCAddMethods (receiver, methods, YES);
971      free(methods);
972    }
973
974  /* Add class methods */
975  methods = class_copyMethodList(object_getClass(override), &count);
976  BDBGPrintf("  class methods from %s %u\n", class_getName(override), count);
977  if (methods == NULL)
978    {
979      BDBGPrintf("    none.\n");
980    }
981  else
982    {
983      GSObjCAddMethods (object_getClass(receiver), methods, YES);
984      free(methods);
985    }
986  GSFlushMethodCacheForClass (receiver);
987}
988
989
990
991
992#ifndef NeXT_Foundation_LIBRARY
993#import	"Foundation/NSValue.h"
994#import	"Foundation/NSKeyValueCoding.h"
995#endif
996
997
998/**
999 * This is used internally by the key-value coding methods, to get a
1000 * value from an object either via an accessor method (if sel is
1001 * supplied), or via direct access (if type, size, and offset are
1002 * supplied).<br />
1003 * Automatic conversion between NSNumber and C scalar types is performed.<br />
1004 * If type is null and can't be determined from the selector, the
1005 * [NSObject-handleQueryWithUnboundKey:] method is called to try
1006 * to get a value.
1007 */
1008id
1009GSObjCGetVal(NSObject *self, const char *key, SEL sel,
1010	       const char *type, unsigned size, int offset)
1011{
1012  NSMethodSignature	*sig = nil;
1013
1014  if (sel != 0)
1015    {
1016      sig = [self methodSignatureForSelector: sel];
1017      if ([sig numberOfArguments] != 2)
1018	{
1019	  [NSException raise: NSInvalidArgumentException
1020		      format: @"key-value get method has wrong number of args"];
1021	}
1022      type = [sig methodReturnType];
1023    }
1024  if (type == NULL)
1025    {
1026      return [self valueForUndefinedKey: [NSString stringWithUTF8String: key]];
1027    }
1028  else
1029    {
1030      id	val = nil;
1031
1032      switch (*type)
1033	{
1034	  case _C_ID:
1035	  case _C_CLASS:
1036	    {
1037	      id	v;
1038
1039	      if (sel == 0)
1040		{
1041		  v = *(id *)((char *)self + offset);
1042		}
1043	      else
1044		{
1045		  id	(*imp)(id, SEL) =
1046		    (id (*)(id, SEL))[self methodForSelector: sel];
1047
1048		  v = (*imp)(self, sel);
1049		}
1050	      val = v;
1051	    }
1052	    break;
1053
1054	  case _C_CHR:
1055	    {
1056	      signed char	v;
1057
1058	      if (sel == 0)
1059		{
1060		  v = *(char *)((char *)self + offset);
1061		}
1062	      else
1063		{
1064		  signed char	(*imp)(id, SEL) =
1065		    (signed char (*)(id, SEL))[self methodForSelector: sel];
1066
1067		  v = (*imp)(self, sel);
1068		}
1069	      val = [NSNumber numberWithChar: v];
1070	    }
1071	    break;
1072
1073	  case _C_UCHR:
1074	    {
1075	      unsigned char	v;
1076
1077	      if (sel == 0)
1078		{
1079		  v = *(unsigned char *)((char *)self + offset);
1080		}
1081	      else
1082		{
1083		  unsigned char	(*imp)(id, SEL) =
1084		    (unsigned char (*)(id, SEL))[self methodForSelector:
1085		    sel];
1086
1087		  v = (*imp)(self, sel);
1088		}
1089	      val = [NSNumber numberWithUnsignedChar: v];
1090	    }
1091	    break;
1092
1093#if __GNUC__ > 2 && defined(_C_BOOL)
1094          case _C_BOOL:
1095            {
1096              _Bool     v;
1097
1098              if (sel == 0)
1099                {
1100                  v = *(_Bool *)((char *)self + offset);
1101                }
1102              else
1103                {
1104                  _Bool (*imp)(id, SEL) =
1105                    (_Bool (*)(id, SEL))[self methodForSelector: sel];
1106
1107                  v = (*imp)(self, sel);
1108                }
1109              val = [NSNumber numberWithBool: (BOOL)v];
1110            }
1111            break;
1112#endif
1113
1114	  case _C_SHT:
1115	    {
1116	      short	v;
1117
1118	      if (sel == 0)
1119		{
1120		  v = *(short *)((char *)self + offset);
1121		}
1122	      else
1123		{
1124		  short	(*imp)(id, SEL) =
1125		    (short (*)(id, SEL))[self methodForSelector: sel];
1126
1127		  v = (*imp)(self, sel);
1128		}
1129	      val = [NSNumber numberWithShort: v];
1130	    }
1131	    break;
1132
1133	  case _C_USHT:
1134	    {
1135	      unsigned short	v;
1136
1137	      if (sel == 0)
1138		{
1139		  v = *(unsigned short *)((char *)self + offset);
1140		}
1141	      else
1142		{
1143		  unsigned short	(*imp)(id, SEL) =
1144		    (unsigned short (*)(id, SEL))[self methodForSelector:
1145		    sel];
1146
1147		  v = (*imp)(self, sel);
1148		}
1149	      val = [NSNumber numberWithUnsignedShort: v];
1150	    }
1151	    break;
1152
1153	  case _C_INT:
1154	    {
1155	      int	v;
1156
1157	      if (sel == 0)
1158		{
1159		  v = *(int *)((char *)self + offset);
1160		}
1161	      else
1162		{
1163		  int	(*imp)(id, SEL) =
1164		    (int (*)(id, SEL))[self methodForSelector: sel];
1165
1166		  v = (*imp)(self, sel);
1167		}
1168	      val = [NSNumber numberWithInt: v];
1169	    }
1170	    break;
1171
1172	  case _C_UINT:
1173	    {
1174	      unsigned int	v;
1175
1176	      if (sel == 0)
1177		{
1178		  v = *(unsigned int *)((char *)self + offset);
1179		}
1180	      else
1181		{
1182		  unsigned int	(*imp)(id, SEL) =
1183		    (unsigned int (*)(id, SEL))[self methodForSelector:
1184		    sel];
1185
1186		  v = (*imp)(self, sel);
1187		}
1188	      val = [NSNumber numberWithUnsignedInt: v];
1189	    }
1190	    break;
1191
1192	  case _C_LNG:
1193	    {
1194	      long	v;
1195
1196	      if (sel == 0)
1197		{
1198		  v = *(long *)((char *)self + offset);
1199		}
1200	      else
1201		{
1202		  long	(*imp)(id, SEL) =
1203		    (long (*)(id, SEL))[self methodForSelector: sel];
1204
1205		  v = (*imp)(self, sel);
1206		}
1207	      val = [NSNumber numberWithLong: v];
1208	    }
1209	    break;
1210
1211	  case _C_ULNG:
1212	    {
1213	      unsigned long	v;
1214
1215	      if (sel == 0)
1216		{
1217		  v = *(unsigned long *)((char *)self + offset);
1218		}
1219	      else
1220		{
1221		  unsigned long	(*imp)(id, SEL) =
1222		    (unsigned long (*)(id, SEL))[self methodForSelector:
1223		    sel];
1224
1225		  v = (*imp)(self, sel);
1226		}
1227	      val = [NSNumber numberWithUnsignedLong: v];
1228	    }
1229	    break;
1230
1231#ifdef	_C_LNG_LNG
1232	  case _C_LNG_LNG:
1233	    {
1234	      long long	v;
1235
1236	      if (sel == 0)
1237		{
1238		  v = *(long long *)((char *)self + offset);
1239		}
1240	      else
1241		{
1242		   long long	(*imp)(id, SEL) =
1243		    (long long (*)(id, SEL))[self methodForSelector: sel];
1244
1245		  v = (*imp)(self, sel);
1246		}
1247	      val = [NSNumber numberWithLongLong: v];
1248	    }
1249	    break;
1250#endif
1251
1252#ifdef	_C_ULNG_LNG
1253	  case _C_ULNG_LNG:
1254	    {
1255	      unsigned long long	v;
1256
1257	      if (sel == 0)
1258		{
1259		  v = *(unsigned long long *)((char *)self + offset);
1260		}
1261	      else
1262		{
1263		  unsigned long long	(*imp)(id, SEL) =
1264		    (unsigned long long (*)(id, SEL))[self
1265		    methodForSelector: sel];
1266
1267		  v = (*imp)(self, sel);
1268		}
1269	      val = [NSNumber numberWithUnsignedLongLong: v];
1270	    }
1271	    break;
1272#endif
1273
1274	  case _C_FLT:
1275	    {
1276	      float	v;
1277
1278	      if (sel == 0)
1279		{
1280		  v = *(float *)((char *)self + offset);
1281		}
1282	      else
1283		{
1284		  float	(*imp)(id, SEL) =
1285		    (float (*)(id, SEL))[self methodForSelector: sel];
1286
1287		  v = (*imp)(self, sel);
1288		}
1289	      val = [NSNumber numberWithFloat: v];
1290	    }
1291	    break;
1292
1293	  case _C_DBL:
1294	    {
1295	      double	v;
1296
1297	      if (sel == 0)
1298		{
1299		  v = *(double *)((char *)self + offset);
1300		}
1301	      else
1302		{
1303		  double	(*imp)(id, SEL) =
1304		    (double (*)(id, SEL))[self methodForSelector: sel];
1305
1306		  v = (*imp)(self, sel);
1307		}
1308	      val = [NSNumber numberWithDouble: v];
1309	    }
1310	    break;
1311
1312	  case _C_VOID:
1313            {
1314              void        (*imp)(id, SEL) =
1315                (void (*)(id, SEL))[self methodForSelector: sel];
1316
1317              (*imp)(self, sel);
1318            }
1319            val = nil;
1320            break;
1321
1322          case _C_STRUCT_B:
1323            if (GSSelectorTypesMatch(@encode(NSPoint), type))
1324              {
1325                NSPoint	v;
1326
1327                if (sel == 0)
1328                  {
1329                    memcpy((char*)&v, ((char *)self + offset), sizeof(v));
1330                  }
1331                else
1332                  {
1333                    NSPoint	(*imp)(id, SEL) =
1334                      (NSPoint (*)(id, SEL))[self methodForSelector: sel];
1335
1336                    v = (*imp)(self, sel);
1337                  }
1338                val = [NSValue valueWithPoint: v];
1339              }
1340            else if (GSSelectorTypesMatch(@encode(NSRange), type))
1341              {
1342                NSRange	v;
1343
1344                if (sel == 0)
1345                  {
1346                    memcpy((char*)&v, ((char *)self + offset), sizeof(v));
1347                  }
1348                else
1349                  {
1350                    NSRange	(*imp)(id, SEL) =
1351                      (NSRange (*)(id, SEL))[self methodForSelector: sel];
1352
1353                    v = (*imp)(self, sel);
1354                  }
1355                val = [NSValue valueWithRange: v];
1356              }
1357            else if (GSSelectorTypesMatch(@encode(NSRect), type))
1358              {
1359                NSRect	v;
1360
1361                if (sel == 0)
1362                  {
1363                    memcpy((char*)&v, ((char *)self + offset), sizeof(v));
1364                  }
1365                else
1366                  {
1367                    NSRect	(*imp)(id, SEL) =
1368                      (NSRect (*)(id, SEL))[self methodForSelector: sel];
1369
1370                    v = (*imp)(self, sel);
1371                  }
1372                val = [NSValue valueWithRect: v];
1373              }
1374            else if (GSSelectorTypesMatch(@encode(NSSize), type))
1375              {
1376                NSSize	v;
1377
1378                if (sel == 0)
1379                  {
1380                    memcpy((char*)&v, ((char *)self + offset), sizeof(v));
1381                  }
1382                else
1383                  {
1384                    NSSize	(*imp)(id, SEL) =
1385                      (NSSize (*)(id, SEL))[self methodForSelector: sel];
1386
1387                    v = (*imp)(self, sel);
1388                  }
1389                val = [NSValue valueWithSize: v];
1390              }
1391            else
1392              {
1393                if (sel == 0)
1394                  {
1395		    return [NSValue valueWithBytes: ((char *)self + offset)
1396					  objCType: type];
1397                  }
1398                else
1399                  {
1400		    NSInvocation	*inv;
1401		    size_t		retSize;
1402
1403		    inv = [NSInvocation invocationWithMethodSignature: sig];
1404		    [inv setSelector: sel];
1405		    [inv invokeWithTarget: self];
1406		    retSize = [sig methodReturnLength];
1407		    {
1408		      char ret[retSize];
1409
1410		      [inv getReturnValue: ret];
1411		      return [NSValue valueWithBytes: ret objCType: type];
1412		    }
1413                  }
1414              }
1415            break;
1416
1417	  default:
1418#ifdef __GNUSTEP_RUNTIME__
1419	    {
1420	      Class		cls;
1421	      struct objc_slot	*type_slot;
1422	      SEL		typed;
1423	      struct objc_slot	*slot;
1424
1425	      cls = [self class];
1426	      type_slot = objc_get_slot(cls, @selector(retain));
1427	      typed = GSSelectorFromNameAndTypes(sel_getName(sel), NULL);
1428	      slot = objc_get_slot(cls, typed);
1429	      if (strcmp(slot->types, type_slot->types) == 0)
1430		{
1431		  return slot->method(self, typed);
1432		}
1433	    }
1434#endif
1435	    val = [self valueForUndefinedKey:
1436	      [NSString stringWithUTF8String: key]];
1437	}
1438      return val;
1439    }
1440}
1441
1442/**
1443 * Calls GSObjCGetVal()
1444 */
1445id
1446GSObjCGetValue(NSObject *self, NSString *key, SEL sel,
1447	       const char *type, unsigned size, int offset)
1448{
1449  return GSObjCGetVal(self, [key UTF8String], sel, type, size, offset);
1450}
1451
1452/**
1453 * This is used internally by the key-value coding methods, to set a
1454 * value in an object either via an accessor method (if sel is
1455 * supplied), or via direct access (if type, size, and offset are
1456 * supplied).<br />
1457 * Automatic conversion between NSNumber and C scalar types is performed.<br />
1458 * If type is null and can't be determined from the selector, the
1459 * [NSObject-handleTakeValue:forUnboundKey:] method is called to try
1460 * to set a value.
1461 */
1462void
1463GSObjCSetVal(NSObject *self, const char *key, id val, SEL sel,
1464  const char *type, unsigned size, int offset)
1465{
1466  static NSNull		*null = nil;
1467  NSMethodSignature	*sig = nil;
1468
1469  if (null == nil)
1470    {
1471      null = [NSNull new];
1472    }
1473  if (sel != 0)
1474    {
1475      sig = [self methodSignatureForSelector: sel];
1476      if ([sig numberOfArguments] != 3)
1477	{
1478	  [NSException raise: NSInvalidArgumentException
1479		      format: @"key-value set method has wrong number of args"];
1480	}
1481      type = [sig getArgumentTypeAtIndex: 2];
1482    }
1483  if (type == NULL)
1484    {
1485      [self setValue: val forUndefinedKey:
1486	[NSString stringWithUTF8String: key]];
1487    }
1488  else if ((val == nil || val == null) && *type != _C_ID && *type != _C_CLASS)
1489    {
1490      [self setNilValueForKey: [NSString stringWithUTF8String: key]];
1491    }
1492  else
1493    {
1494      switch (*type)
1495	{
1496	  case _C_ID:
1497	  case _C_CLASS:
1498	    {
1499	      id	v = val;
1500
1501	      if (sel == 0)
1502		{
1503		  id *ptr = (id *)((char *)self + offset);
1504
1505		  ASSIGN(*ptr, v);
1506		}
1507	      else
1508		{
1509		  void	(*imp)(id, SEL, id) =
1510		    (void (*)(id, SEL, id))[self methodForSelector: sel];
1511
1512		  (*imp)(self, sel, val);
1513		}
1514	    }
1515	    break;
1516
1517	  case _C_CHR:
1518	    {
1519	      char	v = [val charValue];
1520
1521	      if (sel == 0)
1522		{
1523		  char *ptr = (char *)((char *)self + offset);
1524
1525		  *ptr = v;
1526		}
1527	      else
1528		{
1529		  void	(*imp)(id, SEL, char) =
1530		    (void (*)(id, SEL, char))[self methodForSelector: sel];
1531
1532		  (*imp)(self, sel, v);
1533		}
1534	    }
1535	    break;
1536
1537	  case _C_UCHR:
1538	    {
1539	      unsigned char	v = [val unsignedCharValue];
1540
1541	      if (sel == 0)
1542		{
1543		  unsigned char *ptr = (unsigned char*)((char *)self + offset);
1544
1545		  *ptr = v;
1546		}
1547	      else
1548		{
1549		  void	(*imp)(id, SEL, unsigned char) =
1550		    (void (*)(id, SEL, unsigned char))[self methodForSelector:
1551		    sel];
1552
1553		  (*imp)(self, sel, v);
1554		}
1555	    }
1556	    break;
1557
1558#if __GNUC__ > 2 && defined(_C_BOOL)
1559          case _C_BOOL:
1560            {
1561              _Bool     v = (_Bool)[val boolValue];
1562
1563              if (sel == 0)
1564                {
1565                  _Bool *ptr = (_Bool*)((char *)self + offset);
1566
1567                  *ptr = v;
1568                }
1569              else
1570                {
1571                  void  (*imp)(id, SEL, _Bool) =
1572                    (void (*)(id, SEL, _Bool))[self methodForSelector: sel];
1573
1574                  (*imp)(self, sel, v);
1575                }
1576            }
1577            break;
1578#endif
1579
1580	  case _C_SHT:
1581	    {
1582	      short	v = [val shortValue];
1583
1584	      if (sel == 0)
1585		{
1586		  short *ptr = (short*)((char *)self + offset);
1587
1588		  *ptr = v;
1589		}
1590	      else
1591		{
1592		  void	(*imp)(id, SEL, short) =
1593		    (void (*)(id, SEL, short))[self methodForSelector: sel];
1594
1595		  (*imp)(self, sel, v);
1596		}
1597	    }
1598	    break;
1599
1600	  case _C_USHT:
1601	    {
1602	      unsigned short	v = [val unsignedShortValue];
1603
1604	      if (sel == 0)
1605		{
1606		  unsigned short *ptr;
1607
1608		  ptr = (unsigned short*)((char *)self + offset);
1609		  *ptr = v;
1610		}
1611	      else
1612		{
1613		  void	(*imp)(id, SEL, unsigned short) =
1614		    (void (*)(id, SEL, unsigned short))[self methodForSelector:
1615		    sel];
1616
1617		  (*imp)(self, sel, v);
1618		}
1619	    }
1620	    break;
1621
1622	  case _C_INT:
1623	    {
1624	      int	v = [val intValue];
1625
1626	      if (sel == 0)
1627		{
1628		  int *ptr = (int*)((char *)self + offset);
1629
1630		  *ptr = v;
1631		}
1632	      else
1633		{
1634		  void	(*imp)(id, SEL, int) =
1635		    (void (*)(id, SEL, int))[self methodForSelector: sel];
1636
1637		  (*imp)(self, sel, v);
1638		}
1639	    }
1640	    break;
1641
1642	  case _C_UINT:
1643	    {
1644	      unsigned int	v = [val unsignedIntValue];
1645
1646	      if (sel == 0)
1647		{
1648		  unsigned int *ptr = (unsigned int*)((char *)self + offset);
1649
1650		  *ptr = v;
1651		}
1652	      else
1653		{
1654		  void	(*imp)(id, SEL, unsigned int) =
1655		    (void (*)(id, SEL, unsigned int))[self methodForSelector:
1656		    sel];
1657
1658		  (*imp)(self, sel, v);
1659		}
1660	    }
1661	    break;
1662
1663	  case _C_LNG:
1664	    {
1665	      long	v = [val longValue];
1666
1667	      if (sel == 0)
1668		{
1669		  long *ptr = (long*)((char *)self + offset);
1670
1671		  *ptr = v;
1672		}
1673	      else
1674		{
1675		  void	(*imp)(id, SEL, long) =
1676		    (void (*)(id, SEL, long))[self methodForSelector: sel];
1677
1678		  (*imp)(self, sel, v);
1679		}
1680	    }
1681	    break;
1682
1683	  case _C_ULNG:
1684	    {
1685	      unsigned long	v = [val unsignedLongValue];
1686
1687	      if (sel == 0)
1688		{
1689		  unsigned long *ptr = (unsigned long*)((char *)self + offset);
1690
1691		  *ptr = v;
1692		}
1693	      else
1694		{
1695		  void	(*imp)(id, SEL, unsigned long) =
1696		    (void (*)(id, SEL, unsigned long))[self methodForSelector:
1697		    sel];
1698
1699		  (*imp)(self, sel, v);
1700		}
1701	    }
1702	    break;
1703
1704#ifdef	_C_LNG_LNG
1705	  case _C_LNG_LNG:
1706	    {
1707	      long long	v = [val longLongValue];
1708
1709	      if (sel == 0)
1710		{
1711		  long long *ptr = (long long*)((char *)self + offset);
1712
1713		  *ptr = v;
1714		}
1715	      else
1716		{
1717		  void	(*imp)(id, SEL, long long) =
1718		    (void (*)(id, SEL, long long))[self methodForSelector: sel];
1719
1720		  (*imp)(self, sel, v);
1721		}
1722	    }
1723	    break;
1724#endif
1725
1726#ifdef	_C_ULNG_LNG
1727	  case _C_ULNG_LNG:
1728	    {
1729	      unsigned long long	v = [val unsignedLongLongValue];
1730
1731	      if (sel == 0)
1732		{
1733		  unsigned long long *ptr = (unsigned long long*)((char*)self +
1734								  offset);
1735
1736		  *ptr = v;
1737		}
1738	      else
1739		{
1740		  void	(*imp)(id, SEL, unsigned long long) =
1741		    (void (*)(id, SEL, unsigned long long))[self
1742		    methodForSelector: sel];
1743
1744		  (*imp)(self, sel, v);
1745		}
1746	    }
1747	    break;
1748#endif
1749
1750	  case _C_FLT:
1751	    {
1752	      float	v = [val floatValue];
1753
1754	      if (sel == 0)
1755		{
1756		  float *ptr = (float*)((char *)self + offset);
1757
1758		  *ptr = v;
1759		}
1760	      else
1761		{
1762		  void	(*imp)(id, SEL, float) =
1763		    (void (*)(id, SEL, float))[self methodForSelector: sel];
1764
1765		  (*imp)(self, sel, v);
1766		}
1767	    }
1768	    break;
1769
1770	  case _C_DBL:
1771	    {
1772	      double	v = [val doubleValue];
1773
1774	      if (sel == 0)
1775		{
1776		  double *ptr = (double*)((char *)self + offset);
1777
1778		  *ptr = v;
1779		}
1780	      else
1781		{
1782		  void	(*imp)(id, SEL, double) =
1783		    (void (*)(id, SEL, double))[self methodForSelector: sel];
1784
1785		  (*imp)(self, sel, v);
1786		}
1787	    }
1788	    break;
1789
1790          case _C_STRUCT_B:
1791            if (GSSelectorTypesMatch(@encode(NSPoint), type))
1792              {
1793                NSPoint	v = [val pointValue];
1794
1795                if (sel == 0)
1796                  {
1797                    NSPoint *ptr = (NSPoint*)((char *)self + offset);
1798
1799                    *ptr = v;
1800                  }
1801                else
1802                  {
1803                    void	(*imp)(id, SEL, NSPoint) =
1804                      (void (*)(id, SEL, NSPoint))[self methodForSelector: sel];
1805
1806                    (*imp)(self, sel, v);
1807                  }
1808              }
1809            else if (GSSelectorTypesMatch(@encode(NSRange), type))
1810              {
1811                NSRange	v = [val rangeValue];
1812
1813                if (sel == 0)
1814                  {
1815                    NSRange *ptr = (NSRange*)((char *)self + offset);
1816
1817                    *ptr = v;
1818                  }
1819                else
1820                  {
1821                    void	(*imp)(id, SEL, NSRange) =
1822                      (void (*)(id, SEL, NSRange))[self methodForSelector: sel];
1823
1824                    (*imp)(self, sel, v);
1825                  }
1826              }
1827            else if (GSSelectorTypesMatch(@encode(NSRect), type))
1828              {
1829                NSRect	v = [val rectValue];
1830
1831                if (sel == 0)
1832                  {
1833                    NSRect *ptr = (NSRect*)((char *)self + offset);
1834
1835                    *ptr = v;
1836                  }
1837                else
1838                  {
1839                    void	(*imp)(id, SEL, NSRect) =
1840                      (void (*)(id, SEL, NSRect))[self methodForSelector: sel];
1841
1842                    (*imp)(self, sel, v);
1843                  }
1844              }
1845            else if (GSSelectorTypesMatch(@encode(NSSize), type))
1846              {
1847                NSSize	v = [val sizeValue];
1848
1849                if (sel == 0)
1850                  {
1851                    NSSize *ptr = (NSSize*)((char *)self + offset);
1852
1853                    *ptr = v;
1854                  }
1855                else
1856                  {
1857                    void	(*imp)(id, SEL, NSSize) =
1858                      (void (*)(id, SEL, NSSize))[self methodForSelector: sel];
1859
1860                    (*imp)(self, sel, v);
1861                  }
1862              }
1863            else
1864              {
1865		NSUInteger	size;
1866
1867		NSGetSizeAndAlignment(type, &size, 0);
1868                if (sel == 0)
1869                  {
1870		    [val getValue: ((char *)self + offset)];
1871		  }
1872		else
1873		  {
1874		    NSInvocation	*inv;
1875		    char		buf[size];
1876
1877		    [val getValue: buf];
1878		    inv = [NSInvocation invocationWithMethodSignature: sig];
1879		    [inv setSelector: sel];
1880		    [inv setArgument: buf atIndex: 2];
1881		    [inv invokeWithTarget: self];
1882		  }
1883              }
1884            break;
1885
1886	  default:
1887            [self setValue: val forUndefinedKey:
1888	      [NSString stringWithUTF8String: key]];
1889	}
1890    }
1891}
1892
1893/**
1894 * Calls GSObjCSetVal()
1895 */
1896void
1897GSObjCSetValue(NSObject *self, NSString *key, id val, SEL sel,
1898	       const char *type, unsigned size, int offset)
1899{
1900  GSObjCSetVal(self, [key UTF8String], val, sel, type, size, offset);
1901}
1902
1903
1904/** Returns an autoreleased array of subclasses of Class cls, including
1905 *  subclasses of subclasses. */
1906NSArray *GSObjCAllSubclassesOfClass(Class cls)
1907{
1908  if (!cls)
1909    {
1910      return nil;
1911    }
1912  else
1913    {
1914      NSMutableArray	*result;
1915      Class		*classes;
1916      int 		numClasses;
1917      int		i;
1918
1919      numClasses = objc_getClassList(NULL, 0);
1920      classes = NSZoneMalloc(NSDefaultMallocZone(), numClasses*sizeof(Class));
1921      objc_getClassList(classes, numClasses);
1922      result = [NSMutableArray array];
1923      for (i = 0; i < numClasses; i++)
1924	{
1925	  Class	c = classes[i];
1926
1927	  if (YES == GSObjCIsKindOf(c, cls) && cls != c)
1928	    {
1929	      [result addObject: c];
1930	    }
1931	}
1932      NSZoneFree(NSDefaultMallocZone(), classes);
1933      return result;
1934    }
1935}
1936
1937/** Returns an autoreleased array containing subclasses directly descendent of
1938 *  Class cls. */
1939NSArray *GSObjCDirectSubclassesOfClass(Class cls)
1940{
1941  if (!cls)
1942    {
1943      return nil;
1944    }
1945  else
1946    {
1947      NSMutableArray	*result;
1948      Class		*classes;
1949      int 		numClasses;
1950      int		i;
1951
1952      numClasses = objc_getClassList(NULL, 0);
1953      classes = NSZoneMalloc(NSDefaultMallocZone(), numClasses*sizeof(Class));
1954      objc_getClassList(classes, numClasses);
1955      result = [NSMutableArray array];
1956      for (i = 0; i < numClasses; i++)
1957	{
1958	  Class	c = classes[i];
1959
1960	  if (class_getSuperclass(c) == cls)
1961	    {
1962	      [result addObject: c];
1963	    }
1964	}
1965      NSZoneFree(NSDefaultMallocZone(), classes);
1966      return result;
1967    }
1968}
1969
1970@interface 	GSAutoreleasedMemory : NSObject
1971@end
1972@implementation	GSAutoreleasedMemory
1973@end
1974
1975void *
1976GSAutoreleasedBuffer(unsigned size)
1977{
1978#ifdef ALIGN
1979#undef ALIGN
1980#endif
1981#define ALIGN __alignof__(double)
1982
1983  static Class	buffer_class = 0;
1984  static Class	autorelease_class;
1985  static SEL	autorelease_sel;
1986  static IMP	autorelease_imp;
1987  static int	instance_size;
1988  static int	offset;
1989  NSObject	*o;
1990
1991  if (buffer_class == 0)
1992    {
1993      buffer_class = [GSAutoreleasedMemory class];
1994      instance_size = class_getInstanceSize(buffer_class);
1995      offset = instance_size % ALIGN;
1996      autorelease_class = [NSAutoreleasePool class];
1997      autorelease_sel = @selector(addObject:);
1998      autorelease_imp = [autorelease_class methodForSelector: autorelease_sel];
1999    }
2000  o = (NSObject*)NSAllocateObject(buffer_class,
2001    size + offset, NSDefaultMallocZone());
2002  (*autorelease_imp)(autorelease_class, autorelease_sel, o);
2003  return ((void*)o) + instance_size + offset;
2004}
2005
2006
2007
2008/*
2009 * Deprecated function.
2010 */
2011const char *
2012GSLastErrorStr(long error_id)
2013{
2014  return [[[NSError _last] localizedDescription] cString];
2015}
2016
2017
2018
2019BOOL
2020GSPrintf (FILE *fptr, NSString* format, ...)
2021{
2022  static Class                  stringClass = 0;
2023  static NSStringEncoding       enc;
2024  va_list       		ap;
2025  NSAutoreleasePool		*arp = [NSAutoreleasePool new];
2026  NSString      		*message;
2027  NSData        		*data;
2028  BOOL          		ok = NO;
2029
2030  if (stringClass == 0)
2031    {
2032      stringClass = [NSString class];
2033      enc = [stringClass defaultCStringEncoding];
2034    }
2035  message = [stringClass allocWithZone: NSDefaultMallocZone()];
2036  va_start (ap, format);
2037  message = [message initWithFormat: format locale: nil arguments: ap];
2038  va_end (ap);
2039  data = [message dataUsingEncoding: enc];
2040  if (data == nil)
2041    {
2042      data = [message dataUsingEncoding: NSUTF8StringEncoding];
2043    }
2044  [message release];
2045
2046  if (data != nil)
2047    {
2048      unsigned int      length = [data length];
2049
2050      if (length == 0 || fwrite([data bytes], 1, length, fptr) == length)
2051        {
2052          ok = YES;
2053        }
2054    }
2055  [arp drain];
2056  return ok;
2057}
2058
2059#if     defined(GNUSTEP_BASE_LIBRARY)
2060
2061# ifndef	NDEBUG
2062#   define	AADD(c, o) GSDebugAllocationAdd(c, o)
2063#   define	AREM(c, o) GSDebugAllocationRemove(c, o)
2064# else
2065#   define	AADD(c, o)
2066#   define	AREM(c, o)
2067# endif
2068
2069#endif	/* defined(GNUSTEP_BASE_LIBRARY) */
2070
2071void
2072GSClassSwizzle(id instance, Class newClass)
2073{
2074  Class	oldClass = object_getClass(instance);
2075
2076  /* Only set if the old and new class differ
2077   */
2078  if (oldClass != newClass)
2079    {
2080      /* NB.  The call to object_setClass() may not work (eg for a libobjc2
2081       * 'small object', in which case the class is unchanged and we need
2082       * to allow for that.
2083       */
2084      AREM(oldClass, instance);
2085      object_setClass(instance, newClass);
2086      newClass = object_getClass(instance);
2087      AADD(newClass, instance);
2088    }
2089}
2090
2091