1 /* 2 * Copyright (c) 1984, 1985, 1986 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[] = "@(#)outbound.c 3.1 10/29/86"; 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 "../ctlr/hostctlr.h" 34 #include "../ctlr/inbound.ext" 35 #include "../ctlr/oia.h" 36 #include "../ctlr/options.ext" 37 #include "../ctlr/outbound.ext" 38 #include "../ctlr/screen.h" 39 40 #include "../ascii/map3270.ext" 41 42 #include "../general/globals.h" 43 44 #include "video.h" 45 46 extern void EmptyTerminal(); 47 48 #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 49 terminalCursorAddress:UnLocked? CursorAddress: HighestScreen()) 50 51 52 static int terminalCursorAddress; /* where the cursor is on term */ 53 static int screenInitd; /* the screen has been initialized */ 54 static int screenStopped; /* the screen has been stopped */ 55 56 static int needToRing; /* need to ring terinal bell */ 57 58 typedef struct { 59 char 60 data, /* The data for this position */ 61 attr; /* The attributes for this position */ 62 } ScreenBuffer; 63 64 ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS]; 65 ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]]; 66 67 /* Variables for transparent mode */ 68 69 #include "disp_asc.out" 70 71 72 /* OurExitString - designed to keep us from going through infinite recursion */ 73 74 static void 75 OurExitString(file, string, value) 76 FILE *file; 77 char *string; 78 int value; 79 { 80 static int recursion = 0; 81 82 if (!recursion) { 83 recursion = 1; 84 ExitString(file, string, value); 85 } 86 } 87 88 89 static void 90 GoAway(from, where) 91 char *from; /* routine that gave error */ 92 int where; /* cursor address */ 93 { 94 char foo[100]; 95 96 sprintf(foo, "ERR from %s at %d (%d, %d)\n", 97 from, where, ScreenLine(where), ScreenLineOffset(where)); 98 OurExitString(stderr, foo, 1); 99 /* NOTREACHED */ 100 } 101 102 /* 103 * Routines to deal with the screen. These routines are lifted 104 * from mskermit. 105 */ 106 107 #define CRT_STATUS 0x3da /* Color card */ 108 #define DISPLAY_ENABLE 0x08 /* Enable */ 109 #define scrseg() ((crt_mode == 7)? 0xb000 : 0xb800) 110 #define scrwait() if (crt_mode != 7) { \ 111 while ((inp(CRT_STATUS)&DISPLAY_ENABLE) == 0) { \ 112 ; \ 113 } \ 114 } 115 static int 116 crt_mode, 117 crt_cols, 118 crt_lins, 119 curpage; 120 121 /* 122 * Set the cursor position to where it belongs. 123 */ 124 125 static void 126 setcursor(row, column, page) 127 int 128 row, 129 column, 130 page; 131 { 132 union REGS inregs, outregs; 133 134 inregs.h.dh = row; 135 inregs.h.dl = column; 136 inregs.h.bh = page; 137 inregs.h.ah = SetCursorPosition; 138 139 int86(BIOS_VIDEO, &inregs, &outregs); 140 } 141 /* 142 * Read the state of the video system. Put the cursor somewhere 143 * reasonable. 144 */ 145 146 static void 147 scrini() 148 { 149 union REGS inregs, outregs; 150 151 inregs.h.ah = CurrentVideoState; 152 int86(BIOS_VIDEO, &inregs, &outregs); 153 154 crt_mode = outregs.h.al; 155 crt_cols = outregs.h.ah; 156 crt_lins = 25; 157 curpage = outregs.h.bh; 158 159 inregs.h.ah = ReadCursorPosition; 160 inregs.h.bh = curpage; 161 162 int86(BIOS_VIDEO, &inregs, &outregs); 163 164 if (outregs.h.dh > crt_lins) { 165 outregs.h.dh = crt_lins; 166 } 167 if (outregs.h.dl > crt_cols) { 168 outregs.h.dl = crt_cols; 169 } 170 inregs.h.dh = outregs.h.dh; 171 inregs.h.dl = outregs.h.dl; 172 inregs.h.bh = curpage; 173 174 inregs.h.ah = SetCursorPosition; 175 int86(BIOS_VIDEO, &inregs, &outregs); 176 } 177 178 179 static void 180 scrwrite(source, length, offset) 181 ScreenBuffer *source; 182 int 183 length, 184 offset; 185 { 186 struct SREGS segregs; 187 188 segread(&segregs); /* read the current segment register */ 189 190 scrwait(); 191 movedata(segregs.ds, source, scrseg(), sizeof *source*offset, 192 sizeof *source*length); 193 } 194 195 static void 196 scrsave(buffer) 197 ScreenBuffer *buffer; 198 { 199 struct SREGS segregs; 200 201 segread(&segregs); /* read the current segment register */ 202 203 scrwait(); 204 movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2); 205 } 206 207 static void 208 scrrest(buffer) 209 ScreenBuffer *buffer; 210 { 211 scrwrite(buffer, crt_cols*crt_lins, 0); 212 } 213 214 static void 215 TryToSend() 216 { 217 #define STANDOUT 0x0a /* Highlighted mode */ 218 #define NORMAL 0x02 /* Normal mode */ 219 #define NONDISPLAY 0x00 /* Don't display */ 220 221 #define DoAttribute(a) \ 222 if (screenIsFormatted) { \ 223 if (IsNonDisplayAttr(a)) { \ 224 a = NONDISPLAY; /* don't display */ \ 225 } else if (IsHighlightedAttr(a)) { \ 226 a = STANDOUT; \ 227 } else { \ 228 a = NORMAL; \ 229 } \ 230 } else { \ 231 a = NORMAL; /* do display on unformatted */\ 232 } 233 ScreenImage *p, *upper; 234 ScreenBuffer *sp; 235 int fieldattr; /* spends most of its time == 0 or 1 */ 236 int screenIsFormatted = FormattedScreen(); 237 238 /* OK. We want to do this a quickly as possible. So, we assume we 239 * only need to go from Lowest to Highest. However, if we find a 240 * field in the middle, we do the whole screen. 241 * 242 * In particular, we separate out the two cases from the beginning. 243 */ 244 if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 245 sp = &Screen[Lowest]; 246 p = &Host[Lowest]; 247 upper = &Host[Highest]; 248 fieldattr = FieldAttributes(Lowest); 249 DoAttribute(fieldattr); /* Set standout, non-display status */ 250 251 while (p <= upper) { 252 if (IsStartFieldPointer(p)) { /* New field? */ 253 Highest = HighestScreen(); 254 Lowest = LowestScreen(); 255 TryToSend(); /* Recurse */ 256 return; 257 } else if (fieldattr) { /* Should we display? */ 258 /* Display translated data */ 259 sp->data = disp_asc[GetHostPointer(p)]; 260 } else { 261 sp->data = ' '; 262 } 263 sp->attr = fieldattr; 264 p++; 265 sp++; 266 } 267 } else { /* Going from Lowest to Highest */ 268 ScreenImage *End = &Host[ScreenSize]-1; 269 270 sp = Screen; 271 p = Host; 272 fieldattr = FieldAttributes(LowestScreen()); 273 DoAttribute(fieldattr); /* Set standout, non-display status */ 274 275 while (p <= End) { 276 if (IsStartFieldPointer(p)) { /* New field? */ 277 fieldattr = FieldAttributesPointer(p); /* Get attributes */ 278 DoAttribute(fieldattr); /* Set standout, non-display */ 279 } 280 if (fieldattr) { /* Should we display? */ 281 /* Display translated data */ 282 sp->data = disp_asc[GetHostPointer(p)]; 283 } else { 284 sp->data = ' '; 285 } 286 sp->attr = fieldattr; 287 p++; 288 sp++; 289 } 290 } 291 terminalCursorAddress = CorrectTerminalCursor(); 292 /* 293 * We might be here just to update the cursor address. 294 */ 295 if (Highest >= Lowest) { 296 scrwrite(Screen+Lowest, (1+Highest-Lowest), Lowest); 297 } 298 setcursor(ScreenLine(terminalCursorAddress), 299 ScreenLineOffset(terminalCursorAddress), 0); 300 Lowest = HighestScreen()+1; 301 Highest = LowestScreen()-1; 302 if (needToRing) { 303 DataToTerminal("\7", 1); 304 needToRing = 0; 305 } 306 return; 307 } 308 309 /* InitTerminal - called to initialize the screen, etc. */ 310 311 void 312 InitTerminal() 313 { 314 InitMapping(); /* Go do mapping file (MAP3270) first */ 315 if (!screenInitd) { /* not initialized */ 316 MaxNumberLines = 24; /* XXX */ 317 MaxNumberColumns = 80; /* XXX */ 318 scrini(); 319 scrsave(saveScreen); /* Save the screen buffer away */ 320 ClearArray(Screen); 321 terminalCursorAddress = SetBufferAddress(0,0); 322 screenInitd = 1; 323 screenStopped = 0; /* Not stopped */ 324 } 325 Initialized = 1; 326 } 327 328 329 /* StopScreen - called when we are going away... */ 330 331 void 332 StopScreen(doNewLine) 333 int doNewLine; 334 { 335 if (screenInitd && !screenStopped) { 336 scrrest(saveScreen); 337 setcursor(NumberLines-1, NumberColumns-1, 0); 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 bellpos0 = 0; /* Where error message goes */ 383 384 static char bellstring[100];/* Where message goes */ 385 386 #define BELL_SPACES 2 /* 2 spaces between border and bell */ 387 388 #define BELL_HIGH_LOW(h,l) { \ 389 h = bellpos0+2*NumberColumns+bellwinup+BELL_SPACES*2; \ 390 l = bellpos0; \ 391 } 392 393 void 394 BellOff() 395 { 396 if (bellwinup) { 397 BELL_HIGH_LOW(Highest,Lowest); 398 TryToSend(); 399 } 400 } 401 402 403 void 404 RingBell(s) 405 char *s; 406 { 407 needToRing = 1; 408 if (s) { 409 int len = strlen(s); 410 411 if (len > sizeof bellstring-1) { 412 OurExitString(stderr, "Bell string too long.", 1); 413 } 414 memcpy(bellstring, s, len+1); 415 BELL_HIGH_LOW(Highest,Lowest); 416 TryToSend(); 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 (!Initialized) { 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) 466 unsigned char *buffer; 467 int count; 468 { 469 470 while (DoTerminalOutput() == 0) { 471 ; 472 } 473 (void) DataToTerminal(buffer, count); 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