date and time created 87/05/19 16:13:31 by minshall
[unix-history] / usr / src / usr.bin / tn3270 / distribution / sys_dos / termout.c
CommitLineData
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
23static 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
46extern void EmptyTerminal();
47
48#define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
49 terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
50
51
52static int terminalCursorAddress; /* where the cursor is on term */
53static int screenInitd; /* the screen has been initialized */
54static int screenStopped; /* the screen has been stopped */
7f35cb09
GM
55
56static int needToRing; /* need to ring terinal bell */
7f35cb09 57
98e793e6
GM
58typedef struct {
59 char
60 data, /* The data for this position */
61 attr; /* The attributes for this position */
62} ScreenBuffer;
7f35cb09 63
98e793e6 64ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
da3205fa 65ScreenBuffer 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
74static void
75OurExitString(file, string, value)
76FILE *file;
77char *string;
78int 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
89static void
90GoAway(from, where)
91char *from; /* routine that gave error */
92int 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 }
115static 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
125static void
126setcursor(row, column, page)
127int
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
146static void
147scrini()
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
179static void
180scrwrite(source, length, offset)
181ScreenBuffer *source;
182int
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
194static void
195scrsave(buffer)
196ScreenBuffer *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
206static void
207scrrest(buffer)
208ScreenBuffer *buffer;
209{
210 scrwrite(buffer, 2*crt_cols*crt_lins, 0);
211}
212\f
7f35cb09 213static void
98e793e6 214TryToSend()
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
317void
318InitTerminal()
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
337void
338StopScreen(doNewLine)
339int 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
350void
351RefreshScreen()
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
361void
362ConnectScreen()
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
372void
373LocalClearScreen()
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
385int
386 bellwinup = 0; /* If != 0, length of bell message */
387static int
388 bellpos0 = 0; /* Where error message goes */
389
390static 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
399void
400BellOff()
401{
402 if (bellwinup) {
98e793e6
GM
403 BELL_HIGH_LOW(Highest,Lowest);
404 TryToSend();
7f35cb09
GM
405 }
406}
407
408
409void
410RingBell(s)
411char *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
430void
431ScreenOIA(oia)
432OIA *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
442int
443DoTerminalOutput()
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
464void
465TransStop()
466{
7f35cb09
GM
467 RefreshScreen();
468}
469
470void
471TransOut(buffer, count)
472unsigned char *buffer;
473int 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
488void
489init_screen()
7f35cb09 490{
98e793e6 491 bellwinup = 0;
7f35cb09 492}
98e793e6
GM
493
494