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