mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			558 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			558 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
/* GNU Objective C Runtime protocol related functions.
 | 
						|
   Copyright (C) 2010-2013 Free Software Foundation, Inc.
 | 
						|
   Contributed by Nicola Pero
 | 
						|
 | 
						|
This file is part of GCC.
 | 
						|
 | 
						|
GCC is free software; you can redistribute it and/or modify it under the
 | 
						|
terms of the GNU General Public License as published by the Free Software
 | 
						|
Foundation; either version 3, or (at your option) any later version.
 | 
						|
 | 
						|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 | 
						|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
						|
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 | 
						|
details.
 | 
						|
 | 
						|
Under Section 7 of GPL version 3, you are granted additional
 | 
						|
permissions described in the GCC Runtime Library Exception, version
 | 
						|
3.1, as published by the Free Software Foundation.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License and
 | 
						|
a copy of the GCC Runtime Library Exception along with this program;
 | 
						|
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 | 
						|
<http://www.gnu.org/licenses/>.  */
 | 
						|
 | 
						|
#include "objc-private/common.h"
 | 
						|
#include "objc/runtime.h"
 | 
						|
#include "objc-private/module-abi-8.h" /* For runtime structures  */
 | 
						|
#include "objc/thr.h"
 | 
						|
#include "objc-private/runtime.h"      /* the kitchen sink */
 | 
						|
#include "objc-private/hash.h"         /* For the hash table of protocols.  */
 | 
						|
#include "objc-private/protocols.h"    /* For __objc_protocols_init() and
 | 
						|
                                          __objc_protocols_add_protocol().  */
 | 
						|
#include <stdlib.h>                    /* For malloc.  */
 | 
						|
 | 
						|
/* This is a table that maps a name to a Protocol instance with that
 | 
						|
   name.  Because there may be multiple Protocol instances with the
 | 
						|
   same name (no harm in that) the table records only one
 | 
						|
   instance.  */
 | 
						|
static cache_ptr __protocols_hashtable;
 | 
						|
 | 
						|
/* A mutex protecting the protocol_hashtable.  */
 | 
						|
static objc_mutex_t __protocols_hashtable_lock = NULL;
 | 
						|
 | 
						|
/* Called at startup by init.c.  */
 | 
						|
void
 | 
						|
__objc_protocols_init (void)
 | 
						|
{
 | 
						|
  __protocols_hashtable_lock = objc_mutex_allocate ();
 | 
						|
 | 
						|
  /* The keys in the table are strings, and the values are Protocol
 | 
						|
     objects.  */
 | 
						|
  __protocols_hashtable = objc_hash_new (64, (hash_func_type) objc_hash_string,
 | 
						|
					 (compare_func_type) objc_compare_strings);
 | 
						|
}
 | 
						|
 | 
						|
/* Add a protocol to the hashtable.  */
 | 
						|
void
 | 
						|
__objc_protocols_add_protocol (const char *name, struct objc_protocol *object)
 | 
						|
{
 | 
						|
  objc_mutex_lock (__protocols_hashtable_lock);
 | 
						|
 | 
						|
  /* If we find a protocol with the same name already in the
 | 
						|
     hashtable, we do not need to add the new one, because it will be
 | 
						|
     identical to it.  This in the reasonable assumption that two
 | 
						|
     protocols with the same name are identical, which is expected in
 | 
						|
     any sane program.  If we are really paranoid, we would compare
 | 
						|
     the protocols and abort if they are not identical.
 | 
						|
     Unfortunately, this would slow down the startup of all
 | 
						|
     Objective-C programs while trying to catch a problem that has
 | 
						|
     never been seen in practice, so we don't do it.  */
 | 
						|
  if (! objc_hash_is_key_in_hash (__protocols_hashtable, name))
 | 
						|
    objc_hash_add (&__protocols_hashtable, name, object);
 | 
						|
 | 
						|
  objc_mutex_unlock (__protocols_hashtable_lock);
 | 
						|
}
 | 
						|
 | 
						|
Protocol *
 | 
						|
