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

Defined functions

ALRMser defined in line 1261; used 2 times
PEERinit defined in line 257; used 1 times
PIPEser defined in line 1272; used 2 times
SIGser defined in line 1287; used 4 times
TSTPser defined in line 1299; used 3 times
TTYinit defined in line 1124; used 1 times
TTYoff defined in line 1187; used 4 times
TTYon defined in line 1157; used 3 times
WINgetstr defined in line 642; used 1 times
WINinit defined in line 591; used 1 times
WINless defined in line 770; used 3 times
WINputc defined in line 974; used 3 times
WINwritev defined in line 731; used 1 times
adorn defined in line 1336; used 8 times
advertise defined in line 1357; never used
done defined in line 1323; used 6 times
foreground defined in line 1223; used 2 times
ladvance defined in line 1054; used 2 times
lgo defined in line 1090; used 4 times
linsert defined in line 1025; used 1 times
lreset defined in line 1012; used 1 times
lretreat defined in line 1071; used 2 times
main defined in line 153; never used
pFIN defined in line 560; used 1 times
pINI defined in line 303; used 1 times
pLOOP defined in line 341; used 2 times
pTTY defined in line 401; used 1 times
pWIN defined in line 473; used 1 times
pWINaux defined in line 489; used 1 times
sideground defined in line 1249; used 2 times
vmh defined in line 229; used 1 times
writev defined in line 1423; used 1 times

Defined variables

PEERctx defined in line 66; used 2 times
PEERpid defined in line 64; used 7 times
did_less defined in line 95; used 3 times
intrc defined in line 104; used 3 times
largemove defined in line 97; used 6 times
lhead defined in line 91; used 7 times
ltail defined in line 93; used 15 times
ltc defined in line 125; used 2 times
ltop defined in line 92; used 21 times
myprompt defined in line 70; used 3 times
numwins defined in line 78; used 7 times
sg defined in line 118; used 10 times
smallmove defined in line 96; used 5 times
switches defined in line 47; used 3 times
tc defined in line 112; used 5 times
tty_ready defined in line 102; used 7 times

Defined struct's

iovec defined in line 26; used 8 times
line defined in line 84; used 24 times

Defined macros

ALARM defined in line 35; used 1 times
EOFC defined in line 116; used 2 times
ERASE defined in line 114; used 1 times
HELPSW defined in line 56; never used
INTR defined in line 117; used 3 times
KILL defined in line 115; used 1 times
LARGEMOVE defined in line 40; used 1 times
  • in line 97
NPROGSW defined in line 53; never used
NWIN defined in line 77; used 1 times
  • in line 79
PAUSE defined in line 36; used 1 times
PRMPTSW defined in line 48; never used
PROGSW defined in line 51; never used
SMALLMOVE defined in line 39; used 1 times
  • in line 96
WERASC defined in line 124; used 1 times
XYZ defined in line 43; used 4 times
abs defined in line 38; used 2 times
sigmask defined in line 23; used 3 times
Last modified: 1986-01-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4281
Valid CSS Valid XHTML 1.0 Strict