ftp.nice.ch/Attic/openStep/implementation/gnustep/sources/libFoundation.0.7.tgz#/libFoundation-0.7/FoundationExtensions/extensions/behavior.m

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.