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