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