source: trunk/third/nmh/uip/wmh.c @ 12455

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