ftp.nice.ch/pub/next/developer/languages/smalltalk/smalltalk.1.2.alpha5.s.tar.gz#/smalltalk-1.2.alpha5/objc/cfuncs.c

This is cfuncs.c in view mode; [Download] [Up]

/***********************************************************************

***********************************************************************/


#import <objc/objc-runtime.h>
#import <objc/objc-load.h>
#import <objc/objc-class.h>
#import <objc/objc.h>
#import "./objclib/STObjectAdditions.h"
#import "gst.h"

extern void defineCFunc();

BOOL   hasUnderscore(const char *string);
char  *decodeTypeForST(const char *type);
id     createInstance(id aClass);
SEL    methodSelelector(Method aMethod);
char  *methodName(Method aMethod);
int    numberOfClassMethodsFor(id aClass);
Method classMethodFor(id aClass, int at);
int    numberOfInstanceMethodsFor(id aClass);
Method instanceMethodFor(id aClass, int at);
char  *returnTypeForMethod(Method aMethod);
OOP    argTypeArrayForMethod(Method aMethod);
char  *stMethodNameForMethod(Method aMethod);
char  *stMsgSendNameForMethod(Method aMethod);
char  *stMsgSendSelectorForMethod(Method aMethod);
id     subclassOf(id aClass, int at);
int    numberOfSubclassesOf(id aClass);		
int    returnTypeIsIDForMethod(Method aMethod);
int    idsAreEqual(id first, id second);				
int    forwardToSmalltalk(id aClass, SEL aSelector);

