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