tclresult.c
来自「tcl是工具命令语言」· C语言 代码 · 共 1,053 行 · 第 1/2 页
C
1,053 行
/* * tclResult.c -- * * This file contains code to manage the interpreter result. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclResult.c,v 1.5 2002/01/25 20:40:55 dgp Exp $ */#include "tclInt.h"/* * Function prototypes for local procedures in this file: */static void ResetObjResult _ANSI_ARGS_((Interp *iPtr));static void SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr, int newSpace));/* *---------------------------------------------------------------------- * * Tcl_SaveResult -- * * Takes a snapshot of the current result state of the interpreter. * The snapshot can be restored at any point by * Tcl_RestoreResult. Note that this routine does not * preserve the errorCode, errorInfo, or flags fields so it * should not be used if an error is in progress. * * Once a snapshot is saved, it must be restored by calling * Tcl_RestoreResult, or discarded by calling * Tcl_DiscardResult. * * Results: * None. * * Side effects: * Resets the interpreter result. * *---------------------------------------------------------------------- */voidTcl_SaveResult(interp, statePtr) Tcl_Interp *interp; /* Interpreter to save. */ Tcl_SavedResult *statePtr; /* Pointer to state structure. */{ Interp *iPtr = (Interp *) interp; /* * Move the result object into the save state. Note that we don't need * to change its refcount because we're moving it, not adding a new * reference. Put an empty object into the interpreter. */ statePtr->objResultPtr = iPtr->objResultPtr; iPtr->objResultPtr = Tcl_NewObj(); Tcl_IncrRefCount(iPtr->objResultPtr); /* * Save the string result. */ statePtr->freeProc = iPtr->freeProc; if (iPtr->result == iPtr->resultSpace) { /* * Copy the static string data out of the interp buffer. */ statePtr->result = statePtr->resultSpace; strcpy(statePtr->result, iPtr->result); statePtr->appendResult = NULL; } else if (iPtr->result == iPtr->appendResult) { /* * Move the append buffer out of the interp. */ statePtr->appendResult = iPtr->appendResult; statePtr->appendAvl = iPtr->appendAvl; statePtr->appendUsed = iPtr->appendUsed; statePtr->result = statePtr->appendResult; iPtr->appendResult = NULL; iPtr->appendAvl = 0; iPtr->appendUsed = 0; } else { /* * Move the dynamic or static string out of the interpreter. */ statePtr->result = iPtr->result; statePtr->appendResult = NULL; } iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; iPtr->freeProc = 0;}/* *---------------------------------------------------------------------- * * Tcl_RestoreResult -- * * Restores the state of the interpreter to a snapshot taken * by Tcl_SaveResult. After this call, the token for * the interpreter state is no longer valid. * * Results: * None. * * Side effects: * Restores the interpreter result. * *---------------------------------------------------------------------- */voidTcl_RestoreResult(interp, statePtr) Tcl_Interp* interp; /* Interpreter being restored. */ Tcl_SavedResult *statePtr; /* State returned by Tcl_SaveResult. */{ Interp *iPtr = (Interp *) interp; Tcl_ResetResult(interp); /* * Restore the string result. */ iPtr->freeProc = statePtr->freeProc; if (statePtr->result == statePtr->resultSpace) { /* * Copy the static string data into the interp buffer. */ iPtr->result = iPtr->resultSpace; strcpy(iPtr->result, statePtr->result); } else if (statePtr->result == statePtr->appendResult) { /* * Move the append buffer back into the interp. */ if (iPtr->appendResult != NULL) { ckfree((char *)iPtr->appendResult); } iPtr->appendResult = statePtr->appendResult; iPtr->appendAvl = statePtr->appendAvl; iPtr->appendUsed = statePtr->appendUsed; iPtr->result = iPtr->appendResult; } else { /* * Move the dynamic or static string back into the interpreter. */ iPtr->result = statePtr->result; } /* * Restore the object result. */ Tcl_DecrRefCount(iPtr->objResultPtr); iPtr->objResultPtr = statePtr->objResultPtr;}/* *---------------------------------------------------------------------- * * Tcl_DiscardResult -- * * Frees the memory associated with an interpreter snapshot * taken by Tcl_SaveResult. If the snapshot is not * restored, this procedure must be called to discard it, * or the memory will be lost. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */voidTcl_DiscardResult(statePtr) Tcl_SavedResult *statePtr; /* State returned by Tcl_SaveResult. */{ TclDecrRefCount(statePtr->objResultPtr); if (statePtr->result == statePtr->appendResult) { ckfree(statePtr->appendResult); } else if (statePtr->freeProc) { if ((statePtr->freeProc == TCL_DYNAMIC) || (statePtr->freeProc == (Tcl_FreeProc *) free)) { ckfree(statePtr->result); } else { (*statePtr->freeProc)(statePtr->result); } }}/* *---------------------------------------------------------------------- * * Tcl_SetResult -- * * Arrange for "string" to be the Tcl return value. * * Results: * None. * * Side effects: * interp->result is left pointing either to "string" (if "copy" is 0) * or to a copy of string. Also, the object result is reset. * *---------------------------------------------------------------------- */voidTcl_SetResult(interp, string, freeProc) Tcl_Interp *interp; /* Interpreter with which to associate the * return value. */ register char *string; /* Value to be returned. If NULL, the * result is set to an empty string. */ Tcl_FreeProc *freeProc; /* Gives information about the string: * TCL_STATIC, TCL_VOLATILE, or the address * of a Tcl_FreeProc such as free. */{ Interp *iPtr = (Interp *) interp; int length; register Tcl_FreeProc *oldFreeProc = iPtr->freeProc; char *oldResult = iPtr->result; if (string == NULL) { iPtr->resultSpace[0] = 0; iPtr->result = iPtr->resultSpace; iPtr->freeProc = 0; } else if (freeProc == TCL_VOLATILE) { length = strlen(string); if (length > TCL_RESULT_SIZE) { iPtr->result = (char *) ckalloc((unsigned) length+1); iPtr->freeProc = TCL_DYNAMIC; } else { iPtr->result = iPtr->resultSpace; iPtr->freeProc = 0; } strcpy(iPtr->result, string); } else { iPtr->result = string; iPtr->freeProc = freeProc; } /* * If the old result was dynamically-allocated, free it up. Do it * here, rather than at the beginning, in case the new result value * was part of the old result value. */ if (oldFreeProc != 0) { if ((oldFreeProc == TCL_DYNAMIC) || (oldFreeProc == (Tcl_FreeProc *) free)) { ckfree(oldResult); } else { (*oldFreeProc)(oldResult); } } /* * Reset the object result since we just set the string result. */ ResetObjResult(iPtr);}/* *---------------------------------------------------------------------- * * Tcl_GetStringResult -- * * Returns an interpreter's result value as a string. * * Results: * The interpreter's result as a string. * * Side effects: * If the string result is empty, the object result is moved to the * string result, then the object result is reset. * *---------------------------------------------------------------------- */CONST char *Tcl_GetStringResult(interp) register Tcl_Interp *interp; /* Interpreter whose result to return. */{ /* * If the string result is empty, move the object result to the * string result, then reset the object result. */ if (*(interp->result) == 0) { Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); } return interp->result;}/* *---------------------------------------------------------------------- * * Tcl_SetObjResult -- * * Arrange for objPtr to be an interpreter's result value. * * Results: * None. * * Side effects: * interp->objResultPtr is left pointing to the object referenced * by objPtr. The object's reference count is incremented since * there is now a new reference to it. The reference count for any * old objResultPtr value is decremented. Also, the string result * is reset. * *---------------------------------------------------------------------- */voidTcl_SetObjResult(interp, objPtr) Tcl_Interp *interp; /* Interpreter with which to associate the * return object value. */ register Tcl_Obj *objPtr; /* Tcl object to be returned. If NULL, the * obj result is made an empty string * object. */{ register Interp *iPtr = (Interp *) interp; register Tcl_Obj *oldObjResult = iPtr->objResultPtr; iPtr->objResultPtr = objPtr; Tcl_IncrRefCount(objPtr); /* since interp result is a reference */ /* * We wait until the end to release the old object result, in case * we are setting the result to itself. */ TclDecrRefCount(oldObjResult); /* * Reset the string result since we just set the result object. */ if (iPtr->freeProc != NULL) { if ((iPtr->freeProc == TCL_DYNAMIC) || (iPtr->freeProc == (Tcl_FreeProc *) free)) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; } iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0;}/* *---------------------------------------------------------------------- * * Tcl_GetObjResult -- * * Returns an interpreter's result value as a Tcl object. The object's * reference count is not modified; the caller must do that if it * needs to hold on to a long-term reference to it. * * Results: * The interpreter's result as an object. * * Side effects: * If the interpreter has a non-empty string result, the result object * is either empty or stale because some procedure set interp->result * directly. If so, the string result is moved to the result object * then the string result is reset. * *---------------------------------------------------------------------- */Tcl_Obj *Tcl_GetObjResult(interp) Tcl_Interp *interp; /* Interpreter whose result to return. */{ register Interp *iPtr = (Interp *) interp; Tcl_Obj *objResultPtr; int length; /* * If the string result is non-empty, move the string result to the * object result, then reset the string result. */ if (*(iPtr->result) != 0) { ResetObjResult(iPtr); objResultPtr = iPtr->objResultPtr; length = strlen(iPtr->result); TclInitStringRep(objResultPtr, iPtr->result, length); if (iPtr->freeProc != NULL) { if ((iPtr->freeProc == TCL_DYNAMIC) || (iPtr->freeProc == (Tcl_FreeProc *) free)) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; } iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; } return iPtr->objResultPtr;}/* *---------------------------------------------------------------------- * * Tcl_AppendResultVA -- * * Append a variable number of strings onto the interpreter's string * result. * * Results: * None. * * Side effects: * The result of the interpreter given by the first argument is * extended by the strings in the va_list (up to a terminating NULL * argument). * * If the string result is empty, the object result is moved to the * string result, then the object result is reset. * *---------------------------------------------------------------------- */voidTcl_AppendResultVA (interp, argList) Tcl_Interp *interp; /* Interpreter with which to associate the * return value. */ va_list argList; /* Variable argument list. */{#define STATIC_LIST_SIZE 16 Interp *iPtr = (Interp *) interp; char *string, *static_list[STATIC_LIST_SIZE]; char **args = static_list; int nargs_space = STATIC_LIST_SIZE; int nargs, newSpace, i; /* * If the string result is empty, move the object result to the * string result, then reset the object result. */ if (*(iPtr->result) == 0) { Tcl_SetResult((Tcl_Interp *) iPtr, TclGetString(Tcl_GetObjResult((Tcl_Interp *) iPtr)), TCL_VOLATILE); } /* * Scan through all the arguments to see how much space is needed * and save pointers to the arguments in the args array, * reallocating as necessary. */ nargs = 0; newSpace = 0; while (1) { string = va_arg(argList, char *); if (string == NULL) { break; } if (nargs >= nargs_space) { /* * Expand the args buffer */ nargs_space += STATIC_LIST_SIZE; if (args == static_list) { args = (void *)ckalloc(nargs_space * sizeof(char *)); for (i = 0; i < nargs; ++i) { args[i] = static_list[i]; } } else { args = (void *)ckrealloc((void *)args, nargs_space * sizeof(char *)); } } newSpace += strlen(string); args[nargs++] = string; } /* * If the append buffer isn't already setup and large enough to hold * the new data, set it up. */ if ((iPtr->result != iPtr->appendResult) || (iPtr->appendResult[iPtr->appendUsed] != 0) || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) { SetupAppendBuffer(iPtr, newSpace); } /* * Now go through all the argument strings again, copying them into the * buffer. */ for (i = 0; i < nargs; ++i) { string = args[i]; strcpy(iPtr->appendResult + iPtr->appendUsed, string); iPtr->appendUsed += strlen(string);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?