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