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