tclproc.c

来自「tcl是工具命令语言」· C语言 代码 · 共 1,707 行 · 第 1/4 页

C
1,707
字号
		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),			"procedure \"", procName,			buf, (char *) NULL);		ckfree((char *) fieldValues);		goto procError;	    }            /*             * compare the default value if any             */            if (localPtr->defValuePtr != NULL) {                int tmpLength;                char *tmpPtr = Tcl_GetStringFromObj(localPtr->defValuePtr,                        &tmpLength);                if ((valueLength != tmpLength)                        || (strncmp(fieldValues[1], tmpPtr,                                (size_t) tmpLength))) {                    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),                            "procedure \"", procName,                            "\": formal parameter \"",                            fieldValues[0],                            "\" has default value inconsistent with precompiled body",                            (char *) NULL);                    ckfree((char *) fieldValues);                    goto procError;                }            }            localPtr = localPtr->nextPtr;        } else {            /*             * Allocate an entry in the runtime procedure frame's array of             * local variables for the argument.              */            localPtr = (CompiledLocal *) ckalloc((unsigned)                     (sizeof(CompiledLocal) - sizeof(localPtr->name)                            + nameLength+1));            if (procPtr->firstLocalPtr == NULL) {                procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;            } else {                procPtr->lastLocalPtr->nextPtr = localPtr;                procPtr->lastLocalPtr = localPtr;            }            localPtr->nextPtr = NULL;            localPtr->nameLength = nameLength;            localPtr->frameIndex = i;            localPtr->flags = VAR_SCALAR | VAR_ARGUMENT;            localPtr->resolveInfo = NULL;	            if (fieldCount == 2) {                localPtr->defValuePtr =		    Tcl_NewStringObj(fieldValues[1], valueLength);                Tcl_IncrRefCount(localPtr->defValuePtr);            } else {                localPtr->defValuePtr = NULL;            }            strcpy(localPtr->name, fieldValues[0]);	}        ckfree((char *) fieldValues);    }    /*     * Now initialize the new procedure's cmdPtr field. This will be used     * later when the procedure is called to determine what namespace the     * procedure will run in. This will be different than the current     * namespace if the proc was renamed into a different namespace.     */        *procPtrPtr = procPtr;    ckfree((char *) argArray);    return TCL_OK;procError:    if (precompiled) {        procPtr->refCount--;    } else {        Tcl_DecrRefCount(bodyPtr);        while (procPtr->firstLocalPtr != NULL) {            localPtr = procPtr->firstLocalPtr;            procPtr->firstLocalPtr = localPtr->nextPtr;	            defPtr = localPtr->defValuePtr;            if (defPtr != NULL) {                Tcl_DecrRefCount(defPtr);            }	            ckfree((char *) localPtr);        }        ckfree((char *) procPtr);    }    if (argArray != NULL) {	ckfree((char *) argArray);    }    return TCL_ERROR;}/* *---------------------------------------------------------------------- * * TclGetFrame -- * *	Given a description of a procedure frame, such as the first *	argument to an "uplevel" or "upvar" command, locate the *	call frame for the appropriate level of procedure. * * Results: *	The return value is -1 if an error occurred in finding the frame *	(in this case an error message is left in the interp's result). *	1 is returned if string was either a number or a number preceded *	by "#" and it specified a valid frame.  0 is returned if string *	isn't one of the two things above (in this case, the lookup *	acts as if string were "1").  The variable pointed to by *	framePtrPtr is filled in with the address of the desired frame *	(unless an error occurs, in which case it isn't modified). * * Side effects: *	None. * *---------------------------------------------------------------------- */intTclGetFrame(interp, string, framePtrPtr)    Tcl_Interp *interp;		/* Interpreter in which to find frame. */    CONST char *string;		/* String describing frame. */    CallFrame **framePtrPtr;	/* Store pointer to frame here (or NULL				 * if global frame indicated). */{    register Interp *iPtr = (Interp *) interp;    int curLevel, level, result;    CallFrame *framePtr;    /*     * Parse string to figure out which level number to go to.     */    result = 1;    curLevel = (iPtr->varFramePtr == NULL) ? 0 : iPtr->varFramePtr->level;    if (*string == '#') {	if (Tcl_GetInt(interp, string+1, &level) != TCL_OK) {	    return -1;	}	if (level < 0) {	    levelError:	    Tcl_AppendResult(interp, "bad level \"", string, "\"",		    (char *) NULL);	    return -1;	}    } else if (isdigit(UCHAR(*string))) { /* INTL: digit */	if (Tcl_GetInt(interp, string, &level) != TCL_OK) {	    return -1;	}	level = curLevel - level;    } else {	level = curLevel - 1;	result = 0;    }    /*     * Figure out which frame to use, and modify the interpreter so     * its variables come from that frame.     */    if (level == 0) {	framePtr = NULL;    } else {	for (framePtr = iPtr->varFramePtr; framePtr != NULL;		framePtr = framePtr->callerVarPtr) {	    if (framePtr->level == level) {		break;	    }	}	if (framePtr == NULL) {	    goto levelError;	}    }    *framePtrPtr = framePtr;    return result;}/* *---------------------------------------------------------------------- * * Tcl_UplevelObjCmd -- * *	This object procedure is invoked to process the "uplevel" Tcl *	command. See the user documentation for details on what it does. * * Results: *	A standard Tcl object result value. * * Side effects: *	See the user documentation. * *---------------------------------------------------------------------- */	/* ARGSUSED */intTcl_UplevelObjCmd(dummy, interp, objc, objv)    ClientData dummy;		/* Not used. */    Tcl_Interp *interp;		/* Current interpreter. */    int objc;			/* Number of arguments. */    Tcl_Obj *CONST objv[];	/* Argument objects. */{    register Interp *iPtr = (Interp *) interp;    char *optLevel;    int result;    CallFrame *savedVarFramePtr, *framePtr;    if (objc < 2) {	uplevelSyntax:	Tcl_WrongNumArgs(interp, 1, objv, "?level? command ?arg ...?");	return TCL_ERROR;    }    /*     * Find the level to use for executing the command.     */    optLevel = TclGetString(objv[1]);    result = TclGetFrame(interp, optLevel, &framePtr);    if (result == -1) {	return TCL_ERROR;    }    objc -= (result+1);    if (objc == 0) {	goto uplevelSyntax;    }    objv += (result+1);    /*     * Modify the interpreter state to execute in the given frame.     */    savedVarFramePtr = iPtr->varFramePtr;    iPtr->varFramePtr = framePtr;    /*     * Execute the residual arguments as a command.     */    if (objc == 1) {	result = Tcl_EvalObjEx(interp, objv[0], TCL_EVAL_DIRECT);    } else {	/*	 * More than one argument: concatenate them together with spaces	 * between, then evaluate the result.  Tcl_EvalObjEx will delete	 * the object when it decrements its refcount after eval'ing it.	 */	Tcl_Obj *objPtr;	objPtr = Tcl_ConcatObj(objc, objv);	result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT);    }    if (result == TCL_ERROR) {	char msg[32 + TCL_INTEGER_SPACE];	sprintf(msg, "\n    (\"uplevel\" body line %d)", interp->errorLine);	Tcl_AddObjErrorInfo(interp, msg, -1);    }    /*     * Restore the variable frame, and return.     */    iPtr->varFramePtr = savedVarFramePtr;    return result;}/* *---------------------------------------------------------------------- * * TclFindProc -- * *	Given the name of a procedure, return a pointer to the *	record describing the procedure. The procedure will be *	looked up using the usual rules: first in the current *	namespace and then in the global namespace. * * Results: *	NULL is returned if the name doesn't correspond to any *	procedure. Otherwise, the return value is a pointer to *	the procedure's record. If the name is found but refers *	to an imported command that points to a "real" procedure *	defined in another namespace, a pointer to that "real" *	procedure's structure is returned. * * Side effects: *	None. * *---------------------------------------------------------------------- */Proc *TclFindProc(iPtr, procName)    Interp *iPtr;		/* Interpreter in which to look. */    CONST char *procName;		/* Name of desired procedure. */{    Tcl_Command cmd;    Tcl_Command origCmd;    Command *cmdPtr;        cmd = Tcl_FindCommand((Tcl_Interp *) iPtr, procName,            (Tcl_Namespace *) NULL, /*flags*/ 0);    if (cmd == (Tcl_Command) NULL) {        return NULL;    }    cmdPtr = (Command *) cmd;    origCmd = TclGetOriginalCommand(cmd);    if (origCmd != NULL) {	cmdPtr = (Command *) origCmd;    }    if (cmdPtr->proc != TclProcInterpProc) {	return NULL;    }    return (Proc *) cmdPtr->clientData;}/* *---------------------------------------------------------------------- * * TclIsProc -- * *	Tells whether a command is a Tcl procedure or not. * * Results: *	If the given command is actually a Tcl procedure, the *	return value is the address of the record describing *	the procedure.  Otherwise the return value is 0. * * Side effects: *	None. * *---------------------------------------------------------------------- */Proc *TclIsProc(cmdPtr)    Command *cmdPtr;		/* Command to test. */{    Tcl_Command origCmd;    origCmd = TclGetOriginalCommand((Tcl_Command) cmdPtr);    if (origCmd != NULL) {	cmdPtr = (Command *) origCmd;    }    if (cmdPtr->proc == TclProcInterpProc) {	return (Proc *) cmdPtr->clientData;    }    return (Proc *) 0;}/* *---------------------------------------------------------------------- * * TclProcInterpProc -- * *	When a Tcl procedure gets invoked with an argc/argv array of *	strings, this routine gets invoked to interpret the procedure. * * Results: *	A standard Tcl result value, usually TCL_OK. * * Side effects: *	Depends on the commands in the procedure. * *---------------------------------------------------------------------- */intTclProcInterpProc(clientData, interp, argc, argv)    ClientData clientData;	/* Record describing procedure to be				 * interpreted. */    Tcl_Interp *interp;		/* Interpreter in which procedure was				 * invoked. */    int argc;			/* Count of number of arguments to this				 * procedure. */    register CONST char **argv;	/* Argument values. */{    register Tcl_Obj *objPtr;    register int i;    int result;    /*     * This procedure generates an objv array for object arguments that hold     * the argv strings. It starts out with stack-allocated space but uses     * dynamically-allocated storage if needed.     */#define NUM_ARGS 20    Tcl_Obj *(objStorage[NUM_ARGS]);    register Tcl_Obj **objv = objStorage;    /*     * Create the object argument array "objv". Make sure objv is large     * enough to hold the objc arguments plus 1 extra for the zero     * end-of-objv word.     */    if ((argc + 1) > NUM_ARGS) {	objv = (Tcl_Obj **)	    ckalloc((unsigned)(argc + 1) * sizeof(Tcl_Obj *));    }    for (i = 0;  i < argc;  i++) {	objv[i] = Tcl_NewStringObj(argv[i], -1);	Tcl_IncrRefCount(objv[i]);    }    objv[argc] = 0;    /*     * Use TclObjInterpProc to actually interpret the procedure.     */    result = TclObjInterpProc(clientData, interp, argc, objv);    /*     * Move the interpreter's object result to the string result,      * then reset the object result.     */        Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),	    TCL_VOLATILE);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?