Mercurial > hg > Applications > mh
diff uip/vmh.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children | a6481689f99c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uip/vmh.c Mon Apr 18 23:46:02 2005 +0900 @@ -0,0 +1,1834 @@ +/* vmh.c - visual front-end to mh */ +#ifndef lint +static char ident[] = "@(#)$Id$"; +#endif /* lint */ +#if defined(SYS5) && !defined(linux) && !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 + +/* TODO: + Pass signals to client during execution + + 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 + */ + +#ifdef UNISTD +#include <unistd.h> +#endif +#ifdef __osf__ +#define _BSD +#endif +#ifdef NCURSES +#include <ncurses.h> +#else +#include <curses.h> +#endif /* NCURSES */ +#if defined(__NCURSES_H) && !defined(TERMINFO) +#define TERMINFO +#endif /* __NCURSES_H */ +#ifdef ncr +#define _SYS_REG_H /* NCR redefines "ERR" in <sys/reg.h> */ +#endif +#undef OK /* tricky */ +#ifdef TERMINFO +#include <term.h> /* variables describing terminal capabilities */ +#if defined(HAVE_TCGETATTR) && !defined(TCGETATTR) +#define TCGETATTR +#endif +#if defined(__NCURSES_H) +#if defined(TERMIOS) || defined(_USE_TERMIOS) +#ifndef SYS5 +#define SYS5 +#endif +#ifndef TCGETATTR +#define TCGETATTR +#endif +#endif /* TERMIOS */ +#undef OK /* tricky */ +#endif /* __NCURSES_H */ +#endif /* TERMINFO */ +#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 */ +#ifdef ridge +#undef SIGTSTP +#endif /* ridge */ +#if !defined(BSD42) && !defined(SVR4) +struct iovec { + char *iov_base; + int iov_len; +}; +#else /* BSD42 || SVR4 */ +#include <sys/types.h> +#include <sys/uio.h> +#endif /* BSD42 || SVR4 */ +#ifdef LOCALE +#include <locale.h> +#endif +#if defined(hpux) || defined(__osf__) +#include <termio.h> +#define TCGETATTR /* tcgetattr() */ +#endif +#if !defined(__NCURSES_H) && (defined(BSD44) || defined(linux)) +#define USE_OLD_TTY +#define _maxx maxx /* curses.h */ +#define _maxy maxy +#define _curx curx /* curses.h */ +#define _cury cury +#ifndef __NetBSD__ +void __cputchar __P((int)); +#endif +#undef _putchar +#ifdef BSD44 +#define _putchar __cputchar +#else +#define _putchar (int (*)()) __cputchar +#endif +#include <sys/ioctl.h> /* sgttyb */ +#endif /* !__NCURSES_H && (BSD44 || linux) */ + +#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 HELPSW 3 + "help", 4, + + 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] +#ifdef __NCURSES_H +static TTY sg; +#else +#ifndef __osf__ +static struct termio sg; +#else +static struct termios sg; +#endif /* __osf__ */ +#endif /* __NCURSES_H */ +#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) && !defined(TERMINFO) +int _putchar (); +#endif /* not SYS5 */ +#ifdef SIGTSTP +char *tgoto (); +#endif /* SIGTSTP */ + + + /* SIGNALS */ +static TYPESIG ALRMser (), PIPEser (), SIGser (); +#ifdef SIGTSTP +static TYPESIG TSTPser (); +#endif /* SIGTSTP */ + + + /* MISCELLANY */ +extern int errno; +#if !defined(BSD44) && !defined(__GNU_LIBRARY__) +extern int sys_nerr; +extern char *sys_errlist[]; +#endif + +static void adorn (); + +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(); +/* */ + +/* ARGSUSED */ + +main (argc, argv) +int argc; +char *argv[]; +{ + int vecp = 1, + nprog = 0; + char *cp, + buffer[BUFSIZ], + **ap, + **argp, + *arguments[MAXARGS], + *vec[MAXARGS]; + +#ifdef LOCALE + setlocale(LC_ALL, ""); +#endif +#ifdef JAPAN + ml_init(); +#endif /* JAPAN */ + 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; + +/* */ + + 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; + +/* */ + + 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); +} + +/* */ + +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; + } + } +} + +/* 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"); +#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: + (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 (); + } +} + +/* */ + +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++) { +#ifndef __NCURSES_H +#ifdef __NetBSD__ + (void) sprintf (bp, " %d", getmaxy(*w)); +#else /* __NetBSD__ */ + (void) sprintf (bp, " %d", (*w) -> _maxy); +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + (void) sprintf (bp, " %d", (*w) -> _maxy + 1); +#endif /* __NCURSES_H */ + 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 */ +} + +/* */ + +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"); + } +} + +/* */ + +static int pTTY (r) +register struct record *r; +{ + TYPESIG (*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 TERMINFO + if (SO) + tputs (SO, 0, _putchar); +#else /* TERMINFO */ + putp(enter_standout_mode); +#endif /* TERMINFO */ + fprintf (stdout, "Type any key to continue... "); + (void) fflush (stdout); +#ifndef TERMINFO + if (SE) + tputs (SE, 0, _putchar); +#else /* TERMINFO */ + putp(exit_standout_mode); +#endif /* TERMINFO */ + (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 */ +} + +/* */ + +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; +} + +/* */ + +static int pWINaux (w) +register WINDOW *w; +{ + register int n; + int eol; + register char c, + *bp; + struct record rcs; + register struct record *rc = &rcs; +#ifdef JAPAN + char *cp, *ep, *tmpbak = NULLCP; + int kanji1st; /* kanji 1st byte? */ +#endif /* JAPAN */ + + 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; +#ifdef JAPAN + ep = add(rc -> rc_data, tmpbak); + if ((cp = rindex(ep, '\n'))) { + strcpy(rc -> rc_data, ++cp); + *cp = '\0'; + tmpbak = rc -> rc_data; + rc -> rc_data = ep; + } else { + rc -> rc_data[0] = '\0'; + tmpbak = ep; + } + (void) ml_conv(rc -> rc_data); + rc -> rc_len = strlen(rc -> rc_data); + kanji1st = 0; +#endif /* JAPAN */ + for (bp = rc -> rc_data, n = rc -> rc_len; n-- > 0; ) { +#ifdef JAPAN + if ((unsigned char) (c = *bp) > 0xa0 + && (unsigned char) c < 0xff) /* EUC */ + kanji1st = kanji1st ? 0 : 1; +#endif /* JAPAN */ + if ((c = *bp++) == '\n') + linsert (w); +#ifndef __NCURSES_H +#ifdef __NetBSD__ + else if (getcurx(w) == getmaxx(w) - 2 && w == Display) { +#else /* __NetBSD__ */ + else if (w -> _curx == w -> _maxx - 2 && w == Display) { +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + else if (w -> _curx == w -> _maxx - 1 && w == Display) { +#endif /* __NCURSES_H */ + linsert(w); +#ifdef JAPAN + if (!kanji1st + && (c & 0x7f) > 0x20 && (c & 0x7f) < 0x7f) { +#else /* JAPAN */ + if (c > 0x20 && c < 0x7f) { +#endif /* JAPAN */ + int i; +#ifdef __NetBSD__ + for (i = strlen(ltail->l_buf); i < getcurx(w); i++) + ltail -> l_buf[i] = ' '; + ltail -> l_buf[getcurx(w)] = c; + ltail -> l_buf[getcurx(w)] = '\0'; +#else /* __NetBSD__ */ + for (i = strlen(ltail->l_buf); i < w->_curx; i++) + ltail -> l_buf[i] = ' '; + ltail -> l_buf[w -> _curx] = c; + ltail -> l_buf[w -> _curx + 1] = '\0'; +#endif /* __NetBSD__ */ + } else { +#ifdef JAPAN + kanji1st = 0; +#endif /* JAPAN */ + c = '\n'; + bp--; + n++; + } + } + if (WINputc (w, c) == ERR +#ifndef __NCURSES_H +#ifdef __NetBSD__ + || (getcurx(w) >= getmaxx(w) - 1 && w == Display +#else /* __NetBSD__ */ + || (w -> _curx >= w -> _maxx - 1 && w == Display +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + || (w -> _curx >= w -> _maxx && w == Display +#endif /* __NCURSES_H */ + && WINputc (w, '\n') == 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 */ +} + +/* */ + +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; +} + +/* WINDOWS */ + +static int WINinit (nprog) { + register int nlines, /* not "lines" because terminfo uses that */ + top, + bottom; + + foreground (); + if (initscr () == (WINDOW *) ERR) + if (nprog) + return NOTOK; + else + adios (NULLCP, "could not initialize terminal"); +#ifdef SIGTSTP + (void) 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 (NULLCP, + "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 (NULLCP, "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; + +#ifndef __NCURSES_H +#ifdef __NetBSD__ + largemove = getmaxy(Display) / 2 + 2; +#else /* __NetBSD__ */ + largemove = Display -> _maxy / 2 + 2; +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + largemove = (Display -> _maxy + 1) / 2 + 2; +#endif /* __NCURSES_H */ + return OK; +} + +/* */ + +static int WINgetstr (w, buffer) +register WINDOW *w; +char *buffer; +{ + register int c; + register char *bp; + + bp = buffer; + *bp = 0; + + for (;;) { + switch (c = wgetch (w) & 0xff) { + case ERR: + adios (NULLCP, "wgetch lost"); + + case '\f': + wrefresh (curscr); + break; + + case '\r': + case '\n': + *bp = 0; + if (bp > buffer) { + leaveok (curscr, FALSE); +#ifdef __NetBSD__ + wmove (w, 0, getcurx(w) - (bp - buffer)); +#else /* __NetBSD__ */ + wmove (w, 0, w -> _curx - (bp - buffer)); +#endif /* __NetBSD__ */ + 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; +#ifdef __NetBSD__ + bp--; + wmove(w, getcury(w), getcurx(w) - 1); + wrefresh(w); +#else /* __NetBSD__ */ + bp--, w -> _curx--; +#endif /* __NetBSD__ */ + wclrtoeol (w); + break; + } + if (c == KILL) { + if (bp <= buffer) + continue; +#ifdef __NetBSD__ + wmove(w, getcury(w), getcurx(w) - (bp - buffer)); + wrefresh(w); +#else /* __NetBSD__ */ + w -> _curx -= bp - buffer; +#endif /* __NetBSD__ */ + bp = buffer; + wclrtoeol (w); + break; + } + if (c == WERASC) { + if (bp <= buffer) + continue; + do { +#ifdef __NetBSD__ + bp--; + wmove(w, getcury(w), getcurx(w) - 1); +#else /* __NetBSD__ */ + bp--, w -> _curx--; +#endif /* __NetBSD__ */ + } while (isspace (*bp) && bp > buffer); + + if (bp > buffer) { + do { +#ifdef __NetBSD__ + bp--; + wmove(w, getcury(w), getcurx(w) - 1); +#else /* __NetBSD__ */ + bp--, w -> _curx--; +#endif /* __NetBSD__ */ + } while (!isspace (*bp) && bp > buffer); + if (isspace (*bp)) +#ifdef __NetBSD__ + { + bp++; + wmove(w, getcury(w), getcurx(w) + 1); + } +#else /* __NetBSD__ */ + bp++, w -> _curx++; +#endif /* __NetBSD__ */ + } +#ifdef __NetBSD__ + wrefresh (w); +#endif /* __NetBSD__ */ + wclrtoeol (w); + break; + } + + if ((c >= ' ' && c < '\177') || (c >= 0xa1 && c <= 0xfe)) + (void) waddch (w, *bp++ = c); + break; + } + + wrefresh (w); + } +} + +/* */ + +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; +} + +/* */ + +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 (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) { +#ifndef __NCURSES_H +#ifdef __NetBSD__ + (void) lgo (ltail -> l_no - getmaxy(w) + 1); +#else /* __NetBSD__ */ + (void) lgo (ltail -> l_no - w -> _maxy + 1); +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + (void) lgo (ltail -> l_no - w -> _maxy + 2); +#endif /* __NCURSES_H */ + 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 +#ifndef __NCURSES_H +#ifdef __NetBSD__ + if (nlatch && (ltail -> l_no >= getmaxy(w))) { + (void) lgo (ltail -> l_no - getmaxy(w) + 1); +#else /* __NetBSD__ */ + if (nlatch && (ltail -> l_no >= w -> _maxy)) { + (void) lgo (ltail -> l_no - w -> _maxy + 1); +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + if (nlatch && (ltail -> l_no > w -> _maxy)) { + (void) lgo (ltail -> l_no - w -> _maxy + 2); +#endif /* __NCURSES_H */ + 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': +#ifndef __NCURSES_H +#ifdef __NetBSD__ + if (lgo (n ? n : ltail -> l_no - getmaxy(w) + 1)) +#else /* __NetBSD__ */ + if (lgo (n ? n : ltail -> l_no - w -> _maxy + 1)) +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + if (lgo (n ? n : ltail -> l_no - w -> _maxy + 2)) +#endif /* __NCURSES_H */ + 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; + } + } +} + +/* */ + +static int WINputc (w, c) +register WINDOW *w; +register unsigned char c; +{ + register int x, + y; + + switch (c) { + default: + if (!isascii (c) + && !(c >= 0xa1 && c <= 0xfe) /* pass EUC or ISO-8859-x */ + ) { + 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); + +#ifndef __NCURSES_H +#ifdef __NetBSD__ + if ((x = getcurx(w)) < 0 || x >= getmaxx(w) + || (y = getcury(w)) < 0 || y >= getmaxy(w)) +#else /* __NetBSD__ */ + if ((x = w -> _curx) < 0 || x >= w -> _maxx + || (y = w -> _cury) < 0 || y >= w -> _maxy) +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + if ((x = w -> _curx) < 0 || x > w -> _maxx + || (y = w -> _cury) < 0 || y > w -> _maxy) +#endif /* __NCURSES_H */ + return DONE; + + switch (c) { + case '\t': + for (x = 8 - (x & 0x07); x > 0; x--) + if (WINputc (w, ' ') == ERR) + return ERR; + break; + + case '\n': +#ifndef __NCURSES_H +#ifdef __NetBSD__ + if (++y < getmaxy(w)) +#else /* __NetBSD__ */ + if (++y < w -> _maxy) +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + if (++y <= w -> _maxy) +#endif /* __NCURSES_H */ + (void) waddch (w, c); + else + wclrtoeol (w); + break; + + default: +#ifndef __NCURSES_H +#ifdef __NetBSD__ + if (++x < getmaxx(w)) +#else /* __NetBSD__ */ + if (++x < w -> _maxx) +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + if (++x <= w -> _maxx) +#endif /* __NCURSES_H */ + (void) waddch (w, c); + break; + } + + return DONE; +} + +/* 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; + /* + * "chtype" is not always "char". We must not do getcpy() simply. + */ + /* lp -> l_buf = getcpy (w -> _y[w -> _cury]); */ +#ifndef __NCURSES_H +#ifdef __NetBSD__ + { + int i, cur; + if ((lp -> l_buf = (char *) malloc(getmaxx(w) + 1)) == NULL) + adios (NULLCP, "unable to allocate storage"); + cur = getcurx(w); + for (i = 0; i < getmaxx(w); i++) { +#ifdef getmaxx + /* maybe older than NetBSD-1.5 */ + lp -> l_buf[i] = w -> lines[getcury(w)] -> line[i].ch; +#else + wmove(w, getcury(w), i); + lp -> l_buf[i] = winch(w); /* 8bit ?? */ +#endif + } + lp -> l_buf[getmaxx(w)] = '\0'; + wmove(w, getcury(w), cur); + } +#else /* __NetBSD__ */ + { + int i; + if ((lp -> l_buf = (char *) malloc(w -> _maxx + 1)) == NULL) + adios (NULLCP, "unable to allocate storage"); + for (i = 0; i < w -> _maxx; i++) +#if !defined(BSD44) && !defined(__386BSD__) && !defined(linux) + lp -> l_buf[i] = (char) w -> _y[w -> _cury][i]; +#else + lp -> l_buf[i] = w -> lines[w -> _cury] -> line[i].ch; +#endif + lp -> l_buf[w -> _maxx] = '\0'; + } +#endif /* __NetBSD__ */ +#else /* __NCURSES_H */ + { + int i; + if ((lp -> l_buf = (char *) malloc(w -> _maxx + 2)) == NULL) + adios (NULLCP, "unable to allocate storage"); + for (i = 0; i <= w -> _maxx; i++) + lp -> l_buf[i] = (char) w -> _line[w -> _cury].text[i]; + lp -> l_buf[w -> _maxx + 1] = '\0'; + } +#endif /* __NCURSES_H */ + 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 (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; +} + +/* */ + +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 ? 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 (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 */ +#ifdef TCGETATTR + if( tcgetattr( fileno(stdin), &sg) == NOTOK) + adios( "failed", "tcgetattr"); +#else + if (ioctl (fileno (stdin), TCGETA, &sg) == NOTOK) + adios ("failed", "ioctl TCGETA"); +#endif +#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; +} + +/* */ + +static TTYon () { + if (tty_ready == DONE) + return; + + INTR = NOTOK; +#ifndef SYS5 + (void) ioctl (fileno (stdin), TIOCSETC, (char *) &tc); +#else /* SYS5 */ +#if defined(TCGETATTR) && !defined(TCSETA) && defined(TCSANOW) + (void) tcsetattr (fileno (stdin), TCSANOW, &sg); +#else + (void) ioctl (fileno (stdin), TCSETA, &sg); +#endif +#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 */ +} + +/* */ + +static TTYoff () { + if (tty_ready == NOTOK) + return; + + INTR = intrc; +#ifndef SYS5 + (void) ioctl (fileno (stdin), TIOCSETC, (char *) &tc); +#else /* SYS5 */ +#if defined(TCGETATTR) && !defined(TCSETA) && defined(TCSANOW) + (void) tcsetattr (fileno (stdin), TCSANOW, &sg); +#else + (void) ioctl (fileno (stdin), TCSETA, &sg); +#endif +#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"); + } + (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 */ +} + +/* */ + +static foreground () { +#ifdef TIOCGPGRP + int pgrp, + tpgrp; + TYPESIG (*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 */ +} + +/* SIGNALS */ + +/* ARGSUSED */ + +static TYPESIG ALRMser (sig) +int sig; +{ + longjmp (PEERctx, DONE); +} + + +#ifdef BSD42 +/* ARGSUSED */ +#endif /* BSD42 */ + +static TYPESIG PIPEser (sig) +int sig; +{ +#ifndef BSD42 + (void) signal (sig, SIG_IGN); +#endif /* BSD42 */ + + adios (NULLCP, "lost peer"); +} + + +#ifdef BSD42 +/* ARGSUSED */ +#endif /* BSD42 */ + +static TYPESIG SIGser (sig) +int sig; +{ +#ifndef BSD42 + (void) signal (sig, SIG_IGN); +#endif /* BSD42 */ + + done (1); +} + + +#ifdef SIGTSTP +static TYPESIG TSTPser (sig) +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 */ + (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 */ + +/* MISCELLANY */ + +void done (status) +int status; +{ + TTYoff (); + (void) pFIN (); + + exit (status); +} + +/* */ + +/* 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; +} + +/* */ + +/* VARARGS3 */ + +#if !defined(BSD42) && !defined(SVR4) +static int writev(); +#endif + +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 = (char *) 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); +} + +/* */ + +#if !defined(BSD42) && !defined(SVR4) +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 || SVR4 */