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