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

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