~ubuntu-branches/ubuntu/trusty/gnustep-base/trusty

« back to all changes in this revision

Viewing changes to Source/Additions/behavior.m

Tags: upstream-1.20.0
ImportĀ upstreamĀ versionĀ 1.20.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/** Behaviors for Objective-C, "for Protocols with implementations".
2
 
   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
3
 
 
4
 
   Written by:  Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
5
 
   Date: March 1995
6
 
 
7
 
   This file is part of the GNUstep Base Library.
8
 
 
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.
13
 
 
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.
18
 
 
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.
22
 
*/
23
 
 
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.
27
 
 
28
 
   Behavior methods, when added to a class, override the class's
29
 
   superclass methods, but not the class's methods.
30
 
 
31
 
   xxx not necessarily on the "no instance vars".  The behavior just has
32
 
   to have the same layout as the class.
33
 
 
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.
38
 
 
39
 
   This function should be called in CLASS's +initialize method.
40
 
 
41
 
   If you add several behaviors to a class, be aware that the order of
42
 
   the additions is significant.
43
 
 
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."
48
 
 
49
 
   */
50
 
 
51
 
#include "config.h"
52
 
#include <stdio.h>
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>
58
 
#else
59
 
#include <Foundation/Foundation.h>
60
 
#endif
61
 
 
62
 
static BOOL class_is_kind_of(Class self, Class class);
63
 
 
64
 
static int behavior_debug = 0;
65
 
 
66
 
void
67
 
behavior_set_debug(int i)
68
 
{
69
 
  behavior_debug = i;
70
 
}
71
 
 
72
 
void
73
 
behavior_class_add_class (Class class, Class behavior)
74
 
{
75
 
  Class behavior_super_class = class_get_super_class(behavior);
76
 
 
77
 
  NSCAssert(CLS_ISCLASS(class), NSInvalidArgumentException);
78
 
  NSCAssert(CLS_ISCLASS(behavior), NSInvalidArgumentException);
79
 
 
80
 
#if NeXT_RUNTIME
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));
84
 
#else
85
 
  /* If necessary, increase instance_size of CLASS. */
86
 
  if (class->instance_size < behavior->instance_size)
87
 
    {
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;
96
 
    }
97
 
#endif
98
 
 
99
 
  if (behavior_debug)
100
 
    {
101
 
      fprintf(stderr, "Adding behavior to class %s\n",
102
 
              class->name);
103
 
    }
104
 
 
105
 
  /* Add instance methods */
106
 
  if (behavior_debug)
107
 
    {
108
 
      fprintf(stderr, "Adding instance methods from %s\n",
109
 
              behavior->name);
110
 
    }
111
 
#if NeXT_RUNTIME
112
 
  {
113
 
     void *iterator = 0;
114
 
     struct objc_method_list *method_list;
115
 
 
116
 
     while ((method_list = class_nextMethodList(behavior, &iterator)))
117
 
       behavior_class_add_methods (class, method_list);
118
 
  }
119
 
#else
120
 
  behavior_class_add_methods (class, behavior->methods);
121
 
#endif
122
 
 
123
 
  /* Add class methods */
124
 
  if (behavior_debug)
125
 
    {
126
 
      fprintf(stderr, "Adding class methods from %s\n",
127
 
              behavior->class_pointer->name);
128
 
    }
129
 
#if NeXT_RUNTIME
130
 
  {
131
 
     void *iterator = 0;
132
 
     struct objc_method_list *method_list;
133
 
 
134
 
     while ((method_list =
135
 
              class_nextMethodList(behavior->class_pointer, &iterator)))
136
 
       behavior_class_add_methods (class->class_pointer, method_list);
137
 
  }
138
 
#else
139
 
  behavior_class_add_methods (class->class_pointer,
140
 
                              behavior->class_pointer->methods);
141
 
#endif
142
 
 
143
 
  /* Add behavior's superclass, if not already there. */
144
 
  {
145
 
    if (!class_is_kind_of(class, behavior_super_class))
146
 
      behavior_class_add_class (class, behavior_super_class);
147
 
  }
148
 
 
149
 
  return;
150
 
}
151
 
 
152
 
void
153
 
behavior_class_add_category (Class class, struct objc_category *category)
154
 
{
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. */
160
 
}
161
 
 
162
 
#if NeXT_RUNTIME
163
 
 
164
 
static struct objc_method *search_for_method_in_list (Class class, SEL op);
165
 
 
166
 
void
167
 
behavior_class_add_methods (Class class, struct objc_method_list *methods)
168
 
