|
|
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 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.
11: */
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)termout.c 3.3 (Berkeley) 3/31/88";
15: #endif /* not lint */
16:
17: #if defined(unix)
18: #include <signal.h>
19: #include <sgtty.h>
20: #endif
21: #include <stdio.h>
22: #include <curses.h>
23:
24: #include "../general/general.h"
25:
26: #include "terminal.h"
27:
28: #include "../telnet.ext"
29:
30: #include "../api/disp_asc.h"
31:
32: #include "../ctlr/hostctlr.h"
33: #include "../ctlr/inbound.ext"
34: #include "../ctlr/oia.h"
35: #include "../ctlr/options.ext"
36: #include "../ctlr/outbound.ext"
37: #include "../ctlr/screen.h"
38:
39: #include "../ascii/map3270.ext"
40:
41: #include "../general/globals.h"
42:
43: extern void EmptyTerminal();
44:
45: #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
46: CursorAddress:UnLocked? CursorAddress: HighestScreen())
47:
48:
49: static int terminalCursorAddress; /* where the cursor is on term */
50: static int screenInitd; /* the screen has been initialized */
51: static int screenStopped; /* the screen has been stopped */
52: static int max_changes_before_poll; /* how many characters before looking */
53: /* at terminal and net again */
54:
55: static int needToRing; /* need to ring terinal bell */
56: static char *bellSequence = "\07"; /* bell sequence (may be replaced by
57: * VB during initialization)
58: */
59: static WINDOW *bellwin = 0; /* The window the bell message is in */
60: int bellwinup = 0; /* Are we up with it or not */
61:
62: #if defined(unix)
63: static char *KS, *KE;
64: #endif /* defined(unix) */
65:
66:
67: static int inHighlightMode = 0;
68: ScreenImage Terminal[MAXSCREENSIZE];
69:
70: /* Variables for transparent mode */
71: #if defined(unix)
72: static int tcflag = -1; /* transparent mode command flag */
73: static int savefd[2]; /* for storing fds during transcom */
74: extern int tin, tout; /* file descriptors */
75: #endif /* defined(unix) */
76:
77:
78: /*
79: * init_screen()
80: *
81: * Initialize variables used by screen.
82: */
83:
84: void
85: init_screen()
86: {
87: bellwinup = 0;
88: inHighlightMode = 0;
89: ClearArray(Terminal);
90: }
91:
92:
93: /* OurExitString - designed to keep us from going through infinite recursion */
94:
95: static void
96: OurExitString(file, string, value)
97: FILE *file;
98: char *string;
99: int 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:
112: static void
113: DoARefresh()
114: {
115: if (ERR == refresh()) {
116: OurExitString(stderr, "ERR from refresh\n", 1);
117: }
118: }
119:
120: static void
121: GoAway(from, where)
122: char *from; /* routine that gave error */
123: int 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:
133: /* What is the screen address of the attribute byte for the terminal */
134:
135: static int
136: WhereTermAttrByte(p)
137: register 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: }
152:
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:
171: #if defined(NOT43)
172: static int
173: #else /* defined(NOT43) */
174: static void
175: #endif /* defined(NOT43) */
176: SlowScreen()
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:
249: if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */
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 */
318: while ((!IsStartField(pointer)) &&
319: (!TermIsStartField(pointer))) {
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) {
366: /*
367: * pointer is guaranteed to be higher than Highest...
368: */
369: pointer = Highest+1; /* We did the highest thing */
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);
387: /*
388: * The following will terminate at least when we get back
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: }
428:
429: #if defined(NOT43)
430: static int
431: #else /* defined(NOT43) */
432: static void
433: #endif /* defined(NOT43) */
434: FastScreen()
435: {
436: #if defined(MSDOS)
437: #define SaveCorner 0
438: #else /* defined(MSDOS) */
439: #define SaveCorner 1
440: #endif /* defined(MSDOS) */
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];
467: #if !defined(MSDOS)
468: if (Highest == HighestScreen()) {
469: Highest = ScreenDec(Highest);
470: }
471: #endif /* !defined(MSDOS) */
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) {
478: if (IsStartFieldPointer(p)) { /* New field? */
479: Highest = HighestScreen();
480: Lowest = LowestScreen();
481: FastScreen(); /* Recurse */
482: return;
483: } else if (fieldattr) { /* Should we display? */
484: /* Display translated data */
485: addch(disp_asc[GetTerminalPointer(p)]);
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) {
514: if (IsStartFieldPointer(p)) { /* New field? */
515: if (tmp != tmpbuf) {
516: *tmp++ = 0; /* close out */
517: addstr(tmpbuf);
518: tmp = tmpbuf;
519: tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host);
520: }
521: fieldattr = FieldAttributesPointer(p); /* Get attributes */
522: DoAttribute(fieldattr); /* Set standout, non-display */
523: *tmp++ = ' ';
524: } else {
525: if (fieldattr) { /* Should we display? */
526: /* Display translated data */
527: *tmp++ = disp_asc[GetTerminalPointer(p)];
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)
574: int
575: #else /* defined(NOT43) */
576: void
577: #endif /* defined(NOT43) */
578: (*TryToSend)() = FastScreen;
579:
580: void
581: ScreenOIA(oia)
582: OIA *oia;
583: {
584: }
585:
586:
587: /* InitTerminal - called to initialize the screen, etc. */
588:
589: void
590: InitTerminal()
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:
598: InitMapping(); /* Go do mapping file (MAP3270) first */
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:
607: ClearArray(Terminal);
608: terminalCursorAddress = SetBufferAddress(0,0);
609: #if defined(unix)
610: signal(SIGHUP, abort);
611: #endif
612:
613: TryToSend = FastScreen;
614: #if defined(unix)
615: ioctl(1, TIOCGETP, (char *) &ourttyb);
616: if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) {
617: max_changes_before_poll = 1920;
618: } else {
619: max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10;
620: if (max_changes_before_poll < 40) {
621: max_changes_before_poll = 40;
622: }
623: TryToSend = SlowScreen;
624: HaveInput = 1; /* get signals going */
625: }
626: #endif /* defined(unix) */
627: setcommandmode();
628: /*
629: * By now, initscr() (in curses) has been called (from telnet.c),
630: * and the screen has been initialized.
631: */
632: #if defined(unix)
633: nonl();
634: /* the problem is that curses catches SIGTSTP to
635: * be nice, but it messes us up.
636: */
637: signal(SIGTSTP, SIG_DFL);
638: if ((KS = tgetstr("ks", &lotsofspace)) != 0) {
639: KS = strsave(KS);
640: StringToTerminal(KS);
641: }
642: if ((KE = tgetstr("ke", &lotsofspace)) != 0) {
643: KE = strsave(KE);
644: }
645: if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) {
646: SO = strsave(tgetstr("md", &lotsofspace));
647: SE = strsave(tgetstr("me", &lotsofspace));
648: }
649: #endif
650: DoARefresh();
651: setconnmode();
652: if (VB && *VB) {
653: bellSequence = VB; /* use visual bell */
654: }
655: screenInitd = 1;
656: screenStopped = 0; /* Not stopped */
657: }
658: }
659:
660:
661: /* StopScreen - called when we are going away... */
662:
663: void
664: StopScreen(doNewLine)
665: int doNewLine;
666: {
667: if (screenInitd && !screenStopped) {
668: move(NumberLines-1, 1);
669: standend();
670: inHighlightMode = 0;
671: DoARefresh();
672: setcommandmode();
673: endwin();
674: setconnmode();
675: #if defined(unix)
676: if (KE) {
677: StringToTerminal(KE);
678: }
679: #endif /* defined(unix) */
680: if (doNewLine) {
681: StringToTerminal("\r\n");
682: }
683: EmptyTerminal();
684: screenStopped = 1; /* This is stopped */
685: }
686: }
687:
688:
689: /* RefreshScreen - called to cause the screen to be refreshed */
690:
691: void
692: RefreshScreen()
693: {
694: clearok(curscr, TRUE);
695: (*TryToSend)();
696: }
697:
698:
699: /* ConnectScreen - called to reconnect to the screen */
700:
701: void
702: ConnectScreen()
703: {
704: if (screenInitd) {
705: #if defined(unix)
706: if (KS) {
707: StringToTerminal(KS);
708: }
709: #endif /* defined(unix) */
710: RefreshScreen();
711: (*TryToSend)();
712: screenStopped = 0;
713: }
714: }
715:
716: /* LocalClearScreen() - clear the whole ball of wax, cheaply */
717:
718: void
719: LocalClearScreen()
720: {
721: outputPurge(); /* flush all data to terminal */
722: clear(); /* clear in curses */
723: ClearArray(Terminal);
724: Clear3270();
725: Lowest = HighestScreen()+1; /* everything in sync... */
726: Highest = LowestScreen()+1;
727: }
728:
729:
730: void
731: BellOff()
732: {
733: if (bellwinup) {
734: delwin(bellwin);
735: bellwin = 0;
736: bellwinup = 0;
737: touchwin(stdscr);
738: DoARefresh();
739: }
740: }
741:
742:
743: void
744: RingBell(s)
745: char *s;
746: {
747: needToRing = 1;
748: if (s) {
749: int len = strlen(s);
750:
751: if (len > COLS-2) {
752: len = COLS-2;
753: }
754: if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) {
755: OurExitString(stderr, "Error from newwin in RingBell", 1);
756: }
757: werase(bellwin);
758: wstandout(bellwin);
759: box(bellwin, '|', '-');
760: if (wmove(bellwin, 1, 1) == ERR) {
761: OurExitString(stderr, "Error from wmove in RingBell", 1);
762: }
763: while (len--) {
764: if (waddch(bellwin, *s++) == ERR) {
765: OurExitString(stderr, "Error from waddch in RingBell", 1);
766: }
767: }
768: wstandend(bellwin);
769: if (wrefresh(bellwin) == ERR) {
770: OurExitString(stderr, "Error from wrefresh in RingBell", 1);
771: }
772: bellwinup = 1;
773: }
774: }
775:
776:
777: /* returns a 1 if no more output available (so, go ahead and block),
778: or a 0 if there is more output available (so, just poll the other
779: sources/destinations, don't block).
780: */
781:
782: int
783: DoTerminalOutput()
784: {
785: /* called just before a select to conserve IO to terminal */
786: if (!(screenInitd||screenStopped)) {
787: return 1; /* No output if not initialized */
788: }
789: if ((Lowest <= Highest) || needToRing ||
790: (terminalCursorAddress != CorrectTerminalCursor())) {
791: (*TryToSend)();
792: }
793: if (Lowest > Highest) {
794: return 1; /* no more output now */
795: } else {
796: return 0; /* more output for future */
797: }
798: }
799:
800: /*
801: * The following are defined to handle transparent data.
802: */
803:
804: void
805: TransStop()
806: {
807: #if defined(unix)
808: if (tcflag == 0) {
809: tcflag = -1;
810: (void) signal(SIGCHLD, SIG_DFL);
811: } else if (tcflag > 0) {
812: setcommandmode();
813: (void) close(tin);
814: (void) close(tout);
815: tin = savefd[0];
816: tout = savefd[1];
817: setconnmode();
818: tcflag = -1;
819: (void) signal(SIGCHLD, SIG_DFL);
820: }
821: #endif /* defined(unix) */
822: RefreshScreen();
823: }
824:
825: void
826: TransOut(buffer, count, kind, control)
827: unsigned char *buffer;
828: int count;
829: int kind; /* 0 or 5 */
830: int control; /* To see if we are done */
831: {
832: #if defined(unix)
833: extern char *transcom;
834: int inpipefd[2], outpipefd[2], savemode;
835: void aborttc();
836: #endif /* defined(unix) */
837:
838: while (DoTerminalOutput() == 0) {
839: #if defined(unix)
840: HaveInput = 0;
841: #endif /* defined(unix) */
842: }
843: #if defined(unix)
844: if (transcom && tcflag == -1) {
845: while (1) { /* go thru once */
846: if (pipe(outpipefd) < 0) {
847: break;
848: }
849: if (pipe(inpipefd) < 0) {
850: break;
851: }
852: if ((tcflag = fork()) == 0) {
853: (void) close(outpipefd[1]);
854: (void) close(0);
855: if (dup(outpipefd[0]) < 0) {
856: exit(1);
857: }
858: (void) close(outpipefd[0]);
859: (void) close(inpipefd[0]);
860: (void) close(1);
861: if (dup(inpipefd[1]) < 0) {
862: exit(1);
863: }
864: (void) close(inpipefd[1]);
865: if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) {
866: exit(1);
867: }
868: }
869: (void) close(inpipefd[1]);
870: (void) close(outpipefd[0]);
871: savefd[0] = tin;
872: savefd[1] = tout;
873: setcommandmode();
874: tin = inpipefd[0];
875: tout = outpipefd[1];
876: (void) signal(SIGCHLD, aborttc);
877: setconnmode();
878: tcflag = 1;
879: break;
880: }
881: if (tcflag < 1) {
882: tcflag = 0;
883: }
884: }
885: #endif /* defined(unix) */
886: (void) DataToTerminal(buffer, count);
887: if (control && (kind == 0)) { /* Send in AID byte */
888: SendToIBM();
889: } else {
890: TransInput(1, kind); /* Go get some data */
891: }
892: }
893:
894:
895: #if defined(unix)
896: static void
897: aborttc()
898: {
899: int savemode;
900:
901: setcommandmode();
902: (void) close(tin);
903: (void) close(tout);
904: tin = savefd[0];
905: tout = savefd[1];
906: setconnmode();
907: tcflag = 0;
908: }
909: #endif /* defined(unix) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.