diff options
Diffstat (limited to 'tcl8.6/pkgs/itcl4.1.1/generic/itclMethod.c')
-rw-r--r-- | tcl8.6/pkgs/itcl4.1.1/generic/itclMethod.c | 2721 |
1 files changed, 0 insertions, 2721 deletions
diff --git a/tcl8.6/pkgs/itcl4.1.1/generic/itclMethod.c b/tcl8.6/pkgs/itcl4.1.1/generic/itclMethod.c deleted file mode 100644 index e33e62b..0000000 --- a/tcl8.6/pkgs/itcl4.1.1/generic/itclMethod.c +++ /dev/null @@ -1,2721 +0,0 @@ -/* - * ------------------------------------------------------------------------ - * PACKAGE: [incr Tcl] - * DESCRIPTION: Object-Oriented Extensions to Tcl - * - * [incr Tcl] provides object-oriented extensions to Tcl, much as - * C++ provides object-oriented extensions to C. It provides a means - * of encapsulating related procedures together with their shared data - * in a local namespace that is hidden from the outside world. It - * promotes code re-use through inheritance. More than anything else, - * it encourages better organization of Tcl applications through the - * object-oriented paradigm, leading to code that is easier to - * understand and maintain. - * - * These procedures handle commands available within a class scope. - * In [incr Tcl], the term "method" is used for a procedure that has - * access to object-specific data, while the term "proc" is used for - * a procedure that has access only to common class data. - * - * ======================================================================== - * AUTHOR: Michael J. McLennan - * Bell Labs Innovations for Lucent Technologies - * mmclennan@lucent.com - * http://www.tcltk.com/itcl - * - * overhauled version author: Arnulf Wiedemann - * ======================================================================== - * Copyright (c) 1993-1998 Lucent Technologies, Inc. - * ------------------------------------------------------------------------ - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - */ -#include "itclInt.h" - -static int EquivArgLists(Tcl_Interp *interp, ItclArgList *origArgs, - ItclArgList *realArgs); -static int ItclCreateMemberCode(Tcl_Interp* interp, ItclClass *iclsPtr, - const char* arglist, const char* body, ItclMemberCode** mcodePtr, - Tcl_Obj *namePtr, int flags); -static int ItclCreateMemberFunc(Tcl_Interp* interp, ItclClass *iclsPtr, - Tcl_Obj *namePtr, const char* arglist, const char* body, - ItclMemberFunc** imPtrPtr, int flags); - -void -ItclPreserveIMF( - ItclMemberFunc *imPtr) -{ - imPtr->refCount++; -} - -void -ItclReleaseIMF( - ClientData clientData) -{ - ItclMemberFunc *imPtr = (ItclMemberFunc *)clientData; - - if (--imPtr->refCount == 0) { - Itcl_DeleteMemberFunc(clientData); - } -} - -/* - * ------------------------------------------------------------------------ - * Itcl_BodyCmd() - * - * Invoked by Tcl whenever the user issues an "itcl::body" command to - * define or redefine the implementation for a class method/proc. - * Handles the following syntax: - * - * itcl::body <class>::<func> <arglist> <body> - * - * Looks for an existing class member function with the name <func>, - * and if found, tries to assign the implementation. If an argument - * list was specified in the original declaration, it must match - * <arglist> or an error is flagged. If <body> has the form "@name" - * then it is treated as a reference to a C handling procedure; - * otherwise, it is taken as a body of Tcl statements. - * - * Returns TCL_OK/TCL_ERROR to indicate success/failure. - * ------------------------------------------------------------------------ - */ -static int -NRBodyCmd( - ClientData clientData, /* */ - Tcl_Interp *interp, /* current interpreter */ - int objc, /* number of arguments */ - Tcl_Obj *const *objv) /* argument objects */ -{ - Tcl_HashEntry *entry; - Tcl_DString buffer; - Tcl_Obj *objPtr; - ItclClass *iclsPtr; - ItclMemberFunc *imPtr; - const char *head; - const char *tail; - const char *token; - char *arglist; - char *body; - int status = TCL_OK; - - ItclShowArgs(2, "Itcl_BodyCmd", objc, objv); - if (objc != 4) { - token = Tcl_GetString(objv[0]); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "wrong # args: should be \"", - token, " class::func arglist body\"", - (char*)NULL); - return TCL_ERROR; - } - - /* - * Parse the member name "namesp::namesp::class::func". - * Make sure that a class name was specified, and that the - * class exists. - */ - token = Tcl_GetString(objv[1]); - Itcl_ParseNamespPath(token, &buffer, &head, &tail); - - if (!head || *head == '\0') { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "missing class specifier for body declaration \"", token, "\"", - (char*)NULL); - status = TCL_ERROR; - goto bodyCmdDone; - } - - iclsPtr = Itcl_FindClass(interp, head, /* autoload */ 1); - if (iclsPtr == NULL) { - status = TCL_ERROR; - goto bodyCmdDone; - } - - /* - * Find the function and try to change its implementation. - * Note that command resolution table contains *all* functions, - * even those in a base class. Make sure that the class - * containing the method definition is the requested class. - */ - - imPtr = NULL; - objPtr = Tcl_NewStringObj(tail, -1); - entry = Tcl_FindHashEntry(&iclsPtr->resolveCmds, (char *)objPtr); - Tcl_DecrRefCount(objPtr); - if (entry) { - ItclCmdLookup *clookup; - clookup = (ItclCmdLookup *)Tcl_GetHashValue(entry); - imPtr = clookup->imPtr; - if (imPtr->iclsPtr != iclsPtr) { - imPtr = NULL; - } - } - - if (imPtr == NULL) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "function \"", tail, "\" is not defined in class \"", - Tcl_GetString(iclsPtr->fullNamePtr), "\"", - (char*)NULL); - status = TCL_ERROR; - goto bodyCmdDone; - } - - arglist = Tcl_GetString(objv[2]); - body = Tcl_GetString(objv[3]); - - if (Itcl_ChangeMemberFunc(interp, imPtr, arglist, body) != TCL_OK) { - status = TCL_ERROR; - goto bodyCmdDone; - } - -bodyCmdDone: - Tcl_DStringFree(&buffer); - return status; -} - -/* ARGSUSED */ -int -Itcl_BodyCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - return Tcl_NRCallObjProc(interp, NRBodyCmd, clientData, objc, objv); -} - - - -/* - * ------------------------------------------------------------------------ - * Itcl_ConfigBodyCmd() - * - * Invoked by Tcl whenever the user issues an "itcl::configbody" command - * to define or redefine the configuration code associated with a - * public variable. Handles the following syntax: - * - * itcl::configbody <class>::<publicVar> <body> - * - * Looks for an existing public variable with the name <publicVar>, - * and if found, tries to assign the implementation. If <body> has - * the form "@name" then it is treated as a reference to a C handling - * procedure; otherwise, it is taken as a body of Tcl statements. - * - * Returns TCL_OK/TCL_ERROR to indicate success/failure. - * ------------------------------------------------------------------------ - */ -/* ARGSUSED */ -static int -NRConfigBodyCmd( - ClientData dummy, /* unused */ - Tcl_Interp *interp, /* current interpreter */ - int objc, /* number of arguments */ - Tcl_Obj *const objv[]) /* argument objects */ -{ - int status = TCL_OK; - - const char *head; - const char *tail; - const char *token; - Tcl_DString buffer; - ItclClass *iclsPtr; - ItclVarLookup *vlookup; - ItclVariable *ivPtr; - ItclMemberCode *mcode; - Tcl_HashEntry *entry; - - ItclShowArgs(2, "Itcl_ConfigBodyCmd", objc, objv); - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "class::option body"); - return TCL_ERROR; - } - - /* - * Parse the member name "namesp::namesp::class::option". - * Make sure that a class name was specified, and that the - * class exists. - */ - token = Tcl_GetString(objv[1]); - Itcl_ParseNamespPath(token, &buffer, &head, &tail); - - if ((head == NULL) || (*head == '\0')) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "missing class specifier for body declaration \"", token, "\"", - (char*)NULL); - status = TCL_ERROR; - goto configBodyCmdDone; - } - - iclsPtr = Itcl_FindClass(interp, head, /* autoload */ 1); - if (iclsPtr == NULL) { - status = TCL_ERROR; - goto configBodyCmdDone; - } - - /* - * Find the variable and change its implementation. - * Note that variable resolution table has *all* variables, - * even those in a base class. Make sure that the class - * containing the variable definition is the requested class. - */ - vlookup = NULL; - entry = Tcl_FindHashEntry(&iclsPtr->resolveVars, tail); - if (entry) { - vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry); - if (vlookup->ivPtr->iclsPtr != iclsPtr) { - vlookup = NULL; - } - } - - if (vlookup == NULL) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "option \"", tail, "\" is not defined in class \"", - Tcl_GetString(iclsPtr->fullNamePtr), "\"", - (char*)NULL); - status = TCL_ERROR; - goto configBodyCmdDone; - } - ivPtr = vlookup->ivPtr; - - if (ivPtr->protection != ITCL_PUBLIC) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "option \"", Tcl_GetString(ivPtr->fullNamePtr), - "\" is not a public configuration option", - (char*)NULL); - status = TCL_ERROR; - goto configBodyCmdDone; - } - - token = Tcl_GetString(objv[2]); - - if (Itcl_CreateMemberCode(interp, iclsPtr, (char*)NULL, token, - &mcode) != TCL_OK) { - status = TCL_ERROR; - goto configBodyCmdDone; - } - - Itcl_PreserveData((ClientData)mcode); - Itcl_EventuallyFree((ClientData)mcode, Itcl_DeleteMemberCode); - - if (ivPtr->codePtr) { - Itcl_ReleaseData((ClientData)ivPtr->codePtr); - } - ivPtr->codePtr = mcode; - -configBodyCmdDone: - Tcl_DStringFree(&buffer); - return status; -} - -/* ARGSUSED */ -int -Itcl_ConfigBodyCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - return Tcl_NRCallObjProc(interp, NRConfigBodyCmd, clientData, objc, objv); -} - - - -/* - * ------------------------------------------------------------------------ - * Itcl_CreateMethod() - * - * Installs a method into the namespace associated with a class. - * If another command with the same name is already installed, then - * it is overwritten. - * - * Returns TCL_OK on success, or TCL_ERROR (along with an error message - * in the specified interp) if anything goes wrong. - * ------------------------------------------------------------------------ - */ -int -Itcl_CreateMethod( - Tcl_Interp* interp, /* interpreter managing this action */ - ItclClass *iclsPtr, /* class definition */ - Tcl_Obj *namePtr, /* name of new method */ - const char* arglist, /* space-separated list of arg names */ - const char* body) /* body of commands for the method */ -{ - ItclMemberFunc *imPtr; - - return ItclCreateMethod(interp, iclsPtr, namePtr, arglist, body, &imPtr); -} - -/* - * ------------------------------------------------------------------------ - * ItclCreateMethod() - * - * Installs a method into the namespace associated with a class. - * If another command with the same name is already installed, then - * it is overwritten. - * - * Returns TCL_OK on success, or TCL_ERROR (along with an error message - * in the specified interp) if anything goes wrong. - * ------------------------------------------------------------------------ - */ -int -ItclCreateMethod( - Tcl_Interp* interp, /* interpreter managing this action */ - ItclClass *iclsPtr, /* class definition */ - Tcl_Obj *namePtr, /* name of new method */ - const char* arglist, /* space-separated list of arg names */ - const char* body, /* body of commands for the method */ - ItclMemberFunc **imPtrPtr) -{ - ItclMemberFunc *imPtr; - - /* - * Make sure that the method name does not contain anything - * goofy like a "::" scope qualifier. - */ - if (strstr(Tcl_GetString(namePtr),"::")) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "bad method name \"", Tcl_GetString(namePtr), "\"", - (char*)NULL); - Tcl_DecrRefCount(namePtr); - return TCL_ERROR; - } - - /* - * Create the method definition. - */ - if (ItclCreateMemberFunc(interp, iclsPtr, namePtr, arglist, body, - &imPtr, 0) != TCL_OK) { - return TCL_ERROR; - } - - imPtr->flags |= ITCL_METHOD; - if (imPtrPtr != NULL) { - *imPtrPtr = imPtr; - } - ItclAddClassFunctionDictInfo(interp, iclsPtr, imPtr); - return TCL_OK; -} - -/* - * ------------------------------------------------------------------------ - * Itcl_CreateProc() - * - * Installs a class proc into the namespace associated with a class. - * If another command with the same name is already installed, then - * it is overwritten. Returns TCL_OK on success, or TCL_ERROR (along - * with an error message in the specified interp) if anything goes - * wrong. - * ------------------------------------------------------------------------ - */ -int -Itcl_CreateProc( - Tcl_Interp* interp, /* interpreter managing this action */ - ItclClass *iclsPtr, /* class definition */ - Tcl_Obj* namePtr, /* name of new proc */ - const char *arglist, /* space-separated list of arg names */ - const char *body) /* body of commands for the proc */ -{ - ItclMemberFunc *imPtr; - - /* - * Make sure that the proc name does not contain anything - * goofy like a "::" scope qualifier. - */ - if (strstr(Tcl_GetString(namePtr),"::")) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "bad proc name \"", Tcl_GetString(namePtr), "\"", - (char*)NULL); - return TCL_ERROR; - } - - /* - * Create the proc definition. - */ - if (ItclCreateMemberFunc(interp, iclsPtr, namePtr, arglist, - body, &imPtr, ITCL_COMMON) != TCL_OK) { - return TCL_ERROR; - } - - /* - * Mark procs as "common". This distinguishes them from methods. - */ - imPtr->flags |= ITCL_COMMON; - return TCL_OK; -} - - -/* - * ------------------------------------------------------------------------ - * ItclCreateMemberFunc() - * - * Creates the data record representing a member function. This - * includes the argument list and the body of the function. If the - * body is of the form "@name", then it is treated as a label for - * a C procedure registered by Itcl_RegisterC(). - * - * If any errors are encountered, this procedure returns TCL_ERROR - * along with an error message in the interpreter. Otherwise, it - * returns TCL_OK, and "imPtr" returns a pointer to the new - * member function. - * ------------------------------------------------------------------------ - */ -static int -ItclCreateMemberFunc( - Tcl_Interp* interp, /* interpreter managing this action */ - ItclClass *iclsPtr, /* class definition */ - Tcl_Obj *namePtr, /* name of new member */ - const char* arglist, /* space-separated list of arg names */ - const char* body, /* body of commands for the method */ - ItclMemberFunc** imPtrPtr, /* returns: pointer to new method defn */ - int flags) -{ - int newEntry; - char *name; - ItclMemberFunc *imPtr; - ItclMemberCode *mcode; - Tcl_HashEntry *hPtr; - - /* - * Add the member function to the list of functions for - * the class. Make sure that a member function with the - * same name doesn't already exist. - */ - hPtr = Tcl_CreateHashEntry(&iclsPtr->functions, (char *)namePtr, &newEntry); - if (!newEntry) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "\"", Tcl_GetString(namePtr), "\" already defined in class \"", - Tcl_GetString(iclsPtr->fullNamePtr), "\"", - (char*)NULL); - return TCL_ERROR; - } - - /* - * Try to create the implementation for this command member. - */ - if (ItclCreateMemberCode(interp, iclsPtr, arglist, body, - &mcode, namePtr, flags) != TCL_OK) { - - Tcl_DeleteHashEntry(hPtr); - return TCL_ERROR; - } - - Itcl_PreserveData((ClientData)mcode); - Itcl_EventuallyFree((ClientData)mcode, Itcl_DeleteMemberCode); - - /* - * Allocate a member function definition and return. - */ - imPtr = (ItclMemberFunc*)ckalloc(sizeof(ItclMemberFunc)); - memset(imPtr, 0, sizeof(ItclMemberFunc)); - imPtr->iclsPtr = iclsPtr; - imPtr->infoPtr = iclsPtr->infoPtr; - imPtr->protection = Itcl_Protection(interp, 0); - imPtr->namePtr = Tcl_NewStringObj(Tcl_GetString(namePtr), -1); - Tcl_IncrRefCount(imPtr->namePtr); - imPtr->fullNamePtr = Tcl_NewStringObj( - Tcl_GetString(iclsPtr->fullNamePtr), -1); - Tcl_AppendToObj(imPtr->fullNamePtr, "::", 2); - Tcl_AppendToObj(imPtr->fullNamePtr, Tcl_GetString(namePtr), -1); - Tcl_IncrRefCount(imPtr->fullNamePtr); - if (arglist != NULL) { - imPtr->origArgsPtr = Tcl_NewStringObj(arglist, -1); - Tcl_IncrRefCount(imPtr->origArgsPtr); - } - imPtr->codePtr = mcode; - - if (imPtr->protection == ITCL_DEFAULT_PROTECT) { - imPtr->protection = ITCL_PUBLIC; - } - - imPtr->declaringClassPtr = iclsPtr; - - if (arglist) { - imPtr->flags |= ITCL_ARG_SPEC; - } - if (mcode->argListPtr) { - ItclCreateArgList(interp, arglist, &imPtr->argcount, - &imPtr->maxargcount, &imPtr->usagePtr, - &imPtr->argListPtr, imPtr, NULL); - Tcl_IncrRefCount(imPtr->usagePtr); - } - - name = Tcl_GetString(namePtr); - if ((body != NULL) && (body[0] == '@')) { - /* check for builtin cget isa and configure and mark them for - * use of a different arglist "args" for TclOO !! */ - imPtr->codePtr->flags |= ITCL_BUILTIN; - if (strcmp(name, "cget") == 0) { - } - if (strcmp(name, "configure") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "isa") == 0) { - } - if (strcmp(name, "createhull") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "keepcomponentoption") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "ignorecomponentoption") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "renamecomponentoption") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "addoptioncomponent") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "ignoreoptioncomponent") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "renameoptioncomponent") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "setupcomponent") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "itcl_initoptions") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "mytypemethod") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - imPtr->flags |= ITCL_COMMON; - } - if (strcmp(name, "mymethod") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "mytypevar") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - imPtr->flags |= ITCL_COMMON; - } - if (strcmp(name, "myvar") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "itcl_hull") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - imPtr->flags |= ITCL_COMPONENT; - } - if (strcmp(name, "callinstance") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "getinstancevar") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "myproc") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - imPtr->flags |= ITCL_COMMON; - } - if (strcmp(name, "installhull") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "destroy") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "installcomponent") == 0) { - imPtr->argcount = 0; - imPtr->maxargcount = -1; - } - if (strcmp(name, "info") == 0) { - imPtr->flags |= ITCL_COMMON; - } - } - if (strcmp(name, "constructor") == 0) { - /* - * REVISE mcode->bodyPtr here! - * Include a [my ItclConstructBase $iclsPtr] method call. - * Inherited from itcl::Root - */ - - Tcl_Obj *newBody = Tcl_NewStringObj("", -1); - Tcl_AppendToObj(newBody, - "[::info object namespace ${this}]::my ItclConstructBase ", -1); - Tcl_AppendObjToObj(newBody, iclsPtr->fullNamePtr); - Tcl_AppendToObj(newBody, "\n", -1); - - Tcl_AppendObjToObj(newBody, mcode->bodyPtr); - Tcl_DecrRefCount(mcode->bodyPtr); - mcode->bodyPtr = newBody; - Tcl_IncrRefCount(mcode->bodyPtr); - imPtr->flags |= ITCL_CONSTRUCTOR; - } - if (strcmp(name, "destructor") == 0) { - imPtr->flags |= ITCL_DESTRUCTOR; - } - - Tcl_SetHashValue(hPtr, (ClientData)imPtr); - imPtr->refCount = 1; - - *imPtrPtr = imPtr; - return TCL_OK; -} - -/* - * ------------------------------------------------------------------------ - * Itcl_CreateMemberFunc() - * - * Creates the data record representing a member function. This - * includes the argument list and the body of the function. If the - * body is of the form "@name", then it is treated as a label for - * a C procedure registered by Itcl_RegisterC(). - * - * If any errors are encountered, this procedure returns TCL_ERROR - * along with an error message in the interpreter. Otherwise, it - * returns TCL_OK, and "imPtr" returns a pointer to the new - * member function. - * ------------------------------------------------------------------------ - */ -int -Itcl_CreateMemberFunc( - Tcl_Interp* interp, /* interpreter managing this action */ - ItclClass *iclsPtr, /* class definition */ - Tcl_Obj *namePtr, /* name of new member */ - const char* arglist, /* space-separated list of arg names */ - const char* body, /* body of commands for the method */ - ItclMemberFunc** imPtrPtr) /* returns: pointer to new method defn */ -{ - return ItclCreateMemberFunc(interp, iclsPtr, namePtr, arglist, - body, imPtrPtr, 0); -} - -/* - * ------------------------------------------------------------------------ - * Itcl_ChangeMemberFunc() - * - * Modifies the data record representing a member function. This - * is usually the body of the function, but can include the argument - * list if it was not defined when the member was first created. - * If the body is of the form "@name", then it is treated as a label - * for a C procedure registered by Itcl_RegisterC(). - * - * If any errors are encountered, this procedure returns TCL_ERROR - * along with an error message in the interpreter. Otherwise, it - * returns TCL_OK, and "imPtr" returns a pointer to the new - * member function. - * ------------------------------------------------------------------------ - */ -int -Itcl_ChangeMemberFunc( - Tcl_Interp* interp, /* interpreter managing this action */ - ItclMemberFunc* imPtr, /* command member being changed */ - const char* arglist, /* space-separated list of arg names */ - const char* body) /* body of commands for the method */ -{ - Tcl_HashEntry *hPtr; - ItclMemberCode *mcode = NULL; - int isNewEntry; - - /* - * Try to create the implementation for this command member. - */ - if (ItclCreateMemberCode(interp, imPtr->iclsPtr, - arglist, body, &mcode, imPtr->namePtr, 0) != TCL_OK) { - - return TCL_ERROR; - } - - /* - * If the argument list was defined when the function was - * created, compare the arg lists or usage strings to make sure - * that the interface is not being redefined. - */ - if ((imPtr->flags & ITCL_ARG_SPEC) != 0 && - (imPtr->argListPtr != NULL) && - !EquivArgLists(interp, imPtr->argListPtr, mcode->argListPtr)) { - const char *argsStr; - if (imPtr->origArgsPtr != NULL) { - argsStr = Tcl_GetString(imPtr->origArgsPtr); - } else { - argsStr = ""; - } - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "argument list changed for function \"", - Tcl_GetString(imPtr->fullNamePtr), "\": should be \"", - argsStr, "\"", - (char*)NULL); - - Itcl_DeleteMemberCode((char*)mcode); - return TCL_ERROR; - } - - if (imPtr->flags & ITCL_CONSTRUCTOR) { - /* - * REVISE mcode->bodyPtr here! - * Include a [my ItclConstructBase $iclsPtr] method call. - * Inherited from itcl::Root - */ - - Tcl_Obj *newBody = Tcl_NewStringObj("", -1); - Tcl_AppendToObj(newBody, - "[::info object namespace ${this}]::my ItclConstructBase ", -1); - Tcl_AppendObjToObj(newBody, imPtr->iclsPtr->fullNamePtr); - Tcl_AppendToObj(newBody, "\n", -1); - - Tcl_AppendObjToObj(newBody, mcode->bodyPtr); - Tcl_DecrRefCount(mcode->bodyPtr); - mcode->bodyPtr = newBody; - Tcl_IncrRefCount(mcode->bodyPtr); - } - - /* - * Free up the old implementation and install the new one. - */ - Itcl_PreserveData((ClientData)mcode); - Itcl_EventuallyFree((ClientData)mcode, Itcl_DeleteMemberCode); - - Itcl_ReleaseData((ClientData)imPtr->codePtr); - imPtr->codePtr = mcode; - if (mcode->flags & ITCL_IMPLEMENT_TCL) { - ClientData pmPtr; - imPtr->tmPtr = (ClientData)Itcl_NewProcClassMethod(interp, - imPtr->iclsPtr->clsPtr, ItclCheckCallMethod, ItclAfterCallMethod, - ItclProcErrorProc, imPtr, imPtr->namePtr, mcode->argumentPtr, - mcode->bodyPtr, &pmPtr); - hPtr = Tcl_CreateHashEntry(&imPtr->iclsPtr->infoPtr->procMethods, - (char *)imPtr->tmPtr, &isNewEntry); - if (isNewEntry) { - Tcl_SetHashValue(hPtr, imPtr); - } - } - ItclAddClassFunctionDictInfo(interp, imPtr->iclsPtr, imPtr); - return TCL_OK; -} - -static const char * type_reserved_words [] = { - "type", - "self", - "selfns", - NULL -}; - -/* - * ------------------------------------------------------------------------ - * ItclCreateMemberCode() - * - * Creates the data record representing the implementation behind a - * class member function. This includes the argument list and the body - * of the function. If the body is of the form "@name", then it is - * treated as a label for a C procedure registered by Itcl_RegisterC(). - * - * The implementation is kept by the member function definition, and - * controlled by a preserve/release paradigm. That way, if it is in - * use while it is being redefined, it will stay around long enough - * to avoid a core dump. - * - * If any errors are encountered, this procedure returns TCL_ERROR - * along with an error message in the interpreter. Otherwise, it - * returns TCL_OK, and "mcodePtr" returns a pointer to the new - * implementation. - * ------------------------------------------------------------------------ - */ -static int -ItclCreateMemberCode( - Tcl_Interp* interp, /* interpreter managing this action */ - ItclClass *iclsPtr, /* class containing this member */ - const char* arglist, /* space-separated list of arg names */ - const char* body, /* body of commands for the method */ - ItclMemberCode** mcodePtr, /* returns: pointer to new implementation */ - Tcl_Obj *namePtr, - int flags) -{ - int argc; - int maxArgc; - Tcl_Obj *usagePtr; - ItclArgList *argListPtr; - ItclMemberCode *mcode; - const char **cPtrPtr; - int haveError; - - /* - * Allocate some space to hold the implementation. - */ - mcode = (ItclMemberCode*)ckalloc(sizeof(ItclMemberCode)); - memset(mcode, 0, sizeof(ItclMemberCode)); - - if (arglist) { - if (ItclCreateArgList(interp, arglist, &argc, &maxArgc, &usagePtr, - &argListPtr, NULL, NULL) != TCL_OK) { - Itcl_DeleteMemberCode((char*)mcode); - return TCL_ERROR; - } - mcode->argcount = argc; - mcode->maxargcount = maxArgc; - mcode->argListPtr = argListPtr; - mcode->usagePtr = usagePtr; - Tcl_IncrRefCount(mcode->usagePtr); - mcode->argumentPtr = Tcl_NewStringObj((const char *)arglist, -1); - if (iclsPtr->flags & (ITCL_TYPE|ITCL_WIDGETADAPTOR)) { - haveError = 0; - while (argListPtr != NULL) { - cPtrPtr = &type_reserved_words[0]; - while (*cPtrPtr != NULL) { - if ((argListPtr->namePtr != NULL) && - (strcmp(Tcl_GetString(argListPtr->namePtr), - *cPtrPtr) == 0)) { - haveError = 1; - } - if ((flags & ITCL_COMMON) != 0) { - if (! (iclsPtr->infoPtr->functionFlags & - ITCL_TYPE_METHOD)) { - haveError = 0; - } - } - if (haveError) { - const char *startStr = "method "; - if (iclsPtr->infoPtr->functionFlags & - ITCL_TYPE_METHOD) { - startStr = "typemethod "; - } - /* FIXME should use iclsPtr->infoPtr->functionFlags here */ - if ((namePtr != NULL) && - (strcmp(Tcl_GetString(namePtr), - "constructor") == 0)) { - startStr = ""; - } - Tcl_AppendResult(interp, startStr, - namePtr == NULL ? "??" : - Tcl_GetString(namePtr), - "'s arglist may not contain \"", - *cPtrPtr, "\" explicitly", NULL); - Itcl_DeleteMemberCode((char*)mcode); - return TCL_ERROR; - } - cPtrPtr++; - } - argListPtr = argListPtr->nextPtr; - } - } - Tcl_IncrRefCount(mcode->argumentPtr); - mcode->flags |= ITCL_ARG_SPEC; - } else { - argc = 0; - argListPtr = NULL; - } - - if (body) { - mcode->bodyPtr = Tcl_NewStringObj((const char *)body, -1); - } else { - mcode->bodyPtr = Tcl_NewStringObj((const char *)"", -1); - mcode->flags |= ITCL_IMPLEMENT_NONE; - } - Tcl_IncrRefCount(mcode->bodyPtr); - - /* - * If the body definition starts with '@', then treat the value - * as a symbolic name for a C procedure. - */ - if (body == NULL) { - /* No-op */ - } else { - if (*body == '@') { - Tcl_CmdProc *argCmdProc; - Tcl_ObjCmdProc *objCmdProc; - ClientData cdata; - int isDone; - - isDone = 0; - if (strcmp(body, "@itcl-builtin-cget") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-configure") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-isa") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-createhull") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-keepcomponentoption") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-ignorecomponentoption") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-renamecomponentoption") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-addoptioncomponent") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-ignoreoptioncomponent") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-renameoptioncomponent") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-setupcomponent") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-initoptions") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-mytypemethod") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-mymethod") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-myproc") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-mytypevar") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-myvar") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-itcl_hull") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-callinstance") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-getinstancevar") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-installhull") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-installcomponent") == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-destroy") == 0) { - isDone = 1; - } - if (strncmp(body, "@itcl-builtin-setget", 20) == 0) { - isDone = 1; - } - if (strcmp(body, "@itcl-builtin-classunknown") == 0) { - isDone = 1; - } - if (!isDone) { - if (!Itcl_FindC(interp, body+1, &argCmdProc, &objCmdProc, - &cdata)) { - Tcl_AppendResult(interp, - "no registered C procedure with name \"", - body+1, "\"", (char*)NULL); - Itcl_DeleteMemberCode((char*)mcode); - return TCL_ERROR; - } - - /* - * WARNING! WARNING! WARNING! - * This is a pretty dangerous approach. What's done here is - * to copy over the proc + clientData implementation that - * happens to be in place at the moment the method is - * (re-)defined. This denies any freedom for the clientData - * to be changed dynamically or for the implementation to - * shift from OBJCMD to ARGCMD or vice versa, which the - * Itcl_Register(Obj)C routines explicitly permit. The whole - * system also lacks any scheme to unregister. - */ - - if (objCmdProc != NULL) { - mcode->flags |= ITCL_IMPLEMENT_OBJCMD; - mcode->cfunc.objCmd = objCmdProc; - mcode->clientData = cdata; - } else { - if (argCmdProc != NULL) { - mcode->flags |= ITCL_IMPLEMENT_ARGCMD; - mcode->cfunc.argCmd = argCmdProc; - mcode->clientData = cdata; - } - } - } else { - mcode->flags |= ITCL_IMPLEMENT_TCL|ITCL_BUILTIN; - } - } else { - - /* - * Otherwise, treat the body as a chunk of Tcl code. - */ - mcode->flags |= ITCL_IMPLEMENT_TCL; - } - } - - *mcodePtr = mcode; - return TCL_OK; -} - -/* - * ------------------------------------------------------------------------ - * Itcl_CreateMemberCode() - * - * Creates the data record representing the implementation behind a - * class member function. This includes the argument list and the body - * of the function. If the body is of the form "@name", then it is - * treated as a label for a C procedure registered by Itcl_RegisterC(). - * - * The implementation is kept by the member function definition, and - * controlled by a preserve/release paradigm. That way, if it is in - * use while it is being redefined, it will stay around long enough - * to avoid a core dump. - * - * If any errors are encountered, this procedure returns TCL_ERROR - * along with an error message in the interpreter. Otherwise, it - * returns TCL_OK, and "mcodePtr" returns a pointer to the new - * implementation. - * ------------------------------------------------------------------------ - */ -int -Itcl_CreateMemberCode( - Tcl_Interp* interp, /* interpreter managing this action */ - ItclClass *iclsPtr, /* class containing this member */ - const char* arglist, /* space-separated list of arg names */ - const char* body, /* body of commands for the method */ - ItclMemberCode** mcodePtr) /* returns: pointer to new implementation */ -{ - return ItclCreateMemberCode(interp, iclsPtr, arglist, body, mcodePtr, - NULL, 0); -} - -/* - * ------------------------------------------------------------------------ - * Itcl_DeleteMemberCode() - * - * Destroys all data associated with the given command implementation. - * Invoked automatically by Itcl_ReleaseData() when the implementation - * is no longer being used. - * ------------------------------------------------------------------------ - */ -void -Itcl_DeleteMemberCode( - char* cdata) /* pointer to member code definition */ -{ - ItclMemberCode* mCodePtr; - - mCodePtr = (ItclMemberCode*)cdata; - if (mCodePtr == NULL) { - return; - } - if (mCodePtr->argListPtr != NULL) { - ItclDeleteArgList(mCodePtr->argListPtr); - } - if (mCodePtr->usagePtr != NULL) { - Tcl_DecrRefCount(mCodePtr->usagePtr); - } - if (mCodePtr->argumentPtr != NULL) { - Tcl_DecrRefCount(mCodePtr->argumentPtr); - } - if (mCodePtr->bodyPtr != NULL) { - Tcl_DecrRefCount(mCodePtr->bodyPtr); - } - /* do NOT free mCodePtr->bodyPtr here !! that is done in TclOO!! */ - ckfree((char*)mCodePtr); -} - - -/* - * ------------------------------------------------------------------------ - * Itcl_GetMemberCode() - * - * Makes sure that the implementation for an [incr Tcl] code body is - * ready to run. Note that a member function can be declared without - * being defined. The class definition may contain a declaration of - * the member function, but its body may be defined in a separate file. - * If an undefined function is encountered, this routine automatically - * attempts to autoload it. If the body is implemented via Tcl code, - * then it is compiled here as well. - * - * Returns TCL_ERROR (along with an error message in the interpreter) - * if an error is encountered, or if the implementation is not defined - * and cannot be autoloaded. Returns TCL_OK if implementation is - * ready to use. - * ------------------------------------------------------------------------ - */ -int -Itcl_GetMemberCode( - Tcl_Interp* interp, /* interpreter managing this action */ - ItclMemberFunc* imPtr) /* member containing code body */ -{ - int result; - ItclMemberCode *mcode = imPtr->codePtr; - assert(mcode != NULL); - - /* - * If the implementation has not yet been defined, try to - * autoload it now. - */ - - if (!Itcl_IsMemberCodeImplemented(mcode)) { - Tcl_DString buf; - - Tcl_DStringInit(&buf); - Tcl_DStringAppend(&buf, "::auto_load ", -1); - Tcl_DStringAppend(&buf, Tcl_GetString(imPtr->fullNamePtr), -1); - result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); - Tcl_DStringFree(&buf); - if (result != TCL_OK) { - Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( - "\n (while autoloading code for \"%s\")", - Tcl_GetString(imPtr->fullNamePtr))); - return result; - } - Tcl_ResetResult(interp); /* get rid of 1/0 status */ - } - - /* - * If the implementation is still not available, then - * autoloading must have failed. - * - * TRICKY NOTE: If code has been autoloaded, then the - * old mcode pointer is probably invalid. Go back to - * the member and look at the current code pointer again. - */ - mcode = imPtr->codePtr; - assert(mcode != NULL); - - if (!Itcl_IsMemberCodeImplemented(mcode)) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "member function \"", Tcl_GetString(imPtr->fullNamePtr), - "\" is not defined and cannot be autoloaded", - (char*)NULL); - return TCL_ERROR; - } - - return TCL_OK; -} - - - -static int -CallItclObjectCmd( - ClientData data[], - Tcl_Interp *interp, - int result) -{ - Tcl_Object oPtr; - ItclMemberFunc *imPtr = data[0]; - ItclObject *ioPtr = data[1]; - int objc = PTR2INT(data[2]); - Tcl_Obj **objv = data[3]; - - ItclShowArgs(1, "CallItclObjectCmd", objc, objv); - if (ioPtr != NULL) { - ioPtr->hadConstructorError = 0; - } - if (imPtr->flags & (ITCL_CONSTRUCTOR|ITCL_DESTRUCTOR)) { - oPtr = ioPtr->oPtr; - } else { - oPtr = NULL; - } - if (oPtr != NULL) { - result = ItclObjectCmd(imPtr, interp, oPtr, imPtr->iclsPtr->clsPtr, - objc, objv); - } else { - result = ItclObjectCmd(imPtr, interp, NULL, NULL, objc, objv); - } - if (result != TCL_OK) { - if (ioPtr != NULL && ioPtr->hadConstructorError == 0) { - /* we are in a constructor call and did not yet have an error */ - /* -1 means we are not in a constructor */ - ioPtr->hadConstructorError = 1; - } - } - return result; -} -/* - * ------------------------------------------------------------------------ - * Itcl_EvalMemberCode() - * - * Used to execute an ItclMemberCode representation of a code - * fragment. This code may be a body of Tcl commands, or a C handler - * procedure. - * - * Executes the command with the given arguments (objc,objv) and - * returns an integer status code (TCL_OK/TCL_ERROR). Returns the - * result string or an error message in the interpreter. - * ------------------------------------------------------------------------ - */ - -int -Itcl_EvalMemberCode( - Tcl_Interp *interp, /* current interpreter */ - ItclMemberFunc *imPtr, /* member func, or NULL (for error messages) */ - ItclObject *contextIoPtr, /* object context, or NULL */ - int objc, /* number of arguments */ - Tcl_Obj *const objv[]) /* argument objects */ -{ - ItclMemberCode *mcode; - void *callbackPtr; - int result = TCL_OK; - int i; - - ItclShowArgs(1, "Itcl_EvalMemberCode", objc, objv); - /* - * If this code does not have an implementation yet, then - * try to autoload one. Also, if this is Tcl code, make sure - * that it's compiled and ready to use. - */ - if (Itcl_GetMemberCode(interp, imPtr) != TCL_OK) { - return TCL_ERROR; - } - mcode = imPtr->codePtr; - - /* - * Bump the reference count on this code, in case it is - * redefined or deleted during execution. - */ - Itcl_PreserveData((ClientData)mcode); - - if ((imPtr->flags & ITCL_DESTRUCTOR) && (contextIoPtr != NULL)) { - contextIoPtr->destructorHasBeenCalled = 1; - } - - /* - * Execute the code body... - */ - if (((mcode->flags & ITCL_IMPLEMENT_OBJCMD) != 0) || - ((mcode->flags & ITCL_IMPLEMENT_ARGCMD) != 0)) { - - if ((mcode->flags & ITCL_IMPLEMENT_OBJCMD) != 0) { - result = (*mcode->cfunc.objCmd)(mcode->clientData, - interp, objc, objv); - } else { - if ((mcode->flags & ITCL_IMPLEMENT_ARGCMD) != 0) { - char **argv; - argv = (char**)ckalloc( (unsigned)(objc*sizeof(char*)) ); - for (i=0; i < objc; i++) { - argv[i] = Tcl_GetStringFromObj(objv[i], (int*)NULL); - } - - result = (*mcode->cfunc.argCmd)(mcode->clientData, - interp, objc, (const char **)argv); - - ckfree((char*)argv); - } - } - } else { - if ((mcode->flags & ITCL_IMPLEMENT_TCL) != 0) { - callbackPtr = Itcl_GetCurrentCallbackPtr(interp); - Tcl_NRAddCallback(interp, CallItclObjectCmd, imPtr, contextIoPtr, - INT2PTR(objc), (void *)objv); - result = Itcl_NRRunCallbacks(interp, callbackPtr); - } - } - - Itcl_ReleaseData((ClientData)mcode); - return result; -} - -/* - * ------------------------------------------------------------------------ - * ItclEquivArgLists() - * - * Compares two argument lists to see if they are equivalent. The - * first list is treated as a prototype, and the second list must - * match it. Argument names may be different, but they must match in - * meaning. If one argument is optional, the corresponding argument - * must also be optional. If the prototype list ends with the magic - * "args" argument, then it matches everything in the other list. - * - * Returns non-zero if the argument lists are equivalent. - * ------------------------------------------------------------------------ - */ - -static int -EquivArgLists( - Tcl_Interp *interp, - ItclArgList *origArgs, - ItclArgList *realArgs) -{ - ItclArgList *currPtr; - char *argName; - - for (currPtr=origArgs; currPtr != NULL; currPtr=currPtr->nextPtr) { - if ((realArgs != NULL) && (realArgs->namePtr == NULL)) { - if (currPtr->namePtr != NULL) { - if (strcmp(Tcl_GetString(currPtr->namePtr), "args") != 0) { - /* the definition has more arguments */ - return 0; - } - } - } - if (realArgs == NULL) { - if (currPtr->defaultValuePtr != NULL) { - /* default args must be there ! */ - return 0; - } - if (currPtr->namePtr != NULL) { - if (strcmp(Tcl_GetString(currPtr->namePtr), "args") != 0) { - /* the definition has more arguments */ - return 0; - } - } - return 1; - } - if (currPtr->namePtr == NULL) { - /* no args defined */ - if (realArgs->namePtr != NULL) { - return 0; - } - return 1; - } - argName = Tcl_GetString(currPtr->namePtr); - if (strcmp(argName, "args") == 0) { - if (currPtr->nextPtr == NULL) { - /* this is the last arument */ - return 1; - } - } - if (currPtr->defaultValuePtr != NULL) { - if (realArgs->defaultValuePtr != NULL) { - /* default values must be the same */ - if (strcmp(Tcl_GetString(currPtr->defaultValuePtr), - Tcl_GetString(realArgs->defaultValuePtr)) != 0) { - return 0; - } - } - } - realArgs = realArgs->nextPtr; - } - if ((currPtr == NULL) && (realArgs != NULL)) { - /* new definition has more args then the old one */ - return 0; - } - return 1; -} - -/* - * ------------------------------------------------------------------------ - * Itcl_GetContext() - * - * Convenience routine for looking up the current object/class context. - * Useful in implementing methods/procs to see what class, and perhaps - * what object, is active. - * - * Returns TCL_OK if the current namespace is a class namespace. - * Also returns pointers to the class definition, and to object - * data if an object context is active. Returns TCL_ERROR (along - * with an error message in the interpreter) if a class namespace - * is not active. - * ------------------------------------------------------------------------ - */ - -void -Itcl_SetContext( - Tcl_Interp *interp, - ItclObject *ioPtr) -{ - int new; - Itcl_Stack *stackPtr; - Tcl_CallFrame *framePtr = Itcl_GetUplevelCallFrame(interp, 0); - ItclObjectInfo *infoPtr = (ItclObjectInfo *)Tcl_GetAssocData(interp, - ITCL_INTERP_DATA, NULL); - Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(&infoPtr->frameContext, - (char *)framePtr, &new); - ItclCallContext *contextPtr - = (ItclCallContext *) ckalloc(sizeof(ItclCallContext)); - - memset(contextPtr, 0, sizeof(ItclCallContext)); - contextPtr->ioPtr = ioPtr; - contextPtr->refCount = 1; - - if (!new) { - Tcl_Panic("frame already has context?!"); - } - - stackPtr = (Itcl_Stack *) ckalloc(sizeof(Itcl_Stack)); - Itcl_InitStack(stackPtr); - Tcl_SetHashValue(hPtr, stackPtr); - - Itcl_PushStack(contextPtr, stackPtr); -} - -void -Itcl_UnsetContext( - Tcl_Interp *interp) -{ - Tcl_CallFrame *framePtr = Itcl_GetUplevelCallFrame(interp, 0); - ItclObjectInfo *infoPtr = (ItclObjectInfo *)Tcl_GetAssocData(interp, - ITCL_INTERP_DATA, NULL); - Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&infoPtr->frameContext, - (char *)framePtr); - Itcl_Stack *stackPtr = (Itcl_Stack *) Tcl_GetHashValue(hPtr); - ItclCallContext *contextPtr = Itcl_PopStack(stackPtr); - - if (Itcl_GetStackSize(stackPtr) > 0) { - Tcl_Panic("frame context stack not empty!"); - } - Itcl_DeleteStack(stackPtr); - ckfree((char *) stackPtr); - Tcl_DeleteHashEntry(hPtr); - if (--contextPtr->refCount) { - Tcl_Panic("frame context ref count not zero!"); - } - ckfree((char *)contextPtr); -} - -int -Itcl_GetContext( - Tcl_Interp *interp, /* current interpreter */ - ItclClass **iclsPtrPtr, /* returns: class definition or NULL */ - ItclObject **ioPtrPtr) /* returns: object data or NULL */ -{ - Tcl_Namespace *nsPtr; - - /* Fetch the current call frame. That determines context. */ - Tcl_CallFrame *framePtr = Itcl_GetUplevelCallFrame(interp, 0); - - /* Try to map it to a context stack. */ - ItclObjectInfo *infoPtr = (ItclObjectInfo *)Tcl_GetAssocData(interp, - ITCL_INTERP_DATA, NULL); - Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&infoPtr->frameContext, - (char *)framePtr); - if (hPtr) { - /* Frame maps to a context stack. */ - Itcl_Stack *stackPtr = (Itcl_Stack *)Tcl_GetHashValue(hPtr); - ItclCallContext *contextPtr = Itcl_PeekStack(stackPtr); - - assert(contextPtr); - - if (contextPtr->objectFlags & ITCL_OBJECT_ROOT_METHOD) { - ItclObject *ioPtr = contextPtr->ioPtr; - - *iclsPtrPtr = ioPtr->iclsPtr; - *ioPtrPtr = ioPtr; - return TCL_OK; - } - - *iclsPtrPtr = contextPtr->imPtr ? contextPtr->imPtr->iclsPtr - : contextPtr->ioPtr->iclsPtr; - *ioPtrPtr = contextPtr->ioPtr ? contextPtr->ioPtr : infoPtr->currIoPtr; - return TCL_OK; - } - - /* Frame has no Itcl context data. No way to get object context. */ - *ioPtrPtr = NULL; - - /* Fall back to namespace for possible class context info. */ - nsPtr = Tcl_GetCurrentNamespace(interp); - hPtr = Tcl_FindHashEntry(&infoPtr->namespaceClasses, (char *)nsPtr); - if (hPtr) { - *iclsPtrPtr = (ItclClass *)Tcl_GetHashValue(hPtr); - return TCL_OK; - } - - /* Cannot get any context. Record an error message. */ - if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "namespace \"%s\" is not a class namespace", nsPtr->fullName)); - } - return TCL_ERROR; -} - -/* - * ------------------------------------------------------------------------ - * Itcl_GetMemberFuncUsage() - * - * Returns a string showing how a command member should be invoked. - * If the command member is a method, then the specified object name - * is reported as part of the invocation path: - * - * obj method arg ?arg arg ...? - * - * Otherwise, the "obj" pointer is ignored, and the class name is - * used as the invocation path: - * - * class::proc arg ?arg arg ...? - * - * Returns the string by appending it onto the Tcl_Obj passed in as - * an argument. - * ------------------------------------------------------------------------ - */ -void -Itcl_GetMemberFuncUsage( - ItclMemberFunc *imPtr, /* command member being examined */ - ItclObject *contextIoPtr, /* invoked with respect to this object */ - Tcl_Obj *objPtr) /* returns: string showing usage */ -{ - Tcl_HashEntry *entry; - ItclMemberFunc *mf; - ItclClass *iclsPtr; - char *name; - char *arglist; - - /* - * If the command is a method and an object context was - * specified, then add the object context. If the method - * was a constructor, and if the object is being created, - * then report the invocation via the class creation command. - */ - if ((imPtr->flags & ITCL_COMMON) == 0) { - if ((imPtr->flags & ITCL_CONSTRUCTOR) != 0 && - contextIoPtr->constructed) { - - iclsPtr = (ItclClass*)contextIoPtr->iclsPtr; - mf = NULL; - objPtr = Tcl_NewStringObj("constructor", -1); - entry = Tcl_FindHashEntry(&iclsPtr->resolveCmds, (char *)objPtr); - Tcl_DecrRefCount(objPtr); - if (entry) { - ItclCmdLookup *clookup; - clookup = (ItclCmdLookup *)Tcl_GetHashValue(entry); - mf = clookup->imPtr; - } - - if (mf == imPtr) { - Tcl_GetCommandFullName(contextIoPtr->iclsPtr->interp, - contextIoPtr->iclsPtr->accessCmd, objPtr); - Tcl_AppendToObj(objPtr, " ", -1); - name = (char *) Tcl_GetCommandName( - contextIoPtr->iclsPtr->interp, contextIoPtr->accessCmd); - Tcl_AppendToObj(objPtr, name, -1); - } else { - Tcl_AppendToObj(objPtr, Tcl_GetString(imPtr->fullNamePtr), -1); - } - } else { - if (contextIoPtr && contextIoPtr->accessCmd) { - name = (char *) Tcl_GetCommandName( - contextIoPtr->iclsPtr->interp, contextIoPtr->accessCmd); - Tcl_AppendStringsToObj(objPtr, name, " ", - Tcl_GetString(imPtr->namePtr), (char*)NULL); - } else { - Tcl_AppendStringsToObj(objPtr, "<object> ", - Tcl_GetString(imPtr->namePtr), (char*)NULL); - } - } - } else { - Tcl_AppendToObj(objPtr, Tcl_GetString(imPtr->fullNamePtr), -1); - } - - /* - * Add the argument usage info. - */ - if (imPtr->codePtr) { - if (imPtr->codePtr->usagePtr != NULL) { - arglist = Tcl_GetString(imPtr->codePtr->usagePtr); - } else { - arglist = NULL; - } - } else { - if (imPtr->argListPtr != NULL) { - arglist = Tcl_GetString(imPtr->usagePtr); - } else { - arglist = NULL; - } - } - if (arglist) { - if (strlen(arglist) > 0) { - Tcl_AppendToObj(objPtr, " ", -1); - Tcl_AppendToObj(objPtr, arglist, -1); - } - } -} - -/* - * ------------------------------------------------------------------------ - * Itcl_ExecMethod() - * - * Invoked by Tcl to handle the execution of a user-defined method. - * A method is similar to the usual Tcl proc, but has access to - * object-specific data. If for some reason there is no current - * object context, then a method call is inappropriate, and an error - * is returned. - * - * Methods are implemented either as Tcl code fragments, or as C-coded - * procedures. For Tcl code fragments, command arguments are parsed - * according to the argument list, and the body is executed in the - * scope of the class where it was defined. For C procedures, the - * arguments are passed in "as-is", and the procedure is executed in - * the most-specific class scope. - * ------------------------------------------------------------------------ - */ -static int -NRExecMethod( - ClientData clientData, /* method definition */ - Tcl_Interp *interp, /* current interpreter */ - int objc, /* number of arguments */ - Tcl_Obj *const *objv) /* argument objects */ -{ - ItclMemberFunc *imPtr = (ItclMemberFunc*)clientData; - int result = TCL_OK; - - const char *token; - Tcl_HashEntry *entry; - ItclClass *iclsPtr; - ItclObject *ioPtr; - - ItclShowArgs(1, "NRExecMethod", objc, objv); - - /* - * Make sure that the current namespace context includes an - * object that is being manipulated. Methods can be executed - * only if an object context exists. - */ - iclsPtr = imPtr->iclsPtr; - if (Itcl_GetContext(interp, &iclsPtr, &ioPtr) != TCL_OK) { - return TCL_ERROR; - } - if (ioPtr == NULL) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "cannot access object-specific info without an object context", - (char*)NULL); - return TCL_ERROR; - } - - /* - * Make sure that this command member can be accessed from - * the current namespace context. - * That is now done in ItclMapMethodNameProc !! - */ - - /* - * All methods should be "virtual" unless they are invoked with - * a "::" scope qualifier. - * - * To implement the "virtual" behavior, find the most-specific - * implementation for the method by looking in the "resolveCmds" - * table for this class. - */ - token = Tcl_GetString(objv[0]); - if (strstr(token, "::") == NULL) { - if (ioPtr != NULL) { - entry = Tcl_FindHashEntry(&ioPtr->iclsPtr->resolveCmds, - (char *)imPtr->namePtr); - - if (entry) { - ItclCmdLookup *clookup; - clookup = (ItclCmdLookup *)Tcl_GetHashValue(entry); - imPtr = clookup->imPtr; - } - } - } - - /* - * Execute the code for the method. Be careful to protect - * the method in case it gets deleted during execution. - */ - ItclPreserveIMF(imPtr); - result = Itcl_EvalMemberCode(interp, imPtr, ioPtr, objc, objv); - ItclReleaseIMF(imPtr); - return result; -} - -/* ARGSUSED */ -int -Itcl_ExecMethod( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - return Tcl_NRCallObjProc(interp, NRExecMethod, clientData, objc, objv); -} - - -/* - * ------------------------------------------------------------------------ - * Itcl_ExecProc() - * - * Invoked by Tcl to handle the execution of a user-defined proc. - * - * Procs are implemented either as Tcl code fragments, or as C-coded - * procedures. For Tcl code fragments, command arguments are parsed - * according to the argument list, and the body is executed in the - * scope of the class where it was defined. For C procedures, the - * arguments are passed in "as-is", and the procedure is executed in - * the most-specific class scope. - * ------------------------------------------------------------------------ - */ -static int -NRExecProc( - ClientData clientData, /* proc definition */ - Tcl_Interp *interp, /* current interpreter */ - int objc, /* number of arguments */ - Tcl_Obj *const objv[]) /* argument objects */ -{ - ItclMemberFunc *imPtr = (ItclMemberFunc*)clientData; - int result = TCL_OK; - - ItclShowArgs(1, "NRExecProc", objc, objv); - - /* - * Make sure that this command member can be accessed from - * the current namespace context. - */ - if (imPtr->protection != ITCL_PUBLIC) { - if (!Itcl_CanAccessFunc(imPtr, Tcl_GetCurrentNamespace(interp))) { - ItclMemberFunc *imPtr2 = NULL; - Tcl_HashEntry *hPtr; - Tcl_ObjectContext context; - context = Itcl_GetCallFrameClientData(interp); - if (context == NULL) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "can't access \"", Tcl_GetString(imPtr->fullNamePtr), - "\": ", Itcl_ProtectionStr(imPtr->protection), - " function", (char*)NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&imPtr->iclsPtr->infoPtr->procMethods, - (char *)Tcl_ObjectContextMethod(context)); - if (hPtr != NULL) { - imPtr2 = Tcl_GetHashValue(hPtr); - } - if ((imPtr->protection & ITCL_PRIVATE) && (imPtr2 != NULL) && - (imPtr->iclsPtr->nsPtr != imPtr2->iclsPtr->nsPtr)) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "invalid command name \"", - Tcl_GetString(objv[0]), - "\"", NULL); - return TCL_ERROR; - } - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "can't access \"", Tcl_GetString(imPtr->fullNamePtr), - "\": ", Itcl_ProtectionStr(imPtr->protection), - " function", (char*)NULL); - return TCL_ERROR; - } - } - - /* - * Execute the code for the proc. Be careful to protect - * the proc in case it gets deleted during execution. - */ - ItclPreserveIMF(imPtr); - - result = Itcl_EvalMemberCode(interp, imPtr, (ItclObject*)NULL, - objc, objv); - ItclReleaseIMF(imPtr); - return result; -} - -/* ARGSUSED */ -int -Itcl_ExecProc( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - return Tcl_NRCallObjProc(interp, NRExecProc, clientData, objc, objv); -} - -static int -CallInvokeMethodIfExists( - ClientData data[], - Tcl_Interp *interp, - int result) -{ - ItclClass *iclsPtr = data[0]; - ItclObject *contextObj = data[1]; - int objc = PTR2INT(data[2]); - Tcl_Obj* const* objv = data[3]; - - result = Itcl_InvokeMethodIfExists(interp, "constructor", - iclsPtr, contextObj, objc, (Tcl_Obj* const*)objv); - - if (result != TCL_OK) { - return TCL_ERROR; - } - return TCL_OK; -} -/* - * ------------------------------------------------------------------------ - * Itcl_ConstructBase() - * - * Usually invoked just before executing the body of a constructor - * when an object is first created. This procedure makes sure that - * all base classes are properly constructed. If an "initCode" fragment - * was defined with the constructor for the class, then it is invoked. - * After that, the list of base classes is checked for constructors - * that are defined but have not yet been invoked. Each of these is - * invoked implicitly with no arguments. - * - * Assumes that a local call frame is already installed, and that - * constructor arguments have already been matched and are sitting in - * this frame. Returns TCL_OK on success; otherwise, this procedure - * returns TCL_ERROR, along with an error message in the interpreter. - * ------------------------------------------------------------------------ - */ - -int -Itcl_ConstructBase( - Tcl_Interp *interp, /* interpreter */ - ItclObject *contextObj, /* object being constructed */ - ItclClass *contextClass) /* current class being constructed */ -{ - int result = TCL_OK; - Tcl_Obj *objPtr; - Itcl_ListElem *elem; - - /* - * If the class has an "initCode", invoke it in the current context. - */ - - if (contextClass->initCode) { - - /* TODO: NRE */ - result = Tcl_EvalObj(interp, contextClass->initCode); - } - - /* - * Scan through the list of base classes and see if any of these - * have not been constructed. Invoke base class constructors - * implicitly, as needed. Go through the list of base classes - * in reverse order, so that least-specific classes are constructed - * first. - */ - - objPtr = Tcl_NewStringObj("constructor", -1); - Tcl_IncrRefCount(objPtr); - for (elem = Itcl_LastListElem(&contextClass->bases); - result == TCL_OK && elem != NULL; - elem = Itcl_PrevListElem(elem)) { - - Tcl_HashEntry *entry; - ItclClass *iclsPtr = (ItclClass*)Itcl_GetListValue(elem); - - if (Tcl_FindHashEntry(contextObj->constructed, - (char *)iclsPtr->namePtr)) { - - /* Already constructed, nothing to do. */ - continue; - } - - entry = Tcl_FindHashEntry(&iclsPtr->functions, (char *)objPtr); - if (entry) { - void *callbackPtr = Itcl_GetCurrentCallbackPtr(interp); - Tcl_NRAddCallback(interp, CallInvokeMethodIfExists, iclsPtr, - contextObj, INT2PTR(0), NULL); - result = Itcl_NRRunCallbacks(interp, callbackPtr); - } else { - result = Itcl_ConstructBase(interp, contextObj, iclsPtr); - } - } - Tcl_DecrRefCount(objPtr); - return result; -} - -int -ItclConstructGuts( - ItclObject *contextObj, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - ItclClass *contextClass; - - /* Ignore syntax error */ - if (objc != 3) { - return TCL_OK; - } - - /* Object is fully constructed. This becomes no-op. */ - if (contextObj->constructed == NULL) { - return TCL_OK; - } - - contextClass = Itcl_FindClass(interp, Tcl_GetString(objv[2]), 0); - if (contextClass == NULL) { - return TCL_OK; - } - - - return Itcl_ConstructBase(interp, contextObj, contextClass); -} - -/* - * ------------------------------------------------------------------------ - * Itcl_InvokeMethodIfExists() - * - * Looks for a particular method in the specified class. If the - * method is found, it is invoked with the given arguments. Any - * protection level (protected/private) for the method is ignored. - * If the method does not exist, this procedure does nothing. - * - * This procedure is used primarily to invoke the constructor/destructor - * when an object is created/destroyed. - * - * Returns TCL_OK on success; otherwise, this procedure returns - * TCL_ERROR along with an error message in the interpreter. - * ------------------------------------------------------------------------ - */ -int -Itcl_InvokeMethodIfExists( - Tcl_Interp *interp, /* interpreter */ - const char *name, /* name of desired method */ - ItclClass *contextClassPtr, /* current class being constructed */ - ItclObject *contextObjectPtr, /* object being constructed */ - int objc, /* number of arguments */ - Tcl_Obj *const objv[]) /* argument objects */ -{ - Tcl_HashEntry *hPtr; - Tcl_Obj *cmdlinePtr; - Tcl_Obj **cmdlinev; - Tcl_Obj **newObjv; - Tcl_CallFrame frame; - ItclMemberFunc *imPtr; - int cmdlinec; - int result = TCL_OK; - Tcl_Obj *objPtr = Tcl_NewStringObj(name, -1); - - ItclShowArgs(1, "Itcl_InvokeMethodIfExists", objc, objv); - hPtr = Tcl_FindHashEntry(&contextClassPtr->functions, (char *)objPtr); - Tcl_DecrRefCount(objPtr); - if (hPtr) { - imPtr = (ItclMemberFunc*)Tcl_GetHashValue(hPtr); - - /* - * Prepend the method name to the list of arguments. - */ - cmdlinePtr = Itcl_CreateArgs(interp, name, objc, objv); - - (void) Tcl_ListObjGetElements((Tcl_Interp*)NULL, cmdlinePtr, - &cmdlinec, &cmdlinev); - - ItclShowArgs(1, "EMC", cmdlinec, cmdlinev); - /* - * Execute the code for the method. Be careful to protect - * the method in case it gets deleted during execution. - */ - ItclPreserveIMF(imPtr); - - if (contextObjectPtr->oPtr == NULL) { - Tcl_DecrRefCount(cmdlinePtr); - return TCL_ERROR; - } - result = Itcl_EvalMemberCode(interp, imPtr, contextObjectPtr, - cmdlinec, cmdlinev); - ItclReleaseIMF(imPtr); - Tcl_DecrRefCount(cmdlinePtr); - } else { - if (contextClassPtr->flags & - (ITCL_ECLASS|ITCL_TYPE|ITCL_WIDGET|ITCL_WIDGETADAPTOR)) { - if (strcmp(name, "constructor") == 0) { - if (objc > 0) { - if (contextClassPtr->numOptions == 0) { - /* check if all options are delegeted */ - Tcl_Obj *objPtr; - objPtr = Tcl_NewStringObj("*", -1); - hPtr = Tcl_FindHashEntry( - &contextClassPtr->delegatedOptions, - (char *)objPtr); - Tcl_DecrRefCount(objPtr); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "type \"", - Tcl_GetString(contextClassPtr->namePtr), - "\" has no options, but constructor has", - " option arguments", NULL); - return TCL_ERROR; - } - } - if (Itcl_PushCallFrame(interp, &frame, - contextClassPtr->nsPtr, - /*isProcCallFrame*/0) != TCL_OK) { - Tcl_AppendResult(interp, "INTERNAL ERROR in", - "Itcl_InvokeMethodIfExists Itcl_PushCallFrame", - NULL); - } - newObjv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *)*(objc + 2)); - newObjv[0] = Tcl_NewStringObj("my", -1); - Tcl_IncrRefCount(newObjv[0]); - newObjv[1] = Tcl_NewStringObj("configure", -1); - Tcl_IncrRefCount(newObjv[1]); - memcpy(newObjv + 2, objv, (objc * sizeof(Tcl_Obj *))); - ItclShowArgs(1, "DEFAULT Constructor", objc + 2, newObjv); - result = Tcl_EvalObjv(interp, objc + 2, newObjv, 0); - Tcl_DecrRefCount(newObjv[1]); - Tcl_DecrRefCount(newObjv[0]); - ckfree((char *)newObjv); - Itcl_PopCallFrame(interp); - } - } - } - } - return result; -} - - -/* - * ------------------------------------------------------------------------ - * Itcl_ReportFuncErrors() - * - * Used to interpret the status code returned when the body of a - * Tcl-style proc is executed. Handles the "errorInfo" and "errorCode" - * variables properly, and adds error information into the interpreter - * if anything went wrong. Returns a new status code that should be - * treated as the return status code for the command. - * - * This same operation is usually buried in the Tcl InterpProc() - * procedure. It is defined here so that it can be reused more easily. - * ------------------------------------------------------------------------ - */ -int -Itcl_ReportFuncErrors( - Tcl_Interp* interp, /* interpreter being modified */ - ItclMemberFunc *imPtr, /* command member that was invoked */ - ItclObject *contextObj, /* object context for this command */ - int result) /* integer status code from proc body */ -{ -/* FIXME !!! */ -/* adapt to use of ItclProcErrorProc for stubs compatibility !! */ - return result; -} - -/* - * ------------------------------------------------------------------------ - * Itcl_CmdAliasProc() - * - * ------------------------------------------------------------------------ - */ -Tcl_Command -Itcl_CmdAliasProc( - Tcl_Interp *interp, - Tcl_Namespace *nsPtr, - const char *cmdName, - ClientData clientData) -{ - Tcl_HashEntry *hPtr; - Tcl_Obj *objPtr; - ItclObjectInfo *infoPtr; - ItclClass *iclsPtr; - ItclObject *ioPtr; - ItclMemberFunc *imPtr; - ItclResolveInfo *resolveInfoPtr; - ItclCmdLookup *clookup; - - resolveInfoPtr = (ItclResolveInfo *)clientData; - if (resolveInfoPtr->flags & ITCL_RESOLVE_OBJECT) { - ioPtr = resolveInfoPtr->ioPtr; - iclsPtr = ioPtr->iclsPtr; - } else { - ioPtr = NULL; - iclsPtr = resolveInfoPtr->iclsPtr; - } - infoPtr = iclsPtr->infoPtr; - hPtr = Tcl_FindHashEntry(&infoPtr->namespaceClasses, (char *)nsPtr); - if (hPtr == NULL) { - return NULL; - } - iclsPtr = Tcl_GetHashValue(hPtr); - objPtr = Tcl_NewStringObj(cmdName, -1); - hPtr = Tcl_FindHashEntry(&iclsPtr->resolveCmds, (char *)objPtr); - Tcl_DecrRefCount(objPtr); - if (hPtr == NULL) { - if (strcmp(cmdName, "@itcl-builtin-cget") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::cget", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-configure") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::configure", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-destroy") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::destroy", NULL, 0); - } - if (strncmp(cmdName, "@itcl-builtin-setget", 20) == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::setget", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-isa") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::isa", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-createhull") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::createhull", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-keepcomponentoption") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::keepcomponentoption", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-ignorecomponentoption") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::removecomponentoption", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-irgnorecomponentoption") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::ignorecomponentoption", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-setupcomponent") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::setupcomponent", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-initoptions") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::initoptions", NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-mytypemethod") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::mytypemethod", - NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-mymethod") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::mymethod", - NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-myproc") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::myproc", - NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-mytypevar") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::mytypevar", - NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-myvar") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::myvar", - NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-itcl_hull") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::itcl_hull", - NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-callinstance") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::callinstance", - NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-getinstancevar") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::getinstancevar", - NULL, 0); - } - if (strcmp(cmdName, "@itcl-builtin-classunknown") == 0) { - return Tcl_FindCommand(interp, "::itcl::builtin::classunknown", NULL, 0); - } - return NULL; - } - clookup = (ItclCmdLookup *)Tcl_GetHashValue(hPtr); - imPtr = clookup->imPtr; - return imPtr->accessCmd; -} - -/* - * ------------------------------------------------------------------------ - * Itcl_VarAliasProc() - * - * ------------------------------------------------------------------------ - */ -Tcl_Var -Itcl_VarAliasProc( - Tcl_Interp *interp, - Tcl_Namespace *nsPtr, - const char *varName, - ClientData clientData) -{ - - Tcl_HashEntry *hPtr; - ItclObjectInfo *infoPtr; - ItclClass *iclsPtr; - ItclObject *ioPtr; - ItclVarLookup *ivlPtr; - ItclResolveInfo *resolveInfoPtr; - ItclCallContext *callContextPtr; - Tcl_Var varPtr; - - varPtr = NULL; - hPtr = NULL; - callContextPtr = NULL; - resolveInfoPtr = (ItclResolveInfo *)clientData; - if (resolveInfoPtr->flags & ITCL_RESOLVE_OBJECT) { - ioPtr = resolveInfoPtr->ioPtr; - iclsPtr = ioPtr->iclsPtr; - } else { - ioPtr = NULL; - iclsPtr = resolveInfoPtr->iclsPtr; - } - infoPtr = iclsPtr->infoPtr; - hPtr = Tcl_FindHashEntry(&infoPtr->namespaceClasses, (char *)nsPtr); - if (hPtr != NULL) { - iclsPtr = Tcl_GetHashValue(hPtr); - } - hPtr = Tcl_FindHashEntry(&iclsPtr->resolveVars, varName); - if (hPtr == NULL) { - /* no class/object variable */ - return NULL; - } - ivlPtr = Tcl_GetHashValue(hPtr); - if (ivlPtr == NULL) { - return NULL; - } - if (!ivlPtr->accessible) { - return NULL; - } - - if (ioPtr != NULL) { - hPtr = Tcl_FindHashEntry(&ioPtr->objectVariables, - (char *)ivlPtr->ivPtr); - } else { - hPtr = Tcl_FindHashEntry(&iclsPtr->classCommons, - (char *)ivlPtr->ivPtr); - if (hPtr == NULL) { - if (callContextPtr != NULL) { - ioPtr = callContextPtr->ioPtr; - } - if (ioPtr != NULL) { - hPtr = Tcl_FindHashEntry(&ioPtr->objectVariables, - (char *)ivlPtr->ivPtr); - } - } - } - if (hPtr != NULL) { - varPtr = Tcl_GetHashValue(hPtr); - } - return varPtr; -} - -/* - * ------------------------------------------------------------------------ - * ItclCheckCallProc() - * - * - * ------------------------------------------------------------------------ - */ -int -ItclCheckCallProc( - ClientData clientData, - Tcl_Interp *interp, - Tcl_ObjectContext contextPtr, - Tcl_CallFrame *framePtr, - int *isFinished) -{ - int result; - ItclMemberFunc *imPtr; - - imPtr = (ItclMemberFunc *)clientData; - if (!imPtr->iclsPtr->infoPtr->useOldResolvers) { - Itcl_SetCallFrameResolver(interp, imPtr->iclsPtr->resolvePtr); - } - result = TCL_OK; - - if (isFinished != NULL) { - *isFinished = 0; - } - return result; -} - -/* - * ------------------------------------------------------------------------ - * ItclCheckCallMethod() - * - * - * ------------------------------------------------------------------------ - */ -int -ItclCheckCallMethod( - ClientData clientData, - Tcl_Interp *interp, - Tcl_ObjectContext contextPtr, - Tcl_CallFrame *framePtr, - int *isFinished) -{ - Itcl_Stack *stackPtr; - - Tcl_Object oPtr; - ItclObject *ioPtr; - Tcl_HashEntry *hPtr; - Tcl_Obj *const * cObjv; - Tcl_Namespace *currNsPtr; - ItclCallContext *callContextPtr; - ItclCallContext *callContextPtr2; - ItclMemberFunc *imPtr; - int result; - int isNew; - int cObjc; - int min_allowed_args; - - ItclObjectInfo *infoPtr; - - oPtr = NULL; - hPtr = NULL; - imPtr = (ItclMemberFunc *)clientData; - ItclPreserveIMF(imPtr); - if (imPtr->flags & ITCL_CONSTRUCTOR) { - ioPtr = imPtr->iclsPtr->infoPtr->currIoPtr; - } else { - if (contextPtr == NULL) { - if ((imPtr->flags & ITCL_COMMON) || - (imPtr->codePtr->flags & ITCL_BUILTIN)) { - if (!imPtr->iclsPtr->infoPtr->useOldResolvers) { - Itcl_SetCallFrameResolver(interp, - imPtr->iclsPtr->resolvePtr); - } - if (isFinished != NULL) { - *isFinished = 0; - } - return TCL_OK; - } - Tcl_AppendResult(interp, - "ItclCheckCallMethod cannot get context object (NULL)", - " for ", Tcl_GetString(imPtr->fullNamePtr), - NULL); - result = TCL_ERROR; - goto finishReturn; - } - oPtr = Tcl_ObjectContextObject(contextPtr); - ioPtr = Tcl_ObjectGetMetadata(oPtr, - imPtr->iclsPtr->infoPtr->object_meta_type); - } - if ((imPtr->codePtr != NULL) && - (imPtr->codePtr->flags & ITCL_IMPLEMENT_NONE)) { - Tcl_AppendResult(interp, "member function \"", - Tcl_GetString(imPtr->fullNamePtr), - "\" is not defined and cannot be autoloaded", NULL); - if (isFinished != NULL) { - *isFinished = 1; - } - result = TCL_ERROR; - goto finishReturn; - } - if (framePtr) { - /* - * This stanza is in place to seize control over usage error messages - * before TclOO examines the arguments and produces its own. This - * gives Itcl stability in its error messages at the cost of inconsistency - * with Tcl's evolving conventions. - */ - cObjc = Itcl_GetCallFrameObjc(interp); - cObjv = Itcl_GetCallFrameObjv(interp); - min_allowed_args = cObjc-2; - if (strcmp(Tcl_GetString(cObjv[0]), "next") == 0) { - min_allowed_args++; - } - if (min_allowed_args < imPtr->argcount) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tcl_GetString(cObjv[0]), " ", Tcl_GetString(imPtr->namePtr), - " ", Tcl_GetString(imPtr->usagePtr), "\"", NULL); - if (isFinished != NULL) { - *isFinished = 1; - } - result = TCL_ERROR; - goto finishReturn; - } - } - isNew = 0; - callContextPtr = NULL; - currNsPtr = Tcl_GetCurrentNamespace(interp); - if (ioPtr != NULL) { - hPtr = Tcl_CreateHashEntry(&ioPtr->contextCache, (char *)imPtr, &isNew); - if (!isNew) { - callContextPtr2 = Tcl_GetHashValue(hPtr); - if (callContextPtr2->refCount == 0) { - callContextPtr = callContextPtr2; - callContextPtr->objectFlags = ioPtr->flags; - callContextPtr->nsPtr = Tcl_GetCurrentNamespace(interp); - callContextPtr->ioPtr = ioPtr; - callContextPtr->imPtr = imPtr; - callContextPtr->refCount = 1; - } else { - if ((callContextPtr2->objectFlags == ioPtr->flags) - && (callContextPtr2->nsPtr == currNsPtr)) { - callContextPtr = callContextPtr2; - callContextPtr->refCount++; - } - } - } - } - if (callContextPtr == NULL) { - callContextPtr = (ItclCallContext *)ckalloc( - sizeof(ItclCallContext)); - if (ioPtr == NULL) { - callContextPtr->objectFlags = 0; - callContextPtr->ioPtr = NULL; - } else { - callContextPtr->objectFlags = ioPtr->flags; - callContextPtr->ioPtr = ioPtr; - } - callContextPtr->nsPtr = Tcl_GetCurrentNamespace(interp); - callContextPtr->imPtr = imPtr; - callContextPtr->refCount = 1; - } - if (isNew) { - Tcl_SetHashValue(hPtr, callContextPtr); - } - - if (framePtr == NULL) { - framePtr = Itcl_GetUplevelCallFrame(interp, 0); - } - - isNew = 0; - infoPtr = imPtr->iclsPtr->infoPtr; - hPtr = Tcl_CreateHashEntry(&infoPtr->frameContext, - (char *)framePtr, &isNew); - if (isNew) { - stackPtr = (Itcl_Stack *)ckalloc(sizeof(Itcl_Stack)); - Itcl_InitStack(stackPtr); - Tcl_SetHashValue(hPtr, stackPtr); - } else { - stackPtr = (Itcl_Stack *)Tcl_GetHashValue(hPtr); - } - - assert (callContextPtr) ; - Itcl_PushStack(callContextPtr, stackPtr); - - /* Ugly abuse alert. Two maps in one table */ - hPtr = Tcl_CreateHashEntry(&infoPtr->frameContext, - (char *)contextPtr, &isNew); - if (isNew) { - stackPtr = (Itcl_Stack *)ckalloc(sizeof(Itcl_Stack)); - Itcl_InitStack(stackPtr); - Tcl_SetHashValue(hPtr, stackPtr); - } else { - stackPtr = (Itcl_Stack *)Tcl_GetHashValue(hPtr); - } - - Itcl_PushStack(framePtr, stackPtr); - - if (ioPtr != NULL) { - ioPtr->callRefCount++; - ItclPreserveObject(ioPtr); - } - imPtr->iclsPtr->callRefCount++; - if (!imPtr->iclsPtr->infoPtr->useOldResolvers) { - Itcl_SetCallFrameResolver(interp, ioPtr->resolvePtr); - } - result = TCL_OK; - - if (isFinished != NULL) { - *isFinished = 0; - } - return result; -finishReturn: - ItclReleaseIMF(imPtr); - return result; -} - -/* - * ------------------------------------------------------------------------ - * ItclAfterCallMethod() - * - * - * ------------------------------------------------------------------------ - */ -int -ItclAfterCallMethod( - ClientData clientData, - Tcl_Interp *interp, - Tcl_ObjectContext contextPtr, - Tcl_Namespace *nsPtr, - int call_result) -{ - Tcl_HashEntry *hPtr; - ItclObject *ioPtr; - ItclMemberFunc *imPtr; - ItclCallContext *callContextPtr; - int newEntry; - int result; - - imPtr = (ItclMemberFunc *)clientData; - callContextPtr = NULL; - if (contextPtr != NULL) { - ItclObjectInfo *infoPtr = imPtr->infoPtr; - Tcl_CallFrame *framePtr; - Itcl_Stack *stackPtr; - - hPtr = Tcl_FindHashEntry(&infoPtr->frameContext, (char *)contextPtr); - assert(hPtr); - stackPtr = (Itcl_Stack *)Tcl_GetHashValue(hPtr); - framePtr = Itcl_PopStack(stackPtr); - if (Itcl_GetStackSize(stackPtr) == 0) { - Itcl_DeleteStack(stackPtr); - ckfree((char *) stackPtr); - Tcl_DeleteHashEntry(hPtr); - } - - hPtr = Tcl_FindHashEntry(&infoPtr->frameContext, (char *)framePtr); - assert(hPtr); - stackPtr = (Itcl_Stack *)Tcl_GetHashValue(hPtr); - callContextPtr = Itcl_PopStack(stackPtr); - if (Itcl_GetStackSize(stackPtr) == 0) { - Itcl_DeleteStack(stackPtr); - ckfree((char *) stackPtr); - Tcl_DeleteHashEntry(hPtr); - } - } - if (callContextPtr == NULL) { - if ((imPtr->flags & ITCL_COMMON) || - (imPtr->codePtr->flags & ITCL_BUILTIN)) { - result = call_result; - goto finishReturn; - } - Tcl_AppendResult(interp, - "ItclAfterCallMethod cannot get context object (NULL)", - " for ", Tcl_GetString(imPtr->fullNamePtr), NULL); - result = TCL_ERROR; - goto finishReturn; - } - /* - * If this is a constructor or destructor, and if it is being - * invoked at the appropriate time, keep track of which methods - * have been called. This information is used to implicitly - * invoke constructors/destructors as needed. - */ - ioPtr = callContextPtr->ioPtr; - if (ioPtr != NULL) { - if (imPtr->iclsPtr) { - imPtr->iclsPtr->callRefCount--; - if (imPtr->flags & (ITCL_CONSTRUCTOR | ITCL_DESTRUCTOR)) { - if ((imPtr->flags & ITCL_DESTRUCTOR) && ioPtr && - ioPtr->destructed) { - Tcl_CreateHashEntry(ioPtr->destructed, - (char *)imPtr->iclsPtr->namePtr, &newEntry); - } - if ((imPtr->flags & ITCL_CONSTRUCTOR) && ioPtr && - ioPtr->constructed) { - Tcl_CreateHashEntry(ioPtr->constructed, - (char *)imPtr->iclsPtr->namePtr, &newEntry); - } - } - } - ioPtr->callRefCount--; - if (ioPtr->flags & ITCL_OBJECT_SHOULD_VARNS_DELETE) { - ItclDeleteObjectVariablesNamespace(interp, ioPtr); - } - } - - callContextPtr->refCount--; - if (callContextPtr->refCount == 0) { - if (callContextPtr->ioPtr != NULL) { - hPtr = Tcl_FindHashEntry(&callContextPtr->ioPtr->contextCache, - (char *)callContextPtr->imPtr); - if (hPtr == NULL) { - ckfree((char *)callContextPtr); - } - ItclReleaseObject(ioPtr); - } else { - ckfree((char *)callContextPtr); - } - } - result = call_result; -finishReturn: - ItclReleaseIMF(imPtr); - return result; -} - -void -ItclProcErrorProc( - Tcl_Interp *interp, - Tcl_Obj *procNameObj) -{ - Tcl_Obj *objPtr; - Tcl_HashEntry *hPtr; - ItclObjectInfo *infoPtr; - ItclCallContext *callContextPtr; - ItclMemberFunc *imPtr; - ItclObject *contextIoPtr; - ItclClass *currIclsPtr; - char num[20]; - Itcl_Stack *stackPtr; - - /* Fetch the current call frame. That determines context. */ - Tcl_CallFrame *framePtr = Itcl_GetUplevelCallFrame(interp, 0); - - /* Try to map it to a context stack. */ - infoPtr = (ItclObjectInfo *)Tcl_GetAssocData(interp, - ITCL_INTERP_DATA, NULL); - hPtr = Tcl_FindHashEntry(&infoPtr->frameContext, (char *)framePtr); - if (hPtr == NULL) { - /* Can this happen? */ - return; - } - - /* Frame maps to a context stack. */ - stackPtr = (Itcl_Stack *)Tcl_GetHashValue(hPtr); - callContextPtr = Itcl_PeekStack(stackPtr); - - if (callContextPtr == NULL) { - return; - } - - currIclsPtr = NULL; - objPtr = NULL; - { - imPtr = callContextPtr->imPtr; - contextIoPtr = callContextPtr->ioPtr; - objPtr = Tcl_NewStringObj("\n ", -1); - - if (imPtr->flags & ITCL_CONSTRUCTOR) { - currIclsPtr = imPtr->iclsPtr; - Tcl_AppendToObj(objPtr, "while constructing object \"", -1); - Tcl_GetCommandFullName(interp, contextIoPtr->accessCmd, objPtr); - Tcl_AppendToObj(objPtr, "\" in ", -1); - Tcl_AppendToObj(objPtr, currIclsPtr->nsPtr->fullName, -1); - Tcl_AppendToObj(objPtr, "::constructor", -1); - if ((imPtr->codePtr->flags & ITCL_IMPLEMENT_TCL) != 0) { - Tcl_AppendToObj(objPtr, " (", -1); - } - } - if (imPtr->flags & ITCL_DESTRUCTOR) { - contextIoPtr->flags = 0; - Tcl_AppendToObj(objPtr, "while deleting object \"", -1); - Tcl_GetCommandFullName(interp, contextIoPtr->accessCmd, objPtr); - Tcl_AppendToObj(objPtr, "\" in ", -1); - Tcl_AppendToObj(objPtr, Tcl_GetString(imPtr->fullNamePtr), -1); - if ((imPtr->codePtr->flags & ITCL_IMPLEMENT_TCL) != 0) { - Tcl_AppendToObj(objPtr, " (", -1); - } - } - if (!(imPtr->flags & (ITCL_CONSTRUCTOR|ITCL_DESTRUCTOR))) { - Tcl_AppendToObj(objPtr, "(", -1); - - hPtr = Tcl_FindHashEntry(&infoPtr->objects, (char *)contextIoPtr); - if (hPtr != NULL) { - if ((contextIoPtr != NULL) && (contextIoPtr->accessCmd)) { - Tcl_AppendToObj(objPtr, "object \"", -1); - Tcl_GetCommandFullName(interp, contextIoPtr->accessCmd, objPtr); - Tcl_AppendToObj(objPtr, "\" ", -1); - } - } - - if ((imPtr->flags & ITCL_COMMON) != 0) { - Tcl_AppendToObj(objPtr, "procedure", -1); - } else { - Tcl_AppendToObj(objPtr, "method", -1); - } - Tcl_AppendToObj(objPtr, " \"", -1); - Tcl_AppendToObj(objPtr, Tcl_GetString(imPtr->fullNamePtr), -1); - Tcl_AppendToObj(objPtr, "\" ", -1); - } - - if ((imPtr->codePtr->flags & ITCL_IMPLEMENT_TCL) != 0) { - Tcl_Obj *dictPtr; - Tcl_Obj *keyPtr; - Tcl_Obj *valuePtr; - int lineNo; - - keyPtr = Tcl_NewStringObj("-errorline", -1); - dictPtr = Tcl_GetReturnOptions(interp, TCL_ERROR); - if (Tcl_DictObjGet(interp, dictPtr, keyPtr, &valuePtr) != TCL_OK) { - /* how should we handle an error ? */ - Tcl_DecrRefCount(keyPtr); - Tcl_DecrRefCount(objPtr); - return; - } - if (valuePtr == NULL) { - /* how should we handle an error ? */ - Tcl_DecrRefCount(keyPtr); - Tcl_DecrRefCount(objPtr); - return; - } - if (Tcl_GetIntFromObj(interp, valuePtr, &lineNo) != TCL_OK) { - /* how should we handle an error ? */ - Tcl_DecrRefCount(keyPtr); - Tcl_DecrRefCount(valuePtr); - Tcl_DecrRefCount(objPtr); - return; - } - Tcl_DecrRefCount(keyPtr); - Tcl_DecrRefCount(valuePtr); - Tcl_AppendToObj(objPtr, "body line ", -1); - sprintf(num, "%d", lineNo); - Tcl_AppendToObj(objPtr, num, -1); - Tcl_AppendToObj(objPtr, ")", -1); - } else { - Tcl_AppendToObj(objPtr, ")", -1); - } - - Tcl_AppendObjToErrorInfo(interp, objPtr); - objPtr = NULL; - } - if (objPtr != NULL) { - Tcl_DecrRefCount(objPtr); - } -} |