1 /*- 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)termout.c 4.5 (Berkeley) 05/11/93"; 10 #endif /* not lint */ 11 12 #if defined(unix) 13 #include <signal.h> 14 #include <sgtty.h> 15 #endif 16 #include <stdio.h> 17 #include <curses.h> 18 #if defined(ultrix) 19 /* Some version of this OS has a bad definition for nonl() */ 20 #undef nl 21 #undef nonl 22 23 #define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty)) 24 #define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty)) 25 #endif /* defined(ultrix) */ 26 27 #include "../general/general.h" 28 29 #include "terminal.h" 30 31 #include "../api/disp_asc.h" 32 33 #include "../ctlr/hostctlr.h" 34 #include "../ctlr/externs.h" 35 #include "../ctlr/declare.h" 36 #include "../ctlr/oia.h" 37 #include "../ctlr/screen.h" 38 #include "../ctlr/scrnctlr.h" 39 40 #include "../general/globals.h" 41 42 #include "telextrn.h" 43 44 #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 45 CursorAddress:UnLocked? CursorAddress: HighestScreen()) 46 47 48 static int terminalCursorAddress; /* where the cursor is on term */ 49 static int screenInitd; /* the screen has been initialized */ 50 static int screenStopped; /* the screen has been stopped */ 51 static int max_changes_before_poll; /* how many characters before looking */ 52 /* at terminal and net again */ 53 54 static int needToRing; /* need to ring terinal bell */ 55 static char *bellSequence = "\07"; /* bell sequence (may be replaced by 56 * VB during initialization) 57 */ 58 static WINDOW *bellwin = 0; /* The window the bell message is in */ 59 int bellwinup = 0; /* Are we up with it or not */ 60 61 #if defined(unix) 62 static char *myKS, *myKE; 63 #endif /* defined(unix) */ 64 65 66 static int inHighlightMode = 0; 67 ScreenImage Terminal[MAXSCREENSIZE]; 68 69 /* Variables for transparent mode */ 70 #if defined(unix) 71 static int tcflag = -1; /* transparent mode command flag */ 72 static int savefd[2]; /* for storing fds during transcom */ 73 extern int tin, tout; /* file descriptors */ 74 #endif /* defined(unix) */ 75 76 77 /* 78 * init_screen() 79 * 80 * Initialize variables used by screen. 81 */ 82 83 void 84 init_screen() 85 { 86 bellwinup = 0; 87 inHighlightMode = 0; 88 ClearArray(Terminal); 89 } 90 91 92 /* OurExitString - designed to keep us from going through infinite recursion */ 93 94 static void 95 OurExitString(string, value) 96 char *string; 97 int value; 98 { 99 static int recursion = 0; 100 101 if (!recursion) { 102 recursion = 1; 103 ExitString(string, value); 104 } 105 } 106 107 108 /* DoARefresh */ 109 110 static void 111 DoARefresh() 112 { 113 if (ERR == refresh()) { 114 OurExitString("ERR from refresh\n", 1); 115 } 116 } 117 118 static void 119 GoAway(from, where) 120 char *from; /* routine that gave error */ 121 int where; /* cursor address */ 122 { 123 char foo[100]; 124 125 sprintf(foo, "ERR from %s at %d (%d, %d)\n", 126 from, where, ScreenLine(where), ScreenLineOffset(where)); 127 OurExitString(foo, 1); 128 /* NOTREACHED */ 129 } 130 131 /* What is the screen address of the attribute byte for the terminal */ 132 133 static int 134 WhereTermAttrByte(p) 135 register int p; 136 { 137 register int i; 138 139 i = p; 140 141 do { 142 if (TermIsStartField(i)) { 143 return(i); 144 } 145 i = ScreenDec(i); 146 } while (i != p); 147 148 return(LowestScreen()); /* unformatted screen... */ 149 } 150 151 /* 152 * There are two algorithms for updating the screen. 153 * The first, SlowScreen() optimizes the line between the 154 * computer and the screen (say a 9600 baud line). To do 155 * this, we break out of the loop every so often to look 156 * at any pending input from the network (so that successive 157 * screens will only partially print until the final screen, 158 * the one the user possibly wants to see, is displayed 159 * in its entirety). 160 * 161 * The second algorithm tries to optimize CPU time (by 162 * being simpler) at the cost of the bandwidth to the 163 * screen. 164 * 165 * Of course, curses(3X) gets in here also. 166 */ 167 168 169 #if defined(NOT43) 170 static int 171 #else /* defined(NOT43) */ 172 static void 173 #endif /* defined(NOT43) */ 174 SlowScreen() 175 { 176 register int is, shouldbe, isattr, shouldattr; 177 register int pointer; 178 register int fieldattr, termattr; 179 register int columnsleft; 180 181 #define NORMAL 0 182 #define HIGHLIGHT 1 /* Mask bits */ 183 #define NONDISPLAY 4 /* Mask bits */ 184 #define UNDETERMINED 8 /* Mask bits */ 185 186 #define DoAttributes(x) \ 187 switch (x&ATTR_DSPD_MASK) { \ 188 case ATTR_DSPD_NONDISPLAY: \ 189 x = NONDISPLAY; \ 190 break; \ 191 case ATTR_DSPD_HIGH: \ 192 x = HIGHLIGHT; \ 193 break; \ 194 default: \ 195 x = 0; \ 196 break; \ 197 } 198 199 # define SetHighlightMode(x) \ 200 { \ 201 if ((x)&HIGHLIGHT) { \ 202 if (!inHighlightMode) { \ 203 inHighlightMode = HIGHLIGHT; \ 204 standout(); \ 205 } \ 206 } else { \ 207 if (inHighlightMode) { \ 208 inHighlightMode = 0; \ 209 standend(); \ 210 } \ 211 } \ 212 } 213 214 # define DoCharacterAt(c,p) { \ 215 if (p != HighestScreen()) { \ 216 c = disp_asc[c&0xff]; \ 217 if (terminalCursorAddress != p) { \ 218 if (ERR == mvaddch(ScreenLine(p), \ 219 ScreenLineOffset(p), c)) {\ 220 GoAway("mvaddch", p); \ 221 } \ 222 } else { \ 223 if (ERR == addch(c)) {\ 224 GoAway("addch", p); \ 225 } \ 226 } \ 227 terminalCursorAddress = ScreenInc(p); \ 228 } \ 229 } 230 231 232 /* run through screen, printing out non-null lines */ 233 234 /* There are two separate reasons for wanting to terminate this 235 * loop early. One is to respond to new input (either from 236 * the terminal or from the network [host]). For this reason, 237 * we expect to see 'HaveInput' come true when new input comes in. 238 * 239 * The second reason is a bit more difficult (for me) to understand. 240 * Basically, we don't want to get too far ahead of the characters that 241 * appear on the screen. Ideally, we would type out a few characters, 242 * wait until they appeared on the screen, then type out a few more. 243 * The reason for this is that the user, on seeing some characters 244 * appear on the screen may then start to type something. We would 245 * like to look at what the user types at about the same 'time' 246 * (measured by characters being sent to the terminal) that the 247 * user types them. For this reason, what we would like to do 248 * is update a bit, then call curses to do a refresh, flush the 249 * output to the terminal, then wait until the terminal data 250 * has been sent. 251 * 252 * Note that curses is useful for, among other things, deciding whether 253 * or not to send :ce: (clear to end of line), so we should call curses 254 * at end of lines (beginning of next lines). 255 * 256 * The problems here are the following: If we do lots of write(2)s, 257 * we will be doing lots of context switches, thus lots of overhead 258 * (which we have already). Second, if we do a select to wait for 259 * the output to drain, we have to contend with the fact that NOW 260 * we are scheduled to run, but who knows what the scheduler will 261 * decide when the output has caught up. 262 */ 263 264 if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */ 265 Highest = ScreenDec(Highest); /* else, while loop will never end */ 266 } 267 if (Lowest < LowestScreen()) { 268 Lowest = LowestScreen(); /* could be -1 in some cases with 269 * unformatted screens. 270 */ 271 } 272 if (Highest >= (pointer = Lowest)) { 273 /* if there is anything to do, do it. We won't terminate 274 * the loop until we've gone at least to Highest. 275 */ 276 while ((pointer <= Highest) && !HaveInput) { 277 278 /* point at the next place of disagreement */ 279 pointer += (bunequal(Host+pointer, Terminal+pointer, 280 (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 281 282 /* 283 * How many characters to change until the end of the 284 * current line 285 */ 286 columnsleft = NumberColumns - ScreenLineOffset(pointer); 287 /* 288 * Make sure we are where we think we are. 289 */ 290 move(ScreenLine(pointer), ScreenLineOffset(pointer)); 291 292 /* what is the field attribute of the current position */ 293 if (FormattedScreen()) { 294 fieldattr = FieldAttributes(pointer); 295 DoAttributes(fieldattr); 296 } else { 297 fieldattr = NORMAL; 298 } 299 if (TerminalFormattedScreen()) { 300 termattr = TermAttributes(pointer); 301 DoAttributes(termattr); 302 } else { 303 termattr = NORMAL; 304 } 305 306 SetHighlightMode(fieldattr); 307 /* 308 * The following will terminate at least when we get back 309 * to the original 'pointer' location (since we force 310 * things to be equal). 311 */ 312 for (;;) { 313 if (IsStartField(pointer)) { 314 shouldbe = DISP_BLANK; 315 shouldattr = 0; 316 fieldattr = GetHost(pointer); 317 DoAttributes(fieldattr); 318 } else { 319 if (fieldattr&NONDISPLAY) { 320 shouldbe = DISP_BLANK; 321 } else { 322 shouldbe = GetHost(pointer); 323 } 324 shouldattr = fieldattr; 325 } 326 if (TermIsStartField(pointer)) { 327 is = DISP_BLANK; 328 isattr = 0; 329 termattr = UNDETERMINED; /* Need to find out AFTER update */ 330 } else { 331 if (termattr&NONDISPLAY) { 332 is = DISP_BLANK; 333 } else { 334 is = GetTerminal(pointer); 335 } 336 isattr = termattr; 337 } 338 if ((shouldbe == is) && (shouldattr == isattr) 339 && (GetHost(pointer) == GetTerminal(pointer)) 340 && (GetHost(ScreenInc(pointer)) 341 == GetTerminal(ScreenInc(pointer)))) { 342 break; 343 } 344 345 if (shouldattr^inHighlightMode) { 346 SetHighlightMode(shouldattr); 347 } 348 349 DoCharacterAt(shouldbe, pointer); 350 if (IsStartField(pointer)) { 351 TermNewField(pointer, FieldAttributes(pointer)); 352 termattr = GetTerminal(pointer); 353 DoAttributes(termattr); 354 } else { 355 SetTerminal(pointer, GetHost(pointer)); 356 /* 357 * If this USED to be a start field location, 358 * recompute the terminal attributes. 359 */ 360 if (termattr == UNDETERMINED) { 361 termattr = WhereTermAttrByte(pointer); 362 if ((termattr != 0) || TermIsStartField(0)) { 363 termattr = GetTerminal(termattr); 364 DoAttributes(termattr); 365 } else { /* Unformatted screen */ 366 termattr = NORMAL; 367 } 368 } 369 } 370 pointer = ScreenInc(pointer); 371 if (!(--columnsleft)) { 372 DoARefresh(); 373 EmptyTerminal(); 374 if (HaveInput) { /* if input came in, take it */ 375 int c, j; 376 377 /* 378 * We need to start a new terminal field 379 * at this location iff the terminal attributes 380 * of this location are not what we have had 381 * them as (ie: we've overwritten the terminal 382 * start field, a the previous field had different 383 * display characteristics). 384 */ 385 386 isattr = TermAttributes(pointer); 387 DoAttributes(isattr); 388 if ((!TermIsStartField(pointer)) && 389 (isattr != termattr)) { 390 /* 391 * Since we are going to leave a new field 392 * at this terminal position, we 393 * need to make sure that we get an actual 394 * non-highlighted blank on the screen. 395 */ 396 if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) { 397 SetHighlightMode(0); /* Turn off highlight */ 398 c = ScreenInc(pointer); 399 j = DISP_BLANK; 400 DoCharacterAt(j, c); 401 } 402 if (termattr&HIGHLIGHT) { 403 termattr = ATTR_DSPD_HIGH; 404 } else if (termattr&NONDISPLAY) { 405 termattr = ATTR_DSPD_NONDISPLAY; 406 } else { 407 termattr = 0; 408 } 409 TermNewField(pointer, termattr); 410 } 411 break; 412 } 413 move(ScreenLine(pointer), 0); 414 columnsleft = NumberColumns; 415 } 416 } /* end of for (;;) */ 417 } /* end of while (...) */ 418 } 419 DoARefresh(); 420 Lowest = pointer; 421 if (Lowest > Highest) { /* if we finished input... */ 422 Lowest = HighestScreen()+1; 423 Highest = LowestScreen()-1; 424 terminalCursorAddress = CorrectTerminalCursor(); 425 if (ERR == move(ScreenLine(terminalCursorAddress), 426 ScreenLineOffset(terminalCursorAddress))) { 427 GoAway("move", terminalCursorAddress); 428 } 429 DoARefresh(); 430 if (needToRing) { 431 StringToTerminal(bellSequence); 432 needToRing = 0; 433 } 434 } 435 EmptyTerminal(); /* move data along */ 436 return; 437 } 438 439 #if defined(NOT43) 440 static int 441 #else /* defined(NOT43) */ 442 static void 443 #endif /* defined(NOT43) */ 444 FastScreen() 445 { 446 #if defined(MSDOS) 447 #define SaveCorner 0 448 #else /* defined(MSDOS) */ 449 #define SaveCorner 1 450 #endif /* defined(MSDOS) */ 451 452 #define DoAttribute(a) if (IsHighlightedAttr(a)) { \ 453 standout(); \ 454 } else { \ 455 standend(); \ 456 } \ 457 if (IsNonDisplayAttr(a)) { \ 458 a = 0; /* zero == don't display */ \ 459 } \ 460 if (!FormattedScreen()) { \ 461 a = 1; /* one ==> do display on unformatted */\ 462 } 463 ScreenImage *p, *upper; 464 int fieldattr; /* spends most of its time == 0 or 1 */ 465 466 /* OK. We want to do this a quickly as possible. So, we assume we 467 * only need to go from Lowest to Highest. However, if we find a 468 * field in the middle, we do the whole screen. 469 * 470 * In particular, we separate out the two cases from the beginning. 471 */ 472 if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 473 register int columnsleft; 474 475 move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); 476 p = &Host[Lowest]; 477 #if !defined(MSDOS) 478 if (Highest == HighestScreen()) { 479 Highest = ScreenDec(Highest); 480 } 481 #endif /* !defined(MSDOS) */ 482 upper = &Host[Highest]; 483 fieldattr = FieldAttributes(Lowest); 484 DoAttribute(fieldattr); /* Set standout, non-display status */ 485 columnsleft = NumberColumns-ScreenLineOffset(p-Host); 486 487 while (p <= upper) { 488 if (IsStartFieldPointer(p)) { /* New field? */ 489 Highest = HighestScreen(); 490 Lowest = LowestScreen(); 491 FastScreen(); /* Recurse */ 492 return; 493 } else if (fieldattr) { /* Should we display? */ 494 /* Display translated data */ 495 addch((char)disp_asc[GetTerminalPointer(p)]); 496 } else { 497 addch(' '); /* Display a blank */ 498 } 499 /* If the physical screen is larger than what we 500 * are using, we need to make sure that each line 501 * starts at the beginning of the line. Otherwise, 502 * we will just string all the lines together. 503 */ 504 p++; 505 if (--columnsleft == 0) { 506 int i = p-Host; 507 508 move(ScreenLine(i), 0); 509 columnsleft = NumberColumns; 510 } 511 } 512 } else { /* Going from Lowest to Highest */ 513 unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; 514 ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; 515 register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; 516 517 *tmpend = 0; /* terminate from the beginning */ 518 move(0,0); 519 p = Host; 520 fieldattr = FieldAttributes(LowestScreen()); 521 DoAttribute(fieldattr); /* Set standout, non-display status */ 522 523 while (p <= End) { 524 if (IsStartFieldPointer(p)) { /* New field? */ 525 if (tmp != tmpbuf) { 526 *tmp++ = 0; /* close out */ 527 addstr((char *)tmpbuf); 528 tmp = tmpbuf; 529 tmpend = tmpbuf+NumberColumns-ScreenLineOffset(p-Host)-1; 530 } 531 standend(); 532 addch(' '); 533 fieldattr = FieldAttributesPointer(p); /* Get attributes */ 534 DoAttribute(fieldattr); /* Set standout, non-display */ 535 } else { 536 if (fieldattr) { /* Should we display? */ 537 /* Display translated data */ 538 *tmp++ = disp_asc[GetTerminalPointer(p)]; 539 } else { 540 *tmp++ = ' '; 541 } 542 } 543 /* If the physical screen is larger than what we 544 * are using, we need to make sure that each line 545 * starts at the beginning of the line. Otherwise, 546 * we will just string all the lines together. 547 */ 548 p++; 549 if (tmp == tmpend) { 550 int i = p-Host; /* Be sure the "p++" happened first! */ 551 552 *tmp++ = 0; 553 addstr((char *)tmpbuf); 554 tmp = tmpbuf; 555 move(ScreenLine(i), 0); 556 tmpend = tmpbuf + NumberColumns; 557 } 558 } 559 if (tmp != tmpbuf) { 560 *tmp++ = 0; 561 addstr((char *)tmpbuf); 562 tmp = tmpbuf; 563 } 564 } 565 Lowest = HighestScreen()+1; 566 Highest = LowestScreen()-1; 567 terminalCursorAddress = CorrectTerminalCursor(); 568 if (ERR == move(ScreenLine(terminalCursorAddress), 569 ScreenLineOffset(terminalCursorAddress))) { 570 GoAway("move", terminalCursorAddress); 571 } 572 DoARefresh(); 573 if (needToRing) { 574 StringToTerminal(bellSequence); 575 needToRing = 0; 576 } 577 EmptyTerminal(); /* move data along */ 578 return; 579 } 580 581 582 /* TryToSend - send data out to user's terminal */ 583 584 #if defined(NOT43) 585 int 586 #else /* defined(NOT43) */ 587 void 588 #endif /* defined(NOT43) */ 589 (*TryToSend)() = FastScreen; 590 591 /*ARGSUSED*/ 592 void 593 ScreenOIA(oia) 594 OIA *oia; 595 { 596 } 597 598 599 /* InitTerminal - called to initialize the screen, etc. */ 600 601 void 602 InitTerminal() 603 { 604 #if defined(unix) 605 struct sgttyb ourttyb; 606 static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 607 2400, 4800, 9600 }; 608 #endif 609 extern void InitMapping(); 610 611 InitMapping(); /* Go do mapping file (MAP3270) first */ 612 if (!screenInitd) { /* not initialized */ 613 #if defined(unix) 614 char KSEbuffer[2050]; 615 char *lotsofspace = KSEbuffer; 616 extern void abort(); 617 extern char *tgetstr(); 618 #endif /* defined(unix) */ 619 620 if (initscr() == ERR) { /* Initialize curses to get line size */ 621 ExitString("InitTerminal: Error initializing curses", 1); 622 /*NOTREACHED*/ 623 } 624 MaxNumberLines = LINES; 625 MaxNumberColumns = COLS; 626 ClearArray(Terminal); 627 terminalCursorAddress = SetBufferAddress(0,0); 628 #if defined(unix) 629 signal(SIGHUP, abort); 630 #endif 631 632 TryToSend = FastScreen; 633 #if defined(unix) 634 ioctl(1, TIOCGETP, (char *) &ourttyb); 635 if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 636 max_changes_before_poll = 1920; 637 } else { 638 max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 639 if (max_changes_before_poll < 40) { 640 max_changes_before_poll = 40; 641 } 642 TryToSend = SlowScreen; 643 HaveInput = 1; /* get signals going */ 644 } 645 #endif /* defined(unix) */ 646 setcommandmode(); 647 /* 648 * By now, initscr() (in curses) has been called (from telnet.c), 649 * and the screen has been initialized. 650 */ 651 #if defined(unix) 652 nonl(); 653 /* the problem is that curses catches SIGTSTP to 654 * be nice, but it messes us up. 655 */ 656 signal(SIGTSTP, SIG_DFL); 657 if ((myKS = tgetstr("ks", &lotsofspace)) != 0) { 658 myKS = strsave(myKS); 659 StringToTerminal(myKS); 660 } 661 if ((myKE = tgetstr("ke", &lotsofspace)) != 0) { 662 myKE = strsave(myKE); 663 } 664 if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 665 SO = strsave(tgetstr("md", &lotsofspace)); 666 SE = strsave(tgetstr("me", &lotsofspace)); 667 } 668 #endif 669 DoARefresh(); 670 setconnmode(); 671 if (VB && *VB) { 672 bellSequence = VB; /* use visual bell */ 673 } 674 screenInitd = 1; 675 screenStopped = 0; /* Not stopped */ 676 } 677 } 678 679 680 /* StopScreen - called when we are going away... */ 681 682 void 683 StopScreen(doNewLine) 684 int doNewLine; 685 { 686 if (screenInitd && !screenStopped) { 687 move(NumberLines-1, 1); 688 standend(); 689 inHighlightMode = 0; 690 DoARefresh(); 691 setcommandmode(); 692 endwin(); 693 setconnmode(); 694 #if defined(unix) 695 if (myKE) { 696 StringToTerminal(myKE); 697 } 698 #endif /* defined(unix) */ 699 if (doNewLine) { 700 StringToTerminal("\r\n"); 701 } 702 EmptyTerminal(); 703 screenStopped = 1; /* This is stopped */ 704 } 705 } 706 707 708 /* RefreshScreen - called to cause the screen to be refreshed */ 709 710 void 711 RefreshScreen() 712 { 713 clearok(curscr, TRUE); 714 (*TryToSend)(); 715 } 716 717 718 /* ConnectScreen - called to reconnect to the screen */ 719 720 void 721 ConnectScreen() 722 { 723 if (screenInitd) { 724 #if defined(unix) 725 if (myKS) { 726 StringToTerminal(myKS); 727 } 728 #endif /* defined(unix) */ 729 RefreshScreen(); 730 (*TryToSend)(); 731 screenStopped = 0; 732 } 733 } 734 735 /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 736 737 void 738 LocalClearScreen() 739 { 740 extern void Clear3270(); 741 742 outputPurge(); /* flush all data to terminal */ 743 clear(); /* clear in curses */ 744 ClearArray(Terminal); 745 Clear3270(); 746 Lowest = HighestScreen()+1; /* everything in sync... */ 747 Highest = LowestScreen()+1; 748 } 749 750 751 void 752 BellOff() 753 { 754 if (bellwinup) { 755 delwin(bellwin); 756 bellwin = 0; 757 bellwinup = 0; 758 touchwin(stdscr); 759 DoARefresh(); 760 } 761 } 762 763 764 void 765 RingBell(s) 766 char *s; 767 { 768 needToRing = 1; 769 if (s) { 770 int len = strlen(s); 771 772 if (len > COLS-2) { 773 len = COLS-2; 774 } 775 if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 776 OurExitString("Error from newwin in RingBell", 1); 777 } 778 werase(bellwin); 779 wstandout(bellwin); 780 box(bellwin, '|', '-'); 781 if (wmove(bellwin, 1, 1) == ERR) { 782 OurExitString("Error from wmove in RingBell", 1); 783 } 784 while (len--) { 785 if (waddch(bellwin, *s++) == ERR) { 786 OurExitString("Error from waddch in RingBell", 1); 787 } 788 } 789 wstandend(bellwin); 790 if (wrefresh(bellwin) == ERR) { 791 OurExitString("Error from wrefresh in RingBell", 1); 792 } 793 bellwinup = 1; 794 } 795 } 796 797 798 /* returns a 1 if no more output available (so, go ahead and block), 799 or a 0 if there is more output available (so, just poll the other 800 sources/destinations, don't block). 801 */ 802 803 int 804 DoTerminalOutput() 805 { 806 /* called just before a select to conserve IO to terminal */ 807 if (!(screenInitd||screenStopped)) { 808 return 1; /* No output if not initialized */ 809 } 810 if ((Lowest <= Highest) || needToRing || 811 (terminalCursorAddress != CorrectTerminalCursor())) { 812 (*TryToSend)(); 813 } 814 if (Lowest > Highest) { 815 return 1; /* no more output now */ 816 } else { 817 return 0; /* more output for future */ 818 } 819 } 820 821 /* 822 * The following are defined to handle transparent data. 823 */ 824 825 void 826 TransStop() 827 { 828 #if defined(unix) 829 if (tcflag == 0) { 830 tcflag = -1; 831 (void) signal(SIGCHLD, SIG_DFL); 832 } else if (tcflag > 0) { 833 setcommandmode(); 834 (void) close(tin); 835 (void) close(tout); 836 tin = savefd[0]; 837 tout = savefd[1]; 838 setconnmode(); 839 tcflag = -1; 840 (void) signal(SIGCHLD, SIG_DFL); 841 } 842 #endif /* defined(unix) */ 843 RefreshScreen(); 844 } 845 846 void 847 TransOut(buffer, count, kind, control) 848 unsigned char *buffer; 849 int count; 850 int kind; /* 0 or 5 */ 851 int control; /* To see if we are done */ 852 { 853 #if defined(unix) 854 extern char *transcom; 855 int inpipefd[2], outpipefd[2]; 856 static void aborttc(); 857 #endif /* defined(unix) */ 858 859 while (DoTerminalOutput() == 0) { 860 #if defined(unix) 861 HaveInput = 0; 862 #endif /* defined(unix) */ 863 } 864 #if defined(unix) 865 if (transcom && tcflag == -1) { 866 while (1) { /* go thru once */ 867 if (pipe(outpipefd) < 0) { 868 break; 869 } 870 if (pipe(inpipefd) < 0) { 871 break; 872 } 873 if ((tcflag = fork()) == 0) { 874 (void) close(outpipefd[1]); 875 (void) close(0); 876 if (dup(outpipefd[0]) < 0) { 877 exit(1); 878 } 879 (void) close(outpipefd[0]); 880 (void) close(inpipefd[0]); 881 (void) close(1); 882 if (dup(inpipefd[1]) < 0) { 883 exit(1); 884 } 885 (void) close(inpipefd[1]); 886 if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 887 exit(1); 888 } 889 } 890 (void) close(inpipefd[1]); 891 (void) close(outpipefd[0]); 892 savefd[0] = tin; 893 savefd[1] = tout; 894 setcommandmode(); 895 tin = inpipefd[0]; 896 tout = outpipefd[1]; 897 (void) signal(SIGCHLD, aborttc); 898 setconnmode(); 899 tcflag = 1; 900 break; 901 } 902 if (tcflag < 1) { 903 tcflag = 0; 904 } 905 } 906 #endif /* defined(unix) */ 907 (void) DataToTerminal((char *)buffer, count); 908 if (control && (kind == 0)) { /* Send in AID byte */ 909 SendToIBM(); 910 } else { 911 extern void TransInput(); 912 913 TransInput(1, kind); /* Go get some data */ 914 } 915 } 916 917 918 #if defined(unix) 919 static void 920 aborttc(signo) 921 int signo; 922 { 923 setcommandmode(); 924 (void) close(tin); 925 (void) close(tout); 926 tin = savefd[0]; 927 tout = savefd[1]; 928 setconnmode(); 929 tcflag = 0; 930 } 931 #endif /* defined(unix) */ 932