概要
引数
- Tcl_Interp *interp TCL インタープリタへのポインター
- const char *script 実行するコマンド
- int numBytes scriptのバイト数。0より小さいときは全バイト。
- int flags 制御フラグ TCL_EVAL_GLOBALのみサポート
- int line スクリプトの開始行数
- int* clNextOuter
- CONST char* outerScript outerスクリプト。一番outer(呼び出しの浅い)スクリプトを示す。outerScript == scriptの時、一番outerなスクリプトであることを示す。
戻り値
実行結果
処理
変数の宣言
Interp *iPtr = (Interp *) interp;
const char *p, *next;
const unsigned int minObjs = 20;
Tcl_Obj **objv, **objvSpace;
int *expand, *lines, *lineSpace;
Tcl_Token *tokenPtr;
int commandLength, bytesLeft, expandRequested, code = TCL_OK;
CallFrame *savedVarFramePtr;/* Saves old copy of iPtr->varFramePtr in case
* TCL_EVAL_GLOBAL was set. */
int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS);
int gotParse = 0;
unsigned int i, objectsUsed = 0;
/* These variables keep track of how much
* state has been allocated while evaluating
* the script, so that it can be freed
* properly if an error occurs. */
Tcl_Parse *parsePtr = (Tcl_Parse *)
TclStackAlloc(interp, sizeof(Tcl_Parse));
[[CmdFrame]] *eeFramePtr = (CmdFrame *)
TclStackAlloc(interp, sizeof(CmdFrame));
Tcl_Obj **stackObjArray = (Tcl_Obj **)
TclStackAlloc(interp, minObjs * sizeof(Tcl_Obj *));
int *expandStack = (int *) TclStackAlloc(interp, minObjs * sizeof(int));
int *linesStack = (int *) TclStackAlloc(interp, minObjs * sizeof(int));
/* TIP #280 Structures for tracking of command
* locations. */
/*
* Pointer for the tracking of invisible continuation lines. Initialized
* only if the caller gave us a table of locations to track, via
* scriptCLLocPtr. It always refers to the table entry holding the
* location of the next invisible continuation line to look for, while
* parsing the script.
*/
int* clNext = NULL;
if (iPtr->scriptCLLocPtr) {
if (clNextOuter) {
clNext = clNextOuter;
} else {
clNext = &iPtr->scriptCLLocPtr->loc[0];
}
}
if (numBytes < 0) {
numBytes = strlen(script);
}
Tcl_ResetResult(interp);
savedVarFramePtr = iPtr->varFramePtr;
if (flags & TCL_EVAL_GLOBAL) {
iPtr->varFramePtr = iPtr->rootFramePtr;
}
/*
* Each iteration through the following loop parses the next command from
* the script and then executes it.
*/
objv = objvSpace = stackObjArray;
lines = lineSpace = linesStack;
expand = expandStack;
p = script;
bytesLeft = numBytes;
/*
* TIP #280 Initialize tracking. Do not push on the frame stack yet.
*
* We may continue counting based on a specific context (CTX), or open a
* new context, either for a sourced script, or 'eval'. For sourced files
* we always have a path object, even if nothing was specified in the
* interp itself. That makes code using it simpler as NULL checks can be
* left out. Sourced file without path in the 'scriptFile' is possible
* during Tcl initialization.
*/
if (iPtr->evalFlags & TCL_EVAL_CTX) {
/*
* Path information comes out of the context.
*/
eeFramePtr->type = TCL_LOCATION_SOURCE;
eeFramePtr->data.eval.path = iPtr->invokeCmdFramePtr->data.eval.path;
Tcl_IncrRefCount(eeFramePtr->data.eval.path);
} else if (iPtr->evalFlags & TCL_EVAL_FILE) {
/*
* Set up for a sourced file.
*/
eeFramePtr->type = TCL_LOCATION_SOURCE;
if (iPtr->scriptFile) {
/*
* Normalization here, to have the correct pwd. Should have
* negligible impact on performance, as the norm should have been
* done already by the 'source' invoking us, and it caches the
* result.
*/
Tcl_Obj *norm = Tcl_FSGetNormalizedPath(interp, iPtr->scriptFile);
if (norm == NULL) {
/*
* Error message in the interp result.
*/
code = TCL_ERROR;
goto error;
}
eeFramePtr->data.eval.path = norm;
} else {
TclNewLiteralStringObj(eeFramePtr->data.eval.path, "");
}
Tcl_IncrRefCount(eeFramePtr->data.eval.path);
} else {
/*
* Set up for plain eval.
*/
eeFramePtr->type = TCL_LOCATION_EVAL;
eeFramePtr->data.eval.path = NULL;
}
eeFramePtr->level = iPtr->cmdFramePtr ? iPtr->cmdFramePtr->level + 1 : 1;
eeFramePtr->framePtr = iPtr->framePtr;
eeFramePtr->nextPtr = iPtr->cmdFramePtr;
eeFramePtr->nline = 0;
eeFramePtr->line = NULL;
iPtr->evalFlags = 0;
do {
if (Tcl_Parse[[Command]](interp, p, bytesLeft, 0, parsePtr) != TCL_OK) {
code = TCL_ERROR;
goto error;
}
/*
* TIP #280 Track lines. The parser may have skipped text till it
* found the command we are now at. We have to count the lines in this
* block, and do not forget invisible continuation lines.
*/
TclAdvanceLines(&line, p, parsePtr->commandStart);
TclAdvanceContinuations (&line, &clNext,
parsePtr->commandStart - outerScript);
gotParse = 1;
if (parsePtr->numWords > 0) {
/*
* TIP #280. Track lines within the words of the current
* command. We use a separate pointer into the table of
* continuation line locations to not lose our position for the
* per-command parsing.
*/
int wordLine = line;
const char *wordStart = parsePtr->commandStart;
int* wordCLNext = clNext;
/*
* Generate an array of objects for the words of the command.
*/
unsigned int objectsNeeded = 0;
unsigned int numWords = parsePtr->numWords;
if (numWords > minObjs) {
expand = (int *) ckalloc(numWords * sizeof(int));
objvSpace = (Tcl_Obj **)
ckalloc(numWords * sizeof(Tcl_Obj *));
lineSpace = (int *) ckalloc(numWords * sizeof(int));
}
expandRequested = 0;
objv = objvSpace;
lines = lineSpace;
for (objectsUsed = 0, tokenPtr = parsePtr->tokenPtr;
objectsUsed < numWords;
objectsUsed++, tokenPtr += tokenPtr->numComponents+1) {
/*
* TIP #280. Track lines to current word. Save the information
* on a per-word basis, signaling dynamic words as needed.
* Make the information available to the recursively called
* evaluator as well, including the type of context (source
* vs. eval).
*/
TclAdvanceLines(&wordLine, wordStart, tokenPtr->start);
TclAdvanceContinuations (&wordLine, &wordCLNext,
tokenPtr->start - outerScript);
wordStart = tokenPtr->start;
lines[objectsUsed] = TclWordKnownAtCompileTime(tokenPtr, NULL)
? wordLine : -1;
if (eeFramePtr->type == TCL_LOCATION_SOURCE) {
iPtr->evalFlags |= TCL_EVAL_FILE;
}
code = TclSubstTokens(interp, tokenPtr+1,
tokenPtr->numComponents, NULL, wordLine,
wordCLNext, outerScript);
iPtr->evalFlags = 0;
if (code != TCL_OK) {
goto error;
}
objv[objectsUsed] = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(objv[objectsUsed]);
if (tokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
int numElements;
code = TclListObjLength(interp, objv[objectsUsed],
&numElements);
if (code == TCL_ERROR) {
/*
* Attempt to expand a non-list.
*/
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (expanding word %d)", objectsUsed));
Tcl_DecrRefCount(objv[objectsUsed]);
goto error;
}
expandRequested = 1;
expand[objectsUsed] = 1;
objectsNeeded += (numElements ? numElements : 1);
} else {
expand[objectsUsed] = 0;
objectsNeeded++;
}
if (wordCLNext) {
TclContinuationsEnterDerived (objv[objectsUsed],
wordStart - outerScript, wordCLNext);
}
} /* for loop */
if (expandRequested) {
/*
* Some word expansion was requested. Check for objv resize.
*/
Tcl_Obj **copy = objvSpace;
int *lcopy = lineSpace;
int wordIdx = numWords;
int objIdx = objectsNeeded - 1;
if ((numWords > minObjs) || (objectsNeeded > minObjs)) {
objv = objvSpace = (Tcl_Obj **)
ckalloc(objectsNeeded * sizeof(Tcl_Obj *));
lines = lineSpace = (int *)
ckalloc(objectsNeeded * sizeof(int));
}
objectsUsed = 0;
while (wordIdx--) {
if (expand[wordIdx]) {
int numElements;
Tcl_Obj **elements, *temp = copy[wordIdx];
Tcl_ListObjGetElements(NULL, temp, &numElements,
&elements);
objectsUsed += numElements;
while (numElements--) {
lines[objIdx] = -1;
objv[objIdx--] = elements[numElements];
Tcl_IncrRefCount(elements[numElements]);
}
Tcl_DecrRefCount(temp);
} else {
lines[objIdx] = lcopy[wordIdx];
objv[objIdx--] = copy[wordIdx];
objectsUsed++;
}
}
objv += objIdx+1;
if (copy != stackObjArray) {
ckfree((char *) copy);
}
if (lcopy != linesStack) {
ckfree((char *) lcopy);
}
}
/*
* Execute the command and free the objects for its words.
*
* TIP #280: Remember the command itself for 'info frame'. We
* shorten the visible command by one char to exclude the
* termination character, if necessary. Here is where we put our
* frame on the stack of frames too. _After_ the nested commands
* have been executed.
*/
eeFramePtr->cmd.str.cmd = parsePtr->commandStart;
eeFramePtr->cmd.str.len = parsePtr->commandSize;
if (parsePtr->term ==
parsePtr->commandStart + parsePtr->commandSize - 1) {
eeFramePtr->cmd.str.len--;
}
eeFramePtr->nline = objectsUsed;
eeFramePtr->line = lines;
TclArgumentEnter (interp, objv, objectsUsed, eeFramePtr);
iPtr->cmdFramePtr = eeFramePtr;
iPtr->numLevels++;
code = TclEvalObjvInternal(interp, objectsUsed, objv,
parsePtr->commandStart, parsePtr->commandSize, 0);
iPtr->numLevels--;
iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr;
TclArgumentRelease (interp, objv, objectsUsed);
eeFramePtr->line = NULL;
eeFramePtr->nline = 0;
if (code != TCL_OK) {
goto error;
}
for (i = 0; i < objectsUsed; i++) {
Tcl_DecrRefCount(objv[i]);
}
objectsUsed = 0;
if (objvSpace != stackObjArray) {
ckfree((char *) objvSpace);
objvSpace = stackObjArray;
ckfree((char *) lineSpace);
lineSpace = linesStack;
}
/*
* Free expand separately since objvSpace could have been
* reallocated above.
*/
if (expand != expandStack) {
ckfree((char *) expand);
expand = expandStack;
}
}
/*
* Advance to the next command in the script.
*
* TIP #280 Track Lines. Now we track how many lines were in the
* executed command.
*/
next = parsePtr->commandStart + parsePtr->commandSize;
bytesLeft -= next - p;
p = next;
TclAdvanceLines(&line, parsePtr->commandStart, p);
Tcl_FreeParse(parsePtr);
gotParse = 0;
} while (bytesLeft > 0);
iPtr->varFramePtr = savedVarFramePtr;
code = TCL_OK;
goto cleanup_return;
error:
/*
* Generate and log various pieces of error information.
*/
if (iPtr->numLevels == 0) {
if (code == TCL_RETURN) {
code = TclUpdateReturnInfo(iPtr);
}
if ((code != TCL_OK) && (code != TCL_ERROR) && !allowExceptions) {
ProcessUnexpectedResult(interp, code);
code = TCL_ERROR;
}
}
if ((code == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
commandLength = parsePtr->commandSize;
if (parsePtr->term == parsePtr->commandStart + commandLength - 1) {
/*
* The terminator character (such as ; or ]) of the command where
* the error occurred is the last character in the parsed command.
* Reduce the length by one so that the error message doesn't
* include the terminator character.
*/
commandLength -= 1;
}
Tcl_LogCommandInfo(interp, script, parsePtr->commandStart,
commandLength);
}
iPtr->flags &= ~ERR_ALREADY_LOGGED;
/*
* Then free resources that had been allocated to the command.
*/
for (i = 0; i < objectsUsed; i++) {
Tcl_DecrRefCount(objv[i]);
}
if (gotParse) {
Tcl_FreeParse(parsePtr);
}
if (objvSpace != stackObjArray) {
ckfree((char *) objvSpace);
ckfree((char *) lineSpace);
}
if (expand != expandStack) {
ckfree((char *) expand);
}
iPtr->varFramePtr = savedVarFramePtr;
cleanup_return:
/*
* TIP #280. Release the local CmdFrame, and its contents.
*/
if (eeFramePtr->type == TCL_LOCATION_SOURCE) {
Tcl_DecrRefCount(eeFramePtr->data.eval.path);
}
TclStackFree(interp, linesStack);
TclStackFree(interp, expandStack);
TclStackFree(interp, stackObjArray);
TclStackFree(interp, eeFramePtr);
TclStackFree(interp, parsePtr);
return code;
}
ソース
int
TclEvalEx(
[[Tcl_Interp]] *interp, /* Interpreter in which to evaluate the
* script. Also used for error reporting. */
const char *script, /* First character of script to evaluate. */
int numBytes, /* Number of bytes in script. If < 0, the
* script consists of all bytes up to the
* first NUL character. */
int flags, /* Collection of OR-ed bits that control the
* evaluation of the script. Only
* TCL_EVAL_GLOBAL is currently supported. */
int line, /* The line the script starts on. */
int* clNextOuter, /* Information about an outer context for */
CONST char* outerScript) /* continuation line data. This is set only in
* TclSubstTokens(), to properly handle
* [...]-nested commands. The 'outerScript'
* refers to the most-outer script containing the
* embedded command, which is refered to by
* 'script'. The 'clNextOuter' refers to the
* current entry in the table of continuation
* lines in this "master script", and the
* character offsets are relative to the
* 'outerScript' as well.
*
* If outerScript == script, then this call is
* for the outer-most script/command. See
* Tcl_EvalEx() and TclEvalObjEx() for places
* generating arguments for which this is true.
*/
{
Interp *iPtr = (Interp *) interp;
const char *p, *next;
const unsigned int minObjs = 20;
Tcl_Obj **objv, **objvSpace;
int *expand, *lines, *lineSpace;
Tcl_Token *tokenPtr;
int commandLength, bytesLeft, expandRequested, code = TCL_OK;
CallFrame *savedVarFramePtr;/* Saves old copy of iPtr->varFramePtr in case
* TCL_EVAL_GLOBAL was set. */
int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS);
int gotParse = 0;
unsigned int i, objectsUsed = 0;
/* These variables keep track of how much
* state has been allocated while evaluating
* the script, so that it can be freed
* properly if an error occurs. */
Tcl_Parse *parsePtr = (Tcl_Parse *)
TclStackAlloc(interp, sizeof(Tcl_Parse));
CmdFrame *eeFramePtr = (CmdFrame *)
TclStackAlloc(interp, sizeof(CmdFrame));
Tcl_Obj **stackObjArray = (Tcl_Obj **)
TclStackAlloc(interp, minObjs * sizeof(Tcl_Obj *));
int *expandStack = (int *) TclStackAlloc(interp, minObjs * sizeof(int));
int *linesStack = (int *) TclStackAlloc(interp, minObjs * sizeof(int));
/* TIP #280 Structures for tracking of command
* locations. */
/*
* Pointer for the tracking of invisible continuation lines. Initialized
* only if the caller gave us a table of locations to track, via
* scriptCLLocPtr. It always refers to the table entry holding the
* location of the next invisible continuation line to look for, while
* parsing the script.
*/
int* clNext = NULL;
if (iPtr->scriptCLLocPtr) {
if (clNextOuter) {
clNext = clNextOuter;
} else {
clNext = &iPtr->scriptCLLocPtr->loc[0];
}
}
if (numBytes < 0) {
numBytes = strlen(script);
}
Tcl_ResetResult(interp);
savedVarFramePtr = iPtr->varFramePtr;
if (flags & TCL_EVAL_GLOBAL) {
iPtr->varFramePtr = iPtr->rootFramePtr;
}
/*
* Each iteration through the following loop parses the next command from
* the script and then executes it.
*/
objv = objvSpace = stackObjArray;
lines = lineSpace = linesStack;
expand = expandStack;
p = script;
bytesLeft = numBytes;
/*
* TIP #280 Initialize tracking. Do not push on the frame stack yet.
*
* We may continue counting based on a specific context (CTX), or open a
* new context, either for a sourced script, or 'eval'. For sourced files
* we always have a path object, even if nothing was specified in the
* interp itself. That makes code using it simpler as NULL checks can be
* left out. Sourced file without path in the 'scriptFile' is possible
* during Tcl initialization.
*/
if (iPtr->evalFlags & TCL_EVAL_CTX) {
/*
* Path information comes out of the context.
*/
eeFramePtr->type = TCL_LOCATION_SOURCE;
eeFramePtr->data.eval.path = iPtr->invokeCmdFramePtr->data.eval.path;
Tcl_IncrRefCount(eeFramePtr->data.eval.path);
} else if (iPtr->evalFlags & TCL_EVAL_FILE) {
/*
* Set up for a sourced file.
*/
eeFramePtr->type = TCL_LOCATION_SOURCE;
if (iPtr->scriptFile) {
/*
* Normalization here, to have the correct pwd. Should have
* negligible impact on performance, as the norm should have been
* done already by the 'source' invoking us, and it caches the
* result.
*/
Tcl_Obj *norm = Tcl_FSGetNormalizedPath(interp, iPtr->scriptFile);
if (norm == NULL) {
/*
* Error message in the interp result.
*/
code = TCL_ERROR;
goto error;
}
eeFramePtr->data.eval.path = norm;
} else {
TclNewLiteralStringObj(eeFramePtr->data.eval.path, "");
}
Tcl_IncrRefCount(eeFramePtr->data.eval.path);
} else {
/*
* Set up for plain eval.
*/
eeFramePtr->type = TCL_LOCATION_EVAL;
eeFramePtr->data.eval.path = NULL;
}
eeFramePtr->level = iPtr->cmdFramePtr ? iPtr->cmdFramePtr->level + 1 : 1;
eeFramePtr->framePtr = iPtr->framePtr;
eeFramePtr->nextPtr = iPtr->cmdFramePtr;
eeFramePtr->nline = 0;
eeFramePtr->line = NULL;
iPtr->evalFlags = 0;
do {
if (Tcl_ParseCommand(interp, p, bytesLeft, 0, parsePtr) != TCL_OK) {
code = TCL_ERROR;
goto error;
}
/*
* TIP #280 Track lines. The parser may have skipped text till it
* found the command we are now at. We have to count the lines in this
* block, and do not forget invisible continuation lines.
*/
TclAdvanceLines(&line, p, parsePtr->commandStart);
TclAdvanceContinuations (&line, &clNext,
parsePtr->commandStart - outerScript);
gotParse = 1;
if (parsePtr->numWords > 0) {
/*
* TIP #280. Track lines within the words of the current
* command. We use a separate pointer into the table of
* continuation line locations to not lose our position for the
* per-command parsing.
*/
int wordLine = line;
const char *wordStart = parsePtr->commandStart;
int* wordCLNext = clNext;
/*
* Generate an array of objects for the words of the command.
*/
unsigned int objectsNeeded = 0;
unsigned int numWords = parsePtr->numWords;
if (numWords > minObjs) {
expand = (int *) ckalloc(numWords * sizeof(int));
objvSpace = (Tcl_Obj **)
ckalloc(numWords * sizeof(Tcl_Obj *));
lineSpace = (int *) ckalloc(numWords * sizeof(int));
}
expandRequested = 0;
objv = objvSpace;
lines = lineSpace;
for (objectsUsed = 0, tokenPtr = parsePtr->tokenPtr;
objectsUsed < numWords;
objectsUsed++, tokenPtr += tokenPtr->numComponents+1) {
/*
* TIP #280. Track lines to current word. Save the information
* on a per-word basis, signaling dynamic words as needed.
* Make the information available to the recursively called
* evaluator as well, including the type of context (source
* vs. eval).
*/
TclAdvanceLines(&wordLine, wordStart, tokenPtr->start);
TclAdvanceContinuations (&wordLine, &wordCLNext,
tokenPtr->start - outerScript);
wordStart = tokenPtr->start;
lines[objectsUsed] = TclWordKnownAtCompileTime(tokenPtr, NULL)
? wordLine : -1;
if (eeFramePtr->type == TCL_LOCATION_SOURCE) {
iPtr->evalFlags |= TCL_EVAL_FILE;
}
code = TclSubstTokens(interp, tokenPtr+1,
tokenPtr->numComponents, NULL, wordLine,
wordCLNext, outerScript);
iPtr->evalFlags = 0;
if (code != TCL_OK) {
goto error;
}
objv[objectsUsed] = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(objv[objectsUsed]);
if (tokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
int numElements;
code = TclListObjLength(interp, objv[objectsUsed],
&numElements);
if (code == TCL_ERROR) {
/*
* Attempt to expand a non-list.
*/
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (expanding word %d)", objectsUsed));
Tcl_DecrRefCount(objv[objectsUsed]);
goto error;
}
expandRequested = 1;
expand[objectsUsed] = 1;
objectsNeeded += (numElements ? numElements : 1);
} else {
expand[objectsUsed] = 0;
objectsNeeded++;
}
if (wordCLNext) {
TclContinuationsEnterDerived (objv[objectsUsed],
wordStart - outerScript, wordCLNext);
}
} /* for loop */
if (expandRequested) {
/*
* Some word expansion was requested. Check for objv resize.
*/
Tcl_Obj **copy = objvSpace;
int *lcopy = lineSpace;
int wordIdx = numWords;
int objIdx = objectsNeeded - 1;
if ((numWords > minObjs) || (objectsNeeded > minObjs)) {
objv = objvSpace = (Tcl_Obj **)
ckalloc(objectsNeeded * sizeof(Tcl_Obj *));
lines = lineSpace = (int *)
ckalloc(objectsNeeded * sizeof(int));
}
objectsUsed = 0;
while (wordIdx--) {
if (expand[wordIdx]) {
int numElements;
Tcl_Obj **elements, *temp = copy[wordIdx];
Tcl_ListObjGetElements(NULL, temp, &numElements,
&elements);
objectsUsed += numElements;
while (numElements--) {
lines[objIdx] = -1;
objv[objIdx--] = elements[numElements];
Tcl_IncrRefCount(elements[numElements]);
}
Tcl_DecrRefCount(temp);
} else {
lines[objIdx] = lcopy[wordIdx];
objv[objIdx--] = copy[wordIdx];
objectsUsed++;
}
}
objv += objIdx+1;
if (copy != stackObjArray) {
ckfree((char *) copy);
}
if (lcopy != linesStack) {
ckfree((char *) lcopy);
}
}
/*
* Execute the command and free the objects for its words.
*
* TIP #280: Remember the command itself for 'info frame'. We
* shorten the visible command by one char to exclude the
* termination character, if necessary. Here is where we put our
* frame on the stack of frames too. _After_ the nested commands
* have been executed.
*/
eeFramePtr->cmd.str.cmd = parsePtr->commandStart;
eeFramePtr->cmd.str.len = parsePtr->commandSize;
if (parsePtr->term ==
parsePtr->commandStart + parsePtr->commandSize - 1) {
eeFramePtr->cmd.str.len--;
}
eeFramePtr->nline = objectsUsed;
eeFramePtr->line = lines;
TclArgumentEnter (interp, objv, objectsUsed, eeFramePtr);
iPtr->cmdFramePtr = eeFramePtr;
iPtr->numLevels++;
code = TclEvalObjvInternal(interp, objectsUsed, objv,
parsePtr->commandStart, parsePtr->commandSize, 0);
iPtr->numLevels--;
iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr;
TclArgumentRelease (interp, objv, objectsUsed);
eeFramePtr->line = NULL;
eeFramePtr->nline = 0;
if (code != TCL_OK) {
goto error;
}
for (i = 0; i < objectsUsed; i++) {
Tcl_DecrRefCount(objv[i]);
}
objectsUsed = 0;
if (objvSpace != stackObjArray) {
ckfree((char *) objvSpace);
objvSpace = stackObjArray;
ckfree((char *) lineSpace);
lineSpace = linesStack;
}
/*
* Free expand separately since objvSpace could have been
* reallocated above.
*/
if (expand != expandStack) {
ckfree((char *) expand);
expand = expandStack;
}
}
/*
* Advance to the next command in the script.
*
* TIP #280 Track Lines. Now we track how many lines were in the
* executed command.
*/
next = parsePtr->commandStart + parsePtr->commandSize;
bytesLeft -= next - p;
p = next;
TclAdvanceLines(&line, parsePtr->commandStart, p);
Tcl_FreeParse(parsePtr);
gotParse = 0;
} while (bytesLeft > 0);
iPtr->varFramePtr = savedVarFramePtr;
code = TCL_OK;
goto cleanup_return;
error:
/*
* Generate and log various pieces of error information.
*/
if (iPtr->numLevels == 0) {
if (code == TCL_RETURN) {
code = TclUpdateReturnInfo(iPtr);
}
if ((code != TCL_OK) && (code != TCL_ERROR) && !allowExceptions) {
ProcessUnexpectedResult(interp, code);
code = TCL_ERROR;
}
}
if ((code == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
commandLength = parsePtr->commandSize;
if (parsePtr->term == parsePtr->commandStart + commandLength - 1) {
/*
* The terminator character (such as ; or ]) of the command where
* the error occurred is the last character in the parsed command.
* Reduce the length by one so that the error message doesn't
* include the terminator character.
*/
commandLength -= 1;
}
Tcl_LogCommandInfo(interp, script, parsePtr->commandStart,
commandLength);
}
iPtr->flags &= ~ERR_ALREADY_LOGGED;
/*
* Then free resources that had been allocated to the command.
*/
for (i = 0; i < objectsUsed; i++) {
Tcl_DecrRefCount(objv[i]);
}
if (gotParse) {
Tcl_FreeParse(parsePtr);
}
if (objvSpace != stackObjArray) {
ckfree((char *) objvSpace);
ckfree((char *) lineSpace);
}
if (expand != expandStack) {
ckfree((char *) expand);
}
iPtr->varFramePtr = savedVarFramePtr;
cleanup_return:
/*
* TIP #280. Release the local CmdFrame, and its contents.
*/
if (eeFramePtr->type == TCL_LOCATION_SOURCE) {
Tcl_DecrRefCount(eeFramePtr->data.eval.path);
}
TclStackFree(interp, linesStack);
TclStackFree(interp, expandStack);
TclStackFree(interp, stackObjArray);
TclStackFree(interp, eeFramePtr);
TclStackFree(interp, parsePtr);
return code;
}
最終更新:2011年11月01日 11:45