]> err.no Git - sope/blob - gnustep-objc/selector.c
improved rrule parser
[sope] / gnustep-objc / selector.c
1 /* GNU Objective C Runtime selector related functions
2    Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
3    Contributed by Kresten Krab Thorup
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2, or (at your option) any later version.
10
11 GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14 details.
15
16 You should have received a copy of the GNU General Public License along with
17 GNU CC; see the file COPYING.  If not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 /* As a special exception, if you link this library with files compiled with
21    GCC to produce an executable, this does not cause the resulting executable
22    to be covered by the GNU General Public License. This exception does not
23    however invalidate any other reasons why the executable file might be
24    covered by the GNU General Public License.  */
25
26 #include "runtime.h"
27 #include "sarray.h"
28 #include "encoding.h"
29 #include "hash.h"
30 #include <string.h>
31
32 /* Initial selector hash table size. Value doesn't matter much */
33 #define SELECTOR_HASH_SIZE 128
34
35 static void register_selectors_from_list(MethodList_t);
36
37 void __objc_init_selector_tables()
38 {
39   __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE);
40   __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE);
41   __objc_selector_hash  = strhash_new(SELECTOR_HASH_SIZE);
42 }  
43
44 /* This routine is given a class and records all of the methods in its class
45    structure in the record table.  */
46 void __objc_register_selectors_from_class (Class class)
47 {
48   register MethodList_t method_list;
49
50   method_list = class->methods;
51   while (method_list) {
52     register_selectors_from_list (method_list);
53     method_list = method_list->method_next;
54   }
55 }
56
57
58 /* This routine is given a list of methods and records each of the methods in
59    the record table.  This is the routine that does the actual recording
60    work.
61
62    This one is only called for Class objects.  For categories,
63    class_add_method_list is called.
64    */
65 static void register_selectors_from_list (MethodList_t method_list)
66 {
67   register int i = 0;
68   while (i < method_list->method_count)
69     {
70       Method_t method = &method_list->method_list[i];
71       method->method_name 
72         = sel_register_typed_name ((const char*)method->method_name, 
73                                      method->method_types);
74       i += 1;
75     }
76 }
77
78
79 /* Register instance methods as class methods for root classes */
80 void __objc_register_instance_methods_to_class(Class class)
81 {
82   MethodList_t method_list;
83   MethodList_t class_method_list;
84   int          max_methods_no = 16;
85   MethodList_t new_list;
86   Method_t     curr_method;
87
88   /* Only if a root class. */
89   if(class->super_class)
90     return;
91
92   /* Allocate a method list to hold the new class methods */
93   new_list =
94     OBJC_CALLOC_UNCOLLECTABLE(sizeof(struct objc_method_list) +
95                               sizeof(struct objc_method[max_methods_no]));
96
97   method_list = class->methods;
98   class_method_list = class->class_pointer->methods;
99   curr_method = &new_list->method_list[0];
100
101   /* Iterate through the method lists for the class */
102   while (method_list)
103     {
104       int i;
105
106       /* Iterate through the methods from this method list */
107       for (i = 0; i < method_list->method_count; i++)
108         {
109           Method_t mth = &method_list->method_list[i];
110           if (mth->method_name
111               && !search_for_method_in_list (class_method_list,
112                                               mth->method_name))
113             {
114               /* This instance method isn't a class method. 
115                   Add it into the new_list. */
116               *curr_method = *mth;
117   
118               /* Reallocate the method list if necessary */
119               if(++new_list->method_count == max_methods_no)
120                 new_list =
121                   objc_realloc(new_list, sizeof(struct objc_method_list)
122                                 + sizeof(struct 
123                                         objc_method[max_methods_no += 16]));
124               curr_method = &new_list->method_list[new_list->method_count];
125             }
126         }
127
128       method_list = method_list->method_next;
129     }
130
131   /* If we created any new class methods
132      then attach the method list to the class */
133   if (new_list->method_count)
134     {
135       new_list =
136         objc_realloc(new_list, sizeof(struct objc_method_list)
137                      + sizeof(struct objc_method[new_list->method_count]));
138       new_list->method_next = class->class_pointer->methods;
139       class->class_pointer->methods = new_list;
140     }
141
142     __objc_update_dispatch_table_for_class (class->class_pointer);
143 }
144
145
146 /* Returns YES iff t1 and t2 have same method types, but we ignore
147    the argframe layout */
148 BOOL sel_types_match (const char* t1, const char* t2)
149 {
150   if (!t1 || !t2)
151     return NO;
152   while (*t1 && *t2)
153     {
154       if (*t1 == '+') t1++;
155       if (*t2 == '+') t2++;
156       while (isdigit((int)*t1)) t1++;
157       while (isdigit((int)*t2)) t2++;
158       /* xxx Remove these next two lines when qualifiers are put in
159          all selectors, not just Protocol selectors. */
160       t1 = objc_skip_type_qualifiers(t1);
161       t2 = objc_skip_type_qualifiers(t2);
162       if (!*t1 && !*t2)
163         return YES;
164       if (*t1 != *t2)
165         return NO;
166       t1++;
167       t2++;
168     }
169   return NO;
170 }
171
172 /* return selector representing name */
173 SEL sel_get_typed_uid (const char *name, const char *types)
174 {
175   struct objc_list *l;
176   sidx i;
177
178   RUNTIME_LOCK;
179
180   i = (sidx) hash_value_for_key (__objc_selector_hash, name);
181   if (i == 0)
182     {
183       RUNTIME_UNLOCK;
184       return 0;
185     }
186
187   for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
188        l; l = l->tail)
189     {
190       SEL s = (SEL)l->head;
191       if (types == 0 || s->sel_types == 0)
192         {
193           if (s->sel_types == types)
194             {
195               RUNTIME_UNLOCK;
196               return s;
197             }
198         }
199       else if (sel_types_match (s->sel_types, types))
200         {
201           RUNTIME_UNLOCK;
202           return s;
203         }
204     }
205
206   RUNTIME_UNLOCK;
207   return 0;
208 }
209
210 /* Return selector representing name; prefer a selector with non-NULL type */
211 SEL sel_get_any_typed_uid (const char *name)
212 {
213   struct objc_list *l;
214   sidx i;
215   SEL s = NULL;
216
217   RUNTIME_LOCK;
218
219   i = (sidx) hash_value_for_key (__objc_selector_hash, name);
220   if (i == 0) 
221     {
222       RUNTIME_UNLOCK;
223       return 0;
224     }
225
226   for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
227        l; l = l->tail)
228     {
229       s = (SEL) l->head;
230       if (s->sel_types)
231         {
232             RUNTIME_UNLOCK;
233             return s;
234         }
235     }
236
237   RUNTIME_UNLOCK;
238   return s;
239 }
240
241 /* return selector representing name */
242 SEL sel_get_any_uid (const char *name)
243 {
244   struct objc_list *l;
245   sidx i;
246
247   RUNTIME_LOCK;
248
249   i = (sidx) hash_value_for_key (__objc_selector_hash, name);
250   if (i == 0) {
251     RUNTIME_UNLOCK;
252     return 0;
253   }
254
255   l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
256   RUNTIME_UNLOCK;
257
258   if (l == 0)
259     return 0;
260
261   return (SEL)l->head;
262 }
263
264 /* return selector representing name */
265 SEL sel_get_uid (const char *name)
266 {
267   return sel_register_typed_name (name, 0);
268 }
269
270 /* Get name of selector.  If selector is unknown, the empty string "" 
271    is returned */ 
272 const char* sel_get_name (SEL selector)
273 {
274   const char *ret;
275
276   RUNTIME_LOCK;
277   ret = ((selector->sel_id > 0)
278          && ((unsigned int)selector->sel_id <= __objc_selector_max_index))
279     ? sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id)
280     : 0;
281   RUNTIME_UNLOCK;
282   return ret;
283 }
284
285 BOOL sel_is_mapped (SEL selector)
286 {
287   register unsigned int idx = (unsigned int)selector->sel_id;
288   return ((idx > 0) && (idx <= __objc_selector_max_index));
289 }
290
291
292 const char* sel_get_type (SEL selector)
293 {
294   return selector ? selector->sel_types : 0;
295 }
296
297 /* Store the passed selector name in the selector record and return its
298    selector value (value returned by sel_get_uid).
299    Assumes that the calling function has locked down __objc_runtime_mutex. */
300 /* is_const parameter tells us if the name and types parameters
301    are really constant or not.  If YES then they are constant and
302    we can just store the pointers.  If NO then we need to copy
303    name and types because the pointers may disappear later on. */
304 SEL
305 __sel_register_typed_name (const char *name, const char *types, 
306                            struct objc_selector *orig, BOOL is_const)
307 {
308   struct objc_selector* j;
309   sidx i;
310   struct objc_list *l;
311
312   i = (sidx) hash_value_for_key (__objc_selector_hash, name);
313   if (i != 0) {
314     for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
315          l; l = l->tail) {
316       SEL s = (SEL)l->head;
317       if (types == 0 || s->sel_types == 0) {
318         if (s->sel_types == types) {
319           if (orig) {
320             orig->sel_id = (void*)i;
321             return orig;
322           }
323           else
324             return s;
325         }
326       }
327       else if (!strcmp (s->sel_types, types)) {
328         if (orig) {
329           orig->sel_id = (void*)i;
330           return orig;
331         }
332         else
333           return s;
334       }
335     }
336     if (orig)
337       j = orig;
338     else
339       j = OBJC_MALLOC_UNCOLLECTABLE(sizeof(struct objc_selector));
340
341     j->sel_id = (void*)i;
342     /* Can we use the pointer or must copy types?  Don't copy if NULL */
343     if ((is_const) || (types == 0)) {
344       j->sel_types = (const char*)types;
345     }
346     else {
347       j->sel_types = (char *)OBJC_MALLOC_UNCOLLECTABLE(strlen(types) + 1);
348       strcpy((char *)j->sel_types, types);
349     }
350     l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
351   }
352   else {
353     __objc_selector_max_index += 1;
354     i = __objc_selector_max_index;
355       
356     if (orig)
357       j = orig;
358     else
359       j = OBJC_MALLOC_UNCOLLECTABLE (sizeof (struct objc_selector));
360         
361     j->sel_id = (void*)i;
362     /* Can we use the pointer or must copy types?  Don't copy if NULL */
363     if ((is_const) || (types == 0))
364       j->sel_types = (const char*)types;
365     else {
366       j->sel_types = (char *)OBJC_MALLOC_UNCOLLECTABLE(strlen(types)+1);
367
368       strcpy((char *)j->sel_types, types);
369     }
370     l = 0;
371   }
372
373   DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n",
374                 name ? name : "<NULL>", types ? types : "<NULL>", 
375                 (long int)i);
376   
377   {
378     int is_new = (l == 0);
379     const char *new_name;
380
381     /* Can we use the pointer or must copy name?  Don't copy if NULL */
382     if ((is_const) || (name == 0)) {
383       new_name = name;
384     }
385     else {
386       new_name = (char *)OBJC_MALLOC_UNCOLLECTABLE(strlen(name) + 1);
387       strcpy((char *)new_name, name);
388     }
389
390     l = list_cons ((void*)j, l);
391     sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
392     sarray_at_put_safe (__objc_selector_array, i, (void *) l);
393     if (is_new)
394       hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
395   }
396
397   //hh:sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index + 1);
398
399   return (SEL) j;
400 }
401
402 SEL sel_register_name (const char *name)
403 {
404   SEL ret;
405     
406   RUNTIME_LOCK;
407   /* Assume that name is not constant static memory and needs to be
408      copied before put into a runtime structure.  is_const == NO */
409   ret = __sel_register_typed_name (name, 0, 0, NO);
410   RUNTIME_UNLOCK;
411   
412   return ret;
413 }
414
415 SEL sel_register_typed_name (const char *name, const char *type)
416 {
417   SEL ret;
418     
419   RUNTIME_LOCK;
420   /* Assume that name and type are not constant static memory and need to
421      be copied before put into a runtime structure.  is_const == NO */
422   ret = __sel_register_typed_name (name, type, 0, NO);
423   RUNTIME_UNLOCK;
424   
425   return ret;
426 }