/* Implementation for Objective-C Tcl interpreter functions Copyright (C) 1993,1994 R. Andrew McCallum Written by: R. Andrew McCallum Dept. of Computer Science, U. of Rochester, Rochester, NY 14627 With NeXT runtime compatibility incorporated by: Robert Stabl Comp. Sci. Inst., U. of Munich, Leopoldstr. 11B D-80802 Muenchen This file is part of the Tcl/Objective-C interface 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /***************************************************************** in Tcl type: set tclObjcDebug 1 to see debugging information at each message send. *******************************************************************/ /* Choose between: 1. Each time an object is returned, it is defined as a tcl command. 2. Messages to Objective-C objects are caught in 'unknown'. I think 2. is better. */ #define OBJECTS_AS_TCL_COMMANDS 0 #include "tclObjc.h" #include "objc-malloc.h" #include id getObjectReturn(void *); unsigned getPointerReturn(void *); int getIntegerReturn(void *); unsigned int getUIntegerReturn(void *); short getShortReturn(void *); unsigned short getUShortReturn(void *); long getLongReturn(void *); unsigned long getULongReturn(void *); char getCharReturn(void *); unsigned char getUCharReturn(void *); char * getStringReturn(void *); float getFloatReturn(void *); double getDoubleReturn(void *); #include #include #include "coll/List.h" /* for special case hack */ extern int method_get_sizeof_arguments (struct objc_method* mth); #if (HAVE_LIBCOLL) #include /* for special case hack */ #endif /* HAVE_LIBCOLL */ #define XSTR(s) STR(s) #define STR(s) #s const char coll_version[] = XSTR(TCLOBJC_VERSION); int (*tclObjc_eventHook)(); Tcl_Interp *_TclObject_interp; char *tclObjc_objectToName(id obj) { /* Fix this messiness */ static char name[512]; if (obj) { sprintf(name, "%s@0x%x", obj->class_pointer->name, (unsigned)obj); return name; } return "nil"; } extern char *strchr(); /* Return TCLOBJC_NO_OBJ if name is no good */ id tclObjc_nameToObject(const char *name) { id object; unsigned long ul; const char *p = name; while (*p != '@' && *p != '\0') p++; if ((*p) && (sscanf(p+3, "%lx", &ul) == 1)) { return (id)ul; } else if ((!strcmp(name, "nil")) || (!strcmp(name, "Nil")) || (!strcmp(name, "0x0"))) { return nil; } else if ((object = (id)objc_lookup_class(name))) { return object; } return TCLOBJC_NO_OBJ; } int tclObjc_msgSendToClientData(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { char resultString[1024]; char methodName[100]; BOOL argvIsMethodArg[256]; id self; SEL sel; Method_t method; int i; if (argc < 2) { interp->result = "no method specified."; return TCL_ERROR; } argvIsMethodArg[0] = NO; argvIsMethodArg[1] = NO; strcpy(methodName, argv[1]); for (i = 2; i < argc; i++) { if (argv[i][strlen(argv[i])-1] == ':') { strcat(methodName, argv[i]); argvIsMethodArg[i] = NO; } else { argvIsMethodArg[i] = YES; } } self = (id)clientData; #if (HAVE_LIBCOLL) /* special case hack for getting Arrays of id's to tcl. Send the message "contents" to an Array object. */ if (!strcmp("contents", methodName) && [self isKindOf:[Array class]] && !strcmp("@",[self contentEncoding])) { int i; Tcl_ResetResult(interp); for (i = 0; i < [self count]; i++) { Tcl_AppendElement(interp, tclObjc_objectToName([self elementAtIndex:i].id_u)); } return TCL_OK; } #endif /* HAVE_LIBCOLL */ /* special case hack for getting List contents to tcl. Send the message "contents" to a List object. */ if (!strcmp("contents", methodName) && [self isKindOf:[List class]]) { int i; Tcl_ResetResult(interp); for (i = 0; i < [self count]; i++) { Tcl_AppendElement(interp, tclObjc_objectToName([self objectAt:i])); } return TCL_OK; } /* special case hack for sending message to a TclObject */ if (self->class_pointer == [TclObject class]) { static Tcl_DString command; static char *cmd; int i; int code; Tcl_DStringInit(&command); Tcl_DStringAppend(&command, ((TclObject*)self)->_tclName, -1); Tcl_DStringAppend(&command, " ", -1); Tcl_DStringAppend(&command, methodName, -1); for (i = 2; i < argc; i++) { if (argvIsMethodArg[i]) continue; Tcl_DStringAppendElement(&command, argv[i]); Tcl_DStringAppend(&command, " ", -1); } cmd = Tcl_DStringAppend(&command, "\n", -1); if (!(((TclObject*)self)->_interp)) { fprintf(stderr, "TclObject interp not yet set\n"); return TCL_ERROR; } code = Tcl_Eval(((TclObject*)self)->_interp, cmd); if (code != TCL_OK) { char *msg; msg = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); if (msg == NULL) { msg = interp->result; } fprintf(stderr, "(tclObjc: messaging a TclObject:) %s\n", msg); fprintf(stderr, "while evaluating: %s\n", cmd); } Tcl_DStringFree(&command); return code; } sel = sel_get_uid(methodName); if (![self respondsTo:sel]) { printf("%s does not respond to method %s\n", [self name], methodName); Tcl_SetResult(interp, "object does not respond to method", TCL_STATIC); return TCL_ERROR; } if (object_is_instance(self)) method = class_get_instance_method(self->class_pointer, sel); else method = class_get_class_method(self->class_pointer, sel); if (!method) { printf("class %s doesn't have method %s\n", self->class_pointer->name, methodName); Tcl_SetResult(interp, "method is NULL", TCL_STATIC); return TCL_ERROR; } { # define BUILDNEWARGFRAME # ifdef BUILDNEWARGFRAME arglist_t argframe; int regArgSize; const char * typeForReg; # else arglist_t argframe = __builtin_apply_args(); # endif char *datum; void *retframe = NULL ; int argsize = method_get_sizeof_arguments(method); char argptr_buffer[argsize]; unsigned int bargframe = (unsigned int)argptr_buffer; int argnum; const char *type; int tmpint; int tmpuint; char *objcdebug; BOOL debug_printing; #if OBJECTS_AS_TCL_COMMANDS Tcl_CmdInfo cmdInfo; #endif // // We attempt to avoid the __builtin dynamic call entirely // in a few common cases. For example, when all the arguments // and the return value is either an object or an int. // int do_special_hack = 1 ; int hack_arg_count = 0 ; int hack_arguments[3] ; int returnValue = 0; #ifdef BUILDNEWARGFRAME // create the pointer argframe to memory on the stack typeForReg = (const char *) strrchr(objc_skip_typespec(method->method_types), '+'); if (typeForReg) regArgSize = atoi(++typeForReg) + sizeof(void *); else regArgSize = 0; argframe = (arglist_t) alloca(sizeof(char *) + regArgSize); #endif argframe->arg_ptr = argptr_buffer; objcdebug = Tcl_GetVar(interp, "tclObjcDebug", TCL_GLOBAL_ONLY); if (objcdebug) debug_printing = YES; else debug_printing = NO; /* Perhaps later we could add different levels of debugging depending on the contents of objcdebug */ if(debug_printing) printf("The method: %s \n",methodName) ; if (debug_printing) printf("method %s, argc %d argsize %d (on stack), method types: '%s'\n", methodName, argc, argsize, method->method_types); #ifdef BUILDNEWARGFRAME if (debug_printing) printf("Found %d bytes of register args.\n", regArgSize); #endif datum = method_get_first_argument(method, argframe, &type); *(id*)datum = self; datum = method_get_next_argument(argframe, &type); *(SEL*)datum = sel; if (debug_printing) { printf("Filling in method arguments now. There should be %d.\n", method_get_number_of_arguments(method)); } switch( *(method->method_types) ){ case _C_ID: case _C_PTR: case _C_INT: case _C_UINT: case _C_CHARPTR: case _C_VOID: if(debug_printing) printf("Return type is compatible with special_hack!!!\n") ; break ; case _C_SHT: case _C_USHT: case _C_LNG: case _C_ULNG: case _C_CHR: case _C_UCHR: case _C_FLT: case _C_DBL: default: do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> incompatible return type!\n") ; break ; } if(method_get_number_of_arguments(method) > 5){ do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> too many arguments!\n") ; } for (argnum = 2, datum = method_get_next_argument(argframe, &type); datum; datum = method_get_next_argument(argframe, &type), ({argnum++; while (datum && !argvIsMethodArg[argnum]) argnum++;})) { #define marg_getRef(margs, offset, type) ( (type *)offset ) unsigned flags = objc_get_type_qualifiers(type); type = objc_skip_type_qualifiers(type); flags = flags; if (debug_printing) { printf("datum=%x type=%s\n", (unsigned int)datum - bargframe, type); printf("argv[%d] = %s type=%s\n", argnum, argv[argnum], type); } switch (*type) { case _C_ID: *(marg_getRef(argframe, datum, id)) = tclObjc_nameToObject(argv[argnum]); if (*(marg_getRef(argframe, datum, id)) == TCLOBJC_NO_OBJ) { sprintf(interp->result, "Expected objc object, got %s instead.\n", argv[argnum]); return TCL_ERROR; } if(do_special_hack){ hack_arguments[hack_arg_count] = (int) tclObjc_nameToObject(argv[argnum]) ; if(debug_printing) printf("Special Hack: Turned %s (ID) to %d.\n", argv[argnum],hack_arguments[hack_arg_count]) ; hack_arg_count++ ; } break; case _C_PTR: sscanf(argv[argnum], "0x%x", (marg_getRef(argframe, datum, unsigned int))); if(do_special_hack){ sscanf(argv[argnum], "0x%x", hack_arguments + hack_arg_count) ; if(debug_printing) printf("Special Hack: Turned %s (PTR) to %d.\n", argv[argnum],hack_arguments[hack_arg_count]) ; hack_arg_count++ ; } break; case _C_INT: sscanf(argv[argnum], "%d", (marg_getRef(argframe, datum, int))); if(do_special_hack){ sscanf(argv[argnum], "%d", hack_arguments + hack_arg_count) ; if(debug_printing) printf("Special Hack: Turned %s (INT) to %d.\n", argv[argnum],hack_arguments[hack_arg_count]) ; hack_arg_count++ ; } break; case _C_UINT: sscanf(argv[argnum], "%u", (marg_getRef(argframe, datum, unsigned int))); if(do_special_hack){ sscanf(argv[argnum], "%u", hack_arguments + hack_arg_count) ; if(debug_printing) printf("Special Hack: Turned %s (UINT) to %d.\n", argv[argnum],hack_arguments[hack_arg_count]) ; hack_arg_count++ ; } break; case _C_LNG: do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> unsigned short typed argument!\n") ; sscanf(argv[argnum], "%ld", (marg_getRef(argframe, datum, long))); break; case _C_ULNG: do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> unsigned short typed argument!\n") ; sscanf(argv[argnum], "%lu", (marg_getRef(argframe, datum, unsigned long))); break; case _C_SHT: do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> short typed argument!\n") ; sscanf(argv[argnum], "%d", &tmpint); *(marg_getRef(argframe, datum, short)) = (short)tmpint; break; case _C_USHT: do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> unsigned short typed argument!\n") ; sscanf(argv[argnum], "%u", &tmpuint); *(marg_getRef(argframe, datum, unsigned short)) = (unsigned short)tmpuint; break; case _C_CHR: do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> char typed argument!\n") ; sscanf(argv[argnum], "%c", (marg_getRef(argframe, datum, char))); break; case _C_UCHR: do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> unsigned char argument!\n") ; sscanf(argv[argnum], "%d", &tmpuint); *(marg_getRef(argframe, datum, unsigned char)) = (unsigned char)tmpuint; break; case _C_CHARPTR: *(marg_getRef(argframe, datum, char*)) = argv[argnum]; if(do_special_hack){ hack_arguments[hack_arg_count] = (int) argv[argnum] ; if(debug_printing) printf("Special Hack: Turned %s (CHARPTR) to %d.\n", argv[argnum],hack_arguments[hack_arg_count]) ; hack_arg_count++ ; } break; case _C_FLT: do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> float typed argument!\n") ; sscanf(argv[argnum], "%f", (marg_getRef(argframe, datum, float))); break; case _C_DBL: do_special_hack = 0 ; if(debug_printing) printf("Abandoning special_hack option -> double typed argument!\n") ; sscanf(argv[argnum], "%lf", (marg_getRef(argframe, datum, double))); break; default: { fprintf(stderr, "Tcl can't handle arg type %s", type); sprintf(resultString, "Tcl can't handle arg type %s", type); Tcl_SetResult(interp, resultString, TCL_VOLATILE); return TCL_ERROR; } } } if(do_special_hack){ typedef int (*IntImp)(id, SEL, ...) ; IntImp theCall ; theCall = (IntImp) [self methodFor: sel] ; switch(hack_arg_count) { case 0: returnValue = theCall(self,sel) ; break ; case 1: returnValue = theCall(self,sel,hack_arguments[0]) ; break ; case 2: returnValue = theCall(self,sel,hack_arguments[0],hack_arguments[1]) ; break ; case 3: returnValue = theCall(self,sel,hack_arguments[0], hack_arguments[1], hack_arguments[2]) ; break ; default: fprintf(stderr,"Something went awfully wrong in the tclObjc special_hack\n") ; exit(-1) ; break ; } } else { retframe = __builtin_apply((apply_t)method->method_imp, (void*)argframe, argsize); } if (debug_printing) { if(do_special_hack) printf("Special_Hack: return value unsigned int 0x%x\n",returnValue) ; else printf("__Builtin_Apply: retframe unsigned int 0x%x\n", getIntegerReturn(retframe)); } type = method->method_types; switch (*type) { case _C_ID: { id returnedObject; char * s; if(do_special_hack) returnedObject = (id) returnValue ; else returnedObject = getObjectReturn(retframe); s = tclObjc_objectToName(returnedObject); sprintf(resultString, s); } #if OBJECTS_AS_TCL_COMMANDS if (!Tcl_GetCommandInfo(interp, resultString, &cmdInfo)) Tcl_CreateCommand(interp, resultString, tclObjc_msgSendToClientData, *(id*)retframe, 0); #else /* messages caught and forwarded by tcl proc "unknown" */ #endif break; case _C_PTR: if(do_special_hack) sprintf(resultString, "0x%x", returnValue); else sprintf(resultString, "0x%x", getPointerReturn(retframe)); break; case _C_INT: if(do_special_hack) sprintf(resultString, "%d", returnValue); else sprintf(resultString, "%d", getIntegerReturn(retframe)); break; case _C_UINT: if(do_special_hack) sprintf(resultString, "%u", returnValue); else sprintf(resultString, "%u", getUIntegerReturn(retframe)); break; case _C_SHT: sprintf(resultString, "%d", getShortReturn(retframe)); break; case _C_USHT: sprintf(resultString, "%u", getUShortReturn(retframe)); break; case _C_LNG: sprintf(resultString, "%ld", getLongReturn(retframe)); break; case _C_ULNG: sprintf(resultString, "%lx", getULongReturn(retframe)); break; case _C_CHR: sprintf(resultString, "%d", getCharReturn(retframe)); break; case _C_UCHR: sprintf(resultString, "%d", getUCharReturn(retframe)); break; case _C_CHARPTR: /* Yuck. Clean this up. */ if(do_special_hack) Tcl_SetResult(interp, (char *) returnValue, TCL_VOLATILE); else Tcl_SetResult(interp, getStringReturn(retframe), TCL_VOLATILE); return TCL_OK; case _C_FLT: sprintf(resultString, "%g", getFloatReturn(retframe)); break; case _C_DBL: sprintf(resultString, "%g", getDoubleReturn(retframe)); break; case _C_VOID: resultString[0] = '\0'; break; default: { fprintf(stderr, "Tcl can't handle ret type %s", type); sprintf(resultString, "Tcl can't handle ret type %s", type); Tcl_SetResult(interp, resultString, TCL_VOLATILE); return TCL_ERROR; } } Tcl_SetResult(interp, resultString, TCL_VOLATILE); if (*tclObjc_eventHook) (*tclObjc_eventHook)(); return TCL_OK; } } // // __builtin_return does not seem to work within nested procedures so // we must give up using the macro GET_RETVAL as defined in previous // versions of libtclObjc // id getObjectReturn(void * p) { __builtin_return(p); } unsigned getPointerReturn(void * p) { __builtin_return(p); } int getIntegerReturn(void * p) { __builtin_return(p); } unsigned int getUIntegerReturn(void * p) { __builtin_return(p); } short getShortReturn(void * p) { __builtin_return(p); } unsigned short getUShortReturn(void * p) { __builtin_return(p); } long getLongReturn(void * p) { __builtin_return(p); } unsigned long getULongReturn(void * p) { __builtin_return(p); } char getCharReturn(void * p) { __builtin_return(p); } unsigned char getUCharReturn(void * p) { __builtin_return(p); } char * getStringReturn(void * p) { __builtin_return(p); } float getFloatReturn(void * p) { __builtin_return(p); } double getDoubleReturn(void * p) { __builtin_return(p); } void tclObjc_registerObjectWithName(Tcl_Interp *interp, id object, const char *name) { Tcl_CreateCommand(interp, (char *)name, tclObjc_msgSendToClientData, object, 0); } void tclObjc_unregisterObjectNamed(Tcl_Interp *interp, const char *name) { Tcl_DeleteCommand(interp, (char *)name); } void tclObjc_registerClassnames(Tcl_Interp *interp) { id class; void *es = NULL; while ((class = objc_next_class(&es))) tclObjc_registerObjectWithName(interp, class, [class name]); #if 0 node_ptr node = NULL; /* register all class names with tcl */ while ((node = hash_next(__objc_class_hash, node))) { // printf("registering %s\n", (char *)node->key); tclObjc_registerObjectWithName(interp, node->value, node->key); } #endif } int tclObjc_msgSendToArgv1(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { id obj; if ((obj = tclObjc_nameToObject(argv[1])) != TCLOBJC_NO_OBJ) { return tclObjc_msgSendToClientData((ClientData)obj, interp, argc-1, &(argv[1])); } else { sprintf(interp->result, "tclObjc: %s not recognized as an object", argv[1]); return TCL_ERROR; } } @implementation TclObject + newName: (char *)objectName { TclObject *newTclObject = class_create_instance(self); OBJC_MALLOC(newTclObject->_tclName, char, strlen(objectName)+1); strcpy(newTclObject->_tclName, objectName); /* Fix this ugliness!!! */ newTclObject->_interp = _TclObject_interp; return newTclObject; } - free { OBJC_FREE(_tclName); return object_dispose(self); } - (BOOL) respondsTo: (SEL)aSel { Tcl_CmdInfo cmdInfo; char selString[128]; sprintf(selString, "%s%s", _tclName, sel_get_name(aSel)); return (((object_is_instance(self) ?class_get_instance_method(self->ISA, aSel) :class_get_class_method(self->ISA, aSel))!=METHOD_NULL) || Tcl_GetCommandInfo(_interp, selString, &cmdInfo)); } - forward: (SEL)aSel : (arglist_t)argframe { return [self performv: aSel :argframe]; } - performv:(SEL)aSel :(arglist_t)argframe { char *datum; const char *type; char *objcdebug; BOOL debug_printing; Method_t method = 0; char argString[256]; Tcl_DString command; char *cmd; int tmpint; unsigned int tmpuint; if (_interp == NULL) { fprintf(stderr, "interp not set yet, %s\n", sel_get_name(aSel)); return self; } objcdebug = Tcl_GetVar(_interp, "objcdebug", TCL_GLOBAL_ONLY); if (objcdebug) debug_printing = YES; else debug_printing = NO; Tcl_DStringInit(&command); Tcl_DStringAppend(&command, _tclName, -1); // Tcl_DStringAppend(&command, " ", -1); Tcl_DStringAppend(&command, (char *)sel_get_name(aSel), -1); Tcl_DStringAppend(&command, " ", -1); if (debug_printing) printf("selector: %s\n", sel_get_name(aSel)); /* search all classes for the method */ { id class; void *es = NULL; while ((class = objc_next_class(&es)) && (!(method = class_get_instance_method(class, aSel))) && (!(method = class_get_class_method(class, aSel)))) ; } #if 0 { node_ptr node = NULL; while ((node = hash_next(__objc_class_hash, node)) && (!(method = class_get_instance_method(node->value, aSel))) && (!(method = class_get_class_method(node->value, aSel)))) ; } #endif if (!method) { fprintf(stderr, "method not found, %s\n", sel_get_name(aSel)); return self; } /* self */ datum = method_get_first_argument(method, argframe, &type); /* SEL */ datum = method_get_next_argument(argframe, &type); for (datum = method_get_next_argument(argframe, &type); datum; datum = method_get_next_argument(argframe, &type)) { unsigned flags = objc_get_type_qualifiers(type); type = objc_skip_type_qualifiers(type); flags = flags; switch (*type) { case _C_PTR: sprintf(argString, "0x%x", *(unsigned int*)(marg_getRef(argframe, datum, unsigned int))); Tcl_DStringAppendElement(&command, argString); break; case _C_ID: strcpy(argString, tclObjc_objectToName( *(id*)(marg_getRef(argframe, datum, id)))); Tcl_DStringAppendElement(&command, argString); break; case _C_INT: sprintf(argString, "%d", *(int*)(marg_getRef(argframe, datum, int))); Tcl_DStringAppendElement(&command, argString); break; case _C_UINT: sprintf(argString, "%u", *(unsigned int*)(marg_getRef(argframe, datum, unsigned int))); Tcl_DStringAppendElement(&command, argString); break; case _C_SHT: tmpint = *(short*)(marg_getRef(argframe, datum, short)); sprintf(argString, "%d", tmpint); Tcl_DStringAppendElement(&command, argString); break; case _C_USHT: tmpuint = *(unsigned short*)(marg_getRef(argframe, datum, unsigned short)); sprintf(argString, "%u", tmpuint); Tcl_DStringAppendElement(&command, argString); break; case _C_CHR: sprintf(argString, "%c", *(char*)(marg_getRef(argframe, datum, char))); Tcl_DStringAppendElement(&command, argString); break; case _C_UCHR: tmpuint = *(unsigned char*)(marg_getRef(argframe, datum, unsigned char)); sprintf(argString, "%u", tmpuint); Tcl_DStringAppendElement(&command, argString); break; case _C_CHARPTR: Tcl_DStringAppendElement(&command, *(char**)(marg_getRef(argframe, datum, char *))); break; case _C_FLT: sprintf(argString, "%f", *(float*)(marg_getRef(argframe, datum, float))); Tcl_DStringAppendElement(&command, argString); break; case _C_DBL: sprintf(argString, "%f", *(double*)(marg_getRef(argframe, datum, double))); Tcl_DStringAppendElement(&command, argString); break; default: { fprintf(stderr, "TclObject can't handle arg type %s", type); return self; } } } cmd = Tcl_DStringAppend(&command, "\n", -1); Tcl_GlobalEval(_interp, cmd); // I should interpret returned string and return it!; return self; } @end /*****************************************************************/ static char tclObjcInitCmd[] = "if {[llength [info procs unknown]]} { \n\ rename unknown unknown_pre_tclObjc \n\ } \n\ proc unknown {name args} {\n\ if {[string match *@0x* $name]} {\n\ return [uplevel tclObjc_msg_send $name $args]\n\ } else {\n\ if {[llength [info procs unknown_pre_tclObjc]]} {\n\ unknown_pre_tclObjc $name $args\n\ } else {\n\ error \"in unknown: invalid command name: $name\"\n\ }\n\ }\n\ }\n"; int TclObjc_Init(Tcl_Interp *interp) { #if ! OBJECTS_AS_TCL_COMMANDS int code; #endif /* Fix this ugliness!!! */ _TclObject_interp = interp; tclObjc_registerClassnames(interp); Tcl_CreateCommand(interp, "tclObjc_msg_send", tclObjc_msgSendToArgv1, 0, 0); #if ! OBJECTS_AS_TCL_COMMANDS code = Tcl_Eval(interp, tclObjcInitCmd); if (code != TCL_OK) { fprintf(stderr, "tclObjc: Error during TclObjc_Init:\n"); fprintf(stderr, interp->result); } #endif return TCL_OK; }