1 /* $NetBSD: screen.c,v 1.3 2011/07/03 20:14:13 tron Exp $ */ 2 3 /* 4 * Copyright (C) 1984-2011 Mark Nudelman 5 * 6 * You may distribute under the terms of either the GNU General Public 7 * License or the Less License, as specified in the README file. 8 * 9 * For more information about less, or for information on how to 10 * contact the author, see the README file. 11 */ 12 13 14 /* 15 * Routines which deal with the characteristics of the terminal. 16 * Uses termcap to be as terminal-independent as possible. 17 */ 18 19 #include "less.h" 20 #include "cmd.h" 21 22 #if MSDOS_COMPILER 23 #include "pckeys.h" 24 #if MSDOS_COMPILER==MSOFTC 25 #include <graph.h> 26 #else 27 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 28 #include <conio.h> 29 #if MSDOS_COMPILER==DJGPPC 30 #include <pc.h> 31 extern int fd0; 32 #endif 33 #else 34 #if MSDOS_COMPILER==WIN32C 35 #include <windows.h> 36 #endif 37 #endif 38 #endif 39 #include <time.h> 40 41 #else 42 43 #if HAVE_SYS_IOCTL_H 44 #include <sys/ioctl.h> 45 #endif 46 47 #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 48 #include <termios.h> 49 #else 50 #if HAVE_TERMIO_H 51 #include <termio.h> 52 #else 53 #if HAVE_SGSTAT_H 54 #include <sgstat.h> 55 #else 56 #include <sgtty.h> 57 #endif 58 #endif 59 #endif 60 61 #if HAVE_TERMCAP_H 62 #include <termcap.h> 63 #endif 64 #ifdef _OSK 65 #include <signal.h> 66 #endif 67 #if OS2 68 #include <sys/signal.h> 69 #include "pckeys.h" 70 #endif 71 #if HAVE_SYS_STREAM_H 72 #include <sys/stream.h> 73 #endif 74 #if HAVE_SYS_PTEM_H 75 #include <sys/ptem.h> 76 #endif 77 78 #endif /* MSDOS_COMPILER */ 79 80 /* 81 * Check for broken termios package that forces you to manually 82 * set the line discipline. 83 */ 84 #ifdef __ultrix__ 85 #define MUST_SET_LINE_DISCIPLINE 1 86 #else 87 #define MUST_SET_LINE_DISCIPLINE 0 88 #endif 89 90 #if OS2 91 #define DEFAULT_TERM "ansi" 92 static char *windowid; 93 #else 94 #define DEFAULT_TERM "unknown" 95 #endif 96 97 #if MSDOS_COMPILER==MSOFTC 98 static int videopages; 99 static long msec_loops; 100 static int flash_created = 0; 101 #define SETCOLORS(fg,bg) { _settextcolor(fg); _setbkcolor(bg); } 102 #endif 103 104 #if MSDOS_COMPILER==BORLANDC 105 static unsigned short *whitescreen; 106 static int flash_created = 0; 107 #endif 108 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 109 #define _settextposition(y,x) gotoxy(x,y) 110 #define _clearscreen(m) clrscr() 111 #define _outtext(s) cputs(s) 112 #define SETCOLORS(fg,bg) { textcolor(fg); textbackground(bg); } 113 extern int sc_height; 114 #endif 115 116 #if MSDOS_COMPILER==WIN32C 117 struct keyRecord 118 { 119 int ascii; 120 int scan; 121 } currentKey; 122 123 static int keyCount = 0; 124 static WORD curr_attr; 125 static int pending_scancode = 0; 126 static WORD *whitescreen; 127 128 static HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */ 129 static HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */ 130 HANDLE con_out = INVALID_HANDLE_VALUE; /* current console */ 131 132 extern int quitting; 133 static void win32_init_term(); 134 static void win32_deinit_term(); 135 136 #define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY) 137 #define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY) 138 #define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) 139 #define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \ 140 if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ 141 error("SETCOLORS failed"); } 142 #endif 143 144 #if MSDOS_COMPILER 145 public int nm_fg_color; /* Color of normal text */ 146 public int nm_bg_color; 147 public int bo_fg_color; /* Color of bold text */ 148 public int bo_bg_color; 149 public int ul_fg_color; /* Color of underlined text */ 150 public int ul_bg_color; 151 public int so_fg_color; /* Color of standout text */ 152 public int so_bg_color; 153 public int bl_fg_color; /* Color of blinking text */ 154 public int bl_bg_color; 155 static int sy_fg_color; /* Color of system text (before less) */ 156 static int sy_bg_color; 157 158 #else 159 160 /* 161 * Strings passed to tputs() to do various terminal functions. 162 */ 163 static char 164 *sc_pad, /* Pad string */ 165 *sc_home, /* Cursor home */ 166 *sc_addline, /* Add line, scroll down following lines */ 167 *sc_lower_left, /* Cursor to last line, first column */ 168 *sc_return, /* Cursor to beginning of current line */ 169 *sc_move, /* General cursor positioning */ 170 *sc_clear, /* Clear screen */ 171 *sc_eol_clear, /* Clear to end of line */ 172 *sc_eos_clear, /* Clear to end of screen */ 173 *sc_s_in, /* Enter standout (highlighted) mode */ 174 *sc_s_out, /* Exit standout mode */ 175 *sc_u_in, /* Enter underline mode */ 176 *sc_u_out, /* Exit underline mode */ 177 *sc_b_in, /* Enter bold mode */ 178 *sc_b_out, /* Exit bold mode */ 179 *sc_bl_in, /* Enter blink mode */ 180 *sc_bl_out, /* Exit blink mode */ 181 *sc_visual_bell, /* Visual bell (flash screen) sequence */ 182 *sc_backspace, /* Backspace cursor */ 183 *sc_s_keypad, /* Start keypad mode */ 184 *sc_e_keypad, /* End keypad mode */ 185 *sc_init, /* Startup terminal initialization */ 186 *sc_deinit; /* Exit terminal de-initialization */ 187 #endif 188 189 static int init_done = 0; 190 191 public int auto_wrap; /* Terminal does \r\n when write past margin */ 192 public int ignaw; /* Terminal ignores \n immediately after wrap */ 193 public int erase_char; /* The user's erase char */ 194 public int erase2_char; /* The user's other erase char */ 195 public int kill_char; /* The user's line-kill char */ 196 public int werase_char; /* The user's word-erase char */ 197 public int sc_width, sc_height; /* Height & width of screen */ 198 public int bo_s_width, bo_e_width; /* Printing width of boldface seq */ 199 public int ul_s_width, ul_e_width; /* Printing width of underline seq */ 200 public int so_s_width, so_e_width; /* Printing width of standout seq */ 201 public int bl_s_width, bl_e_width; /* Printing width of blink seq */ 202 public int above_mem, below_mem; /* Memory retained above/below screen */ 203 public int can_goto_line; /* Can move cursor to any line */ 204 public int clear_bg; /* Clear fills with background color */ 205 public int missing_cap = 0; /* Some capability is missing */ 206 207 static int attrmode = AT_NORMAL; 208 extern int binattr; 209 210 #if !MSDOS_COMPILER 211 static char *cheaper(); 212 static void tmodes(); 213 #endif 214 215 /* 216 * These two variables are sometimes defined in, 217 * and needed by, the termcap library. 218 */ 219 #if MUST_DEFINE_OSPEED 220 extern short ospeed; /* Terminal output baud rate */ 221 extern char PC; /* Pad character */ 222 #endif 223 #ifdef _OSK 224 short ospeed; 225 char PC_, *UP, *BC; 226 #endif 227 228 extern int quiet; /* If VERY_QUIET, use visual bell for bell */ 229 extern int no_back_scroll; 230 extern int swindow; 231 extern int no_init; 232 extern int quit_at_eof; 233 extern int more_mode; 234 extern int no_keypad; 235 extern int sigs; 236 extern int wscroll; 237 extern int screen_trashed; 238 extern int tty; 239 extern int top_scroll; 240 extern int oldbot; 241 #if HILITE_SEARCH 242 extern int hilite_search; 243 #endif 244 245 #ifndef HAVE_TERMCAP_H 246 extern char *tgetstr(); 247 extern char *tgoto(); 248 #endif 249 250 251 /* 252 * Change terminal to "raw mode", or restore to "normal" mode. 253 * "Raw mode" means 254 * 1. An outstanding read will complete on receipt of a single keystroke. 255 * 2. Input is not echoed. 256 * 3. On output, \n is mapped to \r\n. 257 * 4. \t is NOT expanded into spaces. 258 * 5. Signal-causing characters such as ctrl-C (interrupt), 259 * etc. are NOT disabled. 260 * It doesn't matter whether an input \n is mapped to \r, or vice versa. 261 */ 262 public void 263 raw_mode(on) 264 int on; 265 { 266 static int curr_on = 0; 267 268 if (on == curr_on) 269 return; 270 erase2_char = '\b'; /* in case OS doesn't know about erase2 */ 271 #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 272 { 273 struct termios s; 274 static struct termios save_term; 275 static int saved_term = 0; 276 277 if (on) 278 { 279 /* 280 * Get terminal modes. 281 */ 282 tcgetattr(tty, &s); 283 284 /* 285 * Save modes and set certain variables dependent on modes. 286 */ 287 if (!saved_term) 288 { 289 save_term = s; 290 saved_term = 1; 291 } 292 #if HAVE_OSPEED 293 switch (cfgetospeed(&s)) 294 { 295 #ifdef B0 296 case B0: ospeed = 0; break; 297 #endif 298 #ifdef B50 299 case B50: ospeed = 1; break; 300 #endif 301 #ifdef B75 302 case B75: ospeed = 2; break; 303 #endif 304 #ifdef B110 305 case B110: ospeed = 3; break; 306 #endif 307 #ifdef B134 308 case B134: ospeed = 4; break; 309 #endif 310 #ifdef B150 311 case B150: ospeed = 5; break; 312 #endif 313 #ifdef B200 314 case B200: ospeed = 6; break; 315 #endif 316 #ifdef B300 317 case B300: ospeed = 7; break; 318 #endif 319 #ifdef B600 320 case B600: ospeed = 8; break; 321 #endif 322 #ifdef B1200 323 case B1200: ospeed = 9; break; 324 #endif 325 #ifdef B1800 326 case B1800: ospeed = 10; break; 327 #endif 328 #ifdef B2400 329 case B2400: ospeed = 11; break; 330 #endif 331 #ifdef B4800 332 case B4800: ospeed = 12; break; 333 #endif 334 #ifdef B9600 335 case B9600: ospeed = 13; break; 336 #endif 337 #ifdef EXTA 338 case EXTA: ospeed = 14; break; 339 #endif 340 #ifdef EXTB 341 case EXTB: ospeed = 15; break; 342 #endif 343 #ifdef B57600 344 case B57600: ospeed = 16; break; 345 #endif 346 #ifdef B115200 347 case B115200: ospeed = 17; break; 348 #endif 349 default: ; 350 } 351 #endif 352 erase_char = s.c_cc[VERASE]; 353 #ifdef VERASE2 354 erase2_char = s.c_cc[VERASE2]; 355 #endif 356 kill_char = s.c_cc[VKILL]; 357 #ifdef VWERASE 358 werase_char = s.c_cc[VWERASE]; 359 #else 360 werase_char = CONTROL('W'); 361 #endif 362 363 /* 364 * Set the modes to the way we want them. 365 */ 366 s.c_lflag &= ~(0 367 #ifdef ICANON 368 | ICANON 369 #endif 370 #ifdef ECHO 371 | ECHO 372 #endif 373 #ifdef ECHOE 374 | ECHOE 375 #endif 376 #ifdef ECHOK 377 | ECHOK 378 #endif 379 #if ECHONL 380 | ECHONL 381 #endif 382 ); 383 384 s.c_oflag |= (0 385 #ifdef OXTABS 386 | OXTABS 387 #else 388 #ifdef TAB3 389 | TAB3 390 #else 391 #ifdef XTABS 392 | XTABS 393 #endif 394 #endif 395 #endif 396 #ifdef OPOST 397 | OPOST 398 #endif 399 #ifdef ONLCR 400 | ONLCR 401 #endif 402 ); 403 404 s.c_oflag &= ~(0 405 #ifdef ONOEOT 406 | ONOEOT 407 #endif 408 #ifdef OCRNL 409 | OCRNL 410 #endif 411 #ifdef ONOCR 412 | ONOCR 413 #endif 414 #ifdef ONLRET 415 | ONLRET 416 #endif 417 ); 418 s.c_cc[VMIN] = 1; 419 s.c_cc[VTIME] = 0; 420 #ifdef VLNEXT 421 s.c_cc[VLNEXT] = 0; 422 #endif 423 #ifdef VDSUSP 424 s.c_cc[VDSUSP] = 0; 425 #endif 426 #if MUST_SET_LINE_DISCIPLINE 427 /* 428 * System's termios is broken; need to explicitly 429 * request TERMIODISC line discipline. 430 */ 431 s.c_line = TERMIODISC; 432 #endif 433 } else 434 { 435 /* 436 * Restore saved modes. 437 */ 438 s = save_term; 439 } 440 #if HAVE_FSYNC 441 fsync(tty); 442 #endif 443 tcsetattr(tty, TCSADRAIN, &s); 444 #if MUST_SET_LINE_DISCIPLINE 445 if (!on) 446 { 447 /* 448 * Broken termios *ignores* any line discipline 449 * except TERMIODISC. A different old line discipline 450 * is therefore not restored, yet. Restore the old 451 * line discipline by hand. 452 */ 453 ioctl(tty, TIOCSETD, &save_term.c_line); 454 } 455 #endif 456 } 457 #else 458 #ifdef TCGETA 459 { 460 struct termio s; 461 static struct termio save_term; 462 static int saved_term = 0; 463 464 if (on) 465 { 466 /* 467 * Get terminal modes. 468 */ 469 ioctl(tty, TCGETA, &s); 470 471 /* 472 * Save modes and set certain variables dependent on modes. 473 */ 474 if (!saved_term) 475 { 476 save_term = s; 477 saved_term = 1; 478 } 479 #if HAVE_OSPEED 480 ospeed = s.c_cflag & CBAUD; 481 #endif 482 erase_char = s.c_cc[VERASE]; 483 kill_char = s.c_cc[VKILL]; 484 #ifdef VWERASE 485 werase_char = s.c_cc[VWERASE]; 486 #else 487 werase_char = CONTROL('W'); 488 #endif 489 490 /* 491 * Set the modes to the way we want them. 492 */ 493 s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); 494 s.c_oflag |= (OPOST|ONLCR|TAB3); 495 s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); 496 s.c_cc[VMIN] = 1; 497 s.c_cc[VTIME] = 0; 498 } else 499 { 500 /* 501 * Restore saved modes. 502 */ 503 s = save_term; 504 } 505 ioctl(tty, TCSETAW, &s); 506 } 507 #else 508 #ifdef TIOCGETP 509 { 510 struct sgttyb s; 511 static struct sgttyb save_term; 512 static int saved_term = 0; 513 514 if (on) 515 { 516 /* 517 * Get terminal modes. 518 */ 519 ioctl(tty, TIOCGETP, &s); 520 521 /* 522 * Save modes and set certain variables dependent on modes. 523 */ 524 if (!saved_term) 525 { 526 save_term = s; 527 saved_term = 1; 528 } 529 #if HAVE_OSPEED 530 ospeed = s.sg_ospeed; 531 #endif 532 erase_char = s.sg_erase; 533 kill_char = s.sg_kill; 534 werase_char = CONTROL('W'); 535 536 /* 537 * Set the modes to the way we want them. 538 */ 539 s.sg_flags |= CBREAK; 540 s.sg_flags &= ~(ECHO|XTABS); 541 } else 542 { 543 /* 544 * Restore saved modes. 545 */ 546 s = save_term; 547 } 548 ioctl(tty, TIOCSETN, &s); 549 } 550 #else 551 #ifdef _OSK 552 { 553 struct sgbuf s; 554 static struct sgbuf save_term; 555 static int saved_term = 0; 556 557 if (on) 558 { 559 /* 560 * Get terminal modes. 561 */ 562 _gs_opt(tty, &s); 563 564 /* 565 * Save modes and set certain variables dependent on modes. 566 */ 567 if (!saved_term) 568 { 569 save_term = s; 570 saved_term = 1; 571 } 572 erase_char = s.sg_bspch; 573 kill_char = s.sg_dlnch; 574 werase_char = CONTROL('W'); 575 576 /* 577 * Set the modes to the way we want them. 578 */ 579 s.sg_echo = 0; 580 s.sg_eofch = 0; 581 s.sg_pause = 0; 582 s.sg_psch = 0; 583 } else 584 { 585 /* 586 * Restore saved modes. 587 */ 588 s = save_term; 589 } 590 _ss_opt(tty, &s); 591 } 592 #else 593 /* MS-DOS, Windows, or OS2 */ 594 #if OS2 595 /* OS2 */ 596 LSIGNAL(SIGINT, SIG_IGN); 597 #endif 598 erase_char = '\b'; 599 #if MSDOS_COMPILER==DJGPPC 600 kill_char = CONTROL('U'); 601 /* 602 * So that when we shell out or run another program, its 603 * stdin is in cooked mode. We do not switch stdin to binary 604 * mode if fd0 is zero, since that means we were called before 605 * tty was reopened in open_getchr, in which case we would be 606 * changing the original stdin device outside less. 607 */ 608 if (fd0 != 0) 609 setmode(0, on ? O_BINARY : O_TEXT); 610 #else 611 kill_char = ESC; 612 #endif 613 werase_char = CONTROL('W'); 614 #endif 615 #endif 616 #endif 617 #endif 618 curr_on = on; 619 } 620 621 #if !MSDOS_COMPILER 622 /* 623 * Some glue to prevent calling termcap functions if tgetent() failed. 624 */ 625 static int hardcopy; 626 627 static char * 628 ltget_env(capname) 629 char *capname; 630 { 631 char name[16]; 632 char *s; 633 634 s = lgetenv("LESS_TERMCAP_DEBUG"); 635 if (s != NULL && *s != '\0') 636 { 637 struct env { struct env *next; char *name; char *value; }; 638 static struct env *envs = NULL; 639 struct env *p; 640 for (p = envs; p != NULL; p = p->next) 641 if (strcmp(p->name, capname) == 0) 642 return p->value; 643 p = (struct env *) ecalloc(1, sizeof(struct env)); 644 p->name = save(capname); 645 p->value = (char *) ecalloc(strlen(capname)+3, sizeof(char)); 646 sprintf(p->value, "<%s>", capname); 647 p->next = envs; 648 envs = p; 649 return p->value; 650 } 651 strcpy(name, "LESS_TERMCAP_"); 652 strcat(name, capname); 653 return (lgetenv(name)); 654 } 655 656 static int 657 ltgetflag(capname) 658 char *capname; 659 { 660 char *s; 661 662 if ((s = ltget_env(capname)) != NULL) 663 return (*s != '\0' && *s != '0'); 664 if (hardcopy) 665 return (0); 666 return (tgetflag(capname)); 667 } 668 669 static int 670 ltgetnum(capname) 671 char *capname; 672 { 673 char *s; 674 675 if ((s = ltget_env(capname)) != NULL) 676 return (atoi(s)); 677 if (hardcopy) 678 return (-1); 679 return (tgetnum(capname)); 680 } 681 682 static char * 683 ltgetstr(capname, pp) 684 char *capname; 685 char **pp; 686 { 687 char *s; 688 689 if ((s = ltget_env(capname)) != NULL) 690 return (s); 691 if (hardcopy) 692 return (NULL); 693 return (tgetstr(capname, pp)); 694 } 695 #endif /* MSDOS_COMPILER */ 696 697 /* 698 * Get size of the output screen. 699 */ 700 public void 701 scrsize() 702 { 703 register char *s; 704 int sys_height; 705 int sys_width; 706 #if !MSDOS_COMPILER 707 int n; 708 #endif 709 710 #define DEF_SC_WIDTH 80 711 #if MSDOS_COMPILER 712 #define DEF_SC_HEIGHT 25 713 #else 714 #define DEF_SC_HEIGHT 24 715 #endif 716 717 718 sys_width = sys_height = 0; 719 720 #if MSDOS_COMPILER==MSOFTC 721 { 722 struct videoconfig w; 723 _getvideoconfig(&w); 724 sys_height = w.numtextrows; 725 sys_width = w.numtextcols; 726 } 727 #else 728 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 729 { 730 struct text_info w; 731 gettextinfo(&w); 732 sys_height = w.screenheight; 733 sys_width = w.screenwidth; 734 } 735 #else 736 #if MSDOS_COMPILER==WIN32C 737 { 738 CONSOLE_SCREEN_BUFFER_INFO scr; 739 GetConsoleScreenBufferInfo(con_out, &scr); 740 sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1; 741 sys_width = scr.srWindow.Right - scr.srWindow.Left + 1; 742 } 743 #else 744 #if OS2 745 { 746 int s[2]; 747 _scrsize(s); 748 sys_width = s[0]; 749 sys_height = s[1]; 750 /* 751 * When using terminal emulators for XFree86/OS2, the 752 * _scrsize function does not work well. 753 * Call the scrsize.exe program to get the window size. 754 */ 755 windowid = getenv("WINDOWID"); 756 if (windowid != NULL) 757 { 758 FILE *fd = popen("scrsize", "rt"); 759 if (fd != NULL) 760 { 761 int w, h; 762 fscanf(fd, "%i %i", &w, &h); 763 if (w > 0 && h > 0) 764 { 765 sys_width = w; 766 sys_height = h; 767 } 768 pclose(fd); 769 } 770 } 771 } 772 #else 773 #ifdef TIOCGWINSZ 774 { 775 struct winsize w; 776 if (ioctl(2, TIOCGWINSZ, &w) == 0) 777 { 778 if (w.ws_row > 0) 779 sys_height = w.ws_row; 780 if (w.ws_col > 0) 781 sys_width = w.ws_col; 782 } 783 } 784 #else 785 #ifdef WIOCGETD 786 { 787 struct uwdata w; 788 if (ioctl(2, WIOCGETD, &w) == 0) 789 { 790 if (w.uw_height > 0) 791 sys_height = w.uw_height / w.uw_vs; 792 if (w.uw_width > 0) 793 sys_width = w.uw_width / w.uw_hs; 794 } 795 } 796 #endif 797 #endif 798 #endif 799 #endif 800 #endif 801 #endif 802 803 if (sys_height > 0) 804 sc_height = sys_height; 805 else if ((s = lgetenv("LINES")) != NULL) 806 sc_height = atoi(s); 807 #if !MSDOS_COMPILER 808 else if ((n = ltgetnum("li")) > 0) 809 sc_height = n; 810 #endif 811 else 812 sc_height = DEF_SC_HEIGHT; 813 814 if (sys_width > 0) 815 sc_width = sys_width; 816 else if ((s = lgetenv("COLUMNS")) != NULL) 817 sc_width = atoi(s); 818 #if !MSDOS_COMPILER 819 else if ((n = ltgetnum("co")) > 0) 820 sc_width = n; 821 #endif 822 else 823 sc_width = DEF_SC_WIDTH; 824 } 825 826 #if MSDOS_COMPILER==MSOFTC 827 /* 828 * Figure out how many empty loops it takes to delay a millisecond. 829 */ 830 static void 831 get_clock() 832 { 833 clock_t start; 834 835 /* 836 * Get synchronized at the start of a tick. 837 */ 838 start = clock(); 839 while (clock() == start) 840 ; 841 /* 842 * Now count loops till the next tick. 843 */ 844 start = clock(); 845 msec_loops = 0; 846 while (clock() == start) 847 msec_loops++; 848 /* 849 * Convert from (loops per clock) to (loops per millisecond). 850 */ 851 msec_loops *= CLOCKS_PER_SEC; 852 msec_loops /= 1000; 853 } 854 855 /* 856 * Delay for a specified number of milliseconds. 857 */ 858 static void 859 dummy_func() 860 { 861 static long delay_dummy = 0; 862 delay_dummy++; 863 } 864 865 static void 866 delay(msec) 867 int msec; 868 { 869 long i; 870 871 while (msec-- > 0) 872 { 873 for (i = 0; i < msec_loops; i++) 874 { 875 /* 876 * Make it look like we're doing something here, 877 * so the optimizer doesn't remove the whole loop. 878 */ 879 dummy_func(); 880 } 881 } 882 } 883 #endif 884 885 /* 886 * Return the characters actually input by a "special" key. 887 */ 888 public char * 889 special_key_str(key) 890 int key; 891 { 892 static char tbuf[40]; 893 char *s; 894 #if MSDOS_COMPILER || OS2 895 static char k_right[] = { '\340', PCK_RIGHT, 0 }; 896 static char k_left[] = { '\340', PCK_LEFT, 0 }; 897 static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; 898 static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; 899 static char k_insert[] = { '\340', PCK_INSERT, 0 }; 900 static char k_delete[] = { '\340', PCK_DELETE, 0 }; 901 static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; 902 static char k_ctl_backspace[] = { '\177', 0 }; 903 static char k_home[] = { '\340', PCK_HOME, 0 }; 904 static char k_end[] = { '\340', PCK_END, 0 }; 905 static char k_up[] = { '\340', PCK_UP, 0 }; 906 static char k_down[] = { '\340', PCK_DOWN, 0 }; 907 static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; 908 static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; 909 static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; 910 static char k_f1[] = { '\340', PCK_F1, 0 }; 911 #endif 912 #if !MSDOS_COMPILER 913 char *sp = tbuf; 914 #endif 915 916 switch (key) 917 { 918 #if OS2 919 /* 920 * If windowid is not NULL, assume less is executed in 921 * the XFree86 environment. 922 */ 923 case SK_RIGHT_ARROW: 924 s = windowid ? ltgetstr("kr", &sp) : k_right; 925 break; 926 case SK_LEFT_ARROW: 927 s = windowid ? ltgetstr("kl", &sp) : k_left; 928 break; 929 case SK_UP_ARROW: 930 s = windowid ? ltgetstr("ku", &sp) : k_up; 931 break; 932 case SK_DOWN_ARROW: 933 s = windowid ? ltgetstr("kd", &sp) : k_down; 934 break; 935 case SK_PAGE_UP: 936 s = windowid ? ltgetstr("kP", &sp) : k_pageup; 937 break; 938 case SK_PAGE_DOWN: 939 s = windowid ? ltgetstr("kN", &sp) : k_pagedown; 940 break; 941 case SK_HOME: 942 s = windowid ? ltgetstr("kh", &sp) : k_home; 943 break; 944 case SK_END: 945 s = windowid ? ltgetstr("@7", &sp) : k_end; 946 break; 947 case SK_DELETE: 948 if (windowid) 949 { 950 s = ltgetstr("kD", &sp); 951 if (s == NULL) 952 { 953 tbuf[0] = '\177'; 954 tbuf[1] = '\0'; 955 s = tbuf; 956 } 957 } else 958 s = k_delete; 959 break; 960 #endif 961 #if MSDOS_COMPILER 962 case SK_RIGHT_ARROW: 963 s = k_right; 964 break; 965 case SK_LEFT_ARROW: 966 s = k_left; 967 break; 968 case SK_UP_ARROW: 969 s = k_up; 970 break; 971 case SK_DOWN_ARROW: 972 s = k_down; 973 break; 974 case SK_PAGE_UP: 975 s = k_pageup; 976 break; 977 case SK_PAGE_DOWN: 978 s = k_pagedown; 979 break; 980 case SK_HOME: 981 s = k_home; 982 break; 983 case SK_END: 984 s = k_end; 985 break; 986 case SK_DELETE: 987 s = k_delete; 988 break; 989 #endif 990 #if MSDOS_COMPILER || OS2 991 case SK_INSERT: 992 s = k_insert; 993 break; 994 case SK_CTL_LEFT_ARROW: 995 s = k_ctl_left; 996 break; 997 case SK_CTL_RIGHT_ARROW: 998 s = k_ctl_right; 999 break; 1000 case SK_CTL_BACKSPACE: 1001 s = k_ctl_backspace; 1002 break; 1003 case SK_CTL_DELETE: 1004 s = k_ctl_delete; 1005 break; 1006 case SK_F1: 1007 s = k_f1; 1008 break; 1009 case SK_BACKTAB: 1010 s = k_backtab; 1011 break; 1012 #else 1013 case SK_RIGHT_ARROW: 1014 s = ltgetstr("kr", &sp); 1015 break; 1016 case SK_LEFT_ARROW: 1017 s = ltgetstr("kl", &sp); 1018 break; 1019 case SK_UP_ARROW: 1020 s = ltgetstr("ku", &sp); 1021 break; 1022 case SK_DOWN_ARROW: 1023 s = ltgetstr("kd", &sp); 1024 break; 1025 case SK_PAGE_UP: 1026 s = ltgetstr("kP", &sp); 1027 break; 1028 case SK_PAGE_DOWN: 1029 s = ltgetstr("kN", &sp); 1030 break; 1031 case SK_HOME: 1032 s = ltgetstr("kh", &sp); 1033 break; 1034 case SK_END: 1035 s = ltgetstr("@7", &sp); 1036 break; 1037 case SK_DELETE: 1038 s = ltgetstr("kD", &sp); 1039 if (s == NULL) 1040 { 1041 tbuf[0] = '\177'; 1042 tbuf[1] = '\0'; 1043 s = tbuf; 1044 } 1045 break; 1046 #endif 1047 case SK_CONTROL_K: 1048 tbuf[0] = CONTROL('K'); 1049 tbuf[1] = '\0'; 1050 s = tbuf; 1051 break; 1052 default: 1053 return (NULL); 1054 } 1055 return (s); 1056 } 1057 1058 /* 1059 * Get terminal capabilities via termcap. 1060 */ 1061 public void 1062 get_term() 1063 { 1064 #if MSDOS_COMPILER 1065 auto_wrap = 1; 1066 ignaw = 0; 1067 can_goto_line = 1; 1068 clear_bg = 1; 1069 /* 1070 * Set up default colors. 1071 * The xx_s_width and xx_e_width vars are already initialized to 0. 1072 */ 1073 #if MSDOS_COMPILER==MSOFTC 1074 sy_bg_color = _getbkcolor(); 1075 sy_fg_color = _gettextcolor(); 1076 get_clock(); 1077 #else 1078 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 1079 { 1080 struct text_info w; 1081 gettextinfo(&w); 1082 sy_bg_color = (w.attribute >> 4) & 0x0F; 1083 sy_fg_color = (w.attribute >> 0) & 0x0F; 1084 } 1085 #else 1086 #if MSDOS_COMPILER==WIN32C 1087 { 1088 DWORD nread; 1089 CONSOLE_SCREEN_BUFFER_INFO scr; 1090 1091 con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE); 1092 /* 1093 * Always open stdin in binary. Note this *must* be done 1094 * before any file operations have been done on fd0. 1095 */ 1096 SET_BINARY(0); 1097 GetConsoleScreenBufferInfo(con_out, &scr); 1098 ReadConsoleOutputAttribute(con_out, &curr_attr, 1099 1, scr.dwCursorPosition, &nread); 1100 sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */ 1101 sy_fg_color = curr_attr & FG_COLORS; 1102 } 1103 #endif 1104 #endif 1105 #endif 1106 nm_fg_color = sy_fg_color; 1107 nm_bg_color = sy_bg_color; 1108 bo_fg_color = 11; 1109 bo_bg_color = 0; 1110 ul_fg_color = 9; 1111 ul_bg_color = 0; 1112 so_fg_color = 15; 1113 so_bg_color = 9; 1114 bl_fg_color = 15; 1115 bl_bg_color = 0; 1116 1117 /* 1118 * Get size of the screen. 1119 */ 1120 scrsize(); 1121 pos_init(); 1122 1123 1124 #else /* !MSDOS_COMPILER */ 1125 1126 char *sp; 1127 register char *t1, *t2; 1128 char *term; 1129 char termbuf[TERMBUF_SIZE]; 1130 1131 static char sbuf[TERMSBUF_SIZE]; 1132 1133 #if OS2 1134 /* 1135 * Make sure the termcap database is available. 1136 */ 1137 sp = lgetenv("TERMCAP"); 1138 if (sp == NULL || *sp == '\0') 1139 { 1140 char *termcap; 1141 if ((sp = homefile("termcap.dat")) != NULL) 1142 { 1143 termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char)); 1144 sprintf(termcap, "TERMCAP=%s", sp); 1145 free(sp); 1146 putenv(termcap); 1147 } 1148 } 1149 #endif 1150 /* 1151 * Find out what kind of terminal this is. 1152 */ 1153 if ((term = lgetenv("TERM")) == NULL) 1154 term = DEFAULT_TERM; 1155 hardcopy = 0; 1156 if (tgetent(termbuf, term) != TGETENT_OK) 1157 hardcopy = 1; 1158 if (ltgetflag("hc")) 1159 hardcopy = 1; 1160 1161 /* 1162 * Get size of the screen. 1163 */ 1164 scrsize(); 1165 pos_init(); 1166 1167 auto_wrap = ltgetflag("am"); 1168 ignaw = ltgetflag("xn"); 1169 above_mem = ltgetflag("da"); 1170 below_mem = ltgetflag("db"); 1171 clear_bg = ltgetflag("ut"); 1172 1173 /* 1174 * Assumes termcap variable "sg" is the printing width of: 1175 * the standout sequence, the end standout sequence, 1176 * the underline sequence, the end underline sequence, 1177 * the boldface sequence, and the end boldface sequence. 1178 */ 1179 if ((so_s_width = ltgetnum("sg")) < 0) 1180 so_s_width = 0; 1181 so_e_width = so_s_width; 1182 1183 bo_s_width = bo_e_width = so_s_width; 1184 ul_s_width = ul_e_width = so_s_width; 1185 bl_s_width = bl_e_width = so_s_width; 1186 1187 #if HILITE_SEARCH 1188 if (so_s_width > 0 || so_e_width > 0) 1189 /* 1190 * Disable highlighting by default on magic cookie terminals. 1191 * Turning on highlighting might change the displayed width 1192 * of a line, causing the display to get messed up. 1193 * The user can turn it back on with -g, 1194 * but she won't like the results. 1195 */ 1196 hilite_search = 0; 1197 #endif 1198 1199 /* 1200 * Get various string-valued capabilities. 1201 */ 1202 sp = sbuf; 1203 1204 #if HAVE_OSPEED 1205 sc_pad = ltgetstr("pc", &sp); 1206 if (sc_pad != NULL) 1207 PC = *sc_pad; 1208 #endif 1209 1210 sc_s_keypad = ltgetstr("ks", &sp); 1211 if (sc_s_keypad == NULL) 1212 sc_s_keypad = ""; 1213 sc_e_keypad = ltgetstr("ke", &sp); 1214 if (sc_e_keypad == NULL) 1215 sc_e_keypad = ""; 1216 1217 /* 1218 * This loses for terminals with termcap entries with ti/te strings 1219 * that switch to/from an alternate screen, and we're in quit_at_eof 1220 * (eg, more(1)). 1221 */ 1222 if (quit_at_eof != OPT_ONPLUS && !more_mode) { 1223 sc_init = ltgetstr("ti", &sp); 1224 sc_deinit = ltgetstr("te", &sp); 1225 } else { 1226 sc_init = NULL; 1227 sc_deinit = NULL; 1228 } 1229 1230 if (sc_init == NULL) 1231 sc_init = ""; 1232 if (sc_deinit == NULL) 1233 sc_deinit = ""; 1234 1235 sc_eol_clear = ltgetstr("ce", &sp); 1236 if (sc_eol_clear == NULL || *sc_eol_clear == '\0') 1237 { 1238 missing_cap = 1; 1239 sc_eol_clear = ""; 1240 } 1241 1242 sc_eos_clear = ltgetstr("cd", &sp); 1243 if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0')) 1244 { 1245 missing_cap = 1; 1246 sc_eos_clear = ""; 1247 } 1248 1249 sc_clear = ltgetstr("cl", &sp); 1250 if (sc_clear == NULL || *sc_clear == '\0') 1251 { 1252 missing_cap = 1; 1253 sc_clear = "\n\n"; 1254 } 1255 1256 sc_move = ltgetstr("cm", &sp); 1257 if (sc_move == NULL || *sc_move == '\0') 1258 { 1259 /* 1260 * This is not an error here, because we don't 1261 * always need sc_move. 1262 * We need it only if we don't have home or lower-left. 1263 */ 1264 sc_move = ""; 1265 can_goto_line = 0; 1266 } else 1267 can_goto_line = 1; 1268 1269 tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp); 1270 tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp); 1271 tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp); 1272 tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp); 1273 1274 sc_visual_bell = ltgetstr("vb", &sp); 1275 if (sc_visual_bell == NULL) 1276 sc_visual_bell = ""; 1277 1278 if (ltgetflag("bs")) 1279 sc_backspace = "\b"; 1280 else 1281 { 1282 sc_backspace = ltgetstr("bc", &sp); 1283 if (sc_backspace == NULL || *sc_backspace == '\0') 1284 sc_backspace = "\b"; 1285 } 1286 1287 /* 1288 * Choose between using "ho" and "cm" ("home" and "cursor move") 1289 * to move the cursor to the upper left corner of the screen. 1290 */ 1291 t1 = ltgetstr("ho", &sp); 1292 if (t1 == NULL) 1293 t1 = ""; 1294 if (*sc_move == '\0') 1295 t2 = ""; 1296 else 1297 { 1298 strcpy(sp, tgoto(sc_move, 0, 0)); 1299 t2 = sp; 1300 sp += strlen(sp) + 1; 1301 } 1302 sc_home = cheaper(t1, t2, "|\b^"); 1303 1304 /* 1305 * Choose between using "ll" and "cm" ("lower left" and "cursor move") 1306 * to move the cursor to the lower left corner of the screen. 1307 */ 1308 t1 = ltgetstr("ll", &sp); 1309 if (t1 == NULL) 1310 t1 = ""; 1311 if (*sc_move == '\0') 1312 t2 = ""; 1313 else 1314 { 1315 strcpy(sp, tgoto(sc_move, 0, sc_height-1)); 1316 t2 = sp; 1317 sp += strlen(sp) + 1; 1318 } 1319 sc_lower_left = cheaper(t1, t2, "\r"); 1320 1321 /* 1322 * Get carriage return string. 1323 */ 1324 sc_return = ltgetstr("cr", &sp); 1325 if (sc_return == NULL) 1326 sc_return = "\r"; 1327 1328 /* 1329 * Choose between using "al" or "sr" ("add line" or "scroll reverse") 1330 * to add a line at the top of the screen. 1331 */ 1332 t1 = ltgetstr("al", &sp); 1333 if (t1 == NULL) 1334 t1 = ""; 1335 t2 = ltgetstr("sr", &sp); 1336 if (t2 == NULL) 1337 t2 = ""; 1338 #if OS2 1339 if (*t1 == '\0' && *t2 == '\0') 1340 sc_addline = ""; 1341 else 1342 #endif 1343 if (above_mem) 1344 sc_addline = t1; 1345 else 1346 sc_addline = cheaper(t1, t2, ""); 1347 if (*sc_addline == '\0') 1348 { 1349 /* 1350 * Force repaint on any backward movement. 1351 */ 1352 no_back_scroll = 1; 1353 } 1354 #endif /* MSDOS_COMPILER */ 1355 } 1356 1357 #if !MSDOS_COMPILER 1358 /* 1359 * Return the cost of displaying a termcap string. 1360 * We use the trick of calling tputs, but as a char printing function 1361 * we give it inc_costcount, which just increments "costcount". 1362 * This tells us how many chars would be printed by using this string. 1363 * {{ Couldn't we just use strlen? }} 1364 */ 1365 static int costcount; 1366 1367 /*ARGSUSED*/ 1368 static int 1369 inc_costcount(c) 1370 int c; 1371 { 1372 costcount++; 1373 return (c); 1374 } 1375 1376 static int 1377 cost(t) 1378 char *t; 1379 { 1380 costcount = 0; 1381 tputs(t, sc_height, inc_costcount); 1382 return (costcount); 1383 } 1384 1385 /* 1386 * Return the "best" of the two given termcap strings. 1387 * The best, if both exist, is the one with the lower 1388 * cost (see cost() function). 1389 */ 1390 static char * 1391 cheaper(t1, t2, def) 1392 char *t1, *t2; 1393 char *def; 1394 { 1395 if (*t1 == '\0' && *t2 == '\0') 1396 { 1397 missing_cap = 1; 1398 return (def); 1399 } 1400 if (*t1 == '\0') 1401 return (t2); 1402 if (*t2 == '\0') 1403 return (t1); 1404 if (cost(t1) < cost(t2)) 1405 return (t1); 1406 return (t2); 1407 } 1408 1409 static void 1410 tmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp) 1411 char *incap; 1412 char *outcap; 1413 char **instr; 1414 char **outstr; 1415 char *def_instr; 1416 char *def_outstr; 1417 char **spp; 1418 { 1419 *instr = ltgetstr(incap, spp); 1420 if (*instr == NULL) 1421 { 1422 /* Use defaults. */ 1423 *instr = def_instr; 1424 *outstr = def_outstr; 1425 return; 1426 } 1427 1428 *outstr = ltgetstr(outcap, spp); 1429 if (*outstr == NULL) 1430 /* No specific out capability; use "me". */ 1431 *outstr = ltgetstr("me", spp); 1432 if (*outstr == NULL) 1433 /* Don't even have "me"; use a null string. */ 1434 *outstr = ""; 1435 } 1436 1437 #endif /* MSDOS_COMPILER */ 1438 1439 1440 /* 1441 * Below are the functions which perform all the 1442 * terminal-specific screen manipulation. 1443 */ 1444 1445 1446 #if MSDOS_COMPILER 1447 1448 #if MSDOS_COMPILER==WIN32C 1449 static void 1450 _settextposition(int row, int col) 1451 { 1452 COORD cpos; 1453 CONSOLE_SCREEN_BUFFER_INFO csbi; 1454 1455 GetConsoleScreenBufferInfo(con_out, &csbi); 1456 cpos.X = csbi.srWindow.Left + (col - 1); 1457 cpos.Y = csbi.srWindow.Top + (row - 1); 1458 SetConsoleCursorPosition(con_out, cpos); 1459 } 1460 #endif 1461 1462 /* 1463 * Initialize the screen to the correct color at startup. 1464 */ 1465 static void 1466 initcolor() 1467 { 1468 SETCOLORS(nm_fg_color, nm_bg_color); 1469 #if 0 1470 /* 1471 * This clears the screen at startup. This is different from 1472 * the behavior of other versions of less. Disable it for now. 1473 */ 1474 char *blanks; 1475 int row; 1476 int col; 1477 1478 /* 1479 * Create a complete, blank screen using "normal" colors. 1480 */ 1481 SETCOLORS(nm_fg_color, nm_bg_color); 1482 blanks = (char *) ecalloc(width+1, sizeof(char)); 1483 for (col = 0; col < sc_width; col++) 1484 blanks[col] = ' '; 1485 blanks[sc_width] = '\0'; 1486 for (row = 0; row < sc_height; row++) 1487 _outtext(blanks); 1488 free(blanks); 1489 #endif 1490 } 1491 #endif 1492 1493 #if MSDOS_COMPILER==WIN32C 1494 1495 /* 1496 * Termcap-like init with a private win32 console. 1497 */ 1498 static void 1499 win32_init_term() 1500 { 1501 CONSOLE_SCREEN_BUFFER_INFO scr; 1502 COORD size; 1503 1504 if (con_out_save == INVALID_HANDLE_VALUE) 1505 return; 1506 1507 GetConsoleScreenBufferInfo(con_out_save, &scr); 1508 1509 if (con_out_ours == INVALID_HANDLE_VALUE) 1510 { 1511 /* 1512 * Create our own screen buffer, so that we 1513 * may restore the original when done. 1514 */ 1515 con_out_ours = CreateConsoleScreenBuffer( 1516 GENERIC_WRITE | GENERIC_READ, 1517 FILE_SHARE_WRITE | FILE_SHARE_READ, 1518 (LPSECURITY_ATTRIBUTES) NULL, 1519 CONSOLE_TEXTMODE_BUFFER, 1520 (LPVOID) NULL); 1521 } 1522 1523 size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 1524 size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 1525 SetConsoleScreenBufferSize(con_out_ours, size); 1526 SetConsoleActiveScreenBuffer(con_out_ours); 1527 con_out = con_out_ours; 1528 } 1529 1530 /* 1531 * Restore the startup console. 1532 */ 1533 static void 1534 win32_deinit_term() 1535 { 1536 if (con_out_save == INVALID_HANDLE_VALUE) 1537 return; 1538 if (quitting) 1539 (void) CloseHandle(con_out_ours); 1540 SetConsoleActiveScreenBuffer(con_out_save); 1541 con_out = con_out_save; 1542 } 1543 1544 #endif 1545 1546 /* 1547 * Initialize terminal 1548 */ 1549 public void 1550 init() 1551 { 1552 #if !MSDOS_COMPILER 1553 if (!no_init) 1554 tputs(sc_init, sc_height, putchr); 1555 if (!no_keypad) 1556 tputs(sc_s_keypad, sc_height, putchr); 1557 if (top_scroll) 1558 { 1559 int i; 1560 1561 /* 1562 * This is nice to terminals with no alternate screen, 1563 * but with saved scrolled-off-the-top lines. This way, 1564 * no previous line is lost, but we start with a whole 1565 * screen to ourself. 1566 */ 1567 for (i = 1; i < sc_height; i++) 1568 putchr('\n'); 1569 } else 1570 line_left(); 1571 #else 1572 #if MSDOS_COMPILER==WIN32C 1573 if (!no_init) 1574 win32_init_term(); 1575 #endif 1576 initcolor(); 1577 flush(); 1578 #endif 1579 init_done = 1; 1580 } 1581 1582 /* 1583 * Deinitialize terminal 1584 */ 1585 public void 1586 deinit() 1587 { 1588 if (!init_done) 1589 return; 1590 #if !MSDOS_COMPILER 1591 if (!no_keypad) 1592 tputs(sc_e_keypad, sc_height, putchr); 1593 if (!no_init) 1594 tputs(sc_deinit, sc_height, putchr); 1595 #else 1596 /* Restore system colors. */ 1597 SETCOLORS(sy_fg_color, sy_bg_color); 1598 #if MSDOS_COMPILER==WIN32C 1599 if (!no_init) 1600 win32_deinit_term(); 1601 #else 1602 /* Need clreol to make SETCOLORS take effect. */ 1603 clreol(); 1604 #endif 1605 #endif 1606 init_done = 0; 1607 } 1608 1609 /* 1610 * Home cursor (move to upper left corner of screen). 1611 */ 1612 public void 1613 home() 1614 { 1615 #if !MSDOS_COMPILER 1616 tputs(sc_home, 1, putchr); 1617 #else 1618 flush(); 1619 _settextposition(1,1); 1620 #endif 1621 } 1622 1623 /* 1624 * Add a blank line (called with cursor at home). 1625 * Should scroll the display down. 1626 */ 1627 public void 1628 add_line() 1629 { 1630 #if !MSDOS_COMPILER 1631 tputs(sc_addline, sc_height, putchr); 1632 #else 1633 flush(); 1634 #if MSDOS_COMPILER==MSOFTC 1635 _scrolltextwindow(_GSCROLLDOWN); 1636 _settextposition(1,1); 1637 #else 1638 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 1639 movetext(1,1, sc_width,sc_height-1, 1,2); 1640 gotoxy(1,1); 1641 clreol(); 1642 #else 1643 #if MSDOS_COMPILER==WIN32C 1644 { 1645 CHAR_INFO fillchar; 1646 SMALL_RECT rcSrc, rcClip; 1647 COORD new_org; 1648 CONSOLE_SCREEN_BUFFER_INFO csbi; 1649 1650 GetConsoleScreenBufferInfo(con_out,&csbi); 1651 1652 /* The clip rectangle is the entire visible screen. */ 1653 rcClip.Left = csbi.srWindow.Left; 1654 rcClip.Top = csbi.srWindow.Top; 1655 rcClip.Right = csbi.srWindow.Right; 1656 rcClip.Bottom = csbi.srWindow.Bottom; 1657 1658 /* The source rectangle is the visible screen minus the last line. */ 1659 rcSrc = rcClip; 1660 rcSrc.Bottom--; 1661 1662 /* Move the top left corner of the source window down one row. */ 1663 new_org.X = rcSrc.Left; 1664 new_org.Y = rcSrc.Top + 1; 1665 1666 /* Fill the right character and attributes. */ 1667 fillchar.Char.AsciiChar = ' '; 1668 curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 1669 fillchar.Attributes = curr_attr; 1670 ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 1671 _settextposition(1,1); 1672 } 1673 #endif 1674 #endif 1675 #endif 1676 #endif 1677 } 1678 1679 #if 0 1680 /* 1681 * Remove the n topmost lines and scroll everything below it in the 1682 * window upward. This is needed to stop leaking the topmost line 1683 * into the scrollback buffer when we go down-one-line (in WIN32). 1684 */ 1685 public void 1686 remove_top(n) 1687 int n; 1688 { 1689 #if MSDOS_COMPILER==WIN32C 1690 SMALL_RECT rcSrc, rcClip; 1691 CHAR_INFO fillchar; 1692 COORD new_org; 1693 CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 1694 1695 if (n >= sc_height - 1) 1696 { 1697 clear(); 1698 home(); 1699 return; 1700 } 1701 1702 flush(); 1703 1704 GetConsoleScreenBufferInfo(con_out, &csbi); 1705 1706 /* Get the extent of all-visible-rows-but-the-last. */ 1707 rcSrc.Left = csbi.srWindow.Left; 1708 rcSrc.Top = csbi.srWindow.Top + n; 1709 rcSrc.Right = csbi.srWindow.Right; 1710 rcSrc.Bottom = csbi.srWindow.Bottom; 1711 1712 /* Get the clip rectangle. */ 1713 rcClip.Left = rcSrc.Left; 1714 rcClip.Top = csbi.srWindow.Top; 1715 rcClip.Right = rcSrc.Right; 1716 rcClip.Bottom = rcSrc.Bottom ; 1717 1718 /* Move the source window up n rows. */ 1719 new_org.X = rcSrc.Left; 1720 new_org.Y = rcSrc.Top - n; 1721 1722 /* Fill the right character and attributes. */ 1723 fillchar.Char.AsciiChar = ' '; 1724 curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 1725 fillchar.Attributes = curr_attr; 1726 1727 ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 1728 1729 /* Position cursor on first blank line. */ 1730 goto_line(sc_height - n - 1); 1731 #endif 1732 } 1733 #endif 1734 1735 #if MSDOS_COMPILER==WIN32C 1736 /* 1737 * Clear the screen. 1738 */ 1739 static void 1740 win32_clear() 1741 { 1742 /* 1743 * This will clear only the currently visible rows of the NT 1744 * console buffer, which means none of the precious scrollback 1745 * rows are touched making for faster scrolling. Note that, if 1746 * the window has fewer columns than the console buffer (i.e. 1747 * there is a horizontal scrollbar as well), the entire width 1748 * of the visible rows will be cleared. 1749 */ 1750 COORD topleft; 1751 DWORD nchars; 1752 DWORD winsz; 1753 CONSOLE_SCREEN_BUFFER_INFO csbi; 1754 1755 /* get the number of cells in the current buffer */ 1756 GetConsoleScreenBufferInfo(con_out, &csbi); 1757 winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); 1758 topleft.X = 0; 1759 topleft.Y = csbi.srWindow.Top; 1760 1761 curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 1762 FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars); 1763 FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars); 1764 } 1765 1766 /* 1767 * Remove the n topmost lines and scroll everything below it in the 1768 * window upward. 1769 */ 1770 public void 1771 win32_scroll_up(n) 1772 int n; 1773 { 1774 SMALL_RECT rcSrc, rcClip; 1775 CHAR_INFO fillchar; 1776 COORD topleft; 1777 COORD new_org; 1778 DWORD nchars; 1779 DWORD size; 1780 CONSOLE_SCREEN_BUFFER_INFO csbi; 1781 1782 if (n <= 0) 1783 return; 1784 1785 if (n >= sc_height - 1) 1786 { 1787 win32_clear(); 1788 _settextposition(1,1); 1789 return; 1790 } 1791 1792 /* Get the extent of what will remain visible after scrolling. */ 1793 GetConsoleScreenBufferInfo(con_out, &csbi); 1794 rcSrc.Left = csbi.srWindow.Left; 1795 rcSrc.Top = csbi.srWindow.Top + n; 1796 rcSrc.Right = csbi.srWindow.Right; 1797 rcSrc.Bottom = csbi.srWindow.Bottom; 1798 1799 /* Get the clip rectangle. */ 1800 rcClip.Left = rcSrc.Left; 1801 rcClip.Top = csbi.srWindow.Top; 1802 rcClip.Right = rcSrc.Right; 1803 rcClip.Bottom = rcSrc.Bottom ; 1804 1805 /* Move the source text to the top of the screen. */ 1806 new_org.X = rcSrc.Left; 1807 new_org.Y = rcClip.Top; 1808 1809 /* Fill the right character and attributes. */ 1810 fillchar.Char.AsciiChar = ' '; 1811 fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color); 1812 1813 /* Scroll the window. */ 1814 SetConsoleTextAttribute(con_out, fillchar.Attributes); 1815 ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 1816 1817 /* Clear remaining lines at bottom. */ 1818 topleft.X = csbi.dwCursorPosition.X; 1819 topleft.Y = rcSrc.Bottom - n; 1820 size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X); 1821 FillConsoleOutputCharacter(con_out, ' ', size, topleft, 1822 &nchars); 1823 FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft, 1824 &nchars); 1825 SetConsoleTextAttribute(con_out, curr_attr); 1826 1827 /* Move cursor n lines up from where it was. */ 1828 csbi.dwCursorPosition.Y -= n; 1829 SetConsoleCursorPosition(con_out, csbi.dwCursorPosition); 1830 } 1831 #endif 1832 1833 /* 1834 * Move cursor to lower left corner of screen. 1835 */ 1836 public void 1837 lower_left() 1838 { 1839 #if !MSDOS_COMPILER 1840 tputs(sc_lower_left, 1, putchr); 1841 #else 1842 flush(); 1843 _settextposition(sc_height, 1); 1844 #endif 1845 } 1846 1847 /* 1848 * Move cursor to left position of current line. 1849 */ 1850 public void 1851 line_left() 1852 { 1853 #if !MSDOS_COMPILER 1854 tputs(sc_return, 1, putchr); 1855 #else 1856 int row; 1857 flush(); 1858 #if MSDOS_COMPILER==WIN32C 1859 { 1860 CONSOLE_SCREEN_BUFFER_INFO scr; 1861 GetConsoleScreenBufferInfo(con_out, &scr); 1862 row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 1863 } 1864 #else 1865 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 1866 row = wherey(); 1867 #else 1868 { 1869 struct rccoord tpos = _gettextposition(); 1870 row = tpos.row; 1871 } 1872 #endif 1873 #endif 1874 _settextposition(row, 1); 1875 #endif 1876 } 1877 1878 /* 1879 * Check if the console size has changed and reset internals 1880 * (in lieu of SIGWINCH for WIN32). 1881 */ 1882 public void 1883 check_winch() 1884 { 1885 #if MSDOS_COMPILER==WIN32C 1886 CONSOLE_SCREEN_BUFFER_INFO scr; 1887 COORD size; 1888 1889 if (con_out == INVALID_HANDLE_VALUE) 1890 return; 1891 1892 flush(); 1893 GetConsoleScreenBufferInfo(con_out, &scr); 1894 size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 1895 size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 1896 if (size.Y != sc_height || size.X != sc_width) 1897 { 1898 sc_height = size.Y; 1899 sc_width = size.X; 1900 if (!no_init && con_out_ours == con_out) 1901 SetConsoleScreenBufferSize(con_out, size); 1902 pos_init(); 1903 wscroll = (sc_height + 1) / 2; 1904 screen_trashed = 1; 1905 } 1906 #endif 1907 } 1908 1909 /* 1910 * Goto a specific line on the screen. 1911 */ 1912 public void 1913 goto_line(slinenum) 1914 int slinenum; 1915 { 1916 #if !MSDOS_COMPILER 1917 tputs(tgoto(sc_move, 0, slinenum), 1, putchr); 1918 #else 1919 flush(); 1920 _settextposition(slinenum+1, 1); 1921 #endif 1922 } 1923 1924 #if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC 1925 /* 1926 * Create an alternate screen which is all white. 1927 * This screen is used to create a "flash" effect, by displaying it 1928 * briefly and then switching back to the normal screen. 1929 * {{ Yuck! There must be a better way to get a visual bell. }} 1930 */ 1931 static void 1932 create_flash() 1933 { 1934 #if MSDOS_COMPILER==MSOFTC 1935 struct videoconfig w; 1936 char *blanks; 1937 int row, col; 1938 1939 _getvideoconfig(&w); 1940 videopages = w.numvideopages; 1941 if (videopages < 2) 1942 { 1943 at_enter(AT_STANDOUT); 1944 at_exit(); 1945 } else 1946 { 1947 _setactivepage(1); 1948 at_enter(AT_STANDOUT); 1949 blanks = (char *) ecalloc(w.numtextcols, sizeof(char)); 1950 for (col = 0; col < w.numtextcols; col++) 1951 blanks[col] = ' '; 1952 for (row = w.numtextrows; row > 0; row--) 1953 _outmem(blanks, w.numtextcols); 1954 _setactivepage(0); 1955 _setvisualpage(0); 1956 free(blanks); 1957 at_exit(); 1958 } 1959 #else 1960 #if MSDOS_COMPILER==BORLANDC 1961 register int n; 1962 1963 whitescreen = (unsigned short *) 1964 malloc(sc_width * sc_height * sizeof(short)); 1965 if (whitescreen == NULL) 1966 return; 1967 for (n = 0; n < sc_width * sc_height; n++) 1968 whitescreen[n] = 0x7020; 1969 #else 1970 #if MSDOS_COMPILER==WIN32C 1971 register int n; 1972 1973 whitescreen = (WORD *) 1974 malloc(sc_height * sc_width * sizeof(WORD)); 1975 if (whitescreen == NULL) 1976 return; 1977 /* Invert the standard colors. */ 1978 for (n = 0; n < sc_width * sc_height; n++) 1979 whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color); 1980 #endif 1981 #endif 1982 #endif 1983 flash_created = 1; 1984 } 1985 #endif /* MSDOS_COMPILER */ 1986 1987 /* 1988 * Output the "visual bell", if there is one. 1989 */ 1990 public void 1991 vbell() 1992 { 1993 #if !MSDOS_COMPILER 1994 if (*sc_visual_bell == '\0') 1995 return; 1996 tputs(sc_visual_bell, sc_height, putchr); 1997 #else 1998 #if MSDOS_COMPILER==DJGPPC 1999 ScreenVisualBell(); 2000 #else 2001 #if MSDOS_COMPILER==MSOFTC 2002 /* 2003 * Create a flash screen on the second video page. 2004 * Switch to that page, then switch back. 2005 */ 2006 if (!flash_created) 2007 create_flash(); 2008 if (videopages < 2) 2009 return; 2010 _setvisualpage(1); 2011 delay(100); 2012 _setvisualpage(0); 2013 #else 2014 #if MSDOS_COMPILER==BORLANDC 2015 unsigned short *currscreen; 2016 2017 /* 2018 * Get a copy of the current screen. 2019 * Display the flash screen. 2020 * Then restore the old screen. 2021 */ 2022 if (!flash_created) 2023 create_flash(); 2024 if (whitescreen == NULL) 2025 return; 2026 currscreen = (unsigned short *) 2027 malloc(sc_width * sc_height * sizeof(short)); 2028 if (currscreen == NULL) return; 2029 gettext(1, 1, sc_width, sc_height, currscreen); 2030 puttext(1, 1, sc_width, sc_height, whitescreen); 2031 delay(100); 2032 puttext(1, 1, sc_width, sc_height, currscreen); 2033 free(currscreen); 2034 #else 2035 #if MSDOS_COMPILER==WIN32C 2036 /* paint screen with an inverse color */ 2037 clear(); 2038 2039 /* leave it displayed for 100 msec. */ 2040 Sleep(100); 2041 2042 /* restore with a redraw */ 2043 repaint(); 2044 #endif 2045 #endif 2046 #endif 2047 #endif 2048 #endif 2049 } 2050 2051 /* 2052 * Make a noise. 2053 */ 2054 static void 2055 beep() 2056 { 2057 #if !MSDOS_COMPILER 2058 putchr(CONTROL('G')); 2059 #else 2060 #if MSDOS_COMPILER==WIN32C 2061 MessageBeep(0); 2062 #else 2063 write(1, "\7", 1); 2064 #endif 2065 #endif 2066 } 2067 2068 /* 2069 * Ring the terminal bell. 2070 */ 2071 public void 2072 bell() 2073 { 2074 if (quiet == VERY_QUIET) 2075 vbell(); 2076 else 2077 beep(); 2078 } 2079 2080 /* 2081 * Clear the screen. 2082 */ 2083 public void 2084 clear() 2085 { 2086 #if !MSDOS_COMPILER 2087 tputs(sc_clear, sc_height, putchr); 2088 #else 2089 flush(); 2090 #if MSDOS_COMPILER==WIN32C 2091 win32_clear(); 2092 #else 2093 _clearscreen(_GCLEARSCREEN); 2094 #endif 2095 #endif 2096 } 2097 2098 /* 2099 * Clear from the cursor to the end of the cursor's line. 2100 * {{ This must not move the cursor. }} 2101 */ 2102 public void 2103 clear_eol() 2104 { 2105 #if !MSDOS_COMPILER 2106 tputs(sc_eol_clear, 1, putchr); 2107 #else 2108 #if MSDOS_COMPILER==MSOFTC 2109 short top, left; 2110 short bot, right; 2111 struct rccoord tpos; 2112 2113 flush(); 2114 /* 2115 * Save current state. 2116 */ 2117 tpos = _gettextposition(); 2118 _gettextwindow(&top, &left, &bot, &right); 2119 /* 2120 * Set a temporary window to the current line, 2121 * from the cursor's position to the right edge of the screen. 2122 * Then clear that window. 2123 */ 2124 _settextwindow(tpos.row, tpos.col, tpos.row, sc_width); 2125 _clearscreen(_GWINDOW); 2126 /* 2127 * Restore state. 2128 */ 2129 _settextwindow(top, left, bot, right); 2130 _settextposition(tpos.row, tpos.col); 2131 #else 2132 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 2133 flush(); 2134 clreol(); 2135 #else 2136 #if MSDOS_COMPILER==WIN32C 2137 DWORD nchars; 2138 COORD cpos; 2139 CONSOLE_SCREEN_BUFFER_INFO scr; 2140 2141 flush(); 2142 memset(&scr, 0, sizeof(scr)); 2143 GetConsoleScreenBufferInfo(con_out, &scr); 2144 cpos.X = scr.dwCursorPosition.X; 2145 cpos.Y = scr.dwCursorPosition.Y; 2146 curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 2147 FillConsoleOutputAttribute(con_out, curr_attr, 2148 scr.dwSize.X - cpos.X, cpos, &nchars); 2149 FillConsoleOutputCharacter(con_out, ' ', 2150 scr.dwSize.X - cpos.X, cpos, &nchars); 2151 #endif 2152 #endif 2153 #endif 2154 #endif 2155 } 2156 2157 /* 2158 * Clear the current line. 2159 * Clear the screen if there's off-screen memory below the display. 2160 */ 2161 static void 2162 clear_eol_bot() 2163 { 2164 #if MSDOS_COMPILER 2165 clear_eol(); 2166 #else 2167 if (below_mem) 2168 tputs(sc_eos_clear, 1, putchr); 2169 else 2170 tputs(sc_eol_clear, 1, putchr); 2171 #endif 2172 } 2173 2174 /* 2175 * Clear the bottom line of the display. 2176 * Leave the cursor at the beginning of the bottom line. 2177 */ 2178 public void 2179 clear_bot() 2180 { 2181 /* 2182 * If we're in a non-normal attribute mode, temporarily exit 2183 * the mode while we do the clear. Some terminals fill the 2184 * cleared area with the current attribute. 2185 */ 2186 if (oldbot) 2187 lower_left(); 2188 else 2189 line_left(); 2190 2191 if (attrmode == AT_NORMAL) 2192 clear_eol_bot(); 2193 else 2194 { 2195 int saved_attrmode = attrmode; 2196 2197 at_exit(); 2198 clear_eol_bot(); 2199 at_enter(saved_attrmode); 2200 } 2201 } 2202 2203 public void 2204 at_enter(attr) 2205 int attr; 2206 { 2207 attr = apply_at_specials(attr); 2208 2209 #if !MSDOS_COMPILER 2210 /* The one with the most priority is last. */ 2211 if (attr & AT_UNDERLINE) 2212 tputs(sc_u_in, 1, putchr); 2213 if (attr & AT_BOLD) 2214 tputs(sc_b_in, 1, putchr); 2215 if (attr & AT_BLINK) 2216 tputs(sc_bl_in, 1, putchr); 2217 if (attr & AT_STANDOUT) 2218 tputs(sc_s_in, 1, putchr); 2219 #else 2220 flush(); 2221 /* The one with the most priority is first. */ 2222 if (attr & AT_STANDOUT) 2223 { 2224 SETCOLORS(so_fg_color, so_bg_color); 2225 } else if (attr & AT_BLINK) 2226 { 2227 SETCOLORS(bl_fg_color, bl_bg_color); 2228 } 2229 else if (attr & AT_BOLD) 2230 { 2231 SETCOLORS(bo_fg_color, bo_bg_color); 2232 } 2233 else if (attr & AT_UNDERLINE) 2234 { 2235 SETCOLORS(ul_fg_color, ul_bg_color); 2236 } 2237 #endif 2238 2239 attrmode = attr; 2240 } 2241 2242 public void 2243 at_exit() 2244 { 2245 #if !MSDOS_COMPILER 2246 /* Undo things in the reverse order we did them. */ 2247 if (attrmode & AT_STANDOUT) 2248 tputs(sc_s_out, 1, putchr); 2249 if (attrmode & AT_BLINK) 2250 tputs(sc_bl_out, 1, putchr); 2251 if (attrmode & AT_BOLD) 2252 tputs(sc_b_out, 1, putchr); 2253 if (attrmode & AT_UNDERLINE) 2254 tputs(sc_u_out, 1, putchr); 2255 #else 2256 flush(); 2257 SETCOLORS(nm_fg_color, nm_bg_color); 2258 #endif 2259 2260 attrmode = AT_NORMAL; 2261 } 2262 2263 public void 2264 at_switch(attr) 2265 int attr; 2266 { 2267 int new_attrmode = apply_at_specials(attr); 2268 int ignore_modes = AT_ANSI; 2269 2270 if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes)) 2271 { 2272 at_exit(); 2273 at_enter(attr); 2274 } 2275 } 2276 2277 public int 2278 is_at_equiv(attr1, attr2) 2279 int attr1; 2280 int attr2; 2281 { 2282 attr1 = apply_at_specials(attr1); 2283 attr2 = apply_at_specials(attr2); 2284 2285 return (attr1 == attr2); 2286 } 2287 2288 public int 2289 apply_at_specials(attr) 2290 int attr; 2291 { 2292 if (attr & AT_BINARY) 2293 attr |= binattr; 2294 if (attr & AT_HILITE) 2295 attr |= AT_STANDOUT; 2296 attr &= ~(AT_BINARY|AT_HILITE); 2297 2298 return attr; 2299 } 2300 2301 #if 0 /* No longer used */ 2302 /* 2303 * Erase the character to the left of the cursor 2304 * and move the cursor left. 2305 */ 2306 public void 2307 backspace() 2308 { 2309 #if !MSDOS_COMPILER 2310 /* 2311 * Erase the previous character by overstriking with a space. 2312 */ 2313 tputs(sc_backspace, 1, putchr); 2314 putchr(' '); 2315 tputs(sc_backspace, 1, putchr); 2316 #else 2317 #if MSDOS_COMPILER==MSOFTC 2318 struct rccoord tpos; 2319 2320 flush(); 2321 tpos = _gettextposition(); 2322 if (tpos.col <= 1) 2323 return; 2324 _settextposition(tpos.row, tpos.col-1); 2325 _outtext(" "); 2326 _settextposition(tpos.row, tpos.col-1); 2327 #else 2328 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 2329 cputs("\b"); 2330 #else 2331 #if MSDOS_COMPILER==WIN32C 2332 COORD cpos; 2333 DWORD cChars; 2334 CONSOLE_SCREEN_BUFFER_INFO scr; 2335 2336 flush(); 2337 GetConsoleScreenBufferInfo(con_out, &scr); 2338 cpos = scr.dwCursorPosition; 2339 if (cpos.X <= 0) 2340 return; 2341 cpos.X--; 2342 SetConsoleCursorPosition(con_out, cpos); 2343 FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars); 2344 SetConsoleCursorPosition(con_out, cpos); 2345 #endif 2346 #endif 2347 #endif 2348 #endif 2349 } 2350 #endif /* 0 */ 2351 2352 /* 2353 * Output a plain backspace, without erasing the previous char. 2354 */ 2355 public void 2356 putbs() 2357 { 2358 #if !MSDOS_COMPILER 2359 tputs(sc_backspace, 1, putchr); 2360 #else 2361 int row, col; 2362 2363 flush(); 2364 { 2365 #if MSDOS_COMPILER==MSOFTC 2366 struct rccoord tpos; 2367 tpos = _gettextposition(); 2368 row = tpos.row; 2369 col = tpos.col; 2370 #else 2371 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 2372 row = wherey(); 2373 col = wherex(); 2374 #else 2375 #if MSDOS_COMPILER==WIN32C 2376 CONSOLE_SCREEN_BUFFER_INFO scr; 2377 GetConsoleScreenBufferInfo(con_out, &scr); 2378 row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 2379 col = scr.dwCursorPosition.X - scr.srWindow.Left + 1; 2380 #endif 2381 #endif 2382 #endif 2383 } 2384 if (col <= 1) 2385 return; 2386 _settextposition(row, col-1); 2387 #endif /* MSDOS_COMPILER */ 2388 } 2389 2390 #if MSDOS_COMPILER==WIN32C 2391 /* 2392 * Determine whether an input character is waiting to be read. 2393 */ 2394 static int 2395 win32_kbhit(tty) 2396 HANDLE tty; 2397 { 2398 INPUT_RECORD ip; 2399 DWORD read; 2400 2401 if (keyCount > 0) 2402 return (TRUE); 2403 2404 currentKey.ascii = 0; 2405 currentKey.scan = 0; 2406 2407 /* 2408 * Wait for a real key-down event, but 2409 * ignore SHIFT and CONTROL key events. 2410 */ 2411 do 2412 { 2413 PeekConsoleInput(tty, &ip, 1, &read); 2414 if (read == 0) 2415 return (FALSE); 2416 ReadConsoleInput(tty, &ip, 1, &read); 2417 } while (ip.EventType != KEY_EVENT || 2418 ip.Event.KeyEvent.bKeyDown != TRUE || 2419 ip.Event.KeyEvent.wVirtualScanCode == 0 || 2420 ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT || 2421 ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL || 2422 ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU); 2423 2424 currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar; 2425 currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode; 2426 keyCount = ip.Event.KeyEvent.wRepeatCount; 2427 2428 if (ip.Event.KeyEvent.dwControlKeyState & 2429 (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) 2430 { 2431 switch (currentKey.scan) 2432 { 2433 case PCK_ALT_E: /* letter 'E' */ 2434 currentKey.ascii = 0; 2435 break; 2436 } 2437 } else if (ip.Event.KeyEvent.dwControlKeyState & 2438 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 2439 { 2440 switch (currentKey.scan) 2441 { 2442 case PCK_RIGHT: /* right arrow */ 2443 currentKey.scan = PCK_CTL_RIGHT; 2444 break; 2445 case PCK_LEFT: /* left arrow */ 2446 currentKey.scan = PCK_CTL_LEFT; 2447 break; 2448 case PCK_DELETE: /* delete */ 2449 currentKey.scan = PCK_CTL_DELETE; 2450 break; 2451 } 2452 } 2453 return (TRUE); 2454 } 2455 2456 /* 2457 * Read a character from the keyboard. 2458 */ 2459 public char 2460 WIN32getch(tty) 2461 int tty; 2462 { 2463 int ascii; 2464 2465 if (pending_scancode) 2466 { 2467 pending_scancode = 0; 2468 return ((char)(currentKey.scan & 0x00FF)); 2469 } 2470 2471 while (win32_kbhit((HANDLE)tty) == FALSE) 2472 { 2473 Sleep(20); 2474 if (ABORT_SIGS()) 2475 return ('\003'); 2476 continue; 2477 } 2478 keyCount --; 2479 ascii = currentKey.ascii; 2480 /* 2481 * On PC's, the extended keys return a 2 byte sequence beginning 2482 * with '00', so if the ascii code is 00, the next byte will be 2483 * the lsb of the scan code. 2484 */ 2485 pending_scancode = (ascii == 0x00); 2486 return ((char)ascii); 2487 } 2488 #endif 2489 2490 #if MSDOS_COMPILER 2491 /* 2492 */ 2493 public void 2494 WIN32setcolors(fg, bg) 2495 int fg; 2496 int bg; 2497 { 2498 SETCOLORS(fg, bg); 2499 } 2500 2501 /* 2502 */ 2503 public void 2504 WIN32textout(text, len) 2505 char *text; 2506 int len; 2507 { 2508 #if MSDOS_COMPILER==WIN32C 2509 DWORD written; 2510 WriteConsole(con_out, text, len, &written, NULL); 2511 #else 2512 char c = text[len]; 2513 text[len] = '\0'; 2514 cputs(text); 2515 text[len] = c; 2516 #endif 2517 } 2518 #endif 2519