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