objc_getProtocol (const char *name)
 | 
						|
{
 | 
						|
  Protocol *protocol;
 | 
						|
 | 
						|
  if (name == NULL)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  objc_mutex_lock (__protocols_hashtable_lock);
 | 
						|
  protocol = (Protocol *)(objc_hash_value_for_key (__protocols_hashtable, name));
 | 
						|
  objc_mutex_unlock (__protocols_hashtable_lock);
 | 
						|
 | 
						|
  return protocol;
 | 
						|
}
 | 
						|
 | 
						|
Protocol **
 | 
						|
objc_copyProtocolList (unsigned int *numberOfReturnedProtocols)
 | 
						|
{
 | 
						|
  unsigned int count = 0;
 | 
						|
  Protocol **returnValue = NULL;
 | 
						|
  node_ptr node;
 | 
						|
 | 
						|
  objc_mutex_lock (__protocols_hashtable_lock);
 | 
						|
 | 
						|
  /* Count how many protocols we have.  */
 | 
						|
  node = objc_hash_next (__protocols_hashtable, NULL);
 | 
						|
  while (node)
 | 
						|
    {
 | 
						|
      count++;
 | 
						|
      node = objc_hash_next (__protocols_hashtable, node);
 | 
						|
    }
 | 
						|
 | 
						|
  if (count != 0)
 | 
						|
    {
 | 
						|
      unsigned int i = 0;
 | 
						|
 | 
						|
      /* Allocate enough memory to hold them.  */
 | 
						|
      returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
 | 
						|
      
 | 
						|
      /* Copy the protocols.  */
 | 
						|
      node = objc_hash_next (__protocols_hashtable, NULL);
 | 
						|
      while (node)
 | 
						|
	{
 | 
						|
	  returnValue[i] = node->value;
 | 
						|
	  i++;
 | 
						|
	  node = objc_hash_next (__protocols_hashtable, node);
 | 
						|
	}
 | 
						|
 | 
						|
      returnValue[i] = NULL;
 | 
						|
    }
 | 
						|
  objc_mutex_unlock (__protocols_hashtable_lock);
 | 
						|
 | 
						|
  if (numberOfReturnedProtocols)
 | 
						|
    *numberOfReturnedProtocols = count;
 | 
						|
 | 
						|
  return returnValue;
 | 
						|
}
 | 
						|
 | 
						|
BOOL 
 | 
						|
class_addProtocol (Class class_, Protocol *protocol)
 | 
						|
{
 | 
						|
  struct objc_protocol_list *protocols;
 | 
						|
 | 
						|
  if (class_ == Nil  ||  protocol == NULL)
 | 
						|
    return NO;
 | 
						|
 | 
						|
  if (class_conformsToProtocol (class_, protocol))
 | 
						|
    return NO;
 | 
						|
 | 
						|
  /* Check that it is a Protocol object before casting it to (struct
 | 
						|
     objc_protocol *).  */
 | 
						|
  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    return NO;
 | 
						|
 | 
						|
  objc_mutex_lock (__objc_runtime_mutex);
 | 
						|
 | 
						|
  /* Create the objc_protocol_list.  */
 | 
						|
  protocols = malloc (sizeof (struct objc_protocol_list));
 | 
						|
  protocols->count = 1;
 | 
						|
  protocols->list[0] = (struct objc_protocol *)protocol;
 | 
						|
 | 
						|
  /* Attach it to the list of class protocols.  */
 | 
						|
  protocols->next = class_->protocols;
 | 
						|
  class_->protocols = protocols;
 | 
						|
 | 
						|
  objc_mutex_unlock (__objc_runtime_mutex);
 | 
						|
 | 
						|
  return YES;
 | 
						|
}
 | 
						|
 | 
						|
BOOL 
 | 
						|
