BSD 4_3 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Sun, 16 Mar 1986 14:13:33 +0000 (06:13 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Sun, 16 Mar 1986 14:13:33 +0000 (06:13 -0800)
Work on file usr/contrib/emacs/src/sysdep.c

Synthesized-from: CSRG/cd1/4.3

usr/contrib/emacs/src/sysdep.c [new file with mode: 0644]

diff --git a/usr/contrib/emacs/src/sysdep.c b/usr/contrib/emacs/src/sysdep.c
new file mode 100644 (file)
index 0000000..e444f31
--- /dev/null
@@ -0,0 +1,1275 @@
+/* Interfaces to system-dependent kernel and library entries.
+   Copyright (C) 1985 Richard M. Stallman.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY.  No author or distributor
+accepts responsibility to anyone for the consequences of using it
+or for whether it serves any particular purpose or works at all,
+unless he says so in writing.  Refer to the GNU Emacs General Public
+License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+GNU Emacs, but only under the conditions described in the
+GNU Emacs General Public License.   A copy of this license is
+supposed to have been given to you along with GNU Emacs so you
+can know your rights and responsibilities.  It should be in a
+file named COPYING.  Among other things, the copyright notice
+and this notice must be preserved on all copies.  */
+
+
+#include <signal.h>
+
+#include "config.h"
+#include "lisp.h"
+#undef NULL
+
+/* In this file, open, read and write refer to the system calls,
+   not our sugared interfaces  sys_open, sys_read and sys_write.
+   Contrariwise, for systems where we use the system calls directly,
+   define sys_read, etc. here as aliases for them.  */
+#ifndef read
+#define sys_read read
+#define sys_write write
+#endif /* `read' is not a macro */
+
+#undef read
+#undef write
+
+#ifndef open
+#define sys_open open
+#endif /* `open' is not a macro.  */
+
+#undef open
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined (USG) || (defined (BSD) && !defined (BSD4_1))
+#include <fcntl.h>
+#endif
+
+#ifdef BSD
+#include <sys/ioctl.h>
+#ifdef BSD4_1
+#include <wait.h>
+#else /* not 4.1 */
+#include <sys/wait.h>
+#endif /* not 4.1 */
+#include <sgtty.h>
+#define TERMINAL struct sgttyb
+#define OSPEED(str) str.sg_ospeed
+#define TABS_OK(str) ((str.sg_flags & XTABS) != XTABS)
+#endif
+
+/* Get rid of LLITOUT in 4.1, since it is said to stimulate kernel bugs.  */
+#ifdef BSD4_1
+#undef LLITOUT
+#define LLITOUT 0
+#endif /* 4.1 */
+
+#ifdef USG
+#include <termio.h>
+#include <sys/utsname.h>
+#include <memory.h>
+#include <string.h>
+#ifdef HAVE_TIMEVAL
+#ifdef HPUX
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#endif /* HAVE_TIMEVAL */
+#include <errno.h>
+#define TIOCGETP TCGETA
+#define TIOCSETN TCSETA
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+#define OSPEED(str) (str.c_cflag & CBAUD)
+#define TABS_OK(str) ((str.c_oflag & TABDLY) != TAB3)
+#endif /* USG */
+
+#include "termhooks.h"
+#include "termchar.h"
+#include "termopts.h"
+#include "dispextern.h"
+
+#ifdef NONSYSTEM_DIR_LIBRARY
+#include "ndir.h"
+#endif /* NONSYSTEM_DIR_LIBRARY */
+
+/* Define SIGCHLD as an alias for SIGCLD.  There are many conditionals
+   testing SIGCHLD.  */
+
+#if !defined (SIGCHLD) && defined (SIGCLD)
+#define SIGCHLD SIGCLD
+#endif /* SIGCLD and not SIGCHLD */
+
+static int baud_convert[] =
+  {
+    0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
+    1800, 2400, 4800, 9600, 19200, 38400
+  };
+
+extern short ospeed;
+
+discard_tty_input ()
+{
+  TERMINAL buf;
+
+  if (noninteractive)
+    return;
+
+  ioctl (0, TIOCGETP, &buf);
+  ioctl (0, TIOCSETP, &buf);
+}
+
+#ifdef SIGTSTP
+
+stuff_char (c)
+     char c;
+{
+/* Should perhaps error if in batch mode */
+#ifdef TIOCSTI
+  ioctl (0, TIOCSTI, &c);
+#else /* no TIOCSTI */
+  error ("Cannot stuff terminal input characters in this version of Unix.");
+#endif /* no TIOCSTI */
+}
+
+#endif /* SIGTSTP */
+
+init_baud_rate ()
+{
+  TERMINAL sg;
+
+  if (noninteractive)
+    ospeed = 0;
+  else
+    {
+      ioctl (0, TIOCGETP, &sg);
+      ospeed = OSPEED (sg);
+    }
+  baud_rate = ospeed == 0 ? 1200
+    : ospeed < sizeof baud_convert / sizeof baud_convert[0]
+      ? baud_convert[ospeed] : 9600;
+}
+
+set_exclusive_use (fd)
+     int fd;
+{
+#ifdef FIOCLEX
+  ioctl (fd, FIOCLEX, 0);
+#endif
+  /* Ok to do nothing if this feature does not exist */
+}
+
+#ifndef subprocesses
+
+wait_without_blocking ()
+{
+#ifndef USG
+  wait3 (0, WNOHANG | WUNTRACED, 0);
+#else
+  croak ("wait_without_blocking");
+#endif
+}
+
+#endif /* not subprocesses */
+
+int wait_debugging;   /* Set nonzero to make following function work under dbx
+                        (at least for bsd).  */
+
+/* Wait for subprocess with process id `pid' to terminate and
+   make sure it will get eliminated (not remain forever as a zombie) */
+
+wait_for_termination (pid)
+     int pid;
+{
+  int status;
+  while (1)
+    {
+#ifdef subprocesses
+#ifdef BSD
+      /* Note that kill returns -1 even if the process is just a zombie now.
+        But inevitably a SIGCHLD interrupt should be generated
+        and child_sig will do wait3 and make the process go away. */
+      /* There is some indication that there is a bug involved with
+        termination of subprocesses, perhaps involving a kernel bug too,
+        but no idea what it is.  Just as a hunch we signal SIGCHLD to see
+        if that causes the problem to go away or get worse.  */
+#ifdef BSD4_1
+      extern int synch_process_pid;
+      sighold (SIGCHLD);
+      if (synch_process_pid == 0)
+       {
+          sigrelse (SIGCHLD);
+         break;
+       }
+      if (wait_debugging)
+       sleep (1);
+      else
+       sigpause (SIGCHLD);
+#else /* not BSD4_1 */
+      sigsetmask (1 << (SIGCHLD - 1));
+      if (0 > kill (pid, 0))
+        {
+         sigsetmask (0);
+         kill (getpid (), SIGCHLD);
+         break;
+       }
+      if (wait_debugging)
+       sleep (1);
+      else
+       sigpause (0);
+#endif /* not BSD4_1 */
+#else /* not BSD */
+#ifdef UNIPLUS
+      if (0 > kill (pid, 0))
+       break;
+      wait (0);
+#else /* neither BSD nor UNIPLUS: random sysV */
+      if (0 > kill (pid, 0))
+       break;
+      pause ();
+#endif /* not UNIPLUS */
+#endif /* not BSD */
+#else /* not subprocesses */
+#ifndef BSD4_1
+      if (0 > kill (pid, 0))
+       break;
+      wait (0);
+#else /* BSD4_1 */
+      int status;
+      status = wait (0);
+      if (status == pid || status == -1)
+       break;
+#endif /* BSD4_1 */
+#endif /* not subprocesses */
+    }
+}
+/*
+ *     Insert description of what this command is really supposed to
+ *     to (I.E. what state is the child process line to be placed into,
+ *     and why).  I have tried to interpret this as much as possible from
+ *     the BSD setup and map to an appropriate USG control, but don't
+ *     guarantee the results.  fnf@unisoft
+ */
+
+child_setup_tty (out)
+     int out;
+{
+  TERMINAL s;
+
+  ioctl (out, TIOCGETP, &s);
+#ifdef USG
+  s.c_oflag |= OPOST;          /* Enable output postprocessing */
+  s.c_oflag &= ~ONLCR;         /* Disable map of NL to CR-NL on output */
+  s.c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);        /* No output delays */
+  s.c_lflag &= ~ECHO;          /* Disable echo */
+  s.c_lflag &= ~ICANON;                /* Disable erase/kill processing */
+  s.c_lflag |= ISIG;           /* Enable signals */
+  s.c_iflag &= ~IUCLC;         /* Disable map of upper case to lower on input */
+  s.c_oflag &= ~OLCUC;         /* Disable map of lower case to upper on output */
+  s.c_cc[VMIN] = 1;            /* minimum number of characters to accept */
+  s.c_cc[VTIME] = 0;           /* wait forever for at least 1 character */
+#else /* not USG */
+  s.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE | CBREAK | TANDEM);
+#endif /* not USG */
+  ioctl (out, TIOCSETN, &s);
+
+#ifdef BSD4_1
+  if (interrupt_input)
+    reset_sigio ();
+#endif /* BSD4_1 */
+}
+
+setpgrp_of_tty (pid)
+     int pid;
+{
+#ifdef TIOCSPGRP
+  ioctl (0, TIOCSPGRP, &pid);
+#else
+  /* Just ignore this for now and hope for the best */
+#endif
+}
+\f
+#ifdef F_SETFL
+
+init_sigio ()
+{
+  request_sigio ();
+}
+
+reset_sigio ()
+{
+  unrequest_sigio ();
+}
+
+#ifdef FASYNC          /* F_SETFL does not imply existance of FASYNC */
+int old_fcntl_flags;
+
+request_sigio ()
+{
+  old_fcntl_flags = fcntl (0, F_GETFL, 0);
+  fcntl (0, F_SETFL, old_fcntl_flags | FASYNC);
+}
+
+unrequest_sigio ()
+{
+  fcntl (0, F_SETFL, old_fcntl_flags);
+}
+
+#else /* no FASYNC */
+request_sigio ()
+{
+  croak ("request_sigio");
+}
+unrequest_sigio ()
+{
+  croak ("unrequest_sigio");
+}
+#endif /* FASYNC */
+#endif /* F_SETFL */
+\f
+TERMINAL old_gtty;             /* The initial tty mode bits */
+
+int term_initted;              /* 1 if outer tty status has been recorded */
+
+#ifdef F_SETOWN
+int old_fcntl_owner;
+#endif /* F_SETOWN */
+
+#ifdef TIOCGLTC
+struct tchars old_tchars;
+struct ltchars old_ltchars;
+int old_lmode;
+
+int lmode;                     /* Current lmode value. */
+                               /* Needed as global for 4.1 */
+#endif /* TIOCGLTC */
+
+/* This may also be defined in stdio,
+   but if so, this does no harm,
+   and using the same name avoids wasting the other one's space.  */
+
+#ifdef USG
+unsigned char _sobuf[BUFSIZ+8];
+#else
+char _sobuf[BUFSIZ];
+#endif
+init_sys_modes ()
+{
+  TERMINAL sg;
+#ifdef TIOCGLTC
+  struct tchars tchars;
+  static struct tchars new_tchars = {-1,-1,-1,-1,-1,-1};
+  static struct ltchars new_ltchars = {-1,-1,-1,-1,-1,-1};
+#endif
+
+  if (noninteractive)
+    return;
+
+  ioctl (0, TIOCGETP, &old_gtty);
+  if (!read_socket_hook)
+    {
+      sg = old_gtty;
+
+#ifdef USG
+      sg.c_iflag |= (IGNBRK);  /* Ignore break condition */
+      sg.c_iflag &= ~ICRNL;    /* Disable map of CR to NL on input */
+#ifdef ISTRIP
+      sg.c_iflag &= ~ISTRIP;   /* don't strip 8th bit on input */
+#endif
+      sg.c_lflag &= ~ECHO;     /* Disable echo */
+      sg.c_lflag &= ~ICANON;   /* Disable erase/kill processing */
+      sg.c_lflag |= ISIG;      /* Enable signals */
+      if (flow_control)
+       {
+         sg.c_iflag |= IXON;   /* Enable start/stop output control */
+#ifdef IXANY
+         sg.c_iflag &= ~IXANY;
+#endif /* IXANY */
+       }
+      else
+       sg.c_iflag &= ~IXON;    /* Disable start/stop output control */
+      sg.c_oflag &= ~ONLCR;    /* Disable map of NL to CR-NL on output */
+      sg.c_oflag &= ~TAB3;     /* Disable tab expansion */
+#ifdef CS8
+      sg.c_cflag |= CS8;       /* allow 8th bit on input */
+      sg.c_cflag &= ~PARENB;   /* Don't check parity */
+#endif
+      sg.c_cc[VINTR] = '\007'; /* ^G gives SIGINT */
+#ifdef HPUX
+      /* Can't use CDEL as that makes Meta-DEL do SIGQUIT.
+        Instead set up C-g for both; we handle both alike
+        so which one it really gives us does not matter.  */
+      sg.c_cc[VQUIT] = '\007';
+#else /* not HPUX */
+      sg.c_cc[VQUIT] = CDEL;   /* Turn off SIGQUIT */
+#endif /* not HPUX */
+      sg.c_cc[VMIN] = 1;       /* Input should wait for at least 1 char */
+      sg.c_cc[VTIME] = 0;      /* no matter how long that takes.  */
+#ifdef VSWTCH
+      sg.c_cc[VSWTCH] = CDEL;  /* Turn off shell layering use of C-z */
+#endif /* VSWTCH */
+#else /* if not USG */
+      sg.sg_flags &= ~(ECHO | CRMOD | XTABS);
+      sg.sg_flags |= ANYP;
+      sg.sg_flags |= interrupt_input ? RAW : CBREAK;
+#endif /* not USG (BSD, that is) */
+
+      ioctl (0, TIOCSETN, &sg);
+
+#ifdef F_SETFL
+#ifdef F_GETOWN                /* F_SETFL does not imply existance of F_GETOWN */
+      if (interrupt_input)
+       {
+         old_fcntl_owner = fcntl (0, F_GETOWN, 0);
+         fcntl (0, F_SETOWN, getpid ());
+         init_sigio ();
+       }
+#endif /* F_GETOWN */
+#endif /* F_SETFL */
+
+      /* If going to use CBREAK mode, we must request C-g to interrupt
+          and turn off start and stop chars, etc.
+          If not going to use CBREAK mode, do this anyway
+          so as to turn off local flow control for user coming over
+          network on 4.2; in this case, only t_stopc and t_startc really matter.  */
+#ifdef TIOCGLTC
+      ioctl (0, TIOCGETC, &old_tchars);
+      ioctl (0, TIOCGLTC, &old_ltchars);
+      ioctl (0, TIOCLGET, &old_lmode);
+
+      /* Note: if not using CBREAK mode, it makes no difference how we set this */
+      tchars = new_tchars;
+      tchars.t_intrc = 07;
+      if (flow_control)
+       {
+         tchars.t_startc = '\021';
+         tchars.t_stopc = '\023';
+       }
+/* LPASS8 is new in 4.3, and makes cbreak mode provide all 8 bits.  */
+#ifndef LPASS8
+#define LPASS8 0
+#endif
+
+#ifdef BSD4_1
+#define LNOFLSH 0100000
+#endif
+
+      lmode = LDECCTQ | LLITOUT | LPASS8 | LNOFLSH | old_lmode;
+
+      ioctl (0, TIOCSETC, &tchars);
+      ioctl (0, TIOCSLTC, &new_ltchars);
+      ioctl (0, TIOCLSET, &lmode);
+#endif TIOCGLTC
+#ifdef BSD4_1
+      if (interrupt_input)
+       init_sigio ();
+#endif
+    }
+  screen_garbaged = 1;
+  setbuf (stdout, _sobuf);
+  term_initted = 1;
+  set_terminal_modes ();
+}
+
+/* Return nonzero if safe to use tabs in output.
+   At the time this is called, init_sys_modes has not been done yet.  */
+   
+tabs_safe_p ()
+{
+  TERMINAL sg;
+  if (noninteractive)
+    return 1;
+  ioctl (0, TIOCGETP, &sg);
+  return (TABS_OK(sg));
+}
+
+/* Get terminal size from system.
+   Store number of lines into *heightp and width into *widthp.
+   If zero or a negative number is stored, the value is not valid.  */
+
+get_screen_size (widthp, heightp)
+     int *widthp, *heightp;
+{
+/* Define the 4.3 names in terms of the Sun names
+   if the latter exist and the former do not.  */
+#if !defined (TIOCGWINSZ) && defined (TIOCGSIZE)
+#define TIOCGWINSZ TIOCGSIZE
+#define winsize ttysize
+#define ws_row ts_lines
+#define ws_col ts_cols
+#endif /* Sun */
+
+#ifdef TIOCGWINSZ
+  struct winsize size;
+  *widthp = 0;
+  *heightp = 0;
+  if (ioctl (0, TIOCGWINSZ, &size) < 0)
+    return;
+  *widthp = size.ws_col;
+  *heightp = size.ws_row;
+#else /* system doesn't know size */
+  *widthp = 0;
+  *heightp = 0;
+#endif /* system does not know size */
+}
+\f
+reset_sys_modes ()
+{
+  if (noninteractive)
+    {
+      fflush (stdout);
+      return;
+    }
+  if (!term_initted)
+    return;
+  topos (screen_height - 1, 0);
+  clear_end_of_line (screen_width);
+  /* clear_end_of_line may move the cursor */
+  topos (screen_height - 1, 0);
+  reset_terminal_modes ();
+  fflush (stdout);
+  if (read_socket_hook)
+    return;
+#ifdef TIOCGLTC
+  ioctl (0, TIOCSETC, &old_tchars);
+  ioctl (0, TIOCSLTC, &old_ltchars);
+  ioctl (0, TIOCLSET, &old_lmode);
+#endif /* TIOCGLTC */
+#ifdef F_SETFL
+#ifdef F_SETOWN                /* F_SETFL does not imply existance of F_SETOWN */
+  if (interrupt_input)
+    {
+#ifdef FASYNC
+      old_fcntl_flags &= ~FASYNC;
+#endif /* FASYNC */
+      reset_sigio ();
+      reset_sigio ();
+      fcntl (0, F_SETOWN, old_fcntl_owner);
+    }
+#endif /* F_SETOWN */
+#endif /* F_SETFL */
+#ifdef BSD4_1
+  if (interrupt_input)
+    reset_sigio ();
+#endif /* BSD4_1 */
+  ioctl (0, TIOCSETN, &old_gtty);
+}
+
+/*
+ *     flush any pending output
+ */
+flush_pending_output (channel)
+     int channel;
+{
+#ifdef USG
+  ioctl (channel, TCFLSH, 1);
+#else
+  ioctl (channel, TIOCFLUSH, 0);
+#endif
+}
+/*
+ *     Return the address of the start of the text segment prior to
+ *     doing an unexec().  After unexec() the return value is undefined.
+ *     See crt0.c for further explanation and _start().
+ *
+ */
+
+char *
+start_of_text ()
+{
+#ifdef TEXT_START
+  return ((char *) TEXT_START);
+#else
+  extern int _start ();
+  return ((char *) _start);
+#endif
+}
+
+/*
+ *     Return the address of the start of the data segment prior to
+ *     doing an unexec().  After unexec() the return value is undefined.
+ *     See crt0.c for further information and definition of data_start.
+ *
+ *     Apparently, on BSD systems this is etext at startup.  On
+ *     USG systems (swapping) this is highly mmu dependent and
+ *     is also dependent on whether or not the program is running
+ *     with shared text.  Generally there is a (possibly large)
+ *     gap between end of text and start of data with shared text.
+ *
+ *     On Uniplus+ systems with shared text, data starts at a
+ *     fixed address.  Each port (from a given oem) is generally
+ *     different, and the specific value of the start of data can
+ *     be obtained via the UniPlus+ specific "uvar(2)" system call,
+ *     however the method outlined in crt0.c seems to be more portable.
+ *
+ *     Probably what will have to happen when a USG unexec is available,
+ *     at least on UniPlus, is temacs will have to be made unshared so
+ *     that text and data are contiguous.  Then once loadup is complete,
+ *     unexec will produce a shared executable where the data can be
+ *     at the normal shared text boundry and the startofdata variable
+ *     will be patched by unexec to the correct value.
+ *
+ */
+char *
+start_of_data ()
+{
+#ifdef DATA_START
+  return ((char *) DATA_START);
+#else
+  extern int data_start;
+  return ((char *) &data_start);
+#endif
+}
+
+#ifdef NOTDEF
+
+/*
+ *     Return the address of the end of the text segment prior to
+ *     doing an unexec().  After unexec() the return value is undefined.
+ */
+char *
+end_of_text ()
+{
+#ifdef TEXT_END
+  return ((char *) TEXT_END);
+#else
+  extern int etext;
+  return ((char *) &etext);
+#endif
+}
+/*
+ *     Return the address of the end of the data segment prior to
+ *     doing an unexec().  After unexec() the return value is undefined.
+ */
+
+char *
+end_of_data ()
+{
+#ifdef DATA_END
+  return ((char *) DATA_END);
+#else
+  extern int edata;
+  return ((char *) &edata);
+#endif
+}
+
+#endif NOTDEF
+\f
+
+/* Get_system_name returns as its value
+ a string for the Lisp function system-name to return. */
+
+#ifdef USG
+struct utsname get_system_name_name;
+#endif
+#ifdef BSD4_1
+#include <whoami.h>
+#endif
+
+char *
+get_system_name ()
+{
+#ifdef USG
+  uname (&get_system_name_name);
+  return (get_system_name_name.nodename);
+#else /* Not USG */
+#ifdef BSD4_1
+  return sysname;
+#else /* BSD, not 4.1 */
+  static char system_name_saved[32];
+  (void) gethostname (system_name_saved, sizeof (system_name_saved));
+  return (system_name_saved);
+#endif /* BSD, not 4.1 */
+#endif /* not USG */
+}
+\f
+#ifndef HAVE_SELECT
+
+/* Emulate as much as select as is possible under 4.1 and needed by Gnu Emacs
+ * Only checks read descriptors.
+ */
+/* How long to wait between checking fds in select */
+#define SELECT_PAUSE 1
+int select_alarmed;
+
+select_alarm ()
+{
+  select_alarmed = 1;
+#ifdef BSD4_1
+  sigrelse (SIGALRM);
+#else /* not BSD4_1 */
+  signal (SIGALRM, SIG_IGN);
+#endif /* not BSD4_1 */
+}
+
+/* Only rfds are checked and timeout must point somewhere */
+int
+select (nfds, rfds, wfds, efds, timeout)
+     int nfds;
+     int *rfds, *wfds, *efds, *timeout;
+{
+  int ravail = 0, orfds = 0, old_alarm, val;
+  extern int kbd_count;
+  extern int proc_buffered_char[];
+  extern int child_changed;
+  int (*old_trap) ();
+  char buf;
+
+  if (rfds)
+    {
+      orfds = *rfds;
+      *rfds = 0;
+    }
+  if (wfds)
+    *wfds = 0;
+  if (efds)
+    *efds = 0;
+
+  /* If we are looking only for the terminal, with no timeout,
+     just read it and wait -- that's more efficient.  */
+  if (orfds == 1 && *timeout == 100000 && !child_changed)
+    {
+      if (!kbd_count)
+       read_input_waiting ();
+      *rfds = 1;
+      return 1;
+    }
+
+  /* Once a second, till the timer expires, check all the flagged read
+   * descriptors to see if any input is available.  If there is some then
+   * set the corresponding bit in the return copy of rfds.
+   */ 
+  while (1)
+    {
+      register int to_check, bit, fd;
+
+      if (rfds)
+       {
+         for (to_check = nfds, bit = 1, fd = 0; --to_check >= 0; bit <<= 1, fd++)
+           {
+             if (orfds & bit)
+               {
+                 int avail = 0, status = 0;
+
+                 if (bit == 1)
+                   avail = detect_input_pending(); /* Special keyboard handler */
+                 else
+                   {
+#ifdef FIONREAD
+                     status = ioctl (fd, FIONREAD, &avail);
+#else /* no FIONREAD */
+                     /* Hoping it will return -1 if nothing available
+                        or 0 if all 0 chars requested are read.  */
+                     if (proc_buffered_char[fd] >= 0)
+                       avail = 1;
+                     else
+                       {
+                         avail = read (fd, &buf, 1);
+                         if (avail > 0)
+                           proc_buffered_char[fd] = buf;
+                       }
+#endif /* no FIONREAD */
+                   }
+                 if (status >= 0 && avail > 0)
+                   {
+                     (*rfds) |= bit;
+                     ravail++;
+                   }
+               }
+           }
+       }
+      if (*timeout == 0 || ravail != 0 || child_changed)
+       break;
+      old_alarm = alarm (0);
+      old_trap = signal (SIGALRM, select_alarm);
+      select_alarmed = 0;
+      alarm (SELECT_PAUSE);
+      /* Wait for a SIGALRM (or maybe a SIGTINT) */
+      while (select_alarmed == 0 && *timeout != 0 && child_changed == 0)
+       {
+         /* If we are interested in terminal input,
+            wait by reading the terminal.
+            That makes instant wakeup for terminal input at least.  */
+         if (orfds & 1)
+           {
+             read_input_waiting ();
+             if (kbd_count)
+               select_alarmed = 1;
+           }
+         else
+           pause();
+       }
+      (*timeout) -= SELECT_PAUSE;
+      /* Reset the old alarm if there was one */
+      alarm (0);
+      signal (SIGALRM, old_trap);
+      if (old_alarm != 0)
+       {
+         /* Reset or forge an interrupt for the original handler. */
+         old_alarm -= SELECT_PAUSE;
+         if (old_alarm <= 0)
+           kill (getpid (), SIGALRM); /* Fake an alarm with the orig' handler */
+         else
+           alarm (old_alarm);
+       }
+      if (*timeout == 0)  /* Stop on timer being cleared */
+       break;
+    }
+  return ravail;
+}
+
+/* Read keyboard input into the standard buffer,
+   waiting for at least one character.  */
+
+read_input_waiting ()
+{
+  extern int kbd_count;
+  extern unsigned char kbd_buffer[];
+  extern unsigned char *kbd_ptr;
+  int val = read (fileno(stdin), kbd_buffer, 1);
+  if (val > 0)
+    {
+      kbd_ptr = kbd_buffer;
+      kbd_count = val;
+    }
+}
+
+#endif /* not HAVE_SELECT */
+\f
+#ifdef BSD4_1
+/* VARARGS */
+setpriority ()
+{
+  return 0;
+}
+
+/*
+ * Partially emulate 4.2 open call.
+ * open is defined as this in 4.1.
+ *
+ * - added by Michael Bloom @ Citicorp/TTI
+ *
+ */
+
+int
+sys_open (path, oflag, mode)
+     char *path;
+     int oflag, mode;
+{
+  if (oflag & O_CREAT) 
+    return creat (path, mode);
+  else
+    return open (path, oflag);
+}
+
+init_sigio ()
+{
+  if (noninteractive)
+    return;
+  lmode =  LINTRUP | lmode;
+  ioctl (0, TIOCLSET, &lmode);
+}
+
+reset_sigio ()
+{
+  if (noninteractive)
+    return;
+  lmode = ~LINTRUP & lmode;
+  ioctl (0, TIOCLSET, &lmode);
+}
+
+request_sigio ()
+{
+  sigrelse (SIGTINT);
+}
+
+unrequest_sigio ()
+{
+  sighold (SIGTINT);
+}
+
+/* still inside #ifdef BSD4_1 */
+#ifdef subprocesses
+
+int sigheld; /* Mask of held signals */
+
+sigholdx (signum)
+     int signum;
+{
+  sigheld |= sigbit (signum);
+  sighold (signum);
+}
+
+sigisheld (signum)
+     int signum;
+{
+  sigheld |= sigbit (signum);
+}
+
+sigunhold (signum)
+     int signum;
+{
+  sigheld &= ~sigbit (signum);
+  sigrelse (signum);
+}
+
+sigfree ()    /* Free all held signals */
+{
+  int i;
+  for (i = 0; i < NSIG; i++)
+    if (sigheld & sigbit (i))
+      sigrelse (i);
+  sigheld = 0;
+}
+
+sigbit (i)
+{
+  return 1 << (i - 1);
+}
+#endif /* subprocesses */
+#endif /* BSD4_1 */
+\f
+#ifndef BSTRING
+
+void
+bzero (b, length)
+     register char *b;
+     register int length;
+{
+  while (length-- > 0)
+    *b++ = 0;
+}
+
+void 
+bcopy (b1, b2, length)
+     register char *b1;
+     register char *b2;
+     register int length;
+{
+  while (length-- > 0)
+    *b2++ = *b1++;
+}
+
+int
+bcmp (b1, b2, length)  /* This could be a macro! */
+     register char *b1;
+     register char *b2;
+     register int length;
+{
+  while (length-- > 0)
+    if (*b1++ != *b2++)
+      return 1;
+
+  return 0;
+}
+#endif /* not BSTRING */
+\f
+#if defined (BSD4_1) || defined (USG)
+
+/*
+ *     The BSD random(3) returns numbers in the range of
+ *     0 to 2e31 - 1.  The USG rand(3C) returns numbers in the
+ *     range of 0 to 2e15 - 1.  This is probably not significant
+ *     in this usage.
+ */
+  
+long
+random ()
+{
+  return (rand ());
+}
+
+srandom (arg)
+     int arg;
+{
+  srand (arg);
+}
+
+#endif /* bsd4.1 or any USG */
+\f
+#ifdef USG
+/*
+ *     All of the following are for USG.
+ *
+ *     On USG systems the system calls are interruptable by signals
+ *     that the user program has elected to catch.  Thus the system call
+ *     must be retried in these cases.  To handle this without massive
+ *     changes in the source code, we remap the standard system call names
+ *     to names for our own functions in sysdep.c that do the system call
+ *     with retries.  Actually, for portability reasons, it is good
+ *     programming practice, as this example shows, to limit all actual
+ *     system calls to a single occurance in the source.  Sure, this
+ *     adds an extra level of function call overhead but it is almost
+ *     always negligible.   Fred Fish, Unisoft Systems Inc.
+ */
+
+char *sys_siglist[NSIG + 1] =
+{
+  "bogus signal",                      /* 0 */
+  "hangup",                            /* 1  SIGHUP */
+  "interrupt",                         /* 2  SIGINT */
+  "quit",                              /* 3  SIGQUIT */
+  "illegal instruction",               /* 4  SIGILL */
+  "trace trap",                                /* 5  SIGTRAP */
+  "IOT instruction",                   /* 6  SIGIOT */
+  "EMT instruction",                   /* 7  SIGEMT */
+  "floating point exception",          /* 8  SIGFPE */
+  "kill",                              /* 9  SIGKILL */
+  "bus error",                         /* 10 SIGBUS */
+  "segmentation violation",            /* 11 SIGSEGV */
+  "bad argument to system call",       /* 12 SIGSYS */
+  "write on a pipe with no one to read it", /* 13 SIGPIPE */
+  "alarm clock",                       /* 14 SIGALRM */
+  "software termination signum",       /* 15 SIGTERM */
+  "user defined signal 1",             /* 16 SIGUSR1 */
+  "user defined signal 2",             /* 17 SIGUSR2 */
+  "death of a child",                  /* 18 SIGCLD */
+  "power-fail restart",                        /* 19 SIGPWR */
+  0
+  };
+
+int
+sys_read (fildes, buf, nbyte)
+     int fildes;
+     char *buf;
+     unsigned int nbyte;
+{
+  register int rtnval;
+  
+  while ((rtnval = read (fildes, buf, nbyte)) == -1 && errno == EINTR);
+  return (rtnval);
+}
+
+int
+/* VARARGS 2 */
+sys_open (path, oflag, mode)
+     char *path;
+     int oflag, mode;
+{
+  register int rtnval;
+  
+  while ((rtnval = open (path, oflag, mode)) == -1 && errno == EINTR);
+  return (rtnval);
+}
+
+int
+sys_write (fildes, buf, nbyte)
+     int fildes;
+     char *buf;
+     unsigned int nbyte;
+{
+  register int rtnval;
+
+  while ((rtnval = write (fildes, buf, nbyte)) == -1 && errno == EINTR);
+  return (rtnval);
+}
+
+/*
+ *     Warning, this function may not duplicate 4.2 action properly
+ *     under error conditions.
+ */
+
+#ifndef MAXPATHLEN
+/* In 4.1, param.h fails to define this.  */
+#define MAXPATHLEN 1024
+#endif
+
+char *
+getwd (pathname)
+     char *pathname;
+{
+  extern char *getcwd ();
+
+  return (getcwd (pathname, MAXPATHLEN));
+}
+
+/*
+ *     Emulate rename using unlink/link.  Note that this is
+ *     only partially correct.  Also, doesn't enforce restriction
+ *     that files be of same type (regular->regular, dir->dir, etc).
+ */
+
+rename (from, to)
+     char *from;
+     char *to;
+{
+  if (access (from, 0) == 0)
+    {
+      unlink (to);
+      if (link (from, to) == 0)
+       if (unlink (from) == 0)
+         return (0);
+    }
+  return (-1);
+}
+
+/* VARARGS */
+setpriority ()
+{
+  return (0);
+}
+
+#ifndef HPUX
+
+/*
+ *     Substitute fork(2) for vfork(2) on USG flavors.
+ */
+
+vfork ()
+{
+  return (fork ());
+}
+
+/*
+ *     Emulate BSD dup2(2).  First close newd if it already exists.
+ *     Then, attempt to dup oldd.  If not successful, call dup2 recursively
+ *     until we are, then close the unsuccessful ones.
+ */
+
+dup2 (oldd, newd)
+     int oldd;
+     int newd;
+{
+  register int fd;
+  
+  close (newd);
+  while ((fd = dup (oldd)) != newd) {
+    dup2 (oldd, newd);
+    close (fd);
+  }
+}
+
+/*
+ *     Gettimeofday.  Simulate as much as possible.  Only accurate
+ *     to nearest second.  Emacs doesn't use tzp so ignore it for now.
+ *     Only needed when subprocesses are defined.
+ */
+
+#if defined(subprocesses) && !defined(STRIDE) && defined(HAVE_TIMEVAL)
+/* ARGSUSED */
+gettimeofday (tp, tzp)
+     struct timeval *tp;
+     struct timezone *tzp;
+{
+  extern long time ();
+
+  tp->tv_sec = time ((long *)0);    
+  tp->tv_usec = 0;
+}
+#endif /* subprocess && ~STRIDE && HAVE_TIMEVAL */
+#endif /* not HPUX */ 
+  
+/*
+ *     This function will go away as soon as all the stubs fixed.  (fnf)
+ */
+
+croak (badfunc)
+     char *badfunc;
+{
+  printf ("%s not yet implemented\r\n", badfunc);
+  reset_sys_modes ();
+  exit (1);
+}
+
+#endif /* USG */
+\f
+/* Directory routines for systems that don't have them. */
+
+#ifdef NONSYSTEM_DIR_LIBRARY
+
+DIR *
+opendir (filename)
+     char *filename;   /* name of directory */
+{
+  register DIR *dirp;          /* -> malloc'ed storage */
+  register int fd;             /* file descriptor for read */
+  struct stat sbuf;            /* result of fstat() */
+
+  fd = sys_open (filename, 0);
+  if (fd < 0)
+    return 0;
+
+  if (fstat (fd, &sbuf) < 0
+      || (sbuf.st_mode & S_IFMT) != S_IFDIR
+      || (dirp = (DIR *) malloc (sizeof (DIR))) == 0)
+    {
+      close (fd);
+      return 0;                /* bad luck today */
+    }
+
+  dirp->dd_fd = fd;
+  dirp->dd_loc = dirp->dd_size = 0;    /* refill needed */
+
+  return dirp;
+}
+
+void
+closedir (dirp)
+     register DIR *dirp;               /* stream from opendir() */
+{
+  close (dirp->dd_fd);
+  free ((char *) dirp);
+}
+
+
+#define DIRSIZ 14
+struct olddir
+  {
+    ino_t od_ino;              /* inode */
+    char od_name[DIRSIZ];      /* filename */
+  };
+
+struct direct dir_static;      /* simulated directory contents */
+
+struct direct *
+readdir (dirp)
+     register DIR *dirp;       /* stream from opendir() */
+{
+  register struct olddir *dp;  /* -> directory data */
+
+  for ( ; ; )
+    {
+      if (dirp->dd_loc >= dirp->dd_size)
+       dirp->dd_loc = dirp->dd_size = 0;
+
+      if (dirp->dd_size == 0   /* refill buffer */
+         && (dirp->dd_size = sys_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
+       return 0;
+
+      dp = (struct olddir *) &dirp->dd_buf[dirp->dd_loc];
+      dirp->dd_loc += sizeof (struct olddir);
+
+      if (dp->od_ino != 0)     /* not deleted entry */
+       {
+         dir_static.d_ino = dp->od_ino;
+         strncpy (dir_static.d_name, dp->od_name, DIRSIZ);
+         dir_static.d_name[DIRSIZ] = '\0';
+         dir_static.d_namlen = strlen (dir_static.d_name);
+         dir_static.d_reclen = sizeof (struct direct)
+           - MAXNAMLEN + 3
+             + dir_static.d_namlen - dir_static.d_namlen % 4;
+         return &dir_static;   /* -> simulated structure */
+       }
+    }
+}
+
+#endif /* NONSYSTEM_DIR_LIBRARY */