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