This is objcTypeDecode.m in view mode; [Download] [Up]
/*+++ * title: objcTypeDecode.m * abstract: objc-encoded type decoding functions. * author: Tom Hageman <tom@basil.icce.rug.nl> * created: December 1998 * modified: * copyleft: * * Copyright (C) 1998 Tom R. Hageman. * * You may freely copy, distribute, and reuse the code in this file. * * NO WARRANTY: * ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A * PARTICULAR PURPOSE IS HEREBY DISCLAIMED. IN NO EVENT WILL THE * AFOREMENTIONED PARTIES BE LIABLE FOR DAMAGES, INCLUDING ANY * GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING * OUT OF THE USE OF OR INABILITY TO USE THIS CODE. * * description: * (see corresponding *.h file) *---*/ #ifdef RCS_ID static const char * const RCSid = ((void)&RCSid, "@(#)objcTypeDecode.m,v 1.7 1999/01/10 13:58:27 tom Exp"); # define RCS_objcTypeDecode_ID #endif #import "objcTypeDecode.h" #include <stdio.h> #include <string.h> #include <ctype.h> /* Support functions. */ #if __GNUC__ /* Hack around the lack of long long support in NeXT's printf() */ #include <limits.h> static void ulltoa(char *buf, unsigned long long value) { if (value <= ULONG_MAX) { sprintf(buf, "%lu", (unsigned long)value); } else { /* Chicken out by printing hex value (assumes 32-bit long) */ union { unsigned long long ull; unsigned long ul[2]; } u; #if __BIG_ENDIAN__ enum { HI=0, LO }; #else enum { LO=0, HI }; #endif u.ull = value; sprintf(buf, "0x%lx%08lx", u.ul[HI], u.ul[LO]); } } static void lltoa(char *buf, long long value) { if (LONG_MIN <= value && value <= LONG_MAX) { sprintf(buf, "%ld", (long)value); } else { ulltoa(buf, value); } } #endif /* __GNUC__ */ static const char *decode_objc_encoded_struct_or_union(char *buf, size_t offset, size_t bufsize, const char *type, char endc, unsigned options) { /* Assumes start typespec + name of struct/union has been skipped. */ char t; #if 0 // NOTYET size_t len; // XXX TODO handle verbose expansion. if (!(options & DECODE_OBJC_VERBOSE)) #endif bufsize = 0; // skip or expand field type specs. while ((t = *type) && t != endc) { type = decode_objc_encoded_type(buf + offset, bufsize, type, options); #if 0 //NOTYET len += strlen(buf + offset); offset += len; bufsize -= len; #endif } if (t) ++type; return type; } /* Returns updated position in type string. */ const char *decode_objc_encoded_type(char *buf, size_t bufsize, const char *type, unsigned options) { const char *name; int namelen; size_t offset = 0; int pointers = 0; BOOL done = NO; char t; if (bufsize > 0) buf[0] = '\0'; while (!done && *type) { name = NULL; namelen = 0; done = YES; switch (t = *type++) { // Simple types. case _C_CLASS: name = "Class"; break; case _C_SEL: name = "SEL"; break; case _C_CHR: name = "char"; break; case _C_UCHR: name = "unsigned char"; break; case _C_SHT: name = "short"; break; case _C_USHT: name = "unsigned short"; break; case _C_INT: name = "int"; break; case _C_UINT: name = "unsigned int"; break; case _C_LNG: name = "long"; break; case _C_ULNG: name = "unsigned long"; break; case _C_LLNG: name = "long long"; break; case _C_ULLNG: name = "unsigned long long"; break; case _C_FLT: name = "float"; break; case _C_DBL: name = "double"; break; case _C_VOID: name = "void"; break; case _C_ATOM: name = "NXAtom"; break; case _C_CHARPTR: name = "char *"; break; // Complicated types. case _C_UNDEF: name = (pointers) ? "/*UNKNOWN*/ void" : "/*UNKNOWN*/"; break; case _C_ID: /* May be annotated with class name in GNU runtime; not sure for NeXT, but probably won't hurt. */ if (*type == '"') { name = ++type; while (*type && *type++ != '"') ; namelen = type - name - 1; } if (namelen <= 0) name = "id"; break; case _C_PTR: ++pointers; done = NO; continue; case _C_BFLD: name = type; while (isdigit(*type)) ++type; namelen = type - name - 1; if (offset + (offset > 0) + 8 + 1 + 1 + 1 > bufsize) { offset = bufsize; continue; } if (offset > 0) buf[offset++] = ' '; strcpy(buf + offset, "unsigned :"); offset += 8 + 1 + 1; break; case _C_ARY_B: name = type; while (isdigit(*type)) ++type; namelen = type - name; type = decode_objc_encoded_type(buf + offset, bufsize - offset, type, options); while (*type && *type++ != _C_ARY_E) ; if (offset >= bufsize) continue; offset += strlen(buf + offset); if (offset + 1 + namelen + 1 + 1 > bufsize) { offset = bufsize; continue; } buf[offset++] = '['; strncpy(buf + offset, name, namelen); offset += namelen; buf[offset++] = ']'; buf[offset] = '\0'; continue; case _C_UNION_B: name = type; #if NeXT_RUNTIME /* In NeXT runtime, union does not have name in method definition, but it does in ivar def (Ugh!) In GNU runtime, name is always present. */ if ((options & DECODE_OBJC_KIND_MASK) != DECODE_OBJC_METHOD_TYPE) #endif while (*type && *type != '=' && *type != _C_STRUCT_E) ++type; namelen = type - name; if (*type == '=') ++type; if (namelen <= 0 || (namelen == 1 && *name == '?')) { name = "UNKNOWN", namelen = 7; } if (offset + (offset > 0) + 5 + 1 + namelen + 1 > bufsize) { offset = bufsize; } else { if (offset > 0) buf[offset++] = ' '; sprintf(buf + offset, "union %.*s", namelen, name); offset += 5 + 1 + namelen; } type = decode_objc_encoded_struct_or_union(buf, offset, bufsize, type, _C_UNION_E, options); if (offset < bufsize) offset += strlen(buf + offset); continue; case _C_STRUCT_B: name = type; while (*type && *type != '=' && *type != _C_STRUCT_E) ++type; namelen = type - name; if (*type == '=') ++type; if (namelen <= 0 || (namelen == 1 && *name == '?')) { name = "UNKNOWN", namelen = 7; } if (offset + (offset > 0) + 6 + 1 + namelen + 1 > bufsize) { offset = bufsize; } else { if (offset > 0) buf[offset++] = ' '; sprintf(buf + offset, "struct %.*s", namelen, name); offset += 6 + 1 + namelen; } type = decode_objc_encoded_struct_or_union(buf, offset, bufsize, type, _C_STRUCT_E, options); if (offset < bufsize) offset += strlen(buf + offset); continue; // XXX TODO: factor out more common code in struct/union. /* Protocol qualifier encodings: */ case _C_CONST: name = "const"; done = NO; break; case _C_IN: name = "in"; done = NO; break; case _C_INOUT: name = "inout"; done = NO; break; case _C_OUT: name = "out"; done = NO; break; case _C_BYCOPY: name = "bycopy"; done = NO; break; case _C_ONEWAY: name = "oneway"; done = NO; break; default: --type; continue; // done == YES, so actually exit the loop. } /* Append name to buf, at offset. Prepend blank if needed.*/ if (namelen <= 0) namelen = strlen(name); if (offset + namelen + (offset > 0) + 1 > bufsize) { offset = bufsize; continue; } if (offset > 0) buf[offset++] = ' '; strncpy(buf + offset, name, namelen); offset += namelen; buf[offset] = '\0'; } if (pointers) { if (offset == 0) { name = "void *", namelen = 6; } else if (buf[offset-1] != '*') { name = " *", namelen = 2; } else { name = "*", namelen = 1; } do { if (offset + namelen + 1 > bufsize) { offset = bufsize; break; } strcpy(buf + offset, name); offset += namelen; name = "*", namelen = 1; } while (--pointers); } return type; } #ifndef GNU_RUNTIME static __inline__ const char *objc_skip_type_qualifiers(const char *type) { for (;;) { switch (*type) { case _C_CONST: case _C_IN: case _C_INOUT: case _C_OUT: case _C_BYCOPY: case _C_ONEWAY: ++type; continue; default: return type; } } /* NOTREACHED */ return type; } #endif /* GNU_RUNTIME */ static const char *format_of_objc_encoded_type(const char *type) { type = objc_skip_type_qualifiers(type); switch (*type) { case _C_ID: return "0x%06lx"; case _C_CLASS: return "<%s>"; case _C_SEL: return "\"%s\""; case _C_CHR: return "'%c'"; case _C_UCHR: return "'%c'"; case _C_SHT: return "%hd"; case _C_USHT: return "%hu"; case _C_INT: return "%d"; case _C_UINT: return "%u"; case _C_LNG: return "%ld"; case _C_ULNG: return "%lu"; case _C_FLT: return "%g"; case _C_DBL: return "%g"; case _C_BFLD: return "?"; // cannot really print bitfields. case _C_VOID: return "?"; // should not happen. case _C_UNDEF: return "0x%08lx"; // best we can do... case _C_PTR: return "0x%06lx"; case _C_ATOM: case _C_CHARPTR: return "\"%s\""; case _C_ARY_B: return "0x%06lx"; case _C_UNION_B: return "0x%08lx"; // Hmmm... case _C_STRUCT_B: return "0x%08lx"; // ...could do better. case '\0': return "<invalid type description>"; default: break; } return "0x%lx"; } void decode_objc_encoded_value_for_type(char *buf, size_t bufsize, const char *type, const void *valptr, unsigned options) { // XXX this does not yet use bufsize to limit result string length. const char *format; type = objc_skip_type_qualifiers(type); format = format_of_objc_encoded_type(type); if (bufsize) buf[0] = '\0'; switch (*type) { case _C_ID: { id object = *(id *)valptr; if (object == nil) { strcpy(buf, "nil"); break; } if (options & DECODE_OBJC_VERBOSE) { /* (id) arguments are habitually abused to pass non-pointer values, so this, while nice, may in turn cause a crash. */ if (IS_VALID_POINTER_OF_TYPE(object, id)) { const char *className = object_getClassName(object); sprintf(buf, IS_CLASS(object) ? "<%s>" : "<%s:0x%06lx>", className ? className : "(unknown)", (unsigned long)object); } else { sprintf(buf, "0x%lx", (unsigned long)object); } } else { sprintf(buf, format, object); } } break; case _C_CLASS: { Class class = *(Class *)valptr; if (class == Nil) { strcpy(buf, "Nil"); break; } sprintf(buf, format, object_getClassName(class)); } break; case _C_SEL: { SEL sel = *(SEL *)valptr; if (sel == NULL) { strcpy(buf, "NULL"); break; } sprintf(buf, format, sel_getName(sel)); } break; case _C_CHR: case _C_UCHR: { unsigned char c = *(unsigned char *)valptr; if (!isprint(c)) { sprintf(buf, "'\\x%x'", c); break; } sprintf(buf, format, c); } break; case _C_SHT: case _C_USHT: sprintf(buf, format, *(unsigned short *)valptr); break; case _C_INT: case _C_UINT: sprintf(buf, format, *(unsigned int *)valptr); break; case _C_LNG: case _C_ULNG: sprintf(buf, format, *(unsigned long *)valptr); break; #if __GNUC__ case _C_LLNG: lltoa(buf, *(long long *)valptr); break; case _C_ULLNG: ulltoa(buf, *(unsigned long long *)valptr); break; #endif case _C_FLT: sprintf(buf, format, *(float *)valptr); break; case _C_DBL: sprintf(buf, format, *(double *)valptr); break; case _C_BFLD: case _C_VOID: strcpy(buf, format); break; case _C_UNDEF: case _C_PTR: sprintf(buf, format, *(void **)valptr); break; case _C_ATOM: case _C_CHARPTR: { const char *str = *(const char **)valptr; if (str == NULL) { strcpy(buf, "NULL"); break; } if (strlen(str) > (bufsize-2-1)) { sprintf(buf, "\"%.*s...\"", (int)(bufsize-2-3-1), str); break; } sprintf(buf, format, str); } break; case _C_ARY_B: sprintf(buf, format, *(void **)valptr); break; case _C_UNION_B: sprintf(buf, format, *(long *)valptr); break; case _C_STRUCT_B: // This can in principle be handled a lot better, since the // type information is available. sprintf(buf, format, *(long *)valptr); break; default: sprintf(buf, format, *(void **)valptr); break; } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.