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