Blame exp_trap.c

Packit a69f91
/* exp_trap.c - Expect's trap command
Packit a69f91
Packit a69f91
Written by: Don Libes, NIST, 9/1/93
Packit a69f91
Packit a69f91
Design and implementation of this program was paid for by U.S. tax
Packit a69f91
dollars.  Therefore it is public domain.  However, the author and NIST
Packit a69f91
would appreciate credit if this program or parts of it are used.
Packit a69f91
Packit a69f91
*/
Packit a69f91
Packit a69f91
#include "expect_cf.h"
Packit a69f91
Packit a69f91
#include <stdio.h>
Packit a69f91
#include <signal.h>
Packit a69f91
#include <sys/types.h>
Packit a69f91
Packit a69f91
#ifdef HAVE_SYS_WAIT_H
Packit a69f91
#include <sys/wait.h>
Packit a69f91
#endif
Packit a69f91
#ifdef HAVE_STRING_H
Packit a69f91
#include <string.h>
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#if defined(SIGCLD) && !defined(SIGCHLD)
Packit a69f91
#define SIGCHLD SIGCLD
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#include "tcl.h"
Packit a69f91
Packit a69f91
#include "exp_rename.h"
Packit a69f91
#include "exp_prog.h"
Packit a69f91
#include "exp_command.h"
Packit a69f91
#include "exp_log.h"
Packit a69f91
Packit a69f91
#ifdef TCL_DEBUGGER
Packit a69f91
#include "tcldbg.h"
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#define NO_SIG 0
Packit a69f91
Packit a69f91
static struct trap {
Packit a69f91
	char *action;		/* Tcl command to execute upon sig */
Packit a69f91
				/* Each is handled by the eval_trap_action */
Packit a69f91
	int mark;		/* TRUE if signal has occurred */
Packit a69f91
	Tcl_Interp *interp;	/* interp to use or 0 if we should use the */
Packit a69f91
				/* interpreter active at the time the sig */
Packit a69f91
				/* is processed */
Packit a69f91
	int code;		/* return our new code instead of code */
Packit a69f91
				/* available when signal is processed */
Packit a69f91
	CONST char *name;	/* name of signal */
Packit a69f91
	int reserved;		/* if unavailable for trapping */
Packit a69f91
} traps[NSIG];
Packit a69f91
Packit a69f91
int sigchld_count = 0;	/* # of sigchlds caught but not yet processed */
Packit a69f91
Packit a69f91
static int eval_trap_action();
Packit a69f91
Packit a69f91
static int got_sig;		/* this records the last signal received */
Packit a69f91
				/* it is only a hint and can be wiped out */
Packit a69f91
				/* by multiple signals, but it will always */
Packit a69f91
				/* be left with a valid signal that is */
Packit a69f91
				/* pending */
Packit a69f91
Packit a69f91
static Tcl_AsyncHandler async_handler;
Packit a69f91
Packit a69f91
static CONST char *
Packit a69f91
signal_to_string(sig)
Packit a69f91
int sig;
Packit a69f91
{
Packit a69f91
	if (sig <= 0 || sig > NSIG) return("SIGNAL OUT OF RANGE");
Packit a69f91
	return(traps[sig].name);
Packit a69f91
}
Packit a69f91
Packit a69f91
/* current sig being processed by user sig handler */
Packit a69f91
static int current_sig = NO_SIG;
Packit a69f91
Packit a69f91
int exp_nostack_dump = FALSE;	/* TRUE if user has requested unrolling of */
Packit a69f91
				/* stack with no trace */
