/* exp_main_sub.c - miscellaneous subroutines for Expect or Tk main() */
|
/* exp_main_sub.c - miscellaneous subroutines for Expect or Tk main() */
|
|
|
#include "expect_cf.h"
|
#include "expect_cf.h"
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <errno.h>
|
#include <errno.h>
|
#ifdef HAVE_INTTYPES_H
|
#ifdef HAVE_INTTYPES_H
|
# include <inttypes.h>
|
# include <inttypes.h>
|
#endif
|
#endif
|
#include <sys/types.h>
|
#include <sys/types.h>
|
|
|
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
# include <unistd.h>
|
# include <unistd.h>
|
#endif
|
#endif
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
#ifdef HAVE_SYS_WAIT_H
|
#include <sys/wait.h>
|
#include <sys/wait.h>
|
#endif
|
#endif
|
|
|
#include "tcl.h"
|
#include "tcl.h"
|
#include "tclInt.h"
|
#include "tclInt.h"
|
#include "exp_rename.h"
|
#include "exp_rename.h"
|
#include "exp_prog.h"
|
#include "exp_prog.h"
|
#include "exp_command.h"
|
#include "exp_command.h"
|
#include "exp_tty_in.h"
|
#include "exp_tty_in.h"
|
#include "exp_log.h"
|
#include "exp_log.h"
|
#include "exp_event.h"
|
#include "exp_event.h"
|
#ifdef TCL_DEBUGGER
|
#ifdef TCL_DEBUGGER
|
#include "Dbg.h"
|
#include "Dbg.h"
|
#endif
|
#endif
|
|
|
#ifdef __CENTERLINE__
|
#ifdef __CENTERLINE__
|
#undef EXP_VERSION
|
#undef EXP_VERSION
|
#define EXP_VERSION "5.0.3" /* I give up! */
|
#define EXP_VERSION "5.0.3" /* I give up! */
|
/* It is not necessary that number */
|
/* It is not necessary that number */
|
/* be accurate. It is just here to */
|
/* be accurate. It is just here to */
|
/* pacify Centerline which doesn't */
|
/* pacify Centerline which doesn't */
|
/* seem to be able to get it from */
|
/* seem to be able to get it from */
|
/* the Makefile. */
|
/* the Makefile. */
|
#undef SCRIPTDIR
|
#undef SCRIPTDIR
|
#define SCRIPTDIR "example/"
|
#define SCRIPTDIR "example/"
|
#undef EXECSCRIPTDIR
|
#undef EXECSCRIPTDIR
|
#define EXECSCRIPTDIR "example/"
|
#define EXECSCRIPTDIR "example/"
|
#endif
|
#endif
|
char exp_version[] = EXP_VERSION;
|
char exp_version[] = EXP_VERSION;
|
#define NEED_TCL_MAJOR 7
|
#define NEED_TCL_MAJOR 7
|
#define NEED_TCL_MINOR 5
|
#define NEED_TCL_MINOR 5
|
|
|
char *exp_argv0 = "this program"; /* default program name */
|
char *exp_argv0 = "this program"; /* default program name */
|
void (*exp_app_exit)() = 0;
|
void (*exp_app_exit)() = 0;
|
void (*exp_event_exit)() = 0;
|
void (*exp_event_exit)() = 0;
|
FILE *exp_cmdfile = 0;
|
FILE *exp_cmdfile = 0;
|
char *exp_cmdfilename = 0;
|
char *exp_cmdfilename = 0;
|
int exp_cmdlinecmds = FALSE;
|
int exp_cmdlinecmds = FALSE;
|
int exp_interactive = FALSE;
|
int exp_interactive = FALSE;
|
int exp_buffer_command_input = FALSE;/* read in entire cmdfile at once */
|
int exp_buffer_command_input = FALSE;/* read in entire cmdfile at once */
|
int exp_fgets();
|
int exp_fgets();
|
|
|
Tcl_Interp *exp_interp; /* for use by signal handlers who can't figure out */
|
Tcl_Interp *exp_interp; /* for use by signal handlers who can't figure out */
|
/* the interpreter directly */
|
/* the interpreter directly */
|
int exp_tcl_debugger_available = FALSE;
|
int exp_tcl_debugger_available = FALSE;
|
|
|
int exp_getpid;
|
int exp_getpid;
|
|
|
static void
|
static void
|
usage(interp)
|
usage(interp)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
{
|
{
|
errorlog("usage: expect [-div] [-c cmds] [[-f] cmdfile] [args]\r\n");
|
errorlog("usage: expect [-div] [-c cmds] [[-f] cmdfile] [args]\r\n");
|
exp_exit(interp,1);
|
exp_exit(interp,1);
|
}
|
}
|
|
|
/*ARGSUSED*/
|
/*ARGSUSED*/
|
void
|
void
|
exp_exit(interp,status)
|
exp_exit(interp,status)
|
Tcl_Interp *interp; /* historic */
|
Tcl_Interp *interp; /* historic */
|
int status;
|
int status;
|
{
|
{
|
Tcl_Exit(status);
|
Tcl_Exit(status);
|
}
|
}
|
|
|
/* this clumsiness because pty routines don't know Tcl definitions */
|
/* this clumsiness because pty routines don't know Tcl definitions */
|
static
|
static
|
void
|
void
|
exp_pty_exit_for_tcl(clientData)
|
exp_pty_exit_for_tcl(clientData)
|
ClientData clientData;
|
ClientData clientData;
|
{
|
{
|
exp_pty_exit();
|
exp_pty_exit();
|
}
|
}
|
|
|
static
|
static
|
void
|
void
|
exp_init_pty_exit()
|
exp_init_pty_exit()
|
{
|
{
|
Tcl_CreateExitHandler(exp_pty_exit_for_tcl,(ClientData)0);
|
Tcl_CreateExitHandler(exp_pty_exit_for_tcl,(ClientData)0);
|
}
|
}
|
|
|
/* This can be called twice or even recursively - it's safe. */
|
/* This can be called twice or even recursively - it's safe. */
|
void
|
void
|
exp_exit_handlers(clientData)
|
exp_exit_handlers(clientData)
|
ClientData clientData;
|
ClientData clientData;
|
{
|
{
|
extern int exp_forked;
|
extern int exp_forked;
|
|
|
Tcl_Interp *interp = (Tcl_Interp *)clientData;
|
Tcl_Interp *interp = (Tcl_Interp *)clientData;
|
|
|
/* use following checks to prevent recursion in exit handlers */
|
/* use following checks to prevent recursion in exit handlers */
|
/* if this code ever supports multiple interps, these should */
|
/* if this code ever supports multiple interps, these should */
|
/* become interp-specific */
|
/* become interp-specific */
|
|
|
static int did_app_exit = FALSE;
|
static int did_app_exit = FALSE;
|
static int did_expect_exit = FALSE;
|
static int did_expect_exit = FALSE;
|
|
|
/* don't think this code is relevant any longer, but not positive! */
|
/* don't think this code is relevant any longer, but not positive! */
|
if (!interp) {
|
if (!interp) {
|
/* if no interp handy (i.e., called from interrupt handler) */
|
/* if no interp handy (i.e., called from interrupt handler) */
|
/* use last one created - it's a hack but we're exiting */
|
/* use last one created - it's a hack but we're exiting */
|
/* ungracefully to begin with */
|
/* ungracefully to begin with */
|
interp = exp_interp;
|
interp = exp_interp;
|
}
|
}
|
|
|
if (!did_expect_exit) {
|
if (!did_expect_exit) {
|
did_expect_exit = TRUE;
|
did_expect_exit = TRUE;
|
/* called user-defined exit routine if one exists */
|
/* called user-defined exit routine if one exists */
|
if (exp_onexit_action) {
|
if (exp_onexit_action) {
|
int result = Tcl_GlobalEval(interp,exp_onexit_action);
|
int result = Tcl_GlobalEval(interp,exp_onexit_action);
|
if (result != TCL_OK) Tcl_BackgroundError(interp);
|
if (result != TCL_OK) Tcl_BackgroundError(interp);
|
}
|
}
|
} else {
|
} else {
|
debuglog("onexit handler called recursively - forcing exit\r\n");
|
debuglog("onexit handler called recursively - forcing exit\r\n");
|
}
|
}
|
|
|
if (exp_app_exit) {
|
if (exp_app_exit) {
|
if (!did_app_exit) {
|
if (!did_app_exit) {
|
did_app_exit = TRUE;
|
did_app_exit = TRUE;
|
(*exp_app_exit)(interp);
|
(*exp_app_exit)(interp);
|
} else {
|
} else {
|
debuglog("application exit handler called recursively - forcing exit\r\n");
|
debuglog("application exit handler called recursively - forcing exit\r\n");
|
}
|
}
|
}
|
}
|
|
|
if (!exp_disconnected
|
if (!exp_disconnected
|
&& !exp_forked
|
&& !exp_forked
|
&& (exp_dev_tty != -1)
|
&& (exp_dev_tty != -1)
|
&& isatty(exp_dev_tty)
|
&& isatty(exp_dev_tty)
|
&& exp_ioctled_devtty) {
|
&& exp_ioctled_devtty) {
|
exp_tty_set(interp,&exp_tty_original,exp_dev_tty,0);
|
exp_tty_set(interp,&exp_tty_original,exp_dev_tty,0);
|
}
|
}
|
/* all other files either don't need to be flushed or will be
|
/* all other files either don't need to be flushed or will be
|
implicitly closed at exit. Spawned processes are free to continue
|
implicitly closed at exit. Spawned processes are free to continue
|
running, however most will shutdown after seeing EOF on stdin.
|
running, however most will shutdown after seeing EOF on stdin.
|
Some systems also deliver SIGHUP and other sigs to idle processes
|
Some systems also deliver SIGHUP and other sigs to idle processes
|
which will blow them away if not prepared.
|
which will blow them away if not prepared.
|
*/
|
*/
|
|
|
exp_close_all(interp);
|
exp_close_all(interp);
|
}
|
}
|
|
|
static int
|
static int
|
history_nextid(interp)
|
history_nextid(interp)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
{
|
{
|
Interp *iPtr = (Interp *)interp;
|
Interp *iPtr = (Interp *)interp;
|
|
|
#if TCL_MAJOR_VERSION < 8
|
#if TCL_MAJOR_VERSION < 8
|
return iPtr->curEventNum+1;
|
return iPtr->curEventNum+1;
|
#else
|
#else
|
/* unncessarily tricky coding - if nextid isn't defined,
|
/* unncessarily tricky coding - if nextid isn't defined,
|
maintain our own static version */
|
maintain our own static version */
|
|
|
static int nextid = 0;
|
static int nextid = 0;
|
char *nextidstr = Tcl_GetVar2(interp,"tcl::history","nextid",0);
|
char *nextidstr = Tcl_GetVar2(interp,"tcl::history","nextid",0);
|
if (nextidstr) {
|
if (nextidstr) {
|
/* intentionally ignore failure */
|
/* intentionally ignore failure */
|
(void) sscanf(nextidstr,"%d",&nextid);
|
(void) sscanf(nextidstr,"%d",&nextid);
|
}
|
}
|
return ++nextid;
|
return ++nextid;
|
#endif
|
#endif
|
}
|
}
|
|
|
/* this stupidity because Tcl needs commands in writable space */
|
/* this stupidity because Tcl needs commands in writable space */
|
static char prompt1[] = "prompt1";
|
static char prompt1[] = "prompt1";
|
static char prompt2[] = "prompt2";
|
static char prompt2[] = "prompt2";
|
|
|
static char *prompt2_default = "+> ";
|
static char *prompt2_default = "+> ";
|
static char prompt1_default[] = "expect%d.%d> ";
|
static char prompt1_default[] = "expect%d.%d> ";
|
|
|
/*ARGSUSED*/
|
/*ARGSUSED*/
|
int
|
int
|
Exp_Prompt1Cmd(clientData, interp, argc, argv)
|
Exp_Prompt1Cmd(clientData, interp, argc, argv)
|
ClientData clientData;
|
ClientData clientData;
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
int argc;
|
int argc;
|
char **argv;
|
char **argv;
|
{
|
{
|
Interp *iPtr = (Interp *)interp;
|
Interp *iPtr = (Interp *)interp;
|
|
|
sprintf(interp->result,prompt1_default,
|
sprintf(interp->result,prompt1_default,
|
iPtr->numLevels,history_nextid(interp));
|
iPtr->numLevels,history_nextid(interp));
|
return(TCL_OK);
|
return(TCL_OK);
|
}
|
}
|
|
|
/*ARGSUSED*/
|
/*ARGSUSED*/
|
int
|
int
|
Exp_Prompt2Cmd(clientData, interp, argc, argv)
|
Exp_Prompt2Cmd(clientData, interp, argc, argv)
|
ClientData clientData;
|
ClientData clientData;
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
int argc;
|
int argc;
|
char **argv;
|
char **argv;
|
{
|
{
|
strcpy(interp->result,prompt2_default);
|
strcpy(interp->result,prompt2_default);
|
return(TCL_OK);
|
return(TCL_OK);
|
}
|
}
|
|
|
/*ARGSUSED*/
|
/*ARGSUSED*/
|
static int
|
static int
|
ignore_procs(interp,s)
|
ignore_procs(interp,s)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
char *s; /* function name */
|
char *s; /* function name */
|
{
|
{
|
return ((s[0] == 'p') &&
|
return ((s[0] == 'p') &&
|
(s[1] == 'r') &&
|
(s[1] == 'r') &&
|
(s[2] == 'o') &&
|
(s[2] == 'o') &&
|
(s[3] == 'm') &&
|
(s[3] == 'm') &&
|
(s[4] == 'p') &&
|
(s[4] == 'p') &&
|
(s[5] == 't') &&
|
(s[5] == 't') &&
|
((s[6] == '1') ||
|
((s[6] == '1') ||
|
(s[6] == '2')) &&
|
(s[6] == '2')) &&
|
(s[7] == '\0')
|
(s[7] == '\0')
|
);
|
);
|
}
|
}
|
|
|
/* handle an error from Tcl_Eval or Tcl_EvalFile */
|
/* handle an error from Tcl_Eval or Tcl_EvalFile */
|
static void
|
static void
|
handle_eval_error(interp,check_for_nostack)
|
handle_eval_error(interp,check_for_nostack)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
int check_for_nostack;
|
int check_for_nostack;
|
{
|
{
|
char *msg;
|
char *msg;
|
|
|
/* if errorInfo has something, print it */
|
/* if errorInfo has something, print it */
|
/* else use what's in interp->result */
|
/* else use what's in interp->result */
|
|
|
msg = Tcl_GetVar(interp,"errorInfo",TCL_GLOBAL_ONLY);
|
msg = Tcl_GetVar(interp,"errorInfo",TCL_GLOBAL_ONLY);
|
if (!msg) msg = interp->result;
|
if (!msg) msg = interp->result;
|
else if (check_for_nostack) {
|
else if (check_for_nostack) {
|
/* suppress errorInfo if generated via */
|
/* suppress errorInfo if generated via */
|
/* error ... -nostack */
|
/* error ... -nostack */
|
if (0 == strncmp("-nostack",msg,8)) return;
|
if (0 == strncmp("-nostack",msg,8)) return;
|
|
|
/*
|
/*
|
* This shouldn't be necessary, but previous test fails
|
* This shouldn't be necessary, but previous test fails
|
* because of recent change John made - see eval_trap_action()
|
* because of recent change John made - see eval_trap_action()
|
* in exp_trap.c for more info
|
* in exp_trap.c for more info
|
*/
|
*/
|
if (exp_nostack_dump) {
|
if (exp_nostack_dump) {
|
exp_nostack_dump = FALSE;
|
exp_nostack_dump = FALSE;
|
return;
|
return;
|
}
|
}
|
}
|
}
|
|
|
/* no \n at end, since ccmd will already have one. */
|
/* no \n at end, since ccmd will already have one. */
|
/* Actually, this is not true if command is last in */
|
/* Actually, this is not true if command is last in */
|
/* file and has no newline after it, oh well */
|
/* file and has no newline after it, oh well */
|
errorlog("%s\r\n",exp_cook(msg,(int *)0));
|
errorlog("%s\r\n",exp_cook(msg,(int *)0));
|
}
|
}
|
|
|
/* user has pressed escape char from interact or somehow requested expect.
|
/* user has pressed escape char from interact or somehow requested expect.
|
If a user-supplied command returns:
|
If a user-supplied command returns:
|
|
|
TCL_ERROR, assume user is experimenting and reprompt
|
TCL_ERROR, assume user is experimenting and reprompt
|
TCL_OK, ditto
|
TCL_OK, ditto
|
TCL_RETURN, return TCL_OK (assume user just wants to escape() to return)
|
TCL_RETURN, return TCL_OK (assume user just wants to escape() to return)
|
EXP_TCL_RETURN, return TCL_RETURN
|
EXP_TCL_RETURN, return TCL_RETURN
|
anything else return it
|
anything else return it
|
*/
|
*/
|
int
|
int
|
exp_interpreter(interp)
|
exp_interpreter(interp)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
{
|
{
|
int rc;
|
int rc;
|
char *ccmd; /* pointer to complete command */
|
char *ccmd; /* pointer to complete command */
|
char line[BUFSIZ+1]; /* space for partial command */
|
char line[BUFSIZ+1]; /* space for partial command */
|
int newcmd = TRUE;
|
int newcmd = TRUE;
|
Tcl_DString dstring;
|
Tcl_DString dstring;
|
Interp *iPtr = (Interp *)interp;
|
Interp *iPtr = (Interp *)interp;
|
int tty_changed = FALSE;
|
int tty_changed = FALSE;
|
|
|
exp_tty tty_old;
|
exp_tty tty_old;
|
int was_raw, was_echo;
|
int was_raw, was_echo;
|
|
|
int dummy;
|
int dummy;
|
Tcl_Channel outChannel;
|
Tcl_Channel outChannel;
|
int fd = fileno(stdin);
|
int fd = fileno(stdin);
|
|
|
expect_key++;
|
expect_key++;
|
|
|
Tcl_DStringInit(&dstring);
|
Tcl_DStringInit(&dstring);
|
|
|
newcmd = TRUE;
|
newcmd = TRUE;
|
while (TRUE) {
|
while (TRUE) {
|
outChannel = Tcl_GetStdChannel(TCL_STDOUT);
|
outChannel = Tcl_GetStdChannel(TCL_STDOUT);
|
if (outChannel) {
|
if (outChannel) {
|
Tcl_Flush(outChannel);
|
Tcl_Flush(outChannel);
|
}
|
}
|
|
|
/* force terminal state */
|
/* force terminal state */
|
tty_changed = exp_tty_cooked_echo(interp,&tty_old,&was_raw,&was_echo);
|
tty_changed = exp_tty_cooked_echo(interp,&tty_old,&was_raw,&was_echo);
|
|
|
if (newcmd) {
|
if (newcmd) {
|
rc = Tcl_Eval(interp,prompt1);
|
rc = Tcl_Eval(interp,prompt1);
|
if (rc == TCL_OK) exp_log(1,"%s",interp->result);
|
if (rc == TCL_OK) exp_log(1,"%s",interp->result);
|
else exp_log(1,prompt1_default,iPtr->numLevels,
|
else exp_log(1,prompt1_default,iPtr->numLevels,
|
history_nextid(interp));
|
history_nextid(interp));
|
} else {
|
} else {
|
rc = Tcl_Eval(interp,prompt2);
|
rc = Tcl_Eval(interp,prompt2);
|
if (rc == TCL_OK) exp_log(1,"%s",interp->result);
|
if (rc == TCL_OK) exp_log(1,"%s",interp->result);
|
else exp_log(1,prompt2_default,1);
|
else exp_log(1,prompt2_default,1);
|
}
|
}
|
|
|
exp_fs[fd].force_read = 1;
|
exp_fs[fd].force_read = 1;
|
rc = exp_get_next_event(interp,&fd,1,&dummy,EXP_TIME_INFINITY,
|
rc = exp_get_next_event(interp,&fd,1,&dummy,EXP_TIME_INFINITY,
|
exp_fs[fd].key);
|
exp_fs[fd].key);
|
/* check for rc == EXP_TCLERROR? */
|
/* check for rc == EXP_TCLERROR? */
|
|
|
if (rc != EXP_EOF) {
|
if (rc != EXP_EOF) {
|
rc = read(0,line,BUFSIZ);
|
rc = read(0,line,BUFSIZ);
|
#ifdef SIMPLE_EVENT
|
#ifdef SIMPLE_EVENT
|
if (rc == -1 && errno == EINTR) {
|
if (rc == -1 && errno == EINTR) {
|
if (Tcl_AsyncReady()) {
|
if (Tcl_AsyncReady()) {
|
(void) Tcl_AsyncInvoke(interp,TCL_OK);
|
(void) Tcl_AsyncInvoke(interp,TCL_OK);
|
}
|
}
|
continue;
|
continue;
|
}
|
}
|
#endif
|
#endif
|
if (rc <= 0) {
|
if (rc <= 0) {
|
if (!newcmd) line[0] = 0;
|
if (!newcmd) line[0] = 0;
|
else rc = EXP_EOF;
|
else rc = EXP_EOF;
|
} else line[rc] = '\0';
|
} else line[rc] = '\0';
|
}
|
}
|
|
|
if (rc == EXP_EOF) exp_exit(interp,0);
|
if (rc == EXP_EOF) exp_exit(interp,0);
|
|
|
if (debugfile) fwrite(line,1,strlen(line),debugfile);
|
if (debugfile) fwrite(line,1,strlen(line),debugfile);
|
/* intentionally always write to logfile */
|
/* intentionally always write to logfile */
|
if (logfile) fwrite(line,1,strlen(line),logfile);
|
if (logfile) fwrite(line,1,strlen(line),logfile);
|
/* no need to write to stdout, since they will see */
|
/* no need to write to stdout, since they will see */
|
/* it just from it having been echoed as they are */
|
/* it just from it having been echoed as they are */
|
/* typing it */
|
/* typing it */
|
|
|
ccmd = Tcl_DStringAppend(&dstring,line,rc);
|
ccmd = Tcl_DStringAppend(&dstring,line,rc);
|
if (!Tcl_CommandComplete(ccmd)) {
|
if (!Tcl_CommandComplete(ccmd)) {
|
newcmd = FALSE;
|
newcmd = FALSE;
|
continue; /* continue collecting command */
|
continue; /* continue collecting command */
|
}
|
}
|
newcmd = TRUE;
|
newcmd = TRUE;
|
|
|
if (tty_changed) exp_tty_set(interp,&tty_old,was_raw,was_echo);
|
if (tty_changed) exp_tty_set(interp,&tty_old,was_raw,was_echo);
|
|
|
rc = Tcl_RecordAndEval(interp,ccmd,0);
|
rc = Tcl_RecordAndEval(interp,ccmd,0);
|
Tcl_DStringFree(&dstring);
|
Tcl_DStringFree(&dstring);
|
switch (rc) {
|
switch (rc) {
|
case TCL_OK:
|
case TCL_OK:
|
if (*interp->result != 0)
|
if (*interp->result != 0)
|
exp_log(1,"%s\r\n",exp_cook(interp->result,(int *)0));
|
exp_log(1,"%s\r\n",exp_cook(interp->result,(int *)0));
|
continue;
|
continue;
|
case TCL_ERROR:
|
case TCL_ERROR:
|
handle_eval_error(interp,1);
|
handle_eval_error(interp,1);
|
/* since user is typing by hand, we expect lots */
|
/* since user is typing by hand, we expect lots */
|
/* of errors, and want to give another chance */
|
/* of errors, and want to give another chance */
|
continue;
|
continue;
|
#define finish(x) {rc = x; goto done;}
|
#define finish(x) {rc = x; goto done;}
|
case TCL_BREAK:
|
case TCL_BREAK:
|
case TCL_CONTINUE:
|
case TCL_CONTINUE:
|
finish(rc);
|
finish(rc);
|
case EXP_TCL_RETURN:
|
case EXP_TCL_RETURN:
|
finish(TCL_RETURN);
|
finish(TCL_RETURN);
|
case TCL_RETURN:
|
case TCL_RETURN:
|
finish(TCL_OK);
|
finish(TCL_OK);
|
default:
|
default:
|
/* note that ccmd has trailing newline */
|
/* note that ccmd has trailing newline */
|
errorlog("error %d: %s\r\n",rc,ccmd);
|
errorlog("error %d: %s\r\n",rc,ccmd);
|
continue;
|
continue;
|
}
|
}
|
}
|
}
|
/* cannot fall thru here, must jump to label */
|
/* cannot fall thru here, must jump to label */
|
done:
|
done:
|
if (tty_changed) exp_tty_set(interp,&tty_old,was_raw,was_echo);
|
if (tty_changed) exp_tty_set(interp,&tty_old,was_raw,was_echo);
|
|
|
Tcl_DStringFree(&dstring);
|
Tcl_DStringFree(&dstring);
|
|
|
return(rc);
|
return(rc);
|
}
|
}
|
|
|
/*ARGSUSED*/
|
/*ARGSUSED*/
|
int
|
int
|
Exp_ExpVersionCmd(clientData, interp, argc, argv)
|
Exp_ExpVersionCmd(clientData, interp, argc, argv)
|
ClientData clientData;
|
ClientData clientData;
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
int argc;
|
int argc;
|
char **argv;
|
char **argv;
|
{
|
{
|
int emajor, umajor;
|
int emajor, umajor;
|
char *user_version; /* user-supplied version string */
|
char *user_version; /* user-supplied version string */
|
|
|
if (argc == 1) {
|
if (argc == 1) {
|
Tcl_SetResult(interp,exp_version,TCL_STATIC);
|
Tcl_SetResult(interp,exp_version,TCL_STATIC);
|
return(TCL_OK);
|
return(TCL_OK);
|
}
|
}
|
if (argc > 3) {
|
if (argc > 3) {
|
exp_error(interp,"usage: expect_version [[-exit] version]");
|
exp_error(interp,"usage: expect_version [[-exit] version]");
|
return(TCL_ERROR);
|
return(TCL_ERROR);
|
}
|
}
|
|
|
user_version = argv[argc==2?1:2];
|
user_version = argv[argc==2?1:2];
|
emajor = atoi(exp_version);
|
emajor = atoi(exp_version);
|
umajor = atoi(user_version);
|
umajor = atoi(user_version);
|
|
|
/* first check major numbers */
|
/* first check major numbers */
|
if (emajor == umajor) {
|
if (emajor == umajor) {
|
int u, e;
|
int u, e;
|
|
|
/* now check minor numbers */
|
/* now check minor numbers */
|
char *dot = strchr(user_version,'.');
|
char *dot = strchr(user_version,'.');
|
if (!dot) {
|
if (!dot) {
|
exp_error(interp,"version number must include a minor version number");
|
exp_error(interp,"version number must include a minor version number");
|
return TCL_ERROR;
|
return TCL_ERROR;
|
}
|
}
|
|
|
u = atoi(dot+1);
|
u = atoi(dot+1);
|
dot = strchr(exp_version,'.');
|
dot = strchr(exp_version,'.');
|
e = atoi(dot+1);
|
e = atoi(dot+1);
|
if (e >= u) return(TCL_OK);
|
if (e >= u) return(TCL_OK);
|
}
|
}
|
|
|
if (argc == 2) {
|
if (argc == 2) {
|
exp_error(interp,"%s requires Expect version %s (but using %s)",
|
exp_error(interp,"%s requires Expect version %s (but using %s)",
|
exp_argv0,user_version,exp_version);
|
exp_argv0,user_version,exp_version);
|
return(TCL_ERROR);
|
return(TCL_ERROR);
|
}
|
}
|
errorlog("%s: requires Expect version %s (but using %s)\r\n",
|
errorlog("%s: requires Expect version %s (but using %s)\r\n",
|
exp_argv0,user_version,exp_version);
|
exp_argv0,user_version,exp_version);
|
exp_exit(interp,1);
|
exp_exit(interp,1);
|
/*NOTREACHED*/
|
/*NOTREACHED*/
|
}
|
}
|
|
|
static char init_auto_path[] = "lappend auto_path $exp_library $exp_exec_library";
|
static char init_auto_path[] = "lappend auto_path $exp_library $exp_exec_library";
|
|
|
int
|
int
|
Expect_Init(interp)
|
Expect_Init(interp)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
{
|
{
|
static int first_time = TRUE;
|
static int first_time = TRUE;
|
|
|
if (first_time) {
|
if (first_time) {
|
int tcl_major = atoi(TCL_VERSION);
|
int tcl_major = atoi(TCL_VERSION);
|
char *dot = strchr(TCL_VERSION,'.');
|
char *dot = strchr(TCL_VERSION,'.');
|
int tcl_minor = atoi(dot+1);
|
int tcl_minor = atoi(dot+1);
|
|
|
if (tcl_major < NEED_TCL_MAJOR ||
|
if (tcl_major < NEED_TCL_MAJOR ||
|
(tcl_major == NEED_TCL_MAJOR && tcl_minor < NEED_TCL_MINOR)) {
|
(tcl_major == NEED_TCL_MAJOR && tcl_minor < NEED_TCL_MINOR)) {
|
sprintf(interp->result,
|
sprintf(interp->result,
|
"%s compiled with Tcl %d.%d but needs at least Tcl %d.%d\n",
|
"%s compiled with Tcl %d.%d but needs at least Tcl %d.%d\n",
|
exp_argv0,tcl_major,tcl_minor,
|
exp_argv0,tcl_major,tcl_minor,
|
NEED_TCL_MAJOR,NEED_TCL_MINOR);
|
NEED_TCL_MAJOR,NEED_TCL_MINOR);
|
return TCL_ERROR;
|
return TCL_ERROR;
|
}
|
}
|
|
|
if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
|
if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
|
return TCL_ERROR;
|
return TCL_ERROR;
|
}
|
}
|
if (Tcl_PkgProvide(interp, "Expect", EXP_VERSION) != TCL_OK) {
|
if (Tcl_PkgProvide(interp, "Expect", EXP_VERSION) != TCL_OK) {
|
return TCL_ERROR;
|
return TCL_ERROR;
|
}
|
}
|
|
|
exp_getpid = getpid();
|
exp_getpid = getpid();
|
exp_init_pty();
|
exp_init_pty();
|
exp_init_pty_exit();
|
exp_init_pty_exit();
|
exp_init_tty(); /* do this only now that we have looked at */
|
exp_init_tty(); /* do this only now that we have looked at */
|
/* original tty state */
|
/* original tty state */
|
exp_init_stdio();
|
exp_init_stdio();
|
exp_init_sig();
|
exp_init_sig();
|
exp_init_event();
|
exp_init_event();
|
exp_init_trap();
|
exp_init_trap();
|
exp_init_unit_random();
|
exp_init_unit_random();
|
exp_init_spawn_ids();
|
exp_init_spawn_ids();
|
|
|
Tcl_CreateExitHandler(exp_exit_handlers,(ClientData)interp);
|
Tcl_CreateExitHandler(exp_exit_handlers,(ClientData)interp);
|
|
|
first_time = FALSE;
|
first_time = FALSE;
|
}
|
}
|
|
|
/* save last known interp for emergencies */
|
/* save last known interp for emergencies */
|
exp_interp = interp;
|
exp_interp = interp;
|
|
|
/* initialize commands */
|
/* initialize commands */
|
exp_init_most_cmds(interp); /* add misc cmds to interpreter */
|
exp_init_most_cmds(interp); /* add misc cmds to interpreter */
|
exp_init_expect_cmds(interp); /* add expect cmds to interpreter */
|
exp_init_expect_cmds(interp); /* add expect cmds to interpreter */
|
exp_init_main_cmds(interp); /* add main cmds to interpreter */
|
exp_init_main_cmds(interp); /* add main cmds to interpreter */
|
exp_init_trap_cmds(interp); /* add trap cmds to interpreter */
|
exp_init_trap_cmds(interp); /* add trap cmds to interpreter */
|
exp_init_tty_cmds(interp); /* add tty cmds to interpreter */
|
exp_init_tty_cmds(interp); /* add tty cmds to interpreter */
|
exp_init_interact_cmds(interp); /* add interact cmds to interpreter */
|
exp_init_interact_cmds(interp); /* add interact cmds to interpreter */
|
|
|
exp_init_spawn_id_vars(interp);
|
exp_init_spawn_id_vars(interp);
|
|
|
Tcl_SetVar(interp,"expect_library",SCRIPTDIR,0);/* deprecated */
|
Tcl_SetVar(interp,"expect_library",SCRIPTDIR,0);/* deprecated */
|
Tcl_SetVar(interp,"exp_library",SCRIPTDIR,0);
|
Tcl_SetVar(interp,"exp_library",SCRIPTDIR,0);
|
Tcl_SetVar(interp,"exp_exec_library",EXECSCRIPTDIR,0);
|
Tcl_SetVar(interp,"exp_exec_library",EXECSCRIPTDIR,0);
|
Tcl_Eval(interp,init_auto_path);
|
Tcl_Eval(interp,init_auto_path);
|
Tcl_ResetResult(interp);
|
Tcl_ResetResult(interp);
|
|
|
#ifdef TCL_DEBUGGER
|
#ifdef TCL_DEBUGGER
|
Dbg_IgnoreFuncs(interp,ignore_procs);
|
Dbg_IgnoreFuncs(interp,ignore_procs);
|
#endif
|
#endif
|
|
|
return TCL_OK;
|
return TCL_OK;
|
}
|
}
|
|
|
static char sigexit_init_default[] = "trap exit {SIGINT SIGTERM}";
|
static char sigexit_init_default[] = "trap exit {SIGINT SIGTERM}";
|
static char debug_init_default[] = "trap {exp_debug 1} SIGINT";
|
static char debug_init_default[] = "trap {exp_debug 1} SIGINT";
|
|
|
void
|
void
|
exp_parse_argv(interp,argc,argv)
|
exp_parse_argv(interp,argc,argv)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
int argc;
|
int argc;
|
char **argv;
|
char **argv;
|
{
|
{
|
char argc_rep[10]; /* enough space for storing literal rep of argc */
|
char argc_rep[10]; /* enough space for storing literal rep of argc */
|
|
|
int sys_rc = TRUE; /* read system rc file */
|
int sys_rc = TRUE; /* read system rc file */
|
int my_rc = TRUE; /* read personal rc file */
|
int my_rc = TRUE; /* read personal rc file */
|
|
|
int c;
|
int c;
|
int rc;
|
int rc;
|
|
|
extern int optind;
|
extern int optind;
|
extern char *optarg;
|
extern char *optarg;
|
char *args; /* ptr to string-rep of all args */
|
char *args; /* ptr to string-rep of all args */
|
char *debug_init;
|
char *debug_init;
|
|
|
exp_argv0 = argv[0];
|
exp_argv0 = argv[0];
|
|
|
#ifdef TCL_DEBUGGER
|
#ifdef TCL_DEBUGGER
|
Dbg_ArgcArgv(argc,argv,1);
|
Dbg_ArgcArgv(argc,argv,1);
|
#endif
|
#endif
|
|
|
/* initially, we must assume we are not interactive */
|
/* initially, we must assume we are not interactive */
|
/* this prevents interactive weirdness courtesy of unknown via -c */
|
/* this prevents interactive weirdness courtesy of unknown via -c */
|
/* after handling args, we can change our mind */
|
/* after handling args, we can change our mind */
|
Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
|
Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
|
|
|
Tcl_Eval(interp,sigexit_init_default);
|
Tcl_Eval(interp,sigexit_init_default);
|
|
|
while ((c = getopt(argc, argv, "b:c:dD:f:inN-v")) != EOF) {
|
while ((c = getopt(argc, argv, "b:c:dD:f:inN-v")) != EOF) {
|
switch(c) {
|
switch(c) {
|
case '-':
|
case '-':
|
/* getopt already handles -- internally, however */
|
/* getopt already handles -- internally, however */
|
/* this allows us to abort getopt when dash is at */
|
/* this allows us to abort getopt when dash is at */
|
/* the end of another option which is required */
|
/* the end of another option which is required */
|
/* in order to allow things like -n- on #! line */
|
/* in order to allow things like -n- on #! line */
|
goto abort_getopt;
|
goto abort_getopt;
|
case 'c': /* command */
|
case 'c': /* command */
|
exp_cmdlinecmds = TRUE;
|
exp_cmdlinecmds = TRUE;
|
rc = Tcl_Eval(interp,optarg);
|
rc = Tcl_Eval(interp,optarg);
|
if (rc != TCL_OK) {
|
if (rc != TCL_OK) {
|
errorlog("%s\r\n",exp_cook(Tcl_GetVar(interp,"errorInfo",TCL_GLOBAL_ONLY),(int *)0));
|
errorlog("%s\r\n",exp_cook(Tcl_GetVar(interp,"errorInfo",TCL_GLOBAL_ONLY),(int *)0));
|
}
|
}
|
break;
|
break;
|
case 'd': exp_is_debugging = TRUE;
|
case 'd': exp_is_debugging = TRUE;
|
debuglog("expect version %s\r\n",exp_version);
|
debuglog("expect version %s\r\n",exp_version);
|
break;
|
break;
|
#ifdef TCL_DEBUGGER
|
#ifdef TCL_DEBUGGER
|
case 'D':
|
case 'D':
|
exp_tcl_debugger_available = TRUE;
|
exp_tcl_debugger_available = TRUE;
|
if (Tcl_GetInt(interp,optarg,&rc) != TCL_OK) {
|
if (Tcl_GetInt(interp,optarg,&rc) != TCL_OK) {
|
errorlog("%s: -D argument must be 0 or 1\r\n",
|
errorlog("%s: -D argument must be 0 or 1\r\n",
|
exp_argv0);
|
exp_argv0);
|
exp_exit(interp,1);
|
exp_exit(interp,1);
|
}
|
}
|
|
|
/* set up trap handler before Dbg_On so user does */
|
/* set up trap handler before Dbg_On so user does */
|
/* not have to see it at first debugger prompt */
|
/* not have to see it at first debugger prompt */
|
if (0 == (debug_init = getenv("EXPECT_DEBUG_INIT"))) {
|
if (0 == (debug_init = getenv("EXPECT_DEBUG_INIT"))) {
|
debug_init = debug_init_default;
|
debug_init = debug_init_default;
|
}
|
}
|
Tcl_Eval(interp,debug_init);
|
Tcl_Eval(interp,debug_init);
|
if (rc == 1) Dbg_On(interp,0);
|
if (rc == 1) Dbg_On(interp,0);
|
break;
|
break;
|
#endif
|
#endif
|
case 'f': /* name of cmd file */
|
case 'f': /* name of cmd file */
|
exp_cmdfilename = optarg;
|
exp_cmdfilename = optarg;
|
break;
|
break;
|
case 'b': /* read cmdfile one part at a time */
|
case 'b': /* read cmdfile one part at a time */
|
exp_cmdfilename = optarg;
|
exp_cmdfilename = optarg;
|
exp_buffer_command_input = TRUE;
|
exp_buffer_command_input = TRUE;
|
break;
|
break;
|
case 'i': /* interactive */
|
case 'i': /* interactive */
|
exp_interactive = TRUE;
|
exp_interactive = TRUE;
|
break;
|
break;
|
case 'n': /* don't read personal rc file */
|
case 'n': /* don't read personal rc file */
|
my_rc = FALSE;
|
my_rc = FALSE;
|
break;
|
break;
|
case 'N': /* don't read system-wide rc file */
|
case 'N': /* don't read system-wide rc file */
|
sys_rc = FALSE;
|
sys_rc = FALSE;
|
break;
|
break;
|
case 'v':
|
case 'v':
|
printf("expect version %s\n", exp_version);
|
printf("expect version %s\n", exp_version);
|
exp_exit (interp, 0);
|
exp_exit (interp, 0);
|
break;
|
break;
|
default: usage(interp);
|
default: usage(interp);
|
}
|
}
|
}
|
}
|
|
|
abort_getopt:
|
abort_getopt:
|
|
|
for (c = 0;c<argc;c++) {
|
for (c = 0;c<argc;c++) {
|
debuglog("argv[%d] = %s ",c,argv[c]);
|
debuglog("argv[%d] = %s ",c,argv[c]);
|
}
|
}
|
debuglog("\r\n");
|
debuglog("\r\n");
|
|
|
/* if user hasn't explicitly requested we be interactive */
|
/* if user hasn't explicitly requested we be interactive */
|
/* look for a file or some other source of commands */
|
/* look for a file or some other source of commands */
|
if (!exp_interactive) {
|
if (!exp_interactive) {
|
/* get cmd file name, if we haven't got it already */
|
/* get cmd file name, if we haven't got it already */
|
if (!exp_cmdfilename && (optind < argc)) {
|
if (!exp_cmdfilename && (optind < argc)) {
|
exp_cmdfilename = argv[optind];
|
exp_cmdfilename = argv[optind];
|
optind++;
|
optind++;
|
}
|
}
|
|
|
if (exp_cmdfilename) {
|
if (exp_cmdfilename) {
|
if (streq(exp_cmdfilename,"-")) {
|
if (streq(exp_cmdfilename,"-")) {
|
exp_cmdfile = stdin;
|
exp_cmdfile = stdin;
|
exp_cmdfilename = 0;
|
exp_cmdfilename = 0;
|
} else if (exp_buffer_command_input) {
|
} else if (exp_buffer_command_input) {
|
errno = 0;
|
errno = 0;
|
exp_cmdfile = fopen(exp_cmdfilename,"r");
|
exp_cmdfile = fopen(exp_cmdfilename,"r");
|
if (exp_cmdfile) {
|
if (exp_cmdfile) {
|
exp_cmdfilename = 0;
|
exp_cmdfilename = 0;
|
exp_close_on_exec(fileno(exp_cmdfile));
|
exp_close_on_exec(fileno(exp_cmdfile));
|
} else {
|
} else {
|
char *msg;
|
char *msg;
|
|
|
if (errno == 0) {
|
if (errno == 0) {
|
msg = "could not read - odd file name?";
|
msg = "could not read - odd file name?";
|
} else {
|
} else {
|
msg = Tcl_ErrnoMsg(errno);
|
msg = Tcl_ErrnoMsg(errno);
|
}
|
}
|
errorlog("%s: %s\r\n",exp_cmdfilename,msg);
|
errorlog("%s: %s\r\n",exp_cmdfilename,msg);
|
exp_exit(interp,1);
|
exp_exit(interp,1);
|
}
|
}
|
}
|
}
|
} else if (!exp_cmdlinecmds) {
|
} else if (!exp_cmdlinecmds) {
|
if (isatty(0)) {
|
if (isatty(0)) {
|
/* no other source of commands, force interactive */
|
/* no other source of commands, force interactive */
|
exp_interactive = TRUE;
|
exp_interactive = TRUE;
|
} else {
|
} else {
|
/* read cmds from redirected stdin */
|
/* read cmds from redirected stdin */
|
exp_cmdfile = stdin;
|
exp_cmdfile = stdin;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
if (exp_interactive) {
|
if (exp_interactive) {
|
Tcl_SetVar(interp, "tcl_interactive","1",TCL_GLOBAL_ONLY);
|
Tcl_SetVar(interp, "tcl_interactive","1",TCL_GLOBAL_ONLY);
|
}
|
}
|
|
|
/* collect remaining args and make into argc, argv0, and argv */
|
/* collect remaining args and make into argc, argv0, and argv */
|
sprintf(argc_rep,"%d",argc-optind);
|
sprintf(argc_rep,"%d",argc-optind);
|
Tcl_SetVar(interp,"argc",argc_rep,0);
|
Tcl_SetVar(interp,"argc",argc_rep,0);
|
debuglog("set argc %s\r\n",argc_rep);
|
debuglog("set argc %s\r\n",argc_rep);
|
|
|
if (exp_cmdfilename) {
|
if (exp_cmdfilename) {
|
Tcl_SetVar(interp,"argv0",exp_cmdfilename,0);
|
Tcl_SetVar(interp,"argv0",exp_cmdfilename,0);
|
debuglog("set argv0 \"%s\"\r\n",exp_cmdfilename);
|
debuglog("set argv0 \"%s\"\r\n",exp_cmdfilename);
|
} else {
|
} else {
|
Tcl_SetVar(interp,"argv0",exp_argv0,0);
|
Tcl_SetVar(interp,"argv0",exp_argv0,0);
|
debuglog("set argv0 \"%s\"\r\n",exp_argv0);
|
debuglog("set argv0 \"%s\"\r\n",exp_argv0);
|
}
|
}
|
|
|
args = Tcl_Merge(argc-optind,argv+optind);
|
args = Tcl_Merge(argc-optind,argv+optind);
|
debuglog("set argv \"%s\"\r\n",args);
|
debuglog("set argv \"%s\"\r\n",args);
|
Tcl_SetVar(interp,"argv",args,0);
|
Tcl_SetVar(interp,"argv",args,0);
|
ckfree(args);
|
ckfree(args);
|
|
|
exp_interpret_rcfiles(interp,my_rc,sys_rc);
|
exp_interpret_rcfiles(interp,my_rc,sys_rc);
|
}
|
}
|
|
|
/* read rc files */
|
/* read rc files */
|
void
|
void
|
exp_interpret_rcfiles(interp,my_rc,sys_rc)
|
exp_interpret_rcfiles(interp,my_rc,sys_rc)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
int my_rc;
|
int my_rc;
|
int sys_rc;
|
int sys_rc;
|
{
|
{
|
int rc;
|
int rc;
|
|
|
if (sys_rc) {
|
if (sys_rc) {
|
char file[200];
|
char file[200];
|
int fd;
|
int fd;
|
|
|
sprintf(file,"%s/expect.rc",SCRIPTDIR);
|
sprintf(file,"%s/expect.rc",SCRIPTDIR);
|
if (-1 != (fd = open(file,0))) {
|
if (-1 != (fd = open(file,0))) {
|
if (TCL_ERROR == (rc = Tcl_EvalFile(interp,file))) {
|
if (TCL_ERROR == (rc = Tcl_EvalFile(interp,file))) {
|
errorlog("error executing system initialization file: %s\r\n",file);
|
errorlog("error executing system initialization file: %s\r\n",file);
|
if (rc != TCL_ERROR)
|
if (rc != TCL_ERROR)
|
errorlog("Tcl_Eval = %d\r\n",rc);
|
errorlog("Tcl_Eval = %d\r\n",rc);
|
if (*interp->result != 0)
|
if (*interp->result != 0)
|
errorlog("%s\r\n",interp->result);
|
errorlog("%s\r\n",interp->result);
|
exp_exit(interp,1);
|
exp_exit(interp,1);
|
}
|
}
|
close(fd);
|
close(fd);
|
}
|
}
|
}
|
}
|
if (my_rc) {
|
if (my_rc) {
|
char file[200];
|
char file[200];
|
char *home;
|
char *home;
|
int fd;
|
int fd;
|
char *getenv();
|
char *getenv();
|
|
|
if ((NULL != (home = getenv("DOTDIR"))) ||
|
if ((NULL != (home = getenv("DOTDIR"))) ||
|
(NULL != (home = getenv("HOME")))) {
|
(NULL != (home = getenv("HOME")))) {
|
sprintf(file,"%s/.expect.rc",home);
|
sprintf(file,"%s/.expect.rc",home);
|
if (-1 != (fd = open(file,0))) {
|
if (-1 != (fd = open(file,0))) {
|
if (TCL_ERROR == (rc = Tcl_EvalFile(interp,file))) {
|
if (TCL_ERROR == (rc = Tcl_EvalFile(interp,file))) {
|
errorlog("error executing file: %s\r\n",file);
|
errorlog("error executing file: %s\r\n",file);
|
if (rc != TCL_ERROR)
|
if (rc != TCL_ERROR)
|
errorlog("Tcl_Eval = %d\r\n",rc);
|
errorlog("Tcl_Eval = %d\r\n",rc);
|
if (*interp->result != 0)
|
if (*interp->result != 0)
|
errorlog("%s\r\n",interp->result);
|
errorlog("%s\r\n",interp->result);
|
exp_exit(interp,1);
|
exp_exit(interp,1);
|
}
|
}
|
close(fd);
|
close(fd);
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
int
|
int
|
exp_interpret_cmdfilename(interp,filename)
|
exp_interpret_cmdfilename(interp,filename)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
char *filename;
|
char *filename;
|
{
|
{
|
int rc;
|
int rc;
|
|
|
debuglog("executing commands from command file %s\r\n",filename);
|
debuglog("executing commands from command file %s\r\n",filename);
|
|
|
Tcl_ResetResult(interp);
|
Tcl_ResetResult(interp);
|
if (TCL_OK != (rc = Tcl_EvalFile(interp,filename))) {
|
if (TCL_OK != (rc = Tcl_EvalFile(interp,filename))) {
|
/* EvalFile doesn't bother to copy error to errorInfo */
|
/* EvalFile doesn't bother to copy error to errorInfo */
|
/* so force it */
|
/* so force it */
|
Tcl_AddErrorInfo(interp, "");
|
Tcl_AddErrorInfo(interp, "");
|
handle_eval_error(interp,0);
|
handle_eval_error(interp,0);
|
}
|
}
|
return rc;
|
return rc;
|
}
|
}
|
|
|
int
|
int
|
exp_interpret_cmdfile(interp,fp)
|
exp_interpret_cmdfile(interp,fp)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
FILE *fp;
|
FILE *fp;
|
{
|
{
|
int rc = 0;
|
int rc = 0;
|
int newcmd;
|
int newcmd;
|
int eof;
|
int eof;
|
|
|
Tcl_DString dstring;
|
Tcl_DString dstring;
|
Tcl_DStringInit(&dstring);
|
Tcl_DStringInit(&dstring);
|
|
|
debuglog("executing commands from command file\r\n");
|
debuglog("executing commands from command file\r\n");
|
|
|
newcmd = TRUE;
|
newcmd = TRUE;
|
eof = FALSE;
|
eof = FALSE;
|
while (1) {
|
while (1) {
|
char line[BUFSIZ];/* buffer for partial Tcl command */
|
char line[BUFSIZ];/* buffer for partial Tcl command */
|
char *ccmd; /* pointer to complete Tcl command */
|
char *ccmd; /* pointer to complete Tcl command */
|
|
|
if (fgets(line,BUFSIZ,fp) == NULL) {
|
if (fgets(line,BUFSIZ,fp) == NULL) {
|
if (newcmd) break;
|
if (newcmd) break;
|
eof = TRUE;
|
eof = TRUE;
|
}
|
}
|
ccmd = Tcl_DStringAppend(&dstring,line,-1);
|
ccmd = Tcl_DStringAppend(&dstring,line,-1);
|
if (!Tcl_CommandComplete(ccmd) && !eof) {
|
if (!Tcl_CommandComplete(ccmd) && !eof) {
|
newcmd = FALSE;
|
newcmd = FALSE;
|
continue; /* continue collecting command */
|
continue; /* continue collecting command */
|
}
|
}
|
newcmd = TRUE;
|
newcmd = TRUE;
|
|
|
rc = Tcl_Eval(interp,ccmd);
|
rc = Tcl_Eval(interp,ccmd);
|
Tcl_DStringFree(&dstring);
|
Tcl_DStringFree(&dstring);
|
if (rc != TCL_OK) {
|
if (rc != TCL_OK) {
|
handle_eval_error(interp,0);
|
handle_eval_error(interp,0);
|
break;
|
break;
|
}
|
}
|
if (eof) break;
|
if (eof) break;
|
}
|
}
|
Tcl_DStringFree(&dstring);
|
Tcl_DStringFree(&dstring);
|
return rc;
|
return rc;
|
}
|
}
|
|
|
#ifdef SHARE_CMD_BUFFER
|
#ifdef SHARE_CMD_BUFFER
|
/* fgets that shared input buffer with expect_user */
|
/* fgets that shared input buffer with expect_user */
|
int
|
int
|
exp_fgets(interp,buf,max)
|
exp_fgets(interp,buf,max)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
char *buf;
|
char *buf;
|
int max;
|
int max;
|
{
|
{
|
char *nl; /* position of newline which signifies end of line */
|
char *nl; /* position of newline which signifies end of line */
|
int write_count;/* length of first line of incoming data */
|
int write_count;/* length of first line of incoming data */
|
|
|
int m = fileno(stdin);
|
int m = fileno(stdin);
|
struct exp_f *f;
|
struct exp_f *f;
|
int cc;
|
int cc;
|
|
|
int dummy;
|
int dummy;
|
|
|
/* avoid returning no data, just because someone else read it in by */
|
/* avoid returning no data, just because someone else read it in by */
|
/* passing most recent key */
|
/* passing most recent key */
|
cc = exp_get_next_event(interp,&m,1,&dummy,EXP_TIME_INFINITY,exp_fs[m].key);
|
cc = exp_get_next_event(interp,&m,1,&dummy,EXP_TIME_INFINITY,exp_fs[m].key);
|
|
|
if (cc == EXP_DATA_NEW) {
|
if (cc == EXP_DATA_NEW) {
|
/* try to read it */
|
/* try to read it */
|
|
|
cc = exp_i_read(m,EXP_TIME_INFINITY);
|
cc = exp_i_read(m,EXP_TIME_INFINITY);
|
|
|
/* the meaning of 0 from i_read means eof. Muck with it a */
|
/* the meaning of 0 from i_read means eof. Muck with it a */
|
/* little, so that from now on it means "no new data arrived */
|
/* little, so that from now on it means "no new data arrived */
|
/* but it should be looked at again anyway". */
|
/* but it should be looked at again anyway". */
|
if (cc == 0) {
|
if (cc == 0) {
|
cc = EXP_EOF;
|
cc = EXP_EOF;
|
} else if (cc > 0) {
|
} else if (cc > 0) {
|
f = exp_fs + m;
|
f = exp_fs + m;
|
f->buffer[f->size += cc] = '\0';
|
f->buffer[f->size += cc] = '\0';
|
}
|
}
|
} else if (cc == EXP_DATA_OLD) {
|
} else if (cc == EXP_DATA_OLD) {
|
f = exp_fs + m;
|
f = exp_fs + m;
|
cc = 0;
|
cc = 0;
|
}
|
}
|
|
|
/* EOF and TIMEOUT return here */
|
/* EOF and TIMEOUT return here */
|
/* In such cases, there is no need to update screen since, if there */
|
/* In such cases, there is no need to update screen since, if there */
|
/* was prior data read, it would have been sent to the screen when */
|
/* was prior data read, it would have been sent to the screen when */
|
/* it was read. */
|
/* it was read. */
|
if (cc < 0) return (cc);
|
if (cc < 0) return (cc);
|
|
|
/* copy up to end of first line */
|
/* copy up to end of first line */
|
|
|
/* calculate end of first line */
|
/* calculate end of first line */
|
nl = strchr(f->buffer,'\n');
|
nl = strchr(f->buffer,'\n');
|
if (nl) write_count = 1+nl-f->buffer;
|
if (nl) write_count = 1+nl-f->buffer;
|
else write_count = f->size;
|
else write_count = f->size;
|
|
|
/* make sure line fits in buffer area */
|
/* make sure line fits in buffer area */
|
if (write_count > max) write_count = max;
|
if (write_count > max) write_count = max;
|
|
|
/* copy it */
|
/* copy it */
|
memcpy(buf,f->buffer,write_count);
|
memcpy(buf,f->buffer,write_count);
|
buf[write_count] = '\0';
|
buf[write_count] = '\0';
|
|
|
/* update display and f */
|
/* update display and f */
|
|
|
f->printed = 0;
|
f->printed = 0;
|
/* for simplicity force f->printed = 0. This way, the user gets */
|
/* for simplicity force f->printed = 0. This way, the user gets */
|
/* to see the commands that are about to be executed. Not seeing */
|
/* to see the commands that are about to be executed. Not seeing */
|
/* commands you are supposedly typing sounds very uncomfortable! */
|
/* commands you are supposedly typing sounds very uncomfortable! */
|
|
|
if (logfile_all || (loguser && logfile)) {
|
if (logfile_all || (loguser && logfile)) {
|
fwrite(f->buffer,1,write_count,logfile);
|
fwrite(f->buffer,1,write_count,logfile);
|
}
|
}
|
if (debugfile) fwrite(f->buffer,1,write_count,debugfile);
|
if (debugfile) fwrite(f->buffer,1,write_count,debugfile);
|
|
|
f->size -= write_count;
|
f->size -= write_count;
|
memcpy(f->buffer,f->buffer+write_count,1+f->size);
|
memcpy(f->buffer,f->buffer+write_count,1+f->size);
|
/* copy to lowercase buffer */
|
/* copy to lowercase buffer */
|
exp_lowmemcpy(f->lower,f->buffer,1+f->size);
|
exp_lowmemcpy(f->lower,f->buffer,1+f->size);
|
|
|
return(write_count);
|
return(write_count);
|
}
|
}
|
#endif /*SHARE_CMD_BUFFER*/
|
#endif /*SHARE_CMD_BUFFER*/
|
|
|
static struct exp_cmd_data cmd_data[] = {
|
static struct exp_cmd_data cmd_data[] = {
|
{"expect_version",exp_proc(Exp_ExpVersionCmd), 0, 0}, /* deprecated */
|
{"expect_version",exp_proc(Exp_ExpVersionCmd), 0, 0}, /* deprecated */
|
{"exp_version", exp_proc(Exp_ExpVersionCmd), 0, 0},
|
{"exp_version", exp_proc(Exp_ExpVersionCmd), 0, 0},
|
{"prompt1", exp_proc(Exp_Prompt1Cmd), 0, EXP_NOPREFIX},
|
{"prompt1", exp_proc(Exp_Prompt1Cmd), 0, EXP_NOPREFIX},
|
{"prompt2", exp_proc(Exp_Prompt2Cmd), 0, EXP_NOPREFIX},
|
{"prompt2", exp_proc(Exp_Prompt2Cmd), 0, EXP_NOPREFIX},
|
{0}};
|
{0}};
|
|
|
void
|
void
|
exp_init_main_cmds(interp)
|
exp_init_main_cmds(interp)
|
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
{
|
{
|
exp_create_commands(interp,cmd_data);
|
exp_create_commands(interp,cmd_data);
|
}
|
}
|
|
|