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 *) <c) == 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