diff options
Diffstat (limited to 'generic/tclHistory.c')
-rw-r--r-- | generic/tclHistory.c | 167 |
1 files changed, 126 insertions, 41 deletions
diff --git a/generic/tclHistory.c b/generic/tclHistory.c index 5f2a9f2..b10d423 100644 --- a/generic/tclHistory.c +++ b/generic/tclHistory.c @@ -1,4 +1,4 @@ -/* +/* * tclHistory.c -- * * This module and the Tcl library file history.tcl together implement @@ -9,15 +9,29 @@ * Copyright (c) 1990-1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclHistory.c,v 1.3 1999/04/16 00:46:47 stanton Exp $ + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" -#include "tclPort.h" +/* + * Type of the assocData structure used to hold the reference to the [history + * add] subcommand, used in Tcl_RecordAndEvalObj. + */ + +typedef struct { + Tcl_Obj *historyObj; /* == "::history" */ + Tcl_Obj *addObj; /* == "add" */ +} HistoryObjs; + +#define HISTORY_OBJS_KEY "::tcl::HistoryObjs" + +/* + * Static functions in this file. + */ + +static Tcl_InterpDeleteProc DeleteHistoryObjs; /* *---------------------------------------------------------------------- @@ -25,8 +39,7 @@ * Tcl_RecordAndEval -- * * This procedure adds its command argument to the current list of - * recorded events and then executes the command by calling - * Tcl_Eval. + * recorded events and then executes the command by calling Tcl_Eval. * * Results: * The return value is a standard Tcl return value, the result of @@ -39,12 +52,12 @@ */ int -Tcl_RecordAndEval(interp, cmd, flags) - Tcl_Interp *interp; /* Token for interpreter in which command - * will be executed. */ - char *cmd; /* Command to record. */ - int flags; /* Additional flags. TCL_NO_EVAL means - * only record: don't execute command. +Tcl_RecordAndEval( + Tcl_Interp *interp, /* Token for interpreter in which command will + * be executed. */ + const char *cmd, /* Command to record. */ + int flags) /* Additional flags. TCL_NO_EVAL means only + * record: don't execute command. * TCL_EVAL_GLOBAL means use Tcl_GlobalEval * instead of Tcl_Eval. */ { @@ -62,18 +75,17 @@ Tcl_RecordAndEval(interp, cmd, flags) result = Tcl_RecordAndEvalObj(interp, cmdPtr, flags); /* - * Move the interpreter's object result to the string result, - * then reset the object result. + * Move the interpreter's object result to the string result, then + * reset the object result. */ - Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), - TCL_VOLATILE); + (void) Tcl_GetStringResult(interp); /* * Discard the Tcl object created to hold the command. */ - - Tcl_DecrRefCount(cmdPtr); + + Tcl_DecrRefCount(cmdPtr); } else { /* * An empty string. Just reset the interpreter's result. @@ -105,33 +117,69 @@ Tcl_RecordAndEval(interp, cmd, flags) */ int -Tcl_RecordAndEvalObj(interp, cmdPtr, flags) - Tcl_Interp *interp; /* Token for interpreter in which command - * will be executed. */ - Tcl_Obj *cmdPtr; /* Points to object holding the command to +Tcl_RecordAndEvalObj( + Tcl_Interp *interp, /* Token for interpreter in which command will + * be executed. */ + Tcl_Obj *cmdPtr, /* Points to object holding the command to * record and execute. */ - int flags; /* Additional flags. TCL_NO_EVAL means - * record only: don't execute the command. - * TCL_EVAL_GLOBAL means evaluate the - * script in global variable context instead - * of the current procedure. */ + int flags) /* Additional flags. TCL_NO_EVAL means record + * only: don't execute the command. + * TCL_EVAL_GLOBAL means evaluate the script + * in global variable context instead of the + * current procedure. */ { - int result; - Tcl_Obj *list[3]; - register Tcl_Obj *objPtr; + int result, call = 1; + Tcl_CmdInfo info; + HistoryObjs *histObjsPtr = + Tcl_GetAssocData(interp, HISTORY_OBJS_KEY, NULL); /* - * Do recording by eval'ing a tcl history command: history add $cmd. + * Create the references to the [::history add] command if necessary. */ - list[0] = Tcl_NewStringObj("history", -1); - list[1] = Tcl_NewStringObj("add", -1); - list[2] = cmdPtr; - - objPtr = Tcl_NewListObj(3, list); - Tcl_IncrRefCount(objPtr); - (void) Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_GLOBAL); - Tcl_DecrRefCount(objPtr); + if (histObjsPtr == NULL) { + histObjsPtr = ckalloc(sizeof(HistoryObjs)); + TclNewLiteralStringObj(histObjsPtr->historyObj, "::history"); + TclNewLiteralStringObj(histObjsPtr->addObj, "add"); + Tcl_IncrRefCount(histObjsPtr->historyObj); + Tcl_IncrRefCount(histObjsPtr->addObj); + Tcl_SetAssocData(interp, HISTORY_OBJS_KEY, DeleteHistoryObjs, + histObjsPtr); + } + + /* + * Do not call [history] if it has been replaced by an empty proc + */ + + result = Tcl_GetCommandInfo(interp, "::history", &info); + if (result && (info.deleteProc == TclProcDeleteProc)) { + Proc *procPtr = (Proc *) info.objClientData; + call = (procPtr->cmdPtr->compileProc != TclCompileNoOp); + } + + if (call) { + Tcl_Obj *list[3]; + + /* + * Do recording by eval'ing a tcl history command: history add $cmd. + */ + + list[0] = histObjsPtr->historyObj; + list[1] = histObjsPtr->addObj; + list[2] = cmdPtr; + + Tcl_IncrRefCount(cmdPtr); + (void) Tcl_EvalObjv(interp, 3, list, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(cmdPtr); + + /* + * One possible failure mode above: exceeding a resource limit. + */ + + if (Tcl_LimitExceeded(interp)) { + return TCL_ERROR; + } + } /* * Execute the command. @@ -143,3 +191,40 @@ Tcl_RecordAndEvalObj(interp, cmdPtr, flags) } return result; } + +/* + *---------------------------------------------------------------------- + * + * DeleteHistoryObjs -- + * + * Called to delete the references to the constant words used when adding + * to the history. + * + * Results: + * None. + * + * Side effects: + * The constant words may be deleted. + * + *---------------------------------------------------------------------- + */ + +static void +DeleteHistoryObjs( + ClientData clientData, + Tcl_Interp *interp) +{ + register HistoryObjs *histObjsPtr = clientData; + + TclDecrRefCount(histObjsPtr->historyObj); + TclDecrRefCount(histObjsPtr->addObj); + ckfree(histObjsPtr); +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |