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