/* * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /*********************************************************************** * objc-typeencoding.m * Parsing of old-style type strings. **********************************************************************/ #include "objc-private.h" /*********************************************************************** * SubtypeUntil. * * Delegation. **********************************************************************/ static int SubtypeUntil (const char * type, char end) { int level = 0; const char * head = type; // while (*type) { if (!*type || (!level && (*type == end))) return (int)(type - head); switch (*type) { case ']': case '}': case ')': level--; break; case '[': case '{': case '(': level += 1; break; } type += 1; } _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n"); return 0; } /*********************************************************************** * SkipFirstType. **********************************************************************/ static const char * SkipFirstType (const char * type) { while (1) { switch (*type++) { case 'O': /* bycopy */ case 'n': /* in */ case 'o': /* out */ case 'N': /* inout */ case 'r': /* const */ case 'V': /* oneway */ case '^': /* pointers */ break; case '@': /* objects */ if (type[0] == '?') type++; /* Blocks */ return type; /* arrays */ case '[': while ((*type >= '0') && (*type <= '9')) type += 1; return type + SubtypeUntil (type, ']') + 1; /* structures */ case '{': return type + SubtypeUntil (type, '}') + 1; /* unions */ case '(': return type + SubtypeUntil (type, ')') + 1; /* basic types */ default: return type; } } } /*********************************************************************** * encoding_getNumberOfArguments. **********************************************************************/ unsigned int encoding_getNumberOfArguments(const char *typedesc) { unsigned nargs; // First, skip the return type typedesc = SkipFirstType (typedesc); // Next, skip stack size while ((*typedesc >= '0') && (*typedesc <= '9')) typedesc += 1; // Now, we have the arguments - count how many nargs = 0; while (*typedesc) { // Traverse argument type typedesc = SkipFirstType (typedesc); // Skip GNU runtime's register parameter hint if (*typedesc == '+') typedesc++; // Traverse (possibly negative) argument offset if (*typedesc == '-') typedesc += 1; while ((*typedesc >= '0') && (*typedesc <= '9')) typedesc += 1; // Made it past an argument nargs += 1; } return nargs; } /*********************************************************************** * encoding_getSizeOfArguments. **********************************************************************/ unsigned encoding_getSizeOfArguments(const char *typedesc) { unsigned stack_size; // Get our starting points stack_size = 0; // Skip the return type typedesc = SkipFirstType (typedesc); // Convert ASCII number string to integer while ((*typedesc >= '0') && (*typedesc <= '9')) stack_size = (stack_size * 10) + (*typedesc++ - '0'); return stack_size; } /*********************************************************************** * encoding_getArgumentInfo. **********************************************************************/ unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset) { unsigned nargs = 0; int self_offset = 0; BOOL offset_is_negative = NO; // First, skip the return type typedesc = SkipFirstType (typedesc); // Next, skip stack size while ((*typedesc >= '0') && (*typedesc <= '9')) typedesc += 1; // Now, we have the arguments - position typedesc to the appropriate argument while (*typedesc && nargs != arg) { // Skip argument type typedesc = SkipFirstType (typedesc); if (nargs == 0) { // Skip GNU runtime's register parameter hint if (*typedesc == '+') typedesc++; // Skip negative sign in offset if (*typedesc == '-') { offset_is_negative = YES; typedesc += 1; } else offset_is_negative = NO; while ((*typedesc >= '0') && (*typedesc <= '9')) self_offset = self_offset * 10 + (*typedesc++ - '0'); if (offset_is_negative) self_offset = -(self_offset); } else { // Skip GNU runtime's register parameter hint if (*typedesc == '+') typedesc++; // Skip (possibly negative) argument offset if (*typedesc == '-') typedesc += 1; while ((*typedesc >= '0') && (*typedesc <= '9')) typedesc += 1; } nargs += 1; } if (*typedesc) { int arg_offset = 0; *type = typedesc; typedesc = SkipFirstType (typedesc); if (arg == 0) { *offset = 0; } else { // Skip GNU register parameter hint if (*typedesc == '+') typedesc++; // Pick up (possibly negative) argument offset if (*typedesc == '-') { offset_is_negative = YES; typedesc += 1; } else offset_is_negative = NO; while ((*typedesc >= '0') && (*typedesc <= '9')) arg_offset = arg_offset * 10 + (*typedesc++ - '0'); if (offset_is_negative) arg_offset = - arg_offset; *offset = arg_offset - self_offset; } } else { *type = 0; *offset = 0; } return nargs; } void encoding_getReturnType(const char *t, char *dst, size_t dst_len) { size_t len; const char *end; if (!dst) return; if (!t) { strncpy(dst, "", dst_len); return; } end = SkipFirstType(t); len = end - t; strncpy(dst, t, MIN(len, dst_len)); if (len < dst_len) memset(dst+len, 0, dst_len - len); } /*********************************************************************** * encoding_copyReturnType. Returns the method's return type string * on the heap. **********************************************************************/ char * encoding_copyReturnType(const char *t) { size_t len; const char *end; char *result; if (!t) return NULL; end = SkipFirstType(t); len = end - t; result = (char *)malloc(len + 1); strncpy(result, t, len); result[len] = '\0'; return result; } void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len) { size_t len; const char *end; int offset; if (!dst) return; if (!t) { strncpy(dst, "", dst_len); return; } encoding_getArgumentInfo(t, index, &t, &offset); if (!t) { strncpy(dst, "", dst_len); return; } end = SkipFirstType(t); len = end - t; strncpy(dst, t, MIN(len, dst_len)); if (len < dst_len) memset(dst+len, 0, dst_len - len); } /*********************************************************************** * encoding_copyArgumentType. Returns a single argument's type string * on the heap. Argument 0 is `self`; argument 1 is `_cmd`. **********************************************************************/ char * encoding_copyArgumentType(const char *t, unsigned int index) { size_t len; const char *end; char *result; int offset; if (!t) return NULL; encoding_getArgumentInfo(t, index, &t, &offset); if (!t) return NULL; end = SkipFirstType(t); len = end - t; result = (char *)malloc(len + 1); strncpy(result, t, len); result[len] = '\0'; return result; }