summaryrefslogtreecommitdiff
path: root/exp_select.c
diff options
context:
space:
mode:
Diffstat (limited to 'exp_select.c')
-rw-r--r--exp_select.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/exp_select.c b/exp_select.c
new file mode 100644
index 0000000..de30853
--- /dev/null
+++ b/exp_select.c
@@ -0,0 +1,290 @@
+/* exp_select.c - select() interface for Expect
+
+Written by: Don Libes, NIST, 2/6/90
+
+Design and implementation of this program was paid for by U.S. tax
+dollars. Therefore it is public domain. However, the author and NIST
+would appreciate credit if this program or parts of it are used.
+
+*/
+
+/* suppress file-empty warnings produced by some compilers */
+void exp_unused() {}
+
+#if 0 /* WHOLE FILE!!!! */
+#include "expect_cf.h"
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYSSELECT_H
+# include <sys/select.h> /* Intel needs this for timeval */
+#endif
+
+#ifdef HAVE_PTYTRAP
+# include <sys/ptyio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef _AIX
+/* AIX has some unusual definition of FD_SET */
+#include <sys/select.h>
+#endif
+
+#if !defined( FD_SET ) && defined( HAVE_SYS_BSDTYPES_H )
+ /* like AIX, ISC has it's own definition of FD_SET */
+# include <sys/bsdtypes.h>
+#endif /* ! FD_SET && HAVE_SYS_BSDTYPES_H */
+
+#include "tcl.h"
+#include "exp_prog.h"
+#include "exp_command.h" /* for struct exp_f defs */
+#include "exp_event.h"
+
+#ifdef HAVE_SYSCONF_H
+#include <sys/sysconfig.h>
+#endif
+
+#ifndef FD_SET
+#define FD_SET(fd,fdset) (fdset)->fds_bits[0] |= (1<<(fd))
+#define FD_CLR(fd,fdset) (fdset)->fds_bits[0] &= ~(1<<(fd))
+#define FD_ZERO(fdset) (fdset)->fds_bits[0] = 0
+#define FD_ISSET(fd,fdset) (((fdset)->fds_bits[0]) & (1<<(fd)))
+#ifndef AUX2
+typedef struct fd_set {
+ long fds_bits[1];
+ /* any implementation so pathetic as to not define FD_SET will just */
+ /* have to suffer with only 32 bits worth of fds */
+} fd_set;
+#endif /* AUX2 */
+#endif
+
+static struct timeval zerotime = {0, 0};
+static struct timeval anytime = {0, 0}; /* can be changed by user */
+
+/* returns status, one of EOF, TIMEOUT, ERROR or DATA */
+int
+exp_get_next_event(interp,masters, n,master_out,timeout,key)
+Tcl_Interp *interp;
+int *masters;
+int n; /* # of masters */
+int *master_out; /* 1st event master, not set if none */
+int timeout; /* seconds */
+int key;
+{
+ static rr = 0; /* round robin ptr */
+
+ int i; /* index into in-array */
+ struct timeval *t;
+
+ fd_set rdrs;
+ fd_set excep;
+/* FIXME: This is really gross, but the folks at Lynx said their select is
+ * way hosed and to ignore all exceptions.
+ */
+#ifdef __Lynx__
+#define EXCEP 0
+#else
+#define EXCEP &excep
+#endif
+
+ for (i=0;i<n;i++) {
+ struct exp_f *f;
+ int m;
+
+ 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 (timeout >= 0) {
+ t = &anytime;
+ t->tv_sec = timeout;
+ } else {
+ t = NULL;
+ }
+
+ restart:
+ if (Tcl_AsyncReady()) {
+ int rc = Tcl_AsyncInvoke(interp,TCL_OK);
+ if (rc != TCL_OK) return(exp_tcl2_returnvalue(rc));
+
+ /* anything in the environment could have changed */
+ return EXP_RECONFIGURE;
+ }
+
+ FD_ZERO(&rdrs);
+ FD_ZERO(&excep);
+ for (i = 0;i < n;i++) {
+ FD_SET(masters[i],&rdrs);
+ FD_SET(masters[i],&excep);
+ }
+
+ /* The reason all fd masks are (seemingly) redundantly cast to */
+ /* SELECT_MASK_TYPE is that the HP defines its mask in terms of */
+ /* of int * and yet defines FD_SET in terms of fd_set. */
+
+ if (-1 == select(exp_fd_max+1,
+ (SELECT_MASK_TYPE *)&rdrs,
+ (SELECT_MASK_TYPE *)0,
+ (SELECT_MASK_TYPE *)EXCEP,
+ t)) {
+ /* window refreshes trigger EINTR, ignore */
+ if (errno == EINTR) goto restart;
+ else if (errno == EBADF) {
+ /* someone is rotten */
+ for (i=0;i<n;i++) {
+ fd_set suspect;
+ FD_ZERO(&suspect);
+ FD_SET(masters[i],&suspect);
+ if (-1 == select(exp_fd_max+1,
+ (SELECT_MASK_TYPE *)&suspect,
+ (SELECT_MASK_TYPE *)0,
+ (SELECT_MASK_TYPE *)0,
+ &zerotime)) {
+ exp_error(interp,"invalid spawn_id (%d)\r",masters[i]);
+ return(EXP_TCLERROR);
+ }
+ }
+ } else {
+ /* not prepared to handle anything else */
+ exp_error(interp,"select: %s\r",Tcl_PosixError(interp));
+ return(EXP_TCLERROR);
+ }
+ }
+
+ for (i=0;i<n;i++) {
+ rr++;
+ if (rr >= n) rr = 0; /* ">" catches previous readys that */
+ /* used more fds then we're using now */
+
+ if (FD_ISSET(masters[rr],&rdrs)) {
+ *master_out = masters[rr];
+ return(EXP_DATA_NEW);
+/*#ifdef HAVE_PTYTRAP*/
+ } else if (FD_ISSET(masters[rr], &excep)) {
+#ifndef HAVE_PTYTRAP
+ *master_out = masters[rr];
+ return(EXP_EOF);
+#else
+ struct request_info ioctl_info;
+ if (ioctl(masters[rr],TIOCREQCHECK,&ioctl_info) < 0) {
+ exp_DiagLog("ioctl error on TIOCREQCHECK: %s",Tcl_ErrnoMsg(errno));
+ break;
+ }
+ if (ioctl_info.request == TIOCCLOSE) {
+ /* eof */
+ *master_out = masters[rr];
+ return(EXP_EOF);
+ }
+ if (ioctl(masters[rr], TIOCREQSET, &ioctl_info) < 0)
+ expDiagLog("ioctl error on TIOCREQSET after ioctl or open on slave: %s", Tcl_ErrnoMsg(errno));
+ /* presumably, we trapped an open here */
+ goto restart;
+#endif /* HAVE_PTYTRAP */
+ }
+ }
+ return(EXP_TIMEOUT);
+}
+
+/*ARGSUSED*/
+int
+exp_get_next_event_info(interp,fd,ready_mask)
+Tcl_Interp *interp;
+int fd;
+int ready_mask;
+{
+ /* this function is only used when running with Tk */
+ /* hence, it is merely a stub in this file but to */
+ /* pacify lint, return something */
+ return 0;
+}
+
+int /* returns TCL_XXX */
+exp_dsleep(interp,sec)
+Tcl_Interp *interp;
+double sec;
+{
+ struct timeval t;
+
+ t.tv_sec = sec;
+ t.tv_usec = (sec - t.tv_sec) * 1000000L;
+ restart:
+ if (Tcl_AsyncReady()) {
+ int rc = Tcl_AsyncInvoke(interp,TCL_OK);
+ if (rc != TCL_OK) return rc;
+ }
+ if (-1 == select(1,
+ (SELECT_MASK_TYPE *)0,
+ (SELECT_MASK_TYPE *)0,
+ (SELECT_MASK_TYPE *)0,
+ &t)
+ && errno == EINTR)
+ goto restart;
+ return TCL_OK;
+}
+
+#if 0
+int /* returns TCL_XXX */
+exp_usleep(interp,usec)
+Tcl_Interp *interp;
+long usec; /* microseconds */
+{
+ struct timeval t;
+
+ t.tv_sec = usec/1000000L;
+ t.tv_usec = usec%1000000L;
+ restart:
+ if (Tcl_AsyncReady()) {
+ int rc = Tcl_AsyncInvoke(interp,TCL_OK);
+ if (rc != TCL_OK) return(exp_tcl2_returnvalue(rc));
+ }
+ if (-1 == select(1,
+ (SELECT_MASK_TYPE *)0,
+ (SELECT_MASK_TYPE *)0,
+ (SELECT_MASK_TYPE *)0,
+ &t)
+ && errno == EINTR)
+ goto restart;
+ return TCL_OK;
+}
+#endif /*0*/
+
+/* set things up for later calls to event handler */
+void
+exp_init_event()
+{
+#if 0
+#ifdef _SC_OPEN_MAX
+ maxfds = sysconf(_SC_OPEN_MAX);
+#else
+ maxfds = getdtablesize();
+#endif
+#endif
+
+ exp_event_exit = 0;
+}
+#endif /* WHOLE FILE !!!! */