1*e4b17023SJohn Marino /* GNU Objective C Runtime protocol related functions.
2*e4b17023SJohn Marino Copyright (C) 2010 Free Software Foundation, Inc.
3*e4b17023SJohn Marino Contributed by Nicola Pero
4*e4b17023SJohn Marino
5*e4b17023SJohn Marino This file is part of GCC.
6*e4b17023SJohn Marino
7*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under the
8*e4b17023SJohn Marino terms of the GNU General Public License as published by the Free Software
9*e4b17023SJohn Marino Foundation; either version 3, or (at your option) any later version.
10*e4b17023SJohn Marino
11*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13*e4b17023SJohn Marino FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14*e4b17023SJohn Marino details.
15*e4b17023SJohn Marino
16*e4b17023SJohn Marino Under Section 7 of GPL version 3, you are granted additional
17*e4b17023SJohn Marino permissions described in the GCC Runtime Library Exception, version
18*e4b17023SJohn Marino 3.1, as published by the Free Software Foundation.
19*e4b17023SJohn Marino
20*e4b17023SJohn Marino You should have received a copy of the GNU General Public License and
21*e4b17023SJohn Marino a copy of the GCC Runtime Library Exception along with this program;
22*e4b17023SJohn Marino see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23*e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
24*e4b17023SJohn Marino
25*e4b17023SJohn Marino #include "objc-private/common.h"
26*e4b17023SJohn Marino #include "objc/runtime.h"
27*e4b17023SJohn Marino #include "objc-private/module-abi-8.h" /* For runtime structures */
28*e4b17023SJohn Marino #include "objc/thr.h"
29*e4b17023SJohn Marino #include "objc-private/runtime.h" /* the kitchen sink */
30*e4b17023SJohn Marino #include "objc-private/hash.h" /* For the hash table of protocols. */
31*e4b17023SJohn Marino #include "objc-private/protocols.h" /* For __objc_protocols_init() and
32*e4b17023SJohn Marino __objc_protocols_add_protocol(). */
33*e4b17023SJohn Marino #include <stdlib.h> /* For malloc. */
34*e4b17023SJohn Marino
35*e4b17023SJohn Marino /* This is a table that maps a name to a Protocol instance with that
36*e4b17023SJohn Marino name. Because there may be multiple Protocol instances with the
37*e4b17023SJohn Marino same name (no harm in that) the table records only one
38*e4b17023SJohn Marino instance. */
39*e4b17023SJohn Marino static cache_ptr __protocols_hashtable;
40*e4b17023SJohn Marino
41*e4b17023SJohn Marino /* A mutex protecting the protocol_hashtable. */
42*e4b17023SJohn Marino static objc_mutex_t __protocols_hashtable_lock = NULL;
43*e4b17023SJohn Marino
44*e4b17023SJohn Marino /* Called at startup by init.c. */
45*e4b17023SJohn Marino void
__objc_protocols_init(void)46*e4b17023SJohn Marino __objc_protocols_init (void)
47*e4b17023SJohn Marino {
48*e4b17023SJohn Marino __protocols_hashtable_lock = objc_mutex_allocate ();
49*e4b17023SJohn Marino
50*e4b17023SJohn Marino /* The keys in the table are strings, and the values are Protocol
51*e4b17023SJohn Marino objects. */
52*e4b17023SJohn Marino __protocols_hashtable = objc_hash_new (64, (hash_func_type) objc_hash_string,
53*e4b17023SJohn Marino (compare_func_type) objc_compare_strings);
54*e4b17023SJohn Marino }
55*e4b17023SJohn Marino
56*e4b17023SJohn Marino /* Add a protocol to the hashtable. */
57*e4b17023SJohn Marino void
__objc_protocols_add_protocol(const char * name,struct objc_protocol * object)58*e4b17023SJohn Marino __objc_protocols_add_protocol (const char *name, struct objc_protocol *object)
59*e4b17023SJohn Marino {
60*e4b17023SJohn Marino objc_mutex_lock (__protocols_hashtable_lock);
61*e4b17023SJohn Marino
62*e4b17023SJohn Marino /* If we find a protocol with the same name already in the
63*e4b17023SJohn Marino hashtable, we do not need to add the new one, because it will be
64*e4b17023SJohn Marino identical to it. This in the reasonable assumption that two
65*e4b17023SJohn Marino protocols with the same name are identical, which is expected in
66*e4b17023SJohn Marino any sane program. If we are really paranoid, we would compare
67*e4b17023SJohn Marino the protocols and abort if they are not identical.
68*e4b17023SJohn Marino Unfortunately, this would slow down the startup of all
69*e4b17023SJohn Marino Objective-C programs while trying to catch a problem that has
70*e4b17023SJohn Marino never been seen in practice, so we don't do it. */
71*e4b17023SJohn Marino if (! objc_hash_is_key_in_hash (__protocols_hashtable, name))
72*e4b17023SJohn Marino objc_hash_add (&__protocols_hashtable, name, object);
73*e4b17023SJohn Marino
74*e4b17023SJohn Marino objc_mutex_unlock (__protocols_hashtable_lock);
75*e4b17023SJohn Marino }
76*e4b17023SJohn Marino
77*e4b17023SJohn Marino Protocol *
objc_getProtocol(const char * name)78*e4b17023SJohn Marino objc_getProtocol (const char *name)
79*e4b17023SJohn Marino {
80*e4b17023SJohn Marino Protocol *protocol;
81*e4b17023SJohn Marino
82*e4b17023SJohn Marino if (name == NULL)
83*e4b17023SJohn Marino return NULL;
84*e4b17023SJohn Marino
85*e4b17023SJohn Marino objc_mutex_lock (__protocols_hashtable_lock);
86*e4b17023SJohn Marino protocol = (Protocol *)(objc_hash_value_for_key (__protocols_hashtable, name));
87*e4b17023SJohn Marino objc_mutex_unlock (__protocols_hashtable_lock);
88*e4b17023SJohn Marino
89*e4b17023SJohn Marino return protocol;
90*e4b17023SJohn Marino }
91*e4b17023SJohn Marino
92*e4b17023SJohn Marino Protocol **
objc_copyProtocolList(unsigned int * numberOfReturnedProtocols)93*e4b17023SJohn Marino objc_copyProtocolList (unsigned int *numberOfReturnedProtocols)
94*e4b17023SJohn Marino {
95*e4b17023SJohn Marino unsigned int count = 0;
96*e4b17023SJohn Marino Protocol **returnValue = NULL;
97*e4b17023SJohn Marino node_ptr node;
98*e4b17023SJohn Marino
99*e4b17023SJohn Marino objc_mutex_lock (__protocols_hashtable_lock);
100*e4b17023SJohn Marino
101*e4b17023SJohn Marino /* Count how many protocols we have. */
102*e4b17023SJohn Marino node = objc_hash_next (__protocols_hashtable, NULL);
103*e4b17023SJohn Marino while (node)
104*e4b17023SJohn Marino {
105*e4b17023SJohn Marino count++;
106*e4b17023SJohn Marino node = objc_hash_next (__protocols_hashtable, node);
107*e4b17023SJohn Marino }
108*e4b17023SJohn Marino
109*e4b17023SJohn Marino if (count != 0)
110*e4b17023SJohn Marino {
111*e4b17023SJohn Marino unsigned int i = 0;
112*e4b17023SJohn Marino
113*e4b17023SJohn Marino /* Allocate enough memory to hold them. */
114*e4b17023SJohn Marino returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
115*e4b17023SJohn Marino
116*e4b17023SJohn Marino /* Copy the protocols. */
117*e4b17023SJohn Marino node = objc_hash_next (__protocols_hashtable, NULL);
118*e4b17023SJohn Marino while (node)
119*e4b17023SJohn Marino {
120*e4b17023SJohn Marino returnValue[i] = node->value;
121*e4b17023SJohn Marino i++;
122*e4b17023SJohn Marino node = objc_hash_next (__protocols_hashtable, node);
123*e4b17023SJohn Marino }
124*e4b17023SJohn Marino
125*e4b17023SJohn Marino returnValue[i] = NULL;
126*e4b17023SJohn Marino }
127*e4b17023SJohn Marino objc_mutex_unlock (__protocols_hashtable_lock);
128*e4b17023SJohn Marino
129*e4b17023SJohn Marino if (numberOfReturnedProtocols)
130*e4b17023SJohn Marino *numberOfReturnedProtocols = count;
131*e4b17023SJohn Marino
132*e4b17023SJohn Marino return returnValue;
133*e4b17023SJohn Marino }
134*e4b17023SJohn Marino
135*e4b17023SJohn Marino BOOL
class_addProtocol(Class class_,Protocol * protocol)136*e4b17023SJohn Marino class_addProtocol (Class class_, Protocol *protocol)
137*e4b17023SJohn Marino {
138*e4b17023SJohn Marino struct objc_protocol_list *protocols;
139*e4b17023SJohn Marino
140*e4b17023SJohn Marino if (class_ == Nil || protocol == NULL)
141*e4b17023SJohn Marino return NO;
142*e4b17023SJohn Marino
143*e4b17023SJohn Marino if (class_conformsToProtocol (class_, protocol))
144*e4b17023SJohn Marino return NO;
145*e4b17023SJohn Marino
146*e4b17023SJohn Marino /* Check that it is a Protocol object before casting it to (struct
147*e4b17023SJohn Marino objc_protocol *). */
148*e4b17023SJohn Marino if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
149*e4b17023SJohn Marino return NO;
150*e4b17023SJohn Marino
151*e4b17023SJohn Marino objc_mutex_lock (__objc_runtime_mutex);
152*e4b17023SJohn Marino
153*e4b17023SJohn Marino /* Create the objc_protocol_list. */
154*e4b17023SJohn Marino protocols = malloc (sizeof (struct objc_protocol_list));
155*e4b17023SJohn Marino protocols->count = 1;
156*e4b17023SJohn Marino protocols->list[0] = (struct objc_protocol *)protocol;
157*e4b17023SJohn Marino
158*e4b17023SJohn Marino /* Attach it to the list of class protocols. */
159*e4b17023SJohn Marino protocols->next = class_->protocols;
160*e4b17023SJohn Marino class_->protocols = protocols;
161*e4b17023SJohn Marino
162*e4b17023SJohn Marino objc_mutex_unlock (__objc_runtime_mutex);
163*e4b17023SJohn Marino
164*e4b17023SJohn Marino return YES;
165*e4b17023SJohn Marino }
166*e4b17023SJohn Marino
167*e4b17023SJohn Marino BOOL
class_conformsToProtocol(Class class_,Protocol * protocol)168*e4b17023SJohn Marino class_conformsToProtocol (Class class_, Protocol *protocol)
169*e4b17023SJohn Marino {
170*e4b17023SJohn Marino struct objc_protocol_list* proto_list;
171*e4b17023SJohn Marino
172*e4b17023SJohn Marino if (class_ == Nil || protocol == NULL)
173*e4b17023SJohn Marino return NO;
174*e4b17023SJohn Marino
175*e4b17023SJohn Marino /* Check that it is a Protocol object before casting it to (struct
176*e4b17023SJohn Marino objc_protocol *). */
177*e4b17023SJohn Marino if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
178*e4b17023SJohn Marino return NO;
179*e4b17023SJohn Marino
180*e4b17023SJohn Marino /* Acquire the runtime lock because the list of protocols for a
181*e4b17023SJohn Marino class may be modified concurrently, for example if another thread
182*e4b17023SJohn Marino calls class_addProtocol(), or dynamically loads from a file a
183*e4b17023SJohn Marino category of the class. */
184*e4b17023SJohn Marino objc_mutex_lock (__objc_runtime_mutex);
185*e4b17023SJohn Marino proto_list = class_->protocols;
186*e4b17023SJohn Marino
187*e4b17023SJohn Marino while (proto_list)
188*e4b17023SJohn Marino {
189*e4b17023SJohn Marino size_t i;
190*e4b17023SJohn Marino for (i = 0; i < proto_list->count; i++)
191*e4b17023SJohn Marino {
192*e4b17023SJohn Marino if (proto_list->list[i] == (struct objc_protocol *)protocol
193*e4b17023SJohn Marino || protocol_conformsToProtocol ((Protocol *)proto_list->list[i],
194*e4b17023SJohn Marino protocol))
195*e4b17023SJohn Marino {
196*e4b17023SJohn Marino objc_mutex_unlock (__objc_runtime_mutex);
197*e4b17023SJohn Marino return YES;
198*e4b17023SJohn Marino }
199*e4b17023SJohn Marino }
200*e4b17023SJohn Marino proto_list = proto_list->next;
201*e4b17023SJohn Marino }
202*e4b17023SJohn Marino
203*e4b17023SJohn Marino objc_mutex_unlock (__objc_runtime_mutex);
204*e4b17023SJohn Marino return NO;
205*e4b17023SJohn Marino }
206*e4b17023SJohn Marino
207*e4b17023SJohn Marino Protocol **
class_copyProtocolList(Class class_,unsigned int * numberOfReturnedProtocols)208*e4b17023SJohn Marino class_copyProtocolList (Class class_, unsigned int *numberOfReturnedProtocols)
209*e4b17023SJohn Marino {
210*e4b17023SJohn Marino unsigned int count = 0;
211*e4b17023SJohn Marino Protocol **returnValue = NULL;
212*e4b17023SJohn Marino struct objc_protocol_list* proto_list;
213*e4b17023SJohn Marino
214*e4b17023SJohn Marino if (class_ == Nil)
215*e4b17023SJohn Marino {
216*e4b17023SJohn Marino if (numberOfReturnedProtocols)
217*e4b17023SJohn Marino *numberOfReturnedProtocols = 0;
218*e4b17023SJohn Marino return NULL;
219*e4b17023SJohn Marino }
220*e4b17023SJohn Marino
221*e4b17023SJohn Marino /* Lock the runtime mutex because the class protocols may be
222*e4b17023SJohn Marino concurrently modified. */
223*e4b17023SJohn Marino objc_mutex_lock (__objc_runtime_mutex);
224*e4b17023SJohn Marino
225*e4b17023SJohn Marino /* Count how many protocols we have. */
226*e4b17023SJohn Marino proto_list = class_->protocols;
227*e4b17023SJohn Marino
228*e4b17023SJohn Marino while (proto_list)
229*e4b17023SJohn Marino {
230*e4b17023SJohn Marino count = count + proto_list->count;
231*e4b17023SJohn Marino proto_list = proto_list->next;
232*e4b17023SJohn Marino }
233*e4b17023SJohn Marino
234*e4b17023SJohn Marino if (count != 0)
235*e4b17023SJohn Marino {
236*e4b17023SJohn Marino unsigned int i = 0;
237*e4b17023SJohn Marino
238*e4b17023SJohn Marino /* Allocate enough memory to hold them. */
239*e4b17023SJohn Marino returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
240*e4b17023SJohn Marino
241*e4b17023SJohn Marino /* Copy the protocols. */
242*e4b17023SJohn Marino proto_list = class_->protocols;
243*e4b17023SJohn Marino
244*e4b17023SJohn Marino while (proto_list)
245*e4b17023SJohn Marino {
246*e4b17023SJohn Marino size_t j;
247*e4b17023SJohn Marino for (j = 0; j < proto_list->count; j++)
248*e4b17023SJohn Marino {
249*e4b17023SJohn Marino returnValue[i] = (Protocol *)proto_list->list[j];
250*e4b17023SJohn Marino i++;
251*e4b17023SJohn Marino }
252*e4b17023SJohn Marino proto_list = proto_list->next;
253*e4b17023SJohn Marino }
254*e4b17023SJohn Marino
255*e4b17023SJohn Marino returnValue[i] = NULL;
256*e4b17023SJohn Marino }
257*e4b17023SJohn Marino objc_mutex_unlock (__objc_runtime_mutex);
258*e4b17023SJohn Marino
259*e4b17023SJohn Marino if (numberOfReturnedProtocols)
260*e4b17023SJohn Marino *numberOfReturnedProtocols = count;
261*e4b17023SJohn Marino
262*e4b17023SJohn Marino return returnValue;
263*e4b17023SJohn Marino }
264*e4b17023SJohn Marino
265*e4b17023SJohn Marino BOOL
protocol_conformsToProtocol(Protocol * protocol,Protocol * anotherProtocol)266*e4b17023SJohn Marino protocol_conformsToProtocol (Protocol *protocol, Protocol *anotherProtocol)
267*e4b17023SJohn Marino {
268*e4b17023SJohn Marino struct objc_protocol_list* proto_list;
269*e4b17023SJohn Marino
270*e4b17023SJohn Marino if (protocol == NULL || anotherProtocol == NULL)
271*e4b17023SJohn Marino return NO;
272*e4b17023SJohn Marino
273*e4b17023SJohn Marino if (protocol == anotherProtocol)
274*e4b17023SJohn Marino return YES;
275*e4b17023SJohn Marino
276*e4b17023SJohn Marino /* Check that the objects are Protocol objects before casting them
277*e4b17023SJohn Marino to (struct objc_protocol *). */
278*e4b17023SJohn Marino if (protocol->class_pointer != anotherProtocol->class_pointer)
279*e4b17023SJohn Marino return NO;
280*e4b17023SJohn Marino
281*e4b17023SJohn Marino if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
282*e4b17023SJohn Marino return NO;
283*e4b17023SJohn Marino
284*e4b17023SJohn Marino if (strcmp (((struct objc_protocol *)protocol)->protocol_name,
285*e4b17023SJohn Marino ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0)
286*e4b17023SJohn Marino return YES;
287*e4b17023SJohn Marino
288*e4b17023SJohn Marino /* We do not acquire any lock because protocols are currently
289*e4b17023SJohn Marino immutable. We can freely iterate over a protocol structure. */
290*e4b17023SJohn Marino proto_list = ((struct objc_protocol *)protocol)->protocol_list;
291*e4b17023SJohn Marino while (proto_list)
292*e4b17023SJohn Marino {
293*e4b17023SJohn Marino size_t i;
294*e4b17023SJohn Marino
295*e4b17023SJohn Marino for (i = 0; i < proto_list->count; i++)
296*e4b17023SJohn Marino {
297*e4b17023SJohn Marino if (protocol_conformsToProtocol ((Protocol *)proto_list->list[i], anotherProtocol))
298*e4b17023SJohn Marino return YES;
299*e4b17023SJohn Marino }
300*e4b17023SJohn Marino proto_list = proto_list->next;
301*e4b17023SJohn Marino }
302*e4b17023SJohn Marino
303*e4b17023SJohn Marino return NO;
304*e4b17023SJohn Marino }
305*e4b17023SJohn Marino
306*e4b17023SJohn Marino BOOL
protocol_isEqual(Protocol * protocol,Protocol * anotherProtocol)307*e4b17023SJohn Marino protocol_isEqual (Protocol *protocol, Protocol *anotherProtocol)
308*e4b17023SJohn Marino {
309*e4b17023SJohn Marino if (protocol == anotherProtocol)
310*e4b17023SJohn Marino return YES;
311*e4b17023SJohn Marino
312*e4b17023SJohn Marino if (protocol == NULL || anotherProtocol == NULL)
313*e4b17023SJohn Marino return NO;
314*e4b17023SJohn Marino
315*e4b17023SJohn Marino /* Check that the objects are Protocol objects before casting them
316*e4b17023SJohn Marino to (struct objc_protocol *). */
317*e4b17023SJohn Marino if (protocol->class_pointer != anotherProtocol->class_pointer)
318*e4b17023SJohn Marino return NO;
319*e4b17023SJohn Marino
320*e4b17023SJohn Marino if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
321*e4b17023SJohn Marino return NO;
322*e4b17023SJohn Marino
323*e4b17023SJohn Marino /* Equality between formal protocols is only formal (nothing to do
324*e4b17023SJohn Marino with actually checking the list of methods they have!). Two
325*e4b17023SJohn Marino formal Protocols are equal if and only if they have the same
326*e4b17023SJohn Marino name.
327*e4b17023SJohn Marino
328*e4b17023SJohn Marino Please note (for comparisons with other implementations) that
329*e4b17023SJohn Marino checking the names is equivalent to checking that Protocol A
330*e4b17023SJohn Marino conforms to Protocol B and Protocol B conforms to Protocol A,
331*e4b17023SJohn Marino because this happens iff they have the same name. If they have
332*e4b17023SJohn Marino different names, A conforms to B if and only if A includes B, but
333*e4b17023SJohn Marino the situation where A includes B and B includes A is a circular
334*e4b17023SJohn Marino dependency between Protocols which is forbidden by the compiler,
335*e4b17023SJohn Marino so A conforms to B and B conforms to A with A and B having
336*e4b17023SJohn Marino different names is an impossible case. */
337*e4b17023SJohn Marino if (strcmp (((struct objc_protocol *)protocol)->protocol_name,
338*e4b17023SJohn Marino ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0)
339*e4b17023SJohn Marino return YES;
340*e4b17023SJohn Marino
341*e4b17023SJohn Marino return NO;
342*e4b17023SJohn Marino }
343*e4b17023SJohn Marino
344*e4b17023SJohn Marino const char *
protocol_getName(Protocol * protocol)345*e4b17023SJohn Marino protocol_getName (Protocol *protocol)
346*e4b17023SJohn Marino {
347*e4b17023SJohn Marino /* Check that it is a Protocol object before casting it to (struct
348*e4b17023SJohn Marino objc_protocol *). */
349*e4b17023SJohn Marino if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
350*e4b17023SJohn Marino return NULL;
351*e4b17023SJohn Marino
352*e4b17023SJohn Marino return ((struct objc_protocol *)protocol)->protocol_name;
353*e4b17023SJohn Marino }
354*e4b17023SJohn Marino
protocol_getMethodDescription(Protocol * protocol,SEL selector,BOOL requiredMethod,BOOL instanceMethod)355*e4b17023SJohn Marino struct objc_method_description protocol_getMethodDescription (Protocol *protocol,
356*e4b17023SJohn Marino SEL selector,
357*e4b17023SJohn Marino BOOL requiredMethod,
358*e4b17023SJohn Marino BOOL instanceMethod)
359*e4b17023SJohn Marino {
360*e4b17023SJohn Marino struct objc_method_description no_result = { NULL, NULL };
361*e4b17023SJohn Marino struct objc_method_description_list *methods;
362*e4b17023SJohn Marino int i;
363*e4b17023SJohn Marino
364*e4b17023SJohn Marino /* TODO: New ABI. */
365*e4b17023SJohn Marino /* The current ABI does not have any information on optional protocol methods. */
366*e4b17023SJohn Marino if (! requiredMethod)
367*e4b17023SJohn Marino return no_result;
368*e4b17023SJohn Marino
369*e4b17023SJohn Marino /* Check that it is a Protocol object before casting it to (struct
370*e4b17023SJohn Marino objc_protocol *). */
371*e4b17023SJohn Marino if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
372*e4b17023SJohn Marino return no_result;
373*e4b17023SJohn Marino
374*e4b17023SJohn Marino if (instanceMethod)
375*e4b17023SJohn Marino methods = ((struct objc_protocol *)protocol)->instance_methods;
376*e4b17023SJohn Marino else
377*e4b17023SJohn Marino methods = ((struct objc_protocol *)protocol)->class_methods;
378*e4b17023SJohn Marino
379*e4b17023SJohn Marino if (methods)
380*e4b17023SJohn Marino {
381*e4b17023SJohn Marino for (i = 0; i < methods->count; i++)
382*e4b17023SJohn Marino {
383*e4b17023SJohn Marino if (sel_isEqual (methods->list[i].name, selector))
384*e4b17023SJohn Marino return methods->list[i];
385*e4b17023SJohn Marino /*
386*e4b17023SJohn Marino if (strcmp (sel_getName (methods->list[i].name), selector_name) == 0)
387*e4b17023SJohn Marino return methods->list[i];
388*e4b17023SJohn Marino */
389*e4b17023SJohn Marino }
390*e4b17023SJohn Marino }
391*e4b17023SJohn Marino
392*e4b17023SJohn Marino return no_result;
393*e4b17023SJohn Marino }
394*e4b17023SJohn Marino
protocol_copyMethodDescriptionList(Protocol * protocol,BOOL requiredMethod,BOOL instanceMethod,unsigned int * numberOfReturnedMethods)395*e4b17023SJohn Marino struct objc_method_description *protocol_copyMethodDescriptionList (Protocol *protocol,
396*e4b17023SJohn Marino BOOL requiredMethod,
397*e4b17023SJohn Marino BOOL instanceMethod,
398*e4b17023SJohn Marino unsigned int *numberOfReturnedMethods)
399*e4b17023SJohn Marino {
400*e4b17023SJohn Marino struct objc_method_description_list *methods;
401*e4b17023SJohn Marino unsigned int count = 0;
402*e4b17023SJohn Marino struct objc_method_description *returnValue = NULL;
403*e4b17023SJohn Marino
404*e4b17023SJohn Marino /* TODO: New ABI */
405*e4b17023SJohn Marino /* The current ABI does not have any information on optional protocol methods. */
406*e4b17023SJohn Marino if (! requiredMethod)
407*e4b17023SJohn Marino {
408*e4b17023SJohn Marino if (numberOfReturnedMethods)
409*e4b17023SJohn Marino *numberOfReturnedMethods = 0;
410*e4b17023SJohn Marino
411*e4b17023SJohn Marino return NULL;
412*e4b17023SJohn Marino }
413*e4b17023SJohn Marino
414*e4b17023SJohn Marino /* Check that it is a Protocol object before casting it to (struct
415*e4b17023SJohn Marino objc_protocol *). */
416*e4b17023SJohn Marino if (protocol == NULL || protocol->class_pointer != objc_lookUpClass ("Protocol"))
417*e4b17023SJohn Marino {
418*e4b17023SJohn Marino if (numberOfReturnedMethods)
419*e4b17023SJohn Marino *numberOfReturnedMethods = 0;
420*e4b17023SJohn Marino
421*e4b17023SJohn Marino return NULL;
422*e4b17023SJohn Marino }
423*e4b17023SJohn Marino
424*e4b17023SJohn Marino /* We do not acquire any lock because protocols are currently
425*e4b17023SJohn Marino immutable. We can freely iterate over a protocol structure. */
426*e4b17023SJohn Marino
427*e4b17023SJohn Marino if (instanceMethod)
428*e4b17023SJohn Marino methods = ((struct objc_protocol *)protocol)->instance_methods;
429*e4b17023SJohn Marino else
430*e4b17023SJohn Marino methods = ((struct objc_protocol *)protocol)->class_methods;
431*e4b17023SJohn Marino
432*e4b17023SJohn Marino if (methods)
433*e4b17023SJohn Marino {
434*e4b17023SJohn Marino unsigned int i;
435*e4b17023SJohn Marino count = methods->count;
436*e4b17023SJohn Marino
437*e4b17023SJohn Marino /* Allocate enough memory to hold them. */
438*e4b17023SJohn Marino returnValue = (struct objc_method_description *)(malloc (sizeof (struct objc_method_description) * (count + 1)));
439*e4b17023SJohn Marino
440*e4b17023SJohn Marino /* Copy them. */
441*e4b17023SJohn Marino for (i = 0; i < count; i++)
442*e4b17023SJohn Marino {
443*e4b17023SJohn Marino returnValue[i].name = methods->list[i].name;
444*e4b17023SJohn Marino returnValue[i].types = methods->list[i].types;
445*e4b17023SJohn Marino }
446*e4b17023SJohn Marino returnValue[i].name = NULL;
447*e4b17023SJohn Marino returnValue[i].types = NULL;
448*e4b17023SJohn Marino }
449*e4b17023SJohn Marino
450*e4b17023SJohn Marino if (numberOfReturnedMethods)
451*e4b17023SJohn Marino *numberOfReturnedMethods = count;
452*e4b17023SJohn Marino
453*e4b17023SJohn Marino return returnValue;
454*e4b17023SJohn Marino }
455*e4b17023SJohn Marino
protocol_getProperty(Protocol * protocol,const char * propertyName,BOOL requiredProperty,BOOL instanceProperty)456*e4b17023SJohn Marino Property protocol_getProperty (Protocol *protocol, const char *propertyName,
457*e4b17023SJohn Marino BOOL requiredProperty, BOOL instanceProperty)
458*e4b17023SJohn Marino {
459*e4b17023SJohn Marino if (protocol == NULL || propertyName == NULL)
460*e4b17023SJohn Marino return NULL;
461*e4b17023SJohn Marino
462*e4b17023SJohn Marino if (!requiredProperty || !instanceProperty)
463*e4b17023SJohn Marino return NULL;
464*e4b17023SJohn Marino
465*e4b17023SJohn Marino /* Check that it is a Protocol object before casting it to (struct
466*e4b17023SJohn Marino objc_protocol *). */
467*e4b17023SJohn Marino if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
468*e4b17023SJohn Marino return NULL;
469*e4b17023SJohn Marino
470*e4b17023SJohn Marino /* TODO: New ABI. */
471*e4b17023SJohn Marino /* The current ABI does not have any information on protocol properties. */
472*e4b17023SJohn Marino return NULL;
473*e4b17023SJohn Marino }
474*e4b17023SJohn Marino
protocol_copyPropertyList(Protocol * protocol,unsigned int * numberOfReturnedProperties)475*e4b17023SJohn Marino Property *protocol_copyPropertyList (Protocol *protocol, unsigned int *numberOfReturnedProperties)
476*e4b17023SJohn Marino {
477*e4b17023SJohn Marino unsigned int count = 0;
478*e4b17023SJohn Marino Property *returnValue = NULL;
479*e4b17023SJohn Marino
480*e4b17023SJohn Marino /* Check that it is a Protocol object before casting it to (struct
481*e4b17023SJohn Marino objc_protocol *). */
482*e4b17023SJohn Marino if (protocol == NULL || protocol->class_pointer != objc_lookUpClass ("Protocol"))
483*e4b17023SJohn Marino {
484*e4b17023SJohn Marino if (numberOfReturnedProperties)
485*e4b17023SJohn Marino *numberOfReturnedProperties = 0;
486*e4b17023SJohn Marino
487*e4b17023SJohn Marino return NULL;
488*e4b17023SJohn Marino }
489*e4b17023SJohn Marino
490*e4b17023SJohn Marino /* We do not acquire any lock because protocols are currently
491*e4b17023SJohn Marino immutable. We can freely iterate over a protocol structure. */
492*e4b17023SJohn Marino
493*e4b17023SJohn Marino /* TODO: New ABI. */
494*e4b17023SJohn Marino /* The current ABI does not have any information on protocol properties. */
495*e4b17023SJohn Marino if (numberOfReturnedProperties)
496*e4b17023SJohn Marino *numberOfReturnedProperties = count;
497*e4b17023SJohn Marino
498*e4b17023SJohn Marino return returnValue;
499*e4b17023SJohn Marino }
500*e4b17023SJohn Marino
protocol_copyProtocolList(Protocol * protocol,unsigned int * numberOfReturnedProtocols)501*e4b17023SJohn Marino Protocol **protocol_copyProtocolList (Protocol *protocol, unsigned int *numberOfReturnedProtocols)
502*e4b17023SJohn Marino {
503*e4b17023SJohn Marino unsigned int count = 0;
504*e4b17023SJohn Marino Protocol **returnValue = NULL;
505*e4b17023SJohn Marino struct objc_protocol_list* proto_list;
506*e4b17023SJohn Marino
507*e4b17023SJohn Marino /* Check that it is a Protocol object before casting it to (struct
508*e4b17023SJohn Marino objc_protocol *). */
509*e4b17023SJohn Marino if (protocol == NULL || protocol->class_pointer != objc_lookUpClass ("Protocol"))
510*e4b17023SJohn Marino {
511*e4b17023SJohn Marino if (numberOfReturnedProtocols)
512*e4b17023SJohn Marino *numberOfReturnedProtocols = 0;
513*e4b17023SJohn Marino
514*e4b17023SJohn Marino return NULL;
515*e4b17023SJohn Marino }
516*e4b17023SJohn Marino
517*e4b17023SJohn Marino /* We do not acquire any lock because protocols are currently
518*e4b17023SJohn Marino immutable. We can freely iterate over a protocol structure. */
519*e4b17023SJohn Marino
520*e4b17023SJohn Marino /* Count how many protocols we have. */
521*e4b17023SJohn Marino proto_list = ((struct objc_protocol *)protocol)->protocol_list;
522*e4b17023SJohn Marino
523*e4b17023SJohn Marino while (proto_list)
524*e4b17023SJohn Marino {
525*e4b17023SJohn Marino count = count + proto_list->count;
526*e4b17023SJohn Marino proto_list = proto_list->next;
527*e4b17023SJohn Marino }
528*e4b17023SJohn Marino
529*e4b17023SJohn Marino if (count != 0)
530*e4b17023SJohn Marino {
531*e4b17023SJohn Marino unsigned int i = 0;
532*e4b17023SJohn Marino
533*e4b17023SJohn Marino /* Allocate enough memory to hold them. */
534*e4b17023SJohn Marino returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
535*e4b17023SJohn Marino
536*e4b17023SJohn Marino /* Copy the protocols. */
537*e4b17023SJohn Marino proto_list = ((struct objc_protocol *)protocol)->protocol_list;
538*e4b17023SJohn Marino
539*e4b17023SJohn Marino while (proto_list)
540*e4b17023SJohn Marino {
541*e4b17023SJohn Marino size_t j;
542*e4b17023SJohn Marino for (j = 0; j < proto_list->count; j++)
543*e4b17023SJohn Marino {
544*e4b17023SJohn Marino returnValue[i] = (Protocol *)proto_list->list[j];
545*e4b17023SJohn Marino i++;
546*e4b17023SJohn Marino }
547*e4b17023SJohn Marino proto_list = proto_list->next;
548*e4b17023SJohn Marino }
549*e4b17023SJohn Marino
550*e4b17023SJohn Marino returnValue[i] = NULL;
551*e4b17023SJohn Marino }
552*e4b17023SJohn Marino
553*e4b17023SJohn Marino if (numberOfReturnedProtocols)
554*e4b17023SJohn Marino *numberOfReturnedProtocols = count;
555*e4b17023SJohn Marino
556*e4b17023SJohn Marino return returnValue;
557*e4b17023SJohn Marino }
558