/* * vmh.c -- visual front-end to nmh * * $Id$ * * This code is Copyright (c) 2002, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for * complete copyright information. */ #include #include #if 0 #if defined(SYS5) && !defined(TERMINFO) /* * Define TERMINFO if you have it. * You get it automatically if you're running SYS5, and you don't get * it if you're not. (If you're not SYS5, you probably have termcap.) * We distinguish TERMINFO from SYS5 because in this file SYS5 really * means "AT&T line discipline" (termio, not sgttyb), whereas terminfo * is quite a separate issue. */ #define TERMINFO 1 #endif #endif /* * TODO: * 1) Pass signals to client during execution * 2) Figure out a way for the user to say how big the Scan/Display * windows should be. * 3) If curses ever gets fixed, then XYZ code can be removed */ #include #ifdef ncr # define _SYS_REG_H /* NCR redefines "ERR" in */ #endif #undef OK /* tricky */ /* removed for right now */ #if 0 #ifdef TERMINFO # include /* variables describing terminal capabilities */ #endif /* TERMINFO */ #endif #include #include #include #include #ifndef sigmask # define sigmask(s) (1 << ((s) - 1)) #endif /* not sigmask */ #ifdef ridge # undef SIGTSTP #endif /* ridge */ #ifdef HAVE_WRITEV # include #else struct iovec { char *iov_base; int iov_len; }; #endif #ifdef hpux # include # define TCGETATTR /* tcgetattr() */ #endif #ifdef BSD44 # define USE_OLD_TTY # define _maxx maxx /* curses.h */ # define _maxy maxy # define _curx curx /* curses.h */ # define _cury cury void __cputchar __P((int)); # undef _putchar # define _putchar __cputchar # include /* sgttyb */ #endif #define ALARM ((unsigned int) 10) #define PAUSE ((unsigned int) 2) #ifndef abs # define abs(a) ((a) > 0 ? (a) : -(a)) #endif #define SMALLMOVE 1 #define LARGEMOVE 10 #define XYZ /* XXX */ static struct swit switches[] = { #define PRMPTSW 0 { "prompt string", 6 }, #define PROGSW 1 { "vmhproc program", 7 }, #define NPROGSW 2 { "novmhproc", 9 }, #define VERSIONSW 3 { "version", 0 }, #define HELPSW 4 { "help", 0 }, { NULL, 0 } }; /* 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 */ # ifndef SVR4 # define WERASC ltc.t_werasc static struct ltchars ltc; # else /* SVR4 */ # define WERASC sg.c_cc[VWERASE] # undef TIOCGLTC /* the define exists, but struct ltchars doesn't */ # endif #endif /* TIOCGLTC */ #if !defined(SYS5) && !defined(BSD44) int _putchar(); #endif /* not SYS5 */ #ifdef SIGTSTP char *tgoto(); #endif /* SIGTSTP */ /* SIGNALS */ static RETSIGTYPE ALRMser(int); static RETSIGTYPE PIPEser(int); static RETSIGTYPE SIGser(int); #ifdef SIGTSTP static RETSIGTYPE TSTPser(int); #endif /* SIGTSTP */ /* MISCELLANY */ /* * static prototypes */ static void adorn (char *, char *, ...); static vmh(), lreset(), linsert(), ladvance(), lretreat(), lgo(); static TTYon(), TTYoff(), foreground(); static int PEERinit(), pINI(), pLOOP(), pTTY(), pWIN(), WINinit(); static int WINgetstr(), WINless(), WINputc(), TTYinit(), pWINaux(); int main (int argc, char **argv) { int vecp = 1, nprog = 0; char *cp, buffer[BUFSIZ]; char **argp, **arguments, *vec[MAXARGS]; #ifdef LOCALE setlocale(LC_ALL, ""); #endif invo_name = r1bindex (argv[0], '/'); /* read user profile/context */ context_read(); arguments = getarguments (invo_name, argc, argv, 1); argp = arguments; while ((cp = *argp++)) if (*cp == '-') switch (smatch (++cp, switches)) { case AMBIGSW: ambigsw (cp, switches); done (1); case UNKWNSW: vec[vecp++] = --cp; continue; case HELPSW: snprintf (buffer, sizeof(buffer), "%s [switches for vmhproc]", invo_name); print_help (buffer, switches, 1); done (1); case VERSIONSW: print_version(invo_name); done (1); case PRMPTSW: if (!(myprompt = *argp++) || *myprompt == '-') adios (NULL, "missing argument to %s", argp[-2]); continue; case PROGSW: if (!(vmhproc = *argp++) || *vmhproc == '-') adios (NULL, "missing argument to %s", argp[-2]); continue; case NPROGSW: nprog++; continue; } else vec[vecp++] = cp; if (TTYinit (nprog) == NOTOK || WINinit (nprog) == NOTOK) { vec[vecp] = NULL; vec[0] = r1bindex (vmhproc, '/'); execvp (vmhproc, vec); adios (vmhproc, "unable to exec"); } TTYoff (); PEERinit (vecp, vec); TTYon (); vmh (); return done (0); } static void vmh (void) { char buffer[BUFSIZ]; for (;;) { pLOOP (RC_QRY, NULL); 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) pLOOP (RC_CMD, buffer); break; } } } /* PEERS */ static int PEERinit (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"); #ifdef hpux switch (PEERpid = fork ()) { /* * Calling vfork() and then another routine [like close()] before * an exec() messes up the stack frame, causing crib death. * Use fork() instead. */ #else /* not hpux */ switch (PEERpid = vfork ()) { #endif /* not hpux */ case NOTOK: adios ("vfork", "unable to");/* NOTREACHED */ case OK: close (pfd0[0]); close (pfd1[1]); vec[vecp++] = "-vmhread"; snprintf (buf1, sizeof(buf1), "%d", pfd1[0]); vec[vecp++] = buf1; vec[vecp++] = "-vmhwrite"; snprintf (buf2, sizeof(buf2), "%d", pfd0[1]); vec[vecp++] = buf2; vec[vecp] = NULL; SIGNAL (SIGINT, SIG_DFL); SIGNAL (SIGQUIT, SIG_DFL); vec[0] = r1bindex (vmhproc, '/'); execvp (vmhproc, vec); perror (vmhproc); _exit (-1); /* NOTREACHED */ default: close (pfd0[1]); close (pfd1[0]); rcinit (pfd0[0], pfd1[1]); return pINI (); } } static int pINI (void) { int len, buflen; char *bp, buffer[BUFSIZ]; struct record rcs; register struct record *rc = &rcs; register WINDOW **w; initrc (rc); /* Get buffer ready to go */ bp = buffer; buflen = sizeof(buffer); snprintf (bp, buflen, "%d %d", RC_VRSN, numwins); len = strlen (bp); bp += len; buflen -= len; for (w = windows; *w; w++) { snprintf (bp, buflen, " %d", (*w)->_maxy); len = strlen (bp); bp += len; buflen -= len; } switch (str2rc (RC_INI, buffer, rc)) { case RC_ACK: return OK; case RC_ERR: if (rc->rc_len) adios (NULL, "%s", rc->rc_data); else adios (NULL, "pINI peer error"); case RC_XXX: adios (NULL, "%s", rc->rc_data); default: adios (NULL, "pINI protocol screw-up"); } /* NOTREACHED */ } static int pLOOP (char *code, char *str) { int i; struct record rcs; register struct record *rc = &rcs; initrc (rc); 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) { 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 (NULL, "%s", rc->rc_data); else adorn (NULL, "pLOOP(%s) peer error", code == RC_QRY ? "QRY" : "CMD"); return NOTOK; case RC_FIN: if (rc->rc_len) adorn (NULL, "%s", rc->rc_data); rcdone (); i = pidwait (PEERpid, OK); PEERpid = NOTOK; done (i); case RC_XXX: adios (NULL, "%s", rc->rc_data); default: adios (NULL, "pLOOP(%s) protocol screw-up", code == RC_QRY ? "QRY" : "CMD"); } } static int pTTY (struct record *r) { SIGNAL_HANDLER hstat, istat, qstat, tstat; struct record rcs; register struct record *rc = &rcs; initrc (rc); TTYoff (); /* should be changed to block instead of ignore */ hstat = SIGNAL (SIGHUP, SIG_IGN); istat = SIGNAL (SIGINT, SIG_IGN); qstat = SIGNAL (SIGQUIT, SIG_IGN); tstat = SIGNAL (SIGTERM, SIG_IGN); rc2rc (RC_ACK, 0, NULL, rc); SIGNAL (SIGHUP, hstat); SIGNAL (SIGINT, istat); SIGNAL (SIGQUIT, qstat); SIGNAL (SIGTERM, tstat); TTYon (); if (r->rc_len && strcmp (r->rc_data, "FAST") == 0) goto no_refresh; #ifdef SIGTSTP SIGNAL (SIGTSTP, SIG_IGN); #endif #ifndef TERMINFO if (SO) tputs (SO, 0, _putchar); #else /* TERMINFO */ putp(enter_standout_mode); #endif /* TERMINFO */ fprintf (stdout, "Type any key to continue... "); fflush (stdout); #ifndef TERMINFO if (SE) tputs (SE, 0, _putchar); #else /* TERMINFO */ putp(exit_standout_mode); #endif /* TERMINFO */ getc (stdin); #ifdef SIGTSTP SIGNAL (SIGTSTP, TSTPser); #endif /* SIGTSTP */ wrefresh (curscr); no_refresh: ; switch (rc->rc_type) { case RC_EOF: rc2peer (RC_ACK, 0, NULL); return OK; case RC_ERR: if (rc->rc_len) adorn (NULL, "%s", rc->rc_data); else adorn (NULL, "pTTY peer error"); return NOTOK; case RC_XXX: adios (NULL, "%s", rc->rc_data); default: adios (NULL, "pTTY protocol screw-up"); } /* NOTREACHED */ } static int pWIN (WINDOW *w) { int i; did_less = 0; if ((i = pWINaux (w)) == OK && did_less) WINless (w, 1); lreset (); return i; } static int pWINaux (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, NULL, 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: ; 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: rc2peer (RC_ACK, 0, NULL); #ifdef XYZ if (w == Status) wstandend (w); #endif /* XYZ */ wrefresh (w); return OK; case RC_ERR: if (rc->rc_len) adorn (NULL, "%s", rc->rc_data); else adorn (NULL, "pWIN peer error"); return NOTOK; case RC_XXX: adios (NULL, "%s", rc->rc_data); default: adios (NULL, "pWIN protocol screw-up"); } /* NOTREACHED */ } static int pFIN (void) { int status; if (PEERpid <= OK) return OK; rc2peer (RC_FIN, 0, NULL); rcdone (); switch (setjmp (PEERctx)) { case OK: SIGNAL (SIGALRM, ALRMser); alarm (ALARM); status = pidwait (PEERpid, OK); alarm (0); break; default: kill (PEERpid, SIGKILL); status = NOTOK; break; } PEERpid = NOTOK; return status; } /* WINDOWS */ static int WINinit (int nprog) { register int nlines, /* not "lines" because terminfo uses that */ top, bottom; foreground (); if (initscr () == (WINDOW *) ERR) if (nprog) return NOTOK; else adios (NULL, "could not initialize terminal"); #ifdef SIGTSTP SIGNAL (SIGTSTP, SIG_DFL); #endif /* SIGTSTP */ sideground (); #ifndef TERMINFO if (CM == NULL) #else /* TERMINFO */ if (cursor_address == NULL) /* assume mtr wanted "cm", not "CM" */ #endif /* TERMINFO */ if (nprog) return NOTOK; else adios (NULL, "sorry, your terminal isn't powerful enough to run %s", invo_name); #ifndef TERMINFO if (tgetflag ("xt") || tgetnum ("sg") > 0) SO = SE = US = UE = NULL; #else /* TERMINFO */ /* * If termcap mapped directly to terminfo, we'd use the following: * if (teleray_glitch || magic_cookie_glitch > 0) * enter_standout_mode = exit_standout_mode = * enter_underline_mode = exit_underline_mode = NULL; * But terminfo does the right thing so we don't have to resort to that. */ #endif /* TERMINFO */ if ((nlines = LINES - 1) < 11) adios (NULL, "screen too small"); if ((top = nlines / 3 + 1) > LINES / 4 + 2) top--; bottom = nlines - 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; } static int WINgetstr (WINDOW *w, char *buffer) { register int c; register char *bp; bp = buffer; *bp = 0; for (;;) { switch (c = toascii (wgetch (w))) { case ERR: adios (NULL, "wgetch lost"); case '\f': wrefresh (curscr); break; case '\r': case '\n': *bp = 0; 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 = 0; 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 >= ' ' && c < '\177') waddch (w, *bp++ = c); break; } wrefresh (w); } } static int WINwritev (WINDOW *w, struct iovec *iov, 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; } 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 }; static int WINless (WINDOW *w, int fin) { register int c, i, n; char *cp; register struct line *lbottom; int nfresh, nwait; #ifdef notdef int nlatch; #endif 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) { 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)) { 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 waddstr (w, hlpmsg[i].h_msg); 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; } } } static int WINputc (WINDOW *w, char c) { register int x, y; switch (c) { default: if (!isascii (c)) { if (WINputc (w, 'M') == ERR || WINputc (w, '-') == ERR) return ERR; c = toascii (c); } else if (c < ' ' || c == '\177') { if (WINputc (w, '^') == ERR) return ERR; c ^= 0100; } break; case '\t': case '\n': break; } 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) waddch (w, c); else wclrtoeol (w); break; default: if (++x < w->_maxx) waddch (w, c); break; } return DONE; } /* LINES */ static void lreset (void) { 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 void linsert (WINDOW *w) { register char *cp; register struct line *lp; if ((lp = (struct line *) calloc ((size_t) 1, sizeof *lp)) == NULL) adios (NULL, "unable to allocate line storage"); lp->l_no = (ltail ? ltail->l_no : 0) + 1; #ifndef BSD44 lp->l_buf = getcpy (w->_y[w->_cury]); #else lp->l_buf = getcpy (w->lines[w->_cury]->line); #endif for (cp = lp->l_buf + strlen (lp->l_buf) - 1; cp >= lp->l_buf; cp--) if (isspace (*cp)) *cp = 0; else break; if (lhead == NULL) lhead = lp; if (ltop == NULL) ltop = lp; if (ltail) ltail->l_next = lp; lp->l_prev = ltail; ltail = lp; } static int ladvance (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 (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; } static int lgo (int n) { register int i, j; register struct line *lp; if ((i = n - (lp = lhead)->l_no) > (j = abs (n - (ltop ? ltop : ltail)->l_no))) i = j, lp = ltop ? ltop : ltail; 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; } /* TTYS */ static int TTYinit (int nprog) { if (!isatty (fileno (stdin)) || !isatty (fileno (stdout))) if (nprog) return NOTOK; else adios (NULL, "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 #ifdef TCGETATTR if( tcgetattr( fileno(stdin), &sg) == NOTOK) adios( "failed", "tcgetattr"); #else /* SYS5 */ if (ioctl (fileno (stdin), TCGETA, &sg) == NOTOK) adios ("failed", "ioctl TCGETA"); #endif #endif #ifdef TIOCGLTC if (ioctl (fileno (stdin), TIOCGLTC, (char *) <c) == NOTOK) adios ("failed", "ioctl TIOCGLTC"); #endif /* TIOCGLTC */ intrc = INTR; sideground (); tty_ready = OK; SIGNAL (SIGPIPE, PIPEser); return OK; } static void TTYon (void) { if (tty_ready == DONE) return; INTR = NOTOK; #ifndef SYS5 ioctl (fileno (stdin), TIOCSETC, (char *) &tc); #else /* SYS5 */ ioctl (fileno (stdin), TCSETA, &sg); #endif /* SYS5 */ crmode (); noecho (); nonl (); scrollok (curscr, FALSE); discard (stdin); tty_ready = DONE; SIGNAL (SIGHUP, SIGser); SIGNAL (SIGINT, SIGser); SIGNAL (SIGQUIT, SIGser); #ifdef SIGTSTP SIGNAL (SIGTSTP, TSTPser); #endif /* SIGTSTP */ } static void TTYoff (void) { if (tty_ready == NOTOK) return; INTR = intrc; #ifndef SYS5 ioctl (fileno (stdin), TIOCSETC, (char *) &tc); #else /* SYS5 */ ioctl (fileno (stdin), TCSETA, &sg); #endif /* SYS5 */ leaveok (curscr, TRUE); mvcur (0, COLS - 1, LINES - 1, 0); endwin (); if (tty_ready == DONE) { #ifndef TERMINFO if (CE) tputs (CE, 0, _putchar); else #else /* TERMINFO */ putp(clr_eol); #endif /* TERMINFO */ fprintf (stdout, "\r\n"); } fflush (stdout); tty_ready = NOTOK; SIGNAL (SIGHUP, SIG_DFL); SIGNAL (SIGINT, SIG_DFL); SIGNAL (SIGQUIT, SIG_DFL); #ifdef SIGTSTP SIGNAL (SIGTSTP, SIG_DFL); #endif /* SIGTSTP */ } static void foreground (void) { #ifdef TIOCGPGRP int pgrp, tpgrp; SIGNAL_HANDLER tstat; if ((pgrp = getpgrp()) == 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); kill (0, SIGTTIN); SIGNAL (SIGTTIN, tstat); } SIGNAL (SIGTTIN, SIG_IGN); SIGNAL (SIGTTOU, SIG_IGN); SIGNAL (SIGTSTP, SIG_IGN); #endif /* TIOCGPGRP */ } void sideground (void) { #ifdef TIOCGPGRP SIGNAL (SIGTTIN, SIG_DFL); SIGNAL (SIGTTOU, SIG_DFL); SIGNAL (SIGTSTP, SIG_DFL); #endif /* TIOCGPGRP */ } /* SIGNALS */ static RETSIGTYPE ALRMser (int sig) { longjmp (PEERctx, DONE); } #ifdef BSD42 /* ARGSUSED */ #endif /* BSD42 */ static RETSIGTYPE PIPEser (int sig) { #ifndef RELIABLE_SIGNALS SIGNAL (sig, SIG_IGN); #endif adios (NULL, "lost peer"); } static RETSIGTYPE SIGser (int sig) { #ifndef RELIABLE_SIGNALS SIGNAL (sig, SIG_IGN); #endif done (1); } #ifdef SIGTSTP static RETSIGTYPE TSTPser (int sig) { #ifndef TERMINFO tputs (tgoto (CM, 0, LINES - 1), 0, _putchar); #else /* TERMINFO */ move(LINES - 1, 0); /* to lower left corner */ clrtoeol(); /* clear bottom line */ wrefresh(curscr); /* flush out everything */ #endif /* TERMINFO */ fflush (stdout); TTYoff (); #ifdef BSD42 sigsetmask (sigblock (0) & ~sigmask (SIGTSTP)); #endif /* BSD42 */ kill (getpid (), sig); #ifdef BSD42 sigblock (sigmask (SIGTSTP)); #endif /* BSD42 */ TTYon (); wrefresh (curscr); } #endif /* SIGTSTP */ /* MISCELLANY */ int done (int status) { TTYoff (); pFIN (); exit (status); return 1; /* dead code to satisfy the compiler */ } static void adorn (char *what, char *fmt, ...) { va_list ap; char *cp; cp = invo_name; invo_name = NULL; va_start(ap, fmt); advertise (what, NULL, fmt, ap); va_end(ap); invo_name = cp; } void advertise (char *what, char *tail, char *fmt, va_list ap) { int eindex = errno; char buffer[BUFSIZ], err[BUFSIZ]; struct iovec iob[20]; register struct iovec *iov = iob; fflush (stdout); fflush (stderr); if (invo_name) { iov->iov_len = strlen (iov->iov_base = invo_name); iov++; iov->iov_len = strlen (iov->iov_base = ": "); iov++; } vsnprintf (buffer, sizeof(buffer), fmt, ap); 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 (!(iov->iov_base = strerror (eindex))) { snprintf (err, sizeof(err), "Error %d", eindex); iov->iov_base = err; } iov->iov_len = strlen (iov->iov_base); 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) WINwritev (Display, iob, iov - iob); else writev (fileno (stderr), iob, iov - iob); }