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