class_conformsToProtocol (Class class_, Protocol *protocol)
 | 
						|
{
 | 
						|
  struct objc_protocol_list* proto_list;
 | 
						|
 | 
						|
  if (class_ == Nil  ||  protocol == NULL)
 | 
						|
    return NO;
 | 
						|
 | 
						|
  /* Check that it is a Protocol object before casting it to (struct
 | 
						|
     objc_protocol *).  */
 | 
						|
  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    return NO;
 | 
						|
 | 
						|
  /* Acquire the runtime lock because the list of protocols for a
 | 
						|
     class may be modified concurrently, for example if another thread
 | 
						|
     calls class_addProtocol(), or dynamically loads from a file a
 | 
						|
     category of the class.  */
 | 
						|
  objc_mutex_lock (__objc_runtime_mutex);
 | 
						|
  proto_list = class_->protocols;
 | 
						|
 | 
						|
  while (proto_list)
 | 
						|
    {
 | 
						|
      size_t i;
 | 
						|
      for (i = 0; i < proto_list->count; i++)
 | 
						|
	{
 | 
						|
	  if (proto_list->list[i] == (struct objc_protocol *)protocol
 | 
						|
	      || protocol_conformsToProtocol ((Protocol *)proto_list->list[i],
 | 
						|
					      protocol))
 | 
						|
	    {
 | 
						|
	      objc_mutex_unlock (__objc_runtime_mutex);
 | 
						|
	      return YES;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      proto_list = proto_list->next;
 | 
						|
    }
 | 
						|
  
 | 
						|
  objc_mutex_unlock (__objc_runtime_mutex);
 | 
						|
  return NO;
 | 
						|
}
 | 
						|
 | 
						|
Protocol **
 | 
						|
class_copyProtocolList (Class class_, unsigned int *numberOfReturnedProtocols)
 | 
						|
{
 | 
						|
  unsigned int count = 0;
 | 
						|
  Protocol **returnValue = NULL;
 | 
						|
  struct objc_protocol_list* proto_list;
 | 
						|
 | 
						|
  if (class_ == Nil)
 | 
						|
    {
 | 
						|
      if (numberOfReturnedProtocols)
 | 
						|
	*numberOfReturnedProtocols = 0;
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Lock the runtime mutex because the class protocols may be
 | 
						|
     concurrently modified.  */
 | 
						|
  objc_mutex_lock (__objc_runtime_mutex);
 | 
						|
 | 
						|
  /* Count how many protocols we have.  */
 | 
						|
  proto_list = class_->protocols;
 | 
						|
 | 
						|
  while (proto_list)
 | 
						|
    {
 | 
						|
      count = count + proto_list->count;
 | 
						|
      proto_list = proto_list->next;
 | 
						|
    }
 | 
						|
 | 
						|
  if (count != 0)
 | 
						|
    {
 | 
						|
      unsigned int i = 0;
 | 
						|
      
 | 
						|
      /* Allocate enough memory to hold them.  */
 | 
						|
      returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
 | 
						|
      
 | 
						|
      /* Copy the protocols.  */
 | 
						|
      proto_list = class_->protocols;
 | 
						|
      
 | 
						|
      while (proto_list)
 | 
						|
	{
 | 
						|
	  size_t j;
 | 
						|
	  for (j = 0; j < proto_list->count; j++)
 | 
						|
	    {
 | 
						|
	      returnValue[i] = (Protocol *)proto_list->list[j];
 | 
						|
	      i++;
 | 
						|
	    }
 | 
						|
	  proto_list = proto_list->next;
 | 
						|
	}
 | 
						|
      
 | 
						|
      returnValue[i] = NULL;
 | 
						|
    }
 | 
						|
  objc_mutex_unlock (__objc_runtime_mutex);
 | 
						|
 | 
						|
  if (numberOfReturnedProtocols)
 | 
						|
    *numberOfReturnedProtocols = count;
 | 
						|
 | 
						|
  return returnValue;
 | 
						|
}
 | 
						|
 | 
						|
BOOL 
 | 
						|
protocol_conformsToProtocol (Protocol *protocol, Protocol *anotherProtocol)
 | 
						|
{
 | 
						|
  struct objc_protocol_list* proto_list;
 | 
						|
 | 
						|
  if (protocol == NULL  ||  anotherProtocol == NULL)
 | 
						|
    return NO;
 | 
						|
 | 
						|
  if (protocol == anotherProtocol)
 | 
						|
    return YES;
 | 
						|
    
 | 
						|
  /* Check that the objects are Protocol objects before casting them
 | 
						|
     to (struct objc_protocol *).  */
 | 
						|
  if (protocol->class_pointer != anotherProtocol->class_pointer)
 | 
						|
    return NO;
 | 
						|
  
 | 
						|
  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    return NO;
 | 
						|
 | 
						|
  if (strcmp (((struct objc_protocol *)protocol)->protocol_name,
 | 
						|
	      ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0)
 | 
						|
    return YES;
 | 
						|
 | 
						|
  /* We do not acquire any lock because protocols are currently
 | 
						|
     immutable.  We can freely iterate over a protocol structure.  */
 | 
						|
  proto_list = ((struct objc_protocol *)protocol)->protocol_list;
 | 
						|
  while (proto_list)
 | 
						|
    {
 | 
						|
      size_t i;
 | 
						|
      
 | 
						|
      for (i = 0; i < proto_list->count; i++)
 | 
						|
	{
 | 
						|
	  if (protocol_conformsToProtocol ((Protocol *)proto_list->list[i], anotherProtocol))
 | 
						|
	    return YES;
 | 
						|
	}
 | 
						|
      proto_list = proto_list->next;
 | 
						|
    }
 | 
						|
 | 
						|
  return NO;
 | 
						|
}
 | 
						|
 | 
						|
BOOL 
 | 
						|
protocol_isEqual (Protocol *protocol, Protocol *anotherProtocol)
 | 
						|
{
 | 
						|
  if (protocol == anotherProtocol)
 | 
						|
    return YES;
 | 
						|
 | 
						|
  if (protocol == NULL  ||  anotherProtocol == NULL)
 | 
						|
    return NO;
 | 
						|
  
 | 
						|
  /* Check that the objects are Protocol objects before casting them
 | 
						|
     to (struct objc_protocol *).  */
 | 
						|
  if (protocol->class_pointer != anotherProtocol->class_pointer)
 | 
						|
    return NO;
 | 
						|
  
 | 
						|
  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    return NO;
 | 
						|
 | 
						|
  /* Equality between formal protocols is only formal (nothing to do
 | 
						|
     with actually checking the list of methods they have!).  Two
 | 
						|
     formal Protocols are equal if and only if they have the same
 | 
						|
     name.
 | 
						|
 | 
						|
     Please note (for comparisons with other implementations) that
 | 
						|
     checking the names is equivalent to checking that Protocol A
 | 
						|
     conforms to Protocol B and Protocol B conforms to Protocol A,
 | 
						|
     because this happens iff they have the same name.  If they have
 | 
						|
     different names, A conforms to B if and only if A includes B, but
 | 
						|
     the situation where A includes B and B includes A is a circular
 | 
						|
     dependency between Protocols which is forbidden by the compiler,
 | 
						|
     so A conforms to B and B conforms to A with A and B having
 | 
						|
     different names is an impossible case.  */
 | 
						|
  if (strcmp (((struct objc_protocol *)protocol)->protocol_name,
 | 
						|
	      ((struct objc_protocol *)anotherProtocol)->protocol_name) == 0)
 | 
						|
    return YES;
 | 
						|
  
 | 
						|
  return NO;
 | 
						|
}
 | 
						|
 | 
						|
const char *
 | 
						|
protocol_getName (Protocol *protocol)
 | 
						|
{
 | 
						|
  /* Check that it is a Protocol object before casting it to (struct
 | 
						|
     objc_protocol *).  */
 | 
						|
  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  return ((struct objc_protocol *)protocol)->protocol_name;
 | 
						|
}
 | 
						|
 | 
						|
struct objc_method_description protocol_getMethodDescription (Protocol *protocol, 
 | 
						|
							      SEL selector,
 | 
						|
							      BOOL requiredMethod,
 | 
						|
							      BOOL instanceMethod)
 | 
						|
{
 | 
						|
  struct objc_method_description no_result = { NULL, NULL };
 | 
						|
  struct objc_method_description_list *methods;
 | 
						|
  int i;
 | 
						|
 | 
						|
  /* TODO: New ABI.  */
 | 
						|
  /* The current ABI does not have any information on optional protocol methods.  */
 | 
						|
  if (! requiredMethod)
 | 
						|
    return no_result;
 | 
						|
 | 
						|
  /* Check that it is a Protocol object before casting it to (struct
 | 
						|
     objc_protocol *).  */
 | 
						|
  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    return no_result;
 | 
						|
 | 
						|
  if (instanceMethod)
 | 
						|
    methods = ((struct objc_protocol *)protocol)->instance_methods;
 | 
						|
  else
 | 
						|
    methods = ((struct objc_protocol *)protocol)->class_methods;
 | 
						|
 | 
						|
  if (methods)
 | 
						|
    {
 | 
						|
      for (i = 0; i < methods->count; i++)
 | 
						|
	{
 | 
						|
	  if (sel_isEqual (methods->list[i].name, selector))
 | 
						|
	    return methods->list[i];
 | 
						|
	  /*
 | 
						|
	  if (strcmp (sel_getName (methods->list[i].name), selector_name) == 0)
 | 
						|
	    return methods->list[i];
 | 
						|
	  */
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return no_result;
 | 
						|
}
 | 
						|
 | 
						|
struct objc_method_description *protocol_copyMethodDescriptionList (Protocol *protocol,
 | 
						|
								    BOOL requiredMethod,
 | 
						|
								    BOOL instanceMethod,
 | 
						|
								    unsigned int *numberOfReturnedMethods)
 | 
						|
{
 | 
						|
  struct objc_method_description_list *methods;
 | 
						|
  unsigned int count = 0;
 | 
						|
  struct objc_method_description *returnValue = NULL;
 | 
						|
 | 
						|
  /* TODO: New ABI */
 | 
						|
  /* The current ABI does not have any information on optional protocol methods.  */
 | 
						|
  if (! requiredMethod)
 | 
						|
    {
 | 
						|
      if (numberOfReturnedMethods)
 | 
						|
	*numberOfReturnedMethods = 0;
 | 
						|
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Check that it is a Protocol object before casting it to (struct
 | 
						|
     objc_protocol *).  */
 | 
						|
  if (protocol == NULL  ||  protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    {
 | 
						|
      if (numberOfReturnedMethods)
 | 
						|
	*numberOfReturnedMethods = 0;
 | 
						|
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  
 | 
						|
  /* We do not acquire any lock because protocols are currently
 | 
						|
     immutable.  We can freely iterate over a protocol structure.  */
 | 
						|
 | 
						|
  if (instanceMethod)
 | 
						|
    methods = ((struct objc_protocol *)protocol)->instance_methods;
 | 
						|
  else
 | 
						|
    methods = ((struct objc_protocol *)protocol)->class_methods;
 | 
						|
 | 
						|
  if (methods)
 | 
						|
    {
 | 
						|
      unsigned int i;
 | 
						|
      count = methods->count;
 | 
						|
 | 
						|
      /* Allocate enough memory to hold them.  */
 | 
						|
      returnValue = (struct objc_method_description *)(malloc (sizeof (struct objc_method_description) * (count + 1)));
 | 
						|
 | 
						|
      /* Copy them.  */
 | 
						|
      for (i = 0; i < count; i++)
 | 
						|
	{
 | 
						|
	  returnValue[i].name = methods->list[i].name;
 | 
						|
	  returnValue[i].types = methods->list[i].types;
 | 
						|
	}
 | 
						|
      returnValue[i].name = NULL;
 | 
						|
      returnValue[i].types = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  if (numberOfReturnedMethods)
 | 
						|
    *numberOfReturnedMethods = count;
 | 
						|
 | 
						|
  return returnValue;
 | 
						|
}
 | 
						|
 | 
						|
Property protocol_getProperty (Protocol *protocol, const char *propertyName, 
 | 
						|
			       BOOL requiredProperty, BOOL instanceProperty)
 | 
						|
{
 | 
						|
  if (protocol == NULL  ||  propertyName == NULL)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  if (!requiredProperty  ||  !instanceProperty)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  /* Check that it is a Protocol object before casting it to (struct
 | 
						|
     objc_protocol *).  */
 | 
						|
  if (protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  /* TODO: New ABI.  */
 | 
						|
  /* The current ABI does not have any information on protocol properties.  */
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
Property *protocol_copyPropertyList (Protocol *protocol, unsigned int *numberOfReturnedProperties)
 | 
						|
{
 | 
						|
  unsigned int count = 0;
 | 
						|
  Property *returnValue = NULL;
 | 
						|
 | 
						|
  /* Check that it is a Protocol object before casting it to (struct
 | 
						|
     objc_protocol *).  */
 | 
						|
  if (protocol == NULL  ||  protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    {
 | 
						|
      if (numberOfReturnedProperties)
 | 
						|
	*numberOfReturnedProperties = 0;
 | 
						|
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  
 | 
						|
  /* We do not acquire any lock because protocols are currently
 | 
						|
     immutable.  We can freely iterate over a protocol structure.  */
 | 
						|
 | 
						|
  /* TODO: New ABI.  */
 | 
						|
  /* The current ABI does not have any information on protocol properties.  */
 | 
						|
  if (numberOfReturnedProperties)
 | 
						|
    *numberOfReturnedProperties = count;
 | 
						|
 | 
						|
  return returnValue;
 | 
						|
}
 | 
						|
 | 
						|
Protocol **protocol_copyProtocolList (Protocol *protocol, unsigned int *numberOfReturnedProtocols)
 | 
						|
{
 | 
						|
  unsigned int count = 0;
 | 
						|
  Protocol **returnValue = NULL;
 | 
						|
  struct objc_protocol_list* proto_list;
 | 
						|
 | 
						|
  /* Check that it is a Protocol object before casting it to (struct
 | 
						|
     objc_protocol *).  */
 | 
						|
  if (protocol == NULL  ||  protocol->class_pointer != objc_lookUpClass ("Protocol"))
 | 
						|
    {
 | 
						|
      if (numberOfReturnedProtocols)
 | 
						|
	*numberOfReturnedProtocols = 0;
 | 
						|
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  
 | 
						|
  /* We do not acquire any lock because protocols are currently
 | 
						|
     immutable.  We can freely iterate over a protocol structure.  */
 | 
						|
 | 
						|
  /* Count how many protocols we have.  */
 | 
						|
  proto_list = ((struct objc_protocol *)protocol)->protocol_list;
 | 
						|
 | 
						|
  while (proto_list)
 | 
						|
    {
 | 
						|
      count = count + proto_list->count;
 | 
						|
      proto_list = proto_list->next;
 | 
						|
    }
 | 
						|
 | 
						|
  if (count != 0)
 | 
						|
    {
 | 
						|
      unsigned int i = 0;
 | 
						|
      
 | 
						|
      /* Allocate enough memory to hold them.  */
 | 
						|
      returnValue = (Protocol **)(malloc (sizeof (Protocol *) * (count + 1)));
 | 
						|
      
 | 
						|
      /* Copy the protocols.  */
 | 
						|
      proto_list = ((struct objc_protocol *)protocol)->protocol_list;
 | 
						|
      
 | 
						|
      while (proto_list)
 | 
						|
	{
 | 
						|
	  size_t j;
 | 
						|
	  for (j = 0; j < proto_list->count; j++)
 | 
						|
	    {
 | 
						|
	      returnValue[i] = (Protocol *)proto_list->list[j];
 | 
						|
	      i++;
 | 
						|
	    }
 | 
						|
	  proto_list = proto_list->next;
 | 
						|
	}
 | 
						|
 | 
						|
      returnValue[i] = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  if (numberOfReturnedProtocols)
 | 
						|
    *numberOfReturnedProtocols = count;
 | 
						|
 | 
						|
  return returnValue;
 | 
						|
}
 |