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