+/* 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 *) <c) == 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