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