int TclOOCopyObjectCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_Object oPtr, o2Ptr; if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "sourceName ?targetName?"); return TCL_ERROR; } oPtr = Tcl_GetObjectFromObj(interp, objv[1]); if (oPtr == NULL) { return TCL_ERROR; } /* * Create a cloned object of the correct class. Note that constructors are * not called. Also note that we must resolve the object name ourselves * because we do not want to create the object in the current namespace, * but rather in the context of the namespace of the caller of the overall * [oo::define] command. */ if (objc == 2) { o2Ptr = Tcl_CopyObjectInstance(interp, oPtr, NULL, NULL); } else { const char *name; Tcl_DString buffer; name = TclGetString(objv[2]); Tcl_DStringInit(&buffer); if (name[0]!=':' || name[1]!=':') { Interp *iPtr = (Interp *) interp; if (iPtr->varFramePtr != NULL) { Tcl_DStringAppend(&buffer, iPtr->varFramePtr->nsPtr->fullName, -1); } TclDStringAppendLiteral(&buffer, "::"); Tcl_DStringAppend(&buffer, name, -1); name = Tcl_DStringValue(&buffer); } o2Ptr = Tcl_CopyObjectInstance(interp, oPtr, name, NULL); Tcl_DStringFree(&buffer); } if (o2Ptr == NULL) { return TCL_ERROR; } /* * Return the name of the cloned object. */ Tcl_SetObjResult(interp, TclOOObjectName(interp, (Object *) o2Ptr)); return TCL_OK; }
int TclOONextToObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Interp *iPtr = (Interp *) interp; CallFrame *framePtr = iPtr->varFramePtr; Class *classPtr; CallContext *contextPtr; int i; Tcl_Object object; const char *methodType; /* * Start with sanity checks on the calling context to make sure that we * are invoked from a suitable method context. If so, we can safely * retrieve the handle to the object call context. */ if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "%s may only be called from inside a method", TclGetString(objv[0]))); Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL); return TCL_ERROR; } contextPtr = framePtr->clientData; /* * Sanity check the arguments; we need the first one to refer to a class. */ if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "class ?arg...?"); return TCL_ERROR; } object = Tcl_GetObjectFromObj(interp, objv[1]); if (object == NULL) { return TCL_ERROR; } classPtr = ((Object *)object)->classPtr; if (classPtr == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "\"%s\" is not a class", TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "OO", "CLASS_REQUIRED", NULL); return TCL_ERROR; } /* * Search for an implementation of a method associated with the current * call on the call chain past the point where we currently are. Do not * allow jumping backwards! */ for (i=contextPtr->index+1 ; i<contextPtr->callPtr->numChain ; i++) { struct MInvoke *miPtr = contextPtr->callPtr->chain + i; if (!miPtr->isFilter && miPtr->mPtr->declaringClassPtr == classPtr) { /* * Invoke the (advanced) method call context in the caller * context. Note that this is like [uplevel 1] and not [eval]. */ TclNRAddCallback(interp, NextRestoreFrame, framePtr, contextPtr, INT2PTR(contextPtr->index), NULL); contextPtr->index = i-1; iPtr->varFramePtr = framePtr->callerVarPtr; return TclNRObjectContextInvokeNext(interp, (Tcl_ObjectContext) contextPtr, objc, objv, 2); } } /* * Generate an appropriate error message, depending on whether the value * is on the chain but unreachable, or not on the chain at all. */ if (contextPtr->callPtr->flags & CONSTRUCTOR) { methodType = "constructor"; } else if (contextPtr->callPtr->flags & DESTRUCTOR) { methodType = "destructor"; } else { methodType = "method"; } for (i=contextPtr->index ; i>=0 ; i--) { struct MInvoke *miPtr = contextPtr->callPtr->chain + i; if (!miPtr->isFilter && miPtr->mPtr->declaringClassPtr == classPtr) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "%s implementation by \"%s\" not reachable from here", methodType, TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "OO", "CLASS_NOT_REACHABLE", NULL); return TCL_ERROR; } } Tcl_SetObjResult(interp, Tcl_ObjPrintf( "%s has no non-filter implementation by \"%s\"", methodType, TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "OO", "CLASS_NOT_THERE", NULL); return TCL_ERROR; }
static int Initialize ( Tcl_Interp *interp) { Tcl_Namespace *nsPtr; Tcl_Namespace *itclNs; Tcl_HashEntry *hPtr; Tcl_Obj *objPtr; ItclObjectInfo *infoPtr; const char * ret; char *res_option; int opt; int isNew; if (Tcl_InitStubs(interp, "8.6", 0) == NULL) { return TCL_ERROR; } ret = TclOOInitializeStubs(interp, "1.0"); if (ret == NULL) { return TCL_ERROR; } nsPtr = Tcl_CreateNamespace(interp, ITCL_NAMESPACE, NULL, NULL); if (nsPtr == NULL) { Tcl_Panic("Itcl: cannot create namespace: \"%s\" \n", ITCL_NAMESPACE); } nsPtr = Tcl_CreateNamespace(interp, ITCL_NAMESPACE"::methodset", NULL, NULL); if (nsPtr == NULL) { Tcl_Panic("Itcl: cannot create namespace: \"%s::methodset\" \n", ITCL_NAMESPACE); } nsPtr = Tcl_CreateNamespace(interp, ITCL_NAMESPACE"::internal::dicts", NULL, NULL); if (nsPtr == NULL) { Tcl_Panic("Itcl: cannot create namespace: \"%s::internal::dicts\" \n", ITCL_NAMESPACE); } Tcl_CreateObjCommand(interp, ITCL_NAMESPACE"::finish", ItclFinishCmd, NULL, NULL); /* for debugging only !!! */ #ifdef OBJ_REF_COUNT_DEBUG Tcl_CreateObjCommand(interp, ITCL_NAMESPACE"::dumprefcountinfo", ItclDumpRefCountInfo, NULL, NULL); #endif #ifdef ITCL_PRESERVE_DEBUG Tcl_CreateObjCommand(interp, ITCL_NAMESPACE"::dumppreserveinfo", ItclDumpPreserveInfo, NULL, NULL); #endif /* END for debugging only !!! */ Tcl_CreateObjCommand(interp, ITCL_NAMESPACE"::methodset::callCCommand", ItclCallCCommand, NULL, NULL); Tcl_CreateObjCommand(interp, ITCL_NAMESPACE"::methodset::objectUnknownCommand", ItclObjectUnknownCommand, NULL, NULL); /* * Create the top-level data structure for tracking objects. * Store this as "associated data" for easy access, but link * it to the itcl namespace for ownership. */ infoPtr = (ItclObjectInfo*)ckalloc(sizeof(ItclObjectInfo)); memset(infoPtr, 0, sizeof(ItclObjectInfo)); infoPtr->interp = interp; infoPtr->class_meta_type = (Tcl_ObjectMetadataType *)ckalloc( sizeof(Tcl_ObjectMetadataType)); infoPtr->class_meta_type->version = TCL_OO_METADATA_VERSION_CURRENT; infoPtr->class_meta_type->name = "ItclClass"; infoPtr->class_meta_type->deleteProc = ItclDeleteClassMetadata; infoPtr->class_meta_type->cloneProc = NULL; infoPtr->object_meta_type = (Tcl_ObjectMetadataType *)ckalloc( sizeof(Tcl_ObjectMetadataType)); infoPtr->object_meta_type->version = TCL_OO_METADATA_VERSION_CURRENT; infoPtr->object_meta_type->name = "ItclObject"; infoPtr->object_meta_type->deleteProc = ItclDeleteObjectMetadata; infoPtr->object_meta_type->cloneProc = NULL; Tcl_InitHashTable(&infoPtr->objects, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&infoPtr->objectCmds, TCL_ONE_WORD_KEYS); Tcl_InitObjHashTable(&infoPtr->objectNames); Tcl_InitHashTable(&infoPtr->classes, TCL_ONE_WORD_KEYS); Tcl_InitObjHashTable(&infoPtr->nameClasses); Tcl_InitHashTable(&infoPtr->namespaceClasses, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&infoPtr->procMethods, TCL_ONE_WORD_KEYS); Tcl_InitObjHashTable(&infoPtr->instances); Tcl_InitHashTable(&infoPtr->objectInstances, TCL_ONE_WORD_KEYS); Tcl_InitObjHashTable(&infoPtr->classTypes); infoPtr->ensembleInfo = (EnsembleInfo *)ckalloc(sizeof(EnsembleInfo)); memset(infoPtr->ensembleInfo, 0, sizeof(EnsembleInfo)); Tcl_InitHashTable(&infoPtr->ensembleInfo->ensembles, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&infoPtr->ensembleInfo->subEnsembles, TCL_ONE_WORD_KEYS); infoPtr->ensembleInfo->numEnsembles = 0; infoPtr->protection = ITCL_DEFAULT_PROTECT; infoPtr->currClassFlags = 0; infoPtr->buildingWidget = 0; infoPtr->typeDestructorArgumentPtr = Tcl_NewStringObj("", -1); Tcl_IncrRefCount(infoPtr->typeDestructorArgumentPtr); infoPtr->lastIoPtr = NULL; Tcl_SetVar(interp, ITCL_NAMESPACE"::internal::dicts::classes", "", 0); Tcl_SetVar(interp, ITCL_NAMESPACE"::internal::dicts::objects", "", 0); Tcl_SetVar(interp, ITCL_NAMESPACE"::internal::dicts::classOptions", "", 0); Tcl_SetVar(interp, ITCL_NAMESPACE"::internal::dicts::classDelegatedOptions", "", 0); Tcl_SetVar(interp, ITCL_NAMESPACE"::internal::dicts::classComponents", "", 0); Tcl_SetVar(interp, ITCL_NAMESPACE"::internal::dicts::classVariables", "", 0); Tcl_SetVar(interp, ITCL_NAMESPACE"::internal::dicts::classFunctions", "", 0); Tcl_SetVar(interp, ITCL_NAMESPACE"::internal::dicts::classDelegatedFunctions", "", 0); hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes, (char *)Tcl_NewStringObj("class", -1), &isNew); Tcl_SetHashValue(hPtr, ITCL_CLASS); hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes, (char *)Tcl_NewStringObj("type", -1), &isNew); Tcl_SetHashValue(hPtr, ITCL_TYPE); hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes, (char *)Tcl_NewStringObj("widget", -1), &isNew); Tcl_SetHashValue(hPtr, ITCL_WIDGET); hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes, (char *)Tcl_NewStringObj("widgetadaptor", -1), &isNew); Tcl_SetHashValue(hPtr, ITCL_WIDGETADAPTOR); hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes, (char *)Tcl_NewStringObj("extendedclass", -1), &isNew); Tcl_SetHashValue(hPtr, ITCL_ECLASS); res_option = getenv("ITCL_USE_OLD_RESOLVERS"); if (res_option == NULL) { opt = 1; } else { opt = atoi(res_option); } infoPtr->useOldResolvers = opt; Itcl_InitStack(&infoPtr->clsStack); Itcl_InitStack(&infoPtr->contextStack); Itcl_InitStack(&infoPtr->constructorStack); Tcl_SetAssocData(interp, ITCL_INTERP_DATA, (Tcl_InterpDeleteProc*)FreeItclObjectInfo, (ClientData)infoPtr); Itcl_PreserveData((ClientData)infoPtr); #ifdef NEW_PROTO_RESOLVER ItclVarsAndCommandResolveInit(interp); #endif /* first create the Itcl base class as root of itcl classes */ if (Tcl_EvalEx(interp, clazzClassScript, -1, 0) != TCL_OK) { Tcl_Panic("cannot create Itcl root class ::itcl::clazz"); } objPtr = Tcl_NewStringObj("::itcl::clazz", -1); infoPtr->clazzObjectPtr = Tcl_GetObjectFromObj(interp, objPtr); /* work around for SF bug #254 needed because of problem in TclOO 1.0.2 !! */ if (Tcl_PkgPresent(interp, "TclOO", "1.0.2", 1) != NULL) { Itcl_IncrObjectRefCount(infoPtr->clazzObjectPtr); } Tcl_DecrRefCount(objPtr); if (infoPtr->clazzObjectPtr == NULL) { Tcl_AppendResult(interp, "ITCL: cannot get Object for ::itcl::clazz for class \"", "::itcl::clazz", "\"", NULL); return TCL_ERROR; } infoPtr->clazzClassPtr = Tcl_GetObjectAsClass(infoPtr->clazzObjectPtr); AddClassUnknowMethod(interp, infoPtr, infoPtr->clazzClassPtr); /* * Initialize the ensemble package first, since we need this * for other parts of [incr Tcl]. */ if (Itcl_EnsembleInit(interp) != TCL_OK) { return TCL_ERROR; } Itcl_ParseInit(interp, infoPtr); /* * Create "itcl::builtin" namespace for commands that * are automatically built into class definitions. */ if (Itcl_BiInit(interp, infoPtr) != TCL_OK) { return TCL_ERROR; } /* * Export all commands in the "itcl" namespace so that they * can be imported with something like "namespace import itcl::*" */ itclNs = Tcl_FindNamespace(interp, "::itcl", (Tcl_Namespace*)NULL, TCL_LEAVE_ERR_MSG); /* * This was changed from a glob export (itcl::*) to explicit * command exports, so that the itcl::is command can *not* be * exported. This is done for concern that the itcl::is command * imported might be confusing ("is"). */ if (!itclNs || (Tcl_Export(interp, itclNs, "body", /* reset */ 1) != TCL_OK) || (Tcl_Export(interp, itclNs, "class", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "code", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "configbody", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "delete", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "delete_helper", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "ensemble", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "filter", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "find", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "forward", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "local", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "mixin", 0) != TCL_OK) || (Tcl_Export(interp, itclNs, "scope", 0) != TCL_OK)) { return TCL_ERROR; } Tcl_CreateObjCommand(interp, ITCL_NAMESPACE"::internal::commands::sethullwindowname", ItclSetHullWindowName, infoPtr, NULL); Tcl_CreateObjCommand(interp, ITCL_NAMESPACE"::internal::commands::checksetitclhull", ItclCheckSetItclHull, infoPtr, NULL); /* * Set up the variables containing version info. */ Tcl_SetVar(interp, "::itcl::version", ITCL_VERSION, TCL_NAMESPACE_ONLY); Tcl_SetVar(interp, "::itcl::patchLevel", ITCL_PATCH_LEVEL, TCL_NAMESPACE_ONLY); #ifdef ITCL_DEBUG_C_INTERFACE RegisterDebugCFunctions(interp); #endif /* * Package is now loaded. */ Tcl_PkgProvideEx(interp, "Itcl", ITCL_PATCH_LEVEL, &itclStubs); return Tcl_PkgProvideEx(interp, "itcl", ITCL_PATCH_LEVEL, &itclStubs); }