summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog52
-rw-r--r--generic/tclBasic.c95
2 files changed, 97 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index ce4bab1..33627a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,22 +1,29 @@
+2006-11-02 Donal K. Fellows <donal.k.fellows@manchester.ac.uk>
+
+ * generic/tclBasic.c (TclEvalObjvInternal): Rewrote so that comments
+ are relevant and informative once more. Also made the unknown handler
+ processing use the Tcl execution stack for working space, and not the
+ general heap.
+
2006-11-01 Daniel Steffen <das@users.sourceforge.net>
* unix/tclUnixPort.h: ensure MODULE_SCOPE is defined before use, so
that tclPort.h can once again be included without tclInt.h.
- * generic/tclEnv.c (Darwin): mark _environ symbol as unexported
- even when MODULE_SCOPE != __private_extern__.
+ * generic/tclEnv.c (Darwin): mark _environ symbol as unexported even
+ when MODULE_SCOPE != __private_extern__.
2006-10-31 Don Porter <dgp@users.sourceforge.net>
* generic/tclBasic.c: Refactored and renamed the routines
* generic/tclCkalloc.c: TclObjPrintf, TclFormatObj, and
- * generic/tclCmdAH.c: TclFormatToErrorInfo to a new set of
- * generic/tclCmdIL.c: routines TclAppendPrintfToObj,
- * generic/tclCmdMZ.c: TclAppendFormatToObj, TclObjPrintf, and
- * generic/tclDictObj.c: TclObjFormat, with the intent of making
- * generic/tclExecute.c: the latter list, plus TclAppendLimitedToObj
- * generic/tclIORChan.c: and TclAppendObjToErrorInfo, public via
- * generic/tclIOUtil.c: a revised TIP 270.
+ * generic/tclCmdAH.c: TclFormatToErrorInfo to a new set of routines
+ * generic/tclCmdIL.c: TclAppendPrintfToObj, TclAppendFormatToObj,
+ * generic/tclCmdMZ.c: TclObjPrintf, and TclObjFormat, with the
+ * generic/tclDictObj.c: intent of making the latter list, plus
+ * generic/tclExecute.c: TclAppendLimitedToObj and
+ * generic/tclIORChan.c: TclAppendObjToErrorInfo, public via a revised
+ * generic/tclIOUtil.c: TIP 270.
* generic/tclInt.h:
* generic/tclMain.c:
* generic/tclNamesp.c:
@@ -30,13 +37,11 @@
2006-10-31 Miguel Sofer <msofer@users.sf.net>
- * generic/tclBasic.c:
- * generic/tcl.h:
- * generic/tclInterp.c:
- * generic/tclNamesp.c: removing the flag bit TCL_EVAL_NOREWRITE,
- the last remnant of the callObjc/v fiasco. It is not needed, as it
- is now always set and checked or'ed with TCL_EVAL_INVOKE.
-
+ * generic/tclBasic.c, generic/tcl.h, generic/tclInterp.c:
+ * generic/tclNamesp.c: removing the flag bit TCL_EVAL_NOREWRITE, the
+ last remnant of the callObjc/v fiasco. It is not needed, as it is now
+ always set and checked or'ed with TCL_EVAL_INVOKE.
+
2006-10-31 Pat Thoyts <patthoyts@users.sourceforge.net>
* win/rules.vc: Fix for bug #1582769 - options conflict with VC2003.
@@ -67,7 +72,7 @@
* generic/tclBasic.c (TEOVI): insured that the interp's callObjc/v
fields are restored after traces run, as they be spoiled. This was
causing a segfault in tcllib's profiler tests.
-
+
2006-10-30 Don Porter <dgp@users.sourceforge.net>
* generic/tclExecute.c (INST_MOD): Corrected improper testing of the
@@ -177,7 +182,7 @@
* README: Bump version number to 8.5a6
* generic/tcl.h:
- * library init.tcl:
+ * library/init.tcl:
* tools/tcl.wse.in:
* unix/configure.in:
* unix/tcl.spec:
@@ -189,12 +194,11 @@
2006-10-21 Miguel Sofer <msofer@users.sf.net>
- * generic/tcl.h:
- * generic/tclHash.c: Tcl_FindHashEntry now calls Tcl_CreateHashEntry
- with a newPtr set to NULL: this would have caused a segfault
- previously and eliminates duplicated code. A macro has been added to
- tcl.h (only used when TCL_PRESERVE_BINARY_COMPATABALITY is not set -
- ie, not by default).
+ * generic/tcl.h, generic/tclHash.c: Tcl_FindHashEntry now calls
+ Tcl_CreateHashEntry with a newPtr set to NULL: this would have caused
+ a segfault previously and eliminates duplicated code. A macro has been
+ added to tcl.h (only used when TCL_PRESERVE_BINARY_COMPATABALITY is
+ not set - i.e., not by default).
2006-10-20 Reinhard Max <max@tclers.tk>
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index 2ef6a8d..0518d72 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -13,7 +13,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclBasic.c,v 1.209 2006/10/31 20:19:44 dgp Exp $
+ * RCS: @(#) $Id: tclBasic.c,v 1.210 2006/11/02 09:42:07 dkf Exp $
*/
#include "tclInt.h"
@@ -3271,9 +3271,8 @@ TclEvalObjvInternal(
CallFrame *savedVarFramePtr = NULL;
CallFrame *varFramePtr = iPtr->varFramePtr;
int code = TCL_OK;
- int traceCode = TCL_OK;
+ int traceCode = TCL_OK;
int checkTraces = 1;
- int cmdEpoch;
Namespace *savedNsPtr = NULL;
if (TclInterpReady(interp) == TCL_ERROR) {
@@ -3291,7 +3290,7 @@ TclEvalObjvInternal(
if ((flags & TCL_EVAL_GLOBAL) && (varFramePtr != iPtr->rootFramePtr)) {
varFramePtr = iPtr->rootFramePtr;
savedVarFramePtr = iPtr->varFramePtr;
- iPtr->varFramePtr = varFramePtr;
+ iPtr->varFramePtr = varFramePtr;
} else if (flags & TCL_EVAL_INVOKE) {
savedNsPtr = varFramePtr->nsPtr;
if (iPtr->lookupNsPtr) {
@@ -3329,25 +3328,49 @@ TclEvalObjvInternal(
Tcl_Panic("TclEvalObjvInternal: NULL global namespace pointer");
}
}
+
+ /*
+ * Check to see if the resolution namespace has lost its unknown
+ * handler. If so, reset it to "::unknown".
+ */
+
if (currNsPtr->unknownHandlerPtr == NULL) {
- /* Global namespace has lost unknown handler, reset. */
currNsPtr->unknownHandlerPtr = Tcl_NewStringObj("::unknown", -1);
Tcl_IncrRefCount(currNsPtr->unknownHandlerPtr);
}
+
+ /*
+ * Get the list of words for the unknown handler and allocate enough
+ * space to hold both the handler prefix and all words of the command
+ * invokation itself.
+ */
+
Tcl_ListObjGetElements(NULL, currNsPtr->unknownHandlerPtr,
&handlerObjc, &handlerObjv);
newObjc = objc + handlerObjc;
- newObjv = (Tcl_Obj **) ckalloc((unsigned)
- (newObjc * sizeof(Tcl_Obj *)));
- /* Copy command prefix from unknown handler. */
+ newObjv = (Tcl_Obj **) TclStackAlloc(interp,
+ sizeof(Tcl_Obj *) * (unsigned)newObjc);
+
+ /*
+ * Copy command prefix from unknown handler and add on the real
+ * command's full argument list. Note that we only use memcpy() once
+ * because we have to increment the reference count of all the handler
+ * arguments anyway.
+ */
+
for (i = 0; i < handlerObjc; ++i) {
newObjv[i] = handlerObjv[i];
Tcl_IncrRefCount(newObjv[i]);
}
- /* Add in command name and arguments. */
- for (i = objc-1; i >= 0; --i) {
- newObjv[i+handlerObjc] = objv[i];
- }
+ memcpy(newObjv+handlerObjc, objv, sizeof(Tcl_Obj *) * (unsigned)objc);
+
+ /*
+ * Look up and invoke the handler (by recursive call to this
+ * function). If there is no handler at all, instead of doing the
+ * recursive call we just generate a generic error message; it would
+ * be an infinite-recursion nightmare otherwise.
+ */
+
cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, newObjv[0]);
if (cmdPtr == NULL) {
Tcl_AppendResult(interp, "invalid command name \"",
@@ -3356,13 +3379,19 @@ TclEvalObjvInternal(
} else {
iPtr->numLevels++;
code = TclEvalObjvInternal(interp, newObjc, newObjv, command,
- length, 0);
+ length, 0);
iPtr->numLevels--;
}
+
+ /*
+ * Release any resources we locked and allocated during the handler
+ * call.
+ */
+
for (i = 0; i < handlerObjc; ++i) {
Tcl_DecrRefCount(newObjv[i]);
}
- ckfree((char *) newObjv);
+ TclStackFree(interp);
if (savedNsPtr) {
varFramePtr->nsPtr = savedNsPtr;
iPtr->lookupNsPtr = NULL;
@@ -3373,21 +3402,21 @@ TclEvalObjvInternal(
varFramePtr->nsPtr = savedNsPtr;
iPtr->lookupNsPtr = NULL;
}
-
+
/*
* Call trace functions if needed.
*/
- cmdEpoch = cmdPtr->cmdEpoch;
if (checkTraces && (command != NULL)) {
- cmdPtr->refCount++;
+ int cmdEpoch = cmdPtr->cmdEpoch;
/*
- * If the first set of traces modifies/deletes the command or any
- * existing traces, then the set checkTraces to 0 and go through this
- * while loop one more time.
+ * Execute any command or execution traces. Note that we bump up the
+ * command's reference count for the duration of the calling of the
+ * traces so that the structure doesn't go away underneath our feet.
*/
+ cmdPtr->refCount++;
if (iPtr->tracePtr != NULL && traceCode == TCL_OK) {
traceCode = TclCheckInterpTraces(interp, command, length,
cmdPtr, code, TCL_TRACE_ENTER_EXEC, objc, objv);
@@ -3397,11 +3426,19 @@ TclEvalObjvInternal(
cmdPtr, code, TCL_TRACE_ENTER_EXEC, objc, objv);
}
cmdPtr->refCount--;
- }
- if (cmdEpoch != cmdPtr->cmdEpoch) {
- /* The command has been modified in some way. */
- checkTraces = 0;
- goto reparseBecauseOfTraces;
+
+ /*
+ * If the traces modified/deleted the command or any existing traces,
+ * they will update the command's epoch. When that happens, set
+ * checkTraces is set to 0 to prevent the re-calling of traces (and
+ * any possible infinite loop) and we go back to re-find the command
+ * implementation.
+ */
+
+ if (cmdEpoch != cmdPtr->cmdEpoch) {
+ checkTraces = 0;
+ goto reparseBecauseOfTraces;
+ }
}
/*
@@ -3438,6 +3475,12 @@ TclEvalObjvInternal(
cmdPtr, code, TCL_TRACE_LEAVE_EXEC, objc, objv);
}
}
+
+ /*
+ * Decrement the reference count of cmdPtr and deallocate it if it has
+ * dropped to zero.
+ */
+
TclCleanupCommand(cmdPtr);
/*
@@ -3461,7 +3504,7 @@ TclEvalObjvInternal(
(void) Tcl_GetObjResult(interp);
}
- done:
+ done:
if (savedVarFramePtr) {
iPtr->varFramePtr = savedVarFramePtr;
}