]>
diplodocus.org Git - nmh/blob - uip/vmh.c
3 * vmh.c -- visual front-end to nmh
12 #if defined(SYS5) && !defined(TERMINFO)
14 * Define TERMINFO if you have it.
15 * You get it automatically if you're running SYS5, and you don't get
16 * it if you're not. (If you're not SYS5, you probably have termcap.)
17 * We distinguish TERMINFO from SYS5 because in this file SYS5 really
18 * means "AT&T line discipline" (termio, not sgttyb), whereas terminfo
19 * is quite a separate issue.
27 * 1) Pass signals to client during execution
28 * 2) Figure out a way for the user to say how big the Scan/Display
30 * 3) If curses ever gets fixed, then XYZ code can be removed
36 # define _SYS_REG_H /* NCR redefines "ERR" in <sys/reg.h> */
39 #undef OK /* tricky */
41 /* removed for right now */
44 # include <term.h> /* variables describing terminal capabilities */
54 # define sigmask(s) (1 << ((s) - 1))
55 #endif /* not sigmask */
72 # define TCGETATTR /* tcgetattr() */
77 # define _maxx maxx /* curses.h */
79 # define _curx curx /* curses.h */
81 void __cputchar
__P((int));
83 # define _putchar __cputchar
84 # include <sys/ioctl.h> /* sgttyb */
87 #define ALARM ((unsigned int) 10)
88 #define PAUSE ((unsigned int) 2)
91 # define abs(a) ((a) > 0 ? (a) : -(a))
99 static struct swit switches
[] = {
101 { "prompt string", 6 },
103 { "vmhproc program", 7 },
114 static int PEERpid
= NOTOK
;
116 static jmp_buf PEERctx
;
119 static char *myprompt
= "(%s) ";
122 static WINDOW
*Status
;
123 static WINDOW
*Display
;
124 static WINDOW
*Command
;
128 WINDOW
*windows
[NWIN
+ 1];
140 static struct line
*lhead
= NULL
;
141 static struct line
*ltop
= NULL
;
142 static struct line
*ltail
= NULL
;
144 static int did_less
= 0;
145 static int smallmove
= SMALLMOVE
;
146 static int largemove
= LARGEMOVE
;
151 static int tty_ready
= NOTOK
;
156 # define ERASE sg.sg_erase
157 # define KILL sg.sg_kill
158 static struct sgttyb sg
;
160 #define EOFC tc.t_eofc
161 #define INTR tc.t_intrc
162 static struct tchars tc
;
164 # define ERASE sg.c_cc[VERASE]
165 # define KILL sg.c_cc[VKILL]
166 # define EOFC sg.c_cc[VEOF]
167 # define INTR sg.c_cc[VINTR]
168 static struct termio sg
;
172 # define WERASC ('W' & 037)
175 # define WERASC ltc.t_werasc
176 static struct ltchars ltc
;
178 # define WERASC sg.c_cc[VWERASE]
179 # undef TIOCGLTC /* the define exists, but struct ltchars doesn't */
181 #endif /* TIOCGLTC */
184 #if !defined(SYS5) && !defined(BSD44)
186 #endif /* not SYS5 */
193 static RETSIGTYPE
ALRMser(int);
194 static RETSIGTYPE
PIPEser(int);
195 static RETSIGTYPE
SIGser(int);
197 static RETSIGTYPE
TSTPser(int);
207 static void adorn (char *, char *, ...);
209 static vmh(), lreset(), linsert(), ladvance(), lretreat(), lgo();
210 static TTYon(), TTYoff(), foreground();
211 static int PEERinit(), pINI(), pLOOP(), pTTY(), pWIN(), WINinit();
212 static int WINgetstr(), WINless(), WINputc(), TTYinit(), pWINaux();
216 main (int argc
, char **argv
)
218 int vecp
= 1, nprog
= 0;
219 char *cp
, buffer
[BUFSIZ
];
220 char **argp
, **arguments
, *vec
[MAXARGS
];
223 setlocale(LC_ALL
, "");
225 invo_name
= r1bindex (argv
[0], '/');
227 /* read user profile/context */
230 arguments
= getarguments (invo_name
, argc
, argv
, 1);
233 while ((cp
= *argp
++))
235 switch (smatch (++cp
, switches
)) {
237 ambigsw (cp
, switches
);
244 snprintf (buffer
, sizeof(buffer
), "%s [switches for vmhproc]",
246 print_help (buffer
, switches
, 1);
249 print_version(invo_name
);
253 if (!(myprompt
= *argp
++) || *myprompt
== '-')
254 adios (NULL
, "missing argument to %s", argp
[-2]);
258 if (!(vmhproc
= *argp
++) || *vmhproc
== '-')
259 adios (NULL
, "missing argument to %s", argp
[-2]);
268 if (TTYinit (nprog
) == NOTOK
|| WINinit (nprog
) == NOTOK
) {
271 vec
[0] = r1bindex (vmhproc
, '/');
272 execvp (vmhproc
, vec
);
273 adios (vmhproc
, "unable to exec");
276 PEERinit (vecp
, vec
);
291 pLOOP (RC_QRY
, NULL
);
293 wmove (Command
, 0, 0);
294 wprintw (Command
, myprompt
, invo_name
);
298 switch (WINgetstr (Command
, buffer
)) {
303 done (0); /* NOTREACHED */
307 pLOOP (RC_CMD
, buffer
);
316 PEERinit (int vecp
, char *vec
[])
318 int pfd0
[2], pfd1
[2];
319 char buf1
[BUFSIZ
], buf2
[BUFSIZ
];
321 if (pipe (pfd0
) == NOTOK
|| pipe (pfd1
) == NOTOK
)
322 adios ("pipe", "unable to");
324 switch (PEERpid
= fork ()) {
326 * Calling vfork() and then another routine [like close()] before
327 * an exec() messes up the stack frame, causing crib death.
328 * Use fork() instead.
331 switch (PEERpid
= vfork ()) {
332 #endif /* not hpux */
334 adios ("vfork", "unable to");/* NOTREACHED */
340 vec
[vecp
++] = "-vmhread";
341 snprintf (buf1
, sizeof(buf1
), "%d", pfd1
[0]);
343 vec
[vecp
++] = "-vmhwrite";
344 snprintf (buf2
, sizeof(buf2
), "%d", pfd0
[1]);
348 SIGNAL (SIGINT
, SIG_DFL
);
349 SIGNAL (SIGQUIT
, SIG_DFL
);
351 vec
[0] = r1bindex (vmhproc
, '/');
352 execvp (vmhproc
, vec
);
354 _exit (-1); /* NOTREACHED */
360 rcinit (pfd0
[0], pfd1
[1]);
370 char *bp
, buffer
[BUFSIZ
];
372 register struct record
*rc
= &rcs
;
377 /* Get buffer ready to go */
379 buflen
= sizeof(buffer
);
381 snprintf (bp
, buflen
, "%d %d", RC_VRSN
, numwins
);
386 for (w
= windows
; *w
; w
++) {
387 snprintf (bp
, buflen
, " %d", (*w
)->_maxy
);
393 switch (str2rc (RC_INI
, buffer
, rc
)) {
399 adios (NULL
, "%s", rc
->rc_data
);
401 adios (NULL
, "pINI peer error");
404 adios (NULL
, "%s", rc
->rc_data
);
407 adios (NULL
, "pINI protocol screw-up");
414 pLOOP (char *code
, char *str
)
418 register struct record
*rc
= &rcs
;
422 str2peer (code
, str
);
424 switch (peer2rc (rc
)) {
426 if (pTTY (rc
) == NOTOK
)
431 if (sscanf (rc
->rc_data
, "%d", &i
) != 1
434 fmt2peer (RC_ERR
, "no such window \"%s\"", rc
->rc_data
);
437 if (pWIN (windows
[i
- 1]) == NOTOK
)
446 adorn (NULL
, "%s", rc
->rc_data
);
448 adorn (NULL
, "pLOOP(%s) peer error",
449 code
== RC_QRY
? "QRY" : "CMD");
454 adorn (NULL
, "%s", rc
->rc_data
);
456 i
= pidwait (PEERpid
, OK
);
461 adios (NULL
, "%s", rc
->rc_data
);
464 adios (NULL
, "pLOOP(%s) protocol screw-up",
465 code
== RC_QRY
? "QRY" : "CMD");
471 pTTY (struct record
*r
)
473 SIGNAL_HANDLER hstat
, istat
, qstat
, tstat
;
475 register struct record
*rc
= &rcs
;
481 /* should be changed to block instead of ignore */
482 hstat
= SIGNAL (SIGHUP
, SIG_IGN
);
483 istat
= SIGNAL (SIGINT
, SIG_IGN
);
484 qstat
= SIGNAL (SIGQUIT
, SIG_IGN
);
485 tstat
= SIGNAL (SIGTERM
, SIG_IGN
);
487 rc2rc (RC_ACK
, 0, NULL
, rc
);
489 SIGNAL (SIGHUP
, hstat
);
490 SIGNAL (SIGINT
, istat
);
491 SIGNAL (SIGQUIT
, qstat
);
492 SIGNAL (SIGTERM
, tstat
);
496 if (r
->rc_len
&& strcmp (r
->rc_data
, "FAST") == 0)
500 SIGNAL (SIGTSTP
, SIG_IGN
);
505 tputs (SO
, 0, _putchar
);
507 putp(enter_standout_mode
);
508 #endif /* TERMINFO */
509 fprintf (stdout
, "Type any key to continue... ");
513 tputs (SE
, 0, _putchar
);
515 putp(exit_standout_mode
);
516 #endif /* TERMINFO */
519 SIGNAL (SIGTSTP
, TSTPser
);
525 switch (rc
->rc_type
) {
527 rc2peer (RC_ACK
, 0, NULL
);
532 adorn (NULL
, "%s", rc
->rc_data
);
534 adorn (NULL
, "pTTY peer error");
538 adios (NULL
, "%s", rc
->rc_data
);
541 adios (NULL
, "pTTY protocol screw-up");
553 if ((i
= pWINaux (w
)) == OK
&& did_less
)
567 register char c
, *bp
;
569 register struct record
*rc
= &rcs
;
581 switch (rc2rc (RC_ACK
, 0, NULL
, rc
)) {
583 if (eol
&& WINputc (w
, '\n') == ERR
&& WINless (w
, 0))
585 for (bp
= rc
->rc_data
, n
= rc
->rc_len
; n
-- > 0; ) {
586 if ((c
= *bp
++) == '\n')
588 if (WINputc (w
, c
) == ERR
)
589 if (n
== 0 && c
== '\n')
592 if (WINless (w
, 0)) {
594 fmt2peer (RC_ERR
, "flush window");
595 #ifdef XYZ /* should NEVER happen... */
606 rc2peer (RC_ACK
, 0, NULL
);
616 adorn (NULL
, "%s", rc
->rc_data
);
618 adorn (NULL
, "pWIN peer error");
622 adios (NULL
, "%s", rc
->rc_data
);
625 adios (NULL
, "pWIN protocol screw-up");
639 rc2peer (RC_FIN
, 0, NULL
);
642 switch (setjmp (PEERctx
)) {
644 SIGNAL (SIGALRM
, ALRMser
);
647 status
= pidwait (PEERpid
, OK
);
653 kill (PEERpid
, SIGKILL
);
667 register int nlines
, /* not "lines" because terminfo uses that */
672 if (initscr () == (WINDOW
*) ERR
)
676 adios (NULL
, "could not initialize terminal");
678 SIGNAL (SIGTSTP
, SIG_DFL
);
685 if (cursor_address
== NULL
) /* assume mtr wanted "cm", not "CM" */
686 #endif /* TERMINFO */
691 "sorry, your terminal isn't powerful enough to run %s",
695 if (tgetflag ("xt") || tgetnum ("sg") > 0)
696 SO
= SE
= US
= UE
= NULL
;
699 * If termcap mapped directly to terminfo, we'd use the following:
700 * if (teleray_glitch || magic_cookie_glitch > 0)
701 * enter_standout_mode = exit_standout_mode =
702 * enter_underline_mode = exit_underline_mode = NULL;
703 * But terminfo does the right thing so we don't have to resort to that.
705 #endif /* TERMINFO */
707 if ((nlines
= LINES
- 1) < 11)
708 adios (NULL
, "screen too small");
709 if ((top
= nlines
/ 3 + 1) > LINES
/ 4 + 2)
711 bottom
= nlines
- top
- 2;
714 Scan
= windows
[numwins
++] = newwin (top
, COLS
, 0, 0);
715 Status
= windows
[numwins
++] = newwin (1, COLS
, top
, 0);
719 Display
= windows
[numwins
++] = newwin (bottom
, COLS
, top
+ 1, 0);
720 Command
= newwin (1, COLS
- 1, top
+ 1 + bottom
, 0);
721 windows
[numwins
] = NULL
;
723 largemove
= Display
->_maxy
/ 2 + 2;
728 static int WINgetstr (WINDOW
*w
, char *buffer
)
737 switch (c
= toascii (wgetch (w
))) {
739 adios (NULL
, "wgetch lost");
749 leaveok (curscr
, FALSE
);
750 wmove (w
, 0, w
->_curx
- (bp
- buffer
));
752 leaveok (curscr
, TRUE
);
760 wprintw (w
, "Interrupt");
781 w
->_curx
-= bp
- buffer
;
791 } while (isspace (*bp
) && bp
> buffer
);
796 } while (!isspace (*bp
) && bp
> buffer
);
804 if (c
>= ' ' && c
< '\177')
805 waddch (w
, *bp
++ = c
);
815 WINwritev (WINDOW
*w
, struct iovec
*iov
, int n
)
821 for (i
= 0; i
< n
; i
++, iov
++)
822 wprintw (w
, "%*.*s", iov
->iov_len
, iov
->iov_len
, iov
->iov_base
);
835 " forward backwards", NULL
,
836 " ------- ---------", NULL
,
837 "next screen SPACE", NULL
,
838 "next %d line%s RETURN y", &smallmove
,
839 "next %d line%s EOT u", &largemove
,
842 "refresh CTRL-L", NULL
,
850 WINless (WINDOW
*w
, int fin
)
852 register int c
, i
, n
;
854 register struct line
*lbottom
;
874 if (nfresh
|| nwait
) {
886 lgo (ltail
->l_no
- w
->_maxy
+ 1);
891 ltop
= lbottom
&& lbottom
->l_prev
? lbottom
->l_prev
894 for (lbottom
= ltop
; lbottom
; lbottom
= lbottom
->l_next
)
895 if (waddstr (w
, lbottom
->l_buf
) == ERR
896 || waddch (w
, '\n') == ERR
)
901 if (nlatch
&& (ltail
->l_no
>= w
->_maxy
)) {
902 lgo (ltail
->l_no
- w
->_maxy
+ 1);
908 while (waddstr (w
, "~\n") != ERR
)
920 wmove (Command
, 0, 0);
923 wprintw (Command
, "%s", cp
);
928 wprintw (Command
, fin
? "top:%d bot:%d end:%d" : "top:%d bot:%d",
929 ltop
->l_no
, lbottom
->l_no
, ltail
->l_no
);
930 wprintw (Command
, ">> ");
934 c
= toascii (wgetch (Command
));
948 ltop
= lbottom
->l_next
;
958 if (ladvance (smallmove
))
966 if (lretreat (smallmove
))
974 if (ladvance (largemove
))
981 if (lretreat (largemove
))
991 if (lgo (n
? n
: ltail
->l_no
- w
->_maxy
+ 1))
1004 for (i
= 0; hlpmsg
[i
].h_msg
; i
++) {
1005 if (hlpmsg
[i
].h_val
)
1006 wprintw (w
, hlpmsg
[i
].h_msg
, *hlpmsg
[i
].h_val
,
1007 *hlpmsg
[i
].h_val
!= 1 ? "s" : "");
1009 waddstr (w
, hlpmsg
[i
].h_msg
);
1024 wmove (Command
, 0, 0);
1026 while (isdigit (c
)) {
1027 wprintw (Command
, "%c", c
);
1029 i
= i
* 10 + c
- '0';
1030 c
= toascii (wgetch (Command
));
1042 cp
= "not understood";
1050 WINputc (WINDOW
*w
, char c
)
1057 if (WINputc (w
, 'M') == ERR
|| WINputc (w
, '-') == ERR
)
1062 if (c
< ' ' || c
== '\177') {
1063 if (WINputc (w
, '^') == ERR
)
1075 return waddch (w
, c
);
1077 if ((x
= w
->_curx
) < 0 || x
>= w
->_maxx
1078 || (y
= w
->_cury
) < 0 || y
>= w
->_maxy
)
1083 for (x
= 8 - (x
& 0x07); x
> 0; x
--)
1084 if (WINputc (w
, ' ') == ERR
)
1109 register struct line
*lp
, *mp
;
1111 for (lp
= lhead
; lp
; lp
= mp
) {
1116 lhead
= ltop
= ltail
= NULL
;
1124 register struct line
*lp
;
1126 if ((lp
= (struct line
*) calloc ((size_t) 1, sizeof *lp
)) == NULL
)
1127 adios (NULL
, "unable to allocate line storage");
1129 lp
->l_no
= (ltail
? ltail
->l_no
: 0) + 1;
1131 lp
->l_buf
= getcpy (w
->_y
[w
->_cury
]);
1133 lp
->l_buf
= getcpy (w
->lines
[w
->_cury
]->line
);
1135 for (cp
= lp
->l_buf
+ strlen (lp
->l_buf
) - 1; cp
>= lp
->l_buf
; cp
--)
1156 register struct line
*lp
;
1158 for (i
= 0, lp
= ltop
; i
< n
&& lp
; i
++, lp
= lp
->l_next
)
1173 register struct line
*lp
;
1175 for (i
= 0, lp
= ltop
; i
< n
&& lp
; i
++, lp
= lp
->l_prev
)
1191 register struct line
*lp
;
1193 if ((i
= n
- (lp
= lhead
)->l_no
)
1194 > (j
= abs (n
- (ltop
? ltop
: ltail
)->l_no
)))
1195 i
= j
, lp
= ltop
? ltop
: ltail
;
1196 if (i
> (j
= abs (ltail
->l_no
- n
)))
1199 if (n
>= lp
->l_no
) {
1200 for (; lp
; lp
= lp
->l_next
)
1205 for (; lp
; lp
= lp
->l_prev
)
1224 if (!isatty (fileno (stdin
)) || !isatty (fileno (stdout
)))
1228 adios (NULL
, "not a tty");
1232 if (ioctl (fileno (stdin
), TIOCGETP
, (char *) &sg
) == NOTOK
)
1233 adios ("failed", "ioctl TIOCGETP");
1234 if (ioctl (fileno (stdin
), TIOCGETC
, (char *) &tc
) == NOTOK
)
1235 adios ("failed", "ioctl TIOCGETC");
1238 if( tcgetattr( fileno(stdin
), &sg
) == NOTOK
)
1239 adios( "failed", "tcgetattr");
1241 if (ioctl (fileno (stdin
), TCGETA
, &sg
) == NOTOK
)
1242 adios ("failed", "ioctl TCGETA");
1246 if (ioctl (fileno (stdin
), TIOCGLTC
, (char *) <c
) == NOTOK
)
1247 adios ("failed", "ioctl TIOCGLTC");
1248 #endif /* TIOCGLTC */
1254 SIGNAL (SIGPIPE
, PIPEser
);
1263 if (tty_ready
== DONE
)
1268 ioctl (fileno (stdin
), TIOCSETC
, (char *) &tc
);
1270 ioctl (fileno (stdin
), TCSETA
, &sg
);
1276 scrollok (curscr
, FALSE
);
1282 SIGNAL (SIGHUP
, SIGser
);
1283 SIGNAL (SIGINT
, SIGser
);
1284 SIGNAL (SIGQUIT
, SIGser
);
1286 SIGNAL (SIGTSTP
, TSTPser
);
1287 #endif /* SIGTSTP */
1294 if (tty_ready
== NOTOK
)
1299 ioctl (fileno (stdin
), TIOCSETC
, (char *) &tc
);
1301 ioctl (fileno (stdin
), TCSETA
, &sg
);
1304 leaveok (curscr
, TRUE
);
1305 mvcur (0, COLS
- 1, LINES
- 1, 0);
1307 if (tty_ready
== DONE
) {
1310 tputs (CE
, 0, _putchar
);
1312 #else /* TERMINFO */
1314 #endif /* TERMINFO */
1315 fprintf (stdout
, "\r\n");
1321 SIGNAL (SIGHUP
, SIG_DFL
);
1322 SIGNAL (SIGINT
, SIG_DFL
);
1323 SIGNAL (SIGQUIT
, SIG_DFL
);
1325 SIGNAL (SIGTSTP
, SIG_DFL
);
1326 #endif /* SIGTSTP */
1335 SIGNAL_HANDLER tstat
;
1337 if ((pgrp
= getpgrp()) == NOTOK
)
1338 adios ("process group", "unable to determine");
1340 if (ioctl (fileno (stdin
), TIOCGPGRP
, (char *) &tpgrp
) == NOTOK
)
1341 adios ("tty's process group", "unable to determine");
1345 tstat
= SIGNAL (SIGTTIN
, SIG_DFL
);
1347 SIGNAL (SIGTTIN
, tstat
);
1350 SIGNAL (SIGTTIN
, SIG_IGN
);
1351 SIGNAL (SIGTTOU
, SIG_IGN
);
1352 SIGNAL (SIGTSTP
, SIG_IGN
);
1353 #endif /* TIOCGPGRP */
1361 SIGNAL (SIGTTIN
, SIG_DFL
);
1362 SIGNAL (SIGTTOU
, SIG_DFL
);
1363 SIGNAL (SIGTSTP
, SIG_DFL
);
1364 #endif /* TIOCGPGRP */
1373 longjmp (PEERctx
, DONE
);
1384 #ifndef RELIABLE_SIGNALS
1385 SIGNAL (sig
, SIG_IGN
);
1388 adios (NULL
, "lost peer");
1395 #ifndef RELIABLE_SIGNALS
1396 SIGNAL (sig
, SIG_IGN
);
1408 tputs (tgoto (CM
, 0, LINES
- 1), 0, _putchar
);
1409 #else /* TERMINFO */
1410 move(LINES
- 1, 0); /* to lower left corner */
1411 clrtoeol(); /* clear bottom line */
1412 wrefresh(curscr
); /* flush out everything */
1413 #endif /* TERMINFO */
1418 sigsetmask (sigblock (0) & ~sigmask (SIGTSTP
));
1421 kill (getpid (), sig
);
1424 sigblock (sigmask (SIGTSTP
));
1430 #endif /* SIGTSTP */
1442 return 1; /* dead code to satisfy the compiler */
1447 adorn (char *what
, char *fmt
, ...)
1456 advertise (what
, NULL
, fmt
, ap
);
1464 advertise (char *what
, char *tail
, char *fmt
, va_list ap
)
1467 char buffer
[BUFSIZ
], err
[BUFSIZ
];
1468 struct iovec iob
[20];
1469 register struct iovec
*iov
= iob
;
1475 iov
->iov_len
= strlen (iov
->iov_base
= invo_name
);
1477 iov
->iov_len
= strlen (iov
->iov_base
= ": ");
1481 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
1482 iov
->iov_len
= strlen (iov
->iov_base
= buffer
);
1486 iov
->iov_len
= strlen (iov
->iov_base
= " ");
1488 iov
->iov_len
= strlen (iov
->iov_base
= what
);
1490 iov
->iov_len
= strlen (iov
->iov_base
= ": ");
1493 if (!(iov
->iov_base
= strerror (eindex
))) {
1494 snprintf (err
, sizeof(err
), "Error %d", eindex
);
1495 iov
->iov_base
= err
;
1497 iov
->iov_len
= strlen (iov
->iov_base
);
1500 if (tail
&& *tail
) {
1501 iov
->iov_len
= strlen (iov
->iov_base
= ", ");
1503 iov
->iov_len
= strlen (iov
->iov_base
= tail
);
1506 iov
->iov_len
= strlen (iov
->iov_base
= "\n");
1509 if (tty_ready
== DONE
)
1510 WINwritev (Display
, iob
, iov
- iob
);
1512 writev (fileno (stderr
), iob
, iov
- iob
);