1 /* 2 * Copyright (c) 1984-1987 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[] = "@(#)termout.c 3.1 (Berkeley) 08/11/87"; 24 #endif /* lint */ 25 26 27 #include <stdio.h> 28 #include <dos.h> 29 #include "../general/general.h" 30 31 #include "../telnet.ext" 32 33 #include "../api/disp_asc.h" 34 #include "../ascii/map3270.ext" 35 36 #include "../ctlr/hostctlr.h" 37 #include "../ctlr/inbound.ext" 38 #include "../ctlr/oia.h" 39 #include "../ctlr/options.ext" 40 #include "../ctlr/outbound.ext" 41 #include "../ctlr/screen.h" 42 43 #include "../general/globals.h" 44 45 #include "video.h" 46 47 extern void EmptyTerminal(); 48 49 #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 50 terminalCursorAddress:UnLocked? CursorAddress: HighestScreen()) 51 52 53 static int terminalCursorAddress; /* where the cursor is on term */ 54 static int screenInitd; /* the screen has been initialized */ 55 static int screenStopped; /* the screen has been stopped */ 56 57 static int needToRing; /* need to ring terinal bell */ 58 59 typedef struct { 60 char 61 data, /* The data for this position */ 62 attr; /* The attributes for this position */ 63 } ScreenBuffer; 64 65 ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS]; 66 ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]]; 67 68 /* OurExitString - designed to keep us from going through infinite recursion */ 69 70 static void 71 OurExitString(file, string, value) 72 FILE *file; 73 char *string; 74 int value; 75 { 76 static int recursion = 0; 77 78 if (!recursion) { 79 recursion = 1; 80 ExitString(file, string, value); 81 } 82 } 83 84 85 static void 86 GoAway(from, where) 87 char *from; /* routine that gave error */ 88 int 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 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 } 111 static 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 121 static void 122 setcursor(row, column, page) 123 int 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 142 static void 143 scrini() 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 175 static void 176 scrwrite(source, length, offset) 177 ScreenBuffer *source; 178 int 179 length, 180 offset; 181 { 182 struct SREGS segregs; 183 184 segread(&segregs); /* read the current segment register */ 185 186 scrwait(); 187 movedata(segregs.ds, source, scrseg(), sizeof *source*offset, 188 sizeof *source*length); 189 } 190 191 static void 192 scrsave(buffer) 193 ScreenBuffer *buffer; 194 { 195 struct SREGS segregs; 196 197 segread(&segregs); /* read the current segment register */ 198 199 scrwait(); 200 movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2); 201 } 202 203 static void 204 scrrest(buffer) 205 ScreenBuffer *buffer; 206 { 207 scrwrite(buffer, crt_cols*crt_lins, 0); 208 } 209 210 static void 211 TryToSend() 212 { 213 #define STANDOUT 0x0a /* Highlighted mode */ 214 #define NORMAL 0x02 /* Normal mode */ 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 */\ 228 } 229 ScreenImage *p, *upper; 230 ScreenBuffer *sp; 231 int fieldattr; /* spends most of its time == 0 or 1 */ 232 int screenIsFormatted = FormattedScreen(); 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 sp = &Screen[Lowest]; 242 p = &Host[Lowest]; 243 upper = &Host[Highest]; 244 fieldattr = FieldAttributes(Lowest); 245 DoAttribute(fieldattr); /* Set standout, non-display status */ 246 247 while (p <= upper) { 248 if (IsStartFieldPointer(p)) { /* New field? */ 249 Highest = HighestScreen(); 250 Lowest = LowestScreen(); 251 TryToSend(); /* Recurse */ 252 return; 253 } else if (fieldattr) { /* Should we display? */ 254 /* Display translated data */ 255 sp->data = disp_asc[GetHostPointer(p)]; 256 } else { 257 sp->data = ' '; 258 } 259 sp->attr = fieldattr; 260 p++; 261 sp++; 262 } 263 } else { /* Going from Lowest to Highest */ 264 ScreenImage *End = &Host[ScreenSize]-1; 265 266 sp = Screen; 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? */ 273 fieldattr = FieldAttributesPointer(p); /* Get attributes */ 274 DoAttribute(fieldattr); /* Set standout, non-display */ 275 } 276 if (fieldattr) { /* Should we display? */ 277 /* Display translated data */ 278 sp->data = disp_asc[GetHostPointer(p)]; 279 } else { 280 sp->data = ' '; 281 } 282 sp->attr = fieldattr; 283 p++; 284 sp++; 285 } 286 } 287 terminalCursorAddress = CorrectTerminalCursor(); 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 } 294 setcursor(ScreenLine(terminalCursorAddress), 295 ScreenLineOffset(terminalCursorAddress), 0); 296 Lowest = HighestScreen()+1; 297 Highest = LowestScreen()-1; 298 if (needToRing) { 299 DataToTerminal("\7", 1); 300 needToRing = 0; 301 } 302 return; 303 } 304 305 /* InitTerminal - called to initialize the screen, etc. */ 306 307 void 308 InitTerminal() 309 { 310 InitMapping(); /* Go do mapping file (MAP3270) first */ 311 if (!screenInitd) { /* not initialized */ 312 MaxNumberLines = 24; /* XXX */ 313 MaxNumberColumns = 80; /* XXX */ 314 scrini(); 315 scrsave(saveScreen); /* Save the screen buffer away */ 316 ClearArray(Screen); 317 terminalCursorAddress = SetBufferAddress(0,0); 318 screenInitd = 1; 319 screenStopped = 0; /* Not stopped */ 320 } 321 } 322 323 324 /* StopScreen - called when we are going away... */ 325 326 void 327 StopScreen(doNewLine) 328 int doNewLine; 329 { 330 if (screenInitd && !screenStopped) { 331 scrrest(saveScreen); 332 setcursor(NumberLines-1, 1, 0); 333 if (doNewLine) { 334 StringToTerminal("\r\n"); 335 } 336 EmptyTerminal(); 337 screenStopped = 1; 338 } 339 } 340 341 342 /* RefreshScreen - called to cause the screen to be refreshed */ 343 344 void 345 RefreshScreen() 346 { 347 Highest = HighestScreen(); 348 Lowest = LowestScreen(); 349 TryToSend(); 350 } 351 352 353 /* ConnectScreen - called to reconnect to the screen */ 354 355 void 356 ConnectScreen() 357 { 358 if (screenInitd) { 359 RefreshScreen(); 360 screenStopped = 0; 361 } 362 } 363 364 /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 365 366 void 367 LocalClearScreen() 368 { 369 Clear3270(); 370 Lowest = LowestScreen(); /* everything in sync... */ 371 Highest = HighestScreen(); 372 TryToSend(); 373 } 374 375 /* 376 * Implement the bell/error message function. 377 */ 378 379 int 380 bellwinup = 0; /* If != 0, length of bell message */ 381 static int 382 bell_len = 0; /* Length of error message */ 383 384 385 void 386 BellOff() 387 { 388 ScreenBuffer a[100]; 389 int i; 390 391 if (bellwinup) { 392 unsigned char blank = ' '; 393 394 for (i = 0; i < bell_len; i++) { 395 a[i].attr = NORMAL; 396 a[i].data = ' '; 397 } 398 } 399 scrwrite(a, bell_len, 24*80); /* XXX */ 400 } 401 402 403 void 404 RingBell(s) 405 char *s; 406 { 407 needToRing = 1; 408 if (s) { 409 int i; 410 ScreenBuffer bellstring[100]; 411 412 bell_len = strlen(s); 413 bellwinup = 1; 414 if (bell_len > sizeof bellstring-1) { 415 OurExitString(stderr, "Bell string too long.", 1); 416 } 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 */ 422 } 423 } 424 425 /* 426 * Update the OIA area. 427 */ 428 429 void 430 ScreenOIA(oia) 431 OIA *oia; 432 { 433 } 434 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 441 int 442 DoTerminalOutput() 443 { 444 /* called just before a select to conserve IO to terminal */ 445 if (!(screenInitd||screenStopped)) { 446 return 1; /* No output if not initialized */ 447 } 448 if ((Lowest <= Highest) || needToRing || 449 (terminalCursorAddress != CorrectTerminalCursor())) { 450 TryToSend(); 451 } 452 if (Lowest > Highest) { 453 return 1; /* no more output now */ 454 } else { 455 return 0; /* more output for future */ 456 } 457 } 458 459 /* 460 * The following are defined to handle transparent data. 461 */ 462 463 void 464 TransStop() 465 { 466 RefreshScreen(); 467 } 468 469 void 470 TransOut(buffer, count, kind, control) 471 unsigned char *buffer; 472 int count; 473 int kind; /* 0 or 5 */ 474 int control; /* To see if we are done */ 475 { 476 char *ptr; 477 478 while (DoTerminalOutput() == 0) { 479 ; 480 } 481 for (ptr = buffer; ptr < buffer+count; ptr++) { 482 *ptr &= 0x7f; /* Turn off parity bit */ 483 } 484 (void) DataToTerminal(buffer, count); 485 if (control && (kind == 0)) { /* Send in AID byte */ 486 SendToIBM(); 487 } else { 488 TransInput(1, kind); /* Go get some data */ 489 } 490 } 491 492 /* 493 * init_screen() 494 * 495 * Initialize variables used by screen. 496 */ 497 498 void 499 init_screen() 500 { 501 bellwinup = 0; 502 } 503 504 505