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