This is behavior.m in view mode; [Download] [Up]
/* Copyright (C) 1996 Ovidiu Predescu <ovidiu@bx.logicnet.ro> Mircea Oancea <mircea@jupiter.elcom.pub.ro> Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro> This file implements behaviors, "protocols with implementations", an original idea of Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>. This file is part of the FoundationExtensions library. This implementation works with GNU and NeXT runtimes. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* A Behavior can be seen as a "Protocol with an implementation" or a "Class without any instance variables". A key feature of behaviors is that they give a degree of multiple inheritance. The following function is a sneaky hack way that provides Behaviors without adding any new syntax to the Objective C language. Simply define a class with the methods you want in the behavior, then call this function with that class as the BEHAVIOR argument. This function should be called in CLASS's +initialize method. If you add several behaviors to a class, be aware that the order of the additions is significant. */ #include <extensions/objc-runtime.h> #include <extensions/NSException.h> #include <extensions/exceptions/GeneralExceptions.h> #include "common.h" static void class_add_methods_if_not_there (Class, Class); static struct objc_method *search_for_method_in_list (struct objc_method_list*, SEL); static BOOL class_is_kind_of (Class, Class); void class_add_behavior (Class class, Class behavior) { Class behavior_super_class; if (!CLS_ISCLASS (class) || !CLS_ISCLASS (behavior)) THROW ([[ObjcRuntimeException alloc] initWithFormat: @"Only classes must be passed to class_add_behavior"]); class_add_methods_if_not_there (class, behavior); class_add_methods_if_not_there (class_get_meta_class (class), class_get_meta_class (behavior)); behavior_super_class = class_get_super_class (behavior); if (!class_is_kind_of (class, behavior_super_class)) class_add_behavior (class, behavior_super_class); } static void class_add_methods_if_not_there (Class class, Class behavior) { static SEL initialize_sel = 0; struct objc_method_list *mlist; if (!initialize_sel) initialize_sel = sel_register_name ("initialize"); for (mlist = behavior->methods; mlist; mlist = mlist->method_next) { int i; struct objc_method_list *new_list = Malloc (sizeof (struct objc_method_list) + sizeof (struct objc_method[mlist->method_count - 1])); new_list->method_next = NULL; new_list->method_count = 0; for (i = 0; i < mlist->method_count; i++) { struct objc_method *behavior_method = &(mlist->method_list[i]); struct objc_method *class_method = search_for_method_in_list (class->methods, behavior_method->method_name); if (!class_method && !SEL_EQ (behavior_method->method_name, initialize_sel)) { /* As long as the method isn't defined in the CLASS, put the BEHAVIOR method in there. Thus, behavior methods override the superclasses' methods. */ new_list->method_list[new_list->method_count++] = *behavior_method; } } if (i) { new_list = Realloc (new_list, sizeof (struct objc_method_list) + sizeof (struct objc_method[new_list->method_count - 1])); class_addMethods (class, new_list); } else Free (new_list); } } /* Given a linked list of method and a method's name. Search for the named method's method structure. Return a pointer to the method's method structure if found. NULL otherwise. */ static struct objc_method * search_for_method_in_list (struct objc_method_list *mlist, SEL op) { if (!sel_is_mapped (op)) return NULL; /* If not found then we'll search the list. */ for (; mlist; mlist = mlist->method_next) { int i; /* Search the method list. */ for (i = 0; i < mlist->method_count; ++i) { struct objc_method *method = &mlist->method_list[i]; if (method->method_name) if (SEL_EQ (method->method_name, op)) return method; } } return NULL; } static BOOL class_is_kind_of (Class a, Class b) { for (; a; a = class_get_super_class (a)) if (a == b) return YES; return NO; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.