1 /*-
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)termout.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #include <stdio.h>
13 #include <dos.h>
14 #include "../general/general.h"
15
16 #include "../telnet.ext"
17
18 #include "../api/disp_asc.h"
19 #include "../ascii/map3270.ext"
20
21 #include "../ctlr/hostctlr.h"
22 #include "../ctlr/externs.h"
23 #include "../ctlr/declare.h"
24 #include "../ctlr/oia.h"
25 #include "../ctlr/screen.h"
26
27 #include "../general/globals.h"
28
29 #include "video.h"
30
31 extern void EmptyTerminal();
32
33 #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
34 terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
35
36
37 static int terminalCursorAddress; /* where the cursor is on term */
38 static int screenInitd; /* the screen has been initialized */
39 static int screenStopped; /* the screen has been stopped */
40
41 static int needToRing; /* need to ring terinal bell */
42
43 typedef struct {
44 char
45 data, /* The data for this position */
46 attr; /* The attributes for this position */
47 } ScreenBuffer;
48
49 ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
50 ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]];
51
52 /* OurExitString - designed to keep us from going through infinite recursion */
53
54 static void
OurExitString(file,string,value)55 OurExitString(file, string, value)
56 FILE *file;
57 char *string;
58 int value;
59 {
60 static int recursion = 0;
61
62 if (!recursion) {
63 recursion = 1;
64 ExitString(file, string, value);
65 }
66 }
67
68
69 static void
GoAway(from,where)70 GoAway(from, where)
71 char *from; /* routine that gave error */
72 int where; /* cursor address */
73 {
74 char foo[100];
75
76 sprintf(foo, "ERR from %s at %d (%d, %d)\n",
77 from, where, ScreenLine(where), ScreenLineOffset(where));
78 OurExitString(stderr, foo, 1);
79 /* NOTREACHED */
80 }
81
82 /*
83 * Routines to deal with the screen. These routines are lifted
84 * from mskermit.
85 */
86
87 #define CRT_STATUS 0x3da /* Color card */
88 #define DISPLAY_ENABLE 0x08 /* Enable */
89 #define scrseg() ((crt_mode == 7)? 0xb000 : 0xb800)
90 #define scrwait() if (crt_mode != 7) { \
91 while ((inp(CRT_STATUS)&DISPLAY_ENABLE) == 0) { \
92 ; \
93 } \
94 }
95 static int
96 crt_mode,
97 crt_cols,
98 crt_lins,
99 curpage;
100
101 /*
102 * Set the cursor position to where it belongs.
103 */
104
105 static void
setcursor(row,column,page)106 setcursor(row, column, page)
107 int
108 row,
109 column,
110 page;
111 {
112 union REGS inregs, outregs;
113
114 inregs.h.dh = row;
115 inregs.h.dl = column;
116 inregs.h.bh = page;
117 inregs.h.ah = SetCursorPosition;
118
119 int86(BIOS_VIDEO, &inregs, &outregs);
120 }
121 /*
122 * Read the state of the video system. Put the cursor somewhere
123 * reasonable.
124 */
125
126 static void
scrini()127 scrini()
128 {
129 union REGS inregs, outregs;
130
131 inregs.h.ah = CurrentVideoState;
132 int86(BIOS_VIDEO, &inregs, &outregs);
133
134 crt_mode = outregs.h.al;
135 crt_cols = outregs.h.ah;
136 crt_lins = 25;
137 curpage = outregs.h.bh;
138
139 inregs.h.ah = ReadCursorPosition;
140 inregs.h.bh = curpage;
141
142 int86(BIOS_VIDEO, &inregs, &outregs);
143
144 if (outregs.h.dh > crt_lins) {
145 outregs.h.dh = crt_lins;
146 }
147 if (outregs.h.dl > crt_cols) {
148 outregs.h.dl = crt_cols;
149 }
150 inregs.h.dh = outregs.h.dh;
151 inregs.h.dl = outregs.h.dl;
152 inregs.h.bh = curpage;
153
154 inregs.h.ah = SetCursorPosition;
155 int86(BIOS_VIDEO, &inregs, &outregs);
156 }
157
158
159 static void
scrwrite(source,length,offset)160 scrwrite(source, length, offset)
161 ScreenBuffer *source;
162 int
163 length,
164 offset;
165 {
166 struct SREGS segregs;
167
168 segread(&segregs); /* read the current segment register */
169
170 scrwait();
171 movedata(segregs.ds, source, scrseg(), sizeof *source*offset,
172 sizeof *source*length);
173 }
174
175 static void
scrsave(buffer)176 scrsave(buffer)
177 ScreenBuffer *buffer;
178 {
179 struct SREGS segregs;
180
181 segread(&segregs); /* read the current segment register */
182
183 scrwait();
184 movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2);
185 }
186
187 static void
scrrest(buffer)188 scrrest(buffer)
189 ScreenBuffer *buffer;
190 {
191 scrwrite(buffer, crt_cols*crt_lins, 0);
192 }
193
194 static void
TryToSend()195 TryToSend()
196 {
197 #define STANDOUT 0x0a /* Highlighted mode */
198 #define NORMAL 0x02 /* Normal mode */
199 #define NONDISPLAY 0x00 /* Don't display */
200
201 #define DoAttribute(a) \
202 if (screenIsFormatted) { \
203 if (IsNonDisplayAttr(a)) { \
204 a = NONDISPLAY; /* don't display */ \
205 } else if (IsHighlightedAttr(a)) { \
206 a = STANDOUT; \
207 } else { \
208 a = NORMAL; \
209 } \
210 } else { \
211 a = NORMAL; /* do display on unformatted */\
212 }
213 ScreenImage *p, *upper;
214 ScreenBuffer *sp;
215 int fieldattr; /* spends most of its time == 0 or 1 */
216 int screenIsFormatted = FormattedScreen();
217
218 /* OK. We want to do this a quickly as possible. So, we assume we
219 * only need to go from Lowest to Highest. However, if we find a
220 * field in the middle, we do the whole screen.
221 *
222 * In particular, we separate out the two cases from the beginning.
223 */
224 if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
225 sp = &Screen[Lowest];
226 p = &Host[Lowest];
227 upper = &Host[Highest];
228 fieldattr = FieldAttributes(Lowest);
229 DoAttribute(fieldattr); /* Set standout, non-display status */
230
231 while (p <= upper) {
232 if (IsStartFieldPointer(p)) { /* New field? */
233 Highest = HighestScreen();
234 Lowest = LowestScreen();
235 TryToSend(); /* Recurse */
236 return;
237 } else if (fieldattr) { /* Should we display? */
238 /* Display translated data */
239 sp->data = disp_asc[GetHostPointer(p)];
240 } else {
241 sp->data = ' ';
242 }
243 sp->attr = fieldattr;
244 p++;
245 sp++;
246 }
247 } else { /* Going from Lowest to Highest */
248 ScreenImage *End = &Host[ScreenSize]-1;
249
250 sp = Screen;
251 p = Host;
252 fieldattr = FieldAttributes(LowestScreen());
253 DoAttribute(fieldattr); /* Set standout, non-display status */
254
255 while (p <= End) {
256 if (IsStartFieldPointer(p)) { /* New field? */
257 fieldattr = FieldAttributesPointer(p); /* Get attributes */
258 DoAttribute(fieldattr); /* Set standout, non-display */
259 }
260 if (fieldattr) { /* Should we display? */
261 /* Display translated data */
262 sp->data = disp_asc[GetHostPointer(p)];
263 } else {
264 sp->data = ' ';
265 }
266 sp->attr = fieldattr;
267 p++;
268 sp++;
269 }
270 }
271 terminalCursorAddress = CorrectTerminalCursor();
272 /*
273 * We might be here just to update the cursor address.
274 */
275 if (Highest >= Lowest) {
276 scrwrite(Screen+Lowest, (1+Highest-Lowest), Lowest);
277 }
278 setcursor(ScreenLine(terminalCursorAddress),
279 ScreenLineOffset(terminalCursorAddress), 0);
280 Lowest = HighestScreen()+1;
281 Highest = LowestScreen()-1;
282 if (needToRing) {
283 DataToTerminal("\7", 1);
284 needToRing = 0;
285 }
286 return;
287 }
288
289 /* InitTerminal - called to initialize the screen, etc. */
290
291 void
InitTerminal()292 InitTerminal()
293 {
294 InitMapping(); /* Go do mapping file (MAP3270) first */
295 if (!screenInitd) { /* not initialized */
296 MaxNumberLines = 24; /* XXX */
297 MaxNumberColumns = 80; /* XXX */
298 scrini();
299 scrsave(saveScreen); /* Save the screen buffer away */
300 ClearArray(Screen);
301 terminalCursorAddress = SetBufferAddress(0,0);
302 screenInitd = 1;
303 screenStopped = 0; /* Not stopped */
304 }
305 }
306
307
308 /* StopScreen - called when we are going away... */
309
310 void
StopScreen(doNewLine)311 StopScreen(doNewLine)
312 int doNewLine;
313 {
314 if (screenInitd && !screenStopped) {
315 scrrest(saveScreen);
316 setcursor(NumberLines-1, 1, 0);
317 if (doNewLine) {
318 StringToTerminal("\r\n");
319 }
320 EmptyTerminal();
321 screenStopped = 1;
322 }
323 }
324
325
326 /* RefreshScreen - called to cause the screen to be refreshed */
327
328 void
RefreshScreen()329 RefreshScreen()
330 {
331 Highest = HighestScreen();
332 Lowest = LowestScreen();
333 TryToSend();
334 }
335
336
337 /* ConnectScreen - called to reconnect to the screen */
338
339 void
ConnectScreen()340 ConnectScreen()
341 {
342 if (screenInitd) {
343 RefreshScreen();
344 screenStopped = 0;
345 }
346 }
347
348 /* LocalClearScreen() - clear the whole ball of wax, cheaply */
349
350 void
LocalClearScreen()351 LocalClearScreen()
352 {
353 Clear3270();
354 Lowest = LowestScreen(); /* everything in sync... */
355 Highest = HighestScreen();
356 TryToSend();
357 }
358
359 /*
360 * Implement the bell/error message function.
361 */
362
363 int
364 bellwinup = 0; /* If != 0, length of bell message */
365 static int
366 bell_len = 0; /* Length of error message */
367
368
369 void
BellOff()370 BellOff()
371 {
372 ScreenBuffer a[100];
373 int i;
374
375 if (bellwinup) {
376 unsigned char blank = ' ';
377
378 for (i = 0; i < bell_len; i++) {
379 a[i].attr = NORMAL;
380 a[i].data = ' ';
381 }
382 }
383 scrwrite(a, bell_len, 24*80); /* XXX */
384 }
385
386
387 void
RingBell(s)388 RingBell(s)
389 char *s;
390 {
391 needToRing = 1;
392 if (s) {
393 int i;
394 ScreenBuffer bellstring[100];
395
396 bell_len = strlen(s);
397 bellwinup = 1;
398 if (bell_len > sizeof bellstring-1) {
399 OurExitString(stderr, "Bell string too long.", 1);
400 }
401 for (i = 0; i < bell_len; i++) {
402 bellstring[i].attr = STANDOUT;
403 bellstring[i].data = s[i];
404 }
405 scrwrite(bellstring, bell_len, 24*80); /* XXX */
406 }
407 }
408
409 /*
410 * Update the OIA area.
411 */
412
413 void
ScreenOIA(oia)414 ScreenOIA(oia)
415 OIA *oia;
416 {
417 }
418
419
420 /* returns a 1 if no more output available (so, go ahead and block),
421 or a 0 if there is more output available (so, just poll the other
422 sources/destinations, don't block).
423 */
424
425 int
DoTerminalOutput()426 DoTerminalOutput()
427 {
428 /* called just before a select to conserve IO to terminal */
429 if (!(screenInitd||screenStopped)) {
430 return 1; /* No output if not initialized */
431 }
432 if ((Lowest <= Highest) || needToRing ||
433 (terminalCursorAddress != CorrectTerminalCursor())) {
434 TryToSend();
435 }
436 if (Lowest > Highest) {
437 return 1; /* no more output now */
438 } else {
439 return 0; /* more output for future */
440 }
441 }
442
443 /*
444 * The following are defined to handle transparent data.
445 */
446
447 void
TransStop()448 TransStop()
449 {
450 RefreshScreen();
451 }
452
453 void
TransOut(buffer,count,kind,control)454 TransOut(buffer, count, kind, control)
455 unsigned char *buffer;
456 int count;
457 int kind; /* 0 or 5 */
458 int control; /* To see if we are done */
459 {
460 char *ptr;
461
462 while (DoTerminalOutput() == 0) {
463 ;
464 }
465 for (ptr = buffer; ptr < buffer+count; ptr++) {
466 *ptr &= 0x7f; /* Turn off parity bit */
467 }
468 (void) DataToTerminal(buffer, count);
469 if (control && (kind == 0)) { /* Send in AID byte */
470 SendToIBM();
471 } else {
472 TransInput(1, kind); /* Go get some data */
473 }
474 }
475
476 /*
477 * init_screen()
478 *
479 * Initialize variables used by screen.
480 */
481
482 void
init_screen()483 init_screen()
484 {
485 bellwinup = 0;
486 }
487
488
489