Release 4.1
[unix-history] / usr / src / usr.bin / tn3270 / distribution / sys_dos / termout.c
CommitLineData
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
d43d1075 19static char sccsid[] = "@(#)termout.c 4.1 (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 31#include "../ctlr/hostctlr.h"
b4536ce1
GM
32#include "../ctlr/externs.h"
33#include "../ctlr/declare.h"
98e793e6 34#include "../ctlr/oia.h"
7f35cb09
GM
35#include "../ctlr/screen.h"
36
f478095f 37#include "../general/globals.h"
7f35cb09 38
da3205fa
GM
39#include "video.h"
40
7f35cb09
GM
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 */
7f35cb09
GM
50
51static int needToRing; /* need to ring terinal bell */
7f35cb09 52
98e793e6
GM
53typedef struct {
54 char
55 data, /* The data for this position */
56 attr; /* The attributes for this position */
57} ScreenBuffer;
7f35cb09 58
98e793e6 59ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
da3205fa 60ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]];
7f35cb09 61\f
7f35cb09
GM
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
7f35cb09
GM
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
da3205fa
GM
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();
84f75426
GM
181 movedata(segregs.ds, source, scrseg(), sizeof *source*offset,
182 sizeof *source*length);
da3205fa
GM
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();
84f75426 194 movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2);
da3205fa
GM
195}
196
197static void
198scrrest(buffer)
199ScreenBuffer *buffer;
200{
84f75426 201 scrwrite(buffer, crt_cols*crt_lins, 0);
da3205fa
GM
202}
203\f
7f35cb09 204static void
98e793e6 205TryToSend()
7f35cb09 206{
84f75426 207#define STANDOUT 0x0a /* Highlighted mode */
98e793e6 208#define NORMAL 0x02 /* Normal mode */
84f75426
GM
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 */\
7f35cb09
GM
222 }
223 ScreenImage *p, *upper;
98e793e6 224 ScreenBuffer *sp;
7f35cb09 225 int fieldattr; /* spends most of its time == 0 or 1 */
84f75426 226 int screenIsFormatted = FormattedScreen();
7f35cb09
GM
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())) {
98e793e6 235 sp = &Screen[Lowest];
7f35cb09 236 p = &Host[Lowest];
7f35cb09
GM
237 upper = &Host[Highest];
238 fieldattr = FieldAttributes(Lowest);
239 DoAttribute(fieldattr); /* Set standout, non-display status */
7f35cb09
GM
240
241 while (p <= upper) {
242 if (IsStartFieldPointer(p)) { /* New field? */
243 Highest = HighestScreen();
244 Lowest = LowestScreen();
98e793e6 245 TryToSend(); /* Recurse */
7f35cb09
GM
246 return;
247 } else if (fieldattr) { /* Should we display? */
84f75426
GM
248 /* Display translated data */
249 sp->data = disp_asc[GetHostPointer(p)];
7f35cb09 250 } else {
98e793e6 251 sp->data = ' ';
7f35cb09 252 }
84f75426 253 sp->attr = fieldattr;
7f35cb09 254 p++;
98e793e6 255 sp++;
7f35cb09
GM
256 }
257 } else { /* Going from Lowest to Highest */
98e793e6 258 ScreenImage *End = &Host[ScreenSize]-1;
7f35cb09 259
98e793e6 260 sp = Screen;
7f35cb09
GM
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? */
7f35cb09
GM
267 fieldattr = FieldAttributesPointer(p); /* Get attributes */
268 DoAttribute(fieldattr); /* Set standout, non-display */
84f75426
GM
269 }
270 if (fieldattr) { /* Should we display? */
271 /* Display translated data */
272 sp->data = disp_asc[GetHostPointer(p)];
7f35cb09 273 } else {
84f75426 274 sp->data = ' ';
7f35cb09 275 }
84f75426 276 sp->attr = fieldattr;
7f35cb09 277 p++;
98e793e6 278 sp++;
7f35cb09
GM
279 }
280 }
98e793e6 281 terminalCursorAddress = CorrectTerminalCursor();
84f75426
GM
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 }
da3205fa 288 setcursor(ScreenLine(terminalCursorAddress),
98e793e6 289 ScreenLineOffset(terminalCursorAddress), 0);
7f35cb09
GM
290 Lowest = HighestScreen()+1;
291 Highest = LowestScreen()-1;
7f35cb09 292 if (needToRing) {
98e793e6 293 DataToTerminal("\7", 1);
7f35cb09
GM
294 needToRing = 0;
295 }
7f35cb09
GM
296 return;
297}
7f35cb09
GM
298\f
299/* InitTerminal - called to initialize the screen, etc. */
300
301void
302InitTerminal()
303{
7f35cb09
GM
304 InitMapping(); /* Go do mapping file (MAP3270) first */
305 if (!screenInitd) { /* not initialized */
01929848
GM
306 MaxNumberLines = 24; /* XXX */
307 MaxNumberColumns = 80; /* XXX */
98e793e6 308 scrini();
da3205fa 309 scrsave(saveScreen); /* Save the screen buffer away */
98e793e6 310 ClearArray(Screen);
7f35cb09 311 terminalCursorAddress = SetBufferAddress(0,0);
7f35cb09
GM
312 screenInitd = 1;
313 screenStopped = 0; /* Not stopped */
314 }
7f35cb09
GM
315}
316
317
318/* StopScreen - called when we are going away... */
319
320void
321StopScreen(doNewLine)
322int doNewLine;
323{
324 if (screenInitd && !screenStopped) {
da3205fa 325 scrrest(saveScreen);
6d444e60
GM
326 setcursor(NumberLines-1, 1, 0);
327 if (doNewLine) {
328 StringToTerminal("\r\n");
329 }
330 EmptyTerminal();
331 screenStopped = 1;
7f35cb09
GM
332 }
333}
334
335
336/* RefreshScreen - called to cause the screen to be refreshed */
337
338void
339RefreshScreen()
340{
98e793e6
GM
341 Highest = HighestScreen();
342 Lowest = LowestScreen();
343 TryToSend();
7f35cb09
GM
344}
345
346
347/* ConnectScreen - called to reconnect to the screen */
348
349void
350ConnectScreen()
351{
352 if (screenInitd) {
7f35cb09 353 RefreshScreen();
7f35cb09
GM
354 screenStopped = 0;
355 }
356}
357
358/* LocalClearScreen() - clear the whole ball of wax, cheaply */
359
360void
361LocalClearScreen()
362{
7f35cb09 363 Clear3270();
98e793e6
GM
364 Lowest = LowestScreen(); /* everything in sync... */
365 Highest = HighestScreen();
366 TryToSend();
7f35cb09 367}
98e793e6
GM
368\f
369/*
370 * Implement the bell/error message function.
371 */
372
373int
374 bellwinup = 0; /* If != 0, length of bell message */
375static int
9da6eef6 376 bell_len = 0; /* Length of error message */
98e793e6 377
7f35cb09
GM
378
379void
380BellOff()
381{
9da6eef6
GM
382 ScreenBuffer a[100];
383 int i;
384
7f35cb09 385 if (bellwinup) {
9da6eef6
GM
386 unsigned char blank = ' ';
387
388 for (i = 0; i < bell_len; i++) {
389 a[i].attr = NORMAL;
390 a[i].data = ' ';
391 }
7f35cb09 392 }
9da6eef6 393 scrwrite(a, bell_len, 24*80); /* XXX */
7f35cb09
GM
394}
395
396
397void
398RingBell(s)
399char *s;
400{
401 needToRing = 1;
402 if (s) {
9da6eef6
GM
403 int i;
404 ScreenBuffer bellstring[100];
7f35cb09 405
9da6eef6
GM
406 bell_len = strlen(s);
407 bellwinup = 1;
408 if (bell_len > sizeof bellstring-1) {
98e793e6 409 OurExitString(stderr, "Bell string too long.", 1);
7f35cb09 410 }
9da6eef6
GM
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 */
7f35cb09
GM
416 }
417}
418\f
98e793e6
GM
419/*
420 * Update the OIA area.
421 */
422
423void
424ScreenOIA(oia)
425OIA *oia;
426{
427}
428\f
7f35cb09
GM
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 */
1b911685 439 if (!(screenInitd||screenStopped)) {
7f35cb09
GM
440 return 1; /* No output if not initialized */
441 }
442 if ((Lowest <= Highest) || needToRing ||
443 (terminalCursorAddress != CorrectTerminalCursor())) {
98e793e6 444 TryToSend();
7f35cb09
GM
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{
7f35cb09
GM
460 RefreshScreen();
461}
462
463void
24f81074 464TransOut(buffer, count, kind, control)
7f35cb09
GM
465unsigned char *buffer;
466int count;
24f81074
GM
467int kind; /* 0 or 5 */
468int control; /* To see if we are done */
7f35cb09 469{
24f81074 470 char *ptr;
7f35cb09
GM
471
472 while (DoTerminalOutput() == 0) {
98e793e6 473 ;
7f35cb09 474 }
24f81074
GM
475 for (ptr = buffer; ptr < buffer+count; ptr++) {
476 *ptr &= 0x7f; /* Turn off parity bit */
477 }
7f35cb09 478 (void) DataToTerminal(buffer, count);
24f81074
GM
479 if (control && (kind == 0)) { /* Send in AID byte */
480 SendToIBM();
481 } else {
482 TransInput(1, kind); /* Go get some data */
483 }
7f35cb09 484}
98e793e6
GM
485\f
486/*
487 * init_screen()
488 *
489 * Initialize variables used by screen.
490 */
7f35cb09 491
98e793e6
GM
492void
493init_screen()
7f35cb09 494{
98e793e6 495 bellwinup = 0;
7f35cb09 496}
98e793e6
GM
497
498