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