diff options
Diffstat (limited to 'generic/tclResult.c')
| -rw-r--r-- | generic/tclResult.c | 1272 |
1 files changed, 355 insertions, 917 deletions
diff --git a/generic/tclResult.c b/generic/tclResult.c index 7b58d44..6dbdd90 100644 --- a/generic/tclResult.c +++ b/generic/tclResult.c @@ -1,207 +1,39 @@ -/* +/* * 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. + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* - * Indices of the standard return options dictionary keys. - */ - -enum returnKeys { - KEY_CODE, KEY_ERRORCODE, KEY_ERRORINFO, KEY_ERRORLINE, - KEY_LEVEL, KEY_OPTIONS, KEY_LAST -}; - -/* - * Function prototypes for local functions in this file: + * Function prototypes for local procedures in this file: */ -static Tcl_Obj ** GetKeys(void); -static void ReleaseKeys(ClientData clientData); -static void ResetObjResult(Interp *iPtr); -static void SetupAppendBuffer(Interp *iPtr, int newSpace); +static void ResetObjResult _ANSI_ARGS_((Interp *iPtr)); +static void SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr, + int newSpace)); -/* - * This structure is used to take a snapshot of the interpreter state in - * Tcl_SaveInterpState. You can snapshot the state, execute a command, and - * then back up to the result or the error that was previously in progress. - */ - -typedef struct InterpState { - int status; /* return code status */ - int flags; /* Each remaining field saves the */ - int returnLevel; /* corresponding field of the Interp */ - int returnCode; /* struct. These fields taken together are */ - Tcl_Obj *errorInfo; /* the "state" of the interp. */ - Tcl_Obj *errorCode; - Tcl_Obj *returnOpts; - Tcl_Obj *objResult; -} InterpState; - -/* - *---------------------------------------------------------------------- - * - * Tcl_SaveInterpState -- - * - * Fills a token with a snapshot of the current state of the interpreter. - * The snapshot can be restored at any point by TclRestoreInterpState. - * - * The token returned must be eventally passed to one of the routines - * TclRestoreInterpState or TclDiscardInterpState, or there will be a - * memory leak. - * - * Results: - * Returns a token representing the interp state. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tcl_InterpState -Tcl_SaveInterpState( - Tcl_Interp *interp, /* Interpreter's state to be saved */ - int status) /* status code for current operation */ -{ - Interp *iPtr = (Interp *)interp; - InterpState *statePtr = (InterpState *)ckalloc(sizeof(InterpState)); - - statePtr->status = status; - statePtr->flags = iPtr->flags & ERR_ALREADY_LOGGED; - statePtr->returnLevel = iPtr->returnLevel; - statePtr->returnCode = iPtr->returnCode; - statePtr->errorInfo = iPtr->errorInfo; - if (statePtr->errorInfo) { - Tcl_IncrRefCount(statePtr->errorInfo); - } - statePtr->errorCode = iPtr->errorCode; - if (statePtr->errorCode) { - Tcl_IncrRefCount(statePtr->errorCode); - } - statePtr->returnOpts = iPtr->returnOpts; - if (statePtr->returnOpts) { - Tcl_IncrRefCount(statePtr->returnOpts); - } - statePtr->objResult = Tcl_GetObjResult(interp); - Tcl_IncrRefCount(statePtr->objResult); - return (Tcl_InterpState) statePtr; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_RestoreInterpState -- - * - * Accepts an interp and a token previously returned by - * Tcl_SaveInterpState. Restore the state of the interp to what it was at - * the time of the Tcl_SaveInterpState call. - * - * Results: - * Returns the status value originally passed in to Tcl_SaveInterpState. - * - * Side effects: - * Restores the interp state and frees memory held by token. - * - *---------------------------------------------------------------------- - */ - -int -Tcl_RestoreInterpState( - Tcl_Interp *interp, /* Interpreter's state to be restored. */ - Tcl_InterpState state) /* Saved interpreter state. */ -{ - Interp *iPtr = (Interp *)interp; - InterpState *statePtr = (InterpState *)state; - int status = statePtr->status; - - iPtr->flags &= ~ERR_ALREADY_LOGGED; - iPtr->flags |= (statePtr->flags & ERR_ALREADY_LOGGED); - - iPtr->returnLevel = statePtr->returnLevel; - iPtr->returnCode = statePtr->returnCode; - if (iPtr->errorInfo) { - Tcl_DecrRefCount(iPtr->errorInfo); - } - iPtr->errorInfo = statePtr->errorInfo; - if (iPtr->errorInfo) { - Tcl_IncrRefCount(iPtr->errorInfo); - } - if (iPtr->errorCode) { - Tcl_DecrRefCount(iPtr->errorCode); - } - iPtr->errorCode = statePtr->errorCode; - if (iPtr->errorCode) { - Tcl_IncrRefCount(iPtr->errorCode); - } - if (iPtr->returnOpts) { - Tcl_DecrRefCount(iPtr->returnOpts); - } - iPtr->returnOpts = statePtr->returnOpts; - if (iPtr->returnOpts) { - Tcl_IncrRefCount(iPtr->returnOpts); - } - Tcl_SetObjResult(interp, statePtr->objResult); - Tcl_DiscardInterpState(state); - return status; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_DiscardInterpState -- - * - * Accepts a token previously returned by Tcl_SaveInterpState. Frees the - * memory it uses. - * - * Results: - * None. - * - * Side effects: - * Frees memory. - * - *---------------------------------------------------------------------- - */ - -void -Tcl_DiscardInterpState( - Tcl_InterpState state) /* saved interpreter state */ -{ - InterpState *statePtr = (InterpState *)state; - - if (statePtr->errorInfo) { - Tcl_DecrRefCount(statePtr->errorInfo); - } - if (statePtr->errorCode) { - Tcl_DecrRefCount(statePtr->errorCode); - } - if (statePtr->returnOpts) { - Tcl_DecrRefCount(statePtr->returnOpts); - } - Tcl_DecrRefCount(statePtr->objResult); - ckfree((char *) statePtr); -} /* *---------------------------------------------------------------------- * * 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. + * 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. + * Once a snapshot is saved, it must be restored by calling + * Tcl_RestoreResult, or discarded by calling + * Tcl_DiscardResult. * * Results: * None. @@ -213,24 +45,24 @@ Tcl_DiscardInterpState( */ void -Tcl_SaveResult( - Tcl_Interp *interp, /* Interpreter to save. */ - Tcl_SavedResult *statePtr) /* Pointer to state structure. */ +Tcl_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. + * 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); + iPtr->objResultPtr = Tcl_NewObj(); + Tcl_IncrRefCount(iPtr->objResultPtr); /* - * Save the string result. + * Save the string result. */ statePtr->freeProc = iPtr->freeProc; @@ -273,23 +105,23 @@ Tcl_SaveResult( * * 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. + * 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. + * None. * * Side effects: - * Restores the interpreter result. + * Restores the interpreter result. * *---------------------------------------------------------------------- */ void -Tcl_RestoreResult( - Tcl_Interp *interp, /* Interpreter being restored. */ - Tcl_SavedResult *statePtr) /* State returned by Tcl_SaveResult. */ +Tcl_RestoreResult(interp, statePtr) + Tcl_Interp* interp; /* Interpreter being restored. */ + Tcl_SavedResult *statePtr; /* State returned by Tcl_SaveResult. */ { Interp *iPtr = (Interp *) interp; @@ -313,7 +145,7 @@ Tcl_RestoreResult( */ if (iPtr->appendResult != NULL) { - ckfree((char *) iPtr->appendResult); + ckfree((char *)iPtr->appendResult); } iPtr->appendResult = statePtr->appendResult; @@ -341,22 +173,23 @@ Tcl_RestoreResult( * * Tcl_DiscardResult -- * - * Frees the memory associated with an interpreter snapshot taken by - * Tcl_SaveResult. If the snapshot is not restored, this function must be - * called to discard it, or the memory will be lost. + * 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. + * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ void -Tcl_DiscardResult( - Tcl_SavedResult *statePtr) /* State returned by Tcl_SaveResult. */ +Tcl_DiscardResult(statePtr) + Tcl_SavedResult *statePtr; /* State returned by Tcl_SaveResult. */ { TclDecrRefCount(statePtr->objResultPtr); @@ -376,39 +209,39 @@ Tcl_DiscardResult( * * Tcl_SetResult -- * - * Arrange for "result" to be the Tcl return value. + * Arrange for "string" to be the Tcl return value. * * Results: * None. * * Side effects: - * interp->result is left pointing either to "result" or to a copy of it. - * Also, the object result is reset. + * interp->result is left pointing either to "string" (if "copy" is 0) + * or to a copy of string. Also, the object result is reset. * *---------------------------------------------------------------------- */ void -Tcl_SetResult( - Tcl_Interp *interp, /* Interpreter with which to associate the +Tcl_SetResult(interp, string, freeProc) + Tcl_Interp *interp; /* Interpreter with which to associate the * return value. */ - register char *result, /* 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. */ + 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 (result == NULL) { + if (string == NULL) { iPtr->resultSpace[0] = 0; iPtr->result = iPtr->resultSpace; iPtr->freeProc = 0; } else if (freeProc == TCL_VOLATILE) { - length = strlen(result); + length = strlen(string); if (length > TCL_RESULT_SIZE) { iPtr->result = (char *) ckalloc((unsigned) length+1); iPtr->freeProc = TCL_DYNAMIC; @@ -416,16 +249,16 @@ Tcl_SetResult( iPtr->result = iPtr->resultSpace; iPtr->freeProc = 0; } - strcpy(iPtr->result, result); + strcpy(iPtr->result, string); } else { - iPtr->result = result; + 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 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) { @@ -461,17 +294,17 @@ Tcl_SetResult( */ CONST char * -Tcl_GetStringResult( - register Tcl_Interp *interp)/* Interpreter whose result to return. */ +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 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); + TCL_VOLATILE); } return interp->result; } @@ -487,20 +320,22 @@ Tcl_GetStringResult( * 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. + * 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. * *---------------------------------------------------------------------- */ void -Tcl_SetObjResult( - Tcl_Interp *interp, /* Interpreter with which to associate the +Tcl_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 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; @@ -509,10 +344,10 @@ Tcl_SetObjResult( 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. + * We wait until the end to release the old object result, in case + * we are setting the result to itself. */ - + TclDecrRefCount(oldObjResult); /* @@ -537,41 +372,41 @@ Tcl_SetObjResult( * 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. + * 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 function set interp->result - * directly. If so, the string result is moved to the result object then - * the string result is reset. + * 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( - Tcl_Interp *interp) /* Interpreter whose result to return. */ +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 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) { ckfree(iPtr->result); @@ -591,51 +426,110 @@ Tcl_GetObjResult( * * Tcl_AppendResultVA -- * - * Append a variable number of strings onto the interpreter's result. + * 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). + * 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 non-empty, the object result forced to be a - * duplicate of it first. There will be a string result afterwards. + * If the string result is empty, the object result is moved to the + * string result, then the object result is reset. * *---------------------------------------------------------------------- */ void -Tcl_AppendResultVA( - Tcl_Interp *interp, /* Interpreter with which to associate the +Tcl_AppendResultVA (interp, argList) + Tcl_Interp *interp; /* Interpreter with which to associate the * return value. */ - va_list argList) /* Variable argument list. */ + va_list argList; /* Variable argument list. */ { - Tcl_Obj *objPtr = Tcl_GetObjResult(interp); +#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 (Tcl_IsShared(objPtr)) { - objPtr = Tcl_DuplicateObj(objPtr); + 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; } - Tcl_AppendStringsToObjVA(objPtr, argList); - Tcl_SetObjResult(interp, objPtr); /* - * Strictly we should call Tcl_GetStringResult(interp) here to make sure - * that interp->result is correct according to the old contract, but that - * makes the performance of much code (e.g. in Tk) absolutely awful. So we - * leave it out; code that really wants interp->result can just insert the - * calls to Tcl_GetStringResult() itself. [Patch 1041072 discussion] + * If the append buffer isn't already setup and large enough to hold + * the new data, set it up. */ -#ifdef USE_DIRECT_INTERP_RESULT_ACCESS + if ((iPtr->result != iPtr->appendResult) + || (iPtr->appendResult[iPtr->appendUsed] != 0) + || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) { + SetupAppendBuffer(iPtr, newSpace); + } + /* - * Ensure that the interp->result is legal so old Tcl 7.* code still - * works. There's still embarrasingly much of it about... + * Now go through all the argument strings again, copying them into the + * buffer. */ - (void) Tcl_GetStringResult(interp); -#endif /* USE_DIRECT_INTERP_RESULT_ACCESS */ + for (i = 0; i < nargs; ++i) { + string = args[i]; + strcpy(iPtr->appendResult + iPtr->appendUsed, string); + iPtr->appendUsed += strlen(string); + } + + /* + * If we had to allocate a buffer from the heap, + * free it now. + */ + + if (args != static_list) { + ckfree((void *)args); + } +#undef STATIC_LIST_SIZE } /* @@ -643,29 +537,30 @@ Tcl_AppendResultVA( * * Tcl_AppendResult -- * - * Append a variable number of strings onto the interpreter's result. + * 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). + * 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 non-empty, the object result forced to be a - * duplicate of it first. There will be a string result afterwards. + * If the string result is empty, the object result is moved to the + * string result, then the object result is reset. * *---------------------------------------------------------------------- */ void -Tcl_AppendResult( - Tcl_Interp *interp, ...) +Tcl_AppendResult TCL_VARARGS_DEF(Tcl_Interp *,arg1) { + Tcl_Interp *interp; va_list argList; - va_start(argList, interp); + interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList); Tcl_AppendResultVA(interp, argList); va_end(argList); } @@ -682,10 +577,10 @@ Tcl_AppendResult( * 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 " {". + * 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. @@ -694,11 +589,11 @@ Tcl_AppendResult( */ void -Tcl_AppendElement( - Tcl_Interp *interp, /* Interpreter whose result is to be +Tcl_AppendElement(interp, string) + Tcl_Interp *interp; /* Interpreter whose result is to be * extended. */ - CONST char *element) /* String to convert to list element and add - * to result. */ + CONST char *string; /* String to convert to list element and + * add to result. */ { Interp *iPtr = (Interp *) interp; char *dst; @@ -706,27 +601,30 @@ Tcl_AppendElement( int flags; /* - * If the string result is empty, move the object result to the string - * result, then reset the object result. + * If the string result is empty, move the object result to the + * string result, then reset the object result. */ - (void) Tcl_GetStringResult(interp); + 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. + * See how much space is needed, and grow the append buffer if + * needed to accommodate the list element. */ - size = Tcl_ScanElement(element, &flags) + 1; + 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); + 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. + * 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; @@ -734,16 +632,8 @@ Tcl_AppendElement( iPtr->appendUsed++; *dst = ' '; dst++; - - /* - * If we need a space to separate this element from preceding stuff, - * then this element will not lead a list, and need not have it's - * leading '#' quoted. - */ - - flags |= TCL_DONT_QUOTE_HASH; } - iPtr->appendUsed += Tcl_ConvertElement(element, dst, flags); + iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags); } /* @@ -751,10 +641,10 @@ Tcl_AppendElement( * * SetupAppendBuffer -- * - * This function 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. + * 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. @@ -766,10 +656,10 @@ Tcl_AppendElement( */ static void -SetupAppendBuffer( - 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. */ +SetupAppendBuffer(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; @@ -781,9 +671,9 @@ SetupAppendBuffer( 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 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) { @@ -795,13 +685,13 @@ SetupAppendBuffer( } 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. + * 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; @@ -821,7 +711,7 @@ SetupAppendBuffer( } else if (iPtr->result != iPtr->appendResult) { strcpy(iPtr->appendResult, iPtr->result); } - + Tcl_FreeResult((Tcl_Interp *) iPtr); iPtr->result = iPtr->appendResult; } @@ -831,9 +721,9 @@ SetupAppendBuffer( * * Tcl_FreeResult -- * - * This function frees up the memory associated with an interpreter's + * 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 function is about to + * Tcl_FreeResult is most commonly used when a procedure is about to * replace one result value with another. * * Results: @@ -841,19 +731,19 @@ SetupAppendBuffer( * * 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. + * interp->freeProc to zero, but does not change interp->result or + * clear error state. Resets interp's result object to an unshared + * empty object. * *---------------------------------------------------------------------- */ void -Tcl_FreeResult( - register Tcl_Interp *interp)/* Interpreter for which to free result. */ +Tcl_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) { ckfree(iPtr->result); @@ -862,7 +752,7 @@ Tcl_FreeResult( } iPtr->freeProc = 0; } - + ResetObjResult(iPtr); } @@ -871,23 +761,24 @@ Tcl_FreeResult( * * Tcl_ResetResult -- * - * This function resets both the interpreter's string and object results. + * 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. + * 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. * *---------------------------------------------------------------------- */ void -Tcl_ResetResult( - register Tcl_Interp *interp)/* Interpreter for which to clear result. */ +Tcl_ResetResult(interp) + register Tcl_Interp *interp; /* Interpreter for which to clear result. */ { register Interp *iPtr = (Interp *) interp; @@ -902,31 +793,7 @@ Tcl_ResetResult( } iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; - if (iPtr->errorCode) { - /* Legacy support */ - if (iPtr->flags & ERR_LEGACY_COPY) { - Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL, - iPtr->errorCode, TCL_GLOBAL_ONLY); - } - Tcl_DecrRefCount(iPtr->errorCode); - iPtr->errorCode = NULL; - } - if (iPtr->errorInfo) { - /* Legacy support */ - if (iPtr->flags & ERR_LEGACY_COPY) { - Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, - iPtr->errorInfo, TCL_GLOBAL_ONLY); - } - Tcl_DecrRefCount(iPtr->errorInfo); - iPtr->errorInfo = NULL; - } - iPtr->returnLevel = 1; - iPtr->returnCode = TCL_OK; - if (iPtr->returnOpts) { - Tcl_DecrRefCount(iPtr->returnOpts); - iPtr->returnOpts = NULL; - } - iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_LEGACY_COPY); + iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET); } /* @@ -934,22 +801,22 @@ Tcl_ResetResult( * * ResetObjResult -- * - * Function used to reset an interpreter's Tcl result object. + * 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. + * object with ref count one. It does not clear any error information + * in the interpreter. * *---------------------------------------------------------------------- */ static void -ResetObjResult( - register Interp *iPtr) /* Points to the interpreter whose result +ResetObjResult(iPtr) + register Interp *iPtr; /* Points to the interpreter whose result * object should be reset. */ { register Tcl_Obj *objResultPtr = iPtr->objResultPtr; @@ -960,15 +827,17 @@ ResetObjResult( Tcl_IncrRefCount(objResultPtr); iPtr->objResultPtr = objResultPtr; } else { - if (objResultPtr->bytes != tclEmptyStringRep) { - if (objResultPtr->bytes) { - ckfree((char *) objResultPtr->bytes); - } - objResultPtr->bytes = tclEmptyStringRep; - objResultPtr->length = 0; + if ((objResultPtr->bytes != NULL) + && (objResultPtr->bytes != tclEmptyStringRep)) { + ckfree((char *) objResultPtr->bytes); } - TclFreeIntRep(objResultPtr); - objResultPtr->typePtr = NULL; + objResultPtr->bytes = tclEmptyStringRep; + objResultPtr->length = 0; + if ((objResultPtr->typePtr != NULL) + && (objResultPtr->typePtr->freeIntRepProc != NULL)) { + objResultPtr->typePtr->freeIntRepProc(objResultPtr); + } + objResultPtr->typePtr = (Tcl_ObjType *) NULL; } } @@ -977,40 +846,48 @@ ResetObjResult( * * Tcl_SetErrorCodeVA -- * - * This function is called to record machine-readable information about - * an error that is about to be returned. + * This procedure is called to record machine-readable information + * about an error that is about to be returned. * * Results: * None. * * Side effects: - * The errorCode field of the interp is modified to hold all of the - * arguments to this function, in a list form with each argument becoming - * one element of the list. + * 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. * *---------------------------------------------------------------------- */ void -Tcl_SetErrorCodeVA( - Tcl_Interp *interp, /* Interpreter in which to set errorCode */ - va_list argList) /* Variable argument list. */ +Tcl_SetErrorCodeVA (interp, argList) + Tcl_Interp *interp; /* Interpreter in which to access the errorCode + * variable. */ + va_list argList; /* Variable argument list. */ { - Tcl_Obj *errorObj = Tcl_NewObj(); + char *string; + int flags; + Interp *iPtr = (Interp *) interp; /* - * Scan through the arguments one at a time, appending them to the - * errorCode field as list elements. + * Scan through the arguments one at a time, appending them to + * $errorCode as list elements. */ + flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT; while (1) { - char *elem = va_arg(argList, char *); - if (elem == NULL) { + string = va_arg(argList, char *); + if (string == NULL) { break; } - Tcl_ListObjAppendElement(NULL, errorObj, Tcl_NewStringObj(elem, -1)); + (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode", + (char *) NULL, string, flags); + flags |= TCL_APPEND_VALUE; } - Tcl_SetObjErrorCode(interp, errorObj); + iPtr->flags |= ERROR_CODE_SET; } /* @@ -1018,32 +895,34 @@ Tcl_SetErrorCodeVA( * * Tcl_SetErrorCode -- * - * This function is called to record machine-readable information about - * an error that is about to be returned. + * This procedure is called to record machine-readable information + * about an error that is about to be returned. * * Results: * None. * * Side effects: - * The errorCode field of the interp is modified to hold all of the - * arguments to this function, in a list form with each argument becoming - * one element of the list. + * 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 */ void -Tcl_SetErrorCode( - Tcl_Interp *interp, ...) +Tcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1) { + Tcl_Interp *interp; va_list argList; /* - * Scan through the arguments one at a time, appending them to the - * errorCode field as list elements. + * Scan through the arguments one at a time, appending them to + * $errorCode as list elements. */ - va_start(argList, interp); + interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList); Tcl_SetErrorCodeVA(interp, argList); va_end(argList); } @@ -1053,484 +932,32 @@ Tcl_SetErrorCode( * * Tcl_SetObjErrorCode -- * - * This function 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. + * 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 field of the interp is set to the new value. + * 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. * *---------------------------------------------------------------------- */ void -Tcl_SetObjErrorCode( - Tcl_Interp *interp, - Tcl_Obj *errorObjPtr) -{ - Interp *iPtr = (Interp *) interp; - - if (iPtr->errorCode) { - Tcl_DecrRefCount(iPtr->errorCode); - } - iPtr->errorCode = errorObjPtr; - Tcl_IncrRefCount(iPtr->errorCode); -} - -/* - *---------------------------------------------------------------------- - * - * GetKeys -- - * - * Returns a Tcl_Obj * array of the standard keys used in the return - * options dictionary. - * - * Broadly sharing one copy of these key values helps with both memory - * efficiency and dictionary lookup times. - * - * Results: - * A Tcl_Obj * array. - * - * Side effects: - * First time called in a thread, creates the keys (allocating memory) - * and arranges for their cleanup at thread exit. - * - *---------------------------------------------------------------------- - */ - -static Tcl_Obj ** -GetKeys(void) +Tcl_SetObjErrorCode(interp, errorObjPtr) + Tcl_Interp *interp; + Tcl_Obj *errorObjPtr; { - static Tcl_ThreadDataKey returnKeysKey; - Tcl_Obj **keys = Tcl_GetThreadData(&returnKeysKey, - (int) (KEY_LAST * sizeof(Tcl_Obj *))); - - if (keys[0] == NULL) { - /* - * First call in this thread, create the keys... - */ - - int i; - - TclNewLiteralStringObj(keys[KEY_CODE], "-code"); - TclNewLiteralStringObj(keys[KEY_ERRORCODE], "-errorcode"); - TclNewLiteralStringObj(keys[KEY_ERRORINFO], "-errorinfo"); - TclNewLiteralStringObj(keys[KEY_ERRORLINE], "-errorline"); - TclNewLiteralStringObj(keys[KEY_LEVEL], "-level"); - TclNewLiteralStringObj(keys[KEY_OPTIONS], "-options"); - - for (i = KEY_CODE; i < KEY_LAST; i++) { - Tcl_IncrRefCount(keys[i]); - } - - /* - * ... and arrange for their clenaup. - */ - - Tcl_CreateThreadExitHandler(ReleaseKeys, (ClientData) keys); - } - return keys; -} - -/* - *---------------------------------------------------------------------- - * - * ReleaseKeys -- - * - * Called as a thread exit handler to cleanup return options dictionary - * keys. - * - * Results: - * None. - * - * Side effects: - * Frees memory. - * - *---------------------------------------------------------------------- - */ - -static void -ReleaseKeys( - ClientData clientData) -{ - Tcl_Obj **keys = (Tcl_Obj **)clientData; - int i; - - for (i = KEY_CODE; i < KEY_LAST; i++) { - Tcl_DecrRefCount(keys[i]); - keys[i] = NULL; - } -} - -/* - *---------------------------------------------------------------------- - * - * TclProcessReturn -- - * - * Does the work of the [return] command based on the code, level, and - * returnOpts arguments. Note that the code argument must agree with the - * -code entry in returnOpts and the level argument must agree with the - * -level entry in returnOpts, as is the case for values returned from - * TclMergeReturnOptions. - * - * Results: - * Returns the return code the [return] command should return. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TclProcessReturn( - Tcl_Interp *interp, - int code, - int level, - Tcl_Obj *returnOpts) -{ - Interp *iPtr = (Interp *) interp; - Tcl_Obj *valuePtr; - Tcl_Obj **keys = GetKeys(); - - /* - * Store the merged return options. - */ - - if (iPtr->returnOpts != returnOpts) { - if (iPtr->returnOpts) { - Tcl_DecrRefCount(iPtr->returnOpts); - } - iPtr->returnOpts = returnOpts; - Tcl_IncrRefCount(iPtr->returnOpts); - } - - if (code == TCL_ERROR) { - if (iPtr->errorInfo) { - Tcl_DecrRefCount(iPtr->errorInfo); - iPtr->errorInfo = NULL; - } - Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORINFO], &valuePtr); - if (valuePtr != NULL) { - int infoLen; - - (void) TclGetStringFromObj(valuePtr, &infoLen); - if (infoLen) { - iPtr->errorInfo = valuePtr; - Tcl_IncrRefCount(iPtr->errorInfo); - iPtr->flags |= ERR_ALREADY_LOGGED; - } - } - Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORCODE], &valuePtr); - if (valuePtr != NULL) { - Tcl_SetObjErrorCode(interp, valuePtr); - } else { - Tcl_SetErrorCode(interp, "NONE", NULL); - } - - Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORLINE], &valuePtr); - if (valuePtr != NULL) { - TclGetIntFromObj(NULL, valuePtr, &iPtr->errorLine); - } - } - if (level != 0) { - iPtr->returnLevel = level; - iPtr->returnCode = code; - return TCL_RETURN; - } - if (code == TCL_ERROR) { - iPtr->flags |= ERR_LEGACY_COPY; - } - return code; -} - -/* - *---------------------------------------------------------------------- - * - * TclMergeReturnOptions -- - * - * Parses, checks, and stores the options to the [return] command. - * - * Results: - * Returns TCL_ERROR is any of the option values are invalid. Otherwise, - * returns TCL_OK, and writes the returnOpts, code, and level values to - * the pointers provided. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TclMergeReturnOptions( - Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[], /* Argument objects. */ - Tcl_Obj **optionsPtrPtr, /* If not NULL, points to space for a (Tcl_Obj - * *) where the pointer to the merged return - * options dictionary should be written */ - int *codePtr, /* If not NULL, points to space where the - * -code value should be written */ - int *levelPtr) /* If not NULL, points to space where the - * -level value should be written */ -{ - int code=TCL_OK; - int level = 1; - Tcl_Obj *valuePtr; - Tcl_Obj *returnOpts = Tcl_NewObj(); - Tcl_Obj **keys = GetKeys(); - - for (; objc > 1; objv += 2, objc -= 2) { - int optLen; - CONST char *opt = TclGetStringFromObj(objv[0], &optLen); - int compareLen; - CONST char *compare = - TclGetStringFromObj(keys[KEY_OPTIONS], &compareLen); - - if ((optLen == compareLen) && (strcmp(opt, compare) == 0)) { - Tcl_DictSearch search; - int done = 0; - Tcl_Obj *keyPtr; - Tcl_Obj *dict = objv[1]; - - nestedOptions: - if (TCL_ERROR == Tcl_DictObjFirst(NULL, dict, &search, - &keyPtr, &valuePtr, &done)) { - /* - * Value is not a legal dictionary. - */ - - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad ", compare, - " value: expected dictionary but got \"", - TclGetString(objv[1]), "\"", NULL); - goto error; - } - - while (!done) { - Tcl_DictObjPut(NULL, returnOpts, keyPtr, valuePtr); - Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done); - } - - Tcl_DictObjGet(NULL, returnOpts, keys[KEY_OPTIONS], &valuePtr); - if (valuePtr != NULL) { - dict = valuePtr; - Tcl_DictObjRemove(NULL, returnOpts, keys[KEY_OPTIONS]); - goto nestedOptions; - } - - } else { - Tcl_DictObjPut(NULL, returnOpts, objv[0], objv[1]); - } - } - - /* - * Check for bogus -code value. - */ - - Tcl_DictObjGet(NULL, returnOpts, keys[KEY_CODE], &valuePtr); - if ((valuePtr != NULL) - && (TCL_ERROR == TclGetIntFromObj(NULL, valuePtr, &code))) { - static CONST char *returnCodes[] = { - "ok", "error", "return", "break", "continue", NULL - }; - - if (TCL_ERROR == Tcl_GetIndexFromObj(NULL, valuePtr, returnCodes, - NULL, TCL_EXACT, &code)) { - /* - * Value is not a legal return code. - */ - - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad completion code \"", - TclGetString(valuePtr), - "\": must be ok, error, return, break, " - "continue, or an integer", NULL); - goto error; - } - } - if (valuePtr != NULL) { - Tcl_DictObjRemove(NULL, returnOpts, keys[KEY_CODE]); - } - - /* - * Check for bogus -level value. - */ - - Tcl_DictObjGet(NULL, returnOpts, keys[KEY_LEVEL], &valuePtr); - if (valuePtr != NULL) { - if ((TCL_ERROR == TclGetIntFromObj(NULL, valuePtr, &level)) - || (level < 0)) { - /* - * Value is not a legal level. - */ - - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad -level value: " - "expected non-negative integer but got \"", - TclGetString(valuePtr), "\"", NULL); - goto error; - } - Tcl_DictObjRemove(NULL, returnOpts, keys[KEY_LEVEL]); - } - - /* - * Check for bogus -errorcode value. - */ - - Tcl_DictObjGet(NULL, returnOpts, keys[KEY_ERRORCODE], &valuePtr); - if (valuePtr != NULL) { - int length; - - if (TCL_ERROR == Tcl_ListObjLength(NULL, valuePtr, &length )) { - /* - * Value is not a list, which is illegal for -errorcode. - */ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad -errorcode value: " - "expected a list but got \"", - TclGetString(valuePtr), "\"", NULL); - goto error; - } - } - - /* - * Convert [return -code return -level X] to [return -code ok -level X+1] - */ - - if (code == TCL_RETURN) { - level++; - code = TCL_OK; - } - - if (codePtr != NULL) { - *codePtr = code; - } - if (levelPtr != NULL) { - *levelPtr = level; - } - - if (optionsPtrPtr == NULL) { - /* - * Not passing back the options (?!), so clean them up. - */ - - Tcl_DecrRefCount(returnOpts); - } else { - *optionsPtrPtr = returnOpts; - } - return TCL_OK; - - error: - Tcl_DecrRefCount(returnOpts); - return TCL_ERROR; -} - -/* - *------------------------------------------------------------------------- - * - * Tcl_GetReturnOptions -- - * - * Packs up the interp state into a dictionary of return options. - * - * Results: - * A dictionary of return options. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -Tcl_Obj * -Tcl_GetReturnOptions( - Tcl_Interp *interp, - int result) -{ - Interp *iPtr = (Interp *) interp; - Tcl_Obj *options; - Tcl_Obj **keys = GetKeys(); - - if (iPtr->returnOpts) { - options = Tcl_DuplicateObj(iPtr->returnOpts); - } else { - options = Tcl_NewObj(); - } - - if (result == TCL_RETURN) { - Tcl_DictObjPut(NULL, options, keys[KEY_CODE], - Tcl_NewIntObj(iPtr->returnCode)); - Tcl_DictObjPut(NULL, options, keys[KEY_LEVEL], - Tcl_NewIntObj(iPtr->returnLevel)); - } else { - Tcl_DictObjPut(NULL, options, keys[KEY_CODE], - Tcl_NewIntObj(result)); - Tcl_DictObjPut(NULL, options, keys[KEY_LEVEL], - Tcl_NewIntObj(0)); - } - - if (result == TCL_ERROR) { - Tcl_AddObjErrorInfo(interp, "", -1); - } - if (iPtr->errorCode) { - Tcl_DictObjPut(NULL, options, keys[KEY_ERRORCODE], iPtr->errorCode); - } - if (iPtr->errorInfo) { - Tcl_DictObjPut(NULL, options, keys[KEY_ERRORINFO], iPtr->errorInfo); - Tcl_DictObjPut(NULL, options, keys[KEY_ERRORLINE], - Tcl_NewIntObj(iPtr->errorLine)); - } - return options; -} - -/* - *------------------------------------------------------------------------- - * - * Tcl_SetReturnOptions -- - * - * Accepts an interp and a dictionary of return options, and sets the - * return options of the interp to match the dictionary. - * - * Results: - * A standard status code. Usually TCL_OK, but TCL_ERROR if an invalid - * option value was found in the dictionary. If a -level value of 0 is in - * the dictionary, then the -code value in the dictionary will be - * returned (TCL_OK default). - * - * Side effects: - * Sets the state of the interp. - * - *------------------------------------------------------------------------- - */ - -int -Tcl_SetReturnOptions( - Tcl_Interp *interp, - Tcl_Obj *options) -{ - int objc, level, code; - Tcl_Obj **objv, *mergedOpts; - - Tcl_IncrRefCount(options); - if (TCL_ERROR == TclListObjGetElements(interp, options, &objc, &objv) - || (objc % 2)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected dict but got \"", - TclGetString(options), "\"", NULL); - code = TCL_ERROR; - } else if (TCL_ERROR == TclMergeReturnOptions(interp, objc, objv, - &mergedOpts, &code, &level)) { - code = TCL_ERROR; - } else { - code = TclProcessReturn(interp, code, level, mergedOpts); - } - - Tcl_DecrRefCount(options); - return code; + Interp *iPtr; + + iPtr = (Interp *) interp; + Tcl_SetVar2Ex(interp, "errorCode", NULL, errorObjPtr, TCL_GLOBAL_ONLY); + iPtr->flags |= ERROR_CODE_SET; } /* @@ -1538,72 +965,83 @@ Tcl_SetReturnOptions( * * 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. + * 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. + * 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 errorInfo field may be transferred to the - * target's errorInfo field, and the source's errorCode field may be - * transferred to the target's errorCode field. + * 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. * *------------------------------------------------------------------------- */ - + void -TclTransferResult( - Tcl_Interp *sourceInterp, /* Interp whose result and error information - * should be moved to the target interp. - * After moving result, this interp's result +TclTransferResult(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 + 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. */ + Tcl_Interp *targetInterp; /* Interp where result and error information + * should be stored. If source and target + * are the same, nothing is done. */ { - Interp *tiPtr = (Interp *) targetInterp; - Interp *siPtr = (Interp *) sourceInterp; + Interp *iPtr; + Tcl_Obj *objPtr; if (sourceInterp == targetInterp) { return; } - if (result == TCL_OK && siPtr->returnOpts == NULL) { + if (result == TCL_ERROR) { /* - * Special optimization for the common case of normal command return - * code and no explicit return options. + * 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. */ - if (tiPtr->returnOpts) { - Tcl_DecrRefCount(tiPtr->returnOpts); - tiPtr->returnOpts = NULL; + 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); + if (objPtr) { + Tcl_SetVar2Ex(targetInterp, "errorInfo", NULL, objPtr, + TCL_GLOBAL_ONLY); + ((Interp *) targetInterp)->flags |= ERR_IN_PROGRESS; } - } else { - Tcl_SetReturnOptions(targetInterp, - Tcl_GetReturnOptions(sourceInterp, result)); - tiPtr->flags &= ~(ERR_ALREADY_LOGGED); + + objPtr = Tcl_GetVar2Ex(sourceInterp, "errorCode", NULL, + TCL_GLOBAL_ONLY); + if (objPtr) { + Tcl_SetObjErrorCode(targetInterp, objPtr); + } + } + + ((Interp *) targetInterp)->returnCode = ((Interp *) sourceInterp)->returnCode; Tcl_SetObjResult(targetInterp, Tcl_GetObjResult(sourceInterp)); Tcl_ResetResult(sourceInterp); } - -/* - * Local Variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * End: - */ |
