summaryrefslogtreecommitdiffstats
path: root/generic/tkUndo.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tkUndo.c')
-rw-r--r--generic/tkUndo.c725
1 files changed, 518 insertions, 207 deletions
diff --git a/generic/tkUndo.c b/generic/tkUndo.c
index 81c8648..bf2ed7c 100644
--- a/generic/tkUndo.c
+++ b/generic/tkUndo.c
@@ -1,378 +1,689 @@
-/*
+/*
* tkUndo.c --
*
* This module provides the implementation of an undo stack.
*
* Copyright (c) 2002 by Ludwig Callewaert.
+ * Copyright (c) 2003-2004 by Vincent Darley.
*
- * 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 "tkInt.h"
#include "tkUndo.h"
+static int EvaluateActionList(Tcl_Interp *interp,
+ TkUndoSubAtom *action);
/*
- * TkUndoPushStack
- * Push elem on the stack identified by stack.
+ *----------------------------------------------------------------------
+ *
+ * TkUndoPushStack --
+ *
+ * Push elem on the stack identified by stack.
*
* Results:
- * None
+ * None.
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-void TkUndoPushStack ( stack, elem )
- TkUndoAtom ** stack;
- TkUndoAtom * elem;
-{
+
+void
+TkUndoPushStack(
+ TkUndoAtom **stack,
+ TkUndoAtom *elem)
+{
elem->next = *stack;
*stack = elem;
}
/*
+ *----------------------------------------------------------------------
+ *
* TkUndoPopStack --
- * Remove and return the top element from the stack identified by
- * stack.
+ *
+ * Remove and return the top element from the stack identified by stack.
*
* Results:
- * None
+ * None.
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-TkUndoAtom * TkUndoPopStack ( stack )
- TkUndoAtom ** stack ;
-{
- TkUndoAtom * elem = NULL;
- if (*stack != NULL ) {
- elem = *stack;
- *stack = elem->next;
+
+TkUndoAtom *
+TkUndoPopStack(
+ TkUndoAtom **stack)
+{
+ TkUndoAtom *elem = NULL;
+
+ if (*stack != NULL) {
+ elem = *stack;
+ *stack = elem->next;
}
return elem;
}
/*
+ *----------------------------------------------------------------------
+ *
* TkUndoInsertSeparator --
- * insert a separator on the stack, indicating a border for
- * an undo/redo chunk.
+ *
+ * Insert a separator on the stack, indicating a border for an undo/redo
+ * chunk.
*
* Results:
- * None
+ * None.
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-int TkUndoInsertSeparator ( stack )
- TkUndoAtom ** stack;
+
+int
+TkUndoInsertSeparator(
+ TkUndoAtom **stack)
{
- TkUndoAtom * separator;
-
- if ( *stack != NULL && (*stack)->type != TK_UNDO_SEPARATOR ) {
- separator = (TkUndoAtom *) ckalloc(sizeof(TkUndoAtom));
- separator->type = TK_UNDO_SEPARATOR;
- TkUndoPushStack(stack,separator);
- return 1;
- } else {
- return 0;
+ TkUndoAtom *separator;
+
+ if (*stack!=NULL && (*stack)->type!=TK_UNDO_SEPARATOR) {
+ separator = (TkUndoAtom *) ckalloc(sizeof(TkUndoAtom));
+ separator->type = TK_UNDO_SEPARATOR;
+ TkUndoPushStack(stack,separator);
+ return 1;
}
+ return 0;
}
/*
+ *----------------------------------------------------------------------
+ *
* TkUndoClearStack --
- * Clear an entire undo or redo stack and destroy all elements in it.
+ *
+ * Clear an entire undo or redo stack and destroy all elements in it.
*
* Results:
- * None
+ * None.
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-void TkUndoClearStack ( stack )
- TkUndoAtom ** stack; /* An Undo or Redo stack */
+void
+TkUndoClearStack(
+ TkUndoAtom **stack) /* An Undo or Redo stack */
{
- TkUndoAtom * elem;
-
- while ( (elem = TkUndoPopStack(stack)) ) {
- if ( elem->type != TK_UNDO_SEPARATOR ) {
- Tcl_DecrRefCount(elem->apply);
- Tcl_DecrRefCount(elem->revert);
- }
- ckfree((char *)elem);
+ TkUndoAtom *elem;
+
+ while ((elem = TkUndoPopStack(stack)) != NULL) {
+ if (elem->type != TK_UNDO_SEPARATOR) {
+ TkUndoSubAtom *sub;
+
+ sub = elem->apply;
+ while (sub != NULL) {
+ TkUndoSubAtom *next = sub->next;
+
+ if (sub->action != NULL) {
+ Tcl_DecrRefCount(sub->action);
+ }
+ ckfree((char *)sub);
+ sub = next;
+ }
+
+ sub = elem->revert;
+ while (sub != NULL) {
+ TkUndoSubAtom *next = sub->next;
+
+ if (sub->action != NULL) {
+ Tcl_DecrRefCount(sub->action);
+ }
+ ckfree((char *)sub);
+ sub = next;
+ }
+ }
+ ckfree((char *)elem);
}
*stack = NULL;
}
/*
- * TkUndoPushAction
- * Push a new elem on the stack identified by stack.
- * action and revert are given through Tcl_DStrings
+ *----------------------------------------------------------------------
+ *
+ * TkUndoPushAction --
+ *
+ * Push a new elem on the stack identified by stack. Action and revert
+ * are given through Tcl_Obj's to which we will retain a reference. (So
+ * they can be passed in with a zero refCount if desired).
*
* Results:
- * None
+ * None.
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-void TkUndoPushAction ( stack, actionScript, revertScript )
- TkUndoRedoStack * stack; /* An Undo or Redo stack */
- Tcl_DString * actionScript; /* The script to get the action (redo) */
- Tcl_DString * revertScript; /* The script to revert the action (undo) */
-{
- TkUndoAtom * atom;
+
+void
+TkUndoPushAction(
+ TkUndoRedoStack *stack, /* An Undo or Redo stack */
+ TkUndoSubAtom *apply,
+ TkUndoSubAtom *revert)
+{
+ TkUndoAtom *atom;
atom = (TkUndoAtom *) ckalloc(sizeof(TkUndoAtom));
atom->type = TK_UNDO_ACTION;
+ atom->apply = apply;
+ atom->revert = revert;
- atom->apply = Tcl_NewStringObj(Tcl_DStringValue(actionScript),Tcl_DStringLength(actionScript));
- Tcl_IncrRefCount(atom->apply);
+ TkUndoPushStack(&stack->undoStack, atom);
+ TkUndoClearStack(&stack->redoStack);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkUndoMakeCmdSubAtom --
+ *
+ * Create a new undo/redo step which must later be place into an undo
+ * stack with TkUndoPushAction. This sub-atom, if evaluated, will take
+ * the given command (if non-NULL), find its full Tcl command string, and
+ * then evaluate that command with the list elements of 'actionScript'
+ * appended.
+ *
+ * If 'subAtomList' is non-NULL, the newly created sub-atom is added onto
+ * the end of the linked list of which 'subAtomList' is a part. This
+ * makes it easy to build up a sequence of actions which will be pushed
+ * in one step.
+ *
+ * Note: if the undo stack can persist for longer than the Tcl_Command
+ * provided, the stack will cause crashes when actions are evaluated. In
+ * this case the 'command' argument should not be used. This is the case
+ * with peer text widgets, for example.
+ *
+ * Results:
+ * The newly created subAtom is returned. It must be passed to
+ * TkUndoPushAction otherwise a memory leak will result.
+ *
+ * Side effects:
+ * A refCount is retained on 'actionScript'.
+ *
+ *----------------------------------------------------------------------
+ */
+
+TkUndoSubAtom *
+TkUndoMakeCmdSubAtom(
+ Tcl_Command command, /* Tcl command token for actions, may be NULL
+ * if not needed. */
+ Tcl_Obj *actionScript, /* The script to append to the command to
+ * perform the action (may be NULL if the
+ * command is not-null). */
+ TkUndoSubAtom *subAtomList) /* Add to the end of this list of actions if
+ * non-NULL */
+{
+ TkUndoSubAtom *atom;
- atom->revert = Tcl_NewStringObj(Tcl_DStringValue(revertScript),Tcl_DStringLength(revertScript));
- Tcl_IncrRefCount(atom->revert);
+ if (command == NULL && actionScript == NULL) {
+ Tcl_Panic("NULL command and actionScript in TkUndoMakeCmdSubAtom");
+ }
- TkUndoPushStack(&(stack->undoStack), atom);
- TkUndoClearStack(&(stack->redoStack));
+ atom = (TkUndoSubAtom *) ckalloc(sizeof(TkUndoSubAtom));
+ atom->command = command;
+ atom->funcPtr = NULL;
+ atom->clientData = NULL;
+ atom->next = NULL;
+ atom->action = actionScript;
+ if (atom->action != NULL) {
+ Tcl_IncrRefCount(atom->action);
+ }
+
+ if (subAtomList != NULL) {
+ while (subAtomList->next != NULL) {
+ subAtomList = subAtomList->next;
+ }
+ subAtomList->next = atom;
+ }
+ return atom;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkUndoMakeSubAtom --
+ *
+ * Create a new undo/redo step which must later be place into an undo
+ * stack with TkUndoPushAction. This sub-atom, if evaluated, will take
+ * the given C-funcPtr (which must be non-NULL), and call it with three
+ * arguments: the undo stack's 'interp', the 'clientData' given and the
+ * 'actionScript'. The callback should return a standard Tcl return code
+ * (TCL_OK on success).
+ *
+ * If 'subAtomList' is non-NULL, the newly created sub-atom is added onto
+ * the end of the linked list of which 'subAtomList' is a part. This
+ * makes it easy to build up a sequence of actions which will be pushed
+ * in one step.
+ *
+ * Results:
+ * The newly created subAtom is returned. It must be passed to
+ * TkUndoPushAction otherwise a memory leak will result.
+ *
+ * Side effects:
+ * A refCount is retained on 'actionScript'.
+ *
+ *----------------------------------------------------------------------
+ */
+
+TkUndoSubAtom *
+TkUndoMakeSubAtom(
+ TkUndoProc *funcPtr, /* Callback function to perform the
+ * undo/redo. */
+ ClientData clientData, /* Data to pass to the callback function. */
+ Tcl_Obj *actionScript, /* Additional Tcl data to pass to the callback
+ * function (may be NULL). */
+ TkUndoSubAtom *subAtomList) /* Add to the end of this list of actions if
+ * non-NULL */
+{
+ TkUndoSubAtom *atom;
+ if (funcPtr == NULL) {
+ Tcl_Panic("NULL funcPtr in TkUndoMakeSubAtom");
+ }
+
+ atom = (TkUndoSubAtom *) ckalloc(sizeof(TkUndoSubAtom));
+ atom->command = NULL;
+ atom->funcPtr = funcPtr;
+ atom->clientData = clientData;
+ atom->next = NULL;
+ atom->action = actionScript;
+ if (atom->action != NULL) {
+ Tcl_IncrRefCount(atom->action);
+ }
+
+ if (subAtomList != NULL) {
+ while (subAtomList->next != NULL) {
+ subAtomList = subAtomList->next;
+ }
+ subAtomList->next = atom;
+ }
+ return atom;
+}
/*
- * TkUndoInitStack
- * Initialize a new undo/redo stack
+ *----------------------------------------------------------------------
+ *
+ * TkUndoInitStack --
+ *
+ * Initialize a new undo/redo stack.
*
* Results:
- * un Undo/Redo stack pointer
+ * An Undo/Redo stack pointer.
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-TkUndoRedoStack * TkUndoInitStack ( interp, maxdepth )
- Tcl_Interp * interp; /* The interpreter */
- int maxdepth; /* The maximum stack depth */
-{
- TkUndoRedoStack * stack; /* An Undo/Redo stack */
+
+TkUndoRedoStack *
+TkUndoInitStack(
+ Tcl_Interp *interp, /* The interpreter */
+ int maxdepth) /* The maximum stack depth */
+{
+ TkUndoRedoStack *stack; /* An Undo/Redo stack */
+
stack = (TkUndoRedoStack *) ckalloc(sizeof(TkUndoRedoStack));
stack->undoStack = NULL;
stack->redoStack = NULL;
- stack->interp = interp;
- stack->maxdepth = maxdepth;
- stack->depth = 0;
+ stack->interp = interp;
+ stack->maxdepth = maxdepth;
+ stack->depth = 0;
return stack;
}
-
/*
- * TkUndoInitStack
- * Initialize a new undo/redo stack
+ *----------------------------------------------------------------------
+ *
+ * TkUndoSetDepth --
+ *
+ * Set the maximum depth of stack.
*
* Results:
- * un Undo/Redo stack pointer
+ * None.
*
* Side effects:
- * None.
+ * May delete elements from the stack if the new maximum depth is smaller
+ * than the number of elements previously in the stack.
+ *
+ *----------------------------------------------------------------------
*/
-
-void TkUndoSetDepth ( stack, maxdepth )
- TkUndoRedoStack * stack; /* An Undo/Redo stack */
- int maxdepth; /* The maximum stack depth */
+
+void
+TkUndoSetDepth(
+ TkUndoRedoStack *stack, /* An Undo/Redo stack */
+ int maxdepth) /* The maximum stack depth */
{
- TkUndoAtom * elem;
- TkUndoAtom * prevelem;
- int sepNumber = 0;
-
stack->maxdepth = maxdepth;
- if ((stack->maxdepth > 0) && (stack->depth > stack->maxdepth)) {
- /*
+ if (stack->maxdepth>0 && stack->depth>stack->maxdepth) {
+ TkUndoAtom *elem, *prevelem;
+ int sepNumber = 0;
+
+ /*
* Maximum stack depth exceeded. We have to remove the last compound
* elements on the stack.
*/
- elem = stack->undoStack;
- prevelem = NULL;
- while (elem && (sepNumber <= stack->maxdepth)) {
- if (elem->type == TK_UNDO_SEPARATOR) {
- sepNumber++;
- }
- prevelem = elem;
- elem = elem->next;
- }
- prevelem->next = NULL;
- while ( elem ) {
- prevelem = elem;
- elem = elem->next;
- ckfree((char *) prevelem);
- }
- stack->depth = stack->maxdepth;
+ elem = stack->undoStack;
+ prevelem = NULL;
+ while ((elem != NULL) && (sepNumber <= stack->maxdepth)) {
+ if (elem->type == TK_UNDO_SEPARATOR) {
+ sepNumber++;
+ }
+ prevelem = elem;
+ elem = elem->next;
+ }
+ prevelem->next = NULL;
+ while (elem != NULL) {
+ prevelem = elem;
+ if (elem->type != TK_UNDO_SEPARATOR) {
+ TkUndoSubAtom *sub = elem->apply;
+ while (sub != NULL) {
+ TkUndoSubAtom *next = sub->next;
+
+ if (sub->action != NULL) {
+ Tcl_DecrRefCount(sub->action);
+ }
+ ckfree((char *)sub);
+ sub = next;
+ }
+ sub = elem->revert;
+ while (sub != NULL) {
+ TkUndoSubAtom *next = sub->next;
+
+ if (sub->action != NULL) {
+ Tcl_DecrRefCount(sub->action);
+ }
+ ckfree((char *)sub);
+ sub = next;
+ }
+ }
+ elem = elem->next;
+ ckfree((char *) prevelem);
+ }
+ stack->depth = stack->maxdepth;
}
}
-
/*
- * TkUndoClearStacks
- * Clear both the undo and redo stack
+ *----------------------------------------------------------------------
+ *
+ * TkUndoClearStacks --
+ *
+ * Clear both the undo and redo stack.
*
* Results:
- * None
+ * None.
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-void TkUndoClearStacks ( stack )
- TkUndoRedoStack * stack; /* An Undo/Redo stack */
-{
- TkUndoClearStack(&(stack->undoStack));
- TkUndoClearStack(&(stack->redoStack));
+
+void
+TkUndoClearStacks(
+ TkUndoRedoStack *stack) /* An Undo/Redo stack */
+{
+ TkUndoClearStack(&stack->undoStack);
+ TkUndoClearStack(&stack->redoStack);
stack->depth = 0;
}
-
/*
+ *----------------------------------------------------------------------
+ *
* TkUndoFreeStack
- * Clear both the undo and redo stack
- * also free the memory allocated to the u/r stack pointer
+ *
+ * Clear both the undo and redo stack and free the memory allocated to
+ * the u/r stack pointer.
*
* Results:
- * None
+ * None.
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-void TkUndoFreeStack ( stack )
- TkUndoRedoStack * stack; /* An Undo/Redo stack */
-{
- TkUndoClearStacks(stack);
-/* ckfree((TkUndoRedoStack *) stack); */
- ckfree((char *) stack);
-}
+void
+TkUndoFreeStack(
+ TkUndoRedoStack *stack) /* An Undo/Redo stack */
+{
+ TkUndoClearStacks(stack);
+ ckfree((char *) stack);
+}
/*
+ *----------------------------------------------------------------------
+ *
* TkUndoInsertUndoSeparator --
- * insert a separator on the undo stack, indicating a border for
- * an undo/redo chunk.
+ *
+ * Insert a separator on the undo stack, indicating a border for an
+ * undo/redo chunk.
*
* Results:
- * None
+ * None.
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-void TkUndoInsertUndoSeparator ( stack )
- TkUndoRedoStack * stack;
+
+void
+TkUndoInsertUndoSeparator(
+ TkUndoRedoStack *stack)
{
- if ( TkUndoInsertSeparator(&(stack->undoStack)) ) {
- ++(stack->depth);
- TkUndoSetDepth(stack,stack->maxdepth);
+ if (TkUndoInsertSeparator(&stack->undoStack)) {
+ stack->depth++;
+ TkUndoSetDepth(stack, stack->maxdepth);
}
}
-
/*
+ *----------------------------------------------------------------------
+ *
* TkUndoRevert --
- * Undo a compound action on the stack.
+ *
+ * Undo a compound action on the stack.
*
* Results:
- * A TCL status code
+ * A Tcl status code
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-int TkUndoRevert ( stack )
- TkUndoRedoStack * stack;
+
+int
+TkUndoRevert(
+ TkUndoRedoStack *stack)
{
- TkUndoAtom * elem;
+ TkUndoAtom *elem;
- /* insert a separator on the undo and the redo stack */
+ /*
+ * Insert a separator on the undo and the redo stack.
+ */
TkUndoInsertUndoSeparator(stack);
- TkUndoInsertSeparator(&(stack->redoStack));
-
- /* Pop and skip the first separator if there is one*/
+ TkUndoInsertSeparator(&stack->redoStack);
- elem = TkUndoPopStack(&(stack->undoStack));
+ /*
+ * Pop and skip the first separator if there is one.
+ */
- if ( elem == NULL ) {
- return TCL_ERROR;
+ elem = TkUndoPopStack(&stack->undoStack);
+ if (elem == NULL) {
+ return TCL_ERROR;
}
- if ( ( elem != NULL ) && ( elem->type == TK_UNDO_SEPARATOR ) ) {
- ckfree((char *) elem);
- elem = TkUndoPopStack(&(stack->undoStack));
+ if (elem->type == TK_UNDO_SEPARATOR) {
+ ckfree((char *) elem);
+ elem = TkUndoPopStack(&stack->undoStack);
}
-
- while ( elem && (elem->type != TK_UNDO_SEPARATOR) ) {
- Tcl_EvalObjEx(stack->interp,elem->revert,TCL_EVAL_GLOBAL);
-
- TkUndoPushStack(&(stack->redoStack),elem);
- elem = TkUndoPopStack(&(stack->undoStack));
+
+ while (elem != NULL && elem->type != TK_UNDO_SEPARATOR) {
+ /*
+ * Note that we currently ignore errors thrown here.
+ */
+
+ EvaluateActionList(stack->interp, elem->revert);
+
+ TkUndoPushStack(&stack->redoStack, elem);
+ elem = TkUndoPopStack(&stack->undoStack);
}
-
- /* insert a separator on the redo stack */
-
- TkUndoInsertSeparator(&(stack->redoStack));
-
- --(stack->depth);
-
+
+ /*
+ * Insert a separator on the redo stack.
+ */
+
+ TkUndoInsertSeparator(&stack->redoStack);
+ stack->depth--;
return TCL_OK;
}
-
/*
+ *----------------------------------------------------------------------
+ *
* TkUndoApply --
- * Redo a compound action on the stack.
+ *
+ * Redo a compound action on the stack.
*
* Results:
- * A TCL status code
+ * A Tcl status code
*
* Side effects:
- * None.
+ * None.
+ *
+ *----------------------------------------------------------------------
*/
-
-int TkUndoApply ( stack )
- TkUndoRedoStack * stack;
+
+int
+TkUndoApply(
+ TkUndoRedoStack *stack)
{
TkUndoAtom *elem;
- /* insert a separator on the undo stack */
+ /*
+ * Insert a separator on the undo stack.
+ */
- TkUndoInsertSeparator(&(stack->undoStack));
+ TkUndoInsertSeparator(&stack->undoStack);
- /* Pop and skip the first separator if there is one*/
+ /*
+ * Pop and skip the first separator if there is one.
+ */
- elem = TkUndoPopStack(&(stack->redoStack));
-
- if ( elem == NULL ) {
- return TCL_ERROR;
+ elem = TkUndoPopStack(&stack->redoStack);
+ if (elem == NULL) {
+ return TCL_ERROR;
}
- if ( ( elem != NULL ) && ( elem->type == TK_UNDO_SEPARATOR ) ) {
- ckfree((char *) elem);
- elem = TkUndoPopStack(&(stack->redoStack));
+ if (elem->type == TK_UNDO_SEPARATOR) {
+ ckfree((char *) elem);
+ elem = TkUndoPopStack(&stack->redoStack);
}
- while ( elem && (elem->type != TK_UNDO_SEPARATOR) ) {
- Tcl_EvalObjEx(stack->interp,elem->apply,TCL_EVAL_GLOBAL);
-
- TkUndoPushStack(&(stack->undoStack), elem);
- elem = TkUndoPopStack(&(stack->redoStack));
+ while (elem != NULL && elem->type != TK_UNDO_SEPARATOR) {
+ /*
+ * Note that we currently ignore errors thrown here.
+ */
+
+ EvaluateActionList(stack->interp, elem->apply);
+
+ TkUndoPushStack(&stack->undoStack, elem);
+ elem = TkUndoPopStack(&stack->redoStack);
}
- /* insert a separator on the undo stack */
-
- TkUndoInsertSeparator(&(stack->undoStack));
+ /*
+ * Insert a separator on the undo stack.
+ */
- ++(stack->depth);
-
+ TkUndoInsertSeparator(&stack->undoStack);
+ stack->depth++;
return TCL_OK;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * EvaluateActionList --
+ *
+ * Execute a linked list of undo/redo sub-atoms. If any sub-atom returns
+ * a non TCL_OK value, execution of subsequent sub-atoms is cancelled and
+ * the error returned immediately.
+ *
+ * Results:
+ * A Tcl status code
+ *
+ * Side effects:
+ * The undo/redo subAtoms can perform arbitrary actions.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+EvaluateActionList(
+ Tcl_Interp *interp, /* Interpreter to evaluate the action in. */
+ TkUndoSubAtom *action) /* Head of linked list of action steps to
+ * perform. */
+{
+ int result = TCL_OK;
+
+ while (action != NULL) {
+ if (action->funcPtr != NULL) {
+ result = (*action->funcPtr)(interp, action->clientData,
+ action->action);
+ } else if (action->command != NULL) {
+ Tcl_Obj *cmdNameObj, *evalObj;
+
+ cmdNameObj = Tcl_NewObj();
+ evalObj = Tcl_NewObj();
+ Tcl_IncrRefCount(evalObj);
+ Tcl_GetCommandFullName(interp, action->command, cmdNameObj);
+ Tcl_ListObjAppendElement(NULL, evalObj, cmdNameObj);
+ if (action->action != NULL) {
+ Tcl_ListObjAppendList(NULL, evalObj, action->action);
+ }
+ result = Tcl_EvalObjEx(interp, evalObj, TCL_EVAL_GLOBAL);
+ Tcl_DecrRefCount(evalObj);
+ } else {
+ result = Tcl_EvalObjEx(interp, action->action, TCL_EVAL_GLOBAL);
+ }
+ if (result != TCL_OK) {
+ return result;
+ }
+ action = action->next;
+ }
+ return result;
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */