]>
diplodocus.org Git - nmh/blob - uip/vmh.c
3 * vmh.c -- visual front-end to nmh
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
13 #include <h/signals.h>
16 #if defined(SYS5) && !defined(TERMINFO)
18 * Define TERMINFO if you have it.
19 * You get it automatically if you're running SYS5, and you don't get
20 * it if you're not. (If you're not SYS5, you probably have termcap.)
21 * We distinguish TERMINFO from SYS5 because in this file SYS5 really
22 * means "AT&T line discipline" (termio, not sgttyb), whereas terminfo
23 * is quite a separate issue.
31 * 1) Pass signals to client during execution
32 * 2) Figure out a way for the user to say how big the Scan/Display
34 * 3) If curses ever gets fixed, then XYZ code can be removed
40 # define _SYS_REG_H /* NCR redefines "ERR" in <sys/reg.h> */
43 #undef OK /* tricky */
45 /* removed for right now */
48 # include <term.h> /* variables describing terminal capabilities */
58 # define sigmask(s) (1 << ((s) - 1))
59 #endif /* not sigmask */
76 # define TCGETATTR /* tcgetattr() */
81 # define _maxx maxx /* curses.h */
83 # define _curx curx /* curses.h */
85 void __cputchar
__P((int));
87 # define _putchar __cputchar
88 # include <sys/ioctl.h> /* sgttyb */
91 #define ALARM ((unsigned int) 10)
92 #define PAUSE ((unsigned int) 2)
95 # define abs(a) ((a) > 0 ? (a) : -(a))
101 #define XYZ /* XXX */
103 static struct swit switches
[] = {
105 { "prompt string", 6 },
107 { "vmhproc program", 7 },
118 static int PEERpid
= NOTOK
;
120 static jmp_buf PEERctx
;
123 static char *myprompt
= "(%s) ";
126 static WINDOW
*Status
;
127 static WINDOW
*Display
;
128 static WINDOW
*Command
;
132 WINDOW
*windows
[NWIN
+ 1];
144 static struct line
*lhead
= NULL
;
145 static struct line
*ltop
= NULL
;
146 static struct line
*ltail
= NULL
;
148 static int did_less
= 0;
149 static int smallmove
= SMALLMOVE
;
150 static int largemove
= LARGEMOVE
;
155 static int tty_ready
= NOTOK
;
160 # define ERASE sg.sg_erase
161 # define KILL sg.sg_kill
162 static struct sgttyb sg
;
164 #define EOFC tc.t_eofc
165 #define INTR tc.t_intrc
166 static struct tchars tc
;
168 # define ERASE sg.c_cc[VERASE]
169 # define KILL sg.c_cc[VKILL]
170 # define EOFC sg.c_cc[VEOF]
171 # define INTR sg.c_cc[VINTR]
172 static struct termio sg
;
176 # define WERASC ('W' & 037)
179 # define WERASC ltc.t_werasc
180 static struct ltchars ltc
;
182 # define WERASC sg.c_cc[VWERASE]
183 # undef TIOCGLTC /* the define exists, but struct ltchars doesn't */
185 #endif /* TIOCGLTC */
188 #if !defined(SYS5) && !defined(BSD44)
190 #endif /* not SYS5 */
197 static RETSIGTYPE
ALRMser(int);
198 static RETSIGTYPE
PIPEser(int);
199 static RETSIGTYPE
SIGser(int);
201 static RETSIGTYPE
TSTPser(int);
210 static void adorn (char *, char *, ...);
212 static vmh(), lreset(), linsert(), ladvance(), lretreat(), lgo();
213 static TTYon(), TTYoff(), foreground();
214 static int PEERinit(), pINI(), pLOOP(), pTTY(), pWIN(), WINinit();
215 static int WINgetstr(), WINless(), WINputc(), TTYinit(), pWINaux();
219 main (int argc
, char **argv
)
221 int vecp
= 1, nprog
= 0;
222 char *cp
, buffer
[BUFSIZ
];
223 char **argp
, **arguments
, *vec
[MAXARGS
];
226 setlocale(LC_ALL
, "");
228 invo_name
= r1bindex (argv
[0], '/');
230 /* read user profile/context */
233 arguments
= getarguments (invo_name
, argc
, argv
, 1);
236 while ((cp
= *argp
++))
238 switch (smatch (++cp
, switches
)) {
240 ambigsw (cp
, switches
);
247 snprintf (buffer
, sizeof(buffer
), "%s [switches for vmhproc]",
249 print_help (buffer
, switches
, 1);
252 print_version(invo_name
);
256 if (!(myprompt
= *argp
++) || *myprompt
== '-')
257 adios (NULL
, "missing argument to %s", argp
[-2]);
261 if (!(vmhproc
= *argp
++) || *vmhproc
== '-')
262 adios (NULL
, "missing argument to %s", argp
[-2]);
271 if (TTYinit (nprog
) == NOTOK
|| WINinit (nprog
) == NOTOK
) {
274 vec
[0] = r1bindex (vmhproc
, '/');
275 execvp (vmhproc
, vec
);
276 adios (vmhproc
, "unable to exec");
279 PEERinit (vecp
, vec
);
294 pLOOP (RC_QRY
, NULL
);
296 wmove (Command
, 0, 0);
297 wprintw (Command
, myprompt
, invo_name
);
301 switch (WINgetstr (Command
, buffer
)) {
306 done (0); /* NOTREACHED */
310 pLOOP (RC_CMD
, buffer
);
319 PEERinit (int vecp
, char *vec
[])
321 int pfd0
[2], pfd1
[2];
322 char buf1
[BUFSIZ
], buf2
[BUFSIZ
];
324 if (pipe (pfd0
) == NOTOK
|| pipe (pfd1
) == NOTOK
)
325 adios ("pipe", "unable to");
327 switch (PEERpid
= fork ()) {
329 * Calling vfork() and then another routine [like close()] before
330 * an exec() messes up the stack frame, causing crib death.
331 * Use fork() instead.
334 switch (PEERpid
= vfork ()) {
335 #endif /* not hpux */
337 adios ("vfork", "unable to");/* NOTREACHED */
343 vec
[vecp
++] = "-vmhread";
344 snprintf (buf1
, sizeof(buf1
), "%d", pfd1
[0]);
346 vec
[vecp
++] = "-vmhwrite";
347 snprintf (buf2
, sizeof(buf2
), "%d", pfd0
[1]);
351 SIGNAL (SIGINT
, SIG_DFL
);
352 SIGNAL (SIGQUIT
, SIG_DFL
);
354 vec
[0] = r1bindex (vmhproc
, '/');
355 execvp (vmhproc
, vec
);
357 _exit (-1); /* NOTREACHED */
363 rcinit (pfd0
[0], pfd1
[1]);
373 char *bp
, buffer
[BUFSIZ
];
375 register struct record
*rc
= &rcs
;
380 /* Get buffer ready to go */
382 buflen
= sizeof(buffer
);
384 snprintf (bp
, buflen
, "%d %d", RC_VRSN
, numwins
);
389 for (w
= windows
; *w
; w
++) {
390 snprintf (bp
, buflen
, " %d", (*w
)->_maxy
);
396 switch (str2rc (RC_INI
, buffer
, rc
)) {
402 adios (NULL
, "%s", rc
->rc_data
);
404 adios (NULL
, "pINI peer error");
407 adios (NULL
, "%s", rc
->rc_data
);
410 adios (NULL
, "pINI protocol screw-up");
417 pLOOP (char *code
, char *str
)
421 register struct record
*rc
= &rcs
;
425 str2peer (code
, str
);
427 switch (peer2rc (rc
)) {
429 if (pTTY (rc
) == NOTOK
)
434 if (sscanf (rc
->rc_data
, "%d", &i
) != 1
437 fmt2peer (RC_ERR
, "no such window \"%s\"", rc
->rc_data
);
440 if (pWIN (windows
[i
- 1]) == NOTOK
)
449 adorn (NULL
, "%s", rc
->rc_data
);
451 adorn (NULL
, "pLOOP(%s) peer error",
452 code
== RC_QRY
? "QRY" : "CMD");
457 adorn (NULL
, "%s", rc
->rc_data
);
459 i
= pidwait (PEERpid
, OK
);
464 adios (NULL
, "%s", rc
->rc_data
);
467 adios (NULL
, "pLOOP(%s) protocol screw-up",
468 code
== RC_QRY
? "QRY" : "CMD");
474 pTTY (struct record
*r
)
476 SIGNAL_HANDLER hstat
, istat
, qstat
, tstat
;
478 register struct record
*rc
= &rcs
;
484 /* should be changed to block instead of ignore */
485 hstat
= SIGNAL (SIGHUP
, SIG_IGN
);
486 istat
= SIGNAL (SIGINT
, SIG_IGN
);
487 qstat
= SIGNAL (SIGQUIT
, SIG_IGN
);
488 tstat
= SIGNAL (SIGTERM
, SIG_IGN
);
490 rc2rc (RC_ACK
, 0, NULL
, rc
);
492 SIGNAL (SIGHUP
, hstat
);
493 SIGNAL (SIGINT
, istat
);
494 SIGNAL (SIGQUIT
, qstat
);
495 SIGNAL (SIGTERM
, tstat
);
499 if (r
->rc_len
&& strcmp (r
->rc_data
, "FAST") == 0)
503 SIGNAL (SIGTSTP
, SIG_IGN
);
508 tputs (SO
, 0, _putchar
);
510 putp(enter_standout_mode
);
511 #endif /* TERMINFO */
512 fprintf (stdout
, "Type any key to continue... ");
516 tputs (SE
, 0, _putchar
);
518 putp(exit_standout_mode
);
519 #endif /* TERMINFO */
522 SIGNAL (SIGTSTP
, TSTPser
);
528 switch (rc
->rc_type
) {
530 rc2peer (RC_ACK
, 0, NULL
);
535 adorn (NULL
, "%s", rc
->rc_data
);
537 adorn (NULL
, "pTTY peer error");
541 adios (NULL
, "%s", rc
->rc_data
);
544 adios (NULL
, "pTTY protocol screw-up");
556 if ((i
= pWINaux (w
)) == OK
&& did_less
)
570 register char c
, *bp
;
572 register struct record
*rc
= &rcs
;
584 switch (rc2rc (RC_ACK
, 0, NULL
, rc
)) {
586 if (eol
&& WINputc (w
, '\n') == ERR
&& WINless (w
, 0))
588 for (bp
= rc
->rc_data
, n
= rc
->rc_len
; n
-- > 0; ) {
589 if ((c
= *bp
++) == '\n')
591 if (WINputc (w
, c
) == ERR
)
592 if (n
== 0 && c
== '\n')
595 if (WINless (w
, 0)) {
597 fmt2peer (RC_ERR
, "flush window");
598 #ifdef XYZ /* should NEVER happen... */
609 rc2peer (RC_ACK
, 0, NULL
);
619 adorn (NULL
, "%s", rc
->rc_data
);
621 adorn (NULL
, "pWIN peer error");
625 adios (NULL
, "%s", rc
->rc_data
);
628 adios (NULL
, "pWIN protocol screw-up");
642 rc2peer (RC_FIN
, 0, NULL
);
645 switch (setjmp (PEERctx
)) {
647 SIGNAL (SIGALRM
, ALRMser
);
650 status
= pidwait (PEERpid
, OK
);
656 kill (PEERpid
, SIGKILL
);
670 register int nlines
, /* not "lines" because terminfo uses that */
675 if (initscr () == (WINDOW
*) ERR
)
679 adios (NULL
, "could not initialize terminal");
681 SIGNAL (SIGTSTP
, SIG_DFL
);
688 if (cursor_address
== NULL
) /* assume mtr wanted "cm", not "CM" */
689 #endif /* TERMINFO */
694 "sorry, your terminal isn't powerful enough to run %s",
698 if (tgetflag ("xt") || tgetnum ("sg") > 0)
699 SO
= SE
= US
= UE
= NULL
;
702 * If termcap mapped directly to terminfo, we'd use the following:
703 * if (teleray_glitch || magic_cookie_glitch > 0)
704 * enter_standout_mode = exit_standout_mode =
705 * enter_underline_mode = exit_underline_mode = NULL;
706 * But terminfo does the right thing so we don't have to resort to that.
708 #endif /* TERMINFO */
710 if ((nlines
= LINES
- 1) < 11)
711 adios (NULL
, "screen too small");
712 if ((top
= nlines
/ 3 + 1) > LINES
/ 4 + 2)
714 bottom
= nlines
- top
- 2;
717 Scan
= windows
[numwins
++] = newwin (top
, COLS
, 0, 0);
718 Status
= windows
[numwins
++] = newwin (1, COLS
, top
, 0);
722 Display
= windows
[numwins
++] = newwin (bottom
, COLS
, top
+ 1, 0);
723 Command
= newwin (1, COLS
- 1, top
+ 1 + bottom
, 0);
724 windows
[numwins
] = NULL
;
726 largemove
= Display
->_maxy
/ 2 + 2;
731 static int WINgetstr (WINDOW
*w
, char *buffer
)
740 switch (c
= toascii (wgetch (w
))) {
742 adios (NULL
, "wgetch lost");
752 leaveok (curscr
, FALSE
);
753 wmove (w
, 0, w
->_curx
- (bp
- buffer
));
755 leaveok (curscr
, TRUE
);
763 wprintw (w
, "Interrupt");
784 w
->_curx
-= bp
- buffer
;
794 } while (isspace (*bp
) && bp
> buffer
);
799 } while (!isspace (*bp
) && bp
> buffer
);
807 if (c
>= ' ' && c
< '\177')
808 waddch (w
, *bp
++ = c
);
818 WINwritev (WINDOW
*w
, struct iovec
*iov
, int n
)
824 for (i
= 0; i
< n
; i
++, iov
++)
825 wprintw (w
, "%*.*s", iov
->iov_len
, iov
->iov_len
, iov
->iov_base
);
838 " forward backwards", NULL
,
839 " ------- ---------", NULL
,
840 "next screen SPACE", NULL
,
841 "next %d line%s RETURN y", &smallmove
,
842 "next %d line%s EOT u", &largemove
,
845 "refresh CTRL-L", NULL
,
853 WINless (WINDOW
*w
, int fin
)
855 register int c
, i
, n
;
857 register struct line
*lbottom
;
877 if (nfresh
|| nwait
) {
889 lgo (ltail
->l_no
- w
->_maxy
+ 1);
894 ltop
= lbottom
&& lbottom
->l_prev
? lbottom
->l_prev
897 for (lbottom
= ltop
; lbottom
; lbottom
= lbottom
->l_next
)
898 if (waddstr (w
, lbottom
->l_buf
) == ERR
899 || waddch (w
, '\n') == ERR
)
904 if (nlatch
&& (ltail
->l_no
>= w
->_maxy
)) {
905 lgo (ltail
->l_no
- w
->_maxy
+ 1);
911 while (waddstr (w
, "~\n") != ERR
)
923 wmove (Command
, 0, 0);
926 wprintw (Command
, "%s", cp
);
931 wprintw (Command
, fin
? "top:%d bot:%d end:%d" : "top:%d bot:%d",
932 ltop
->l_no
, lbottom
->l_no
, ltail
->l_no
);
933 wprintw (Command
, ">> ");
937 c
= toascii (wgetch (Command
));
951 ltop
= lbottom
->l_next
;
961 if (ladvance (smallmove
))
969 if (lretreat (smallmove
))
977 if (ladvance (largemove
))
984 if (lretreat (largemove
))
994 if (lgo (n
? n
: ltail
->l_no
- w
->_maxy
+ 1))
1007 for (i
= 0; hlpmsg
[i
].h_msg
; i
++) {
1008 if (hlpmsg
[i
].h_val
)
1009 wprintw (w
, hlpmsg
[i
].h_msg
, *hlpmsg
[i
].h_val
,
1010 *hlpmsg
[i
].h_val
!= 1 ? "s" : "");
1012 waddstr (w
, hlpmsg
[i
].h_msg
);
1027 wmove (Command
, 0, 0);
1029 while (isdigit (c
)) {
1030 wprintw (Command
, "%c", c
);
1032 i
= i
* 10 + c
- '0';
1033 c
= toascii (wgetch (Command
));
1045 cp
= "not understood";
1053 WINputc (WINDOW
*w
, char c
)
1060 if (WINputc (w
, 'M') == ERR
|| WINputc (w
, '-') == ERR
)
1065 if (c
< ' ' || c
== '\177') {
1066 if (WINputc (w
, '^') == ERR
)
1078 return waddch (w
, c
);
1080 if ((x
= w
->_curx
) < 0 || x
>= w
->_maxx
1081 || (y
= w
->_cury
) < 0 || y
>= w
->_maxy
)
1086 for (x
= 8 - (x
& 0x07); x
> 0; x
--)
1087 if (WINputc (w
, ' ') == ERR
)
1112 register struct line
*lp
, *mp
;
1114 for (lp
= lhead
; lp
; lp
= mp
) {
1119 lhead
= ltop
= ltail
= NULL
;
1127 register struct line
*lp
;
1129 if ((lp
= (struct line
*) calloc ((size_t) 1, sizeof *lp
)) == NULL
)
1130 adios (NULL
, "unable to allocate line storage");
1132 lp
->l_no
= (ltail
? ltail
->l_no
: 0) + 1;
1134 lp
->l_buf
= getcpy (w
->_y
[w
->_cury
]);
1136 lp
->l_buf
= getcpy (w
->lines
[w
->_cury
]->line
);
1138 for (cp
= lp
->l_buf
+ strlen (lp
->l_buf
) - 1; cp
>= lp
->l_buf
; cp
--)
1159 register struct line
*lp
;
1161 for (i
= 0, lp
= ltop
; i
< n
&& lp
; i
++, lp
= lp
->l_next
)
1176 register struct line
*lp
;
1178 for (i
= 0, lp
= ltop
; i
< n
&& lp
; i
++, lp
= lp
->l_prev
)
1194 register struct line
*lp
;
1196 if ((i
= n
- (lp
= lhead
)->l_no
)
1197 > (j
= abs (n
- (ltop
? ltop
: ltail
)->l_no
)))
1198 i
= j
, lp
= ltop
? ltop
: ltail
;
1199 if (i
> (j
= abs (ltail
->l_no
- n
)))
1202 if (n
>= lp
->l_no
) {
1203 for (; lp
; lp
= lp
->l_next
)
1208 for (; lp
; lp
= lp
->l_prev
)
1227 if (!isatty (fileno (stdin
)) || !isatty (fileno (stdout
)))
1231 adios (NULL
, "not a tty");
1235 if (ioctl (fileno (stdin
), TIOCGETP
, (char *) &sg
) == NOTOK
)
1236 adios ("failed", "ioctl TIOCGETP");
1237 if (ioctl (fileno (stdin
), TIOCGETC
, (char *) &tc
) == NOTOK
)
1238 adios ("failed", "ioctl TIOCGETC");
1241 if( tcgetattr( fileno(stdin
), &sg
) == NOTOK
)
1242 adios( "failed", "tcgetattr");
1244 if (ioctl (fileno (stdin
), TCGETA
, &sg
) == NOTOK
)
1245 adios ("failed", "ioctl TCGETA");
1249 if (ioctl (fileno (stdin
), TIOCGLTC
, (char *) <c
) == NOTOK
)
1250 adios ("failed", "ioctl TIOCGLTC");
1251 #endif /* TIOCGLTC */
1257 SIGNAL (SIGPIPE
, PIPEser
);
1266 if (tty_ready
== DONE
)
1271 ioctl (fileno (stdin
), TIOCSETC
, (char *) &tc
);
1273 ioctl (fileno (stdin
), TCSETA
, &sg
);
1279 scrollok (curscr
, FALSE
);
1285 SIGNAL (SIGHUP
, SIGser
);
1286 SIGNAL (SIGINT
, SIGser
);
1287 SIGNAL (SIGQUIT
, SIGser
);
1289 SIGNAL (SIGTSTP
, TSTPser
);
1290 #endif /* SIGTSTP */
1297 if (tty_ready
== NOTOK
)
1302 ioctl (fileno (stdin
), TIOCSETC
, (char *) &tc
);
1304 ioctl (fileno (stdin
), TCSETA
, &sg
);
1307 leaveok (curscr
, TRUE
);
1308 mvcur (0, COLS
- 1, LINES
- 1, 0);
1310 if (tty_ready
== DONE
) {
1313 tputs (CE
, 0, _putchar
);
1315 #else /* TERMINFO */
1317 #endif /* TERMINFO */
1318 fprintf (stdout
, "\r\n");
1324 SIGNAL (SIGHUP
, SIG_DFL
);
1325 SIGNAL (SIGINT
, SIG_DFL
);
1326 SIGNAL (SIGQUIT
, SIG_DFL
);
1328 SIGNAL (SIGTSTP
, SIG_DFL
);
1329 #endif /* SIGTSTP */
1338 SIGNAL_HANDLER tstat
;
1340 if ((pgrp
= getpgrp()) == NOTOK
)
1341 adios ("process group", "unable to determine");
1343 if (ioctl (fileno (stdin
), TIOCGPGRP
, (char *) &tpgrp
) == NOTOK
)
1344 adios ("tty's process group", "unable to determine");
1348 tstat
= SIGNAL (SIGTTIN
, SIG_DFL
);
1350 SIGNAL (SIGTTIN
, tstat
);
1353 SIGNAL (SIGTTIN
, SIG_IGN
);
1354 SIGNAL (SIGTTOU
, SIG_IGN
);
1355 SIGNAL (SIGTSTP
, SIG_IGN
);
1356 #endif /* TIOCGPGRP */
1364 SIGNAL (SIGTTIN
, SIG_DFL
);
1365 SIGNAL (SIGTTOU
, SIG_DFL
);
1366 SIGNAL (SIGTSTP
, SIG_DFL
);
1367 #endif /* TIOCGPGRP */
1376 longjmp (PEERctx
, DONE
);
1387 #ifndef RELIABLE_SIGNALS
1388 SIGNAL (sig
, SIG_IGN
);
1391 adios (NULL
, "lost peer");
1398 #ifndef RELIABLE_SIGNALS
1399 SIGNAL (sig
, SIG_IGN
);
1411 tputs (tgoto (CM
, 0, LINES
- 1), 0, _putchar
);
1412 #else /* TERMINFO */
1413 move(LINES
- 1, 0); /* to lower left corner */
1414 clrtoeol(); /* clear bottom line */
1415 wrefresh(curscr
); /* flush out everything */
1416 #endif /* TERMINFO */
1421 sigsetmask (sigblock (0) & ~sigmask (SIGTSTP
));
1424 kill (getpid (), sig
);
1427 sigblock (sigmask (SIGTSTP
));
1433 #endif /* SIGTSTP */
1445 return 1; /* dead code to satisfy the compiler */
1450 adorn (char *what
, char *fmt
, ...)
1459 advertise (what
, NULL
, fmt
, ap
);
1467 advertise (char *what
, char *tail
, char *fmt
, va_list ap
)
1470 char buffer
[BUFSIZ
], err
[BUFSIZ
];
1471 struct iovec iob
[20];
1472 register struct iovec
*iov
= iob
;
1478 iov
->iov_len
= strlen (iov
->iov_base
= invo_name
);
1480 iov
->iov_len
= strlen (iov
->iov_base
= ": ");
1484 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
1485 iov
->iov_len
= strlen (iov
->iov_base
= buffer
);
1489 iov
->iov_len
= strlen (iov
->iov_base
= " ");
1491 iov
->iov_len
= strlen (iov
->iov_base
= what
);
1493 iov
->iov_len
= strlen (iov
->iov_base
= ": ");
1496 if (!(iov
->iov_base
= strerror (eindex
))) {
1497 snprintf (err
, sizeof(err
), "Error %d", eindex
);
1498 iov
->iov_base
= err
;
1500 iov
->iov_len
= strlen (iov
->iov_base
);
1503 if (tail
&& *tail
) {
1504 iov
->iov_len
= strlen (iov
->iov_base
= ", ");
1506 iov
->iov_len
= strlen (iov
->iov_base
= tail
);
1509 iov
->iov_len
= strlen (iov
->iov_base
= "\n");
1512 if (tty_ready
== DONE
)
1513 WINwritev (Display
, iob
, iov
- iob
);
1515 writev (fileno (stderr
), iob
, iov
- iob
);