]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/vmh.c
sbr/mts.c: Delete mmdlm2; use same-valued mmdlm1 instead.
[nmh] / docs / historical / mh-6.8.5 / uip / vmh.c
1 /* vmh.c - visual front-end to mh */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: vmh.c,v 1.20 1993/08/25 17:29:44 jromine Exp $";
4 #endif /* lint */
5 #if defined(SYS5) && !defined(TERMINFO)
6 /*
7 * Define TERMINFO if you have it.
8 * You get it automatically if you're running SYS5, and you don't get
9 * it if you're not. (If you're not SYS5, you probably have termcap.)
10 * We distinguish TERMINFO from SYS5 because in this file SYS5 really
11 * means "AT&T line discipline" (termio, not sgttyb), whereas terminfo
12 * is quite a separate issue.
13 */
14 #define TERMINFO 1
15 #endif
16
17 /* TODO:
18 Pass signals to client during execution
19
20 Figure out a way for the user to say how big the Scan/Display
21 windows should be.
22
23 If curses ever gets fixed, then XYZ code can be removed
24 */
25
26 #include <curses.h>
27 #ifdef ncr
28 #define _SYS_REG_H /* NCR redefines "ERR" in <sys/reg.h> */
29 #endif
30 #undef OK /* tricky */
31 #ifdef TERMINFO
32 #include <term.h> /* variables describing terminal capabilities */
33 #endif /* TERMINFO */
34 #include "../h/mh.h"
35 #include "../h/vmhsbr.h"
36 #include <ctype.h>
37 #include <errno.h>
38 #include <setjmp.h>
39 #include <signal.h>
40 #ifndef sigmask
41 #define sigmask(s) (1 << ((s) - 1))
42 #endif /* not sigmask */
43 #ifdef ridge
44 #undef SIGTSTP
45 #endif /* ridge */
46 #ifndef BSD42
47 struct iovec {
48 char *iov_base;
49 int iov_len;
50 };
51 #else /* BSD42 */
52 #include <sys/types.h>
53 #include <sys/uio.h>
54 #endif /* BSD42 */
55 #ifdef LOCALE
56 #include <locale.h>
57 #endif
58 #ifdef hpux
59 #include <termio.h>
60 #define TCGETATTR /* tcgetattr() */
61 #endif
62 #ifdef BSD44
63 #define USE_OLD_TTY
64 #define _maxx maxx /* curses.h */
65 #define _maxy maxy
66 #define _curx curx /* curses.h */
67 #define _cury cury
68 void __cputchar __P((int));
69 #undef _putchar
70 #define _putchar __cputchar
71 #include <sys/ioctl.h> /* sgttyb */
72 #endif
73
74 #define ALARM ((unsigned int) 10)
75 #define PAUSE ((unsigned int) 2)
76
77 #ifndef abs
78 #define abs(a) ((a) > 0 ? (a) : -(a))
79 #endif
80 #define SMALLMOVE 1
81 #define LARGEMOVE 10
82
83
84 #define XYZ /* XXX */
85
86 /* \f */
87
88 static struct swit switches[] = {
89 #define PRMPTSW 0
90 "prompt string", 6,
91
92 #define PROGSW 1
93 "vmhproc program", 7,
94 #define NPROGSW 2
95 "novmhproc", 9,
96
97 #define HELPSW 3
98 "help", 4,
99
100 NULL, 0
101 };
102
103 /* \f */
104 /* PEERS */
105 static int PEERpid = NOTOK;
106
107 static jmp_buf PEERctx;
108
109
110 /* WINDOWS */
111 static char *myprompt = "(%s) ";
112
113 static WINDOW *Scan;
114 static WINDOW *Status;
115 static WINDOW *Display;
116 static WINDOW *Command;
117
118 #define NWIN 3
119 static int numwins;
120 WINDOW *windows[NWIN + 1];
121
122
123 /* LINES */
124
125 struct line {
126 int l_no;
127 char *l_buf;
128 struct line *l_prev;
129 struct line *l_next;
130 };
131
132 static struct line *lhead = NULL;
133 static struct line *ltop = NULL;
134 static struct line *ltail = NULL;
135
136 static int did_less = 0;
137 static int smallmove = SMALLMOVE;
138 static int largemove = LARGEMOVE;
139
140
141 /* TTYS */
142
143 static int tty_ready = NOTOK;
144
145 static int intrc;
146 #ifndef SYS5
147 #define ERASE sg.sg_erase
148 #define KILL sg.sg_kill
149 static struct sgttyb sg;
150
151 #define EOFC tc.t_eofc
152 #define INTR tc.t_intrc
153 static struct tchars tc;
154 #else /* SYS5 */
155 #define ERASE sg.c_cc[VERASE]
156 #define KILL sg.c_cc[VKILL]
157 #define EOFC sg.c_cc[VEOF]
158 #define INTR sg.c_cc[VINTR]
159 static struct termio sg;
160 #endif /* SYS5 */
161
162 #ifndef TIOCGLTC
163 #define WERASC ('W' & 037)
164 #else /* TIOCGLTC */
165 #ifndef SVR4
166 #define WERASC ltc.t_werasc
167 static struct ltchars ltc;
168 #else /* SVR4 */
169 #define WERASC sg.c_cc[VWERASE]
170 #undef TIOCGLTC /* the define exists, but struct ltchars doesn't */
171 #endif
172 #endif /* TIOCGLTC */
173
174
175 #if !defined(SYS5) && !defined(BSD44)
176 int _putchar ();
177 #endif /* not SYS5 */
178 #ifdef SIGTSTP
179 char *tgoto ();
180 #endif /* SIGTSTP */
181
182
183 /* SIGNALS */
184 static TYPESIG ALRMser (), PIPEser (), SIGser ();
185 #ifdef SIGTSTP
186 static TYPESIG TSTPser ();
187 #endif /* SIGTSTP */
188
189
190 /* MISCELLANY */
191 extern int errno;
192 #ifndef BSD44
193 extern int sys_nerr;
194 extern char *sys_errlist[];
195 #endif
196
197 static void adorn ();
198
199 static vmh(), lreset(), linsert(), ladvance(), lretreat(), lgo();
200 static TTYon(), TTYoff(), foreground();
201 static int PEERinit(), pINI(), pLOOP(), pTTY(), pWIN(), WINinit();
202 static int WINgetstr(), WINless(), WINputc(), TTYinit(), pWINaux();
203 /* \f */
204
205 /* ARGSUSED */
206
207 main (argc, argv)
208 int argc;
209 char *argv[];
210 {
211 int vecp = 1,
212 nprog = 0;
213 char *cp,
214 buffer[BUFSIZ],
215 **ap,
216 **argp,
217 *arguments[MAXARGS],
218 *vec[MAXARGS];
219
220 #ifdef LOCALE
221 setlocale(LC_ALL, "");
222 #endif
223 invo_name = r1bindex (argv[0], '/');
224 if ((cp = m_find (invo_name)) != NULL) {
225 ap = brkstring (cp = getcpy (cp), " ", "\n");
226 ap = copyip (ap, arguments);
227 }
228 else
229 ap = arguments;
230 (void) copyip (argv + 1, ap);
231 argp = arguments;
232
233 /* \f */
234
235 while (cp = *argp++)
236 if (*cp == '-')
237 switch (smatch (++cp, switches)) {
238 case AMBIGSW:
239 ambigsw (cp, switches);
240 done (1);
241 case UNKWNSW:
242 vec[vecp++] = --cp;
243 continue;
244 case HELPSW:
245 (void) sprintf (buffer, "%s [switches for vmhproc]",
246 invo_name);
247 help (buffer, switches);
248 done (1);
249
250 case PRMPTSW:
251 if (!(myprompt = *argp++) || *myprompt == '-')
252 adios (NULLCP, "missing argument to %s", argp[-2]);
253 continue;
254
255 case PROGSW:
256 if (!(vmhproc = *argp++) || *vmhproc == '-')
257 adios (NULLCP, "missing argument to %s", argp[-2]);
258 continue;
259 case NPROGSW:
260 nprog++;
261 continue;
262 }
263 else
264 vec[vecp++] = cp;
265
266 /* \f */
267
268 if (TTYinit (nprog) == NOTOK || WINinit (nprog) == NOTOK) {
269 vec[vecp] = NULL;
270
271 vec[0] = r1bindex (vmhproc, '/');
272 execvp (vmhproc, vec);
273 adios (vmhproc, "unable to exec");
274 }
275 TTYoff ();
276 (void) PEERinit (vecp, vec);
277 TTYon ();
278
279 vmh ();
280
281 done (0);
282 }
283
284 /* \f */
285
286 static vmh () {
287 char buffer[BUFSIZ];
288
289 for (;;) {
290 (void) pLOOP (RC_QRY, NULLCP);
291
292 wmove (Command, 0, 0);
293 wprintw (Command, myprompt, invo_name);
294 wclrtoeol (Command);
295 wrefresh (Command);
296
297 switch (WINgetstr (Command, buffer)) {
298 case NOTOK:
299 break;
300
301 case OK:
302 done (0); /* NOTREACHED */
303
304 default:
305 if (*buffer)
306 (void) pLOOP (RC_CMD, buffer);
307 break;
308 }
309 }
310 }
311
312 /* \f PEERS */
313
314 static int PEERinit (vecp, vec)
315 int vecp;
316 char *vec[];
317 {
318 int pfd0[2],
319 pfd1[2];
320 char buf1[BUFSIZ],
321 buf2[BUFSIZ];
322
323 if (pipe (pfd0) == NOTOK || pipe (pfd1) == NOTOK)
324 adios ("pipe", "unable to");
325 #ifdef hpux
326 switch (PEERpid = fork ()) {
327 /*
328 * Calling vfork() and then another routine [like close()] before
329 * an exec() messes up the stack frame, causing crib death.
330 * Use fork() instead.
331 */
332 #else /* not hpux */
333 switch (PEERpid = vfork ()) {
334 #endif /* not hpux */
335 case NOTOK:
336 adios ("vfork", "unable to");/* NOTREACHED */
337
338 case OK:
339 (void) close (pfd0[0]);
340 (void) close (pfd1[1]);
341
342 vec[vecp++] = "-vmhread";
343 (void) sprintf (buf1, "%d", pfd1[0]);
344 vec[vecp++] = buf1;
345 vec[vecp++] = "-vmhwrite";
346 (void) sprintf (buf2, "%d", pfd0[1]);
347 vec[vecp++] = buf2;
348 vec[vecp] = NULL;
349
350 (void) signal (SIGINT, SIG_DFL);
351 (void) signal (SIGQUIT, SIG_DFL);
352
353 vec[0] = r1bindex (vmhproc, '/');
354 execvp (vmhproc, vec);
355 perror (vmhproc);
356 _exit (-1); /* NOTREACHED */
357
358 default:
359 (void) close (pfd0[1]);
360 (void) close (pfd1[0]);
361
362 (void) rcinit (pfd0[0], pfd1[1]);
363 return pINI ();
364 }
365 }
366
367 /* \f */
368
369 static int pINI () {
370 register char *bp;
371 char buffer[BUFSIZ];
372 struct record rcs;
373 register struct record *rc = &rcs;
374 register WINDOW **w;
375
376 initrc (rc);
377
378 bp = buffer;
379 (void) sprintf (bp, "%d %d", RC_VRSN, numwins);
380 bp += strlen (bp);
381 for (w = windows; *w; w++) {
382 (void) sprintf (bp, " %d", (*w) -> _maxy);
383 bp += strlen (bp);
384 }
385
386 switch (str2rc (RC_INI, buffer, rc)) {
387 case RC_ACK:
388 return OK;
389
390 case RC_ERR:
391 if (rc -> rc_len)
392 adios (NULLCP, "%s", rc -> rc_data);
393 else
394 adios (NULLCP, "pINI peer error");
395
396 case RC_XXX:
397 adios (NULLCP, "%s", rc -> rc_data);
398
399 default:
400 adios (NULLCP, "pINI protocol screw-up");
401 }
402 /* NOTREACHED */
403 }
404
405 /* \f */
406
407 static int pLOOP (code, str)
408 char code,
409 *str;
410 {
411 int i;
412 struct record rcs;
413 register struct record *rc = &rcs;
414
415 initrc (rc);
416
417 (void) str2peer (code, str);
418 for (;;)
419 switch (peer2rc (rc)) {
420 case RC_TTY:
421 if (pTTY (rc) == NOTOK)
422 return NOTOK;
423 break;
424
425 case RC_WIN:
426 if (sscanf (rc -> rc_data, "%d", &i) != 1
427 || i <= 0
428 || i > numwins) {
429 (void) fmt2peer (RC_ERR, "no such window \"%s\"",
430 rc -> rc_data);
431 return NOTOK;
432 }
433 if (pWIN (windows[i - 1]) == NOTOK)
434 return NOTOK;
435 break;
436
437 case RC_EOF:
438 return OK;
439
440 case RC_ERR:
441 if (rc -> rc_len)
442 adorn (NULLCP, "%s", rc -> rc_data);
443 else
444 adorn (NULLCP, "pLOOP(%s) peer error",
445 code == RC_QRY ? "QRY" : "CMD");
446 return NOTOK;
447
448 case RC_FIN:
449 if (rc -> rc_len)
450 adorn (NULLCP, "%s", rc -> rc_data);
451 (void) rcdone ();
452 i = pidwait (PEERpid, OK);
453 PEERpid = NOTOK;
454 done (i);
455
456 case RC_XXX:
457 adios (NULLCP, "%s", rc -> rc_data);
458
459 default:
460 adios (NULLCP, "pLOOP(%s) protocol screw-up",
461 code == RC_QRY ? "QRY" : "CMD");
462 }
463 }
464
465 /* \f */
466
467 static int pTTY (r)
468 register struct record *r;
469 {
470 TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
471 struct record rcs;
472 register struct record *rc = &rcs;
473
474 initrc (rc);
475
476 TTYoff ();
477
478 hstat = signal (SIGHUP, SIG_IGN);
479 istat = signal (SIGINT, SIG_IGN);
480 qstat = signal (SIGQUIT, SIG_IGN);
481 tstat = signal (SIGTERM, SIG_IGN);
482
483 (void) rc2rc (RC_ACK, 0, NULLCP, rc);
484
485 (void) signal (SIGHUP, hstat);
486 (void) signal (SIGINT, istat);
487 (void) signal (SIGQUIT, qstat);
488 (void) signal (SIGTERM, tstat);
489
490 TTYon ();
491
492 if (r -> rc_len && strcmp (r -> rc_data, "FAST") == 0)
493 goto no_refresh;
494
495 #ifdef SIGTSTP
496 (void) signal (SIGTSTP, SIG_IGN);
497 #endif /* SIGTSTP */
498 #ifndef TERMINFO
499 if (SO)
500 tputs (SO, 0, _putchar);
501 #else /* TERMINFO */
502 putp(enter_standout_mode);
503 #endif /* TERMINFO */
504 fprintf (stdout, "Type any key to continue... ");
505 (void) fflush (stdout);
506 #ifndef TERMINFO
507 if (SE)
508 tputs (SE, 0, _putchar);
509 #else /* TERMINFO */
510 putp(exit_standout_mode);
511 #endif /* TERMINFO */
512 (void) getc (stdin);
513 #ifdef SIGTSTP
514 (void) signal (SIGTSTP, TSTPser);
515 #endif /* SIGTSTP */
516
517 wrefresh (curscr);
518
519 no_refresh: ;
520 switch (rc -> rc_type) {
521 case RC_EOF:
522 (void) rc2peer (RC_ACK, 0, NULLCP);
523 return OK;
524
525 case RC_ERR:
526 if (rc -> rc_len)
527 adorn (NULLCP, "%s", rc -> rc_data);
528 else
529 adorn (NULLCP, "pTTY peer error");
530 return NOTOK;
531
532 case RC_XXX:
533 adios (NULLCP, "%s", rc -> rc_data);
534
535 default:
536 adios (NULLCP, "pTTY protocol screw-up");
537 }
538 /* NOTREACHED */
539 }
540
541 /* \f */
542
543 static int pWIN (w)
544 register WINDOW *w;
545 {
546 int i;
547
548 did_less = 0;
549 if ((i = pWINaux (w)) == OK && did_less)
550 (void) WINless (w, 1);
551
552 lreset ();
553
554 return i;
555 }
556
557 /* \f */
558
559 static int pWINaux (w)
560 register WINDOW *w;
561 {
562 register int n;
563 int eol;
564 register char c,
565 *bp;
566 struct record rcs;
567 register struct record *rc = &rcs;
568
569 initrc (rc);
570
571 werase (w);
572 wmove (w, 0, 0);
573 #ifdef XYZ
574 if (w == Status)
575 wstandout (w);
576 #endif /* XYZ */
577
578 for (eol = 0;;)
579 switch (rc2rc (RC_ACK, 0, NULLCP, rc)) {
580 case RC_DATA:
581 if (eol && WINputc (w, '\n') == ERR && WINless (w, 0))
582 goto flush;
583 for (bp = rc -> rc_data, n = rc -> rc_len; n-- > 0; ) {
584 if ((c = *bp++) == '\n')
585 linsert (w);
586 if (WINputc (w, c) == ERR)
587 if (n == 0 && c == '\n')
588 eol++;
589 else
590 if (WINless (w, 0)) {
591 flush: ;
592 (void) fmt2peer (RC_ERR, "flush window");
593 #ifdef XYZ /* should NEVER happen... */
594 if (w == Status)
595 wstandend (w);
596 #endif /* XYZ */
597 wrefresh (w);
598 return NOTOK;
599 }
600 }
601 break;
602
603 case RC_EOF:
604 (void) rc2peer (RC_ACK, 0, NULLCP);
605 #ifdef XYZ
606 if (w == Status)
607 wstandend (w);
608 #endif /* XYZ */
609 wrefresh (w);
610 return OK;
611
612 case RC_ERR:
613 if (rc -> rc_len)
614 adorn (NULLCP, "%s", rc -> rc_data);
615 else
616 adorn (NULLCP, "pWIN peer error");
617 return NOTOK;
618
619 case RC_XXX:
620 adios (NULLCP, "%s", rc -> rc_data);
621
622 default:
623 adios (NULLCP, "pWIN protocol screw-up");
624 }
625 /* NOTREACHED */
626 }
627
628 /* \f */
629
630 static int pFIN () {
631 int status;
632
633 if (PEERpid <= OK)
634 return OK;
635
636 (void) rc2peer (RC_FIN, 0, NULLCP);
637 (void) rcdone ();
638
639 switch (setjmp (PEERctx)) {
640 case OK:
641 (void) signal (SIGALRM, ALRMser);
642 (void) alarm (ALARM);
643
644 status = pidwait (PEERpid, OK);
645
646 (void) alarm (0);
647 break;
648
649 default:
650 (void) kill (PEERpid, SIGKILL);
651 status = NOTOK;
652 break;
653 }
654 PEERpid = NOTOK;
655
656 return status;
657 }
658
659 /* \f WINDOWS */
660
661 static int WINinit (nprog) {
662 register int nlines, /* not "lines" because terminfo uses that */
663 top,
664 bottom;
665
666 foreground ();
667 if (initscr () == (WINDOW *) ERR)
668 if (nprog)
669 return NOTOK;
670 else
671 adios (NULLCP, "could not initialize terminal");
672 #ifdef SIGTSTP
673 (void) signal (SIGTSTP, SIG_DFL);
674 #endif /* SIGTSTP */
675 sideground ();
676
677 #ifndef TERMINFO
678 if (CM == NULL)
679 #else /* TERMINFO */
680 if (cursor_address == NULL) /* assume mtr wanted "cm", not "CM" */
681 #endif /* TERMINFO */
682 if (nprog)
683 return NOTOK;
684 else
685 adios (NULLCP,
686 "sorry, your terminal isn't powerful enough to run %s",
687 invo_name);
688
689 #ifndef TERMINFO
690 if (tgetflag ("xt") || tgetnum ("sg") > 0)
691 SO = SE = US = UE = NULL;
692 #else /* TERMINFO */
693 /*
694 * If termcap mapped directly to terminfo, we'd use the following:
695 * if (teleray_glitch || magic_cookie_glitch > 0)
696 * enter_standout_mode = exit_standout_mode =
697 * enter_underline_mode = exit_underline_mode = NULL;
698 * But terminfo does the right thing so we don't have to resort to that.
699 */
700 #endif /* TERMINFO */
701
702 if ((nlines = LINES - 1) < 11)
703 adios (NULLCP, "screen too small");
704 if ((top = nlines / 3 + 1) > LINES / 4 + 2)
705 top--;
706 bottom = nlines - top - 2;
707
708 numwins = 0;
709 Scan = windows[numwins++] = newwin (top, COLS, 0, 0);
710 Status = windows[numwins++] = newwin (1, COLS, top, 0);
711 #ifndef XYZ
712 wstandout (Status);
713 #endif /* XYZ */
714 Display = windows[numwins++] = newwin (bottom, COLS, top + 1, 0);
715 Command = newwin (1, COLS - 1, top + 1 + bottom, 0);
716 windows[numwins] = NULL;
717
718 largemove = Display -> _maxy / 2 + 2;
719 return OK;
720 }
721
722 /* \f */
723
724 static int WINgetstr (w, buffer)
725 register WINDOW *w;
726 char *buffer;
727 {
728 register int c;
729 register char *bp;
730
731 bp = buffer;
732 *bp = 0;
733
734 for (;;) {
735 switch (c = toascii (wgetch (w))) {
736 case ERR:
737 adios (NULLCP, "wgetch lost");
738
739 case '\f':
740 wrefresh (curscr);
741 break;
742
743 case '\r':
744 case '\n':
745 *bp = 0;
746 if (bp > buffer) {
747 leaveok (curscr, FALSE);
748 wmove (w, 0, w -> _curx - (bp - buffer));
749 wrefresh (w);
750 leaveok (curscr, TRUE);
751 }
752 return DONE;
753
754 default:
755 if (c == intrc) {
756 wprintw (w, " ");
757 wstandout (w);
758 wprintw (w, "Interrupt");
759 wstandend (w);
760 wrefresh (w);
761 *buffer = 0;
762 return NOTOK;
763 }
764 if (c == EOFC) {
765 if (bp <= buffer)
766 return OK;
767 break;
768 }
769 if (c == ERASE) {
770 if (bp <= buffer)
771 continue;
772 bp--, w -> _curx--;
773 wclrtoeol (w);
774 break;
775 }
776 if (c == KILL) {
777 if (bp <= buffer)
778 continue;
779 w -> _curx -= bp - buffer;
780 bp = buffer;
781 wclrtoeol (w);
782 break;
783 }
784 if (c == WERASC) {
785 if (bp <= buffer)
786 continue;
787 do {
788 bp--, w -> _curx--;
789 } while (isspace (*bp) && bp > buffer);
790
791 if (bp > buffer) {
792 do {
793 bp--, w -> _curx--;
794 } while (!isspace (*bp) && bp > buffer);
795 if (isspace (*bp))
796 bp++, w -> _curx++;
797 }
798 wclrtoeol (w);
799 break;
800 }
801
802 if (c >= ' ' && c < '\177')
803 (void) waddch (w, *bp++ = c);
804 break;
805 }
806
807 wrefresh (w);
808 }
809 }
810
811 /* \f */
812
813 static int WINwritev (w, iov, n)
814 register WINDOW *w;
815 register struct iovec *iov;
816 register int n;
817 {
818 register int i;
819
820 werase (w);
821 wmove (w, 0, 0);
822 for (i = 0; i < n; i++, iov++)
823 wprintw (w, "%*.*s", iov -> iov_len, iov -> iov_len, iov -> iov_base);
824 wrefresh (w);
825
826 sleep (PAUSE);
827
828 return OK;
829 }
830
831 /* \f */
832
833 static struct {
834 char *h_msg;
835 int *h_val;
836 } hlpmsg[] = {
837 " forward backwards", NULL,
838 " ------- ---------", NULL,
839 "next screen SPACE", NULL,
840 "next %d line%s RETURN y", &smallmove,
841 "next %d line%s EOT u", &largemove,
842 "go g G", NULL,
843 "", NULL,
844 "refresh CTRL-L", NULL,
845 "quit q", NULL,
846
847 NULL, NULL
848 };
849
850 /* \f */
851
852 static int WINless (w, fin)
853 register WINDOW *w;
854 int fin;
855 {
856 register int c,
857 i,
858 n;
859 int nfresh,
860 #ifdef notdef
861 nlatch,
862 #endif /* notdef */
863 nwait;
864 char *cp;
865 register struct line *lbottom;
866
867 did_less++;
868
869 cp = NULL;
870 #ifdef notdef
871 if (fin)
872 ltop = NULL;
873 #endif /* notdef */
874 lbottom = NULL;
875 nfresh = 1;
876 nwait = 0;
877 wrefresh (w);
878
879 for (;;) {
880 if (nfresh || nwait) {
881 nfresh = 0;
882 #ifdef notdef
883 nlatch = 1;
884
885 once_only: ;
886 #endif /* notdef */
887 werase (w);
888 wmove (w, 0, 0);
889
890 if (ltop == NULL)
891 if (fin) {
892 (void) lgo (ltail -> l_no - w -> _maxy + 1);
893 if (ltop == NULL)
894 ltop = lhead;
895 }
896 else
897 ltop = lbottom && lbottom -> l_prev ? lbottom -> l_prev
898 : lbottom;
899
900 for (lbottom = ltop; lbottom; lbottom = lbottom -> l_next)
901 if (waddstr (w, lbottom -> l_buf) == ERR
902 || waddch (w, '\n') == ERR)
903 break;
904 if (lbottom == NULL)
905 if (fin) {
906 #ifdef notdef
907 if (nlatch && (ltail -> l_no >= w -> _maxy)) {
908 (void) lgo (ltail -> l_no - w -> _maxy + 1);
909 nlatch = 0;
910 goto once_only;
911 }
912 #endif /* notdef */
913 lbottom = ltail;
914 while (waddstr (w, "~\n") != ERR)
915 continue;
916 }
917 else {
918 wrefresh (w);
919 return 0;
920 }
921
922 if (!nwait)
923 wrefresh (w);
924 }
925
926 wmove (Command, 0, 0);
927 if (cp) {
928 wstandout (Command);
929 wprintw (Command, "%s", cp);
930 wstandend (Command);
931 cp = NULL;
932 }
933 else
934 wprintw (Command, fin ? "top:%d bot:%d end:%d" : "top:%d bot:%d",
935 ltop -> l_no, lbottom -> l_no, ltail -> l_no);
936 wprintw (Command, ">> ");
937 wclrtoeol (Command);
938 wrefresh (Command);
939
940 c = toascii (wgetch (Command));
941
942 werase (Command);
943 wrefresh (Command);
944
945 if (nwait) {
946 nwait = 0;
947 wrefresh (w);
948 }
949
950 n = 0;
951 again: ;
952 switch (c) {
953 case ' ':
954 ltop = lbottom -> l_next;
955 nfresh++;
956 break;
957
958 case '\r':
959 case '\n':
960 case 'e':
961 case 'j':
962 if (n)
963 smallmove = n;
964 if (ladvance (smallmove))
965 nfresh++;
966 break;
967
968 case 'y':
969 case 'k':
970 if (n)
971 smallmove = n;
972 if (lretreat (smallmove))
973 nfresh++;
974 break;
975
976 case 'd':
977 eof: ;
978 if (n)
979 largemove = n;
980 if (ladvance (largemove))
981 nfresh++;
982 break;
983
984 case 'u':
985 if (n)
986 largemove = n;
987 if (lretreat (largemove))
988 nfresh++;
989 break;
990
991 case 'g':
992 if (lgo (n ? n : 1))
993 nfresh++;
994 break;
995
996 case 'G':
997 if (lgo (n ? n : ltail -> l_no - w -> _maxy + 1))
998 nfresh++;
999 break;
1000
1001 case '\f':
1002 case 'r':
1003 wrefresh (curscr);
1004 break;
1005
1006 case 'h':
1007 case '?':
1008 werase (w);
1009 wmove (w, 0, 0);
1010 for (i = 0; hlpmsg[i].h_msg; i++) {
1011 if (hlpmsg[i].h_val)
1012 wprintw (w, hlpmsg[i].h_msg, *hlpmsg[i].h_val,
1013 *hlpmsg[i].h_val != 1 ? "s" : "");
1014 else
1015 (void) waddstr (w, hlpmsg[i].h_msg);
1016 (void) waddch (w, '\n');
1017 }
1018 wrefresh (w);
1019 nwait++;
1020 break;
1021
1022 case 'q':
1023 return 1;
1024
1025 default:
1026 if (c == EOFC)
1027 goto eof;
1028
1029 if (isdigit (c)) {
1030 wmove (Command, 0, 0);
1031 i = 0;
1032 while (isdigit (c)) {
1033 wprintw (Command, "%c", c);
1034 wrefresh (Command);
1035 i = i * 10 + c - '0';
1036 c = toascii (wgetch (Command));
1037 }
1038 werase (Command);
1039 wrefresh (Command);
1040
1041 if (i > 0) {
1042 n = i;
1043 goto again;
1044 }
1045 cp = "bad number";
1046 }
1047 else
1048 cp = "not understood";
1049 break;
1050 }
1051 }
1052 }
1053
1054 /* \f */
1055
1056 static int WINputc (w, c)
1057 register WINDOW *w;
1058 register char c;
1059 {
1060 register int x,
1061 y;
1062
1063 switch (c) {
1064 default:
1065 if (!isascii (c)) {
1066 if (WINputc (w, 'M') == ERR || WINputc (w, '-') == ERR)
1067 return ERR;
1068 c = toascii (c);
1069 }
1070 else
1071 if (c < ' ' || c == '\177') {
1072 if (WINputc (w, '^') == ERR)
1073 return ERR;
1074 c ^= 0100;
1075 }
1076 break;
1077
1078 case '\t':
1079 case '\n':
1080 break;
1081 }
1082
1083 if (w != Scan)
1084 return waddch (w, c);
1085
1086 if ((x = w -> _curx) < 0 || x >= w -> _maxx
1087 || (y = w -> _cury) < 0 || y >= w -> _maxy)
1088 return DONE;
1089
1090 switch (c) {
1091 case '\t':
1092 for (x = 8 - (x & 0x07); x > 0; x--)
1093 if (WINputc (w, ' ') == ERR)
1094 return ERR;
1095 break;
1096
1097 case '\n':
1098 if (++y < w -> _maxy)
1099 (void) waddch (w, c);
1100 else
1101 wclrtoeol (w);
1102 break;
1103
1104 default:
1105 if (++x < w -> _maxx)
1106 (void) waddch (w, c);
1107 break;
1108 }
1109
1110 return DONE;
1111 }
1112
1113 /* \f LINES */
1114
1115 static lreset () {
1116 register struct line *lp,
1117 *mp;
1118
1119 for (lp = lhead; lp; lp = mp) {
1120 mp = lp -> l_next;
1121 free (lp -> l_buf);
1122 free ((char *) lp);
1123 }
1124 lhead = ltop = ltail = NULL;
1125 }
1126
1127
1128 static linsert (w)
1129 WINDOW *w;
1130 {
1131 register char *cp;
1132 register struct line *lp;
1133
1134 if ((lp = (struct line *) calloc ((unsigned) 1, sizeof *lp)) == NULL)
1135 adios (NULLCP, "unable to allocate line storage");
1136
1137 lp -> l_no = (ltail ? ltail -> l_no : 0) + 1;
1138 #ifndef BSD44
1139 lp -> l_buf = getcpy (w -> _y[w -> _cury]);
1140 #else
1141 lp -> l_buf = getcpy (w -> lines[w -> _cury]->line);
1142 #endif
1143 for (cp = lp -> l_buf + strlen (lp -> l_buf) - 1; cp >= lp -> l_buf; cp--)
1144 if (isspace (*cp))
1145 *cp = 0;
1146 else
1147 break;
1148
1149 if (lhead == NULL)
1150 lhead = lp;
1151 if (ltop == NULL)
1152 ltop = lp;
1153 if (ltail)
1154 ltail -> l_next = lp;
1155 lp -> l_prev = ltail;
1156 ltail = lp;
1157 }
1158
1159 /* \f */
1160
1161 static int ladvance (n)
1162 int n;
1163 {
1164 register int i;
1165 register struct line *lp;
1166
1167 for (i = 0, lp = ltop; i < n && lp; i++, lp = lp -> l_next)
1168 continue;
1169
1170 if (ltop == lp)
1171 return 0;
1172
1173 ltop = lp;
1174 return 1;
1175 }
1176
1177
1178 static int lretreat (n)
1179 int n;
1180 {
1181 register int i;
1182 register struct line *lp;
1183
1184 for (i = 0, lp = ltop; i < n && lp; i++, lp = lp -> l_prev)
1185 if (!lp -> l_prev)
1186 break;
1187
1188 if (ltop == lp)
1189 return 0;
1190
1191 ltop = lp;
1192 return 1;
1193 }
1194
1195 /* \f */
1196
1197 static int lgo (n)
1198 int n;
1199 {
1200 register int i,
1201 j;
1202 register struct line *lp;
1203
1204 if ((i = n - (lp = lhead) -> l_no)
1205 > (j = abs (n - (ltop ? ltop : ltail) -> l_no)))
1206 i = j, lp = ltop ? ltop : ltail;
1207 if (i > (j = abs (ltail -> l_no - n)))
1208 i = j, lp = ltail;
1209
1210 if (n >= lp -> l_no) {
1211 for (; lp; lp = lp -> l_next)
1212 if (lp -> l_no == n)
1213 break;
1214 }
1215 else {
1216 for (; lp; lp = lp -> l_prev)
1217 if (lp -> l_no == n)
1218 break;
1219 if (!lp)
1220 lp = lhead;
1221 }
1222
1223 if (ltop == lp)
1224 return 0;
1225
1226 ltop = lp;
1227 return 1;
1228 }
1229
1230 /* \f TTYS */
1231
1232 static int TTYinit (nprog) {
1233 if (!isatty (fileno (stdin)) || !isatty (fileno (stdout)))
1234 if (nprog)
1235 return NOTOK;
1236 else
1237 adios (NULLCP, "not a tty");
1238
1239 foreground ();
1240 #ifndef SYS5
1241 if (ioctl (fileno (stdin), TIOCGETP, (char *) &sg) == NOTOK)
1242 adios ("failed", "ioctl TIOCGETP");
1243 if (ioctl (fileno (stdin), TIOCGETC, (char *) &tc) == NOTOK)
1244 adios ("failed", "ioctl TIOCGETC");
1245 #else
1246 #ifdef TCGETATTR
1247 if( tcgetattr( fileno(stdin), &sg) == NOTOK)
1248 adios( "failed", "tcgetattr");
1249 #else /* SYS5 */
1250 if (ioctl (fileno (stdin), TCGETA, &sg) == NOTOK)
1251 adios ("failed", "ioctl TCGETA");
1252 #endif
1253 #endif
1254 #ifdef TIOCGLTC
1255 if (ioctl (fileno (stdin), TIOCGLTC, (char *) &ltc) == NOTOK)
1256 adios ("failed", "ioctl TIOCGLTC");
1257 #endif /* TIOCGLTC */
1258 intrc = INTR;
1259 sideground ();
1260
1261 tty_ready = OK;
1262
1263 (void) signal (SIGPIPE, PIPEser);
1264
1265 return OK;
1266 }
1267
1268 /* \f */
1269
1270 static TTYon () {
1271 if (tty_ready == DONE)
1272 return;
1273
1274 INTR = NOTOK;
1275 #ifndef SYS5
1276 (void) ioctl (fileno (stdin), TIOCSETC, (char *) &tc);
1277 #else /* SYS5 */
1278 (void) ioctl (fileno (stdin), TCSETA, &sg);
1279 #endif /* SYS5 */
1280
1281 (void) crmode ();
1282 (void) noecho ();
1283 (void) nonl ();
1284 scrollok (curscr, FALSE);
1285
1286 discard (stdin);
1287
1288 tty_ready = DONE;
1289
1290 (void) signal (SIGHUP, SIGser);
1291 (void) signal (SIGINT, SIGser);
1292 (void) signal (SIGQUIT, SIGser);
1293 #ifdef SIGTSTP
1294 (void) signal (SIGTSTP, TSTPser);
1295 #endif /* SIGTSTP */
1296 }
1297
1298 /* \f */
1299
1300 static TTYoff () {
1301 if (tty_ready == NOTOK)
1302 return;
1303
1304 INTR = intrc;
1305 #ifndef SYS5
1306 (void) ioctl (fileno (stdin), TIOCSETC, (char *) &tc);
1307 #else /* SYS5 */
1308 (void) ioctl (fileno (stdin), TCSETA, &sg);
1309 #endif /* SYS5 */
1310
1311 leaveok (curscr, TRUE);
1312 mvcur (0, COLS - 1, LINES - 1, 0);
1313 endwin ();
1314 if (tty_ready == DONE) {
1315 #ifndef TERMINFO
1316 if (CE)
1317 tputs (CE, 0, _putchar);
1318 else
1319 #else /* TERMINFO */
1320 putp(clr_eol);
1321 #endif /* TERMINFO */
1322 fprintf (stdout, "\r\n");
1323 }
1324 (void) fflush (stdout);
1325
1326 tty_ready = NOTOK;
1327
1328 (void) signal (SIGHUP, SIG_DFL);
1329 (void) signal (SIGINT, SIG_DFL);
1330 (void) signal (SIGQUIT, SIG_DFL);
1331 #ifdef SIGTSTP
1332 (void) signal (SIGTSTP, SIG_DFL);
1333 #endif /* SIGTSTP */
1334 }
1335
1336 /* \f */
1337
1338 static foreground () {
1339 #ifdef TIOCGPGRP
1340 int pgrp,
1341 tpgrp;
1342 TYPESIG (*tstat) ();
1343
1344 if ((pgrp = getpgrp (0)) == NOTOK)
1345 adios ("process group", "unable to determine");
1346 for (;;) {
1347 if (ioctl (fileno (stdin), TIOCGPGRP, (char *) &tpgrp) == NOTOK)
1348 adios ("tty's process group", "unable to determine");
1349 if (pgrp == tpgrp)
1350 break;
1351
1352 tstat = signal (SIGTTIN, SIG_DFL);
1353 (void) kill (0, SIGTTIN);
1354 (void) signal (SIGTTIN, tstat);
1355 }
1356
1357 (void) signal (SIGTTIN, SIG_IGN);
1358 (void) signal (SIGTTOU, SIG_IGN);
1359 (void) signal (SIGTSTP, SIG_IGN);
1360 #endif /* TIOCGPGRP */
1361 }
1362
1363
1364 sideground () {
1365 #ifdef TIOCGPGRP
1366 (void) signal (SIGTTIN, SIG_DFL);
1367 (void) signal (SIGTTOU, SIG_DFL);
1368 (void) signal (SIGTSTP, SIG_DFL);
1369 #endif /* TIOCGPGRP */
1370 }
1371
1372 /* \f SIGNALS */
1373
1374 /* ARGSUSED */
1375
1376 static TYPESIG ALRMser (sig)
1377 int sig;
1378 {
1379 longjmp (PEERctx, DONE);
1380 }
1381
1382
1383 #ifdef BSD42
1384 /* ARGSUSED */
1385 #endif /* BSD42 */
1386
1387 static TYPESIG PIPEser (sig)
1388 int sig;
1389 {
1390 #ifndef BSD42
1391 (void) signal (sig, SIG_IGN);
1392 #endif /* BSD42 */
1393
1394 adios (NULLCP, "lost peer");
1395 }
1396
1397
1398 #ifdef BSD42
1399 /* ARGSUSED */
1400 #endif /* BSD42 */
1401
1402 static TYPESIG SIGser (sig)
1403 int sig;
1404 {
1405 #ifndef BSD42
1406 (void) signal (sig, SIG_IGN);
1407 #endif /* BSD42 */
1408
1409 done (1);
1410 }
1411
1412
1413 #ifdef SIGTSTP
1414 static TYPESIG TSTPser (sig)
1415 int sig;
1416 {
1417 #ifndef TERMINFO
1418 tputs (tgoto (CM, 0, LINES - 1), 0, _putchar);
1419 #else /* TERMINFO */
1420 move(LINES - 1, 0); /* to lower left corner */
1421 clrtoeol(); /* clear bottom line */
1422 wrefresh(curscr); /* flush out everything */
1423 #endif /* TERMINFO */
1424 (void) fflush (stdout);
1425
1426 TTYoff ();
1427 #ifdef BSD42
1428 (void) sigsetmask (sigblock (0) & ~sigmask (SIGTSTP));
1429 #endif /* BSD42 */
1430
1431 (void) kill (getpid (), sig);
1432
1433 #ifdef BSD42
1434 (void) sigblock (sigmask (SIGTSTP));
1435 #endif /* BSD42 */
1436 TTYon ();
1437
1438 wrefresh (curscr);
1439 }
1440 #endif /* SIGTSTP */
1441
1442 /* \f MISCELLANY */
1443
1444 void done (status)
1445 int status;
1446 {
1447 TTYoff ();
1448 (void) pFIN ();
1449
1450 exit (status);
1451 }
1452
1453 /* \f */
1454
1455 /* VARARGS2 */
1456
1457 static void adorn (what, fmt, a, b, c, d, e, f)
1458 char *what,
1459 *fmt,
1460 *a,
1461 *b,
1462 *c,
1463 *d,
1464 *e,
1465 *f;
1466 {
1467 char *cp = invo_name;
1468
1469 invo_name = NULL;
1470 advise (what, fmt, a, b, c, d, e, f);
1471 invo_name = cp;
1472 }
1473
1474 /* \f */
1475
1476 /* VARARGS3 */
1477
1478 void advertise (what, tail, fmt, a, b, c, d, e, f)
1479 char *what,
1480 *tail,
1481 *fmt,
1482 *a,
1483 *b,
1484 *c,
1485 *d,
1486 *e,
1487 *f;
1488 {
1489 int eindex = errno;
1490 char buffer[BUFSIZ],
1491 err[BUFSIZ];
1492 struct iovec iob[20];
1493 register struct iovec *iov = iob;
1494
1495 (void) fflush (stdout);
1496
1497 (void) fflush (stderr);
1498
1499 if (invo_name) {
1500 iov -> iov_len = strlen (iov -> iov_base = invo_name);
1501 iov++;
1502 iov -> iov_len = strlen (iov -> iov_base = ": ");
1503 iov++;
1504 }
1505
1506 (void) sprintf (buffer, fmt, a, b, c, d, e, f);
1507 iov -> iov_len = strlen (iov -> iov_base = buffer);
1508 iov++;
1509 if (what) {
1510 if (*what) {
1511 iov -> iov_len = strlen (iov -> iov_base = " ");
1512 iov++;
1513 iov -> iov_len = strlen (iov -> iov_base = what);
1514 iov++;
1515 iov -> iov_len = strlen (iov -> iov_base = ": ");
1516 iov++;
1517 }
1518 if (eindex > 0 && eindex < sys_nerr)
1519 iov -> iov_len = strlen (iov -> iov_base = sys_errlist[eindex]);
1520 else {
1521 (void) sprintf (err, "Error %d", eindex);
1522 iov -> iov_len = strlen (iov -> iov_base = err);
1523 }
1524 iov++;
1525 }
1526 if (tail && *tail) {
1527 iov -> iov_len = strlen (iov -> iov_base = ", ");
1528 iov++;
1529 iov -> iov_len = strlen (iov -> iov_base = tail);
1530 iov++;
1531 }
1532 iov -> iov_len = strlen (iov -> iov_base = "\n");
1533 iov++;
1534
1535 if (tty_ready == DONE)
1536 (void) WINwritev (Display, iob, iov - iob);
1537 else
1538 (void) writev (fileno (stderr), iob, iov - iob);
1539 }
1540
1541 /* \f */
1542
1543 #ifndef BSD42
1544 static int writev (fd, iov, n)
1545 register int fd;
1546 register struct iovec *iov;
1547 register int n;
1548 {
1549 register int i,
1550 j;
1551
1552 for (i = j = 0; i < n; i++, iov++)
1553 if (write (fd, iov -> iov_base, iov -> iov_len) != iov -> iov_len)
1554 break;
1555 else
1556 j += iov -> iov_len;
1557
1558 return j;
1559 }
1560 #endif /* BSD42 */