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.