]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/wmh.c
Always check that mktemp()/mktemp2() succeeds before trying to
[nmh] / docs / historical / mh-6.8.5 / uip / wmh.c
1 /* wmh.c - window front-end to mh */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: wmh.c,v 1.5 1993/08/25 17:29:59 jromine Exp $";
4 #endif lint
5
6 /* TODO:
7 Pass signals to client during execution
8
9 Figure out a way for the user to say how big the Scan/Display
10 windows should be, and where all the windows should be.
11 */
12
13 #include <stdio.h>
14 #include "../h/mh.h"
15 #include "../h/vmhsbr.h"
16 #include <ctype.h>
17 #include <errno.h>
18 #include <setjmp.h>
19 #include <signal.h>
20 #ifndef sigmask
21 #define sigmask(s) (1 << ((s) - 1))
22 #endif not sigmask
23 #include <sys/types.h>
24 #include <sys/uio.h>
25 #include <vt.h>
26 #include <bitmap.h>
27 #include <tools.h>
28 #ifdef LOCALE
29 #include <locale.h>
30 #endif
31
32
33 #define ALARM ((unsigned int) 10)
34 #define PAUSE ((unsigned int) 2)
35
36 #define abs(a) ((a) > 0 ? (a) : -(a))
37
38 #define SZ(a) (sizeof a / sizeof a[0])
39
40 /* \f */
41
42 static struct swit switches[] = {
43 #define PRMPTSW 0
44 "prompt string", 6,
45
46 #define PROGSW 1
47 "vmhproc program", 7,
48 #define NPROGSW 2
49 "novmhproc", 9,
50
51 #define HELPSW 3
52 "help", 4,
53
54 NULL, NULL
55 };
56
57 /* \f */
58 /* PEERS */
59 static int PEERpid = NOTOK;
60
61 static jmp_buf PEERctx;
62
63
64
65 /* WINDOWS */
66 static int dfd = NOTOK;
67
68 static int twd = NOTOK;
69
70 static char *myprompt = "(%s) ";
71
72
73 struct line {
74 int l_no;
75 char *l_buf;
76 struct line *l_prev;
77 struct line *l_next;
78 };
79
80
81 typedef struct {
82 int w_fd;
83
84 int w_flags;
85 #define W_NULL 0x00
86 #define W_CMND 0x01
87 #define W_FAKE 0x02
88 #define W_EBAR 0x04
89
90 int w_wd;
91
92 struct wstate w_ws;
93
94 char *w_eb;
95 int w_ebloc;
96 int w_ebsize;
97
98 int w_cbase;
99 int w_height;
100 int w_cheight;
101 int w_width;
102 int w_cwidth;
103
104 struct line *w_head;
105 struct line *w_top;
106 struct line *w_bottom;
107 struct line *w_tail;
108
109 char w_buffer[BUFSIZ];
110 int w_bufpos;
111 } WINDOW;
112
113
114 static WINDOW *Scan;
115 static WINDOW *Status;
116 static WINDOW *Display;
117 static WINDOW *Command;
118
119
120 #define NWIN 4
121 static int numwins;
122 WINDOW *windows[NWIN + 1];
123
124
125 WINDOW *WINnew ();
126
127
128 /* SIGNALS */
129 #define ERASE sg.sg_erase
130 #define KILL sg.sg_kill
131 static struct sgttyb sg;
132
133 #define EOFC tc.t_eofc
134 #define INTR tc.t_intrc
135 static struct tchars tc;
136
137 #define WERASC ltc.t_werasc
138 static struct ltchars ltc;
139
140
141 int ALRMser (), PIPEser (), SIGser ();
142 int ADJser (), REFser ();
143
144
145 /* MISCELLANY */
146 extern int errno;
147 #ifndef BSD44
148 extern int sys_nerr;
149 extern char *sys_errlist[];
150 #endif
151
152 void adorn ();
153
154 /* \f */
155
156 /* ARGSUSED */
157
158 main (argc, argv)
159 int argc;
160 char *argv[];
161 {
162 int vecp = 1,
163 nprog = 0;
164 char *cp,
165 buffer[BUFSIZ],
166 **ap,
167 **argp,
168 *arguments[MAXARGS],
169 *vec[MAXARGS];
170
171 #ifdef LOCALE
172 setlocale(LC_ALL, "");
173 #endif
174 invo_name = r1bindex (argv[0], '/');
175 if ((cp = m_find (invo_name)) != NULL) {
176 ap = brkstring (cp = getcpy (cp), " ", "\n");
177 ap = copyip (ap, arguments);
178 }
179 else
180 ap = arguments;
181 (void) copyip (argv + 1, ap);
182 argp = arguments;
183
184 /* \f */
185
186 while (cp = *argp++)
187 if (*cp == '-')
188 switch (smatch (++cp, switches)) {
189 case AMBIGSW:
190 ambigsw (cp, switches);
191 done (1);
192 case UNKWNSW:
193 vec[vecp++] = --cp;
194 continue;
195 case HELPSW:
196 (void) sprintf (buffer, "%s [switches for vmhproc]",
197 invo_name);
198 help (buffer, switches);
199 done (1);
200
201 case PRMPTSW:
202 if (!(myprompt = *argp++) || *myprompt == '-')
203 adios (NULLCP, "missing argument to %s", argp[-2]);
204 continue;
205
206 case PROGSW:
207 if (!(vmhproc = *argp++) || *vmhproc == '-')
208 adios (NULLCP, "missing argument to %s", argp[-2]);
209 continue;
210 case NPROGSW:
211 nprog++;
212 continue;
213 }
214 else
215 vec[vecp++] = cp;
216
217 /* \f */
218
219 (void) SIGinit ();
220 if (WINinit (nprog) == NOTOK) {
221 vec[vecp] = NULL;
222
223 vec[0] = r1bindex (vmhproc, '/');
224 execvp (vmhproc, vec);
225 adios (vmhproc, "unable to exec");
226 }
227 (void) PEERinit (vecp, vec);
228
229 vmh ();
230
231 done (0);
232 }
233
234 /* \f */
235
236 static vmh () {
237 char buffer[BUFSIZ],
238 prompt[BUFSIZ];
239
240 for (;;) {
241 (void) pLOOP (RC_QRY, NULLCP);
242
243 (void) sprintf (prompt, myprompt, invo_name);
244
245 switch (WINgetstr (Command, prompt, buffer)) {
246 case NOTOK:
247 break;
248
249 case OK:
250 done (0); /* NOTREACHED */
251
252 default:
253 if (*buffer)
254 (void) pLOOP (RC_CMD, buffer);
255 break;
256 }
257 }
258 }
259
260 /* \f PEERS */
261
262 static int PEERinit (vecp, vec)
263 int vecp;
264 char *vec[];
265 {
266 int pfd0[2],
267 pfd1[2];
268 char buf1[BUFSIZ],
269 buf2[BUFSIZ];
270 register WINDOW **w;
271
272 (void) signal (SIGPIPE, PIPEser);
273
274 if (pipe (pfd0) == NOTOK || pipe (pfd1) == NOTOK)
275 adios ("pipe", "unable to");
276 switch (PEERpid = vfork ()) {
277 case NOTOK:
278 adios ("vfork", "unable to");/* NOTREACHED */
279
280 case OK:
281 for (w = windows; *w; w++)
282 if ((*w) -> w_fd != NOTOK)
283 (void) close ((*w) -> w_fd);
284 (void) close (pfd0[0]);
285 (void) close (pfd1[1]);
286
287 vec[vecp++] = "-vmhread";
288 (void) sprintf (buf1, "%d", pfd1[0]);
289 vec[vecp++] = buf1;
290 vec[vecp++] = "-vmhwrite";
291 (void) sprintf (buf2, "%d", pfd0[1]);
292 vec[vecp++] = buf2;
293 vec[vecp] = NULL;
294
295 (void) signal (SIGINT, SIG_DFL);
296 (void) signal (SIGQUIT, SIG_DFL);
297 (void) signal (SIGTERM, SIG_DFL);
298
299 vec[0] = r1bindex (vmhproc, '/');
300 execvp (vmhproc, vec);
301 perror (vmhproc);
302 _exit (-1); /* NOTREACHED */
303
304 default:
305 (void) close (pfd0[1]);
306 (void) close (pfd1[0]);
307
308 (void) rcinit (pfd0[0], pfd1[1]);
309 return pINI ();
310 }
311 }
312
313 /* \f */
314
315 static int pINI () {
316 register char *bp;
317 char buffer[BUFSIZ];
318 struct record rcs;
319 register struct record *rc = &rcs;
320 register WINDOW **w;
321
322 initrc (rc);
323
324 bp = buffer;
325 (void) sprintf (bp, "%d %d", RC_VRSN, numwins);
326 bp += strlen (bp);
327 for (w = windows; *w; w++) {
328 (void) sprintf (bp, " %d", (*w) -> w_height);
329 bp += strlen (bp);
330 }
331
332 switch (str2rc (RC_INI, buffer, rc)) {
333 case RC_ACK:
334 return OK;
335
336 case RC_ERR:
337 if (rc -> rc_len)
338 adios (NULLCP, "%s", rc -> rc_data);
339 else
340 adios (NULLCP, "pINI peer error");
341
342 case RC_XXX:
343 adios (NULLCP, "%s", rc -> rc_data);
344
345 default:
346 adios (NULLCP, "pINI protocol screw-up");
347 }
348 /* NOTREACHED */
349 }
350
351 /* \f */
352
353 static int pLOOP (code, str)
354 char code,
355 *str;
356 {
357 int i;
358 struct record rcs;
359 register struct record *rc = &rcs;
360 WINDOW *w;
361
362 initrc (rc);
363
364 (void) str2peer (code, str);
365 for (;;)
366 switch (peer2rc (rc)) {
367 case RC_TTY:
368 if (pTTY () == NOTOK)
369 return NOTOK;
370 break;
371
372 case RC_WIN:
373 if (sscanf (rc -> rc_data, "%d", &i) != 1
374 || i <= 0
375 || i > numwins) {
376 (void) fmt2peer (RC_ERR, "no such window \"%s\"",
377 rc -> rc_data);
378 return NOTOK;
379 }
380 if ((w = windows[i - 1]) -> w_flags & W_CMND) {
381 (void) fmt2peer (RC_ERR, "not a display window \"%s\"",
382 rc -> rc_data);
383 return NOTOK;
384 }
385 if (pWIN (w) == NOTOK)
386 return NOTOK;
387 break;
388
389 case RC_EOF:
390 return OK;
391
392 case RC_ERR:
393 if (rc -> rc_len)
394 adorn (NULLCP, "%s", rc -> rc_data);
395 else
396 adorn (NULLCP, "pLOOP(%s) peer error",
397 code == RC_QRY ? "QRY" : "CMD");
398 return NOTOK;
399
400 case RC_FIN:
401 if (rc -> rc_len)
402 adorn (NULLCP, "%s", rc -> rc_data);
403 (void) rcdone ();
404 i = pidwait (PEERpid, OK);
405 PEERpid = NOTOK;
406 done (i);
407
408 case RC_XXX:
409 adios (NULLCP, "%s", rc -> rc_data);
410
411 default:
412 adios (NULLCP, "pLOOP(%s) protocol screw-up",
413 code == RC_QRY ? "QRY" : "CMD");
414 }
415 }
416
417 /* \f */
418
419 static int pTTY () {
420 TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
421 struct record rcs;
422 register struct record *rc = &rcs;
423
424 initrc (rc);
425
426 if (ChangeWindowDepth (dfd, twd, 0) == NOTOK)
427 adios ("failed", "ChangeWindowDepth");
428
429 hstat = signal (SIGHUP, SIG_IGN);
430 istat = signal (SIGINT, SIG_IGN);
431 qstat = signal (SIGQUIT, SIG_IGN);
432 tstat = signal (SIGTERM, SIG_IGN);
433
434 (void) rc2rc (RC_ACK, 0, NULLCP, rc);
435
436 (void) signal (SIGHUP, hstat);
437 (void) signal (SIGINT, istat);
438 (void) signal (SIGQUIT, qstat);
439 (void) signal (SIGTERM, tstat);
440
441 switch (rc -> rc_type) {
442 case RC_EOF:
443 (void) rc2peer (RC_ACK, 0, NULLCP);
444 return OK;
445
446 case RC_ERR:
447 if (rc -> rc_len)
448 adorn (NULLCP, "%s", rc -> rc_data);
449 else
450 adorn (NULLCP, "pTTY peer error");
451 return NOTOK;
452
453 case RC_XXX:
454 adios (NULLCP, "%s", rc -> rc_data);
455
456 default:
457 adios (NULLCP, "pTTY protocol screw-up");
458 }
459 /* NOTREACHED */
460 }
461
462 /* \f */
463
464 static int pWIN (w)
465 register WINDOW *w;
466 {
467 int i;
468
469 if ((i = pWINaux (w)) == OK)
470 WINless (w);
471
472 return i;
473 }
474
475 /* \f */
476
477 static int pWINaux (w)
478 register WINDOW *w;
479 {
480 register int n;
481 register char *bp;
482 register struct line *lp,
483 *mp;
484 struct record rcs;
485 register struct record *rc = &rcs;
486
487 initrc (rc);
488
489 for (lp = w -> w_head; lp; lp = mp) {
490 mp = lp -> l_next;
491 free (lp -> l_buf);
492 free ((char *) lp);
493 }
494 w -> w_head = w -> w_top = w -> w_bottom = w -> w_tail = NULL;
495 w -> w_bufpos = 0;
496
497 for (;;)
498 switch (rc2rc (RC_ACK, 0, NULLCP, rc)) {
499 case RC_DATA:
500 for (bp = rc -> rc_data, n = rc -> rc_len; n-- > 0; )
501 (void) WINputc (w, *bp++);
502 break;
503
504 case RC_EOF:
505 (void) rc2peer (RC_ACK, 0, NULLCP);
506 if (w -> w_bufpos)
507 (void) WINputc (w, '\n');
508 return OK;
509
510 case RC_ERR:
511 if (rc -> rc_len)
512 adorn (NULLCP, "%s", rc -> rc_data);
513 else
514 adorn (NULLCP, "pWIN peer error");
515 return NOTOK;
516
517 case RC_XXX:
518 adios (NULLCP, "%s", rc -> rc_data);
519
520 default:
521 adios (NULLCP, "pWIN protocol screw-up");
522 }
523 /* NOTREACHED */
524 }
525
526 /* \f */
527
528 static int pFIN () {
529 int status;
530
531 if (PEERpid <= OK)
532 return OK;
533
534 (void) rc2peer (RC_FIN, 0, NULLCP);
535 (void) rcdone ();
536
537 switch (setjmp (PEERctx)) {
538 case OK:
539 (void) signal (SIGALRM, ALRMser);
540 (void) alarm (ALARM);
541
542 status = pidwait (PEERpid, OK);
543
544 (void) alarm (0);
545 break;
546
547 default:
548 (void) kill (PEERpid, SIGKILL);
549 status = NOTOK;
550 break;
551 }
552 PEERpid = NOTOK;
553
554 return status;
555 }
556
557 /* \f WINDOWS */
558
559 /* should dynamically determine all this stuff from gconfig... */
560
561 #define MyX 20 /* anchored hpos */
562 #define MyY 40 /* .. vpos */
563 #define MyW 800 /* .. width */
564 #define MyH 500 /* .. height */
565 #define MyS 30 /* .. height for Status, about one line */
566
567
568 #define MySlop 45 /* slop */
569
570 #define EWIDTH 25 /* Width of vertical EBAR */
571 #define ESLOP 5 /* .. slop */
572
573
574 static int WINinit (nprog) {
575 short wx,
576 wy,
577 wh,
578 sy;
579 struct gconfig gc;
580
581 if (GetGraphicsConfig (fileno (stderr), &gc) == NOTOK)
582 if (nprog)
583 return NOTOK;
584 else
585 adios (NULLCP, "not a window");
586
587 if ((dfd = open ("/dev/ttyw0", 2)) == NOTOK)
588 adios ("/dev/ttyw0", "unable to open");
589
590 if ((twd = GetTopWindow (dfd)) == NOTOK)
591 adios ("failed", "GetTopWindow");
592
593 (void) BlockRefreshAdjust (1);
594
595 numwins = 0;
596
597 wx = gc.w - (MyX + MyW + EWIDTH + ESLOP);
598 Scan = WINnew (wx, wy = MyY, MyW, wh = MyH * 2 / 3, "Scan", W_EBAR);
599
600 wy += wh + MySlop;
601 Status = WINnew (wx, sy = wy, MyW, wh = MyS, "Status", W_FAKE);
602
603 wy += wh + MySlop;
604 Display = WINnew (wx, wy, MyW, MyH, "Display", W_EBAR);
605
606 Command = WINnew (wx, sy, MyW, MyS, invo_name, W_CMND);
607
608 windows[numwins] = NULL;
609
610 return OK;
611 }
612
613 /* \f */
614
615 WINDOW *WINnew (wx, wy, ww, wh, name, flags)
616 short wx,
617 wy,
618 ww,
619 wh;
620 char *name;
621 int flags;
622 {
623 register WINDOW *w;
624
625 if ((w = (WINDOW *) calloc (1, sizeof *w)) == NULL)
626 adios (NULLCP, "unable to allocate window");
627
628 if ((w -> w_flags = flags) & W_FAKE) {
629 w -> w_fd = NOTOK;
630 w -> w_height = 1;
631
632 goto out;
633 }
634
635 if (w -> w_flags & W_EBAR)
636 ww += EWIDTH + ESLOP;
637 else
638 wx += EWIDTH + ESLOP;
639
640 if ((w -> w_fd = OpenWindow (wx, wy, ww, wh, name)) == NOTOK)
641 adios ("failed", "OpenWindow");
642 if ((w -> w_wd = GetTopWindow (dfd)) == NOTOK)
643 adios ("failed", "GetTopWindow");
644 if (GetWindowState (w -> w_fd, &w -> w_ws) == NOTOK)
645 adios ("failed", "GetWindowState");
646 if (SetLineDisc (w -> w_fd, TWSDISC) == NOTOK)
647 adios ("failed", "SetLineDisc");
648
649 SetBuf (w -> w_fd, 1024);
650 (void) SetAdjust (w -> w_fd, numwins, ADJser);
651 (void) SetRefresh (w -> w_fd, numwins, REFser);
652
653 SetAddressing (w -> w_fd, VT_ABSOLUTE);
654
655 if (w -> w_flags & W_EBAR) {
656 w -> w_eb = CreateElevatorBar (w -> w_fd, 0, 0, EWIDTH,
657 w -> w_ws.height, VT_Gray50, 1, EB_VERTICAL,
658 EB_ARROWS, w -> w_ebloc = 0, w -> w_ebsize = EB_MAX,
659 VT_White);
660 if (w -> w_eb == NULL)
661 adios (NULLCP, "CreateElevatorBar failed");
662 RefreshElevatorBar (w -> w_eb);
663 }
664
665 if ((w -> w_cbase = CharacterBaseline (w -> w_ws.font)) <= 0)
666 w -> w_cbase = 14;
667
668 if ((w -> w_cheight = CharacterHeight (w -> w_ws.font)) <= 0)
669 w -> w_cheight = 20;
670 w -> w_height = w -> w_ws.height / w -> w_cheight;
671 if (w -> w_height < 1)
672 w -> w_height = 1;
673
674 /* 1 em */
675 if ((w -> w_cwidth = CharacterWidth (w -> w_ws.font, 'm')) <= 0)
676 w -> w_cwidth = 10;
677 w -> w_width = (w -> w_ws.width - (w -> w_eb ? (EWIDTH + ESLOP) : 0))
678 / w -> w_cwidth;
679 if (w -> w_width < 1)
680 w -> w_width = 1;
681
682 out: ;
683 windows[numwins++] = w;
684
685 return w;
686 }
687
688 /* \f */
689
690 static int WINgetstr (w, prompt, buffer)
691 register WINDOW *w;
692 char *prompt,
693 *buffer;
694 {
695 register int c;
696 register char *bp,
697 *ip;
698 char image[BUFSIZ];
699 struct vtseq vts;
700 register struct vtseq *vt = &vts;
701
702 if (w -> w_eb != NULL)
703 adios (NULLCP, "internal error--elevator bar found");
704
705 if (w -> w_head == NULL
706 && (w -> w_head = (struct line *) calloc (1, sizeof *w -> w_head))
707 == NULL)
708 adios (NULLCP, "unable to allocate line storage");
709 w -> w_head -> l_buf = image;
710 w -> w_top = w -> w_bottom = w -> w_tail = w -> w_head;
711
712 if (ChangeWindowDepth (dfd, w -> w_wd, 0) == NOTOK)
713 adios ("failed", "ChangeWindowDepth");
714
715 (void) strcpy (image, prompt);
716 bp = ip = image + strlen (image);
717
718 Redisplay (w, 0);
719
720 for (;;)
721 switch (getvtseq (w -> w_fd, vt)) {
722 case VT_HARDKEY:
723 DisplayStatus (w -> w_fd, "no hardkeys, please");
724 break;
725
726 case VT_ASCII:
727 switch (c = toascii (vt -> u.ascii)) {
728 case '\f': /* refresh? */
729 break;
730
731 case '\r':
732 case '\n':
733 (void) strcpy (buffer, ip);
734 return DONE;
735
736 default:
737 if (c == INTR) {
738 adorn (NULLCP, "Interrupt");
739 return NOTOK;
740 }
741
742 if (c == EOFC) {
743 if (bp <= ip)
744 return OK;
745 break;
746 }
747
748 if (c == ERASE) {
749 if (bp <= ip)
750 continue;
751 bp--;
752 break;
753 }
754
755 if (c == KILL) {
756 if (bp <= ip)
757 continue;
758 bp = ip;
759 break;
760 }
761
762 if (c == WERASC) {
763 if (bp <= ip)
764 continue;
765 do {
766 bp--;
767 } while (isspace (*bp) && bp > ip);
768 if (bp > ip) {
769 do {
770 bp--;
771 } while (!isspace (*bp) && bp > buffer);
772 if (isspace (*bp))
773 bp++;
774 }
775 break;
776 }
777
778 if (c < ' ' || c >= '\177')
779 continue;
780 *bp++ = c;
781 break;
782 }
783 *bp = NULL;
784 Redisplay (w, 0);
785 break;
786
787 case VT_MOUSE:
788 switch (vt -> u.mouse.buttons
789 & (VT_MOUSE_LEFT | VT_MOUSE_MIDDLE | VT_MOUSE_RIGHT)) {
790 case VT_MOUSE_LEFT:
791 DisplayStatus (w -> w_fd, "use middle or right button");
792 break;
793
794 #define WPOP "WMH\0Advance\0Burst\0Exit\0EOF\0"
795 case VT_MOUSE_MIDDLE:
796 SetPosition (w -> w_fd, vt -> u.mouse.x,
797 vt -> u.mouse.y);
798 switch (DisplayPopUp (w -> w_fd, WPOP)) {
799 case 1: /* Advance */
800 do_advance: ;
801 (void) strcpy (buffer, "advance");
802 return DONE;
803
804 case 2: /* Burst */
805 (void) strcpy (buffer, "burst");
806 return DONE;
807
808 case 3: /* Exit */
809 (void) strcpy (buffer, "exit");
810 return DONE;
811
812 case 4: /* EOF */
813 return OK;
814
815 default: /* failed or none taken */
816 break;
817 }
818 break;
819 #undef WPOP
820
821 case VT_MOUSE_RIGHT:
822 goto do_advance;
823 }
824 break;
825
826 case VT_EOF:
827 adios (NULLCP, "end-of-file on window");/* NOTREACHED */
828
829 default:
830 DisplayStatus (w -> w_fd, "unknown VT sequence");
831 break;
832 }
833 }
834
835 /* \f */
836
837 static int WINputc (w, c)
838 register WINDOW *w;
839 register char c;
840 {
841 register int i;
842 register char *cp;
843 register struct line *lp;
844
845 switch (c) {
846 default:
847 if (!isascii (c)) {
848 if (WINputc (w, 'M') == NOTOK || WINputc (w, '-') == NOTOK)
849 return NOTOK;
850 c = toascii (c);
851 }
852 else
853 if (c < ' ' || c == '\177') {
854 if (WINputc (w, '^') == NOTOK)
855 return NOTOK;
856 c ^= 0100;
857 }
858 break;
859
860 case '\t':
861 for (i = 8 - (w -> w_bufpos & 0x07); i > 0; i--)
862 if (WINputc (w, ' ') == NOTOK)
863 return NOTOK;
864 return OK;
865
866 case '\b':
867 if (w -> w_bufpos > 0)
868 w -> w_bufpos--;
869 return OK;
870
871 case '\n':
872 break;
873 }
874
875 if (c != '\n') {
876 w -> w_buffer[w -> w_bufpos++] = c;
877 return OK;
878 }
879
880 w -> w_buffer[w -> w_bufpos] = NULL;
881 w -> w_bufpos = 0;
882
883 if ((lp = (struct line *) calloc (1, sizeof *lp)) == NULL)
884 adios (NULLCP, "unable to allocate line storage");
885
886 lp -> l_no = (w -> w_tail ? w -> w_tail -> l_no : 0) + 1;
887 lp -> l_buf = getcpy (w -> w_buffer);
888 for (cp = lp -> l_buf + strlen (lp -> l_buf) - 1; cp >= lp -> l_buf; cp--)
889 if (isspace (*cp))
890 *cp = NULL;
891 else
892 break;
893
894 if (w -> w_head == NULL)
895 w -> w_head = lp;
896 if (w -> w_top == NULL)
897 w -> w_top = lp;
898 if (w -> w_bottom == NULL)
899 w -> w_bottom = lp;
900 if (w -> w_tail)
901 w -> w_tail -> l_next = lp;
902 lp -> l_prev = w -> w_tail;
903 w -> w_tail = lp;
904
905 return DONE;
906 }
907
908 /* \f */
909
910 #define PSLOP 2
911
912
913 static char mylineno[5];
914
915 static bool cancel[] = { 1 };
916 static struct choice mychoices[] = { LABEL, "cancel", VT_White };
917
918 static struct question myquestions[] = {
919 STRING, "Line", SZ (mylineno), (struct choice *) 0,
920
921 TOGGLE, "", SZ (mychoices), mychoices
922 };
923
924 static struct menu mymenu = { "Goto", SZ (myquestions), myquestions };
925
926 static int *myanswers[] = { (int *) mylineno, (int *) cancel };
927
928
929 static WINless (w)
930 register WINDOW *w;
931 {
932 int clear,
933 pos,
934 forw,
935 refresh;
936 struct vtseq vts;
937 register struct vtseq *vt = &vts;
938
939 if (w -> w_fd == NOTOK) {
940 if (w -> w_head)
941 DisplayStatus (dfd, w -> w_top -> l_buf);
942 else
943 RemoveStatus (dfd);
944
945 return;
946 }
947
948 if (ChangeWindowDepth (dfd, w -> w_wd, 0) == NOTOK)
949 adios ("failed", "ChangeWindowDepth");
950
951 Redisplay (w, 0);
952
953 if (w -> w_bottom == w -> w_tail)
954 return;
955
956 if (w -> w_eb == NULL)
957 adios (NULLCP, "internal error--no elevator bar");
958
959 for (clear = refresh = 0, forw = 1;;) {
960 if (clear) {
961 RemoveStatus (w -> w_fd);
962 clear = 0;
963 }
964 if (refresh) {
965 Redisplay (w, 0);
966 refresh = 0;
967 }
968
969 switch (getvtseq (w -> w_fd, vt)) {
970 case VT_HARDKEY:
971 case VT_ASCII:
972 DisplayStatus (w -> w_fd, "use the mouse");
973 clear++;
974 break;
975
976 case VT_MOUSE:
977 switch (vt -> u.mouse.buttons
978 & (VT_MOUSE_LEFT | VT_MOUSE_MIDDLE | VT_MOUSE_RIGHT)) {
979 case VT_MOUSE_LEFT:
980 if ((pos = vt -> u.mouse.x) < EWIDTH) {
981 pos = w -> w_ebloc = DoElevatorBar (w -> w_eb, pos,
982 vt -> u.mouse.y);
983 refresh = WINgoto (w, ((pos * (w -> w_tail -> l_no
984 - w -> w_head -> l_no))
985 / EB_MAX) + w -> w_head -> l_no);
986 }
987 break;
988
989 #define WPOP "Paging\0Next\0Prev\0Left\0Right\0First\0Last\0Goto ...\0Exit\0"
990 case VT_MOUSE_MIDDLE:
991 SetPosition (w -> w_fd, vt -> u.mouse.x,
992 vt -> u.mouse.y);
993 switch (DisplayPopUp (w -> w_fd, WPOP)) {
994 case 1: /* Next */
995 do_next_page: ;
996 if (w -> w_bottom == w -> w_tail)
997 forw = 0;
998 refresh = WINgoto (w, w -> w_bottom -> l_no + 1 - PSLOP);
999 break;
1000
1001 case 2: /* Prev */
1002 do_prev_page: ;
1003 if (w -> w_top == w -> w_head)
1004 forw = 1;
1005 refresh = WINgoto (w, w -> w_top -> l_no
1006 - w -> w_height + PSLOP);
1007 break;
1008
1009 case 3: /* Left */
1010 case 4: /* Right */
1011 DisplayStatus (w -> w_fd, "not yet");
1012 clear++;
1013 break;
1014
1015 case 5: /* First */
1016 forw = 1;
1017 refresh = WINgoto (w, w -> w_head -> l_no);
1018 break;
1019
1020 case 6: /* Last */
1021 forw = 0;
1022 refresh = WINgoto (w, w -> w_tail -> l_no
1023 - w -> w_height + 1);
1024 break;
1025
1026 case 7: /* Goto ... */
1027 (void) sprintf (mylineno, "%d",
1028 w -> w_top -> l_no);
1029 cancel[0] = 0;
1030 if (PresentMenu (&mymenu, myanswers)
1031 || cancel[0])
1032 break;
1033 if (sscanf (mylineno, "%d", &pos) != 1) {
1034 DisplayStatus (w -> w_fd, "bad format");
1035 clear++;
1036 break;
1037 }
1038 if (pos < w -> w_head -> l_no
1039 || pos > w -> w_tail -> l_no) {
1040 DisplayStatus (w -> w_fd, "no such line");
1041 clear++;
1042 break;
1043 }
1044 refresh = WINgoto (w, pos);
1045 break;
1046
1047 case 8: /* Exit */
1048 return;
1049
1050 default: /* failed or none taken */
1051 break;
1052 }
1053 break;
1054 #undef WPOP
1055
1056 case VT_MOUSE_RIGHT:
1057 if (forw) {
1058 if (w -> w_bottom == w -> w_tail)
1059 return;
1060 else
1061 goto do_next_page;
1062 }
1063 else
1064 goto do_prev_page;
1065 }
1066 break;
1067
1068 case VT_EOF:
1069 adios (NULLCP, "end-of-file on window");/* NOTREACHED */
1070
1071 default:
1072 DisplayStatus (w -> w_fd, "unknown VT sequence");
1073 clear++;
1074 break;
1075 }
1076 }
1077 }
1078
1079 /* \f */
1080
1081 static int WINgoto (w, n)
1082 register WINDOW *w;
1083 register int n;
1084 {
1085 register int i,
1086 j;
1087 register struct line *lp;
1088
1089 if (n > (i = w -> w_tail -> l_no - w -> w_height + 1))
1090 n = i;
1091 if (n < w -> w_head -> l_no)
1092 n = w -> w_head -> l_no;
1093
1094 if ((i = n - (lp = w -> w_head) -> l_no)
1095 > (j = abs (n - w -> w_top -> l_no)))
1096 i = j, lp = w -> w_top;
1097
1098 if (i > (j = abs (w -> w_tail -> l_no - n)))
1099 i = j, lp = w -> w_tail;
1100
1101 if (n >= lp -> l_no) {
1102 for (; lp; lp = lp -> l_next)
1103 if (lp -> l_no == n)
1104 break;
1105 }
1106 else {
1107 for (; lp; lp = lp -> l_prev)
1108 if (lp -> l_no == n)
1109 break;
1110 if (!lp)
1111 lp = w -> w_head;
1112 }
1113
1114 if (w -> w_top == lp)
1115 return 0;
1116
1117 w -> w_top = lp;
1118
1119 return 1;
1120 }
1121
1122 /* \f */
1123
1124 static int ADJser (id, ww, wh)
1125 int id;
1126 short ww,
1127 wh;
1128 {
1129 register WINDOW *w;
1130
1131 if (id < 0 || id >= numwins)
1132 adios (NULLCP, "ADJser on bogus window (%d)", id);
1133 w = windows[id];
1134 if (w -> w_fd == NOTOK)
1135 adios (NULLCP, "ADJser on closed window (%d)", id);
1136
1137 w -> w_ws.width = w -> w_ws.tw = ww;
1138 w -> w_ws.height = w -> w_ws.th = wh;
1139
1140 if (w -> w_eb) {
1141 DeleteElevatorBar (w -> w_eb);
1142 w -> w_eb = CreateElevatorBar (w -> w_fd, 0, 0, EWIDTH,
1143 w -> w_ws.height, VT_Gray50, 1, EB_VERTICAL,
1144 EB_ARROWS, w -> w_ebloc = 0, w -> w_ebsize = EB_MAX,
1145 VT_White);
1146 if (w -> w_eb == NULL)
1147 adios (NULLCP, "CreateElevatorBar failed");
1148 }
1149
1150 Redisplay (w, 1);
1151 }
1152
1153
1154 /* ARGSUSED */
1155
1156 static int REFser (id, wx, wy, ww, wh)
1157 int id;
1158 short wx,
1159 wy,
1160 ww,
1161 wh;
1162 {
1163 short cx,
1164 cy,
1165 cw,
1166 ch;
1167 register WINDOW *w;
1168
1169 if (id < 0 || id >= numwins)
1170 adios (NULLCP, "REFser on bogus window (%d)", id);
1171 w = windows[id];
1172 if (w -> w_fd == NOTOK)
1173 adios (NULLCP, "REFser on closed window (%d)", id);
1174
1175
1176 if (GetWindowState (w -> w_fd, &w -> w_ws) == NOTOK)
1177 adios ("failed", "GetWindowState");
1178
1179 GetPermanentClipping (w -> w_fd, &cx, &cy, &cw, &ch);
1180 SetPermanentClipping (w -> w_fd, wx, wy, ww, wh);
1181 Redisplay (w, 1);
1182 SetPermanentClipping (w -> w_fd, cx, cy, cw, ch);
1183 }
1184
1185 /* \f */
1186
1187 static Redisplay (w, doeb)
1188 register WINDOW *w;
1189 int doeb;
1190 {
1191 register int y;
1192 short sx;
1193 register struct line *lp;
1194
1195 if (w -> w_fd == NOTOK)
1196 return;
1197
1198 sx = w -> w_eb ? (EWIDTH + ESLOP) : 0;
1199 w -> w_height = w -> w_ws.height / w -> w_cheight;
1200 if (w -> w_height < 1)
1201 w -> w_height = 1;
1202
1203 w -> w_width = (w -> w_ws.width - (w -> w_eb ? (EWIDTH + ESLOP) : 0))
1204 / w -> w_cwidth;
1205 if (w -> w_width < 1)
1206 w -> w_width = 1;
1207
1208 SetPosition (w -> w_fd, sx, 0);
1209 SetColor (w -> w_fd, VT_White);
1210 PaintRectangleInterior (w -> w_fd, w -> w_ws.width, w -> w_ws.height);
1211
1212 if (w -> w_head) {
1213 SetColor (w -> w_fd, VT_Black);
1214 for (lp = w -> w_top, y = 0;
1215 lp && y < w -> w_height;
1216 w -> w_bottom = lp, lp = lp -> l_next, y++) {
1217 SetPosition (w -> w_fd, sx, y * w -> w_cheight + w -> w_cbase);
1218 PaintString (w -> w_fd, VT_STREND, lp -> l_buf);
1219 }
1220 }
1221
1222 if (w -> w_eb) {
1223 if ((y = EB_LOC (w)) != w -> w_ebloc)
1224 MoveElevator (w -> w_eb, w -> w_ebloc = y);
1225 if ((y = EB_SIZE (w)) != w -> w_ebsize)
1226 SizeElevator (w -> w_eb, w -> w_ebsize = y);
1227 if (doeb)
1228 RefreshElevatorBar (w -> w_eb);
1229 }
1230
1231 Flush (w -> w_fd);
1232 }
1233
1234 /* \f */
1235
1236 static int EB_SIZE (w)
1237 register WINDOW *w;
1238 {
1239 register int i;
1240
1241 if (w -> w_head == NULL)
1242 return 0;
1243
1244 if ((i = w -> w_tail -> l_no - w -> w_head -> l_no) <= 0)
1245 return EB_MAX;
1246
1247 return (((w -> w_bottom -> l_no - w -> w_top -> l_no) * EB_MAX) / i);
1248 }
1249
1250
1251 static int EB_LOC (w)
1252 register WINDOW *w;
1253 {
1254 register int i;
1255
1256 if (w -> w_head == NULL)
1257 return 0;
1258
1259 if ((i = w -> w_tail -> l_no - w -> w_head -> l_no) <= 0)
1260 return EB_MAX;
1261
1262 return (((w -> w_top -> l_no - w -> w_head -> l_no) * EB_MAX) / i);
1263 }
1264
1265 /* \f SIGNALS */
1266
1267 static SIGinit () {
1268 foreground ();
1269 if (ioctl (fileno (stdin), TIOCGETP, (char *) &sg) == NOTOK)
1270 adios ("failed", "ioctl TIOCGETP");
1271 if (ioctl (fileno (stdin), TIOCGETC, (char *) &tc) == NOTOK)
1272 adios ("failed", "ioctl TIOCGETC");
1273 if (ioctl (fileno (stdin), TIOCGLTC, (char *) &ltc) == NOTOK)
1274 adios ("failed", "ioctl TIOCGLTC");
1275 sideground ();
1276
1277 (void) signal (SIGHUP, SIGser);
1278 (void) signal (SIGINT, SIGser);
1279 (void) signal (SIGQUIT, SIGser);
1280 }
1281
1282 /* \f */
1283
1284 static foreground () {
1285 #ifdef TIOCGPGRP
1286 int pgrp,
1287 tpgrp;
1288 TYPESIG (*tstat) ();
1289
1290 if ((pgrp = getpgrp (0)) == NOTOK)
1291 adios ("process group", "unable to determine");
1292 for (;;) {
1293 if (ioctl (fileno (stdin), TIOCGPGRP, (char *) &tpgrp) == NOTOK)
1294 adios ("tty's process group", "unable to determine");
1295 if (pgrp == tpgrp)
1296 break;
1297
1298 tstat = signal (SIGTTIN, SIG_DFL);
1299 (void) kill (0, SIGTTIN);
1300 (void) signal (SIGTTIN, tstat);
1301 }
1302
1303 (void) signal (SIGTTIN, SIG_IGN);
1304 (void) signal (SIGTTOU, SIG_IGN);
1305 (void) signal (SIGTSTP, SIG_IGN);
1306 #endif TIOCGPGRP
1307 }
1308
1309
1310 static sideground () {
1311 #ifdef TIOCGPGRP
1312 (void) signal (SIGTTIN, SIG_DFL);
1313 (void) signal (SIGTTOU, SIG_DFL);
1314 (void) signal (SIGTSTP, SIG_DFL);
1315 #endif TIOCGPGRP
1316 }
1317
1318 /* \f */
1319
1320 /* ARGSUSED */
1321
1322 static int ALRMser (sig)
1323 int sig;
1324 {
1325 longjmp (PEERctx, DONE);
1326 }
1327
1328
1329 #ifdef BSD42
1330 /* ARGSUSED */
1331 #endif BSD42
1332
1333 static int PIPEser (sig)
1334 int sig;
1335 {
1336 #ifndef BSD42
1337 (void) signal (sig, SIG_IGN);
1338 #endif BSD42
1339
1340 adios (NULLCP, "lost peer");
1341 }
1342
1343
1344 #ifdef BSD42
1345 /* ARGSUSED */
1346 #endif BSD42
1347
1348 static int SIGser (sig)
1349 int sig;
1350 {
1351 #ifndef BSD42
1352 (void) signal (sig, SIG_IGN);
1353 #endif BSD42
1354
1355 done (1);
1356 }
1357
1358 /* \f MISCELLANY */
1359
1360 void done (status)
1361 int status;
1362 {
1363 if (dfd != NOTOK)
1364 RemoveStatus (dfd);
1365
1366 (void) pFIN ();
1367
1368 exit (status);
1369 }
1370
1371 /* \f */
1372
1373 /* VARARGS2 */
1374
1375 static void adorn (what, fmt, a, b, c, d, e, f)
1376 char *what,
1377 *fmt,
1378 *a,
1379 *b,
1380 *c,
1381 *d,
1382 *e,
1383 *f;
1384 {
1385 char *cp = invo_name;
1386
1387 invo_name = NULL;
1388 advise (what, fmt, a, b, c, d, e, f);
1389 invo_name = cp;
1390 }
1391
1392 /* \f */
1393
1394 /* VARARGS3 */
1395
1396 void advertise (what, tail, fmt, a, b, c, d, e, f)
1397 char *what,
1398 *tail,
1399 *fmt,
1400 *a,
1401 *b,
1402 *c,
1403 *d,
1404 *e,
1405 *f;
1406 {
1407 int eindex = errno;
1408 char buffer[BUFSIZ],
1409 err[BUFSIZ];
1410 struct iovec iob[20];
1411 register struct iovec *iov = iob;
1412
1413 (void) fflush (stdout);
1414
1415 (void) fflush (stderr);
1416
1417 if (invo_name) {
1418 iov -> iov_len = strlen (iov -> iov_base = invo_name);
1419 iov++;
1420 iov -> iov_len = strlen (iov -> iov_base = ": ");
1421 iov++;
1422 }
1423
1424 (void) sprintf (buffer, fmt, a, b, c, d, e, f);
1425 iov -> iov_len = strlen (iov -> iov_base = buffer);
1426 iov++;
1427 if (what) {
1428 if (*what) {
1429 iov -> iov_len = strlen (iov -> iov_base = " ");
1430 iov++;
1431 iov -> iov_len = strlen (iov -> iov_base = what);
1432 iov++;
1433 iov -> iov_len = strlen (iov -> iov_base = ": ");
1434 iov++;
1435 }
1436 if (eindex > 0 && eindex < sys_nerr)
1437 iov -> iov_len = strlen (iov -> iov_base = sys_errlist[eindex]);
1438 else {
1439 (void) sprintf (err, "Error %d", eindex);
1440 iov -> iov_len = strlen (iov -> iov_base = err);
1441 }
1442 iov++;
1443 }
1444 if (tail && *tail) {
1445 iov -> iov_len = strlen (iov -> iov_base = ", ");
1446 iov++;
1447 iov -> iov_len = strlen (iov -> iov_base = tail);
1448 iov++;
1449 }
1450 iov -> iov_len = strlen (iov -> iov_base = "\n");
1451 iov++;
1452
1453 if (dfd != NOTOK)
1454 (void) DisplayVector (iob, iov - iob);
1455 else
1456 (void) writev (fileno (stderr), iob, iov - iob);
1457 }
1458
1459 /* \f */
1460
1461 static DisplayVector (iov, n)
1462 register struct iovec *iov;
1463 register int n;
1464 {
1465 register int i;
1466 register char *cp;
1467 char buffer[BUFSIZ];
1468
1469 for (i = 0, cp = NULL; i < n; i++, iov++) {
1470 (void) sprintf (buffer, "%*.*s", iov -> iov_len, iov -> iov_len,
1471 iov -> iov_base);
1472 cp = add (buffer, cp);
1473 }
1474
1475 DisplayStatus (dfd, cp);
1476
1477 free (cp);
1478
1479 sleep (PAUSE);
1480
1481 RemoveStatus (dfd);
1482 }