1/* 2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/*********************************************************************** 25* objc-typeencoding.m 26* Parsing of old-style type strings. 27**********************************************************************/ 28 29#include "objc-private.h" 30 31/*********************************************************************** 32* SubtypeUntil. 33* 34* Delegation. 35**********************************************************************/ 36static int SubtypeUntil (const char * type, 37 char end) 38{ 39 int level = 0; 40 const char * head = type; 41 42 // 43 while (*type) 44 { 45 if (!*type || (!level && (*type == end))) 46 return (int)(type - head); 47 48 switch (*type) 49 { 50 case ']': case '}': case ')': level--; break; 51 case '[': case '{': case '(': level += 1; break; 52 } 53 54 type += 1; 55 } 56 57 _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n"); 58 return 0; 59} 60 61 62/*********************************************************************** 63* SkipFirstType. 64**********************************************************************/ 65static const char * SkipFirstType (const char * type) 66{ 67 while (1) 68 { 69 switch (*type++) 70 { 71 case 'O': /* bycopy */ 72 case 'n': /* in */ 73 case 'o': /* out */ 74 case 'N': /* inout */ 75 case 'r': /* const */ 76 case 'V': /* oneway */ 77 case '^': /* pointers */ 78 break; 79 80 case '@': /* objects */ 81 if (type[0] == '?') type++; /* Blocks */ 82 return type; 83 84 /* arrays */ 85 case '[': 86 while ((*type >= '0') && (*type <= '9')) 87 type += 1; 88 return type + SubtypeUntil (type, ']') + 1; 89 90 /* structures */ 91 case '{': 92 return type + SubtypeUntil (type, '}') + 1; 93 94 /* unions */ 95 case '(': 96 return type + SubtypeUntil (type, ')') + 1; 97 98 /* basic types */ 99 default: 100 return type; 101 } 102 } 103} 104 105 106/*********************************************************************** 107* encoding_getNumberOfArguments. 108**********************************************************************/ 109unsigned int 110encoding_getNumberOfArguments(const char *typedesc) 111{ 112 unsigned nargs; 113 114 // First, skip the return type 115 typedesc = SkipFirstType (typedesc); 116 117 // Next, skip stack size 118 while ((*typedesc >= '0') && (*typedesc <= '9')) 119 typedesc += 1; 120 121 // Now, we have the arguments - count how many 122 nargs = 0; 123 while (*typedesc) 124 { 125 // Traverse argument type 126 typedesc = SkipFirstType (typedesc); 127 128 // Skip GNU runtime's register parameter hint 129 if (*typedesc == '+') typedesc++; 130 131 // Traverse (possibly negative) argument offset 132 if (*typedesc == '-') 133 typedesc += 1; 134 while ((*typedesc >= '0') && (*typedesc <= '9')) 135 typedesc += 1; 136 137 // Made it past an argument 138 nargs += 1; 139 } 140 141 return nargs; 142} 143 144/*********************************************************************** 145* encoding_getSizeOfArguments. 146**********************************************************************/ 147unsigned 148encoding_getSizeOfArguments(const char *typedesc) 149{ 150 unsigned stack_size; 151 152 // Get our starting points 153 stack_size = 0; 154 155 // Skip the return type 156 typedesc = SkipFirstType (typedesc); 157 158 // Convert ASCII number string to integer 159 while ((*typedesc >= '0') && (*typedesc <= '9')) 160 stack_size = (stack_size * 10) + (*typedesc++ - '0'); 161 162 return stack_size; 163} 164 165 166/*********************************************************************** 167* encoding_getArgumentInfo. 168**********************************************************************/ 169unsigned int 170encoding_getArgumentInfo(const char *typedesc, unsigned int arg, 171 const char **type, int *offset) 172{ 173 unsigned nargs = 0; 174 int self_offset = 0; 175 BOOL offset_is_negative = NO; 176 177 // First, skip the return type 178 typedesc = SkipFirstType (typedesc); 179 180 // Next, skip stack size 181 while ((*typedesc >= '0') && (*typedesc <= '9')) 182 typedesc += 1; 183 184 // Now, we have the arguments - position typedesc to the appropriate argument 185 while (*typedesc && nargs != arg) 186 { 187 188 // Skip argument type 189 typedesc = SkipFirstType (typedesc); 190 191 if (nargs == 0) 192 { 193 // Skip GNU runtime's register parameter hint 194 if (*typedesc == '+') typedesc++; 195 196 // Skip negative sign in offset 197 if (*typedesc == '-') 198 { 199 offset_is_negative = YES; 200 typedesc += 1; 201 } 202 else 203 offset_is_negative = NO; 204 205 while ((*typedesc >= '0') && (*typedesc <= '9')) 206 self_offset = self_offset * 10 + (*typedesc++ - '0'); 207 if (offset_is_negative) 208 self_offset = -(self_offset); 209 210 } 211 212 else 213 { 214 // Skip GNU runtime's register parameter hint 215 if (*typedesc == '+') typedesc++; 216 217 // Skip (possibly negative) argument offset 218 if (*typedesc == '-') 219 typedesc += 1; 220 while ((*typedesc >= '0') && (*typedesc <= '9')) 221 typedesc += 1; 222 } 223 224 nargs += 1; 225 } 226 227 if (*typedesc) 228 { 229 int arg_offset = 0; 230 231 *type = typedesc; 232 typedesc = SkipFirstType (typedesc); 233 234 if (arg == 0) 235 { 236 *offset = 0; 237 } 238 239 else 240 { 241 // Skip GNU register parameter hint 242 if (*typedesc == '+') typedesc++; 243 244 // Pick up (possibly negative) argument offset 245 if (*typedesc == '-') 246 { 247 offset_is_negative = YES; 248 typedesc += 1; 249 } 250 else 251 offset_is_negative = NO; 252 253 while ((*typedesc >= '0') && (*typedesc <= '9')) 254 arg_offset = arg_offset * 10 + (*typedesc++ - '0'); 255 if (offset_is_negative) 256 arg_offset = - arg_offset; 257 258 *offset = arg_offset - self_offset; 259 } 260 261 } 262 263 else 264 { 265 *type = 0; 266 *offset = 0; 267 } 268 269 return nargs; 270} 271 272 273void 274encoding_getReturnType(const char *t, char *dst, size_t dst_len) 275{ 276 size_t len; 277 const char *end; 278 279 if (!dst) return; 280 if (!t) { 281 strncpy(dst, "", dst_len); 282 return; 283 } 284 285 end = SkipFirstType(t); 286 len = end - t; 287 strncpy(dst, t, MIN(len, dst_len)); 288 if (len < dst_len) memset(dst+len, 0, dst_len - len); 289} 290 291/*********************************************************************** 292* encoding_copyReturnType. Returns the method's return type string 293* on the heap. 294**********************************************************************/ 295char * 296encoding_copyReturnType(const char *t) 297{ 298 size_t len; 299 const char *end; 300 char *result; 301 302 if (!t) return NULL; 303 304 end = SkipFirstType(t); 305 len = end - t; 306 result = (char *)malloc(len + 1); 307 strncpy(result, t, len); 308 result[len] = '\0'; 309 return result; 310} 311 312 313void 314encoding_getArgumentType(const char *t, unsigned int index, 315 char *dst, size_t dst_len) 316{ 317 size_t len; 318 const char *end; 319 int offset; 320 321 if (!dst) return; 322 if (!t) { 323 strncpy(dst, "", dst_len); 324 return; 325 } 326 327 encoding_getArgumentInfo(t, index, &t, &offset); 328 329 if (!t) { 330 strncpy(dst, "", dst_len); 331 return; 332 } 333 334 end = SkipFirstType(t); 335 len = end - t; 336 strncpy(dst, t, MIN(len, dst_len)); 337 if (len < dst_len) memset(dst+len, 0, dst_len - len); 338} 339 340 341/*********************************************************************** 342* encoding_copyArgumentType. Returns a single argument's type string 343* on the heap. Argument 0 is `self`; argument 1 is `_cmd`. 344**********************************************************************/ 345char * 346encoding_copyArgumentType(const char *t, unsigned int index) 347{ 348 size_t len; 349 const char *end; 350 char *result; 351 int offset; 352 353 if (!t) return NULL; 354 355 encoding_getArgumentInfo(t, index, &t, &offset); 356 357 if (!t) return NULL; 358 359 end = SkipFirstType(t); 360 len = end - t; 361 result = (char *)malloc(len + 1); 362 strncpy(result, t, len); 363 result[len] = '\0'; 364 return result; 365} 366