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