]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-typeencoding.mm
objc4-781.2.tar.gz
[apple/objc4.git] / runtime / objc-typeencoding.mm
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 **********************************************************************/
36 static 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 **********************************************************************/
65 static 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 **********************************************************************/
109 unsigned int
110 encoding_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 **********************************************************************/
147 unsigned
148 encoding_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 **********************************************************************/
169 unsigned int
170 encoding_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
273 void
274 encoding_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 **********************************************************************/
295 char *
296 encoding_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
313 void
314 encoding_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 **********************************************************************/
345 char *
346 encoding_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 }