BSD 4_3 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Wed, 22 Jan 1986 04:44:19 +0000 (20:44 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Wed, 22 Jan 1986 04:44:19 +0000 (20:44 -0800)
Work on file usr/contrib/mh/uip/vmh.c

Synthesized-from: CSRG/cd1/4.3

usr/contrib/mh/uip/vmh.c [new file with mode: 0644]

diff --git a/usr/contrib/mh/uip/vmh.c b/usr/contrib/mh/uip/vmh.c
new file mode 100644 (file)
index 0000000..e53409c
--- /dev/null
@@ -0,0 +1,1439 @@
+/* vmh.c - visual front-end to mh */
+
+/* TODO:
+       Pass signals to client during execution
+
+       Get stand-alone SO/SE/CE to work under #ifdef SYS5
+
+       Figure out a way for the user to say how big the Scan/Display
+       windows should be.
+
+       If curses ever gets fixed, then XYZ code can be removed
+ */
+
+#include <curses.h>
+#undef OK                      /* tricky */
+#include "../h/mh.h"
+#include "../h/vmhsbr.h"
+#include <ctype.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#ifndef        sigmask
+#define        sigmask(s)      (1 << ((s) - 1))
+#endif not sigmask
+#ifndef        BSD42
+struct iovec {
+    char   *iov_base;
+    int     iov_len;
+};
+#else  BSD42
+#include <sys/types.h>
+#include <sys/uio.h>
+#endif BSD42
+
+#define        ALARM   ((unsigned int) 10)
+#define        PAUSE   ((unsigned int) 2)
+
+#define        abs(a)          ((a) > 0 ? (a) : -(a))
+#define        SMALLMOVE       1
+#define        LARGEMOVE       10
+
+
+#define        XYZ                     /* XXX */
+
+/* \f */
+
+static struct swit switches[] = {
+#define        PRMPTSW 0
+    "prompt string", 6,
+
+#define        PROGSW  1
+    "vmhproc program", 7,
+#define        NPROGSW 2
+    "novmhproc", 9,
+
+#define        HELPSW  3
+    "help", 4,
+
+    NULL, NULL
+};
+
+/* \f */
+                                       /* PEERS */
+static int  PEERpid = NOTOK;
+
+static  jmp_buf PEERctx;
+
+
+                                       /* WINDOWS */
+static char *myprompt = "(%s) ";
+
+static  WINDOW *Scan;
+static  WINDOW *Status;
+static  WINDOW *Display;
+static  WINDOW *Command;
+
+#define        NWIN    3
+static int numwins;
+WINDOW *windows[NWIN + 1];
+
+
+                                       /* LINES */
+
+struct line {
+    int     l_no;
+    char   *l_buf;
+    struct line *l_prev;
+    struct line *l_next;
+};
+
+static struct line *lhead = NULL;
+static struct line *ltop = NULL;
+static struct line *ltail = NULL;
+
+static int did_less = 0;
+static int smallmove = SMALLMOVE;
+static int largemove = LARGEMOVE;
+
+
+                                       /* TTYS */
+
+static int  tty_ready = NOTOK;
+
+static int  intrc;
+#ifndef        SYS5
+#define        ERASE   sg.sg_erase
+#define        KILL    sg.sg_kill
+static struct sgttyb    sg;
+
+#define        EOFC    tc.t_eofc
+#define        INTR    tc.t_intrc
+static struct tchars    tc;
+#else  SYS5
+#define        ERASE   sg.c_cc[VERASE]
+#define        KILL    sg.c_cc[VKILL]
+#define        EOFC    sg.c_cc[VEOF]
+#define        INTR    sg.c_cc[VINTR]
+static struct termio    sg;
+#endif SYS5
+
+#ifndef        TIOCGLTC
+#define        WERASC  ('W' & 037)
+#else  TIOCGLTC
+#define        WERASC  ltc.t_werasc
+static struct ltchars ltc;
+#endif TIOCGLTC
+
+
+#ifndef        SYS5
+int    _putchar ();
+#endif not SYS5
+char   *tgoto ();
+
+
+                                       /* SIGNALS */
+int     ALRMser (), PIPEser (), SIGser ();
+#ifdef SIGTSTP
+int    TSTPser ();
+#endif SIGTSTP
+
+
+                                       /* MISCELLANY */
+extern int  errno;
+extern int  sys_nerr;
+extern char *sys_errlist[];
+
+void   adorn ();
+
+/* \f */
+
+/* ARGSUSED */
+
+main (argc, argv)
+int     argc;
+char   *argv[];
+{
+    int     vecp = 1,
+           nprog = 0;
+    char   *cp,
+            buffer[BUFSIZ],
+          **ap,
+          **argp,
+           *arguments[MAXARGS],
+           *vec[MAXARGS];
+
+    invo_name = r1bindex (argv[0], '/');
+    if ((cp = m_find (invo_name)) != NULL) {
+       ap = brkstring (cp = getcpy (cp), " ", "\n");
+       ap = copyip (ap, arguments);
+    }
+    else
+       ap = arguments;
+    (void) copyip (argv + 1, ap);
+    argp = arguments;
+
+/* \f */
+
+    while (cp = *argp++)
+       if (*cp == '-')
+           switch (smatch (++cp, switches)) {
+               case AMBIGSW: 
+                   ambigsw (cp, switches);
+                   done (1);
+               case UNKWNSW: 
+                   vec[vecp++] = --cp;
+                   continue;
+               case HELPSW: 
+                   (void) sprintf (buffer, "%s [switches for vmhproc]",
+                           invo_name);
+                   help (buffer, switches);
+                   done (1);
+
+               case PRMPTSW:
+                   if (!(myprompt = *argp++) || *myprompt == '-')
+                       adios (NULLCP, "missing argument to %s", argp[-2]);
+                   continue;
+
+               case PROGSW: 
+                   if (!(vmhproc = *argp++) || *vmhproc == '-')
+                       adios (NULLCP, "missing argument to %s", argp[-2]);
+                   continue;
+               case NPROGSW:
+                   nprog++;
+                   continue;
+           }
+       else
+           vec[vecp++] = cp;
+
+/* \f */
+
+    if (TTYinit (nprog) == NOTOK || WINinit (nprog) == NOTOK) {
+       vec[vecp] = NULL;
+
+       vec[0] = r1bindex (vmhproc, '/');
+       execvp (vmhproc, vec);
+       adios (vmhproc, "unable to exec");
+    }
+    TTYoff ();
+    (void) PEERinit (vecp, vec);
+    TTYon ();
+
+    vmh ();
+
+    done (0);
+}
+
+/* \f */
+
+static  vmh () {
+    char    buffer[BUFSIZ];
+
+    for (;;) {
+       (void) pLOOP (RC_QRY, NULLCP);
+
+       wmove (Command, 0, 0);
+       wprintw (Command, myprompt, invo_name);
+       wclrtoeol (Command);
+       wrefresh (Command);
+
+       switch (WINgetstr (Command, buffer)) {
+           case NOTOK: 
+               break;
+
+           case OK:
+               done (0);       /* NOTREACHED */
+
+           default: 
+               if (*buffer)
+                   (void) pLOOP (RC_CMD, buffer);
+               break;
+       }
+    }
+}
+
+/* \f   PEERS */
+
+static int  PEERinit (vecp, vec)
+int    vecp;
+char   *vec[];
+{
+    int            pfd0[2],
+            pfd1[2];
+    char    buf1[BUFSIZ],
+            buf2[BUFSIZ];
+
+    if (pipe (pfd0) == NOTOK || pipe (pfd1) == NOTOK)
+       adios ("pipe", "unable to");
+    switch (PEERpid = vfork ()) {
+       case NOTOK: 
+           adios ("vfork", "unable to");/* NOTREACHED */
+
+       case OK: 
+           (void) close (pfd0[0]);
+           (void) close (pfd1[1]);
+
+           vec[vecp++] = "-vmhread";
+           (void) sprintf (buf1, "%d", pfd1[0]);
+           vec[vecp++] = buf1;
+           vec[vecp++] = "-vmhwrite";
+           (void) sprintf (buf2, "%d", pfd0[1]);
+           vec[vecp++] = buf2;
+           vec[vecp] = NULL;
+
+           (void) signal (SIGINT, SIG_DFL);
+           (void) signal (SIGQUIT, SIG_DFL);
+
+           vec[0] = r1bindex (vmhproc, '/');
+           execvp (vmhproc, vec);
+           perror (vmhproc);
+           _exit (-1);         /* NOTREACHED */
+
+       default: 
+           (void) close (pfd0[1]);
+           (void) close (pfd1[0]);
+
+           (void) rcinit (pfd0[0], pfd1[1]);
+           return pINI ();
+    }
+}
+
+/* \f */
+
+static int  pINI () {
+    register char  *bp;
+    char    buffer[BUFSIZ];
+    struct record   rcs;
+    register struct record *rc = &rcs;
+    register    WINDOW **w;
+
+    initrc (rc);
+
+    bp = buffer;
+    (void) sprintf (bp, "%d %d", RC_VRSN, numwins);
+    bp += strlen (bp);
+    for (w = windows; *w; w++) {
+       (void) sprintf (bp, " %d", (*w) -> _maxy);
+       bp += strlen (bp);
+    }
+
+    switch (str2rc (RC_INI, buffer, rc)) {
+       case RC_ACK: 
+           return OK;
+
+       case RC_ERR: 
+           if (rc -> rc_len)
+               adios (NULLCP, "%s", rc -> rc_data);
+           else
+               adios (NULLCP, "pINI peer error");
+
+       case RC_XXX: 
+           adios (NULLCP, "%s", rc -> rc_data);
+
+       default:
+           adios (NULLCP, "pINI protocol screw-up");
+    }
+/* NOTREACHED */
+}
+
+/* \f */
+
+static int  pLOOP (code, str)
+char   code,
+       *str;
+{
+    int            i;
+    struct record   rcs;
+    register struct record *rc = &rcs;
+
+    initrc (rc);
+
+    (void) str2peer (code, str);
+    for (;;)
+       switch (peer2rc (rc)) {
+           case RC_TTY:
+               if (pTTY (rc) == NOTOK)
+                   return NOTOK;
+               break;
+
+           case RC_WIN:
+               if (sscanf (rc -> rc_data, "%d", &i) != 1
+                       || i <= 0
+                       || i > numwins) {
+                   (void) fmt2peer (RC_ERR, "no such window \"%s\"",
+                               rc -> rc_data);
+                   return NOTOK;
+               }
+               if (pWIN (windows[i - 1]) == NOTOK)
+                   return NOTOK;
+               break;
+
+           case RC_EOF:
+               return OK;
+
+           case RC_ERR:
+               if (rc -> rc_len)
+                   adorn (NULLCP, "%s", rc -> rc_data);
+               else
+                   adorn (NULLCP, "pLOOP(%s) peer error",
+                           code == RC_QRY ? "QRY" : "CMD");
+               return NOTOK;
+
+           case RC_FIN:
+               if (rc -> rc_len)
+                   adorn (NULLCP, "%s", rc -> rc_data);
+               (void) rcdone ();
+               i = pidwait (PEERpid, OK);
+               PEERpid = NOTOK;
+               done (i);
+
+           case RC_XXX: 
+               adios (NULLCP, "%s", rc -> rc_data);
+
+           default:
+               adios (NULLCP, "pLOOP(%s) protocol screw-up",
+                       code == RC_QRY ? "QRY" : "CMD");
+       }
+}
+
+/* \f */
+
+static int  pTTY (r)
+register struct record *r;
+{
+    int     (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
+    struct record   rcs;
+    register struct record *rc = &rcs;
+
+    initrc (rc);
+
+    TTYoff ();
+
+    hstat = signal (SIGHUP, SIG_IGN);
+    istat = signal (SIGINT, SIG_IGN);
+    qstat = signal (SIGQUIT, SIG_IGN);
+    tstat = signal (SIGTERM, SIG_IGN);
+
+    (void) rc2rc (RC_ACK, 0, NULLCP, rc);
+
+    (void) signal (SIGHUP, hstat);
+    (void) signal (SIGINT, istat);
+    (void) signal (SIGQUIT, qstat);
+    (void) signal (SIGTERM, tstat);
+
+    TTYon ();
+
+    if (r -> rc_len && strcmp (r -> rc_data, "FAST") == 0)
+       goto no_refresh;
+
+#ifdef SIGTSTP
+    (void) signal (SIGTSTP, SIG_IGN);
+#endif SIGTSTP
+#ifndef        SYS5
+    if (SO)
+       tputs (SO, 0, _putchar);
+#endif not SYS5
+    fprintf (stdout, "Type any key to continue... ");
+    (void) fflush (stdout);
+#ifndef        SYS5
+    if (SE)
+       tputs (SE, 0, _putchar);
+#endif not SYS5
+    (void) getc (stdin);
+#ifdef SIGTSTP
+    (void) signal (SIGTSTP, TSTPser);
+#endif SIGTSTP
+
+    wrefresh (curscr);
+
+no_refresh: ;
+    switch (rc -> rc_type) {
+       case RC_EOF: 
+           (void) rc2peer (RC_ACK, 0, NULLCP);
+           return OK;
+
+       case RC_ERR: 
+           if (rc -> rc_len)
+               adorn (NULLCP, "%s", rc -> rc_data);
+           else
+               adorn (NULLCP, "pTTY peer error");
+           return NOTOK;
+
+       case RC_XXX: 
+           adios (NULLCP, "%s", rc -> rc_data);
+
+       default:
+           adios (NULLCP, "pTTY protocol screw-up");
+    }
+/* NOTREACHED */
+}
+
+/* \f */
+
+static int  pWIN (w)
+register WINDOW *w;
+{
+    int     i;
+
+    did_less = 0;
+    if ((i = pWINaux (w)) == OK && did_less)
+       (void) WINless (w, 1);
+
+    lreset ();
+
+    return i;
+}
+
+/* \f */
+
+static int  pWINaux (w)
+register WINDOW *w;
+{
+    register int    n;
+    int            eol;
+    register char   c,
+                   *bp;
+    struct record   rcs;
+    register struct record *rc = &rcs;
+
+    initrc (rc);
+
+    werase (w);
+    wmove (w, 0, 0);
+#ifdef XYZ
+    if (w == Status)
+       wstandout (w);
+#endif XYZ
+
+    for (eol = 0;;)
+       switch (rc2rc (RC_ACK, 0, NULLCP, rc)) {
+           case RC_DATA: 
+               if (eol && WINputc (w, '\n') == ERR && WINless (w, 0))
+                   goto flush;
+               for (bp = rc -> rc_data, n = rc -> rc_len; n-- > 0; ) {
+                   if ((c = *bp++) == '\n')
+                       linsert (w);
+                   if (WINputc (w, c) == ERR)
+                       if (n == 0 && c == '\n')
+                           eol++;
+                       else
+                           if (WINless (w, 0)) {
+flush: ;
+                               (void) fmt2peer (RC_ERR, "flush window");
+#ifdef XYZ                     /* should NEVER happen... */
+                               if (w == Status)
+                                   wstandend (w);
+#endif XYZ
+                               wrefresh (w);
+                               return NOTOK;
+                           }
+               }
+               break;
+
+           case RC_EOF: 
+               (void) rc2peer (RC_ACK, 0, NULLCP);
+#ifdef XYZ
+               if (w == Status)
+                   wstandend (w);
+#endif XYZ
+               wrefresh (w);
+               return OK;
+
+           case RC_ERR: 
+               if (rc -> rc_len)
+                   adorn (NULLCP, "%s", rc -> rc_data);
+               else
+                   adorn (NULLCP, "pWIN peer error");
+               return NOTOK;
+
+           case RC_XXX: 
+               adios (NULLCP, "%s", rc -> rc_data);
+
+           default:
+               adios (NULLCP, "pWIN protocol screw-up");
+       }
+/* NOTREACHED */
+}
+
+/* \f */
+
+static int  pFIN () {
+    int     status;
+
+    if (PEERpid <= OK)
+       return OK;
+
+    (void) rc2peer (RC_FIN, 0, NULLCP);
+    (void) rcdone ();
+
+    switch (setjmp (PEERctx)) {
+       case OK: 
+           (void) signal (SIGALRM, ALRMser);
+           (void) alarm (ALARM);
+
+           status = pidwait (PEERpid, OK);
+
+           (void) alarm (0);
+           break;
+
+       default: 
+           (void) kill (PEERpid, SIGKILL);
+           status = NOTOK;
+           break;
+    }
+    PEERpid = NOTOK;
+
+    return status;
+}
+
+/* \f   WINDOWS */
+
+static int  WINinit (nprog) {
+    register int    lines,
+                    top,
+                    bottom;
+
+    foreground ();
+    if (initscr () == ERR)
+       if (nprog)
+           return NOTOK;
+       else
+           adios (NULLCP, "could not initialize terminal");
+#ifdef SIGTSTP
+    (void) signal (SIGTSTP, SIG_DFL);
+#endif SIGTSTP
+    sideground ();
+
+    if (CM == NULL)
+       if (nprog)
+           return NOTOK;
+       else
+           adios (NULLCP,
+                   "sorry, your terminal isn't powerful enough to run %s",
+                   invo_name);
+
+#ifndef        SYS5
+    if (tgetflag ("xt") || tgetnum ("sg") > 0)
+       SO = SE = US = UE = NULL;
+#endif not SYS5
+
+    if ((lines = LINES - 1) < 11)
+       adios (NULLCP, "screen too small");
+    if ((top = lines / 3 + 1) > LINES / 4 + 2)
+       top--;
+    bottom = lines - top - 2;
+
+    numwins = 0;
+    Scan = windows[numwins++] = newwin (top, COLS, 0, 0);
+    Status = windows[numwins++] = newwin (1, COLS, top, 0);
+#ifndef        XYZ
+    wstandout (Status);
+#endif XYZ
+    Display = windows[numwins++] = newwin (bottom, COLS, top + 1, 0);
+    Command = newwin (1, COLS - 1, top + 1 + bottom, 0);
+    windows[numwins] = NULL;
+
+    largemove = Display -> _maxy / 2 + 2;
+    return OK;
+}
+
+/* \f */
+
+static int WINgetstr (w, buffer)
+register WINDOW *w;
+char   *buffer;
+{
+    register int    c;
+    register char  *bp;
+
+    bp = buffer;
+    *bp = NULL;
+
+    for (;;) {
+       switch (c = toascii (wgetch (w))) {
+           case ERR: 
+               adios (NULLCP, "wgetch lost");
+
+           case '\f':
+               wrefresh (curscr);
+               break;
+
+           case '\r': 
+           case '\n': 
+               *bp = NULL;
+               if (bp > buffer) {
+                   leaveok (curscr, FALSE);
+                   wmove (w, 0, w -> _curx - (bp - buffer));
+                   wrefresh (w);
+                   leaveok (curscr, TRUE);
+               }
+               return DONE;
+
+           default: 
+               if (c == intrc) {
+                   wprintw (w, " ");
+                   wstandout (w);
+                   wprintw (w, "Interrupt");
+                   wstandend (w);
+                   wrefresh (w);
+                   *buffer = NULL;
+                   return NOTOK;
+               }
+               if (c == EOFC) {
+                   if (bp <= buffer)
+                       return OK;
+                   break;
+               }
+               if (c == ERASE) {
+                   if (bp <= buffer)
+                       continue;
+                   bp--, w -> _curx--;
+                   wclrtoeol (w);
+                   break;
+               }
+               if (c == KILL) {
+                   if (bp <= buffer)
+                       continue;
+                   w -> _curx -= bp - buffer;
+                   bp = buffer;
+                   wclrtoeol (w);
+                   break;
+               }
+               if (c == WERASC) {
+                   if (bp <= buffer)
+                       continue;
+                   do {
+                       bp--, w -> _curx--;
+                   } while (isspace (*bp) && bp > buffer);
+
+                   if (bp > buffer) {
+                       do {
+                           bp--, w -> _curx--;
+                       } while (!isspace (*bp) && bp > buffer);
+                       if (isspace (*bp))
+                           bp++, w -> _curx++;
+                   }
+                   wclrtoeol (w);
+                   break;
+               }
+               
+               if (c >= ' ')
+                   (void) waddch (w, *bp++ = c);
+               break;
+       }
+
+       wrefresh (w);
+    }
+}
+
+/* \f */
+
+static int  WINwritev (w, iov, n)
+register WINDOW *w;
+register struct iovec   *iov;
+register int     n;
+{
+    register int    i;
+
+    werase (w);
+    wmove (w, 0, 0);
+    for (i = 0; i < n; i++, iov++)
+       wprintw (w, "%*.*s", iov -> iov_len, iov -> iov_len, iov -> iov_base);
+    wrefresh (w);
+
+    sleep (PAUSE);
+
+    return OK;
+}
+
+/* \f */
+
+static struct {
+    char   *h_msg;
+    int    *h_val;
+}               hlpmsg[] = {
+                    "          forward         backwards", NULL,
+                    "          -------         ---------", NULL,
+                    "next screen       SPACE", NULL,
+                    "next %d line%s    RETURN          y", &smallmove,
+                    "next %d line%s    EOT             u", &largemove,
+                    "go                g               G", NULL,
+                    "", NULL,
+                    "refresh           CTRL-L", NULL,
+                    "quit              q", NULL,
+
+                    NULL, NULL
+};
+
+/* \f */
+
+static int  WINless (w, fin)
+register WINDOW *w;
+int    fin;
+{
+    register int    c,
+                    i,
+                    n;
+    int     nfresh,
+#ifdef notdef
+           nlatch,
+#endif notdef
+            nwait;
+    char   *cp;
+    register struct line   *lbottom;
+
+    did_less++;
+
+    cp = NULL;
+#ifdef notdef
+    if (fin)
+       ltop = NULL;
+#endif notdef
+    lbottom = NULL;
+    nfresh = 1;
+    nwait = 0;
+    wrefresh (w);
+
+    for (;;) {
+       if (nfresh || nwait) {
+           nfresh = 0;
+#ifdef notdef
+           nlatch = 1;
+
+once_only: ;
+#endif notdef
+           werase (w);
+           wmove (w, 0, 0);
+
+           if (ltop == NULL)
+               if (fin) {
+                   (void) lgo (ltail -> l_no - w -> _maxy + 1);
+                   if (ltop == NULL)
+                       ltop = lhead;
+               }
+               else
+                   ltop = lbottom && lbottom -> l_prev ? lbottom -> l_prev
+                           : lbottom;
+
+           for (lbottom = ltop; lbottom; lbottom = lbottom -> l_next)
+               if (waddstr (w, lbottom -> l_buf) == ERR
+                       || waddch (w, '\n') == ERR)
+                   break;
+           if (lbottom == NULL)
+               if (fin) {
+#ifdef notdef
+                   if (nlatch && (ltail -> l_no >= w -> _maxy)) {
+                       (void) lgo (ltail -> l_no - w -> _maxy + 1);
+                       nlatch = 0;
+                       goto once_only;
+                   }
+#endif notdef
+                   lbottom = ltail;
+                   while (waddstr (w, "~\n") != ERR)
+                       continue;
+               }
+               else {
+                   wrefresh (w);
+                   return 0;
+               }
+
+           if (!nwait)
+               wrefresh (w);
+       }
+
+       wmove (Command, 0, 0);
+       if (cp) {
+           wstandout (Command);
+           wprintw (Command, "%s", cp);
+           wstandend (Command);
+           cp = NULL;
+       }
+       else
+           wprintw (Command, fin ? "top:%d bot:%d end:%d" : "top:%d bot:%d",
+                   ltop -> l_no, lbottom -> l_no, ltail -> l_no);
+       wprintw (Command, ">> ");
+       wclrtoeol (Command);
+       wrefresh (Command);
+
+       c = toascii (wgetch (Command));
+
+       werase (Command);
+       wrefresh (Command);
+
+       if (nwait) {
+           nwait = 0;
+           wrefresh (w);
+       }
+
+       n = 0;
+again:         ;
+       switch (c) {
+           case ' ': 
+               ltop = lbottom -> l_next;
+               nfresh++;
+               break;
+
+           case '\r': 
+           case '\n': 
+           case 'e': 
+           case 'j': 
+               if (n)
+                   smallmove = n;
+               if (ladvance (smallmove))
+                   nfresh++;
+               break;
+
+           case 'y': 
+           case 'k': 
+               if (n)
+                   smallmove = n;
+               if (lretreat (smallmove))
+                   nfresh++;
+               break;
+
+           case 'd': 
+       eof:    ;
+               if (n)
+                   largemove = n;
+               if (ladvance (largemove))
+                   nfresh++;
+               break;
+
+           case 'u': 
+               if (n)
+                   largemove = n;
+               if (lretreat (largemove))
+                   nfresh++;
+               break;
+
+           case 'g': 
+               if (lgo (n ? n : 1))
+                   nfresh++;
+               break;
+
+           case 'G': 
+               if (lgo (n ? n : ltail -> l_no - w -> _maxy + 1))
+                   nfresh++;
+               break;
+
+           case '\f': 
+           case 'r': 
+               wrefresh (curscr);
+               break;
+
+           case 'h': 
+           case '?': 
+               werase (w);
+               wmove (w, 0, 0);
+               for (i = 0; hlpmsg[i].h_msg; i++) {
+                   if (hlpmsg[i].h_val)
+                       wprintw (w, hlpmsg[i].h_msg, *hlpmsg[i].h_val,
+                               *hlpmsg[i].h_val != 1 ? "s" : "");
+                   else
+                       (void) waddstr (w, hlpmsg[i].h_msg);
+                   (void) waddch (w, '\n');
+               }
+               wrefresh (w);
+               nwait++;
+               break;
+
+           case 'q': 
+               return 1;
+
+           default: 
+               if (c == EOFC)
+                   goto eof;
+
+               if (isdigit (c)) {
+                   wmove (Command, 0, 0);
+                   i = 0;
+                   while (isdigit (c)) {
+                       wprintw (Command, "%c", c);
+                       wrefresh (Command);
+                       i = i * 10 + c - '0';
+                       c = toascii (wgetch (Command));
+                   }
+                   werase (Command);
+                   wrefresh (Command);
+
+                   if (i > 0) {
+                       n = i;
+                       goto again;
+                   }
+                   cp = "bad number";
+               }
+               else
+                   cp = "not understood";
+               break;
+       }
+    }
+}
+
+/* \f */
+
+static int  WINputc (w, c)
+register WINDOW *w;
+register char c;
+{
+    register int    x,
+                    y;
+
+    if (w != Scan)
+       return waddch (w, c);
+
+    if ((x = w -> _curx) < 0 || x >= w -> _maxx
+           || (y = w -> _cury) < 0 || y >= w -> _maxy)
+       return DONE;
+
+    switch (c) {
+       case '\t': 
+           for (x = 8 - (x & 0x07); x > 0; x--)
+               if (WINputc (w, ' ') == ERR)
+                   return ERR;
+           break;
+
+       case '\n': 
+           if (++y < w -> _maxy) 
+               (void) waddch (w, c);
+           else
+               wclrtoeol (w);
+           break;
+
+       default: 
+           if (++x < w -> _maxx) 
+               (void) waddch (w, c);
+           break;
+    }
+    return DONE;
+}
+
+/* \f   LINES */
+
+static  lreset () {
+    register struct line   *lp,
+                           *mp;
+
+    for (lp = lhead; lp; lp = mp) {
+       mp = lp -> l_next;
+       free (lp -> l_buf);
+       free ((char *) lp);
+    }
+    lhead = ltop = ltail = NULL;
+}
+
+
+static linsert (w)
+WINDOW *w;
+{
+    register char  *cp;
+    register struct line   *lp;
+
+    if ((lp = (struct line  *) calloc ((unsigned) 1, sizeof *lp)) == NULL)
+       adios (NULLCP, "unable to allocate line storage");
+
+    lp -> l_no = (ltail ? ltail -> l_no : 0) + 1;
+    lp -> l_buf = getcpy (w -> _y[w -> _cury]);
+    for (cp = lp -> l_buf + strlen (lp -> l_buf) - 1; cp >= lp -> l_buf; cp--)
+       if (isspace (*cp))
+           *cp = NULL;
+       else
+           break;
+
+    if (lhead == NULL)
+       lhead = lp;
+    if (ltop == NULL)
+       ltop = lp;
+    if (ltail)
+       ltail -> l_next = lp;
+    lp -> l_prev = ltail;
+    ltail = lp;
+}
+
+/* \f */
+
+static int  ladvance (n)
+int    n;
+{
+    register int    i;
+    register struct line   *lp;
+
+    for (i = 0, lp = ltop; i < n && lp; i++, lp = lp -> l_next)
+       continue;
+
+    if (ltop == lp)
+       return 0;
+
+    ltop = lp;
+    return 1;
+}
+
+
+static int  lretreat (n)
+int    n;
+{
+    register int    i;
+    register struct line   *lp;
+
+    for (i = 0, lp = ltop; i < n && lp; i++, lp = lp -> l_prev)
+       if (!lp -> l_prev)
+           break;
+
+    if (ltop == lp)
+       return 0;
+
+    ltop = lp;
+    return 1;
+}
+
+/* \f */
+
+static int  lgo (n)
+int    n;
+{
+    register int    i,
+                    j;
+    register struct line   *lp;
+
+    if ((i = n - (lp = lhead) -> l_no) > (j = abs (n - ltop -> l_no)))
+       i = j, lp = ltop;
+    if (i > (j = abs (ltail -> l_no - n)))
+       i = j, lp = ltail;
+
+    if (n >= lp -> l_no) {
+       for (; lp; lp = lp -> l_next)
+           if (lp -> l_no == n)
+               break;
+    }
+    else {
+       for (; lp; lp = lp -> l_prev)
+           if (lp -> l_no == n)
+               break;
+       if (!lp)
+           lp = lhead;
+    }
+
+    if (ltop == lp)
+       return 0;
+
+    ltop = lp;
+    return 1;
+}
+
+/* \f   TTYS */
+
+static int  TTYinit (nprog) {
+    if (!isatty (fileno (stdin)) || !isatty (fileno (stdout)))
+       if (nprog)
+           return NOTOK;
+       else
+           adios (NULLCP, "not a tty");
+
+    foreground ();
+#ifndef        SYS5
+    if (ioctl (fileno (stdin), TIOCGETP, (char *) &sg) == NOTOK)
+       adios ("failed", "ioctl TIOCGETP");
+    if (ioctl (fileno (stdin), TIOCGETC, (char *) &tc) == NOTOK)
+       adios ("failed", "ioctl TIOCGETC");
+#else  SYS5
+    if (ioctl (fileno (stdin), TCGETA, &sg) == NOTOK)
+       adios ("failed", "ioctl TCGETA");
+#endif SYS5
+#ifdef TIOCGLTC
+    if (ioctl (fileno (stdin), TIOCGLTC, (char *) &ltc) == NOTOK)
+       adios ("failed", "ioctl TIOCGLTC");
+#endif TIOCGLTC
+    intrc = INTR;
+    sideground ();
+
+    tty_ready = OK;
+
+    (void) signal (SIGPIPE, PIPEser);
+
+    return OK;
+}
+
+/* \f */
+
+static TTYon () {
+    if (tty_ready == DONE)
+       return;
+
+    INTR = NOTOK;
+#ifndef        SYS5
+    (void) ioctl (fileno (stdin), TIOCSETC, (char *) &tc);
+#else  SYS5
+    (void) ioctl (fileno (stdin), TCSETA, &sg);
+#endif SYS5
+
+    (void) crmode ();
+    (void) noecho ();
+    (void) nonl ();
+    scrollok (curscr, FALSE);
+
+    discard (stdin);
+
+    tty_ready = DONE;
+
+    (void) signal (SIGHUP, SIGser);
+    (void) signal (SIGINT, SIGser);
+    (void) signal (SIGQUIT, SIGser);
+#ifdef SIGTSTP
+    (void) signal (SIGTSTP, TSTPser);
+#endif SIGTSTP
+}
+
+/* \f */
+
+static TTYoff () {
+    if (tty_ready == NOTOK)
+       return;
+
+    INTR = intrc;
+#ifndef        SYS5
+    (void) ioctl (fileno (stdin), TIOCSETC, (char *) &tc);
+#else  SYS5
+    (void) ioctl (fileno (stdin), TCSETA, &sg);
+#endif SYS5
+
+    leaveok (curscr, TRUE);
+    mvcur (0, COLS - 1, LINES - 1, 0);
+    endwin ();
+    if (tty_ready == DONE) {
+#ifndef        SYS5
+       if (CE)
+           tputs (CE, 0, _putchar);
+       else
+#endif SYS5
+           fprintf (stdout, "\r\n");
+    }
+    (void) fflush (stdout);
+
+    tty_ready = NOTOK;
+
+    (void) signal (SIGHUP, SIG_DFL);
+    (void) signal (SIGINT, SIG_DFL);
+    (void) signal (SIGQUIT, SIG_DFL);
+#ifdef SIGTSTP
+    (void) signal (SIGTSTP, SIG_DFL);
+#endif SIGTSTP
+}
+
+/* \f */
+
+static  foreground () {
+#ifdef TIOCGPGRP
+    int     pgrp,
+            tpgrp;
+    int     (*tstat) ();
+
+    if ((pgrp = getpgrp (0)) == NOTOK)
+       adios ("process group", "unable to determine");
+    for (;;) {
+       if (ioctl (fileno (stdin), TIOCGPGRP, (char *) &tpgrp) == NOTOK)
+           adios ("tty's process group", "unable to determine");
+       if (pgrp == tpgrp)
+           break;
+
+       tstat = signal (SIGTTIN, SIG_DFL);
+       (void) kill (0, SIGTTIN);
+       (void) signal (SIGTTIN, tstat);
+    }
+    
+    (void) signal (SIGTTIN, SIG_IGN);
+    (void) signal (SIGTTOU, SIG_IGN);
+    (void) signal (SIGTSTP, SIG_IGN);
+#endif TIOCGPGRP
+}
+
+
+sideground () {
+#ifdef TIOCGPGRP
+    (void) signal (SIGTTIN, SIG_DFL);
+    (void) signal (SIGTTOU, SIG_DFL);
+    (void) signal (SIGTSTP, SIG_DFL);
+#endif TIOCGPGRP
+}
+
+/* \f   SIGNALS */
+
+/* ARGSUSED */
+
+static int  ALRMser (sig)
+int     sig;
+{
+     longjmp (PEERctx, DONE);
+}
+
+
+#ifdef BSD42
+/* ARGSUSED */
+#endif BSD42
+
+static int  PIPEser (sig)
+int    sig;
+{
+#ifndef        BSD42
+    (void) signal (sig, SIG_IGN);
+#endif BSD42
+
+    adios (NULLCP, "lost peer");
+}
+
+
+#ifdef BSD42
+/* ARGSUSED */
+#endif BSD42
+
+static int  SIGser (sig)
+int     sig;
+{
+#ifndef        BSD42
+    (void) signal (sig, SIG_IGN);
+#endif BSD42
+
+    done (1);
+}
+
+
+#ifdef SIGTSTP
+static int  TSTPser (sig)
+int     sig;
+{
+    tputs (tgoto (CM, 0, LINES - 1), 0, _putchar);
+    (void) fflush (stdout);
+
+    TTYoff ();
+#ifdef BSD42
+    (void) sigsetmask (sigblock (0) & ~sigmask (SIGTSTP));
+#endif BSD42
+
+    (void) kill (getpid (), sig);
+
+#ifdef BSD42
+    (void) sigblock (sigmask (SIGTSTP));
+#endif BSD42
+    TTYon ();
+
+    wrefresh (curscr);
+}
+#endif SIGTSTP
+
+/* \f   MISCELLANY */
+
+void   done (status)
+int    status;
+{
+    TTYoff ();
+    (void) pFIN ();
+
+    exit (status);
+}
+
+/* \f */
+
+/* VARARGS2 */
+
+static void  adorn (what, fmt, a, b, c, d, e, f)
+char   *what,
+       *fmt,
+       *a,
+       *b,
+       *c,
+       *d,
+       *e,
+       *f;
+{
+    char   *cp = invo_name;
+
+    invo_name = NULL;
+    advise (what, fmt, a, b, c, d, e, f);
+    invo_name = cp;
+}
+
+/* \f */
+
+/* VARARGS3 */
+
+void advertise (what, tail, fmt, a, b, c, d, e, f)
+char   *what,
+       *tail,
+       *fmt,
+       *a,
+       *b,
+       *c,
+       *d,
+       *e,
+       *f;
+{
+    int            eindex = errno;
+    char    buffer[BUFSIZ],
+            err[BUFSIZ];
+    struct iovec    iob[20];
+    register struct iovec  *iov = iob;
+
+    (void) fflush (stdout);
+
+    (void) fflush (stderr);
+
+    if (invo_name) {
+       iov -> iov_len = strlen (iov -> iov_base = invo_name);
+       iov++;
+       iov -> iov_len = strlen (iov -> iov_base = ": ");
+       iov++;
+    }
+    
+    (void) sprintf (buffer, fmt, a, b, c, d, e, f);
+    iov -> iov_len = strlen (iov -> iov_base = buffer);
+    iov++;
+    if (what) {
+       if (*what) {
+           iov -> iov_len = strlen (iov -> iov_base = " ");
+           iov++;
+           iov -> iov_len = strlen (iov -> iov_base = what);
+           iov++;
+           iov -> iov_len = strlen (iov -> iov_base = ": ");
+           iov++;
+       }
+       if (eindex > 0 && eindex < sys_nerr)
+           iov -> iov_len = strlen (iov -> iov_base = sys_errlist[eindex]);
+       else {
+           (void) sprintf (err, "Error %d", eindex);
+           iov -> iov_len = strlen (iov -> iov_base = err);
+       }
+       iov++;
+    }
+    if (tail && *tail) {
+       iov -> iov_len = strlen (iov -> iov_base = ", ");
+       iov++;
+       iov -> iov_len = strlen (iov -> iov_base = tail);
+       iov++;
+    }
+    iov -> iov_len = strlen (iov -> iov_base = "\n");
+    iov++;
+
+    if (tty_ready == DONE)
+       (void) WINwritev (Display, iob, iov - iob);
+    else
+       (void) writev (fileno (stderr), iob, iov - iob);
+}
+
+/* \f */
+
+#ifndef        BSD42
+static int     writev (fd, iov, n)
+register int     fd;
+register struct iovec   *iov;
+register int     n;
+{
+    register int    i,
+                    j;
+
+    for (i = j = 0; i < n; i++, iov++)
+       if (write (fd, iov -> iov_base, iov -> iov_len) != iov -> iov_len)
+           break;
+       else
+           j += iov -> iov_len;
+
+    return j;
+}
+#endif BSD42