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