Install sccs headers and copyright notices.
[unix-history] / usr / src / usr.bin / tn3270 / distribution / sys_dos / termout.c
CommitLineData
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
992de934 23static char sccsid[] = "@(#)termout.c 1.13 (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
47extern void EmptyTerminal();
48
49#define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
50 terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
51
52
53static int terminalCursorAddress; /* where the cursor is on term */
54static int screenInitd; /* the screen has been initialized */
55static int screenStopped; /* the screen has been stopped */
7f35cb09
GM
56
57static int needToRing; /* need to ring terinal bell */
7f35cb09 58
98e793e6
GM
59typedef struct {
60 char
61 data, /* The data for this position */
62 attr; /* The attributes for this position */
63} ScreenBuffer;
7f35cb09 64
98e793e6 65ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
da3205fa 66ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]];
7f35cb09 67\f
7f35cb09
GM
68/* OurExitString - designed to keep us from going through infinite recursion */
69
70static void
71OurExitString(file, string, value)
72FILE *file;
73char *string;
74int 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
85static void
86GoAway(from, where)
87char *from; /* routine that gave error */
88int 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 }
111static 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
121static void
122setcursor(row, column, page)
123int
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
142static void
143scrini()
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
175static void
176scrwrite(source, length, offset)
177ScreenBuffer *source;
178int
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
191static void
192scrsave(buffer)
193ScreenBuffer *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
203static void
204scrrest(buffer)
205ScreenBuffer *buffer;
206{
84f75426 207 scrwrite(buffer, crt_cols*crt_lins, 0);
da3205fa
GM
208}
209\f
7f35cb09 210static void
98e793e6 211TryToSend()
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
307void
308InitTerminal()
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
326void
327StopScreen(doNewLine)
328int 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
344void
345RefreshScreen()
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
355void
356ConnectScreen()
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
366void
367LocalClearScreen()
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
379int
380 bellwinup = 0; /* If != 0, length of bell message */
381static int
9da6eef6 382 bell_len = 0; /* Length of error message */
98e793e6 383
7f35cb09
GM
384
385void
386BellOff()
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
403void
404RingBell(s)
405char *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
429void
430ScreenOIA(oia)
431OIA *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
441int
442DoTerminalOutput()
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
463void
464TransStop()
465{
7f35cb09
GM
466 RefreshScreen();
467}
468
469void
24f81074 470TransOut(buffer, count, kind, control)
7f35cb09
GM
471unsigned char *buffer;
472int count;
24f81074
GM
473int kind; /* 0 or 5 */
474int 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
498void
499init_screen()
7f35cb09 500{
98e793e6 501 bellwinup = 0;
7f35cb09 502}
98e793e6
GM
503
504