1: /* 2: * Copyright 1984, 1985 by the Regents of the University of 3: * 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: 23: /* this exists to patch over DataFromNetwork until it is ready */ 24: 25: #include <signal.h> 26: #include <sgtty.h> 27: #include <stdio.h> 28: #include <curses.h> 29: 30: #include "ascebc.h" 31: #include "3270.h" 32: #include "screen.h" 33: 34: #if defined(DOSCCS) && !defined(lint) 35: static char sccsid[] = "@(#)datastream.c 2.13\t1/1/94"; 36: #endif 37: 38: void EmptyTerminal(); 39: 40: #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? terminalCursorAddress:UnLocked? CursorAddress: HighestScreen()) 41: 42: #define SetHighestLowest(position) { \ 43: if (position < Lowest) { \ 44: Lowest = position; \ 45: } \ 46: if (position > Highest) { \ 47: Highest = position; \ 48: } \ 49: } 50: 51: extern char ebcasc[NEBCASC][NEBC]; /* translate table */ 52: 53: static int terminalCursorAddress; /* where the cursor is on term */ 54: static int screenInitd; /* the screen has been initialized */ 55: static int MAX_CHANGES_BEFORE_POLL; /* how many characters before looking */ 56: /* at terminal and net again */ 57: 58: static int needToRing = 0; /* need to ring terinal bell */ 59: static char *bellSequence = "\07"; /* bell sequence (may be replaced by 60: * VB during initialization) 61: */ 62: static char *KS, *KE; /* Turn on and off keyboard */ 63: 64: static char Blanks[sizeof Terminal]; /* lots of blanks */ 65: 66: /* some globals */ 67: 68: int OutputClock; /* what time it is */ 69: int TransparentClock; /* time we were last in transparent */ 70: 71: 72: /* StartScreen - called to initialize the screen, etc. */ 73: 74: StartScreen() 75: { 76: int save; 77: struct sgttyb ourttyb; 78: static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 79: 2400, 4800, 9600 }; 80: #ifndef pdp11 81: static char KSEbuffer[2050]; 82: #else 83: static char KSEbuffer[512]; 84: #endif 85: char *lotsofspace = KSEbuffer, *tgetstr(); 86: 87: if (!screenInitd) { 88: ioctl(1, TIOCGETP, (char *) &ourttyb); 89: if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 90: MAX_CHANGES_BEFORE_POLL = 1920; 91: } else { 92: MAX_CHANGES_BEFORE_POLL = speeds[ourttyb.sg_ospeed]/10; 93: if (MAX_CHANGES_BEFORE_POLL < 40) { 94: MAX_CHANGES_BEFORE_POLL = 40; 95: } 96: } 97: save = mode(0); 98: initscr(); /* start up curses */ 99: nonl(); 100: /* the problem is that curses catches SIGTSTP to 101: * be nice, but it messes us up. 102: */ 103: signal(SIGTSTP, SIG_DFL); 104: KS = tgetstr("ks", &lotsofspace); 105: KE = tgetstr("ke", &lotsofspace); 106: if (KS) { 107: StringToTerminal(KS); 108: } 109: DoARefresh(); 110: (void) mode(save); 111: if (VB && *VB) { 112: bellSequence = VB; /* use visual bell */ 113: } 114: screenInitd = 1; 115: } 116: } 117: 118: 119: 120: /* Stop3270 - called when we are going away... */ 121: 122: Stop3270(doNewLine) 123: int doNewLine; 124: { 125: if (screenInitd) { 126: int save; 127: 128: move(NUMBERLINES-1, 1); 129: DoARefresh(); 130: if (KE) { 131: StringToTerminal(KE); 132: } 133: if (doNewLine) { 134: StringToTerminal("\r\n"); 135: } 136: EmptyTerminal(); 137: save = mode(0); 138: endwin(); 139: (void) mode(save); 140: } 141: } 142: 143: 144: /* ConnectScreen - called to reconnect to the screen */ 145: 146: ConnectScreen() 147: { 148: if (screenInitd) { 149: if (KS) { 150: StringToTerminal(KS); 151: } 152: RefreshScreen(); 153: TryToSend(); 154: } 155: } 156: 157: /* RefreshScreen - called to cause the screen to be refreshed */ 158: 159: RefreshScreen() 160: { 161: clearok(curscr, TRUE); 162: TryToSend(); 163: } 164: 165: 166: /* Clear3270 - called to clear the screen */ 167: 168: Clear3270() 169: { 170: bzero((char *)Host, sizeof(Host)); 171: DeleteAllFields(); /* get rid of all fields */ 172: BufferAddress = SetBufferAddress(0,0); 173: CursorAddress = SetBufferAddress(0,0); 174: Lowest = LowestScreen(); 175: Highest = HighestScreen(); 176: } 177: 178: /* LocalClear3270() - clear the whole ball of wax, cheaply */ 179: 180: LocalClear3270() 181: { 182: outputPurge(); /* flush all data to terminal */ 183: clear(); /* clear in curses */ 184: bzero((char *)Terminal, sizeof Terminal); 185: Clear3270(); /* clear host part */ 186: Lowest = HighestScreen()+1; /* everything in sync... */ 187: Highest = LowestScreen()+1; 188: } 189: 190: /* OurExitString - designed to keep us from going through infinite recursion */ 191: 192: OurExitString(file, string, value) 193: FILE *file; 194: char *string; 195: int value; 196: { 197: static int recursion = 0; 198: 199: if (!recursion) { 200: recursion = 1; 201: ExitString(file, string, value); 202: } 203: } 204: 205: 206: RingBell() 207: { 208: needToRing = 1; 209: } 210: 211: /* AddHost - called to add a character to the buffer. 212: * We use a macro in this module, since we call it so 213: * often from loops. 214: * 215: * NOTE: It is a macro, so don't go around using AddHost(p, *c++), or 216: * anything similar. (I don't define any temporary variables, again 217: * just for the speed.) 218: */ 219: AddHost(position, character) 220: int position; 221: char character; 222: { 223: # define AddHostA(p,c) \ 224: { \ 225: if (IsStartField(p)) { \ 226: DeleteField(p); \ 227: SetHighestLowest(p); \ 228: } \ 229: SetHost(p, c); \ 230: } 231: # define AddHost(p,c) \ 232: { \ 233: AddHostA(p,c); \ 234: if ((c != GetTerminal(p)) || TermIsStartField(p)) { \ 235: SetHighestLowest(p); \ 236: } \ 237: } /* end of macro of AddHost */ 238: 239: AddHost(position, character); 240: } 241: 242: /* DoARefresh */ 243: 244: static 245: DoARefresh() 246: { 247: if (ERR == refresh()) { 248: OurExitString(stderr, "ERR from refresh\n", 1); 249: } 250: } 251: 252: /* TryToSend - send data out to user's terminal */ 253: 254: static 255: TryToSend() 256: { 257: register int pointer; 258: register int c; 259: register int fieldattr; 260: register int changes; 261: 262: static int inHighlightMode = 0; 263: extern int HaveInput; /* 1 if there is input to check out */ 264: 265: # define SetHighlightMode(p) { \ 266: if (!IsStartField(p) && IsHighlightedAttr(fieldattr)) { \ 267: if (!inHighlightMode) { \ 268: inHighlightMode = 1; \ 269: standout(); \ 270: } \ 271: } else { \ 272: if (inHighlightMode) { \ 273: inHighlightMode = 0; \ 274: standend(); \ 275: } \ 276: } \ 277: } 278: 279: # define DoCharacterAt(c,p) { \ 280: SetTerminal(p, c); \ 281: if (p != HighestScreen()) { \ 282: c = TerminalCharacterAttr(ebcasc[0][c&0xff], p, \ 283: fieldattr); \ 284: if (terminalCursorAddress != p) { \ 285: if (ERR == mvaddch(ScreenLine(p), \ 286: ScreenLineOffset(p), c)) {\ 287: char foo[100]; \ 288: \ 289: sprintf(foo, "ERR from mvaddch at %d (%d, %d)\n", \ 290: p, ScreenLine(p), ScreenLineOffset(p)); \ 291: OurExitString(stderr, foo, 1); \ 292: } \ 293: } else { \ 294: if (ERR == addch(c)) {\ 295: char foo[100]; \ 296: \ 297: sprintf(foo, "ERR from addch at %d (%d, %d)\n", \ 298: p, ScreenLine(p), ScreenLineOffset(p)); \ 299: OurExitString(stderr, foo, 1); \ 300: } \ 301: } \ 302: terminalCursorAddress = ScreenInc(p); \ 303: } \ 304: /* if (pointer%LINESIZE == LINESIZE-1) { \ 305: DoARefresh(); \ 306: if (TtyChars() > MAX_CHANGES_BEFORE_POLL) { \ 307: EmptyTerminal(); \ 308: } \ 309: } */ \ 310: } 311: 312: /* run through screen, printing out non-null lines */ 313: 314: /* There are two separate reasons for wanting to terminate this 315: * loop early. One is to respond to new input (either from 316: * the terminal or from the network [host]). For this reason, 317: * we expect to see 'HaveInput' come true when new input comes in. 318: * 319: * The second reason is a bit more difficult (for me) to understand. 320: * Basically, we don't want to get too far ahead of the characters that 321: * appear on the screen. Ideally, we would type out a few characters, 322: * wait until they appeared on the screen, then type out a few more. 323: * The reason for this is that the user, on seeing some characters 324: * appear on the screen may then start to type something. We would 325: * like to look at what the user types at about the same 'time' 326: * (measured by characters being sent to the terminal) that the 327: * user types them. For this reason, what we would like to do 328: * is update a bit, then call curses to do a refresh, flush the 329: * output to the terminal, then wait until the terminal data 330: * has been sent. 331: * 332: * Note that curses is useful for, among other things, deciding whether 333: * or not to send :ce: (clear to end of line), so we should call curses 334: * at end of lines (beginning of next lines). 335: * 336: * The problems here are the following: If we do lots of write(2)s, 337: * we will be doing lots of context switches, thus lots of overhead 338: * (which we have already). Second, if we do a select to wait for 339: * the output to drain, we have to contend with the fact that NOW 340: * we are scheduled to run, but who knows what the scheduler will 341: * decide when the output has caught up. 342: */ 343: 344: if (Highest == HighestScreen()) { 345: Highest = ScreenDec(Highest); /* else, while loop will never end */ 346: } 347: if (Lowest < LowestScreen()) { 348: Lowest = LowestScreen(); /* could be -1 in some cases with 349: * unformatted screens. 350: */ 351: } 352: if (Highest >= Lowest) { 353: /* if there is anything to do, do it. We won't terminate 354: * the loop until we've gone at least to Highest. 355: */ 356: pointer = Lowest; 357: while ((pointer <= Highest) && !HaveInput) { 358: 359: /* point at the next place of disagreement */ 360: pointer += (bunequal(Host+pointer, Terminal+pointer, 361: (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 362: 363: /* how many characters to change until the end of the 364: * current line 365: */ 366: changes = LINESIZE - ScreenLineOffset(pointer); 367: 368: /* what is the field attribute of the current position */ 369: fieldattr = FieldAttributes(WhereAttrByte(pointer)); 370: 371: if ((IsStartField(pointer) != TermIsStartField(pointer)) || 372: (IsStartField(pointer) && 373: fieldattr != TermAttributes(pointer))) { 374: 375: int oldterm; 376: 377: oldterm = TermAttributes(pointer); 378: if (IsStartField(pointer)) { 379: TermNewField(pointer, fieldattr); 380: SetTerminal(pointer, 0); 381: } else { 382: TermDeleteField(pointer); 383: } 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: c = GetHost(pointer); 394: DoCharacterAt(c,pointer); 395: 396: if (NotVisuallyCompatibleAttributes 397: (pointer, fieldattr, oldterm)) { 398: int j; 399: 400: j = pointer; 401: 402: pointer = ScreenInc(pointer); 403: SetHighlightMode(pointer); /* Turn on highlighting */ 404: while (!IsStartField(pointer) && 405: !TermIsStartField(pointer)) { 406: c = GetHost(pointer); 407: DoCharacterAt(c,pointer); /* MACRO */ 408: pointer = ScreenInc(pointer); 409: if (!(--changes)) { 410: DoARefresh(); 411: EmptyTerminal(); 412: /* We don't look at HaveInput here, since 413: * if we leave this loop before the end of 414: * the 3270 field, we could have pointer 415: * higher than Highest. This would cause 416: * us to end the highest "while" loop, 417: * but we may, in fact, need to go around the 418: * screen once again. 419: */ 420: } 421: /* The loop needs to be protected 422: * from the situation where there had been only 423: * one field on the Terminal, and none on the Host. 424: * In this case, we have just deleted our last 425: * field. Hence, the break. 426: */ 427: if (j == pointer) { 428: break; 429: } 430: } 431: if (!TermIsStartField(pointer)) { 432: /* Remember what the terminal looked like */ 433: TermNewField(pointer, oldterm); 434: SetTerminal(pointer, 0); 435: /* The danger here is that the current position may 436: * be the start of a Host field. If so, and the field 437: * is highlighted, and our terminal was highlighted, 438: * then we will leave a highlighted blank at this 439: * position. 440: */ 441: SetHighlightMode(pointer); 442: c = 0; 443: DoCharacterAt(c,pointer); 444: } 445: /* We could be in the situation of needing to exit. 446: * This could happen if the current field wrapped around 447: * the end of the screen. 448: */ 449: if (j > pointer) { 450: break; 451: } 452: } else { 453: c = GetHost(pointer); 454: /* We always do the first character in a divergent 455: * field, since otherwise the start of a field in 456: * the Host structure may leave a highlighted blank 457: * on the screen, and the start of a field in the 458: * Terminal structure may leave a non-highlighted 459: * something in the middle of a highlighted field 460: * on the screen. 461: */ 462: SetHighlightMode(pointer); 463: DoCharacterAt(c,pointer); 464: } 465: } else { 466: SetHighlightMode(pointer); 467: /* The following will terminate at least when we get back 468: * to the original 'pointer' location (since we force 469: * things to be equal). 470: */ 471: while (((c = GetHost(pointer)) != GetTerminal(pointer)) && 472: !IsStartField(pointer) && !TermIsStartField(pointer)) { 473: DoCharacterAt(c, pointer); 474: pointer = ScreenInc(pointer); 475: if (!(--changes)) { 476: DoARefresh(); 477: EmptyTerminal(); 478: if (HaveInput) { /* if input came in, take it */ 479: break; 480: } 481: } 482: } 483: } 484: } 485: } 486: DoARefresh(); 487: Lowest = pointer; 488: if (Lowest > Highest) { /* if we finished input... */ 489: Lowest = HighestScreen()+1; 490: Highest = LowestScreen()-1; 491: terminalCursorAddress = CorrectTerminalCursor(); 492: if (ERR == move(ScreenLine(terminalCursorAddress), 493: ScreenLineOffset(terminalCursorAddress))) { 494: OurExitString(stderr, "ERR from move\n", 1); 495: } 496: DoARefresh(); 497: if (needToRing) { 498: StringToTerminal(bellSequence); 499: needToRing = 0; 500: } 501: } 502: EmptyTerminal(); /* move data along */ 503: return; 504: } 505: 506: 507: /* returns a 1 if no more output available (so, go ahead and block), 508: or a 0 if there is more output available (so, just poll the other 509: sources/destinations, don't block). 510: */ 511: 512: int 513: DoTerminalOutput() 514: { 515: /* called just before a select to conserve IO to terminal */ 516: if (Initialized && 517: ((Lowest <= Highest) || needToRing || 518: (terminalCursorAddress != CorrectTerminalCursor()))) { 519: TryToSend(); 520: } 521: if (Lowest > Highest) { 522: return(1); /* no more output now */ 523: } else { 524: return(0); /* more output for future */ 525: } 526: } 527: 528: /* returns the number of characters consumed */ 529: int 530: DataFromNetwork(buffer, count, control) 531: register char *buffer; /* what the data is */ 532: register int count; /* and how much there is */ 533: int control; /* this buffer terminated block */ 534: { 535: int origCount; 536: register int c; 537: register int i; 538: static int Command; 539: static int Wcc; 540: static int LastWasTerminated = 0; /* was "control" = 1 last time? */ 541: 542: if (!Initialized) { /* not initialized */ 543: int abort(); 544: 545: bzero((char *)Host, sizeof Host); 546: DeleteAllFields(); 547: for (i = 0; i < sizeof Blanks; i++) { 548: Blanks[i] = ' '; 549: } 550: bzero((char *)Terminal, sizeof Terminal); 551: Lowest = HighestScreen()+1; 552: Highest = LowestScreen()-1; 553: terminalCursorAddress = 554: CursorAddress = 555: BufferAddress = SetBufferAddress(0,0); 556: UnLocked = 1; 557: StartScreen(); 558: LastWasTerminated = 1; 559: Initialized = 1; 560: OutputClock = 1; 561: TransparentClock = -1; 562: signal(SIGHUP, abort); 563: } 564: 565: origCount = count; 566: 567: if (LastWasTerminated) { 568: 569: if (count < 2) { 570: if (count == 0) { 571: StringToTerminal("Short count received from host!\n"); 572: return(count); 573: } 574: Command = buffer[0]&0xff; 575: switch (Command) { /* This had better be a read command */ 576: case CMD_READ_MODIFIED: 577: DoReadModified(); 578: break; 579: case CMD_READ_BUFFER: 580: DoReadBuffer(); 581: break; 582: default: 583: break; 584: } 585: return(1); /* We consumed everything */ 586: } 587: Command = buffer[0]&0xff; 588: Wcc = buffer[1]&0xff; 589: if (Wcc & WCC_RESET_MDT) { 590: i = c = WhereAttrByte(LowestScreen()); 591: do { 592: if (HasMdt(i)) { 593: TurnOffMdt(i); 594: } 595: i = FieldInc(i); 596: } while (i != c); 597: } 598: 599: switch (Command) { 600: case CMD_ERASE_WRITE: 601: Clear3270(); 602: if (TransparentClock == OutputClock) { 603: clearok(curscr, TRUE); 604: } 605: break; 606: case CMD_ERASE_ALL_UNPROTECTED: 607: CursorAddress = HighestScreen()+1; 608: for (i = LowestScreen(); i <= HighestScreen(); ScreenInc(i)) { 609: if (IsUnProtected(i)) { 610: if (CursorAddress > i) { 611: CursorAddress = i; 612: } 613: AddHost(i, '\0'); 614: } 615: if (HasMdt(i)) { 616: TurnOffMdt(i); 617: } 618: } 619: if (CursorAddress == HighestScreen()+1) { 620: CursorAddress = SetBufferAddress(0,0); 621: } 622: UnLocked = 1; 623: AidByte = 0; 624: break; 625: case CMD_WRITE: 626: break; 627: default: 628: break; 629: } 630: 631: count -= 2; /* strip off command and wcc */ 632: buffer += 2; 633: 634: } 635: LastWasTerminated = 0; /* then, reset at end... */ 636: 637: while (count) { 638: count--; 639: c = (*buffer++)&0xff; 640: if (IsOrder(c)) { 641: /* handle an order */ 642: switch (c) { 643: # define Ensure(x) if (count < x) { \ 644: if (!control) { \ 645: return(origCount-(count+1)); \ 646: } else { \ 647: /* XXX - should not occur */ \ 648: count = 0; \ 649: break; \ 650: } \ 651: } 652: case ORDER_SF: 653: Ensure(1); 654: c = (*buffer++)&0xff; 655: count--; 656: if ( ! (IsStartField(BufferAddress) && 657: FieldAttributes(BufferAddress) == c)) { 658: if (NotVisuallyCompatibleAttributes(BufferAddress, c, 659: FieldAttributes(BufferAddress))) { 660: SetHighestLowest(BufferAddress); 661: } 662: if (GetTerminal(BufferAddress)) { 663: SetHighestLowest(BufferAddress); 664: } 665: NewField(BufferAddress,c); 666: } 667: SetHost(BufferAddress, 0); 668: BufferAddress = ScreenInc(BufferAddress); 669: break; 670: case ORDER_SBA: 671: Ensure(2); 672: i = buffer[0]; 673: c = buffer[1]; 674: if (!i && !c) { /* transparent write */ 675: if (!control) { 676: return(origCount-(count+1)); 677: } else { 678: while (Initialized && 679: ((Lowest <= Highest) || needToRing || 680: (terminalCursorAddress != 681: CorrectTerminalCursor()))) { 682: extern int HaveInput; 683: 684: HaveInput = 0; 685: TryToSend(); 686: } 687: if (TransparentClock != OutputClock) { 688: if (!DoTerminalOutput()) { 689: return(origCount-(count+1)); 690: } 691: move(ScreenLine(CursorAddress), 692: ScreenLineOffset(CursorAddress)); 693: DoARefresh(); 694: } 695: TransparentClock = OutputClock; /* this clock */ 696: (void) DataToTerminal(buffer+2, count-2); 697: SendToIBM(); 698: TransparentClock = OutputClock+1; /* clock next */ 699: buffer += count; 700: count -= count; 701: } 702: } else { 703: BufferAddress = Addr3270(i, c); 704: buffer += 2; 705: count -= 2; 706: } 707: break; 708: case ORDER_IC: 709: CursorAddress = BufferAddress; 710: break; 711: case ORDER_PT: 712: for (i = BufferAddress; (i != HighestScreen()); 713: i = ScreenInc(i)) { 714: if (IsStartField(i)) { 715: i = ScreenInc(i); 716: if (!IsProtected(i)) { 717: break; 718: } 719: if (i == HighestScreen()) { 720: break; 721: } 722: } 723: } 724: BufferAddress = i; 725: break; 726: case ORDER_RA: 727: Ensure(2); 728: i = Addr3270(buffer[0], buffer[1]); 729: c = buffer[2]; 730: do { 731: AddHost(BufferAddress, c); 732: BufferAddress = ScreenInc(BufferAddress); 733: } while (BufferAddress != i); 734: buffer += 3; 735: count -= 3; 736: break; 737: case ORDER_EUA: /* (from [here,there), ie: half open interval] */ 738: Ensure(2); 739: c = FieldAttributes(WhereAttrByte(BufferAddress)); 740: for (i = Addr3270(buffer[0], buffer[1]); i != BufferAddress; 741: BufferAddress = ScreenInc(BufferAddress)) { 742: if (!IsProtectedAttr(BufferAddress, c)) { 743: AddHost(BufferAddress, 0); 744: } 745: } 746: buffer += 2; 747: count -= 2; 748: break; 749: case ORDER_YALE: /* special YALE defined order */ 750: Ensure(2); /* need at least two characters */ 751: if ((*buffer&0xff) == 0x5b) { 752: i = OptOrder(buffer+1, count-1, control); 753: if (i == 0) { 754: return(origCount-(count+1)); /* come here again */ 755: } else { 756: buffer += 1 + i; 757: count - = (1 + i); 758: } 759: } 760: break; 761: default: 762: break; /* XXX ? */ 763: } 764: if (count < 0) { 765: count = 0; 766: } 767: } else { 768: /* Data comes in large clumps - take it all */ 769: i = BufferAddress; 770: #ifdef NOTDEF 771: AddHost(i, c); 772: #else /* NOTDEF */ 773: AddHostA(i, c); 774: SetHighestLowest(i); 775: #endif /* NOTDEF */ 776: i = ScreenInc(i); 777: while (count && !IsOrder(c = *(buffer)&0xff)) { 778: buffer++; 779: #ifdef NOTDEF 780: AddHost(i, c); 781: #else /* NOTDEF */ 782: AddHostA(i, c); 783: #endif /* NOTDEF */ 784: i = ScreenInc(i); 785: #ifndef NOTDEF 786: if (i == LowestScreen()) { 787: SetHighestLowest(HighestScreen()); 788: } 789: #endif /* NOTDEF */ 790: count--; 791: } 792: #ifndef NOTDEF 793: SetHighestLowest(i); 794: #endif /* NOTDEF */ 795: BufferAddress = i; 796: } 797: } 798: if (count == 0) { 799: OutputClock++; /* time rolls on */ 800: if (control) { 801: if (Wcc & WCC_RESTORE) { 802: if (TransparentClock != OutputClock) { 803: AidByte = 0; 804: } 805: UnLocked = 1; 806: (void) TerminalIn(); /* move along user's input */ 807: } 808: if (Wcc & WCC_ALARM) { 809: RingBell(); 810: } 811: } 812: LastWasTerminated = control; /* state for next time */ 813: return(origCount); 814: } else { 815: return(origCount-count); 816: } 817: }