⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclproc.c

📁 linux系统下的音频通信
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  * tclProc.c -- * *	This file contains routines that implement Tcl procedures, *	including the "proc" and "uplevel" commands. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1994-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tclProc.c 1.14 98/08/07 11:47:46 */#include "tclInt.h"#include "tclCompile.h"/* *---------------------------------------------------------------------- * * Tcl_ProcObjCmd -- * *	This object-based procedure is invoked to process the "proc" Tcl  *	command. See the user documentation for details on what it does. * * Results: *	A standard Tcl object result value. * * Side effects: *	A new procedure gets created. * *---------------------------------------------------------------------- */	/* ARGSUSED */intTcl_ProcObjCmd(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;    Proc *procPtr;    char *fullName, *procName;    Namespace *nsPtr, *altNsPtr, *cxtNsPtr;    Tcl_Command cmd;    Tcl_DString ds;    int result;    if (objc != 4) {	Tcl_WrongNumArgs(interp, 1, objv, "name args body");	return TCL_ERROR;    }    /*     * Determine the namespace where the procedure should reside. Unless     * the command name includes namespace qualifiers, this will be the     * current namespace.     */        fullName = Tcl_GetStringFromObj(objv[1], (int *) NULL);    result = TclGetNamespaceForQualName(interp, fullName,	    (Namespace *) NULL, TCL_LEAVE_ERR_MSG,            &nsPtr, &altNsPtr, &cxtNsPtr, &procName);    if (result != TCL_OK) {        return result;    }    if (nsPtr == NULL) {        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),		"can't create procedure \"", fullName,		"\": unknown namespace", (char *) NULL);        return TCL_ERROR;    }    if (procName == NULL) {	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),		"can't create procedure \"", fullName,		"\": bad procedure name", (char *) NULL);        return TCL_ERROR;    }    if ((nsPtr != iPtr->globalNsPtr)	    && (procName != NULL) && (procName[0] == ':')) {	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),		"can't create procedure \"", procName,		"\" in non-global namespace with name starting with \":\"",	        (char *) NULL);        return TCL_ERROR;    }    /*     *  Create the data structure to represent the procedure.     */    if (TclCreateProc(interp, nsPtr, procName, objv[2], objv[3],        &procPtr) != TCL_OK) {        return TCL_ERROR;    }    /*     * Now create a command for the procedure. This will initially be in     * the current namespace unless the procedure's name included namespace     * qualifiers. To create the new command in the right namespace, we     * generate a fully qualified name for it.     */    Tcl_DStringInit(&ds);    if (nsPtr != iPtr->globalNsPtr) {	Tcl_DStringAppend(&ds, nsPtr->fullName, -1);	Tcl_DStringAppend(&ds, "::", 2);    }    Tcl_DStringAppend(&ds, procName, -1);        Tcl_CreateCommand(interp, Tcl_DStringValue(&ds), TclProcInterpProc,	    (ClientData) procPtr, TclProcDeleteProc);    cmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds),	    TclObjInterpProc, (ClientData) procPtr, TclProcDeleteProc);    /*     * 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.     */        procPtr->cmdPtr = (Command *) cmd;	    return TCL_OK;}/* *---------------------------------------------------------------------- * * TclCreateProc -- * *	Creates the data associated with a Tcl procedure definition. * * Results: *	Returns TCL_OK on success, along with a pointer to a Tcl *	procedure definition in procPtrPtr.  This definition should *	be freed by calling TclCleanupProc() when it is no longer *	needed.  Returns TCL_ERROR if anything goes wrong. * * Side effects: *	If anything goes wrong, this procedure returns an error *	message in the interpreter. * *---------------------------------------------------------------------- */intTclCreateProc(interp, nsPtr, procName, argsPtr, bodyPtr, procPtrPtr)    Tcl_Interp *interp;         /* interpreter containing proc */    Namespace *nsPtr;           /* namespace containing this proc */    char *procName;             /* unqualified name of this proc */    Tcl_Obj *argsPtr;           /* description of arguments */    Tcl_Obj *bodyPtr;           /* command body */    Proc **procPtrPtr;          /* returns:  pointer to proc data */{    Interp *iPtr = (Interp*)interp;    char **argArray = NULL;    register Proc *procPtr;    int i, length, result, numArgs;    char *args, *bytes, *p;    register CompiledLocal *localPtr;    Tcl_Obj *defPtr;    /*     * If the procedure's body object is shared because its string value is     * identical to, e.g., the body of another procedure, we must create a     * private copy for this procedure to use. Such sharing of procedure     * bodies is rare but can cause problems. A procedure body is compiled     * in a context that includes the number of compiler-allocated "slots"     * for local variables. Each formal parameter is given a local variable     * slot (the "procPtr->numCompiledLocals = numArgs" assignment     * below). This means that the same code can not be shared by two     * procedures that have a different number of arguments, even if their     * bodies are identical. Note that we don't use Tcl_DuplicateObj since     * we would not want any bytecode internal representation.     */    if (Tcl_IsShared(bodyPtr)) {        bytes = Tcl_GetStringFromObj(bodyPtr, &length);        bodyPtr = Tcl_NewStringObj(bytes, length);    }    /*     * Create and initialize a Proc structure for the procedure. Note that     * we initialize its cmdPtr field below after we've created the command     * for the procedure. We increment the ref count of the procedure's     * body object since there will be a reference to it in the Proc     * structure.     */        Tcl_IncrRefCount(bodyPtr);    procPtr = (Proc *) ckalloc(sizeof(Proc));    procPtr->iPtr = iPtr;    procPtr->refCount = 1;    procPtr->bodyPtr = bodyPtr;    procPtr->numArgs  = 0;	/* actual argument count is set below. */    procPtr->numCompiledLocals = 0;    procPtr->firstLocalPtr = NULL;    procPtr->lastLocalPtr = NULL;        /*     * Break up the argument list into argument specifiers, then process     * each argument specifier.     * THIS FAILS IF THE ARG LIST OBJECT'S STRING REP CONTAINS NULLS.     */    args = Tcl_GetStringFromObj(argsPtr, &length);    result = Tcl_SplitList(interp, args, &numArgs, &argArray);    if (result != TCL_OK) {	goto procError;    }        procPtr->numArgs = numArgs;    procPtr->numCompiledLocals = numArgs;    for (i = 0;  i < numArgs;  i++) {	int fieldCount, nameLength, valueLength;	char **fieldValues;	/*	 * Now divide the specifier up into name and default.	 */	result = Tcl_SplitList(interp, argArray[i], &fieldCount,		&fieldValues);	if (result != TCL_OK) {	    goto procError;	}	if (fieldCount > 2) {	    ckfree((char *) fieldValues);	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),		    "too many fields in argument specifier \"",		    argArray[i], "\"", (char *) NULL);	    goto procError;	}	if ((fieldCount == 0) || (*fieldValues[0] == 0)) {	    ckfree((char *) fieldValues);	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),		    "procedure \"", procName,		    "\" has argument with no name", (char *) NULL);	    goto procError;	}		nameLength = strlen(fieldValues[0]);	if (fieldCount == 2) {	    valueLength = strlen(fieldValues[1]);	} else {	    valueLength = 0;	}	/*	 * Check that the formal parameter name is a scalar.	 */	p = fieldValues[0];	while (*p != '\0') {	    if (*p == '(') {		char *q = p;		do {		    q++;		} while (*q != '\0');		q--;		if (*q == ')') { /* we have an array element */		    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),		            "procedure \"", procName,		            "\" has formal parameter \"", fieldValues[0],			    "\" that is an array element",			    (char *) NULL);		    ckfree((char *) fieldValues);		    goto procError;		}	    }	    p++;	}	/*	 * 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:    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 interp->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. */    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))) {	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;	    }

⌨️ 快捷键说明

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