Packit a69f91
Packit a69f91
Packit a69f91
Packit a69f91
/*ARGSUSED*/
Packit a69f91
static int
Packit a69f91
tophalf(clientData,interp,code)
Packit a69f91
ClientData clientData;
Packit a69f91
Tcl_Interp *interp;
Packit a69f91
int code;
Packit a69f91
{
Packit a69f91
	struct trap *trap;	/* last trap processed */
Packit a69f91
	int rc;
Packit a69f91
	int i;
Packit a69f91
	Tcl_Interp *sig_interp;
Packit a69f91
Packit a69f91
	expDiagLog("sighandler: handling signal(%d)\r\n",got_sig);
Packit a69f91
Packit a69f91
	if (got_sig <= 0 || got_sig >= NSIG) {
Packit a69f91
		expErrorLog("caught impossible signal %d\r\n",got_sig);
Packit a69f91
		abort();
Packit a69f91
	}
Packit a69f91
Packit a69f91
	/* start to work on this sig.  got_sig can now be overwritten */
Packit a69f91
	/* and it won't cause a problem */
Packit a69f91
	current_sig = got_sig;
Packit a69f91
	trap = &traps[current_sig];
Packit a69f91
Packit a69f91
	trap->mark = FALSE;
Packit a69f91
Packit a69f91
	/* decrement below looks dangerous */
Packit a69f91
	/* Don't we need to temporarily block bottomhalf? */
Packit a69f91
	if (current_sig == SIGCHLD) {
Packit a69f91
		sigchld_count--;
Packit a69f91
		expDiagLog("sigchld_count-- == %d\n",sigchld_count);
Packit a69f91
	}
Packit a69f91
Packit a69f91
	if (!trap->action) {
Packit a69f91
		/* In this one case, we let ourselves be called when no */
Packit a69f91
		/* signaler predefined, since we are calling explicitly */
Packit a69f91
		/* from another part of the program, and it is just simpler */
Packit a69f91
		if (current_sig == 0) return code;
Packit a69f91
		expErrorLog("caught unexpected signal: %s (%d)\r\n",
Packit a69f91
			signal_to_string(current_sig),current_sig);
Packit a69f91
		abort();
Packit a69f91
	}
Packit a69f91
Packit a69f91
	if (trap->interp) {
Packit a69f91
		/* if trap requested original interp, use it */
Packit a69f91
		sig_interp = trap->interp;
Packit a69f91
	} else if (interp) {
Packit a69f91
		/* else if another interp is available, use it */
Packit a69f91
		sig_interp = interp;
Packit a69f91
	} else {
Packit a69f91
		/* fall back to exp_interp */
Packit a69f91
		sig_interp = exp_interp;
Packit a69f91
	}
Packit a69f91
Packit a69f91
	rc = eval_trap_action(sig_interp,current_sig,trap,code);
Packit a69f91
	current_sig = NO_SIG;
Packit a69f91
Packit a69f91
	/*
Packit a69f91
	 * scan for more signals to process
Packit a69f91
	 */
Packit a69f91
Packit a69f91
	/* first check for additional SIGCHLDs */
Packit a69f91
	if (sigchld_count) {
Packit a69f91
		got_sig = SIGCHLD;
Packit a69f91
		traps[SIGCHLD].mark = TRUE;
Packit a69f91
		Tcl_AsyncMark(async_handler);
Packit a69f91
	} else {
Packit a69f91
		got_sig = -1;
Packit a69f91
		for (i=1;i
Packit a69f91
			if (traps[i].mark) {
Packit a69f91
				got_sig = i;
Packit a69f91
				Tcl_AsyncMark(async_handler);
Packit a69f91
				break;
Packit a69f91
			}
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
	return rc;
Packit a69f91
}
Packit a69f91
Packit a69f91
#ifdef REARM_SIG
Packit a69f91
int sigchld_sleep;
Packit a69f91
static int rearm_sigchld = FALSE;	/* TRUE if sigchld needs to be */
Packit a69f91
					/* rearmed (i.e., because it has */
Packit a69f91
					/* just gone off) */
Packit a69f91
static int rearming_sigchld = FALSE;
Packit a69f91
#endif
Packit a69f91
Packit a69f91
/* called upon receipt of a user-declared signal */
Packit a69f91
static void
Packit a69f91
bottomhalf(sig)
Packit a69f91
int sig;
Packit a69f91
{
Packit a69f91
#ifdef REARM_SIG
Packit a69f91
	/*
Packit a69f91
	 * tiny window of death if same signal should arrive here
Packit a69f91
	 * before we've reinstalled it
Packit a69f91
	 */
Packit a69f91
Packit a69f91
	/* In SV, sigchld must be rearmed after wait to avoid recursion */
Packit a69f91
	if (sig != SIGCHLD) {
Packit a69f91
		signal(sig,bottomhalf);
Packit a69f91
	} else {
Packit a69f91
		/* request rearm */
Packit a69f91
		rearm_sigchld = TRUE;
Packit a69f91
		if (rearming_sigchld) sigchld_sleep = TRUE;
Packit a69f91
	}
Packit a69f91
#endif
Packit a69f91
Packit a69f91
	traps[sig].mark = TRUE;
Packit a69f91
	got_sig = sig;		/* just a hint - can be wiped out by another */
Packit a69f91
	Tcl_AsyncMark(async_handler);
Packit a69f91
Packit a69f91
	/* if we are called while this particular async is being processed */
Packit a69f91
	/* original async_proc will turn off "mark" so that when async_proc */
Packit a69f91
	/* is recalled, it will see that nothing was left to do */
Packit a69f91
Packit a69f91
	/* In case of SIGCHLD though, we must recall it as many times as
Packit a69f91
	 * we have received it.
Packit a69f91
	 */
Packit a69f91
	if (sig == SIGCHLD) {
Packit a69f91
		sigchld_count++;
Packit a69f91
	}
Packit a69f91
#if 0
Packit a69f91
	/* if we are doing an i_read, restart it */
Packit a69f91
#ifdef HAVE_SIGLONGJMP
Packit a69f91
      if (env_valid && (sig != 0)) siglongjmp(env,2);
Packit a69f91
#else
Packit a69f91
      if (env_valid && (sig != 0)) longjmp(env,2);
Packit a69f91
#endif  /* HAVE_SIGLONGJMP */
Packit a69f91
#endif /* 0 */
Packit a69f91
}
Packit a69f91
Packit a69f91
/*ARGSUSED*/
Packit a69f91
void
Packit a69f91
exp_rearm_sigchld(interp)
Packit a69f91
Tcl_Interp *interp;
Packit a69f91
{
Packit a69f91
#ifdef REARM_SIG
Packit a69f91
	if (rearm_sigchld) {
Packit a69f91
		rearm_sigchld = FALSE;
Packit a69f91
		rearming_sigchld = TRUE;
Packit a69f91
		signal(SIGCHLD,bottomhalf);
Packit a69f91
	}
Packit a69f91
Packit a69f91
	rearming_sigchld = FALSE;
Packit a69f91
Packit a69f91
	/* if the rearming immediately caused another SIGCHLD, slow down */
Packit a69f91
	/* It's probably one of Tcl's intermediary pipeline processes that */
Packit a69f91
	/* Tcl hasn't caught up with yet. */
Packit a69f91
	if (sigchld_sleep) {
Packit a69f91
		exp_dsleep(interp,0.2);
Packit a69f91
		sigchld_sleep = FALSE;
Packit a69f91
	}
Packit a69f91
#endif
Packit a69f91
}
Packit a69f91
Packit a69f91
Packit a69f91
void
Packit a69f91
exp_init_trap()
Packit a69f91
{
Packit a69f91
	int i;
Packit a69f91
Packit a69f91
	for (i=1;i
Packit a69f91
		traps[i].name = Tcl_SignalId(i);
Packit a69f91
		traps[i].action = 0;
Packit a69f91
		traps[i].reserved = FALSE;
Packit a69f91
	}
Packit a69f91
Packit a69f91
	/*
Packit a69f91
	 * fix up any special cases
Packit a69f91
	 */
Packit a69f91
Packit a69f91
#if defined(SIGCLD)
Packit a69f91
	/* Tcl names it SIGCLD, not good for portable scripts */
Packit a69f91
	traps[SIGCLD].name = "SIGCHLD";
Packit a69f91
#endif
Packit a69f91
#if defined(SIGALRM)
Packit a69f91
	traps[SIGALRM].reserved = TRUE;
Packit a69f91
#endif
Packit a69f91
#if defined(SIGKILL)
Packit a69f91
	traps[SIGKILL].reserved = TRUE;
Packit a69f91
#endif
Packit a69f91
#if defined(SIGSTOP)
Packit a69f91
	traps[SIGSTOP].reserved = TRUE;
Packit a69f91
#endif
Packit a69f91
Packit a69f91
	async_handler = Tcl_AsyncCreate(tophalf,(ClientData)0);
Packit a69f91
Packit a69f91
}
Packit a69f91
Packit a69f91
/* given signal index or name as string, */
Packit a69f91
/* returns signal index or -1 if bad arg */
Packit a69f91
int
Packit a69f91
exp_string_to_signal(interp,s)
Packit a69f91
Tcl_Interp *interp;
Packit a69f91
char *s;
Packit a69f91
{
Packit a69f91
	int sig;
Packit a69f91
	CONST char *name;
Packit a69f91
Packit a69f91
	/* try interpreting as an integer */
Packit a69f91
	if (1 == sscanf(s,"%d",&sig)) {
Packit a69f91
		if (sig > 0 && sig < NSIG) return sig;
Packit a69f91
	} else {
Packit a69f91
		/* try interpreting as a string */
Packit a69f91
		for (sig=1;sig
Packit a69f91
			name = traps[sig].name;
Packit a69f91
			if (streq(s,name) || streq(s,name+3)) return(sig);
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
Packit a69f91
	exp_error(interp,"invalid signal %s",s);
Packit a69f91
	
Packit a69f91
	return -1;
Packit a69f91
}
Packit a69f91
Packit a69f91
/*ARGSUSED*/
Packit a69f91
int
Packit a69f91
Exp_TrapObjCmd(clientData, interp, objc, objv)
Packit a69f91
ClientData clientData;
Packit a69f91
Tcl_Interp *interp;
Packit a69f91
int objc;
Packit a69f91
Tcl_Obj *CONST objv[];
Packit a69f91
{
Packit a69f91
	char *action = 0;
Packit a69f91
	int n;		/* number of signals in list */
Packit a69f91
	Tcl_Obj **list;	/* list of signals */
Packit a69f91
	char *arg;
Packit a69f91
	int len;	/* length of action */
Packit a69f91
	int i;
Packit a69f91
	int show_name = FALSE;	/* if user asked for current sig by name */
Packit a69f91
	int show_number = FALSE;/* if user asked for current sig by number */
Packit a69f91
	int show_max = FALSE;	/* if user asked for NSIG-1 */
Packit a69f91
	int rc = TCL_OK;
Packit a69f91
	int new_code = FALSE;	/* if action result should overwrite orig */
Packit a69f91
	Tcl_Interp *new_interp = interp;/* interp in which to evaluate */
Packit a69f91
					/* action when signal occurs */
Packit a69f91
Packit a69f91
	objc--; objv++;
Packit a69f91
Packit a69f91
	while (objc) {
Packit a69f91
	  arg = Tcl_GetString(*objv);
Packit a69f91
Packit a69f91
		if (streq(arg,"-code")) {
Packit a69f91
			objc--; objv++; 
Packit a69f91
			new_code = TRUE;
Packit a69f91
		} else if (streq(arg,"-interp")) {
Packit a69f91
			objc--; objv++; 
Packit a69f91
			new_interp = 0;
Packit a69f91
		} else if (streq(arg,"-name")) {
Packit a69f91
			objc--; objv++;
Packit a69f91
			show_name = TRUE;
Packit a69f91
		} else if (streq(arg,"-number")) {
Packit a69f91
			objc--; objv++;
Packit a69f91
			show_number = TRUE;
Packit a69f91
		} else if (streq(arg,"-max")) {
Packit a69f91
			objc--; objv++;
Packit a69f91
			show_max = TRUE;
Packit a69f91
		} else break;
Packit a69f91
	}
Packit a69f91
Packit a69f91
	if (show_name || show_number || show_max) {
Packit a69f91
		if (objc > 0) goto usage_error;
Packit a69f91
		if (show_max) {
Packit a69f91
		  Tcl_SetObjResult(interp,Tcl_NewIntObj(NSIG-1));
Packit a69f91
		}
Packit a69f91
Packit a69f91
		if (current_sig == NO_SIG) {
Packit a69f91
		  Tcl_SetResult(interp,"no signal in progress",TCL_STATIC);
Packit a69f91
		  return TCL_ERROR;
Packit a69f91
		}
Packit a69f91
		if (show_name) {
Packit a69f91
		  /* skip over "SIG" */
Packit a69f91
		  /* TIP 27: Casting away the CONST should be ok because of TCL_STATIC
Packit a69f91
		   */
Packit a69f91
		  Tcl_SetResult(interp,(char*)signal_to_string(current_sig) + 3,TCL_STATIC);
Packit a69f91
		} else {
Packit a69f91
		  Tcl_SetObjResult(interp,Tcl_NewIntObj(current_sig));
Packit a69f91
		}
Packit a69f91
		return TCL_OK;
Packit a69f91
	}
Packit a69f91
Packit a69f91
	if (objc == 0 || objc > 2) goto usage_error;
Packit a69f91
Packit a69f91
	if (objc == 1) {
Packit a69f91
		int sig = exp_string_to_signal(interp,arg);
Packit a69f91
		if (sig == -1) return TCL_ERROR;
Packit a69f91
Packit a69f91
		if (traps[sig].action) {
Packit a69f91
			Tcl_SetResult(interp,traps[sig].action,TCL_STATIC);
Packit a69f91
		} else {
Packit a69f91
			Tcl_SetResult(interp,"SIG_DFL",TCL_STATIC);
Packit a69f91
		}
Packit a69f91
		return TCL_OK;
Packit a69f91
	}
Packit a69f91
Packit a69f91
	action = arg;
Packit a69f91
Packit a69f91
	/* objv[1] is the list of signals - crack it open */
Packit a69f91
	if (TCL_OK != Tcl_ListObjGetElements(interp,objv[1],&n,&list)) {
Packit a69f91
	  return TCL_ERROR;
Packit a69f91
	}
Packit a69f91
Packit a69f91
	for (i=0;i
Packit a69f91
	  char *s;
Packit a69f91
	  int sig;
Packit a69f91
Packit a69f91
	  s = Tcl_GetString(list[i]);
Packit a69f91
Packit a69f91
		sig = exp_string_to_signal(interp,s);
Packit a69f91
		if (sig == -1) {
Packit a69f91
			rc = TCL_ERROR;
Packit a69f91
			break;
Packit a69f91
		}
Packit a69f91
Packit a69f91
		if (traps[sig].reserved) {
Packit a69f91
			exp_error(interp,"cannot trap %s",signal_to_string(sig));
Packit a69f91
			rc = TCL_ERROR;
Packit a69f91
			break;
Packit a69f91
		}
Packit a69f91
Packit a69f91
		expDiagLog("trap: setting up signal %d (\"%s\")\r\n",sig,s);
Packit a69f91
		if (traps[sig].action) ckfree(traps[sig].action);
Packit a69f91
		if (streq(action,"SIG_DFL")) {
Packit a69f91
			/* should've been free'd by now if nec. */
Packit a69f91
			traps[sig].action = 0;
Packit a69f91
			signal(sig,SIG_DFL);
Packit a69f91
#ifdef REARM_SIG
Packit a69f91
			if (sig == SIGCHLD)
Packit a69f91
				rearm_sigchld = FALSE;
Packit a69f91
#endif /*REARM_SIG*/
Packit a69f91
		} else {
Packit a69f91
			len = 1 + strlen(action);
Packit a69f91
			traps[sig].action = ckalloc(len);
Packit a69f91
			memcpy(traps[sig].action,action,len);
Packit a69f91
			traps[sig].interp = new_interp;
Packit a69f91
			traps[sig].code = new_code;
Packit a69f91
			if (streq(action,"SIG_IGN")) {
Packit a69f91
				signal(sig,SIG_IGN);
Packit a69f91
			} else signal(sig,bottomhalf);
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
	/* It is no longer necessary to free the split list since it */
Packit a69f91
	/* is still owned by Tcl, yes? */
Packit a69f91
	/*	ckfree((char *)list); */
Packit a69f91
	return(rc);
Packit a69f91
 usage_error:
Packit a69f91
	exp_error(interp,"usage: trap [command or SIG_DFL or SIG_IGN] {list of signals}");
Packit a69f91
	return TCL_ERROR;
Packit a69f91
}
Packit a69f91
Packit a69f91
/* called by tophalf() to process the given signal */
Packit a69f91
static int
Packit a69f91
eval_trap_action(interp,sig,trap,oldcode)
Packit a69f91
Tcl_Interp *interp;
Packit a69f91
int sig;
Packit a69f91
struct trap *trap;
Packit a69f91
int oldcode;
Packit a69f91
{
Packit a69f91
	int code_flag;
Packit a69f91
	int newcode;
Packit a69f91
	Tcl_Obj *eip;   /* errorInfo */
Packit a69f91
	Tcl_Obj *ecp;	/* errorCode */
Packit a69f91
	Tcl_Obj *irp;	/* interp's result */
Packit a69f91
Packit a69f91
	expDiagLogU("async event handler: Tcl_Eval(");
Packit a69f91
	expDiagLogU(trap->action);
Packit a69f91
	expDiagLogU(")\r\n");
Packit a69f91
Packit a69f91
	/* save to prevent user from redefining trap->code while trap */
Packit a69f91
	/* is executing */
Packit a69f91
	code_flag = trap->code;
Packit a69f91
Packit a69f91
	if (!code_flag) {
Packit a69f91
		/* 
Packit a69f91
		 * save return values
Packit a69f91
		 */
Packit a69f91
Packit a69f91
		eip = Tcl_GetVar2Ex(interp,"errorInfo","",TCL_GLOBAL_ONLY);
Packit a69f91
		if (eip) eip = Tcl_DuplicateObj(eip);
Packit a69f91
		ecp = Tcl_GetVar2Ex(interp,"errorCode","",TCL_GLOBAL_ONLY);
Packit a69f91
		if (ecp) ecp = Tcl_DuplicateObj(ecp);
Packit a69f91
		irp = Tcl_GetObjResult(interp);
Packit a69f91
		if (irp) irp = Tcl_DuplicateObj(irp);
Packit a69f91
	}
Packit a69f91
Packit a69f91
	newcode = Tcl_GlobalEval(interp,trap->action);
Packit a69f91
Packit a69f91
	/*
Packit a69f91
	 * if new code is to be ignored (usual case - see "else" below)
Packit a69f91
	 *	allow only OK/RETURN from trap, otherwise complain
Packit a69f91
	 */
Packit a69f91
Packit a69f91
	if (code_flag) {
Packit a69f91
		expDiagLog("return value = %d for trap %s, action ",newcode,signal_to_string(sig));
Packit a69f91
		expDiagLogU(trap->action);
Packit a69f91
		expDiagLogU("\r\n");
Packit a69f91
		if (0 != strcmp(Tcl_GetStringResult(interp),"")) {
Packit a69f91
Packit a69f91
			/*
Packit a69f91
			 * Check errorinfo and see if it contains -nostack.
Packit a69f91
			 * This shouldn't be necessary, but John changed the
Packit a69f91
			 * top level interp so that it distorts arbitrary
Packit a69f91
			 * return values into TCL_ERROR, so by the time we
Packit a69f91
			 * get back, we'll have lost the value of errorInfo
Packit a69f91
			 */
Packit a69f91
Packit a69f91
			eip = Tcl_GetVar2Ex(interp,"errorInfo","",TCL_GLOBAL_ONLY);
Packit a69f91
			if (eip) {
Packit a69f91
			  exp_nostack_dump = (0 == strncmp("-nostack",Tcl_GetString(eip),8));
Packit a69f91
			}
Packit a69f91
		}
Packit a69f91
	} else if (newcode != TCL_OK && newcode != TCL_RETURN) {
Packit a69f91
	  if (newcode != TCL_ERROR) {
Packit a69f91
	    exp_error(interp,"return value = %d for trap %s, action %s\r\n",newcode,signal_to_string(sig),trap->action);
Packit a69f91
	  }
Packit a69f91
	  Tcl_BackgroundError(interp);
Packit a69f91
	}
Packit a69f91
Packit a69f91
	if (!code_flag) {
Packit a69f91
		/*
Packit a69f91
		 * restore values
Packit a69f91
		 */
Packit a69f91
		Tcl_ResetResult(interp);	/* turns off Tcl's internal */
Packit a69f91
		   /* flags: ERR_IN_PROGRESS, ERROR_CODE_SET */
Packit a69f91
		   /* This also wipes clean errorInfo/Code/result which is why */
Packit a69f91
		   /* all the calls to Tcl_Dup earlier */
Packit a69f91
Packit a69f91
		if (eip) {
Packit a69f91
		  /* odd that Tcl doesn't have a call that does all this at once */
Packit a69f91
		  int len;
Packit a69f91
		  char *s = Tcl_GetStringFromObj(eip,&len;;
Packit a69f91
		  Tcl_AddObjErrorInfo(interp,s,len);
Packit a69f91
		  Tcl_DecrRefCount(eip);
Packit a69f91
		  /* we never incr'd it, but the code allows this */
Packit a69f91
		} else {
Packit a69f91
		  Tcl_UnsetVar(interp,"errorInfo",0);
Packit a69f91
		}
Packit a69f91
Packit a69f91
		/* restore errorCode.  Note that Tcl_AddErrorInfo (above) */
Packit a69f91
		/* resets it to NONE.  If the previous value is NONE, it's */
Packit a69f91
		/* important to avoid calling Tcl_SetErrorCode since this */
Packit a69f91
		/* with cause Tcl to set its internal ERROR_CODE_SET flag. */
Packit a69f91
		if (ecp) {
Packit a69f91
		  if (!streq("NONE",Tcl_GetString(ecp)))
Packit a69f91
		    Tcl_SetErrorCode(interp,ecp);
Packit a69f91
		  /* we're just passing on the errorcode obj */
Packit a69f91
		  /* presumably, Tcl will incr ref count */
Packit a69f91
		} else {
Packit a69f91
		  Tcl_UnsetVar(interp,"errorCode",0);
Packit a69f91
		}
Packit a69f91
Packit a69f91
		newcode = oldcode;
Packit a69f91
Packit a69f91
		/* note that since newcode gets overwritten here by old code */
Packit a69f91
		/* it is possible to return in the middle of a trap by using */
Packit a69f91
		/* "return" (or "continue" for that matter)! */
Packit a69f91
	}
Packit a69f91
	return newcode;
Packit a69f91
}
Packit a69f91
Packit a69f91
static struct exp_cmd_data
Packit a69f91
cmd_data[]  = {
Packit a69f91
{"trap",	Exp_TrapObjCmd, 0,	(ClientData)EXP_SPAWN_ID_BAD,	0},
Packit a69f91
{0}};
Packit a69f91
Packit a69f91
void
Packit a69f91
exp_init_trap_cmds(interp)
Packit a69f91
Tcl_Interp *interp;
Packit a69f91
{
Packit a69f91
	exp_create_commands(interp,cmd_data);
Packit a69f91
}
Packit a69f91