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