tclresult.c
来自「tcl是工具命令语言」· C语言 代码 · 共 1,053 行 · 第 1/2 页
C
1,053 行
} /* * If we had to allocate a buffer from the heap, * free it now. */ if (args != static_list) { ckfree((void *)args); }#undef STATIC_LIST_SIZE}/* *---------------------------------------------------------------------- * * Tcl_AppendResult -- * * 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 given by the second and following arguments * (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_AppendResult TCL_VARARGS_DEF(Tcl_Interp *,arg1){ Tcl_Interp *interp; va_list argList; interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList); Tcl_AppendResultVA(interp, argList); va_end(argList);}/* *---------------------------------------------------------------------- * * Tcl_AppendElement -- * * Convert a string to a valid Tcl list element and append it to the * result (which is ostensibly a list). * * Results: * None. * * Side effects: * The result in the interpreter given by the first argument is * extended with a list element converted from string. A separator * space is added before the converted list element unless the current * result is empty, contains the single character "{", or ends in " {". * * If the string result is empty, the object result is moved to the * string result, then the object result is reset. * *---------------------------------------------------------------------- */voidTcl_AppendElement(interp, string) Tcl_Interp *interp; /* Interpreter whose result is to be * extended. */ CONST char *string; /* String to convert to list element and * add to result. */{ Interp *iPtr = (Interp *) interp; char *dst; int size; int flags; /* * 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(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); } /* * See how much space is needed, and grow the append buffer if * needed to accommodate the list element. */ size = Tcl_ScanElement(string, &flags) + 1; if ((iPtr->result != iPtr->appendResult) || (iPtr->appendResult[iPtr->appendUsed] != 0) || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) { SetupAppendBuffer(iPtr, size+iPtr->appendUsed); } /* * Convert the string into a list element and copy it to the * buffer that's forming, with a space separator if needed. */ dst = iPtr->appendResult + iPtr->appendUsed; if (TclNeedSpace(iPtr->appendResult, dst)) { iPtr->appendUsed++; *dst = ' '; dst++; } iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);}/* *---------------------------------------------------------------------- * * SetupAppendBuffer -- * * This procedure makes sure that there is an append buffer properly * initialized, if necessary, from the interpreter's result, and * that it has at least enough room to accommodate newSpace new * bytes of information. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */static voidSetupAppendBuffer(iPtr, newSpace) Interp *iPtr; /* Interpreter whose result is being set up. */ int newSpace; /* Make sure that at least this many bytes * of new information may be added. */{ int totalSpace; /* * Make the append buffer larger, if that's necessary, then copy the * result into the append buffer and make the append buffer the official * Tcl result. */ if (iPtr->result != iPtr->appendResult) { /* * If an oversized buffer was used recently, then free it up * so we go back to a smaller buffer. This avoids tying up * memory forever after a large operation. */ if (iPtr->appendAvl > 500) { ckfree(iPtr->appendResult); iPtr->appendResult = NULL; iPtr->appendAvl = 0; } iPtr->appendUsed = strlen(iPtr->result); } else if (iPtr->result[iPtr->appendUsed] != 0) { /* * Most likely someone has modified a result created by * Tcl_AppendResult et al. so that it has a different size. * Just recompute the size. */ iPtr->appendUsed = strlen(iPtr->result); } totalSpace = newSpace + iPtr->appendUsed; if (totalSpace >= iPtr->appendAvl) { char *new; if (totalSpace < 100) { totalSpace = 200; } else { totalSpace *= 2; } new = (char *) ckalloc((unsigned) totalSpace); strcpy(new, iPtr->result); if (iPtr->appendResult != NULL) { ckfree(iPtr->appendResult); } iPtr->appendResult = new; iPtr->appendAvl = totalSpace; } else if (iPtr->result != iPtr->appendResult) { strcpy(iPtr->appendResult, iPtr->result); } Tcl_FreeResult((Tcl_Interp *) iPtr); iPtr->result = iPtr->appendResult;}/* *---------------------------------------------------------------------- * * Tcl_FreeResult -- * * This procedure frees up the memory associated with an interpreter's * string result. It also resets the interpreter's result object. * Tcl_FreeResult is most commonly used when a procedure is about to * replace one result value with another. * * Results: * None. * * Side effects: * Frees the memory associated with interp's string result and sets * interp->freeProc to zero, but does not change interp->result or * clear error state. Resets interp's result object to an unshared * empty object. * *---------------------------------------------------------------------- */voidTcl_FreeResult(interp) register Tcl_Interp *interp; /* Interpreter for which to free result. */{ register Interp *iPtr = (Interp *) interp; 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; } ResetObjResult(iPtr);}/* *---------------------------------------------------------------------- * * Tcl_ResetResult -- * * This procedure resets both the interpreter's string and object * results. * * Results: * None. * * Side effects: * It resets the result object to an unshared empty object. It * then restores the interpreter's string result area to its default * initialized state, freeing up any memory that may have been * allocated. It also clears any error information for the interpreter. * *---------------------------------------------------------------------- */voidTcl_ResetResult(interp) register Tcl_Interp *interp; /* Interpreter for which to clear result. */{ register Interp *iPtr = (Interp *) interp; ResetObjResult(iPtr); 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; iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);}/* *---------------------------------------------------------------------- * * ResetObjResult -- * * Procedure used to reset an interpreter's Tcl result object. * * Results: * None. * * Side effects: * Resets the interpreter's result object to an unshared empty string * object with ref count one. It does not clear any error information * in the interpreter. * *---------------------------------------------------------------------- */static voidResetObjResult(iPtr) register Interp *iPtr; /* Points to the interpreter whose result * object should be reset. */{ register Tcl_Obj *objResultPtr = iPtr->objResultPtr; if (Tcl_IsShared(objResultPtr)) { TclDecrRefCount(objResultPtr); TclNewObj(objResultPtr); Tcl_IncrRefCount(objResultPtr); iPtr->objResultPtr = objResultPtr; } else { if ((objResultPtr->bytes != NULL) && (objResultPtr->bytes != tclEmptyStringRep)) { ckfree((char *) objResultPtr->bytes); } objResultPtr->bytes = tclEmptyStringRep; objResultPtr->length = 0; if ((objResultPtr->typePtr != NULL) && (objResultPtr->typePtr->freeIntRepProc != NULL)) { objResultPtr->typePtr->freeIntRepProc(objResultPtr); } objResultPtr->typePtr = (Tcl_ObjType *) NULL; }}/* *---------------------------------------------------------------------- * * Tcl_SetErrorCodeVA -- * * This procedure is called to record machine-readable information * about an error that is about to be returned. * * Results: * None. * * Side effects: * The errorCode global variable is modified to hold all of the * arguments to this procedure, in a list form with each argument * becoming one element of the list. A flag is set internally * to remember that errorCode has been set, so the variable doesn't * get set automatically when the error is returned. * *---------------------------------------------------------------------- */voidTcl_SetErrorCodeVA (interp, argList) Tcl_Interp *interp; /* Interpreter in which to access the errorCode * variable. */ va_list argList; /* Variable argument list. */{ char *string; int flags; Interp *iPtr = (Interp *) interp; /* * Scan through the arguments one at a time, appending them to * $errorCode as list elements. */ flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT; while (1) { string = va_arg(argList, char *); if (string == NULL) { break; } (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode", (char *) NULL, string, flags); flags |= TCL_APPEND_VALUE; } iPtr->flags |= ERROR_CODE_SET;}/* *---------------------------------------------------------------------- * * Tcl_SetErrorCode -- * * This procedure is called to record machine-readable information * about an error that is about to be returned. * * Results: * None. * * Side effects: * The errorCode global variable is modified to hold all of the * arguments to this procedure, in a list form with each argument * becoming one element of the list. A flag is set internally * to remember that errorCode has been set, so the variable doesn't * get set automatically when the error is returned. * *---------------------------------------------------------------------- */ /* VARARGS2 */voidTcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1){ Tcl_Interp *interp; va_list argList; /* * Scan through the arguments one at a time, appending them to * $errorCode as list elements. */ interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList); Tcl_SetErrorCodeVA(interp, argList); va_end(argList);}/* *---------------------------------------------------------------------- * * Tcl_SetObjErrorCode -- * * This procedure is called to record machine-readable information * about an error that is about to be returned. The caller should * build a list object up and pass it to this routine. * * Results: * None. * * Side effects: * The errorCode global variable is modified to be the new value. * A flag is set internally to remember that errorCode has been * set, so the variable doesn't get set automatically when the * error is returned. * *---------------------------------------------------------------------- */voidTcl_SetObjErrorCode(interp, errorObjPtr) Tcl_Interp *interp; Tcl_Obj *errorObjPtr;{ Interp *iPtr; iPtr = (Interp *) interp; Tcl_SetVar2Ex(interp, "errorCode", NULL, errorObjPtr, TCL_GLOBAL_ONLY); iPtr->flags |= ERROR_CODE_SET;}/* *------------------------------------------------------------------------- * * TclTransferResult -- * * Copy the result (and error information) from one interp to * another. Used when one interp has caused another interp to * evaluate a script and then wants to transfer the results back * to itself. * * This routine copies the string reps of the result and error * information. It does not simply increment the refcounts of the * result and error information objects themselves. * It is not legal to exchange objects between interps, because an * object may be kept alive by one interp, but have an internal rep * that is only valid while some other interp is alive. * * Results: * The target interp's result is set to a copy of the source interp's * result. The source's error information "$errorInfo" may be * appended to the target's error information and the source's error * code "$errorCode" may be stored in the target's error code. * * Side effects: * None. * *------------------------------------------------------------------------- */ voidTclTransferResult(sourceInterp, result, targetInterp) Tcl_Interp *sourceInterp; /* Interp whose result and error information * should be moved to the target interp. * After moving result, this interp's result * is reset. */ int result; /* TCL_OK if just the result should be copied, * TCL_ERROR if both the result and error * information should be copied. */ Tcl_Interp *targetInterp; /* Interp where result and error information * should be stored. If source and target * are the same, nothing is done. */{ Interp *iPtr; Tcl_Obj *objPtr; if (sourceInterp == targetInterp) { return; } if (result == TCL_ERROR) { /* * An error occurred, so transfer error information from the source * interpreter to the target interpreter. Setting the flags tells * the target interp that it has inherited a partial traceback * chain, not just a simple error message. */ iPtr = (Interp *) sourceInterp; if ((iPtr->flags & ERR_ALREADY_LOGGED) == 0) { Tcl_AddErrorInfo(sourceInterp, ""); } iPtr->flags &= ~(ERR_ALREADY_LOGGED); Tcl_ResetResult(targetInterp); objPtr = Tcl_GetVar2Ex(sourceInterp, "errorInfo", NULL, TCL_GLOBAL_ONLY); Tcl_SetVar2Ex(targetInterp, "errorInfo", NULL, objPtr, TCL_GLOBAL_ONLY); objPtr = Tcl_GetVar2Ex(sourceInterp, "errorCode", NULL, TCL_GLOBAL_ONLY); Tcl_SetVar2Ex(targetInterp, "errorCode", NULL, objPtr, TCL_GLOBAL_ONLY); ((Interp *) targetInterp)->flags |= (ERR_IN_PROGRESS | ERROR_CODE_SET); } ((Interp *) targetInterp)->returnCode = ((Interp *) sourceInterp)->returnCode; Tcl_SetObjResult(targetInterp, Tcl_GetObjResult(sourceInterp)); Tcl_ResetResult(sourceInterp);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?