2001-12-17 14:31:42 +00:00
|
|
|
/** Implementation of NSMethodSignature for GNUStep
|
2015-06-26 08:50:17 +00:00
|
|
|
Copyright (C) 1994-2015 Free Software Foundation, Inc.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1995-03-12 19:58:48 +00:00
|
|
|
Date: August 1994
|
1998-08-13 20:45:32 +00:00
|
|
|
Rewritten: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
Date: August 1998
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
This file is part of the GNUstep Base Library.
|
1995-03-12 19:58:48 +00:00
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
modify it under the terms of the GNU Lesser General Public
|
1995-03-12 19:58:48 +00:00
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1995-03-12 19:58:48 +00:00
|
|
|
This library 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
|
2019-12-09 23:36:00 +00:00
|
|
|
Lesser General Public License for more details.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
You should have received a copy of the GNU Lesser General Public
|
1995-03-12 19:58:48 +00:00
|
|
|
License along with this library; if not, write to the Free
|
2024-11-07 13:37:59 +00:00
|
|
|
Software Foundation, Inc., 31 Milk Street #960789 Boston, MA 02196 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
<title>NSMethodSignature class reference</title>
|
|
|
|
$Date$ $Revision$
|
2005-02-22 11:22:44 +00:00
|
|
|
*/
|
1994-11-08 16:44:01 +00:00
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
#import "common.h"
|
2011-05-19 08:19:24 +00:00
|
|
|
|
|
|
|
#if !defined (__GNU_LIBOBJC__)
|
|
|
|
# include <objc/encoding.h>
|
2010-12-23 02:23:05 +00:00
|
|
|
#endif
|
2011-05-19 08:19:24 +00:00
|
|
|
|
2010-02-14 10:48:10 +00:00
|
|
|
#define EXPOSE_NSMethodSignature_IVARS 1
|
1998-01-26 14:18:18 +00:00
|
|
|
|
2010-02-14 10:48:10 +00:00
|
|
|
#import "Foundation/NSMethodSignature.h"
|
|
|
|
#import "Foundation/NSException.h"
|
|
|
|
#import "Foundation/NSCoder.h"
|
1994-11-08 16:44:01 +00:00
|
|
|
|
2024-11-10 16:05:23 +00:00
|
|
|
|
|
|
|
static inline unsigned int
|
|
|
|
gs_string_hash(const char *s)
|
|
|
|
{
|
|
|
|
unsigned int val = 0;
|
|
|
|
while (*s != 0)
|
|
|
|
{
|
|
|
|
val = (val << 5) + val + *s++;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define GSI_MAP_RETAIN_KEY(M, X)
|
|
|
|
#define GSI_MAP_RELEASE_KEY(M, X)
|
|
|
|
#define GSI_MAP_HASH(M, X) (gs_string_hash(X.ptr))
|
|
|
|
#define GSI_MAP_EQUAL(M, X,Y) (strcmp(X.ptr, Y.ptr) == 0)
|
|
|
|
#define GSI_MAP_KTYPES GSUNION_PTR
|
|
|
|
#define GSI_MAP_VTYPES GSUNION_OBJ
|
|
|
|
#import "GNUstepBase/GSIMap.h"
|
|
|
|
|
2010-02-14 10:48:10 +00:00
|
|
|
#import "GSInvocation.h"
|
2024-11-10 16:05:23 +00:00
|
|
|
#import "GSPThread.h"
|
1998-04-30 20:11:42 +00:00
|
|
|
|
2010-03-16 06:11:00 +00:00
|
|
|
#ifdef HAVE_MALLOC_H
|
2015-06-26 08:50:17 +00:00
|
|
|
#if !defined(__OpenBSD__)
|
2010-03-16 06:11:00 +00:00
|
|
|
#include <malloc.h>
|
|
|
|
#endif
|
2015-06-26 08:50:17 +00:00
|
|
|
#endif
|
|
|
|
|
2010-02-25 19:05:21 +00:00
|
|
|
#ifdef HAVE_ALLOCA_H
|
|
|
|
#include <alloca.h>
|
|
|
|
#endif
|
|
|
|
|
2009-10-05 16:00:28 +00:00
|
|
|
/* The objc runtime library objc_skip_offset() is buggy on some compiler
|
|
|
|
* versions, so we use our own alternative implementation.
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
skip_offset(const char *ptr)
|
|
|
|
{
|
|
|
|
if (*ptr == '+' || *ptr == '-') ptr++;
|
|
|
|
while (isdigit(*ptr)) ptr++;
|
|
|
|
return ptr;
|
|
|
|
}
|
1994-11-08 16:44:01 +00:00
|
|
|
|
2009-10-05 16:00:28 +00:00
|
|
|
#define ROUND(V, A) \
|
2020-12-15 13:01:00 +00:00
|
|
|
({ __typeof__(V) __v=(V); __typeof__(A) __a=(A); \
|
2009-10-05 16:00:28 +00:00
|
|
|
__a*((__v+__a-1)/__a); })
|
|
|
|
|
|
|
|
/* Step through method encoding information extracting details.
|
|
|
|
* If outTypes is non-nul then we copy the qualified type into
|
|
|
|
* the buffer as a nul terminated string and use the values in
|
|
|
|
* this buffer for the qtype and type in info, rather than pointers
|
|
|
|
* to positions in typePtr
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
next_arg(const char *typePtr, NSArgumentInfo *info, char *outTypes)
|
1994-11-08 16:44:01 +00:00
|
|
|
{
|
2009-10-05 16:00:28 +00:00
|
|
|
NSArgumentInfo local;
|
|
|
|
BOOL flag;
|
|
|
|
BOOL negative = NO;
|
|
|
|
|
2013-07-06 07:14:45 +00:00
|
|
|
if (0 == typePtr)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (0 == info)
|
2009-10-05 16:00:28 +00:00
|
|
|
{
|
|
|
|
info = &local;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->qtype = typePtr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip past any type qualifiers - if the caller wants them, return them.
|
|
|
|
*/
|
|
|
|
flag = YES;
|
|
|
|
info->qual = 0;
|
|
|
|
while (flag)
|
|
|
|
{
|
|
|
|
switch (*typePtr)
|
|
|
|
{
|
|
|
|
case _C_CONST: info->qual |= _F_CONST; break;
|
|
|
|
case _C_IN: info->qual |= _F_IN; break;
|
|
|
|
case _C_INOUT: info->qual |= _F_INOUT; break;
|
|
|
|
case _C_OUT: info->qual |= _F_OUT; break;
|
|
|
|
case _C_BYCOPY: info->qual |= _F_BYCOPY; break;
|
|
|
|
#ifdef _C_BYREF
|
|
|
|
case _C_BYREF: info->qual |= _F_BYREF; break;
|
|
|
|
#endif
|
|
|
|
case _C_ONEWAY: info->qual |= _F_ONEWAY; break;
|
|
|
|
#ifdef _C_GCINVISIBLE
|
|
|
|
case _C_GCINVISIBLE: info->qual |= _F_GCINVISIBLE; break;
|
|
|
|
#endif
|
|
|
|
default: flag = NO;
|
|
|
|
}
|
|
|
|
if (flag)
|
|
|
|
{
|
|
|
|
typePtr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
info->type = typePtr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan for size and alignment information.
|
|
|
|
*/
|
|
|
|
switch (*typePtr++)
|
|
|
|
{
|
|
|
|
case _C_ID:
|
|
|
|
info->size = sizeof(id);
|
|
|
|
info->align = __alignof__(id);
|
2012-04-07 13:54:55 +00:00
|
|
|
/* Blocks are encoded as @? */
|
|
|
|
if (*(typePtr) == '?')
|
|
|
|
{
|
|
|
|
typePtr++;
|
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_CLASS:
|
|
|
|
info->size = sizeof(Class);
|
|
|
|
info->align = __alignof__(Class);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_SEL:
|
|
|
|
info->size = sizeof(SEL);
|
|
|
|
info->align = __alignof__(SEL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_CHR:
|
|
|
|
info->size = sizeof(char);
|
|
|
|
info->align = __alignof__(char);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_UCHR:
|
|
|
|
info->size = sizeof(unsigned char);
|
|
|
|
info->align = __alignof__(unsigned char);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_SHT:
|
|
|
|
info->size = sizeof(short);
|
|
|
|
info->align = __alignof__(short);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_USHT:
|
|
|
|
info->size = sizeof(unsigned short);
|
|
|
|
info->align = __alignof__(unsigned short);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_INT:
|
|
|
|
info->size = sizeof(int);
|
|
|
|
info->align = __alignof__(int);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_UINT:
|
|
|
|
info->size = sizeof(unsigned int);
|
|
|
|
info->align = __alignof__(unsigned int);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_LNG:
|
|
|
|
info->size = sizeof(long);
|
|
|
|
info->align = __alignof__(long);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_ULNG:
|
|
|
|
info->size = sizeof(unsigned long);
|
|
|
|
info->align = __alignof__(unsigned long);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_LNG_LNG:
|
|
|
|
info->size = sizeof(long long);
|
|
|
|
info->align = __alignof__(long long);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_ULNG_LNG:
|
|
|
|
info->size = sizeof(unsigned long long);
|
|
|
|
info->align = __alignof__(unsigned long long);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_FLT:
|
|
|
|
info->size = sizeof(float);
|
|
|
|
info->align = __alignof__(float);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_DBL:
|
|
|
|
info->size = sizeof(double);
|
|
|
|
info->align = __alignof__(double);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_PTR:
|
|
|
|
info->size = sizeof(char*);
|
|
|
|
info->align = __alignof__(char*);
|
|
|
|
if (*typePtr == '?')
|
|
|
|
{
|
|
|
|
typePtr++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
typePtr = objc_skip_typespec(typePtr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_ATOM:
|
|
|
|
case _C_CHARPTR:
|
|
|
|
info->size = sizeof(char*);
|
|
|
|
info->align = __alignof__(char*);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_ARY_B:
|
|
|
|
{
|
|
|
|
int length = atoi(typePtr);
|
|
|
|
|
|
|
|
while (isdigit(*typePtr))
|
|
|
|
{
|
|
|
|
typePtr++;
|
|
|
|
}
|
|
|
|
typePtr = next_arg(typePtr, &local, 0);
|
|
|
|
info->size = length * ROUND(local.size, local.align);
|
|
|
|
info->align = local.align;
|
|
|
|
typePtr++; /* Skip end-of-array */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_STRUCT_B:
|
|
|
|
{
|
|
|
|
unsigned int acc_size = 0;
|
|
|
|
unsigned int def_align = objc_alignof_type(typePtr-1);
|
|
|
|
unsigned int acc_align = def_align;
|
|
|
|
const char *ptr = typePtr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip "<name>=" stuff.
|
|
|
|
*/
|
|
|
|
while (*ptr != _C_STRUCT_E && *ptr != '=') ptr++;
|
|
|
|
if (*ptr == '=') typePtr = ptr;
|
|
|
|
typePtr++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Base structure alignment on first element.
|
|
|
|
*/
|
|
|
|
if (*typePtr != _C_STRUCT_E)
|
|
|
|
{
|
|
|
|
typePtr = next_arg(typePtr, &local, 0);
|
|
|
|
if (typePtr == 0)
|
|
|
|
{
|
|
|
|
return 0; /* error */
|
|
|
|
}
|
|
|
|
acc_size = ROUND(acc_size, local.align);
|
|
|
|
acc_size += local.size;
|
|
|
|
acc_align = MAX(local.align, def_align);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Continue accumulating structure size
|
|
|
|
* and adjust alignment if necessary
|
|
|
|
*/
|
|
|
|
while (*typePtr != _C_STRUCT_E)
|
|
|
|
{
|
|
|
|
typePtr = next_arg(typePtr, &local, 0);
|
|
|
|
if (typePtr == 0)
|
|
|
|
{
|
|
|
|
return 0; /* error */
|
|
|
|
}
|
|
|
|
acc_size = ROUND(acc_size, local.align);
|
|
|
|
acc_size += local.size;
|
|
|
|
acc_align = MAX(local.align, acc_align);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Size must be a multiple of alignment
|
|
|
|
*/
|
|
|
|
if (acc_size % acc_align != 0)
|
|
|
|
{
|
|
|
|
acc_size += acc_align - acc_size % acc_align;
|
|
|
|
}
|
|
|
|
info->size = acc_size;
|
|
|
|
info->align = acc_align;
|
|
|
|
typePtr++; /* Skip end-of-struct */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_UNION_B:
|
|
|
|
{
|
|
|
|
unsigned int max_size = 0;
|
|
|
|
unsigned int max_align = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip "<name>=" stuff.
|
|
|
|
*/
|
|
|
|
while (*typePtr != _C_UNION_E)
|
|
|
|
{
|
|
|
|
if (*typePtr++ == '=')
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (*typePtr != _C_UNION_E)
|
|
|
|
{
|
|
|
|
typePtr = next_arg(typePtr, &local, 0);
|
|
|
|
if (typePtr == 0)
|
|
|
|
{
|
|
|
|
return 0; /* error */
|
|
|
|
}
|
|
|
|
max_size = MAX(max_size, local.size);
|
|
|
|
max_align = MAX(max_align, local.align);
|
|
|
|
}
|
|
|
|
info->size = max_size;
|
|
|
|
info->align = max_align;
|
|
|
|
typePtr++; /* Skip end-of-union */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_VOID:
|
|
|
|
info->size = 0;
|
|
|
|
info->align = __alignof__(char*);
|
|
|
|
break;
|
|
|
|
|
2021-08-07 14:37:52 +00:00
|
|
|
#if defined(_C_BOOL) && (!defined(__GNUC__) || __GNUC__ > 2)
|
2015-09-22 09:46:10 +00:00
|
|
|
case _C_BOOL:
|
|
|
|
info->size = sizeof(_Bool);
|
|
|
|
info->align = __alignof__(_Bool);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if defined(_C_BFLD)
|
|
|
|
case _C_BFLD:
|
|
|
|
/* Rely on the runtime to either provide the info or bomb out.
|
|
|
|
* Nowadays we ought to be able to expect modern enough runtimes.
|
|
|
|
*/
|
|
|
|
typePtr--;
|
|
|
|
info->size = objc_sizeof_type(typePtr);
|
|
|
|
info->align = objc_alignof_type(typePtr);
|
|
|
|
typePtr = objc_skip_typespec(typePtr);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(_C_COMPLEX)
|
|
|
|
case _C_COMPLEX:
|
|
|
|
switch (*typePtr++)
|
|
|
|
{
|
|
|
|
case _C_CHR:
|
|
|
|
info->size = sizeof(_Complex char);
|
|
|
|
info->align = __alignof__(_Complex char);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_UCHR:
|
|
|
|
info->size = sizeof(_Complex unsigned char);
|
|
|
|
info->align = __alignof__(_Complex unsigned char);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_SHT:
|
|
|
|
info->size = sizeof(_Complex short);
|
|
|
|
info->align = __alignof__(_Complex short);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_USHT:
|
|
|
|
info->size = sizeof(_Complex unsigned short);
|
|
|
|
info->align = __alignof__(_Complex unsigned short);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_INT:
|
|
|
|
info->size = sizeof(_Complex int);
|
|
|
|
info->align = __alignof__(_Complex int);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_UINT:
|
|
|
|
info->size = sizeof(_Complex unsigned int);
|
|
|
|
info->align = __alignof__(_Complex unsigned int);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_LNG:
|
|
|
|
info->size = sizeof(_Complex long);
|
|
|
|
info->align = __alignof__(_Complex long);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_ULNG:
|
|
|
|
info->size = sizeof(_Complex unsigned long);
|
|
|
|
info->align = __alignof__(_Complex unsigned long);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_LNG_LNG:
|
|
|
|
info->size = sizeof(_Complex long long);
|
|
|
|
info->align = __alignof__(_Complex long long);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_ULNG_LNG:
|
|
|
|
info->size = sizeof(_Complex unsigned long long);
|
|
|
|
info->align = __alignof__(_Complex unsigned long long);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_FLT:
|
|
|
|
info->size = sizeof(_Complex float);
|
|
|
|
info->align = __alignof__(_Complex float);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case _C_DBL:
|
|
|
|
info->size = sizeof(_Complex double);
|
|
|
|
info->align = __alignof__(_Complex double);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
NSLog(@"unknown complex type '%s'", typePtr-2);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2009-10-05 16:00:28 +00:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typePtr == 0)
|
|
|
|
{ /* Error condition. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the type information into the buffer if provided.
|
|
|
|
*/
|
|
|
|
if (outTypes != 0)
|
|
|
|
{
|
|
|
|
unsigned len = typePtr - info->qtype;
|
|
|
|
|
|
|
|
strncpy(outTypes, info->qtype, len);
|
|
|
|
outTypes[len] = '\0';
|
|
|
|
info->qtype = outTypes;
|
|
|
|
info->type = objc_skip_type_qualifiers (outTypes);
|
|
|
|
}
|
1998-04-30 20:11:42 +00:00
|
|
|
|
2009-10-05 16:00:28 +00:00
|
|
|
/*
|
|
|
|
* May tell the caller if the item is stored in a register.
|
|
|
|
*/
|
|
|
|
if (*typePtr == '+')
|
|
|
|
{
|
|
|
|
typePtr++;
|
|
|
|
info->isReg = YES;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
info->isReg = NO;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Cope with negative offsets.
|
|
|
|
*/
|
|
|
|
if (*typePtr == '-')
|
|
|
|
{
|
|
|
|
typePtr++;
|
|
|
|
negative = YES;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* May tell the caller what the stack/register offset is for
|
|
|
|
* this argument.
|
|
|
|
*/
|
|
|
|
info->offset = 0;
|
|
|
|
while (isdigit(*typePtr))
|
|
|
|
{
|
|
|
|
info->offset = info->offset * 10 + (*typePtr++ - '0');
|
|
|
|
}
|
|
|
|
if (negative == YES)
|
|
|
|
{
|
|
|
|
info->offset = -info->offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
return typePtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
@implementation NSMethodSignature
|
|
|
|
|
|
|
|
- (id) _initWithObjCTypes: (const char*)t
|
|
|
|
{
|
|
|
|
const char *p = t;
|
|
|
|
|
2001-04-10 03:27:01 +00:00
|
|
|
if (t == 0 || *t == '\0')
|
|
|
|
{
|
2010-02-25 18:49:31 +00:00
|
|
|
DESTROY(self);
|
2001-04-10 03:27:01 +00:00
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
const char *q;
|
|
|
|
char *args;
|
|
|
|
char *ret;
|
2011-03-07 15:34:06 +00:00
|
|
|
char *end;
|
|
|
|
char *ptr;
|
2011-03-07 11:34:17 +00:00
|
|
|
int alen;
|
2011-03-07 15:34:06 +00:00
|
|
|
int blen;
|
2011-03-07 11:34:17 +00:00
|
|
|
int rlen;
|
2009-10-05 16:00:28 +00:00
|
|
|
|
|
|
|
/* In case we have been given a method encoding string without offsets,
|
|
|
|
* we attempt to generate the frame size and offsets in a new copy of
|
|
|
|
* the types string.
|
|
|
|
*/
|
2011-03-07 15:34:06 +00:00
|
|
|
blen = (strlen(t) + 1) * 16; // Total buffer length
|
|
|
|
ret = alloca(blen);
|
|
|
|
end = ret + blen;
|
1998-04-30 20:11:42 +00:00
|
|
|
|
2009-10-05 16:00:28 +00:00
|
|
|
/* Copy the return type (including qualifiers) with ehough room
|
|
|
|
* after it to store the frame size.
|
|
|
|
*/
|
|
|
|
p = t;
|
|
|
|
p = objc_skip_typespec (p);
|
2011-03-07 15:34:06 +00:00
|
|
|
rlen = p - t;
|
|
|
|
strncpy(ret, t, rlen);
|
|
|
|
ret[rlen] = '\0';
|
|
|
|
ptr = args = ret + rlen + 10; // Allow room for a decimal integer
|
|
|
|
*ptr = '\0';
|
2009-10-05 16:00:28 +00:00
|
|
|
|
|
|
|
/* Skip to the first arg type, taking note of where the qualifiers start.
|
2010-02-18 08:45:00 +00:00
|
|
|
* Assume that casting _argFrameLength to int will not lose information.
|
2009-10-05 16:00:28 +00:00
|
|
|
*/
|
|
|
|
p = skip_offset (p);
|
|
|
|
q = p;
|
|
|
|
p = objc_skip_type_qualifiers (p);
|
|
|
|
while (p && *p)
|
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
|
|
|
_numArgs++;
|
|
|
|
size = objc_promoted_size (p);
|
|
|
|
p = objc_skip_typespec (p);
|
2011-03-07 15:34:06 +00:00
|
|
|
memcpy(ptr, q, p - q);
|
|
|
|
ptr += (p - q);
|
|
|
|
snprintf(ptr, end - ptr, "%d", (int)_argFrameLength);
|
|
|
|
ptr += strlen(ptr);
|
2009-10-05 16:00:28 +00:00
|
|
|
_argFrameLength += size;
|
|
|
|
p = skip_offset (p);
|
|
|
|
q = p;
|
|
|
|
p = objc_skip_type_qualifiers (p);
|
|
|
|
}
|
2011-03-07 15:34:06 +00:00
|
|
|
alen = ptr - args;
|
2011-04-19 16:26:09 +00:00
|
|
|
rlen += sprintf(ret + rlen, "%d", (int)_argFrameLength);
|
2011-03-07 11:34:17 +00:00
|
|
|
|
2011-05-25 11:15:08 +00:00
|
|
|
_methodTypes = NSAllocateCollectable(alen + rlen + 1, 0);
|
2011-03-07 11:34:17 +00:00
|
|
|
strncpy((char*)_methodTypes, ret, rlen);
|
|
|
|
strncpy(((char*)_methodTypes) + rlen, args, alen);
|
|
|
|
((char*)_methodTypes)[alen + rlen] = '\0';
|
2009-10-05 16:00:28 +00:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSMethodSignature*) signatureWithObjCTypes: (const char*)t
|
|
|
|
{
|
2024-11-10 16:05:23 +00:00
|
|
|
GSIMapNode node;
|
|
|
|
NSMethodSignature *sig;
|
|
|
|
|
|
|
|
static GSIMapTable_t cacheTable = {};
|
|
|
|
static gs_mutex_t cacheTableLock = GS_MUTEX_INIT_STATIC;
|
|
|
|
|
|
|
|
GS_MUTEX_LOCK(cacheTableLock);
|
|
|
|
if (cacheTable.zone == 0)
|
|
|
|
{
|
|
|
|
GSIMapInitWithZoneAndCapacity(&cacheTable, [self zone], 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
node = GSIMapNodeForKey(&cacheTable, (GSIMapKey)t);
|
|
|
|
if (node == 0)
|
|
|
|
{
|
|
|
|
sig = [[self alloc] _initWithObjCTypes: t];
|
|
|
|
GSIMapAddPair(&cacheTable, (GSIMapKey)t, (GSIMapVal)(id)sig);
|
|
|
|
} else {
|
|
|
|
sig = RETAIN(node->value.obj);
|
|
|
|
}
|
|
|
|
GS_MUTEX_UNLOCK(cacheTableLock);
|
|
|
|
|
|
|
|
return AUTORELEASE(sig);
|
1994-11-08 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
- (NSArgumentInfo) argumentInfoAtIndex: (NSUInteger)index
|
1994-11-08 16:44:01 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
if (index >= _numArgs)
|
|
|
|
{
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
format: @"Index too high."];
|
1998-02-03 14:20:00 +00:00
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
if (_inf == 0)
|
1999-09-16 07:21:34 +00:00
|
|
|
{
|
|
|
|
[self methodInfo];
|
2011-02-11 14:31:25 +00:00
|
|
|
NSAssert(0 != _inf, @"Initialising failed");
|
1998-02-03 14:20:00 +00:00
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
return _inf[index+1];
|
1994-11-08 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
- (NSUInteger) frameLength
|
1994-11-08 16:44:01 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
return _argFrameLength;
|
1998-08-13 20:45:32 +00:00
|
|
|
}
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
- (const char*) getArgumentTypeAtIndex: (NSUInteger)index
|
1998-08-13 20:45:32 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
if (index >= _numArgs)
|
|
|
|
{
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
format: @"Index too high."];
|
1998-08-13 20:45:32 +00:00
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
if (_inf == 0)
|
1999-09-16 07:21:34 +00:00
|
|
|
{
|
|
|
|
[self methodInfo];
|
2011-02-11 14:31:25 +00:00
|
|
|
NSAssert(0 != _inf, @"Initialising failed");
|
1998-08-13 20:45:32 +00:00
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
return _inf[index+1].qtype;
|
1994-11-08 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) isOneway
|
|
|
|
{
|
2009-10-05 16:00:28 +00:00
|
|
|
if (_inf == 0)
|
1999-09-16 07:21:34 +00:00
|
|
|
{
|
|
|
|
[self methodInfo];
|
2011-02-11 14:31:25 +00:00
|
|
|
NSAssert(0 != _inf, @"Initialising failed");
|
1998-08-13 20:45:32 +00:00
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
return (_inf[0].qual & _F_ONEWAY) ? YES : NO;
|
1994-11-08 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
- (NSUInteger) methodReturnLength
|
1994-11-08 16:44:01 +00:00
|
|
|
{
|
2009-10-05 16:00:28 +00:00
|
|
|
if (_inf == 0)
|
1999-09-16 07:21:34 +00:00
|
|
|
{
|
|
|
|
[self methodInfo];
|
2011-02-11 14:31:25 +00:00
|
|
|
NSAssert(0 != _inf, @"Initialising failed");
|
1998-08-13 20:45:32 +00:00
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
return _inf[0].size;
|
1994-11-08 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
1998-08-13 20:45:32 +00:00
|
|
|
- (const char*) methodReturnType
|
1994-11-08 16:44:01 +00:00
|
|
|
{
|
2009-10-05 16:00:28 +00:00
|
|
|
if (_inf == 0)
|
1999-09-16 07:21:34 +00:00
|
|
|
{
|
|
|
|
[self methodInfo];
|
2011-02-11 14:31:25 +00:00
|
|
|
NSAssert(0 != _inf, @"Initialising failed");
|
1998-08-13 20:45:32 +00:00
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
return _inf[0].qtype;
|
1994-11-08 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
- (NSUInteger) numberOfArguments
|
1994-11-08 16:44:01 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
return _numArgs;
|
1994-11-08 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
1995-03-12 19:58:48 +00:00
|
|
|
- (void) dealloc
|
1994-11-08 16:44:01 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
if (_methodTypes)
|
1999-09-28 11:10:34 +00:00
|
|
|
NSZoneFree(NSDefaultMallocZone(), (void*)_methodTypes);
|
2009-10-05 16:00:28 +00:00
|
|
|
if (_inf)
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), (void*)_inf);
|
1999-09-16 07:21:34 +00:00
|
|
|
[super dealloc];
|
1994-11-08 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 15:26:07 +00:00
|
|
|
- (BOOL) isEqual: (id)other
|
2002-05-06 14:42:14 +00:00
|
|
|
{
|
|
|
|
BOOL isEqual = YES;
|
|
|
|
if (other == nil)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
2011-02-20 16:21:43 +00:00
|
|
|
if (object_getClass(other) != object_getClass(self))
|
2002-05-06 14:42:14 +00:00
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
isEqual = ([self numberOfArguments] == [other numberOfArguments]
|
|
|
|
&& [self frameLength] == [other frameLength]
|
|
|
|
&& *[self methodReturnType] == *[other methodReturnType]
|
2002-05-06 14:42:14 +00:00
|
|
|
&& [self isOneway] == [other isOneway]);
|
2005-02-22 11:22:44 +00:00
|
|
|
if (isEqual == NO)
|
2002-05-06 14:42:14 +00:00
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
n = [self numberOfArguments];
|
2005-02-22 11:22:44 +00:00
|
|
|
for (i = 0; i < n; i++)
|
2002-05-06 14:42:14 +00:00
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
if ((*[self getArgumentTypeAtIndex:i]
|
2002-05-06 14:42:14 +00:00
|
|
|
== *[other getArgumentTypeAtIndex:i]) == NO)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return isEqual;
|
|
|
|
}
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
@end
|
1998-01-26 14:18:18 +00:00
|
|
|
|
2004-04-16 23:21:26 +00:00
|
|
|
@implementation NSMethodSignature(GNUstep)
|
1998-08-13 20:45:32 +00:00
|
|
|
- (NSArgumentInfo*) methodInfo
|
|
|
|
{
|
2009-10-05 16:00:28 +00:00
|
|
|
if (_inf == 0)
|
1999-09-16 07:21:34 +00:00
|
|
|
{
|
2004-07-02 08:04:54 +00:00
|
|
|
const char *types = _methodTypes;
|
2008-02-22 12:59:30 +00:00
|
|
|
char *outTypes;
|
2003-01-03 20:14:47 +00:00
|
|
|
unsigned int i;
|
1999-09-16 07:21:34 +00:00
|
|
|
|
2008-02-22 12:59:30 +00:00
|
|
|
/* Allocate space enough for an NSArgumentInfo structure for each
|
|
|
|
* argument (including the return type), and enough space to hold
|
|
|
|
* the type information for each argument as a nul terminated
|
|
|
|
* string.
|
|
|
|
*/
|
|
|
|
outTypes = NSZoneMalloc(NSDefaultMallocZone(),
|
|
|
|
sizeof(NSArgumentInfo)*(_numArgs+1) + strlen(types)*2);
|
2009-10-05 16:00:28 +00:00
|
|
|
_info = (void*)outTypes;
|
2008-02-22 12:59:30 +00:00
|
|
|
outTypes = outTypes + sizeof(NSArgumentInfo)*(_numArgs+1);
|
|
|
|
/* Fill in the full argment information for each arg.
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
for (i = 0; i <= _numArgs; i++)
|
|
|
|
{
|
2009-10-05 16:00:28 +00:00
|
|
|
types = next_arg(types, &_inf[i], outTypes);
|
2008-02-22 12:59:30 +00:00
|
|
|
outTypes += strlen(outTypes) + 1;
|
1998-08-13 20:45:32 +00:00
|
|
|
}
|
|
|
|
}
|
2009-10-05 16:00:28 +00:00
|
|
|
return _inf;
|
1998-08-13 20:45:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (const char*) methodType
|
1998-01-26 14:18:18 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
return _methodTypes;
|
1998-01-26 14:18:18 +00:00
|
|
|
}
|
|
|
|
@end
|