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