📄 vmh.c
字号:
/* vmh.c - visual front-end to mh */#ifndef lintstatic char ident[] = "@(#)$Id: vmh.c,v 1.20 1993/08/25 17:29:44 jromine Exp $";#endif /* lint */#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/* 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 */#include <curses.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 */#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 */#ifndef BSD42struct iovec { char *iov_base; int iov_len;};#else /* BSD42 */#include <sys/types.h>#include <sys/uio.h>#endif /* BSD42 */#ifdef LOCALE#include <locale.h>#endif#ifdef hpux#include <termio.h>#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 curyvoid __cputchar __P((int));#undef _putchar#define _putchar __cputchar#include <sys/ioctl.h> /* 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 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 3static 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_killstatic struct sgttyb sg;#define EOFC tc.t_eofc#define INTR tc.t_intrcstatic 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_werascstatic 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 SIGTSTPchar *tgoto ();#endif /* SIGTSTP */ /* SIGNALS */static TYPESIG ALRMser (), PIPEser (), SIGser ();#ifdef SIGTSTPstatic TYPESIG TSTPser ();#endif /* SIGTSTP */ /* MISCELLANY */extern int errno;#ifndef BSD44extern int sys_nerr;extern char *sys_errlist[];#endifstatic 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 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++) { (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 */}/* */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; 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 */}/* */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; largemove = Display -> _maxy / 2 + 2; 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 = toascii (wgetch (w))) { case ERR: adios (NULLCP, "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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -