/** Implementation of ObjC runtime for GNUStep Copyright (C) 1995 Free Software Foundation, Inc. Written by: Andrew Kachites McCallum Date: Aug 1995 This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. NSObjCRuntime class reference $Date$ $Revision$ */ #include #include #include #include #include #include #include NSString * NSStringFromSelector(SEL aSelector) { if (aSelector != (SEL)0) return [NSString stringWithCString: GSNameFromSelector(aSelector)]; return nil; } SEL NSSelectorFromString(NSString *aSelectorName) { if (aSelectorName != nil) return GSSelectorFromName ([aSelectorName lossyCString]); return (SEL)0; } Class NSClassFromString(NSString *aClassName) { if (aClassName != nil) return GSClassFromName ([aClassName lossyCString]); return (Class)0; } NSString * NSStringFromClass(Class aClass) { if (aClass != (Class)0) return [NSString stringWithCString: (char*)GSNameFromClass(aClass)]; return nil; } const char * NSGetSizeAndAlignment(const char *typePtr, unsigned *sizep, unsigned *alignp) { NSArgumentInfo info; typePtr = mframe_next_arg(typePtr, &info); if (sizep) *sizep = info.size; if (alignp) *alignp = info.align; return typePtr; } /** * This function is used to locate information about the instance * variable of obj called name. It returns YES if the variable * was found, NO otherwise. If it returns YES, then the values * pointed to by type, size, and offset will be set (except where * they are nul pointers). */ BOOL GSFindInstanceVariable(id obj, const char *name, const char **type, unsigned int *size, int *offset) { Class class; struct objc_ivar_list *ivars; struct objc_ivar *ivar = 0; class = [obj class]; while (class != nil && ivar == 0) { ivars = class->ivars; class = class->super_class; if (ivars != 0) { int i; for (i = 0; i < ivars->ivar_count; i++) { if (strcmp(ivars->ivar_list[i].ivar_name, name) == 0) { ivar = &ivars->ivar_list[i]; break; } } } } if (ivar == 0) { return NO; } if (type) *type = ivar->ivar_type; if (size) *size = objc_sizeof_type(ivar->ivar_type); if (offset) *offset = ivar->ivar_offset; return YES; } /** * This function performs no checking ... you should use it only where * you are providing information from a call to GSFindInstanceVariable() * and you know that the data area provided is the correct size. */ void GSGetVariable(id obj, int offset, unsigned int size, void *data) { memcpy(data, ((void*)obj) + offset, size); } /** * This function performs no checking ... you should use it only where * you are providing information from a call to GSFindInstanceVariable() * and you know that the data area provided is the correct size. */ void GSSetVariable(id obj, int offset, unsigned int size, const void *data) { memcpy(((void*)obj) + offset, data, size); } /** ## deprecated ## */ BOOL GSInstanceVariableInfo(id obj, NSString *iVarName, const char **type, unsigned *size, unsigned *offset) { const char *name = [iVarName cString]; return GSFindInstanceVariable(obj, name, type, size, offset); } /** ## deprecated ## */ BOOL GSGetInstanceVariable(id obj, NSString *iVarName, void *data) { const char *name = [iVarName cString]; int offset; unsigned int size; if (GSFindInstanceVariable(obj, name, 0, &size, &offset) == YES) { GSGetVariable(obj, offset, size, data); return YES; } return NO; } /** ## deprecated ## */ BOOL GSSetInstanceVariable(id obj, NSString *iVarName, const void *data) { const char *name = [iVarName cString]; int offset; unsigned int size; if (GSFindInstanceVariable(obj, name, 0, &size, &offset) == YES) { GSSetVariable(obj, offset, size, data); return YES; } return NO; } #include #include /** * This is used internally by the key-value coding methods, to get a * value from an object either via an accessor method (if sel is * supplied), or via direct access (if type, size, and offset are * supplied).
* Automatic conversion between NSNumber and C scalar types is performed.
* If type is nul and can't be determined from the selector, the * [NSObject-handleQueryWithUnboundKey:] method is called to try * to get a value. */ id GSGetValue(NSObject *self, NSString *key, SEL sel, const char *type, unsigned size, int offset) { if (sel != 0) { NSMethodSignature *sig = [self methodSignatureForSelector: sel]; if ([sig numberOfArguments] != 2) { [NSException raise: NSInvalidArgumentException format: @"key-value get method has wrong number of args"]; } type = [sig methodReturnType]; } if (type == NULL) { return [self handleQueryWithUnboundKey: key]; } else { id val = nil; switch (*type) { case _C_ID: case _C_CLASS: { id v; if (sel == 0) { v = *(id *)((char *)self + offset); } else { id (*imp)(id, SEL) = (id (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = v; } break; case _C_CHR: { signed char v; if (sel == 0) { v = *(char *)((char *)self + offset); } else { signed char (*imp)(id, SEL) = (signed char (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithChar: v]; } break; case _C_UCHR: { unsigned char v; if (sel == 0) { v = *(unsigned char *)((char *)self + offset); } else { unsigned char (*imp)(id, SEL) = (unsigned char (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithUnsignedChar: v]; } break; case _C_SHT: { short v; if (sel == 0) { v = *(short *)((char *)self + offset); } else { short (*imp)(id, SEL) = (short (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithShort: v]; } break; case _C_USHT: { unsigned short v; if (sel == 0) { v = *(unsigned short *)((char *)self + offset); } else { unsigned short (*imp)(id, SEL) = (unsigned short (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithUnsignedShort: v]; } break; case _C_INT: { int v; if (sel == 0) { v = *(int *)((char *)self + offset); } else { int (*imp)(id, SEL) = (int (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithInt: v]; } break; case _C_UINT: { unsigned int v; if (sel == 0) { v = *(unsigned int *)((char *)self + offset); } else { unsigned int (*imp)(id, SEL) = (unsigned int (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithUnsignedInt: v]; } break; case _C_LNG: { long v; if (sel == 0) { v = *(long *)((char *)self + offset); } else { long (*imp)(id, SEL) = (long (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithLong: v]; } break; case _C_ULNG: { unsigned long v; if (sel == 0) { v = *(unsigned long *)((char *)self + offset); } else { unsigned long (*imp)(id, SEL) = (unsigned long (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithUnsignedLong: v]; } break; #ifdef _C_LNG_LNG case _C_LNG_LNG: { long long v; if (sel == 0) { v = *(long long *)((char *)self + offset); } else { long long (*imp)(id, SEL) = (long long (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithLongLong: v]; } break; #endif #ifdef _C_ULNG_LNG case _C_ULNG_LNG: { unsigned long long v; if (sel == 0) { v = *(unsigned long long *)((char *)self + offset); } else { unsigned long long (*imp)(id, SEL) = (unsigned long long (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithUnsignedLongLong: v]; } break; #endif case _C_FLT: { float v; if (sel == 0) { v = *(float *)((char *)self + offset); } else { float (*imp)(id, SEL) = (float (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithFloat: v]; } break; case _C_DBL: { double v; if (sel == 0) { v = *(double *)((char *)self + offset); } else { double (*imp)(id, SEL) = (double (*)(id, SEL))[self methodForSelector: sel]; v = (*imp)(self, sel); } val = [NSNumber numberWithDouble: v]; } break; case _C_VOID: { void (*imp)(id, SEL) = (void (*)(id, SEL))[self methodForSelector: sel]; (*imp)(self, sel); } val = nil; break; default: [NSException raise: NSInvalidArgumentException format: @"key-value get method has unsupported type"]; } return val; } } /** * This is used internally by the key-value coding methods, to set a * value in an object either via an accessor method (if sel is * supplied), or via direct access (if type, size, and offset are * supplied).
* Automatic conversion between NSNumber and C scalar types is performed.
* If type is nul and can't be determined from the selector, the * [NSObject-handleTakevalue:forUnboundKey:] method is called to try * to set a value. */ void GSSetValue(NSObject *self, NSString *key, id val, SEL sel, const char *type, unsigned size, int offset) { if (sel != 0) { NSMethodSignature *sig = [self methodSignatureForSelector: sel]; if ([sig numberOfArguments] != 3) { [NSException raise: NSInvalidArgumentException format: @"key-value set method has wrong number of args"]; } type = [sig getArgumentTypeAtIndex: 2]; } if (type == NULL) { [self handleTakeValue: val forUnboundKey: key]; } else { switch (*type) { case _C_ID: case _C_CLASS: { id v = val; if (sel == 0) { id *ptr = (id *)((char *)self + offset); [*ptr autorelease]; *ptr = [v retain]; } else { void (*imp)(id, SEL, id) = (void (*)(id, SEL, id))[self methodForSelector: sel]; (*imp)(self, sel, val); } } break; case _C_CHR: { char v = [val charValue]; if (sel == 0) { char *ptr = (char *)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, char) = (void (*)(id, SEL, char))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; case _C_UCHR: { unsigned char v = [val unsignedCharValue]; if (sel == 0) { unsigned char *ptr = (unsigned char*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, unsigned char) = (void (*)(id, SEL, unsigned char))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; case _C_SHT: { short v = [val shortValue]; if (sel == 0) { short *ptr = (short*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, short) = (void (*)(id, SEL, short))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; case _C_USHT: { unsigned short v = [val unsignedShortValue]; if (sel == 0) { unsigned short *ptr; ptr = (unsigned short*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, unsigned short) = (void (*)(id, SEL, unsigned short))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; case _C_INT: { int v = [val intValue]; if (sel == 0) { int *ptr = (int*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, int) = (void (*)(id, SEL, int))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; case _C_UINT: { unsigned int v = [val unsignedIntValue]; if (sel == 0) { unsigned int *ptr = (unsigned int*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, unsigned int) = (void (*)(id, SEL, unsigned int))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; case _C_LNG: { long v = [val longValue]; if (sel == 0) { long *ptr = (long*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, long) = (void (*)(id, SEL, long))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; case _C_ULNG: { unsigned long v = [val unsignedLongValue]; if (sel == 0) { unsigned long *ptr = (unsigned long*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, unsigned long) = (void (*)(id, SEL, unsigned long))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; #ifdef _C_LNG_LNG case _C_LNG_LNG: { long long v = [val longLongValue]; if (sel == 0) { long long *ptr = (long long*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, long long) = (void (*)(id, SEL, long long))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; #endif #ifdef _C_ULNG_LNG case _C_ULNG_LNG: { unsigned long long v = [val unsignedLongLongValue]; if (sel == 0) { unsigned long long *ptr = (unsigned long long*)((char*)self + offset); *ptr = v; } else { void (*imp)(id, SEL, unsigned long long) = (void (*)(id, SEL, unsigned long long))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; #endif case _C_FLT: { float v = [val floatValue]; if (sel == 0) { float *ptr = (float*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, float) = (void (*)(id, SEL, float))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; case _C_DBL: { double v = [val doubleValue]; if (sel == 0) { double *ptr = (double*)((char *)self + offset); *ptr = v; } else { void (*imp)(id, SEL, double) = (void (*)(id, SEL, double))[self methodForSelector: sel]; (*imp)(self, sel, v); } } break; default: [NSException raise: NSInvalidArgumentException format: @"key-value set method has unsupported type"]; } } } /* Getting a system error message on a variety of systems */ #ifdef __MINGW__ LPTSTR GetErrorMsg(DWORD msgId) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, msgId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR)&lpMsgBuf, 0, NULL); return (LPTSTR)lpMsgBuf; } #else #ifndef HAVE_STRERROR const char* strerror(int eno) { extern char* sys_errlist[]; extern int sys_nerr; if (eno < 0 || eno >= sys_nerr) { return("unknown error number"); } return(sys_errlist[eno]); } #endif #endif /* __MINGW__ */ const char *GSLastErrorStr(long error_id) { #ifdef __MINGW__ return GetErrorMsg(GetLastError()); #else return strerror(error_id); #endif }