| /* The implementation of class Object for Objective-C. |
| Copyright (C) 1993, 1994, 1995, 1997, 2002 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it |
| under the terms of the GNU General Public License as published by the |
| Free Software Foundation; either version 2, or (at your option) any |
| later version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
| License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING. If not, write to |
| the Free Software Foundation, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. */ |
| |
| /* As a special exception, if you link this library with files compiled |
| with GCC to produce an executable, this does not cause the resulting |
| executable to be covered by the GNU General Public License. This |
| exception does not however invalidate any other reasons why the |
| executable file might be covered by the GNU General Public License. */ |
| |
| #include <stdarg.h> |
| #include "objc/Object.h" |
| #include "objc/Protocol.h" |
| #include "objc/objc-api.h" |
| |
| extern int errno; |
| |
| #define MAX_CLASS_NAME_LEN 256 |
| |
| @implementation Object |
| |
| + initialize |
| { |
| return self; |
| } |
| |
| - init |
| { |
| return self; |
| } |
| |
| + new |
| { |
| return [[self alloc] init]; |
| } |
| |
| + alloc |
| { |
| return class_create_instance(self); |
| } |
| |
| - free |
| { |
| return object_dispose(self); |
| } |
| |
| - copy |
| { |
| return [[self shallowCopy] deepen]; |
| } |
| |
| - shallowCopy |
| { |
| return object_copy(self); |
| } |
| |
| - deepen |
| { |
| return self; |
| } |
| |
| - deepCopy |
| { |
| return [self copy]; |
| } |
| |
| - (Class)class |
| { |
| return object_get_class(self); |
| } |
| |
| - (Class)superClass |
| { |
| return object_get_super_class(self); |
| } |
| |
| - (MetaClass)metaClass |
| { |
| return object_get_meta_class(self); |
| } |
| |
| - (const char *)name |
| { |
| return object_get_class_name(self); |
| } |
| |
| - self |
| { |
| return self; |
| } |
| |
| - (unsigned int)hash |
| { |
| return (size_t)self; |
| } |
| |
| - (BOOL)isEqual:anObject |
| { |
| return self==anObject; |
| } |
| |
| - (int)compare:anotherObject; |
| { |
| if ([self isEqual:anotherObject]) |
| return 0; |
| // Ordering objects by their address is pretty useless, |
| // so subclasses should override this is some useful way. |
| else if (self > anotherObject) |
| return 1; |
| else |
| return -1; |
| } |
| |
| - (BOOL)isMetaClass |
| { |
| return NO; |
| } |
| |
| - (BOOL)isClass |
| { |
| return object_is_class(self); |
| } |
| |
| - (BOOL)isInstance |
| { |
| return object_is_instance(self); |
| } |
| |
| - (BOOL)isKindOf:(Class)aClassObject |
| { |
| Class class; |
| |
| for (class = self->isa; class!=Nil; class = class_get_super_class(class)) |
| if (class==aClassObject) |
| return YES; |
| return NO; |
| } |
| |
| - (BOOL)isMemberOf:(Class)aClassObject |
| { |
| return self->isa==aClassObject; |
| } |
| |
| - (BOOL)isKindOfClassNamed:(const char *)aClassName |
| { |
| Class class; |
| |
| if (aClassName!=NULL) |
| for (class = self->isa; class!=Nil; class = class_get_super_class(class)) |
| if (!strcmp(class_get_class_name(class), aClassName)) |
| return YES; |
| return NO; |
| } |
| |
| - (BOOL)isMemberOfClassNamed:(const char *)aClassName |
| { |
| return ((aClassName!=NULL) |
| &&!strcmp(class_get_class_name(self->isa), aClassName)); |
| } |
| |
| + (BOOL)instancesRespondTo:(SEL)aSel |
| { |
| return class_get_instance_method(self, aSel)!=METHOD_NULL; |
| } |
| |
| - (BOOL)respondsTo:(SEL)aSel |
| { |
| return ((object_is_instance(self) |
| ?class_get_instance_method(self->isa, aSel) |
| :class_get_class_method(self->isa, aSel))!=METHOD_NULL); |
| } |
| |
| + (IMP)instanceMethodFor:(SEL)aSel |
| { |
| return method_get_imp(class_get_instance_method(self, aSel)); |
| } |
| |
| // Indicates if the receiving class or instance conforms to the given protocol |
| // not usually overridden by subclasses |
| // |
| // Modified 9/5/94 to always search the class object's protocol list, rather |
| // than the meta class. |
| |
| + (BOOL) conformsTo: (Protocol*)aProtocol |
| { |
| size_t i; |
| struct objc_protocol_list* proto_list; |
| id parent; |
| |
| for (proto_list = ((Class)self)->protocols; |
| proto_list; proto_list = proto_list->next) |
| { |
| for (i=0; i < proto_list->count; i++) |
| { |
| if ([proto_list->list[i] conformsTo: aProtocol]) |
| return YES; |
| } |
| } |
| |
| if ((parent = [self superClass])) |
| return [parent conformsTo: aProtocol]; |
| else |
| return NO; |
| } |
| |
| - (BOOL) conformsTo: (Protocol*)aProtocol |
| { |
| return [[self class] conformsTo:aProtocol]; |
| } |
| |
| - (IMP)methodFor:(SEL)aSel |
| { |
| return (method_get_imp(object_is_instance(self) |
| ?class_get_instance_method(self->isa, aSel) |
| :class_get_class_method(self->isa, aSel))); |
| } |
| |
| + (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel |
| { |
| return ((struct objc_method_description *) |
| class_get_instance_method(self, aSel)); |
| } |
| |
| - (struct objc_method_description *)descriptionForMethod:(SEL)aSel |
| { |
| return ((struct objc_method_description *) |
| (object_is_instance(self) |
| ?class_get_instance_method(self->isa, aSel) |
| :class_get_class_method(self->isa, aSel))); |
| } |
| |
| - perform:(SEL)aSel |
| { |
| IMP msg = objc_msg_lookup(self, aSel); |
| if (!msg) |
| return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; |
| return (*msg)(self, aSel); |
| } |
| |
| - perform:(SEL)aSel with:anObject |
| { |
| IMP msg = objc_msg_lookup(self, aSel); |
| if (!msg) |
| return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; |
| return (*msg)(self, aSel, anObject); |
| } |
| |
| - perform:(SEL)aSel with:anObject1 with:anObject2 |
| { |
| IMP msg = objc_msg_lookup(self, aSel); |
| if (!msg) |
| return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; |
| return (*msg)(self, aSel, anObject1, anObject2); |
| } |
| |
| - (retval_t)forward:(SEL)aSel :(arglist_t)argFrame |
| { |
| (void) argFrame; /* UNUSED */ |
| return (retval_t)[self doesNotRecognize: aSel]; |
| } |
| |
| - (retval_t)performv:(SEL)aSel :(arglist_t)argFrame |
| { |
| return objc_msg_sendv(self, aSel, argFrame); |
| } |
| |
| + poseAs:(Class)aClassObject |
| { |
| return class_pose_as(self, aClassObject); |
| } |
| |
| - (Class)transmuteClassTo:(Class)aClassObject |
| { |
| if (object_is_instance(self)) |
| if (class_is_class(aClassObject)) |
| if (class_get_instance_size(aClassObject)==class_get_instance_size(isa)) |
| if ([self isKindOf:aClassObject]) |
| { |
| Class old_isa = isa; |
| isa = aClassObject; |
| return old_isa; |
| } |
| return nil; |
| } |
| |
| - subclassResponsibility:(SEL)aSel |
| { |
| return [self error:"subclass should override %s", sel_get_name(aSel)]; |
| } |
| |
| - notImplemented:(SEL)aSel |
| { |
| return [self error:"method %s not implemented", sel_get_name(aSel)]; |
| } |
| |
| - shouldNotImplement:(SEL)aSel |
| { |
| return [self error:"%s should not implement %s", |
| object_get_class_name(self), sel_get_name(aSel)]; |
| } |
| |
| - doesNotRecognize:(SEL)aSel |
| { |
| return [self error:"%s does not recognize %s", |
| object_get_class_name(self), sel_get_name(aSel)]; |
| } |
| |
| - error:(const char *)aString, ... |
| { |
| #define FMT "error: %s (%s)\n%s\n" |
| char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self)) |
| +((aString!=NULL)?strlen((char*)aString):0)+8)]; |
| va_list ap; |
| |
| sprintf(fmt, FMT, object_get_class_name(self), |
| object_is_instance(self)?"instance":"class", |
| (aString!=NULL)?aString:""); |
| va_start(ap, aString); |
| objc_verror(self, OBJC_ERR_UNKNOWN, fmt, ap); |
| va_end(ap); |
| return nil; |
| #undef FMT |
| } |
| |
| + (int)version |
| { |
| return class_get_version(self); |
| } |
| |
| + setVersion:(int)aVersion |
| { |
| class_set_version(self, aVersion); |
| return self; |
| } |
| |
| + (int)streamVersion: (TypedStream*)aStream |
| { |
| if (aStream->mode == OBJC_READONLY) |
| return objc_get_stream_class_version (aStream, self); |
| else |
| return class_get_version (self); |
| } |
| |
| // These are used to write or read the instance variables |
| // declared in this particular part of the object. Subclasses |
| // should extend these, by calling [super read/write: aStream] |
| // before doing their own archiving. These methods are private, in |
| // the sense that they should only be called from subclasses. |
| |
| - read: (TypedStream*)aStream |
| { |
| (void) aStream; /* UNUSED */ |
| // [super read: aStream]; |
| return self; |
| } |
| |
| - write: (TypedStream*)aStream |
| { |
| (void) aStream; /* UNUSED */ |
| // [super write: aStream]; |
| return self; |
| } |
| |
| - awake |
| { |
| // [super awake]; |
| return self; |
| } |
| |
| @end |