{
169
 
  static SEL initialize_sel = 0;
170
 
  struct objc_method_list *mlist;
171
 
 
172
 
  if (!initialize_sel)
173
 
    initialize_sel = sel_register_name ("initialize");
174
 
 
175
 
  /* Add methods to class->dtable and class->methods */
176
 
  mlist = methods;
177
 
    {
178
 
      int counter;
179
 
      struct objc_method_list *new_list;
180
 
 
181
 
      counter = mlist->method_count ? mlist->method_count - 1 : 1;
182
 
 
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;
189
 
 
190
 
      while (counter >= 0)
191
 
        {
192
 
          struct objc_method *method = &(mlist->method_list[counter]);
193
 
 
194
 
          if (behavior_debug)
195
 
            {
196
 
              fprintf(stderr, "   processing method [%s] ... ",
197
 
                sel_get_name(method->method_name));
198
 
            }
199
 
 
200
 
          if (!search_for_method_in_list(class,method->method_name)
201
 
            && !sel_eq(method->method_name, initialize_sel))
202
 
            {
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)++;
208
 
              if (behavior_debug)
209
 
                {
210
 
                  fprintf(stderr, "added.\n");
211
 
                }
212
 
            }
213
 
          else if (behavior_debug)
214
 
            {
215
 
              fprintf(stderr, "ignored.\n");
216
 
            }
217
 
          counter -= 1;
218
 
        }
219
 
      if (new_list->method_count)
220
 
        {
221
 
          class_add_method_list(class, new_list);
222
 
        }
223
 
      else
224
 
        {
225
 
          OBJC_FREE(new_list);
226
 
        }
227
 
    }
228
 
}
229
 
 
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)
234
 
{
235
 
  void *iterator = 0;
236
 
  struct objc_method_list *method_list;
237
 
 
238
 
  if (! sel_is_mapped (op))
239
 
    return NULL;
240
 
 
241
 
  /* If not found then we'll search the list.  */
242
 
  while ((method_list = class_nextMethodList(class, &iterator)))
243
 
    {
244
 
      int i;
245
 
 
246
 
      /* Search the method list.  */
247
 
      for (i = 0; i < method_list->method_count; ++i)
248
 
        {
249
 
          struct objc_method *method = &method_list->method_list[i];
250
 
 
251
 
          if (method->method_name)
252
 
            {
253
 
              if (sel_eq(method->method_name, op))
254
 
                return method;
255
 
            }
256
 
        }
257
 
    }
258
 
 
259
 
  return NULL;
260
 
}
261
 
 
262
 
#else
263
 
/* GNU runtime */
264
 
 
265
 
/*
266
 
 * The following two functions are implemented in the GNU objc runtime
267
 
 */
268
 
extern Method_t search_for_method_in_list(MethodList_t list, SEL op);
269
 
extern void class_add_method_list(Class, MethodList_t);
270
 
 
271
 
void
272
 
behavior_class_add_methods (Class class,
273
 
                            struct objc_method_list *methods)
274
 
{
275
 
  static SEL initialize_sel = 0;
276
 
  struct objc_method_list *mlist;
277
 
 
278
 
  if (!initialize_sel)
279
 
    initialize_sel = sel_register_name ("initialize");
280
 
 
281
 
  /* Add methods to class->dtable and class->methods */
282
 
  for (mlist = methods; mlist; mlist = mlist->method_next)
283
 
    {
284
 
      int counter;
285
 
      struct objc_method_list *new_list;
286
 
 
287
 
      counter = mlist->method_count ? mlist->method_count - 1 : 1;
288
 
 
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;
296
 
 
297
 
      while (counter >= 0)
298
 
        {
299
 
          struct objc_method    *method = &(mlist->method_list[counter]);
300
 
          const char            *name = sel_get_name(method->method_name);
301
 
 
302
 
          if (behavior_debug)
303
 
            {
304
 
              fprintf(stderr, "   processing method [%s] ... ", name);
305
 
            }
306
 
          if (!search_for_method_in_list(class->methods, method->method_name)
307
 
              && !sel_eq(method->method_name, initialize_sel))
308
 
            {
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;
313
 
              /*
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
317
 
               * for that.
318
 
               */
319
 
              new_list->method_list[new_list->method_count].method_name
320
 
                = (SEL)name;
321
 
              (new_list->method_count)++;
322
 
              if (behavior_debug)
323
 
                {
324
 
                  fprintf(stderr, "added.\n");
325
 
                }
326
 
            }
327
 
          else if (behavior_debug)
328
 
            {
329
 
              fprintf(stderr, "ignored.\n");
330
 
            }
331
 
          counter -= 1;
332
 
        }
333
 
      if (new_list->method_count)
334
 
        {
335
 
          class_add_method_list(class, new_list);
336
 
        }
337
 
      else
338
 
        {
339
 
          OBJC_FREE(new_list);
340
 
        }
341
 
    }
342
 
}
343
 
 
344
 
#endif /* NeXT runtime */
345
 
 
346
 
static BOOL class_is_kind_of(Class self, Class aClassObject)
347
 
{
348
 
  Class class;
349
 
 
350
 
  for (class = self; class!=Nil; class = class_get_super_class(class))
351
 
    if (class==aClassObject)
352
 
      return YES;
353
 
  return NO;
354
 
}