1
/** Behaviors for Objective-C, "for Protocols with implementations".
2
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
4
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
7
This file is part of the GNUstep Base Library.
9
This library is free software; you can redistribute it and/or
10
modify it under the terms of the GNU Lesser General Public
11
License as published by the Free Software Foundation; either
12
version 2 of the License, or (at your option) any later version.
14
This library is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
Library General Public License for more details.
19
You should have received a copy of the GNU Lesser General Public
20
License along with this library; if not, write to the Free
21
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
24
/* A Behavior can be seen as a "Protocol with an implementation" or a
25
"Class without any instance variables". A key feature of behaviors
26
is that they give a degree of multiple inheritance.
28
Behavior methods, when added to a class, override the class's
29
superclass methods, but not the class's methods.
31
xxx not necessarily on the "no instance vars". The behavior just has
32
to have the same layout as the class.
34
The following function is a sneaky hack way that provides Behaviors
35
without adding any new syntax to the Objective C language. Simply
36
define a class with the methods you want in the behavior, then call
37
this function with that class as the BEHAVIOR argument.
39
This function should be called in CLASS's +initialize method.
41
If you add several behaviors to a class, be aware that the order of
42
the additions is significant.
44
McCallum talking to himself:
45
"Yipes. Be careful with [super ...] calls.
46
BEHAVIOR methods running in CLASS will now have a different super class.
47
No; wrong. See objc-api.h; typedef struct objc_super."
53
#include "GNUstepBase/preface.h"
54
#include "GNUstepBase/behavior.h"
55
#ifndef NeXT_Foundation_LIBRARY
56
#include <Foundation/NSException.h>
57
#include <Foundation/NSString.h>
59
#include <Foundation/Foundation.h>
62
static BOOL class_is_kind_of(Class self, Class class);
64
static int behavior_debug = 0;
67
behavior_set_debug(int i)
73
behavior_class_add_class (Class class, Class behavior)
75
Class behavior_super_class = class_get_super_class(behavior);
77
NSCAssert(CLS_ISCLASS(class), NSInvalidArgumentException);
78
NSCAssert(CLS_ISCLASS(behavior), NSInvalidArgumentException);
81
NSCAssert2(class->instance_size >= behavior->instance_size,
82
@"Trying to add behavior (%s) with instance size larger than class (%s)",
83
class_get_class_name(behavior), class_get_class_name(class));
85
/* If necessary, increase instance_size of CLASS. */
86
if (class->instance_size < behavior->instance_size)
88
NSCAssert(!class->subclass_list,
89
@"The behavior-addition code wants to increase the\n"
90
@"instance size of a class, but it cannot because you\n"
91
@"have subclassed the class. There are two solutions:\n"
92
@"(1) Don't subclass it; (2) Add placeholder instance\n"
93
@"variables to the class, so the behavior-addition code\n"
94
@"will not have to increase the instance size\n");
95
class->instance_size = behavior->instance_size;
101
fprintf(stderr, "Adding behavior to class %s\n",
105
/* Add instance methods */
108
fprintf(stderr, "Adding instance methods from %s\n",
114
struct objc_method_list *method_list;
116
while ((method_list = class_nextMethodList(behavior, &iterator)))
117
behavior_class_add_methods (class, method_list);
120
behavior_class_add_methods (class, behavior->methods);
123
/* Add class methods */
126
fprintf(stderr, "Adding class methods from %s\n",
127
behavior->class_pointer->name);
132
struct objc_method_list *method_list;
134
while ((method_list =
135
class_nextMethodList(behavior->class_pointer, &iterator)))
136
behavior_class_add_methods (class->class_pointer, method_list);
139
behavior_class_add_methods (class->class_pointer,
140
behavior->class_pointer->methods);
143
/* Add behavior's superclass, if not already there. */
145
if (!class_is_kind_of(class, behavior_super_class))
146
behavior_class_add_class (class, behavior_super_class);
153
behavior_class_add_category (Class class, struct objc_category *category)
155
behavior_class_add_methods (class,
156
category->instance_methods);
157
behavior_class_add_methods (class->class_pointer,
158
category->class_methods);
159
/* xxx Add the protocols (category->protocols) too. */
164
static struct objc_method *search_for_method_in_list (Class class, SEL op);
167
behavior_class_add_methods (Class class, struct objc_method_list *methods)
169
static SEL initialize_sel = 0;
170
struct objc_method_list *mlist;
173
initialize_sel = sel_register_name ("initialize");
175
/* Add methods to class->dtable and class->methods */
179
struct objc_method_list *new_list;
181
counter = mlist->method_count ? mlist->method_count - 1 : 1;
183
/* This is a little wasteful of memory, since not necessarily
184
all methods will go in here. */
185
new_list = (struct objc_method_list *)
186
objc_malloc (sizeof(struct objc_method_list) +
187
sizeof(struct objc_method[counter+1]));
188
new_list->method_count = 0;
192
struct objc_method *method = &(mlist->method_list[counter]);
196
fprintf(stderr, " processing method [%s] ... ",
197
sel_get_name(method->method_name));
200
if (!search_for_method_in_list(class,method->method_name)
201
&& !sel_eq(method->method_name, initialize_sel))
203
/* As long as the method isn't defined in the CLASS,
204
put the BEHAVIOR method in there. Thus, behavior
205
methods override the superclasses' methods. */
206
new_list->method_list[new_list->method_count] = *method;
207
(new_list->method_count)++;
210
fprintf(stderr, "added.\n");
213
else if (behavior_debug)
215
fprintf(stderr, "ignored.\n");
219
if (new_list->method_count)
221
class_add_method_list(class, new_list);
230
/* Search for the named method's method structure. Return a pointer
231
to the method's method structure if found. NULL otherwise. */
232
static struct objc_method *
233
search_for_method_in_list (Class class, SEL op)
236
struct objc_method_list *method_list;
238
if (! sel_is_mapped (op))
241
/* If not found then we'll search the list. */
242
while ((method_list = class_nextMethodList(class, &iterator)))
246
/* Search the method list. */
247
for (i = 0; i < method_list->method_count; ++i)
249
struct objc_method *method = &method_list->method_list[i];
251
if (method->method_name)
253
if (sel_eq(method->method_name, op))
266
* The following two functions are implemented in the GNU objc runtime
268
extern Method_t search_for_method_in_list(MethodList_t list, SEL op);
269
extern void class_add_method_list(Class, MethodList_t);
272
behavior_class_add_methods (Class class,
273
struct objc_method_list *methods)
275
static SEL initialize_sel = 0;
276
struct objc_method_list *mlist;
279
initialize_sel = sel_register_name ("initialize");
281
/* Add methods to class->dtable and class->methods */
282
for (mlist = methods; mlist; mlist = mlist->method_next)
285
struct objc_method_list *new_list;
287
counter = mlist->method_count ? mlist->method_count - 1 : 1;
289
/* This is a little wasteful of memory, since not necessarily
290
all methods will go in here. */
291
new_list = (struct objc_method_list *)
292
objc_malloc (sizeof(struct objc_method_list) +
293
sizeof(struct objc_method[counter+1]));
294
new_list->method_count = 0;
295
new_list->method_next = NULL;
299
struct objc_method *method = &(mlist->method_list[counter]);
300
const char *name = sel_get_name(method->method_name);
304
fprintf(stderr, " processing method [%s] ... ", name);
306
if (!search_for_method_in_list(class->methods, method->method_name)
307
&& !sel_eq(method->method_name, initialize_sel))
309
/* As long as the method isn't defined in the CLASS,
310
put the BEHAVIOR method in there. Thus, behavior
311
methods override the superclasses' methods. */
312
new_list->method_list[new_list->method_count] = *method;
314
* HACK ... the GNU runtime implementation of
315
* class_add_method_list() expects the method names to be
316
* C-strings rather than selectors ... so we must allow
319
new_list->method_list[new_list->method_count].method_name
321
(new_list->method_count)++;
324
fprintf(stderr, "added.\n");
327
else if (behavior_debug)
329
fprintf(stderr, "ignored.\n");
333
if (new_list->method_count)
335
class_add_method_list(class, new_list);
344
#endif /* NeXT runtime */
346
static BOOL class_is_kind_of(Class self, Class aClassObject)
350
for (class = self; class!=Nil; class = class_get_super_class(class))
351
if (class==aClassObject)