#include "expect_cf.h"
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_PTYTRAP
# include <sys/ptyio.h>
#endif
#include "tcl.h"
#include "exp_prog.h"
#include "exp_command.h"
#include "exp_event.h"
static int ready_fd = EXP_SPAWN_ID_BAD;
static int ready_mask;
static int default_mask = TCL_READABLE | TCL_EXCEPTION;
void
exp_event_disarm(fd)
int fd;
{
#if TCL_MAJOR_VERSION < 8
Tcl_DeleteFileHandler(exp_fs[fd].Master);
#else
Tcl_DeleteFileHandler(fd);
#endif
exp_fs[fd].fg_armed = FALSE;
}
void
exp_event_disarm_fast(fd,filehandler)
int fd;
Tcl_FileProc *filehandler;
{
#if TCL_MAJOR_VERSION < 8
Tcl_CreateFileHandler(exp_fs[fd].Master,0,filehandler,(ClientData)0);
#else
Tcl_CreateFileHandler(fd,0,filehandler,(ClientData)0);
#endif
exp_fs[fd].fg_armed = FALSE;
}
static void
exp_arm_background_filehandler_force(m)
int m;
{
#if TCL_MAJOR_VERSION < 8
Tcl_CreateFileHandler(exp_fs[m].Master,
#else
Tcl_CreateFileHandler(m,
#endif
TCL_READABLE|TCL_EXCEPTION,
exp_background_filehandler,
(ClientData)(exp_fs[m].fd_ptr));
exp_fs[m].bg_status = armed;
}
void
exp_arm_background_filehandler(m)
int m;
{
switch (exp_fs[m].bg_status) {
case unarmed:
exp_arm_background_filehandler_force(m);
break;
case disarm_req_while_blocked:
exp_fs[m].bg_status = blocked;
break;
case armed:
case blocked:
break;
}
}
void
exp_disarm_background_filehandler(m)
int m;
{
switch (exp_fs[m].bg_status) {
case blocked:
exp_fs[m].bg_status = disarm_req_while_blocked;
break;
case armed:
exp_fs[m].bg_status = unarmed;
exp_event_disarm(m);
break;
case disarm_req_while_blocked:
case unarmed:
break;
}
}
void
exp_disarm_background_filehandler_force(m)
int m;
{
switch (exp_fs[m].bg_status) {
case blocked:
case disarm_req_while_blocked:
case armed:
exp_fs[m].bg_status = unarmed;
exp_event_disarm(m);
break;
case unarmed:
break;
}
}
void
exp_unblock_background_filehandler(m)
int m;
{
switch (exp_fs[m].bg_status) {
case blocked:
exp_arm_background_filehandler_force(m);
break;
case disarm_req_while_blocked:
exp_disarm_background_filehandler_force(m);
break;
case armed:
case unarmed:
break;
}
}
void
exp_block_background_filehandler(m)
int m;
{
exp_fs[m].bg_status = blocked;
exp_event_disarm_fast(m,exp_background_filehandler);
}
static void
exp_timehandler(clientData)
ClientData clientData;
{
*(int *)clientData = TRUE;
}
static void exp_filehandler(clientData,mask)
ClientData clientData;
int mask;
{
ready_fd = *(int *)clientData;
ready_mask = mask;
exp_event_disarm_fast(ready_fd,exp_filehandler);
#if 0
if (ready_fd == *(int *)clientData) {
exp_event_disarm_fast(ready_fd,exp_filehandler);
} else {
ready_fd = *(int *)clientData;
ready_mask = mask;
}
#endif
}
int exp_get_next_event(interp,masters, n,master_out,timeout,key)
Tcl_Interp *interp;
int *masters;
int n;
int *master_out;
int timeout;
int key;
{
static rr = 0;
int i;
#ifdef HAVE_PTYTRAP
struct request_info ioctl_info;
#endif
int old_configure_count = exp_configure_count;
int timer_created = FALSE;
int timer_fired = FALSE;
Tcl_TimerToken timetoken;
for (;;) {
int m;
struct exp_f *f;
for (i=0;i<n;i++) {
rr++;
if (rr >= n) rr = 0;
m = masters[rr];
f = exp_fs + m;
if (f->key != key) {
f->key = key;
f->force_read = FALSE;
*master_out = m;
return(EXP_DATA_OLD);
} else if ((!f->force_read) && (f->size != 0)) {
*master_out = m;
return(EXP_DATA_OLD);
}
}
if (!timer_created) {
if (timeout >= 0) {
timetoken = Tcl_CreateTimerHandler(1000*timeout,
exp_timehandler,
(ClientData)&timer_fired);
timer_created = TRUE;
}
}
for (;;) {
int j;
for (j=0;j<n;j++) {
int k = masters[j];
if (!exp_fs[k].fg_armed) {
Tcl_CreateFileHandler(
#if TCL_MAJOR_VERSION < 8
exp_fs[k].Master,
#else
k,
#endif
default_mask,
exp_filehandler,
(ClientData)exp_fs[k].fd_ptr);
exp_fs[k].fg_armed = TRUE;
}
}
Tcl_DoOneEvent(0);
if (timer_fired) return(EXP_TIMEOUT);
if (old_configure_count != exp_configure_count) {
if (timer_created) Tcl_DeleteTimerHandler(timetoken);
return EXP_RECONFIGURE;
}
if (ready_fd == EXP_SPAWN_ID_BAD) continue;
for (j=0;j<n;j++) {
if (ready_fd == masters[j]) goto found;
}
exp_event_disarm_fast(ready_fd,exp_filehandler);
ready_fd = EXP_SPAWN_ID_BAD;
continue;
found:
*master_out = ready_fd;
ready_fd = EXP_SPAWN_ID_BAD;
if (ready_mask & TCL_READABLE) {
if (timer_created) Tcl_DeleteTimerHandler(timetoken);
return EXP_DATA_NEW;
}
#ifndef HAVE_PTYTRAP
if (timer_created) Tcl_DeleteTimerHandler(timetoken);
return(EXP_EOF);
#else
if (ioctl(*master_out,TIOCREQCHECK,&ioctl_info) < 0) {
if (timer_created)
Tcl_DeleteTimerHandler(timetoken);
exp_debuglog("ioctl error on TIOCREQCHECK: %s", Tcl_PosixError(interp));
return(EXP_TCLERROR);
}
if (ioctl_info.request == TIOCCLOSE) {
if (timer_created)
Tcl_DeleteTimerHandler(timetoken);
return(EXP_EOF);
}
if (ioctl(*master_out, TIOCREQSET, &ioctl_info) < 0) {
exp_debuglog("ioctl error on TIOCREQSET after ioctl or open on slave: %s", Tcl_ErrnoMsg(errno));
}
continue;
#endif
}
}
}
int
exp_get_next_event_info(interp,fd,ready_mask)
Tcl_Interp *interp;
int fd;
int ready_mask;
{
#ifdef HAVE_PTYTRAP
struct request_info ioctl_info;
#endif
if (ready_mask & TCL_READABLE) return EXP_DATA_NEW;
#ifndef HAVE_PTYTRAP
return(EXP_EOF);
#else
if (ioctl(fd,TIOCREQCHECK,&ioctl_info) < 0) {
exp_debuglog("ioctl error on TIOCREQCHECK: %s",
Tcl_PosixError(interp));
return(EXP_TCLERROR);
}
if (ioctl_info.request == TIOCCLOSE) {
return(EXP_EOF);
}
if (ioctl(fd, TIOCREQSET, &ioctl_info) < 0) {
exp_debuglog("ioctl error on TIOCREQSET after ioctl or open on slave: %s", Tcl_ErrnoMsg(errno));
}
return EXP_TCLERROR;
#endif
}
int
exp_dsleep(interp,sec)
Tcl_Interp *interp;
double sec;
{
int timer_fired = FALSE;
Tcl_CreateTimerHandler((int)(sec*1000),exp_timehandler,(ClientData)&timer_fired);
while (1) {
Tcl_DoOneEvent(0);
if (timer_fired) return TCL_OK;
if (ready_fd == EXP_SPAWN_ID_BAD) continue;
exp_event_disarm_fast(ready_fd,exp_filehandler);
ready_fd = EXP_SPAWN_ID_BAD;
}
}
#if 0
int
exp_usleep(interp,usec)
Tcl_Interp *interp;
long usec;
{
int timer_fired = FALSE;
Tcl_CreateTimerHandler(usec/1000,exp_timehandler,(ClientData)&timer_fired);
while (1) {
Tcl_DoOneEvent(0);
if (timer_fired) return TCL_OK;
if (ready_fd == EXP_SPAWN_ID_BAD) continue;
exp_event_disarm_fast(ready_fd,exp_filehandler);
ready_fd = EXP_SPAWN_ID_BAD;
}
}
#endif
static char destroy_cmd[] = "destroy .";
static void
exp_event_exit_real(interp)
Tcl_Interp *interp;
{
Tcl_Eval(interp,destroy_cmd);
}
void
exp_init_event()
{
exp_event_exit = exp_event_exit_real;
}