From 526ca6e88662ebf69d982acb29ca5663a85e3aeb Mon Sep 17 00:00:00 2001 From: mccallum Date: Fri, 24 Mar 1995 21:50:00 +0000 Subject: [PATCH] Initial revision git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@206 72102866-910b-0410-8b05-ffd578937521 --- Headers/gnustep/base/behavior.h | 43 ++++ Source/behavior.c | 351 ++++++++++++++++++++++++++++++++ Source/behavior.m | 351 ++++++++++++++++++++++++++++++++ Source/objects/behavior.h | 43 ++++ 4 files changed, 788 insertions(+) create mode 100644 Headers/gnustep/base/behavior.h create mode 100644 Source/behavior.c create mode 100644 Source/behavior.m create mode 100644 Source/objects/behavior.h diff --git a/Headers/gnustep/base/behavior.h b/Headers/gnustep/base/behavior.h new file mode 100644 index 000000000..79a1d7eac --- /dev/null +++ b/Headers/gnustep/base/behavior.h @@ -0,0 +1,43 @@ +/* Interface for behaviors for Obj-C, "for Protocols with implementations". + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: R. Andrew McCallum + Date: March 1995 + + This file is part of the GNU Objective C Class Library. + + 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; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __behavior_h_OBJECTS_INCLUDE +#define __behavior_h_OBJECTS_INCLUDE + +/* Call this method from CLASS's +initialize method to add a behavior + to CLASS. A "behavior" is like a protocol with an implementation. + + This functions adds to CLASS all the instance and factory methods + of BEHAVIOR as well as the instance and factory methods of + BEHAVIOR's superclasses (We stop adding super classes as soon as we + encounter a common ancestor.) CLASS and BEHAVIOR should share the + same instance variable layout. + + xxx We do not yet deal with Protocols, but we should. */ +void class_add_behavior (Class class, Class behavior); + + +/* Set to non-zero if you want debugging messages on stderr. */ +void set_behavior_debug(int i); + +#endif /* __behavior_h_OBJECTS_INCLUDE */ diff --git a/Source/behavior.c b/Source/behavior.c new file mode 100644 index 000000000..630fa1ef5 --- /dev/null +++ b/Source/behavior.c @@ -0,0 +1,351 @@ +/* Behaviors for Objective-C, "for Protocols with implementations". + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: R. Andrew McCallum + Date: March 1995 + + This file is part of the GNU Objective C Class Library. + + 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; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. + + xxx not necessarily on the "no instance vars". The behavior just has + to have the same layout as the class. + + 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 +#include +#include +#include +#include + +static int debug_behavior = 0; + +static Method_t search_for_method_in_list (MethodList_t list, SEL op); +static void __objc_send_initialize(Class class); +#if 0 +static void __objc_init_protocols (struct objc_protocol_list* protos); +static void __objc_class_add_protocols (Class class, + struct objc_protocol_list* protos); +#endif +static BOOL class_is_kind_of(Class self, Class class); +void class_add_methods_if_not_there(Class class, MethodList_t mlist); + +/* xxx consider using sendmsg.c:__objc_update_dispatch_table_for_class, + but, I think it will be slower than the current method. */ + +void +set_behavior_debug(int i) +{ + behavior_debug = i; +} + +void +class_add_behavior (Class class, Class behavior) +{ + Class behavior_super_class = class_get_super_class(behavior); + + assert(CLS_ISCLASS(class)); + assert(CLS_ISCLASS(behavior)); + + __objc_send_initialize(class); + __objc_send_initialize(behavior); + +#if 0 + /* xxx Do protocols */ + if (behavior->protocols) + { + /* xxx Make sure they are not already there before adding. */ + __objc_init_protocols (behavior->protocols); + __objc_class_add_protocols (class, behavior->protocols); + } +#endif + + /* Add instance methods */ + class_add_methods_if_not_there(class, + behavior->methods); + + /* Add class methods */ + class_add_methods_if_not_there(class->class_pointer, + behavior->class_pointer->methods); + + /* Add behavior's superclass, if not already there. */ + { + if (!class_is_kind_of(class, behavior_super_class)) + class_add_behavior(class, behavior_super_class); + } + + return; +} + +void +class_add_methods_if_not_there(Class class, MethodList_t mlist) +{ + static SEL initialize_sel = 0; + + if (!initialize_sel) + initialize_sel = sel_register_name ("initialize"); + + /* Add methods to class->dtable and class->methods */ + for ( ; mlist; mlist = mlist->method_next) + { + int counter; + MethodList_t new_list; + + counter = mlist->method_count - 1; + + /* xxx This is a little wasteful of memory, since not necessarily + all methods will go in here. */ + new_list = (MethodList_t) + (*objc_malloc) + (sizeof(MethodList) + sizeof(struct objc_method[counter])); + new_list->method_count = 0; + + while (counter >= 0) + { + Method_t method = &(mlist->method_list[counter]); + + if (debug_behavior) + fprintf(stderr, "processing method %s\n", + sel_get_name(method->method_name)); + + if (!search_for_method_in_list(class->methods, method->method_name) + && method->method_name->sel_id != initialize_sel->sel_id) + { + /* As long as the method isn't defined in the CLASS, + put the BEHAVIOR method in there. Thus, behavior + methods override the superclasses' methods. */ + sarray_at_put_safe (class->dtable, + (sidx) method->method_name->sel_id, + method->method_imp); + new_list->method_list[new_list->method_count] = *method; + (new_list->method_count)++; + if (debug_behavior) + fprintf(stderr, "added method %s\n", + sel_get_name(method->method_name)); + } + counter -= 1; + } + new_list->method_next = class->methods; + class->methods = new_list; + } +} + +#if 0 +/* This is like class_add_method_list(), except is doesn't balk at + duplicates; it simply ignores them. Thus, a method implemented + in CLASS overrides a method implemented in BEHAVIOR. */ + +void +class_add_behavior_method_list (Class class, MethodList_t list) +{ + int i; + static SEL initialize_sel = 0; + if (!initialize_sel) + initialize_sel = sel_register_name ("initialize"); + + /* Passing of a linked list is not allowed. Do multiple calls. */ + assert (!list->method_next); + + /* Check for duplicates. */ + for (i = 0; i < list->method_count; ++i) + { + Method_t method = &list->method_list[i]; + + if (method->method_name) /* Sometimes these are NULL */ + { + if (search_for_method_in_list (class->methods, method->method_name) + && method->method_name->sel_id != initialize_sel->sel_id) + { + /* Duplication. Print a error message an change the method name + to NULL. */ + fprintf (stderr, "attempt to add a existing method: %s\n", + sel_get_name(method->method_name)); + method->method_name = 0; + } + else + { + /* Behavior method not implemented in class. Add it. */ + sarray_at_put_safe (class->dtable, + (sidx) method->method_name->sel_id, + method->method_imp); + } + } + } + + /* Add the methods to the class's method list. */ + list->method_next = class->methods; + class->methods = list; +} +#endif + +/* 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 Method_t +search_for_method_in_list (MethodList_t list, SEL op) +{ + MethodList_t method_list = list; + + if (! sel_is_mapped (op)) + return NULL; + + /* If not found then we'll search the list. */ + while (method_list) + { + int i; + + /* Search the method list. */ + for (i = 0; i < method_list->method_count; ++i) + { + Method_t method = &method_list->method_list[i]; + + if (method->method_name) + if (method->method_name->sel_id == op->sel_id) + return method; + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + + return NULL; +} + +/* Send +initialize to class if not already done */ +static void __objc_send_initialize(Class class) +{ + /* This *must* be a class object */ + assert(CLS_ISCLASS(class)); + assert(!CLS_ISMETA(class)); + + if (!CLS_ISINITIALIZED(class)) + { + CLS_SETINITIALIZED(class); + CLS_SETINITIALIZED(class->class_pointer); + + if(class->super_class) + __objc_send_initialize(class->super_class); + + { + MethodList_t method_list = class->class_pointer->methods; + SEL op = sel_register_name ("initialize"); + + /* If not found then we'll search the list. */ + while (method_list) + { + int i; + + /* Search the method list. */ + for (i = 0; i < method_list->method_count; ++i) + { + Method_t method = &method_list->method_list[i]; + + + if (method->method_name->sel_id == op->sel_id) + (*method->method_imp)((id) class, op); + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + } + } +} + +#if 0 +static void +__objc_init_protocols (struct objc_protocol_list* protos) +{ + int i; + static Class proto_class = 0; + + if (! protos) + return; + + if (!proto_class) + proto_class = objc_lookup_class("Protocol"); + + if (!proto_class) + { + unclaimed_proto_list = list_cons (protos, unclaimed_proto_list); + return; + } + +#if 0 + assert (protos->next == 0); /* only single ones allowed */ +#endif + + for(i = 0; i < protos->count; i++) + { + struct objc_protocol* aProto = protos->list[i]; + if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION) + { + /* assign class pointer */ + aProto->class_pointer = proto_class; + + /* init super protocols */ + __objc_init_protocols (aProto->protocol_list); + } + else if (protos->list[i]->class_pointer != proto_class) + { + fprintf (stderr, + "Version %d doesn't match runtime protocol version %d\n", + (int)((char*)protos->list[i]->class_pointer-(char*)0), + PROTOCOL_VERSION); + abort (); + } + } +} + +static void __objc_class_add_protocols (Class class, + struct objc_protocol_list* protos) +{ + /* Well... */ + if (! protos) + return; + + /* Add it... */ + protos->next = class->protocols; + class->protocols = protos; +} +#endif /* 0 */ + +static BOOL class_is_kind_of(Class self, Class aClassObject) +{ + Class class; + + for (class = self; class!=Nil; class = class_get_super_class(class)) + if (class==aClassObject) + return YES; + return NO; +} diff --git a/Source/behavior.m b/Source/behavior.m new file mode 100644 index 000000000..630fa1ef5 --- /dev/null +++ b/Source/behavior.m @@ -0,0 +1,351 @@ +/* Behaviors for Objective-C, "for Protocols with implementations". + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: R. Andrew McCallum + Date: March 1995 + + This file is part of the GNU Objective C Class Library. + + 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; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. + + xxx not necessarily on the "no instance vars". The behavior just has + to have the same layout as the class. + + 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 +#include +#include +#include +#include + +static int debug_behavior = 0; + +static Method_t search_for_method_in_list (MethodList_t list, SEL op); +static void __objc_send_initialize(Class class); +#if 0 +static void __objc_init_protocols (struct objc_protocol_list* protos); +static void __objc_class_add_protocols (Class class, + struct objc_protocol_list* protos); +#endif +static BOOL class_is_kind_of(Class self, Class class); +void class_add_methods_if_not_there(Class class, MethodList_t mlist); + +/* xxx consider using sendmsg.c:__objc_update_dispatch_table_for_class, + but, I think it will be slower than the current method. */ + +void +set_behavior_debug(int i) +{ + behavior_debug = i; +} + +void +class_add_behavior (Class class, Class behavior) +{ + Class behavior_super_class = class_get_super_class(behavior); + + assert(CLS_ISCLASS(class)); + assert(CLS_ISCLASS(behavior)); + + __objc_send_initialize(class); + __objc_send_initialize(behavior); + +#if 0 + /* xxx Do protocols */ + if (behavior->protocols) + { + /* xxx Make sure they are not already there before adding. */ + __objc_init_protocols (behavior->protocols); + __objc_class_add_protocols (class, behavior->protocols); + } +#endif + + /* Add instance methods */ + class_add_methods_if_not_there(class, + behavior->methods); + + /* Add class methods */ + class_add_methods_if_not_there(class->class_pointer, + behavior->class_pointer->methods); + + /* Add behavior's superclass, if not already there. */ + { + if (!class_is_kind_of(class, behavior_super_class)) + class_add_behavior(class, behavior_super_class); + } + + return; +} + +void +class_add_methods_if_not_there(Class class, MethodList_t mlist) +{ + static SEL initialize_sel = 0; + + if (!initialize_sel) + initialize_sel = sel_register_name ("initialize"); + + /* Add methods to class->dtable and class->methods */ + for ( ; mlist; mlist = mlist->method_next) + { + int counter; + MethodList_t new_list; + + counter = mlist->method_count - 1; + + /* xxx This is a little wasteful of memory, since not necessarily + all methods will go in here. */ + new_list = (MethodList_t) + (*objc_malloc) + (sizeof(MethodList) + sizeof(struct objc_method[counter])); + new_list->method_count = 0; + + while (counter >= 0) + { + Method_t method = &(mlist->method_list[counter]); + + if (debug_behavior) + fprintf(stderr, "processing method %s\n", + sel_get_name(method->method_name)); + + if (!search_for_method_in_list(class->methods, method->method_name) + && method->method_name->sel_id != initialize_sel->sel_id) + { + /* As long as the method isn't defined in the CLASS, + put the BEHAVIOR method in there. Thus, behavior + methods override the superclasses' methods. */ + sarray_at_put_safe (class->dtable, + (sidx) method->method_name->sel_id, + method->method_imp); + new_list->method_list[new_list->method_count] = *method; + (new_list->method_count)++; + if (debug_behavior) + fprintf(stderr, "added method %s\n", + sel_get_name(method->method_name)); + } + counter -= 1; + } + new_list->method_next = class->methods; + class->methods = new_list; + } +} + +#if 0 +/* This is like class_add_method_list(), except is doesn't balk at + duplicates; it simply ignores them. Thus, a method implemented + in CLASS overrides a method implemented in BEHAVIOR. */ + +void +class_add_behavior_method_list (Class class, MethodList_t list) +{ + int i; + static SEL initialize_sel = 0; + if (!initialize_sel) + initialize_sel = sel_register_name ("initialize"); + + /* Passing of a linked list is not allowed. Do multiple calls. */ + assert (!list->method_next); + + /* Check for duplicates. */ + for (i = 0; i < list->method_count; ++i) + { + Method_t method = &list->method_list[i]; + + if (method->method_name) /* Sometimes these are NULL */ + { + if (search_for_method_in_list (class->methods, method->method_name) + && method->method_name->sel_id != initialize_sel->sel_id) + { + /* Duplication. Print a error message an change the method name + to NULL. */ + fprintf (stderr, "attempt to add a existing method: %s\n", + sel_get_name(method->method_name)); + method->method_name = 0; + } + else + { + /* Behavior method not implemented in class. Add it. */ + sarray_at_put_safe (class->dtable, + (sidx) method->method_name->sel_id, + method->method_imp); + } + } + } + + /* Add the methods to the class's method list. */ + list->method_next = class->methods; + class->methods = list; +} +#endif + +/* 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 Method_t +search_for_method_in_list (MethodList_t list, SEL op) +{ + MethodList_t method_list = list; + + if (! sel_is_mapped (op)) + return NULL; + + /* If not found then we'll search the list. */ + while (method_list) + { + int i; + + /* Search the method list. */ + for (i = 0; i < method_list->method_count; ++i) + { + Method_t method = &method_list->method_list[i]; + + if (method->method_name) + if (method->method_name->sel_id == op->sel_id) + return method; + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + + return NULL; +} + +/* Send +initialize to class if not already done */ +static void __objc_send_initialize(Class class) +{ + /* This *must* be a class object */ + assert(CLS_ISCLASS(class)); + assert(!CLS_ISMETA(class)); + + if (!CLS_ISINITIALIZED(class)) + { + CLS_SETINITIALIZED(class); + CLS_SETINITIALIZED(class->class_pointer); + + if(class->super_class) + __objc_send_initialize(class->super_class); + + { + MethodList_t method_list = class->class_pointer->methods; + SEL op = sel_register_name ("initialize"); + + /* If not found then we'll search the list. */ + while (method_list) + { + int i; + + /* Search the method list. */ + for (i = 0; i < method_list->method_count; ++i) + { + Method_t method = &method_list->method_list[i]; + + + if (method->method_name->sel_id == op->sel_id) + (*method->method_imp)((id) class, op); + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + } + } +} + +#if 0 +static void +__objc_init_protocols (struct objc_protocol_list* protos) +{ + int i; + static Class proto_class = 0; + + if (! protos) + return; + + if (!proto_class) + proto_class = objc_lookup_class("Protocol"); + + if (!proto_class) + { + unclaimed_proto_list = list_cons (protos, unclaimed_proto_list); + return; + } + +#if 0 + assert (protos->next == 0); /* only single ones allowed */ +#endif + + for(i = 0; i < protos->count; i++) + { + struct objc_protocol* aProto = protos->list[i]; + if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION) + { + /* assign class pointer */ + aProto->class_pointer = proto_class; + + /* init super protocols */ + __objc_init_protocols (aProto->protocol_list); + } + else if (protos->list[i]->class_pointer != proto_class) + { + fprintf (stderr, + "Version %d doesn't match runtime protocol version %d\n", + (int)((char*)protos->list[i]->class_pointer-(char*)0), + PROTOCOL_VERSION); + abort (); + } + } +} + +static void __objc_class_add_protocols (Class class, + struct objc_protocol_list* protos) +{ + /* Well... */ + if (! protos) + return; + + /* Add it... */ + protos->next = class->protocols; + class->protocols = protos; +} +#endif /* 0 */ + +static BOOL class_is_kind_of(Class self, Class aClassObject) +{ + Class class; + + for (class = self; class!=Nil; class = class_get_super_class(class)) + if (class==aClassObject) + return YES; + return NO; +} diff --git a/Source/objects/behavior.h b/Source/objects/behavior.h new file mode 100644 index 000000000..79a1d7eac --- /dev/null +++ b/Source/objects/behavior.h @@ -0,0 +1,43 @@ +/* Interface for behaviors for Obj-C, "for Protocols with implementations". + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: R. Andrew McCallum + Date: March 1995 + + This file is part of the GNU Objective C Class Library. + + 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; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __behavior_h_OBJECTS_INCLUDE +#define __behavior_h_OBJECTS_INCLUDE + +/* Call this method from CLASS's +initialize method to add a behavior + to CLASS. A "behavior" is like a protocol with an implementation. + + This functions adds to CLASS all the instance and factory methods + of BEHAVIOR as well as the instance and factory methods of + BEHAVIOR's superclasses (We stop adding super classes as soon as we + encounter a common ancestor.) CLASS and BEHAVIOR should share the + same instance variable layout. + + xxx We do not yet deal with Protocols, but we should. */ +void class_add_behavior (Class class, Class behavior); + + +/* Set to non-zero if you want debugging messages on stderr. */ +void set_behavior_debug(int i); + +#endif /* __behavior_h_OBJECTS_INCLUDE */