void initUserCFuncs()
{
    /*
     * ObjCClass methods 
     */
    defineCFunc("createInstance", createInstance);
    defineCFunc("getInstanceMethod", class_getInstanceMethod);
    defineCFunc("getClassMethod", class_getClassMethod);
    defineCFunc("getInstanceVariable", class_getInstanceVariable);
    defineCFunc("poseAs", class_poseAs);
    defineCFunc("getClass", objc_getClass);
    defineCFunc("lookUpClass", objc_lookUpClass);
    defineCFunc("getMetaClass", objc_getMetaClass);
    defineCFunc("getClasses", objc_getClasses);
    defineCFunc("loadModules", objc_loadModules);
    defineCFunc("unloadModules", objc_unloadModules);
    
    /*
     * Stuff written by me
     */
    defineCFunc("methodSelelector", methodSelelector);
    defineCFunc("methodName", methodName);
    
    defineCFunc("numberOfInstanceMethodsFor", numberOfInstanceMethodsFor);
    defineCFunc("instanceMethodFor", instanceMethodFor);
    defineCFunc("numberOfClassMethodsFor", numberOfClassMethodsFor);
    defineCFunc("classMethodFor", classMethodFor);
    defineCFunc("returnTypeForMethod", returnTypeForMethod);
    defineCFunc("argTypeArrayForMethod", argTypeArrayForMethod);
    defineCFunc("stMethodNameForMethod", stMethodNameForMethod);
    defineCFunc("stMsgSendNameForMethod", stMsgSendNameForMethod);
    defineCFunc("stMsgSendSelectorForMethod", stMsgSendSelectorForMethod);
    defineCFunc("numberOfSubclassesOf", numberOfSubclassesOf);
    defineCFunc("subclassOf", subclassOf);
    defineCFunc("returnTypeIsIDForMethod", returnTypeIsIDForMethod);
    defineCFunc("idsAreEqual", idsAreEqual);
    defineCFunc("forwardToSmalltalk", forwardToSmalltalk);
    
    /*
     * ObjCMethod methods 
     */
    /*
      defineCFunc("getValue", marg_getValue);
      defineCFunc("getRef", marg_getRef);
      defineCFunc("setValue", marg_setValue);
      */
    defineCFunc("getNumberOfArguments", method_getNumberOfArguments);
    defineCFunc("getSizeOfArguments", method_getSizeOfArguments);
    defineCFunc("getArgumentInfo", method_getArgumentInfo);
    defineCFunc("getUid", sel_getUid);
    defineCFunc("getName", sel_getName);
    defineCFunc("isMapped", sel_isMapped);

    /*
     * ObjCObject methods 
     */
    defineCFunc("msgSend", objc_msgSend);
    defineCFunc("getIndexedIvars", object_getIndexedIvars);
    defineCFunc("setInstanceVariable", object_setInstanceVariable);
    defineCFunc("getInstanceVariable", object_getInstanceVariable);
    defineCFunc("getClassName", object_getClassName);
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

id createInstance(id aClass)
{
    return class_createInstance(aClass, (((struct objc_class *)aClass)->instance_size));
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================
 
char *decodeTypeForST(const char *type)
{
    switch(type[0])
    {
    case '@':
    case '#':
    case ':':
    case '^':
	return "cObject";
    case 'c':
	return "char";
    case 'C':
	return "char";
    case 'i':
	return "int";
    case 'I':
	return "int";
    case 'l':
	return "long";
    case 'L':
	return "long";
    case 's':
	return "int";		// should be short
    case 'S':
	return "int";
    case 'f':
	return "float";
    case 'd':
	return "double";
    case '*':
	return "string";	
    case 'v':
	return "void";	
    }
    return "unknown";
}

/*
 * stMsgSendNameForMethod return the string used to create
 * a c callout to the function objc_msgSend with the casts
 * to the corrent return type and args
 */

// ============================================================
// Function:	stMsgSendNameForMethod
// Args:		Method
// Description:	Creates a string that smalltalk uniquely
//  describe the return and arg types for a objc_msgSend
//  call.  For instance, the if the method drawSelf
//  was passed in, we would return 
//  cObjectMsgSend:  andId sel: aSelector argcObject: arg1 argint: arg2
// ============================================================

char *stMsgSendNameForMethod(Method aMethod)
{
    static char	 msgSendString[1024];
    static char	 argString[32];
    char	*type;
    int		 offset;
    int		 i, argCount = (method_getNumberOfArguments(aMethod) - 2);
    
    sprintf(msgSendString, "%sMsgSend%d: anId sel: aSelector", returnTypeForMethod(aMethod), argCount);
    if (argCount > 0)
    {
	for (i=0 ; i<argCount ; i++)
	{
	    method_getArgumentInfo(aMethod, i+2, &type, &offset);
	    
	    sprintf(argString, " arg%s: arg%d", decodeTypeForST(type), i);
	    strcat(msgSendString, argString);
	}
    }
    return msgSendString;
}

// ============================================================
// Function:	stMsgSendSelectorForMethod
// Args:		Method
// Description:	Returns a selector string that smalltalk can
//  use to identify a selector.  If the method for drawSelf::
//  was passed in we would return 
//  cObjectMsgSend:sel:argcObject:argint:
// ============================================================

char *stMsgSendSelectorForMethod(Method aMethod)
{
    static char	 msgSendString[1024];
    static char	 argString[32];
    char	*type;
    int		 offset;
    int		 i, argCount = (method_getNumberOfArguments(aMethod) - 2);
    
    sprintf(msgSendString, "%sMsgSend%d:sel:", returnTypeForMethod(aMethod), argCount);
    if (argCount > 0)
    {
	for (i=0 ; i<argCount ; i++)
	{
	    method_getArgumentInfo(aMethod, i+2, &type, &offset);
	    
	    sprintf(argString, "arg%s:", decodeTypeForST(type), i);
	    strcat(msgSendString, argString);
	}
    }
    return msgSendString;
}
/*
 * stMethodNameForMethod returns the string used to create the
 * actual smalltalk method.  This method will then call the 
 * msgSend ObjCRTInterface class method 
 * 		XXXMsqSendX: anId sel: aSelector arg1: anArg1 .... argN: anArgN
 */
// ============================================================
// Function:		stMethodNameForMethod
// Args:			Method
// Description:		This the name of the method in smalltalk
//  including arg names.  The method for smalltalk would
//  be returned as drawSelf: arg1 anArg: arg2.  Notice that
//  anArg was added to the name.  That is because GNU smalltalk
//  doesn't recognize ':' as part of a selector name.
// ============================================================

char *stMethodNameForMethod(Method aMethod)
{
    char	*start = methodName(aMethod);
    char	 end[1024];
    char	 argString[32];
    //char	 *aChar[1], *prevChar[1];
    char	 aChar[1], prevChar[1];
    int		 argCount = 0, i, len = strlen(start);	
	
    end[0] = '\0';
    
    for (i=0 ; i<len ; i++)
    {
	aChar[0] = start[i];
	
	if ((start[i] == ':') && (prevChar[0] == ':'))
	{			
	    sprintf(argString, "anArg: arg%d ", argCount);
	    strcat(end, argString);
	    argCount++;
	}
	else if (start[i] == ':')
	{			
	    sprintf(argString, ": arg%d ", argCount);
	    strcat(end, argString);
	    argCount++;
	}
	else
	{
	    aChar[1] = '\0';
	    strcat(end, aChar);
	}
	prevChar[0] = aChar[0];
    }
    return end;
}

// ============================================================
// Function:	returnTypeIsIDForMethod
// Args:		Method
// Description: Returns 1 if aMethod returns an Id and 
// 	0 if not.
// ============================================================

int returnTypeIsIDForMethod(Method aMethod)
{ 
    if (aMethod->method_types[0] == '@')
	return 1;
    return 0;
} 

// ============================================================
// Function:	idsAreEqual
// Args:		two id's
// Description:	Return one if both id's are equal and 0 if not.
// ============================================================

int idsAreEqual(id first, id second)
{ 
    if (first == second)
	return 1;
    return 0;
} 

// ============================================================
// Function:	returnTypeForMethod
// Args:		Method
// Description:	Returns a smalltalk type that describes the 
// 	return type of a method.  If the return type is not a
//  standard C type we return unknown.  
// ============================================================

char *returnTypeForMethod(Method aMethod)
{
    int	  len;
    char *temp;
    char *typeString;
	
    temp = decodeTypeForST(aMethod->method_types);

    // We can't have float as a return type, but it will automatically
    // be promoted to a double by this piece of magic.
	
    if (strcmp(temp, "float") == 0)
	return "double";

    return temp;
}

// ============================================================
// Function:		argTypeArrayForMethod
// Args:			Method
// Description:		returns an smalltalk array (an OOP) that
//  contains symbols for each argument type.
// ============================================================

OOP argTypeArrayForMethod(Method aMethod)
{
/*
	int			 i, offset, count;
	const char 	*type;
	char		 array[1024];
	
	array[0] = '\0';
	strcat(array, "( cObject cObject ");	// for the id and sel 
	
	for (i=2 ; i < method_getNumberOfArguments(aMethod) ; i++)
	{
		method_getArgumentInfo(aMethod, i, &type, &offset);
		strcat(array, decodeTypeForST(type));
		strcat(array, " ");
	}
	strcat(array, ")");
	return array;
*/
    int         i, offset, count, argCount = method_getNumberOfArguments(aMethod);
    const char *type;
    OOP		array = (OOP)arrayNew(argCount);
    OOP		argString;

    arrayAtPut(array, 1, symbolToOOP("cObject"));
    arrayAtPut(array, 2, symbolToOOP("cObject"));

    for (i=2 ; i < argCount ; i++)
    {
	method_getArgumentInfo(aMethod, i, &type, &offset);
	arrayAtPut(array, i+1, symbolToOOP(decodeTypeForST(type)));
    }

    return array;
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

SEL methodSelelector(Method aMethod)
{
    return aMethod->method_name;
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

char *methodName(Method aMethod)
{
    return (char *)sel_getName(aMethod->method_name);
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

int numberOfInstanceMethodsFor(id aClass)
{
    struct objc_method_list 	*methods;
    SEL                 		 selector;
    int                 		 i;
    int                 		 total = 0;
    struct objc_class  			*s = (struct objc_object *)aClass;
    
    for (methods = s->methods; methods; methods = methods->method_next)
	for (i = 0; (i < methods->method_count); i++)
	    if (!hasUnderscore(sel_getName((SEL)(methods->method_list[i].method_name))))
		total++;

    return total;
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

Method instanceMethodFor(id aClass, int at)
{
    struct objc_method_list 	*methods;
    SEL                 		 selector;
    //SEL                 		*selectors;
    int                 		 i;
    int                 		 total = 0;
    struct objc_class  			*s = (struct objc_object *)aClass;
    
    for (methods = s->methods; methods; methods = methods->method_next)
    {
	for (i = 0; (i < methods->method_count); i++)
	{				
	    selector = (SEL)(methods->method_list[i].method_name);
	    
	    if (total == at && !hasUnderscore(sel_getName(selector)))
		return &(methods->method_list[i]);
	    else if (!hasUnderscore(sel_getName(selector)))
		total++;
	}
    }
    return NULL;
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

int numberOfClassMethodsFor(id aClass)
{
    struct objc_method_list 	*methods;
    int                 		 i;
    int                 		 total = 0;
    struct objc_class  			*s = (struct objc_object *)aClass;
    
    for (methods = s->isa->methods; methods; methods = methods->method_next)
	for (i = 0; (i < methods->method_count); i++)
	    if (!hasUnderscore(sel_getName((SEL)(methods->method_list[i].method_name))))
		total++;

    return total;
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

Method classMethodFor(id aClass, int at)
{
    struct objc_method_list 	*methods;
    SEL                 		 selector;
    int                 		 i;
    int                 		 total = 0;
    struct objc_class  			*s = (struct objc_object *)aClass;

    for (methods = s->isa->methods; methods; methods = methods->method_next)
    {
	for (i = 0; (i < methods->method_count); i++)
	{
	    selector = (SEL)(methods->method_list[i].method_name);
	    
	    if (total == at && !hasUnderscore(sel_getName(selector)))
		return &(methods->method_list[i]);
	    else if (!hasUnderscore(sel_getName(selector)))
		total++;
	}
    }
    return NULL;
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

BOOL hasUnderscore(const char *string)
{
    int 	i, len = strlen(string);
    
    for (i=0 ; i<len ; i++)
	if (string[i] == '_')
	    return YES;
    
    return NO;
}


// ============================================================
// Function:
// Args:
// Description:
// ============================================================

int numberOfSubclassesOf(id aClass)
{
    NXHashTable			*p;
    NXHashState			 state;
    void				*value;
    int                	 count = 0;
    struct objc_class	*candidate;
    struct objc_class	*of =  (struct objc_object *)aClass;
    
    
    p = objc_getClasses();
    state = NXInitHashState(p);
    
    while (NXNextHashState(p, &state, &value))
    {
	candidate = (struct objc_class *) value;
	
	if (candidate->super_class == of)
	    count++;
    }
    return count;
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

id subclassOf(id aClass, int at)
{
    NXHashTable			*p;
    NXHashState			 state;
    void				*value;
    int                	 count = 0;
    struct objc_class	*candidate;
    struct objc_class	*of =  (struct objc_object *)aClass;
    id					 class;
    
    
    p = objc_getClasses();
    state = NXInitHashState(p);

    while (NXNextHashState(p, &state, &value))
    {
	candidate = (struct objc_class *) value;
	if (candidate->super_class == of)
	{
	    if (at == count)
		return candidate;
	    count++;
	}
    }
    return class;
}

// ============================================================
// Function:
// Args:
// Description:
// ============================================================

int forwardToSmalltalk(id aClass, SEL aSelector)
{
    return [[aClass class] forwardToSmalltalk:aSelector];
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.