]> git.saurik.com Git - apple/objc4.git/blobdiff - runtime/objc-typeencoding.mm
objc4-532.tar.gz
[apple/objc4.git] / runtime / objc-typeencoding.mm
diff --git a/runtime/objc-typeencoding.mm b/runtime/objc-typeencoding.mm
new file mode 100644 (file)
index 0000000..03255d2
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * 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;
+}