1238730Sdelphij/* 2330571Sdelphij * Copyright (C) 1984-2017 Mark Nudelman 3238730Sdelphij * 4238730Sdelphij * You may distribute under the terms of either the GNU General Public 5238730Sdelphij * License or the Less License, as specified in the README file. 6238730Sdelphij * 7238730Sdelphij * For more information, see the README file. 8238730Sdelphij */ 960786Sps 1060786Sps 1160786Sps/* 1260786Sps * Routines which deal with the characteristics of the terminal. 1360786Sps * Uses termcap to be as terminal-independent as possible. 1460786Sps */ 1560786Sps 1660786Sps#include "less.h" 1760786Sps#include "cmd.h" 1860786Sps 1960786Sps#if MSDOS_COMPILER 2060786Sps#include "pckeys.h" 2160786Sps#if MSDOS_COMPILER==MSOFTC 2260786Sps#include <graph.h> 2360786Sps#else 2460786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 2560786Sps#include <conio.h> 2660786Sps#if MSDOS_COMPILER==DJGPPC 2760786Sps#include <pc.h> 2860786Spsextern int fd0; 2960786Sps#endif 3060786Sps#else 3160786Sps#if MSDOS_COMPILER==WIN32C 3260786Sps#include <windows.h> 3360786Sps#endif 3460786Sps#endif 3560786Sps#endif 3660786Sps#include <time.h> 3760786Sps 3860786Sps#else 3960786Sps 40161478Sdelphij#if HAVE_SYS_IOCTL_H 41161478Sdelphij#include <sys/ioctl.h> 42161478Sdelphij#endif 43161478Sdelphij 4460786Sps#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 4560786Sps#include <termios.h> 4660786Sps#else 4760786Sps#if HAVE_TERMIO_H 4860786Sps#include <termio.h> 4960786Sps#else 5060786Sps#if HAVE_SGSTAT_H 5160786Sps#include <sgstat.h> 5260786Sps#else 5360786Sps#include <sgtty.h> 5460786Sps#endif 5560786Sps#endif 5660786Sps#endif 5760786Sps 5860786Sps#if HAVE_TERMCAP_H 5960786Sps#include <termcap.h> 6060786Sps#endif 6160786Sps#ifdef _OSK 6260786Sps#include <signal.h> 6360786Sps#endif 6460786Sps#if OS2 6560786Sps#include <sys/signal.h> 6689022Sps#include "pckeys.h" 6760786Sps#endif 6860786Sps#if HAVE_SYS_STREAM_H 6960786Sps#include <sys/stream.h> 7060786Sps#endif 7160786Sps#if HAVE_SYS_PTEM_H 7260786Sps#include <sys/ptem.h> 7360786Sps#endif 7460786Sps 7560786Sps#endif /* MSDOS_COMPILER */ 7660786Sps 7760786Sps/* 7860786Sps * Check for broken termios package that forces you to manually 7960786Sps * set the line discipline. 8060786Sps */ 8160786Sps#ifdef __ultrix__ 8260786Sps#define MUST_SET_LINE_DISCIPLINE 1 8360786Sps#else 8460786Sps#define MUST_SET_LINE_DISCIPLINE 0 8560786Sps#endif 8660786Sps 8760786Sps#if OS2 8860786Sps#define DEFAULT_TERM "ansi" 8989022Spsstatic char *windowid; 9060786Sps#else 9160786Sps#define DEFAULT_TERM "unknown" 9260786Sps#endif 9360786Sps 9460786Sps#if MSDOS_COMPILER==MSOFTC 9560786Spsstatic int videopages; 9660786Spsstatic long msec_loops; 9760786Spsstatic int flash_created = 0; 9860786Sps#define SETCOLORS(fg,bg) { _settextcolor(fg); _setbkcolor(bg); } 9960786Sps#endif 10060786Sps 10160786Sps#if MSDOS_COMPILER==BORLANDC 10260786Spsstatic unsigned short *whitescreen; 10360786Spsstatic int flash_created = 0; 10460786Sps#endif 10560786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 10660786Sps#define _settextposition(y,x) gotoxy(x,y) 10760786Sps#define _clearscreen(m) clrscr() 10860786Sps#define _outtext(s) cputs(s) 10960786Sps#define SETCOLORS(fg,bg) { textcolor(fg); textbackground(bg); } 11060786Spsextern int sc_height; 11160786Sps#endif 11260786Sps 11360786Sps#if MSDOS_COMPILER==WIN32C 11460786Spsstruct keyRecord 11560786Sps{ 11660786Sps int ascii; 11760786Sps int scan; 11860786Sps} currentKey; 11960786Sps 12060786Spsstatic int keyCount = 0; 12160786Spsstatic WORD curr_attr; 12260786Spsstatic int pending_scancode = 0; 12360786Spsstatic WORD *whitescreen; 12460786Sps 12560786Spsstatic HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */ 12660786Spsstatic HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */ 12760786SpsHANDLE con_out = INVALID_HANDLE_VALUE; /* current console */ 12860786Sps 129330571Sdelphijextern int utf_mode; 13060786Spsextern int quitting; 13160786Spsstatic void win32_init_term(); 13260786Spsstatic void win32_deinit_term(); 13360786Sps 134330571Sdelphij#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING 135330571Sdelphij#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 4 136330571Sdelphij#endif 137330571Sdelphij 13860786Sps#define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY) 13960786Sps#define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY) 14060786Sps#define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) 14160786Sps#define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \ 14260786Sps if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ 143330571Sdelphij error("SETCOLORS failed", NULL_PARG); } 14460786Sps#endif 14560786Sps 14660786Sps#if MSDOS_COMPILER 14760786Spspublic int nm_fg_color; /* Color of normal text */ 14860786Spspublic int nm_bg_color; 14960786Spspublic int bo_fg_color; /* Color of bold text */ 15060786Spspublic int bo_bg_color; 15160786Spspublic int ul_fg_color; /* Color of underlined text */ 15260786Spspublic int ul_bg_color; 15360786Spspublic int so_fg_color; /* Color of standout text */ 15460786Spspublic int so_bg_color; 15560786Spspublic int bl_fg_color; /* Color of blinking text */ 15660786Spspublic int bl_bg_color; 15760786Spsstatic int sy_fg_color; /* Color of system text (before less) */ 15860786Spsstatic int sy_bg_color; 159330571Sdelphijpublic int sgr_mode; /* Honor ANSI sequences rather than using above */ 160330571Sdelphij#if MSDOS_COMPILER==WIN32C 161330571Sdelphijpublic int have_ul; /* Is underline available? */ 162330571Sdelphij#endif 16360786Sps#else 16460786Sps 16560786Sps/* 16660786Sps * Strings passed to tputs() to do various terminal functions. 16760786Sps */ 16860786Spsstatic char 16960786Sps *sc_pad, /* Pad string */ 17060786Sps *sc_home, /* Cursor home */ 17160786Sps *sc_addline, /* Add line, scroll down following lines */ 17260786Sps *sc_lower_left, /* Cursor to last line, first column */ 173170259Sdelphij *sc_return, /* Cursor to beginning of current line */ 17460786Sps *sc_move, /* General cursor positioning */ 17560786Sps *sc_clear, /* Clear screen */ 17660786Sps *sc_eol_clear, /* Clear to end of line */ 17760786Sps *sc_eos_clear, /* Clear to end of screen */ 17860786Sps *sc_s_in, /* Enter standout (highlighted) mode */ 17960786Sps *sc_s_out, /* Exit standout mode */ 18060786Sps *sc_u_in, /* Enter underline mode */ 18160786Sps *sc_u_out, /* Exit underline mode */ 18260786Sps *sc_b_in, /* Enter bold mode */ 18360786Sps *sc_b_out, /* Exit bold mode */ 18460786Sps *sc_bl_in, /* Enter blink mode */ 18560786Sps *sc_bl_out, /* Exit blink mode */ 18660786Sps *sc_visual_bell, /* Visual bell (flash screen) sequence */ 18760786Sps *sc_backspace, /* Backspace cursor */ 18860786Sps *sc_s_keypad, /* Start keypad mode */ 18960786Sps *sc_e_keypad, /* End keypad mode */ 19060786Sps *sc_init, /* Startup terminal initialization */ 19160786Sps *sc_deinit; /* Exit terminal de-initialization */ 19260786Sps#endif 19360786Sps 19460786Spsstatic int init_done = 0; 19560786Sps 19660786Spspublic int auto_wrap; /* Terminal does \r\n when write past margin */ 19760786Spspublic int ignaw; /* Terminal ignores \n immediately after wrap */ 198161478Sdelphijpublic int erase_char; /* The user's erase char */ 199161478Sdelphijpublic int erase2_char; /* The user's other erase char */ 200161478Sdelphijpublic int kill_char; /* The user's line-kill char */ 20160786Spspublic int werase_char; /* The user's word-erase char */ 20260786Spspublic int sc_width, sc_height; /* Height & width of screen */ 20360786Spspublic int bo_s_width, bo_e_width; /* Printing width of boldface seq */ 20460786Spspublic int ul_s_width, ul_e_width; /* Printing width of underline seq */ 20560786Spspublic int so_s_width, so_e_width; /* Printing width of standout seq */ 20660786Spspublic int bl_s_width, bl_e_width; /* Printing width of blink seq */ 20760786Spspublic int above_mem, below_mem; /* Memory retained above/below screen */ 20860786Spspublic int can_goto_line; /* Can move cursor to any line */ 20960786Spspublic int clear_bg; /* Clear fills with background color */ 21060786Spspublic int missing_cap = 0; /* Some capability is missing */ 211330571Sdelphijpublic char *kent = NULL; /* Keypad ENTER sequence */ 21260786Sps 21360786Spsstatic int attrmode = AT_NORMAL; 214161478Sdelphijextern int binattr; 215330571Sdelphijextern int line_count; 21660786Sps 21760786Sps#if !MSDOS_COMPILER 21860786Spsstatic char *cheaper(); 21960786Spsstatic void tmodes(); 22060786Sps#endif 22160786Sps 22260786Sps/* 22360786Sps * These two variables are sometimes defined in, 22460786Sps * and needed by, the termcap library. 22560786Sps */ 22660786Sps#if MUST_DEFINE_OSPEED 22760786Spsextern short ospeed; /* Terminal output baud rate */ 22860786Spsextern char PC; /* Pad character */ 22960786Sps#endif 23060786Sps#ifdef _OSK 23160786Spsshort ospeed; 23260786Spschar PC_, *UP, *BC; 23360786Sps#endif 23460786Sps 23560786Spsextern int quiet; /* If VERY_QUIET, use visual bell for bell */ 23660786Spsextern int no_back_scroll; 23760786Spsextern int swindow; 23860786Spsextern int no_init; 23989022Spsextern int no_keypad; 24060786Spsextern int sigs; 24160786Spsextern int wscroll; 24260786Spsextern int screen_trashed; 243128348Stjrextern int tty; 244161478Sdelphijextern int top_scroll; 245330571Sdelphijextern int quit_if_one_screen; 246170259Sdelphijextern int oldbot; 24760786Sps#if HILITE_SEARCH 24860786Spsextern int hilite_search; 24960786Sps#endif 25060786Sps 25160786Spsextern char *tgetstr(); 25260786Spsextern char *tgoto(); 25360786Sps 25460786Sps 25560786Sps/* 25660786Sps * Change terminal to "raw mode", or restore to "normal" mode. 25760786Sps * "Raw mode" means 25860786Sps * 1. An outstanding read will complete on receipt of a single keystroke. 25960786Sps * 2. Input is not echoed. 26060786Sps * 3. On output, \n is mapped to \r\n. 26160786Sps * 4. \t is NOT expanded into spaces. 26260786Sps * 5. Signal-causing characters such as ctrl-C (interrupt), 26360786Sps * etc. are NOT disabled. 26460786Sps * It doesn't matter whether an input \n is mapped to \r, or vice versa. 26560786Sps */ 26660786Sps public void 26760786Spsraw_mode(on) 26860786Sps int on; 26960786Sps{ 27060786Sps static int curr_on = 0; 27160786Sps 27260786Sps if (on == curr_on) 27360786Sps return; 274161478Sdelphij erase2_char = '\b'; /* in case OS doesn't know about erase2 */ 27560786Sps#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 27660786Sps { 27760786Sps struct termios s; 27860786Sps static struct termios save_term; 27960786Sps static int saved_term = 0; 28060786Sps 28160786Sps if (on) 28260786Sps { 28360786Sps /* 28460786Sps * Get terminal modes. 28560786Sps */ 286128348Stjr tcgetattr(tty, &s); 28760786Sps 28860786Sps /* 28960786Sps * Save modes and set certain variables dependent on modes. 29060786Sps */ 29160786Sps if (!saved_term) 29260786Sps { 29360786Sps save_term = s; 29460786Sps saved_term = 1; 29560786Sps } 29660786Sps#if HAVE_OSPEED 29760786Sps switch (cfgetospeed(&s)) 29860786Sps { 29960786Sps#ifdef B0 30060786Sps case B0: ospeed = 0; break; 30160786Sps#endif 30260786Sps#ifdef B50 30360786Sps case B50: ospeed = 1; break; 30460786Sps#endif 30560786Sps#ifdef B75 30660786Sps case B75: ospeed = 2; break; 30760786Sps#endif 30860786Sps#ifdef B110 30960786Sps case B110: ospeed = 3; break; 31060786Sps#endif 31160786Sps#ifdef B134 31260786Sps case B134: ospeed = 4; break; 31360786Sps#endif 31460786Sps#ifdef B150 31560786Sps case B150: ospeed = 5; break; 31660786Sps#endif 31760786Sps#ifdef B200 31860786Sps case B200: ospeed = 6; break; 31960786Sps#endif 32060786Sps#ifdef B300 32160786Sps case B300: ospeed = 7; break; 32260786Sps#endif 32360786Sps#ifdef B600 32460786Sps case B600: ospeed = 8; break; 32560786Sps#endif 32660786Sps#ifdef B1200 32760786Sps case B1200: ospeed = 9; break; 32860786Sps#endif 32960786Sps#ifdef B1800 33060786Sps case B1800: ospeed = 10; break; 33160786Sps#endif 33260786Sps#ifdef B2400 33360786Sps case B2400: ospeed = 11; break; 33460786Sps#endif 33560786Sps#ifdef B4800 33660786Sps case B4800: ospeed = 12; break; 33760786Sps#endif 33860786Sps#ifdef B9600 33960786Sps case B9600: ospeed = 13; break; 34060786Sps#endif 34160786Sps#ifdef EXTA 34260786Sps case EXTA: ospeed = 14; break; 34360786Sps#endif 34460786Sps#ifdef EXTB 34560786Sps case EXTB: ospeed = 15; break; 34660786Sps#endif 34760786Sps#ifdef B57600 34860786Sps case B57600: ospeed = 16; break; 34960786Sps#endif 35060786Sps#ifdef B115200 35160786Sps case B115200: ospeed = 17; break; 35260786Sps#endif 35360786Sps default: ; 35460786Sps } 35560786Sps#endif 35660786Sps erase_char = s.c_cc[VERASE]; 357161478Sdelphij#ifdef VERASE2 358161478Sdelphij erase2_char = s.c_cc[VERASE2]; 359161478Sdelphij#endif 36060786Sps kill_char = s.c_cc[VKILL]; 36160786Sps#ifdef VWERASE 36260786Sps werase_char = s.c_cc[VWERASE]; 36360786Sps#else 36460786Sps werase_char = CONTROL('W'); 36560786Sps#endif 36660786Sps 36760786Sps /* 36860786Sps * Set the modes to the way we want them. 36960786Sps */ 37060786Sps s.c_lflag &= ~(0 37160786Sps#ifdef ICANON 37260786Sps | ICANON 37360786Sps#endif 37460786Sps#ifdef ECHO 37560786Sps | ECHO 37660786Sps#endif 37760786Sps#ifdef ECHOE 37860786Sps | ECHOE 37960786Sps#endif 38060786Sps#ifdef ECHOK 38160786Sps | ECHOK 38260786Sps#endif 38360786Sps#if ECHONL 38460786Sps | ECHONL 38560786Sps#endif 38660786Sps ); 38760786Sps 38860786Sps s.c_oflag |= (0 38960786Sps#ifdef OXTABS 39060786Sps | OXTABS 39160786Sps#else 39260786Sps#ifdef TAB3 39360786Sps | TAB3 39460786Sps#else 39560786Sps#ifdef XTABS 39660786Sps | XTABS 39760786Sps#endif 39860786Sps#endif 39960786Sps#endif 40060786Sps#ifdef OPOST 40160786Sps | OPOST 40260786Sps#endif 40360786Sps#ifdef ONLCR 40460786Sps | ONLCR 40560786Sps#endif 40660786Sps ); 40760786Sps 40860786Sps s.c_oflag &= ~(0 40960786Sps#ifdef ONOEOT 41060786Sps | ONOEOT 41160786Sps#endif 41260786Sps#ifdef OCRNL 41360786Sps | OCRNL 41460786Sps#endif 41560786Sps#ifdef ONOCR 41660786Sps | ONOCR 41760786Sps#endif 41860786Sps#ifdef ONLRET 41960786Sps | ONLRET 42060786Sps#endif 42160786Sps ); 42260786Sps s.c_cc[VMIN] = 1; 42360786Sps s.c_cc[VTIME] = 0; 42460786Sps#ifdef VLNEXT 42560786Sps s.c_cc[VLNEXT] = 0; 42660786Sps#endif 42760786Sps#ifdef VDSUSP 42860786Sps s.c_cc[VDSUSP] = 0; 42960786Sps#endif 43060786Sps#if MUST_SET_LINE_DISCIPLINE 43160786Sps /* 43260786Sps * System's termios is broken; need to explicitly 43360786Sps * request TERMIODISC line discipline. 43460786Sps */ 43560786Sps s.c_line = TERMIODISC; 43660786Sps#endif 43760786Sps } else 43860786Sps { 43960786Sps /* 44060786Sps * Restore saved modes. 44160786Sps */ 44260786Sps s = save_term; 44360786Sps } 44489022Sps#if HAVE_FSYNC 445128348Stjr fsync(tty); 44689022Sps#endif 447128348Stjr tcsetattr(tty, TCSADRAIN, &s); 44860786Sps#if MUST_SET_LINE_DISCIPLINE 44960786Sps if (!on) 45060786Sps { 45160786Sps /* 45260786Sps * Broken termios *ignores* any line discipline 45360786Sps * except TERMIODISC. A different old line discipline 45460786Sps * is therefore not restored, yet. Restore the old 45560786Sps * line discipline by hand. 45660786Sps */ 457128348Stjr ioctl(tty, TIOCSETD, &save_term.c_line); 45860786Sps } 45960786Sps#endif 46060786Sps } 46160786Sps#else 46260786Sps#ifdef TCGETA 46360786Sps { 46460786Sps struct termio s; 46560786Sps static struct termio save_term; 46660786Sps static int saved_term = 0; 46760786Sps 46860786Sps if (on) 46960786Sps { 47060786Sps /* 47160786Sps * Get terminal modes. 47260786Sps */ 473128348Stjr ioctl(tty, TCGETA, &s); 47460786Sps 47560786Sps /* 47660786Sps * Save modes and set certain variables dependent on modes. 47760786Sps */ 47860786Sps if (!saved_term) 47960786Sps { 48060786Sps save_term = s; 48160786Sps saved_term = 1; 48260786Sps } 48360786Sps#if HAVE_OSPEED 48460786Sps ospeed = s.c_cflag & CBAUD; 48560786Sps#endif 48660786Sps erase_char = s.c_cc[VERASE]; 48760786Sps kill_char = s.c_cc[VKILL]; 48860786Sps#ifdef VWERASE 48960786Sps werase_char = s.c_cc[VWERASE]; 49060786Sps#else 49160786Sps werase_char = CONTROL('W'); 49260786Sps#endif 49360786Sps 49460786Sps /* 49560786Sps * Set the modes to the way we want them. 49660786Sps */ 49760786Sps s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); 49860786Sps s.c_oflag |= (OPOST|ONLCR|TAB3); 49960786Sps s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); 50060786Sps s.c_cc[VMIN] = 1; 50160786Sps s.c_cc[VTIME] = 0; 50260786Sps } else 50360786Sps { 50460786Sps /* 50560786Sps * Restore saved modes. 50660786Sps */ 50760786Sps s = save_term; 50860786Sps } 509128348Stjr ioctl(tty, TCSETAW, &s); 51060786Sps } 51160786Sps#else 51260786Sps#ifdef TIOCGETP 51360786Sps { 51460786Sps struct sgttyb s; 51560786Sps static struct sgttyb save_term; 51660786Sps static int saved_term = 0; 51760786Sps 51860786Sps if (on) 51960786Sps { 52060786Sps /* 52160786Sps * Get terminal modes. 52260786Sps */ 523128348Stjr ioctl(tty, TIOCGETP, &s); 52460786Sps 52560786Sps /* 52660786Sps * Save modes and set certain variables dependent on modes. 52760786Sps */ 52860786Sps if (!saved_term) 52960786Sps { 53060786Sps save_term = s; 53160786Sps saved_term = 1; 53260786Sps } 53360786Sps#if HAVE_OSPEED 53460786Sps ospeed = s.sg_ospeed; 53560786Sps#endif 53660786Sps erase_char = s.sg_erase; 53760786Sps kill_char = s.sg_kill; 53860786Sps werase_char = CONTROL('W'); 53960786Sps 54060786Sps /* 54160786Sps * Set the modes to the way we want them. 54260786Sps */ 54360786Sps s.sg_flags |= CBREAK; 54460786Sps s.sg_flags &= ~(ECHO|XTABS); 54560786Sps } else 54660786Sps { 54760786Sps /* 54860786Sps * Restore saved modes. 54960786Sps */ 55060786Sps s = save_term; 55160786Sps } 552128348Stjr ioctl(tty, TIOCSETN, &s); 55360786Sps } 55460786Sps#else 55560786Sps#ifdef _OSK 55660786Sps { 55760786Sps struct sgbuf s; 55860786Sps static struct sgbuf save_term; 55960786Sps static int saved_term = 0; 56060786Sps 56160786Sps if (on) 56260786Sps { 56360786Sps /* 56460786Sps * Get terminal modes. 56560786Sps */ 566128348Stjr _gs_opt(tty, &s); 56760786Sps 56860786Sps /* 56960786Sps * Save modes and set certain variables dependent on modes. 57060786Sps */ 57160786Sps if (!saved_term) 57260786Sps { 57360786Sps save_term = s; 57460786Sps saved_term = 1; 57560786Sps } 57660786Sps erase_char = s.sg_bspch; 57760786Sps kill_char = s.sg_dlnch; 57860786Sps werase_char = CONTROL('W'); 57960786Sps 58060786Sps /* 58160786Sps * Set the modes to the way we want them. 58260786Sps */ 58360786Sps s.sg_echo = 0; 58460786Sps s.sg_eofch = 0; 58560786Sps s.sg_pause = 0; 58660786Sps s.sg_psch = 0; 58760786Sps } else 58860786Sps { 58960786Sps /* 59060786Sps * Restore saved modes. 59160786Sps */ 59260786Sps s = save_term; 59360786Sps } 594128348Stjr _ss_opt(tty, &s); 59560786Sps } 59660786Sps#else 59760786Sps /* MS-DOS, Windows, or OS2 */ 59860786Sps#if OS2 59960786Sps /* OS2 */ 60060786Sps LSIGNAL(SIGINT, SIG_IGN); 60160786Sps#endif 60260786Sps erase_char = '\b'; 60360786Sps#if MSDOS_COMPILER==DJGPPC 60460786Sps kill_char = CONTROL('U'); 60560786Sps /* 60660786Sps * So that when we shell out or run another program, its 60760786Sps * stdin is in cooked mode. We do not switch stdin to binary 60860786Sps * mode if fd0 is zero, since that means we were called before 60960786Sps * tty was reopened in open_getchr, in which case we would be 61060786Sps * changing the original stdin device outside less. 61160786Sps */ 61260786Sps if (fd0 != 0) 61360786Sps setmode(0, on ? O_BINARY : O_TEXT); 61460786Sps#else 61560786Sps kill_char = ESC; 61660786Sps#endif 61760786Sps werase_char = CONTROL('W'); 61860786Sps#endif 61960786Sps#endif 62060786Sps#endif 62160786Sps#endif 62260786Sps curr_on = on; 62360786Sps} 62460786Sps 62560786Sps#if !MSDOS_COMPILER 62660786Sps/* 62760786Sps * Some glue to prevent calling termcap functions if tgetent() failed. 62860786Sps */ 62960786Spsstatic int hardcopy; 63060786Sps 63160786Sps static char * 63260786Spsltget_env(capname) 63360786Sps char *capname; 63460786Sps{ 63560786Sps char name[16]; 636170967Sdelphij char *s; 63760786Sps 638170967Sdelphij s = lgetenv("LESS_TERMCAP_DEBUG"); 639170967Sdelphij if (s != NULL && *s != '\0') 640170967Sdelphij { 641170967Sdelphij struct env { struct env *next; char *name; char *value; }; 642170967Sdelphij static struct env *envs = NULL; 643170967Sdelphij struct env *p; 644170967Sdelphij for (p = envs; p != NULL; p = p->next) 645170967Sdelphij if (strcmp(p->name, capname) == 0) 646170967Sdelphij return p->value; 647170967Sdelphij p = (struct env *) ecalloc(1, sizeof(struct env)); 648170967Sdelphij p->name = save(capname); 649170967Sdelphij p->value = (char *) ecalloc(strlen(capname)+3, sizeof(char)); 650170967Sdelphij sprintf(p->value, "<%s>", capname); 651170967Sdelphij p->next = envs; 652170967Sdelphij envs = p; 653170967Sdelphij return p->value; 654170967Sdelphij } 65560786Sps strcpy(name, "LESS_TERMCAP_"); 65660786Sps strcat(name, capname); 65760786Sps return (lgetenv(name)); 65860786Sps} 65960786Sps 66060786Sps static int 66160786Spsltgetflag(capname) 66260786Sps char *capname; 66360786Sps{ 66460786Sps char *s; 66560786Sps 66660786Sps if ((s = ltget_env(capname)) != NULL) 66760786Sps return (*s != '\0' && *s != '0'); 66860786Sps if (hardcopy) 66960786Sps return (0); 67060786Sps return (tgetflag(capname)); 67160786Sps} 67260786Sps 67360786Sps static int 67460786Spsltgetnum(capname) 67560786Sps char *capname; 67660786Sps{ 67760786Sps char *s; 67860786Sps 67960786Sps if ((s = ltget_env(capname)) != NULL) 68060786Sps return (atoi(s)); 68160786Sps if (hardcopy) 68260786Sps return (-1); 68360786Sps return (tgetnum(capname)); 68460786Sps} 68560786Sps 68660786Sps static char * 68760786Spsltgetstr(capname, pp) 68860786Sps char *capname; 68960786Sps char **pp; 69060786Sps{ 69160786Sps char *s; 69260786Sps 69360786Sps if ((s = ltget_env(capname)) != NULL) 69460786Sps return (s); 69560786Sps if (hardcopy) 69660786Sps return (NULL); 69760786Sps return (tgetstr(capname, pp)); 69860786Sps} 69960786Sps#endif /* MSDOS_COMPILER */ 70060786Sps 70160786Sps/* 70260786Sps * Get size of the output screen. 70360786Sps */ 70460786Sps public void 70560786Spsscrsize() 70660786Sps{ 707330571Sdelphij char *s; 70860786Sps int sys_height; 70960786Sps int sys_width; 71060786Sps#if !MSDOS_COMPILER 71160786Sps int n; 71260786Sps#endif 71360786Sps 71460786Sps#define DEF_SC_WIDTH 80 71560786Sps#if MSDOS_COMPILER 71660786Sps#define DEF_SC_HEIGHT 25 71760786Sps#else 71860786Sps#define DEF_SC_HEIGHT 24 71960786Sps#endif 72060786Sps 72160786Sps 72260786Sps sys_width = sys_height = 0; 72360786Sps 72460786Sps#if MSDOS_COMPILER==MSOFTC 72560786Sps { 72660786Sps struct videoconfig w; 72760786Sps _getvideoconfig(&w); 72860786Sps sys_height = w.numtextrows; 72960786Sps sys_width = w.numtextcols; 73060786Sps } 73160786Sps#else 73260786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 73360786Sps { 73460786Sps struct text_info w; 73560786Sps gettextinfo(&w); 73660786Sps sys_height = w.screenheight; 73760786Sps sys_width = w.screenwidth; 73860786Sps } 73960786Sps#else 74060786Sps#if MSDOS_COMPILER==WIN32C 74160786Sps { 74260786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 74360786Sps GetConsoleScreenBufferInfo(con_out, &scr); 74460786Sps sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1; 74560786Sps sys_width = scr.srWindow.Right - scr.srWindow.Left + 1; 74660786Sps } 74760786Sps#else 74860786Sps#if OS2 74960786Sps { 75060786Sps int s[2]; 75160786Sps _scrsize(s); 75260786Sps sys_width = s[0]; 75360786Sps sys_height = s[1]; 75489022Sps /* 75589022Sps * When using terminal emulators for XFree86/OS2, the 75689022Sps * _scrsize function does not work well. 75789022Sps * Call the scrsize.exe program to get the window size. 75889022Sps */ 75989022Sps windowid = getenv("WINDOWID"); 76089022Sps if (windowid != NULL) 76189022Sps { 76289022Sps FILE *fd = popen("scrsize", "rt"); 76389022Sps if (fd != NULL) 76489022Sps { 76589022Sps int w, h; 76689022Sps fscanf(fd, "%i %i", &w, &h); 76789022Sps if (w > 0 && h > 0) 76889022Sps { 76989022Sps sys_width = w; 77089022Sps sys_height = h; 77189022Sps } 77289022Sps pclose(fd); 77389022Sps } 77489022Sps } 77560786Sps } 77660786Sps#else 77760786Sps#ifdef TIOCGWINSZ 77860786Sps { 77960786Sps struct winsize w; 78060786Sps if (ioctl(2, TIOCGWINSZ, &w) == 0) 78160786Sps { 78260786Sps if (w.ws_row > 0) 78360786Sps sys_height = w.ws_row; 78460786Sps if (w.ws_col > 0) 78560786Sps sys_width = w.ws_col; 78660786Sps } 78760786Sps } 78860786Sps#else 78960786Sps#ifdef WIOCGETD 79060786Sps { 79160786Sps struct uwdata w; 79260786Sps if (ioctl(2, WIOCGETD, &w) == 0) 79360786Sps { 79460786Sps if (w.uw_height > 0) 79560786Sps sys_height = w.uw_height / w.uw_vs; 79660786Sps if (w.uw_width > 0) 79760786Sps sys_width = w.uw_width / w.uw_hs; 79860786Sps } 79960786Sps } 80060786Sps#endif 80160786Sps#endif 80260786Sps#endif 80360786Sps#endif 80460786Sps#endif 80560786Sps#endif 80660786Sps 80760786Sps if (sys_height > 0) 80860786Sps sc_height = sys_height; 80960786Sps else if ((s = lgetenv("LINES")) != NULL) 81060786Sps sc_height = atoi(s); 81160786Sps#if !MSDOS_COMPILER 81260786Sps else if ((n = ltgetnum("li")) > 0) 81360786Sps sc_height = n; 81460786Sps#endif 815242584Sdelphij if (sc_height <= 0) 81660786Sps sc_height = DEF_SC_HEIGHT; 81760786Sps 81860786Sps if (sys_width > 0) 81960786Sps sc_width = sys_width; 82060786Sps else if ((s = lgetenv("COLUMNS")) != NULL) 82160786Sps sc_width = atoi(s); 82260786Sps#if !MSDOS_COMPILER 82360786Sps else if ((n = ltgetnum("co")) > 0) 82460786Sps sc_width = n; 82560786Sps#endif 826242584Sdelphij if (sc_width <= 0) 82760786Sps sc_width = DEF_SC_WIDTH; 82860786Sps} 82960786Sps 83060786Sps#if MSDOS_COMPILER==MSOFTC 83160786Sps/* 83260786Sps * Figure out how many empty loops it takes to delay a millisecond. 83360786Sps */ 83460786Sps static void 83560786Spsget_clock() 83660786Sps{ 83760786Sps clock_t start; 83860786Sps 83960786Sps /* 84060786Sps * Get synchronized at the start of a tick. 84160786Sps */ 84260786Sps start = clock(); 84360786Sps while (clock() == start) 84460786Sps ; 84560786Sps /* 84660786Sps * Now count loops till the next tick. 84760786Sps */ 84860786Sps start = clock(); 84960786Sps msec_loops = 0; 85060786Sps while (clock() == start) 85160786Sps msec_loops++; 85260786Sps /* 85360786Sps * Convert from (loops per clock) to (loops per millisecond). 85460786Sps */ 85560786Sps msec_loops *= CLOCKS_PER_SEC; 85660786Sps msec_loops /= 1000; 85760786Sps} 85860786Sps 85960786Sps/* 86060786Sps * Delay for a specified number of milliseconds. 86160786Sps */ 86260786Sps static void 86360786Spsdummy_func() 86460786Sps{ 86560786Sps static long delay_dummy = 0; 86660786Sps delay_dummy++; 86760786Sps} 86860786Sps 86960786Sps static void 87060786Spsdelay(msec) 87160786Sps int msec; 87260786Sps{ 87360786Sps long i; 87460786Sps 87560786Sps while (msec-- > 0) 87660786Sps { 87760786Sps for (i = 0; i < msec_loops; i++) 87860786Sps { 87960786Sps /* 88060786Sps * Make it look like we're doing something here, 88160786Sps * so the optimizer doesn't remove the whole loop. 88260786Sps */ 88360786Sps dummy_func(); 88460786Sps } 88560786Sps } 88660786Sps} 88760786Sps#endif 88860786Sps 88960786Sps/* 89060786Sps * Return the characters actually input by a "special" key. 89160786Sps */ 89260786Sps public char * 89360786Spsspecial_key_str(key) 89460786Sps int key; 89560786Sps{ 89660786Sps static char tbuf[40]; 89760786Sps char *s; 89889022Sps#if MSDOS_COMPILER || OS2 89960786Sps static char k_right[] = { '\340', PCK_RIGHT, 0 }; 90060786Sps static char k_left[] = { '\340', PCK_LEFT, 0 }; 90160786Sps static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; 90260786Sps static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; 90360786Sps static char k_insert[] = { '\340', PCK_INSERT, 0 }; 90460786Sps static char k_delete[] = { '\340', PCK_DELETE, 0 }; 90560786Sps static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; 90660786Sps static char k_ctl_backspace[] = { '\177', 0 }; 90760786Sps static char k_home[] = { '\340', PCK_HOME, 0 }; 90860786Sps static char k_end[] = { '\340', PCK_END, 0 }; 90960786Sps static char k_up[] = { '\340', PCK_UP, 0 }; 91060786Sps static char k_down[] = { '\340', PCK_DOWN, 0 }; 91160786Sps static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; 91260786Sps static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; 91360786Sps static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; 91460786Sps static char k_f1[] = { '\340', PCK_F1, 0 }; 91589022Sps#endif 91689022Sps#if !MSDOS_COMPILER 91760786Sps char *sp = tbuf; 91860786Sps#endif 91960786Sps 92060786Sps switch (key) 92160786Sps { 92289022Sps#if OS2 92389022Sps /* 92489022Sps * If windowid is not NULL, assume less is executed in 92589022Sps * the XFree86 environment. 92689022Sps */ 92789022Sps case SK_RIGHT_ARROW: 92889022Sps s = windowid ? ltgetstr("kr", &sp) : k_right; 92989022Sps break; 93089022Sps case SK_LEFT_ARROW: 93189022Sps s = windowid ? ltgetstr("kl", &sp) : k_left; 93289022Sps break; 93389022Sps case SK_UP_ARROW: 93489022Sps s = windowid ? ltgetstr("ku", &sp) : k_up; 93589022Sps break; 93689022Sps case SK_DOWN_ARROW: 93789022Sps s = windowid ? ltgetstr("kd", &sp) : k_down; 93889022Sps break; 93989022Sps case SK_PAGE_UP: 94089022Sps s = windowid ? ltgetstr("kP", &sp) : k_pageup; 94189022Sps break; 94289022Sps case SK_PAGE_DOWN: 94389022Sps s = windowid ? ltgetstr("kN", &sp) : k_pagedown; 94489022Sps break; 94589022Sps case SK_HOME: 94689022Sps s = windowid ? ltgetstr("kh", &sp) : k_home; 94789022Sps break; 94889022Sps case SK_END: 94989022Sps s = windowid ? ltgetstr("@7", &sp) : k_end; 95089022Sps break; 95189022Sps case SK_DELETE: 95289022Sps if (windowid) 95389022Sps { 95489022Sps s = ltgetstr("kD", &sp); 95589022Sps if (s == NULL) 95689022Sps { 95789022Sps tbuf[0] = '\177'; 95889022Sps tbuf[1] = '\0'; 95989022Sps s = tbuf; 96089022Sps } 96189022Sps } else 96289022Sps s = k_delete; 96389022Sps break; 96489022Sps#endif 96560786Sps#if MSDOS_COMPILER 96660786Sps case SK_RIGHT_ARROW: 96760786Sps s = k_right; 96860786Sps break; 96960786Sps case SK_LEFT_ARROW: 97060786Sps s = k_left; 97160786Sps break; 97260786Sps case SK_UP_ARROW: 97360786Sps s = k_up; 97460786Sps break; 97560786Sps case SK_DOWN_ARROW: 97660786Sps s = k_down; 97760786Sps break; 97860786Sps case SK_PAGE_UP: 97960786Sps s = k_pageup; 98060786Sps break; 98160786Sps case SK_PAGE_DOWN: 98260786Sps s = k_pagedown; 98360786Sps break; 98460786Sps case SK_HOME: 98560786Sps s = k_home; 98660786Sps break; 98760786Sps case SK_END: 98860786Sps s = k_end; 98960786Sps break; 99060786Sps case SK_DELETE: 99160786Sps s = k_delete; 99260786Sps break; 99389022Sps#endif 99489022Sps#if MSDOS_COMPILER || OS2 99560786Sps case SK_INSERT: 99660786Sps s = k_insert; 99760786Sps break; 99860786Sps case SK_CTL_LEFT_ARROW: 99960786Sps s = k_ctl_left; 100060786Sps break; 100160786Sps case SK_CTL_RIGHT_ARROW: 100260786Sps s = k_ctl_right; 100360786Sps break; 100460786Sps case SK_CTL_BACKSPACE: 100560786Sps s = k_ctl_backspace; 100660786Sps break; 100760786Sps case SK_CTL_DELETE: 100860786Sps s = k_ctl_delete; 100960786Sps break; 101060786Sps case SK_F1: 101160786Sps s = k_f1; 101260786Sps break; 101360786Sps case SK_BACKTAB: 101460786Sps s = k_backtab; 101560786Sps break; 101660786Sps#else 101760786Sps case SK_RIGHT_ARROW: 101860786Sps s = ltgetstr("kr", &sp); 101960786Sps break; 102060786Sps case SK_LEFT_ARROW: 102160786Sps s = ltgetstr("kl", &sp); 102260786Sps break; 102360786Sps case SK_UP_ARROW: 102460786Sps s = ltgetstr("ku", &sp); 102560786Sps break; 102660786Sps case SK_DOWN_ARROW: 102760786Sps s = ltgetstr("kd", &sp); 102860786Sps break; 102960786Sps case SK_PAGE_UP: 103060786Sps s = ltgetstr("kP", &sp); 103160786Sps break; 103260786Sps case SK_PAGE_DOWN: 103360786Sps s = ltgetstr("kN", &sp); 103460786Sps break; 103560786Sps case SK_HOME: 103660786Sps s = ltgetstr("kh", &sp); 103760786Sps break; 103860786Sps case SK_END: 103960786Sps s = ltgetstr("@7", &sp); 104060786Sps break; 104160786Sps case SK_DELETE: 104260786Sps s = ltgetstr("kD", &sp); 104360786Sps if (s == NULL) 104460786Sps { 104560786Sps tbuf[0] = '\177'; 104660786Sps tbuf[1] = '\0'; 104760786Sps s = tbuf; 104860786Sps } 104960786Sps break; 105060786Sps#endif 105160786Sps case SK_CONTROL_K: 105260786Sps tbuf[0] = CONTROL('K'); 105360786Sps tbuf[1] = '\0'; 105460786Sps s = tbuf; 105560786Sps break; 105660786Sps default: 105760786Sps return (NULL); 105860786Sps } 105960786Sps return (s); 106060786Sps} 106160786Sps 106260786Sps/* 106360786Sps * Get terminal capabilities via termcap. 106460786Sps */ 106560786Sps public void 106660786Spsget_term() 106760786Sps{ 106860786Sps#if MSDOS_COMPILER 106960786Sps auto_wrap = 1; 107060786Sps ignaw = 0; 107160786Sps can_goto_line = 1; 107260786Sps clear_bg = 1; 107360786Sps /* 107460786Sps * Set up default colors. 107560786Sps * The xx_s_width and xx_e_width vars are already initialized to 0. 107660786Sps */ 107760786Sps#if MSDOS_COMPILER==MSOFTC 107860786Sps sy_bg_color = _getbkcolor(); 107960786Sps sy_fg_color = _gettextcolor(); 108060786Sps get_clock(); 108160786Sps#else 108260786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 108360786Sps { 108460786Sps struct text_info w; 108560786Sps gettextinfo(&w); 108660786Sps sy_bg_color = (w.attribute >> 4) & 0x0F; 108760786Sps sy_fg_color = (w.attribute >> 0) & 0x0F; 108860786Sps } 108960786Sps#else 109060786Sps#if MSDOS_COMPILER==WIN32C 109160786Sps { 109260786Sps DWORD nread; 109360786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 109460786Sps 109560786Sps con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE); 109660786Sps /* 109760786Sps * Always open stdin in binary. Note this *must* be done 109860786Sps * before any file operations have been done on fd0. 109960786Sps */ 110060786Sps SET_BINARY(0); 110160786Sps GetConsoleScreenBufferInfo(con_out, &scr); 110260786Sps ReadConsoleOutputAttribute(con_out, &curr_attr, 110360786Sps 1, scr.dwCursorPosition, &nread); 110460786Sps sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */ 110560786Sps sy_fg_color = curr_attr & FG_COLORS; 110660786Sps } 110760786Sps#endif 110860786Sps#endif 110960786Sps#endif 111060786Sps nm_fg_color = sy_fg_color; 111160786Sps nm_bg_color = sy_bg_color; 111260786Sps bo_fg_color = 11; 111360786Sps bo_bg_color = 0; 111460786Sps ul_fg_color = 9; 111560786Sps ul_bg_color = 0; 111660786Sps so_fg_color = 15; 111760786Sps so_bg_color = 9; 111860786Sps bl_fg_color = 15; 111960786Sps bl_bg_color = 0; 1120330571Sdelphij sgr_mode = 0; 112160786Sps 112260786Sps /* 112360786Sps * Get size of the screen. 112460786Sps */ 112560786Sps scrsize(); 112660786Sps pos_init(); 112760786Sps 112860786Sps 112960786Sps#else /* !MSDOS_COMPILER */ 113060786Sps 113160786Sps char *sp; 1132330571Sdelphij char *t1, *t2; 113360786Sps char *term; 113460786Sps char termbuf[TERMBUF_SIZE]; 113560786Sps 113660786Sps static char sbuf[TERMSBUF_SIZE]; 113760786Sps 113860786Sps#if OS2 113960786Sps /* 114060786Sps * Make sure the termcap database is available. 114160786Sps */ 114260786Sps sp = lgetenv("TERMCAP"); 114360786Sps if (sp == NULL || *sp == '\0') 114460786Sps { 114560786Sps char *termcap; 114660786Sps if ((sp = homefile("termcap.dat")) != NULL) 114760786Sps { 114860786Sps termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char)); 114960786Sps sprintf(termcap, "TERMCAP=%s", sp); 115060786Sps free(sp); 115160786Sps putenv(termcap); 115260786Sps } 115360786Sps } 115460786Sps#endif 115560786Sps /* 115660786Sps * Find out what kind of terminal this is. 115760786Sps */ 115860786Sps if ((term = lgetenv("TERM")) == NULL) 115960786Sps term = DEFAULT_TERM; 116060786Sps hardcopy = 0; 1161170259Sdelphij if (tgetent(termbuf, term) != TGETENT_OK) 116260786Sps hardcopy = 1; 116360786Sps if (ltgetflag("hc")) 116460786Sps hardcopy = 1; 116560786Sps 116660786Sps /* 116760786Sps * Get size of the screen. 116860786Sps */ 116960786Sps scrsize(); 117060786Sps pos_init(); 117160786Sps 117260786Sps auto_wrap = ltgetflag("am"); 117360786Sps ignaw = ltgetflag("xn"); 117460786Sps above_mem = ltgetflag("da"); 117560786Sps below_mem = ltgetflag("db"); 117660786Sps clear_bg = ltgetflag("ut"); 117760786Sps 117860786Sps /* 117960786Sps * Assumes termcap variable "sg" is the printing width of: 118060786Sps * the standout sequence, the end standout sequence, 118160786Sps * the underline sequence, the end underline sequence, 118260786Sps * the boldface sequence, and the end boldface sequence. 118360786Sps */ 118460786Sps if ((so_s_width = ltgetnum("sg")) < 0) 118560786Sps so_s_width = 0; 118660786Sps so_e_width = so_s_width; 118760786Sps 118860786Sps bo_s_width = bo_e_width = so_s_width; 118960786Sps ul_s_width = ul_e_width = so_s_width; 119060786Sps bl_s_width = bl_e_width = so_s_width; 119160786Sps 119260786Sps#if HILITE_SEARCH 119360786Sps if (so_s_width > 0 || so_e_width > 0) 119460786Sps /* 119560786Sps * Disable highlighting by default on magic cookie terminals. 119660786Sps * Turning on highlighting might change the displayed width 119760786Sps * of a line, causing the display to get messed up. 119860786Sps * The user can turn it back on with -g, 119960786Sps * but she won't like the results. 120060786Sps */ 120160786Sps hilite_search = 0; 120260786Sps#endif 120360786Sps 120460786Sps /* 120560786Sps * Get various string-valued capabilities. 120660786Sps */ 120760786Sps sp = sbuf; 120860786Sps 120960786Sps#if HAVE_OSPEED 121060786Sps sc_pad = ltgetstr("pc", &sp); 121160786Sps if (sc_pad != NULL) 121260786Sps PC = *sc_pad; 121360786Sps#endif 121460786Sps 121560786Sps sc_s_keypad = ltgetstr("ks", &sp); 121660786Sps if (sc_s_keypad == NULL) 121760786Sps sc_s_keypad = ""; 121860786Sps sc_e_keypad = ltgetstr("ke", &sp); 121960786Sps if (sc_e_keypad == NULL) 122060786Sps sc_e_keypad = ""; 1221330571Sdelphij kent = ltgetstr("@8", &sp); 1222330571Sdelphij 1223171009Sdelphij sc_init = ltgetstr("ti", &sp); 122460786Sps if (sc_init == NULL) 122560786Sps sc_init = ""; 122660786Sps 1227171009Sdelphij sc_deinit= ltgetstr("te", &sp); 122860786Sps if (sc_deinit == NULL) 122960786Sps sc_deinit = ""; 123060786Sps 123160786Sps sc_eol_clear = ltgetstr("ce", &sp); 123260786Sps if (sc_eol_clear == NULL || *sc_eol_clear == '\0') 123360786Sps { 123460786Sps missing_cap = 1; 123560786Sps sc_eol_clear = ""; 123660786Sps } 123760786Sps 123860786Sps sc_eos_clear = ltgetstr("cd", &sp); 123960786Sps if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0')) 124060786Sps { 124160786Sps missing_cap = 1; 1242161478Sdelphij sc_eos_clear = ""; 124360786Sps } 124460786Sps 124560786Sps sc_clear = ltgetstr("cl", &sp); 124660786Sps if (sc_clear == NULL || *sc_clear == '\0') 124760786Sps { 124860786Sps missing_cap = 1; 124960786Sps sc_clear = "\n\n"; 125060786Sps } 125160786Sps 125260786Sps sc_move = ltgetstr("cm", &sp); 125360786Sps if (sc_move == NULL || *sc_move == '\0') 125460786Sps { 125560786Sps /* 125660786Sps * This is not an error here, because we don't 125760786Sps * always need sc_move. 125860786Sps * We need it only if we don't have home or lower-left. 125960786Sps */ 126060786Sps sc_move = ""; 126160786Sps can_goto_line = 0; 126260786Sps } else 126360786Sps can_goto_line = 1; 126460786Sps 126560786Sps tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp); 126660786Sps tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp); 126760786Sps tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp); 126860786Sps tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp); 126960786Sps 127060786Sps sc_visual_bell = ltgetstr("vb", &sp); 127160786Sps if (sc_visual_bell == NULL) 127260786Sps sc_visual_bell = ""; 127360786Sps 127460786Sps if (ltgetflag("bs")) 127560786Sps sc_backspace = "\b"; 127660786Sps else 127760786Sps { 127860786Sps sc_backspace = ltgetstr("bc", &sp); 127960786Sps if (sc_backspace == NULL || *sc_backspace == '\0') 128060786Sps sc_backspace = "\b"; 128160786Sps } 128260786Sps 128360786Sps /* 128460786Sps * Choose between using "ho" and "cm" ("home" and "cursor move") 128560786Sps * to move the cursor to the upper left corner of the screen. 128660786Sps */ 128760786Sps t1 = ltgetstr("ho", &sp); 128860786Sps if (t1 == NULL) 128960786Sps t1 = ""; 129060786Sps if (*sc_move == '\0') 129160786Sps t2 = ""; 129260786Sps else 129360786Sps { 129460786Sps strcpy(sp, tgoto(sc_move, 0, 0)); 129560786Sps t2 = sp; 129660786Sps sp += strlen(sp) + 1; 129760786Sps } 129860786Sps sc_home = cheaper(t1, t2, "|\b^"); 129960786Sps 130060786Sps /* 130160786Sps * Choose between using "ll" and "cm" ("lower left" and "cursor move") 130260786Sps * to move the cursor to the lower left corner of the screen. 130360786Sps */ 130460786Sps t1 = ltgetstr("ll", &sp); 130560786Sps if (t1 == NULL) 130660786Sps t1 = ""; 130760786Sps if (*sc_move == '\0') 130860786Sps t2 = ""; 130960786Sps else 131060786Sps { 131160786Sps strcpy(sp, tgoto(sc_move, 0, sc_height-1)); 131260786Sps t2 = sp; 131360786Sps sp += strlen(sp) + 1; 131460786Sps } 131560786Sps sc_lower_left = cheaper(t1, t2, "\r"); 131660786Sps 131760786Sps /* 1318170259Sdelphij * Get carriage return string. 1319170259Sdelphij */ 1320170259Sdelphij sc_return = ltgetstr("cr", &sp); 1321170259Sdelphij if (sc_return == NULL) 1322170259Sdelphij sc_return = "\r"; 1323170259Sdelphij 1324170259Sdelphij /* 132560786Sps * Choose between using "al" or "sr" ("add line" or "scroll reverse") 132660786Sps * to add a line at the top of the screen. 132760786Sps */ 132860786Sps t1 = ltgetstr("al", &sp); 132960786Sps if (t1 == NULL) 133060786Sps t1 = ""; 133160786Sps t2 = ltgetstr("sr", &sp); 133260786Sps if (t2 == NULL) 133360786Sps t2 = ""; 133460786Sps#if OS2 133560786Sps if (*t1 == '\0' && *t2 == '\0') 133660786Sps sc_addline = ""; 133760786Sps else 133860786Sps#endif 133960786Sps if (above_mem) 134060786Sps sc_addline = t1; 134160786Sps else 134260786Sps sc_addline = cheaper(t1, t2, ""); 134360786Sps if (*sc_addline == '\0') 134460786Sps { 134560786Sps /* 134660786Sps * Force repaint on any backward movement. 134760786Sps */ 134860786Sps no_back_scroll = 1; 134960786Sps } 135060786Sps#endif /* MSDOS_COMPILER */ 135160786Sps} 135260786Sps 135360786Sps#if !MSDOS_COMPILER 135460786Sps/* 135560786Sps * Return the cost of displaying a termcap string. 135660786Sps * We use the trick of calling tputs, but as a char printing function 135760786Sps * we give it inc_costcount, which just increments "costcount". 135860786Sps * This tells us how many chars would be printed by using this string. 135960786Sps * {{ Couldn't we just use strlen? }} 136060786Sps */ 136160786Spsstatic int costcount; 136260786Sps 136360786Sps/*ARGSUSED*/ 136460786Sps static int 136560786Spsinc_costcount(c) 136660786Sps int c; 136760786Sps{ 136860786Sps costcount++; 136960786Sps return (c); 137060786Sps} 137160786Sps 137260786Sps static int 137360786Spscost(t) 137460786Sps char *t; 137560786Sps{ 137660786Sps costcount = 0; 137760786Sps tputs(t, sc_height, inc_costcount); 137860786Sps return (costcount); 137960786Sps} 138060786Sps 138160786Sps/* 138260786Sps * Return the "best" of the two given termcap strings. 138360786Sps * The best, if both exist, is the one with the lower 138460786Sps * cost (see cost() function). 138560786Sps */ 138660786Sps static char * 138760786Spscheaper(t1, t2, def) 138860786Sps char *t1, *t2; 138960786Sps char *def; 139060786Sps{ 139160786Sps if (*t1 == '\0' && *t2 == '\0') 139260786Sps { 139360786Sps missing_cap = 1; 139460786Sps return (def); 139560786Sps } 139660786Sps if (*t1 == '\0') 139760786Sps return (t2); 139860786Sps if (*t2 == '\0') 139960786Sps return (t1); 140060786Sps if (cost(t1) < cost(t2)) 140160786Sps return (t1); 140260786Sps return (t2); 140360786Sps} 140460786Sps 140560786Sps static void 140660786Spstmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp) 140760786Sps char *incap; 140860786Sps char *outcap; 140960786Sps char **instr; 141060786Sps char **outstr; 141160786Sps char *def_instr; 141260786Sps char *def_outstr; 141360786Sps char **spp; 141460786Sps{ 141560786Sps *instr = ltgetstr(incap, spp); 141660786Sps if (*instr == NULL) 141760786Sps { 141860786Sps /* Use defaults. */ 141960786Sps *instr = def_instr; 142060786Sps *outstr = def_outstr; 142160786Sps return; 142260786Sps } 142360786Sps 142460786Sps *outstr = ltgetstr(outcap, spp); 142560786Sps if (*outstr == NULL) 142660786Sps /* No specific out capability; use "me". */ 142760786Sps *outstr = ltgetstr("me", spp); 142860786Sps if (*outstr == NULL) 142960786Sps /* Don't even have "me"; use a null string. */ 143060786Sps *outstr = ""; 143160786Sps} 143260786Sps 143360786Sps#endif /* MSDOS_COMPILER */ 143460786Sps 143560786Sps 143660786Sps/* 143760786Sps * Below are the functions which perform all the 143860786Sps * terminal-specific screen manipulation. 143960786Sps */ 144060786Sps 144160786Sps 144260786Sps#if MSDOS_COMPILER 144360786Sps 144460786Sps#if MSDOS_COMPILER==WIN32C 144560786Sps static void 144660786Sps_settextposition(int row, int col) 144760786Sps{ 144860786Sps COORD cpos; 144960786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 145060786Sps 145160786Sps GetConsoleScreenBufferInfo(con_out, &csbi); 145260786Sps cpos.X = csbi.srWindow.Left + (col - 1); 145360786Sps cpos.Y = csbi.srWindow.Top + (row - 1); 145460786Sps SetConsoleCursorPosition(con_out, cpos); 145560786Sps} 145660786Sps#endif 145760786Sps 145860786Sps/* 145960786Sps * Initialize the screen to the correct color at startup. 146060786Sps */ 146160786Sps static void 146260786Spsinitcolor() 146360786Sps{ 1464330571Sdelphij#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 1465330571Sdelphij intensevideo(); 1466330571Sdelphij#endif 146760786Sps SETCOLORS(nm_fg_color, nm_bg_color); 146860786Sps#if 0 146960786Sps /* 147060786Sps * This clears the screen at startup. This is different from 147160786Sps * the behavior of other versions of less. Disable it for now. 147260786Sps */ 147360786Sps char *blanks; 147460786Sps int row; 147560786Sps int col; 147660786Sps 147760786Sps /* 147860786Sps * Create a complete, blank screen using "normal" colors. 147960786Sps */ 148060786Sps SETCOLORS(nm_fg_color, nm_bg_color); 148160786Sps blanks = (char *) ecalloc(width+1, sizeof(char)); 148260786Sps for (col = 0; col < sc_width; col++) 148360786Sps blanks[col] = ' '; 148460786Sps blanks[sc_width] = '\0'; 148560786Sps for (row = 0; row < sc_height; row++) 148660786Sps _outtext(blanks); 148760786Sps free(blanks); 148860786Sps#endif 148960786Sps} 149060786Sps#endif 149160786Sps 149260786Sps#if MSDOS_COMPILER==WIN32C 149360786Sps 149460786Sps/* 149560786Sps * Termcap-like init with a private win32 console. 149660786Sps */ 149760786Sps static void 149860786Spswin32_init_term() 149960786Sps{ 150060786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 150160786Sps COORD size; 150260786Sps 150360786Sps if (con_out_save == INVALID_HANDLE_VALUE) 150460786Sps return; 150560786Sps 150660786Sps GetConsoleScreenBufferInfo(con_out_save, &scr); 150760786Sps 150860786Sps if (con_out_ours == INVALID_HANDLE_VALUE) 150960786Sps { 1510330571Sdelphij DWORD output_mode; 1511330571Sdelphij 151260786Sps /* 151360786Sps * Create our own screen buffer, so that we 151460786Sps * may restore the original when done. 151560786Sps */ 151660786Sps con_out_ours = CreateConsoleScreenBuffer( 151760786Sps GENERIC_WRITE | GENERIC_READ, 151860786Sps FILE_SHARE_WRITE | FILE_SHARE_READ, 151960786Sps (LPSECURITY_ATTRIBUTES) NULL, 152060786Sps CONSOLE_TEXTMODE_BUFFER, 152160786Sps (LPVOID) NULL); 1522330571Sdelphij /* 1523330571Sdelphij * Enable underline, if available. 1524330571Sdelphij */ 1525330571Sdelphij GetConsoleMode(con_out_ours, &output_mode); 1526330571Sdelphij have_ul = SetConsoleMode(con_out_ours, 1527330571Sdelphij output_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); 152860786Sps } 152960786Sps 153060786Sps size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 153160786Sps size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 153260786Sps SetConsoleScreenBufferSize(con_out_ours, size); 153360786Sps SetConsoleActiveScreenBuffer(con_out_ours); 153460786Sps con_out = con_out_ours; 153560786Sps} 153660786Sps 153760786Sps/* 153860786Sps * Restore the startup console. 153960786Sps */ 154060786Spsstatic void 154160786Spswin32_deinit_term() 154260786Sps{ 154360786Sps if (con_out_save == INVALID_HANDLE_VALUE) 154460786Sps return; 154560786Sps if (quitting) 154660786Sps (void) CloseHandle(con_out_ours); 154760786Sps SetConsoleActiveScreenBuffer(con_out_save); 154860786Sps con_out = con_out_save; 154960786Sps} 155060786Sps 155160786Sps#endif 155260786Sps 155360786Sps/* 155460786Sps * Initialize terminal 155560786Sps */ 155660786Sps public void 155760786Spsinit() 155860786Sps{ 155960786Sps#if !MSDOS_COMPILER 1560330571Sdelphij if (quit_if_one_screen && line_count >= sc_height) 1561330571Sdelphij quit_if_one_screen = FALSE; 1562330571Sdelphij if (!no_init && !quit_if_one_screen) 156389022Sps tputs(sc_init, sc_height, putchr); 156489022Sps if (!no_keypad) 156589022Sps tputs(sc_s_keypad, sc_height, putchr); 1566161478Sdelphij if (top_scroll) 1567161478Sdelphij { 1568161478Sdelphij int i; 1569161478Sdelphij 1570161478Sdelphij /* 1571161478Sdelphij * This is nice to terminals with no alternate screen, 1572161478Sdelphij * but with saved scrolled-off-the-top lines. This way, 1573161478Sdelphij * no previous line is lost, but we start with a whole 1574161478Sdelphij * screen to ourself. 1575161478Sdelphij */ 1576161478Sdelphij for (i = 1; i < sc_height; i++) 1577161478Sdelphij putchr('\n'); 1578191930Sdelphij } else 1579191930Sdelphij line_left(); 158060786Sps#else 158160786Sps#if MSDOS_COMPILER==WIN32C 158289022Sps if (!no_init) 158389022Sps win32_init_term(); 158460786Sps#endif 158560786Sps initcolor(); 158660786Sps flush(); 158760786Sps#endif 158860786Sps init_done = 1; 158960786Sps} 159060786Sps 159160786Sps/* 159260786Sps * Deinitialize terminal 159360786Sps */ 159460786Sps public void 159560786Spsdeinit() 159660786Sps{ 159760786Sps if (!init_done) 159860786Sps return; 159960786Sps#if !MSDOS_COMPILER 160089022Sps if (!no_keypad) 160189022Sps tputs(sc_e_keypad, sc_height, putchr); 1602330571Sdelphij if (!no_init && !quit_if_one_screen) 160389022Sps tputs(sc_deinit, sc_height, putchr); 160460786Sps#else 160589022Sps /* Restore system colors. */ 160660786Sps SETCOLORS(sy_fg_color, sy_bg_color); 160760786Sps#if MSDOS_COMPILER==WIN32C 160889022Sps if (!no_init) 160989022Sps win32_deinit_term(); 161089022Sps#else 161189022Sps /* Need clreol to make SETCOLORS take effect. */ 161289022Sps clreol(); 161360786Sps#endif 161460786Sps#endif 161560786Sps init_done = 0; 161660786Sps} 161760786Sps 161860786Sps/* 161960786Sps * Home cursor (move to upper left corner of screen). 162060786Sps */ 162160786Sps public void 162260786Spshome() 162360786Sps{ 162460786Sps#if !MSDOS_COMPILER 162560786Sps tputs(sc_home, 1, putchr); 162660786Sps#else 162760786Sps flush(); 162860786Sps _settextposition(1,1); 162960786Sps#endif 163060786Sps} 163160786Sps 163260786Sps/* 163360786Sps * Add a blank line (called with cursor at home). 163460786Sps * Should scroll the display down. 163560786Sps */ 163660786Sps public void 163760786Spsadd_line() 163860786Sps{ 163960786Sps#if !MSDOS_COMPILER 164060786Sps tputs(sc_addline, sc_height, putchr); 164160786Sps#else 164260786Sps flush(); 164360786Sps#if MSDOS_COMPILER==MSOFTC 164460786Sps _scrolltextwindow(_GSCROLLDOWN); 164560786Sps _settextposition(1,1); 164660786Sps#else 164760786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 164860786Sps movetext(1,1, sc_width,sc_height-1, 1,2); 164960786Sps gotoxy(1,1); 165060786Sps clreol(); 165160786Sps#else 165260786Sps#if MSDOS_COMPILER==WIN32C 165360786Sps { 165460786Sps CHAR_INFO fillchar; 165560786Sps SMALL_RECT rcSrc, rcClip; 165660786Sps COORD new_org; 165760786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 165860786Sps 165960786Sps GetConsoleScreenBufferInfo(con_out,&csbi); 166060786Sps 166160786Sps /* The clip rectangle is the entire visible screen. */ 166260786Sps rcClip.Left = csbi.srWindow.Left; 166360786Sps rcClip.Top = csbi.srWindow.Top; 166460786Sps rcClip.Right = csbi.srWindow.Right; 166560786Sps rcClip.Bottom = csbi.srWindow.Bottom; 166660786Sps 166760786Sps /* The source rectangle is the visible screen minus the last line. */ 166860786Sps rcSrc = rcClip; 166960786Sps rcSrc.Bottom--; 167060786Sps 167160786Sps /* Move the top left corner of the source window down one row. */ 167260786Sps new_org.X = rcSrc.Left; 167360786Sps new_org.Y = rcSrc.Top + 1; 167460786Sps 167560786Sps /* Fill the right character and attributes. */ 167660786Sps fillchar.Char.AsciiChar = ' '; 167760786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 167860786Sps fillchar.Attributes = curr_attr; 167960786Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 168060786Sps _settextposition(1,1); 168160786Sps } 168260786Sps#endif 168360786Sps#endif 168460786Sps#endif 168560786Sps#endif 168660786Sps} 168760786Sps 168889022Sps#if 0 168960786Sps/* 169060786Sps * Remove the n topmost lines and scroll everything below it in the 169160786Sps * window upward. This is needed to stop leaking the topmost line 169260786Sps * into the scrollback buffer when we go down-one-line (in WIN32). 169360786Sps */ 169460786Sps public void 169560786Spsremove_top(n) 169660786Sps int n; 169760786Sps{ 169860786Sps#if MSDOS_COMPILER==WIN32C 169960786Sps SMALL_RECT rcSrc, rcClip; 170060786Sps CHAR_INFO fillchar; 170160786Sps COORD new_org; 170260786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 170360786Sps 170460786Sps if (n >= sc_height - 1) 170560786Sps { 170660786Sps clear(); 170760786Sps home(); 170860786Sps return; 170960786Sps } 171060786Sps 171160786Sps flush(); 171260786Sps 171360786Sps GetConsoleScreenBufferInfo(con_out, &csbi); 171460786Sps 171560786Sps /* Get the extent of all-visible-rows-but-the-last. */ 171660786Sps rcSrc.Left = csbi.srWindow.Left; 171760786Sps rcSrc.Top = csbi.srWindow.Top + n; 171860786Sps rcSrc.Right = csbi.srWindow.Right; 171960786Sps rcSrc.Bottom = csbi.srWindow.Bottom; 172060786Sps 172160786Sps /* Get the clip rectangle. */ 172260786Sps rcClip.Left = rcSrc.Left; 172360786Sps rcClip.Top = csbi.srWindow.Top; 172460786Sps rcClip.Right = rcSrc.Right; 172560786Sps rcClip.Bottom = rcSrc.Bottom ; 172660786Sps 172760786Sps /* Move the source window up n rows. */ 172860786Sps new_org.X = rcSrc.Left; 172960786Sps new_org.Y = rcSrc.Top - n; 173060786Sps 173160786Sps /* Fill the right character and attributes. */ 173260786Sps fillchar.Char.AsciiChar = ' '; 173360786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 173460786Sps fillchar.Attributes = curr_attr; 173560786Sps 173660786Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 173760786Sps 173860786Sps /* Position cursor on first blank line. */ 173960786Sps goto_line(sc_height - n - 1); 174060786Sps#endif 174160786Sps} 174289022Sps#endif 174360786Sps 174489022Sps#if MSDOS_COMPILER==WIN32C 174560786Sps/* 174689022Sps * Clear the screen. 174789022Sps */ 174889022Sps static void 174989022Spswin32_clear() 175089022Sps{ 175189022Sps /* 175289022Sps * This will clear only the currently visible rows of the NT 175389022Sps * console buffer, which means none of the precious scrollback 175489022Sps * rows are touched making for faster scrolling. Note that, if 175589022Sps * the window has fewer columns than the console buffer (i.e. 175689022Sps * there is a horizontal scrollbar as well), the entire width 175789022Sps * of the visible rows will be cleared. 175889022Sps */ 175989022Sps COORD topleft; 176089022Sps DWORD nchars; 176189022Sps DWORD winsz; 176289022Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 176389022Sps 176489022Sps /* get the number of cells in the current buffer */ 176589022Sps GetConsoleScreenBufferInfo(con_out, &csbi); 176689022Sps winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); 176789022Sps topleft.X = 0; 176889022Sps topleft.Y = csbi.srWindow.Top; 176989022Sps 177089022Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 177189022Sps FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars); 177289022Sps FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars); 177389022Sps} 177489022Sps 177589022Sps/* 177689022Sps * Remove the n topmost lines and scroll everything below it in the 177789022Sps * window upward. 177889022Sps */ 177989022Sps public void 178089022Spswin32_scroll_up(n) 178189022Sps int n; 178289022Sps{ 178389022Sps SMALL_RECT rcSrc, rcClip; 178489022Sps CHAR_INFO fillchar; 178589022Sps COORD topleft; 178689022Sps COORD new_org; 178789022Sps DWORD nchars; 178889022Sps DWORD size; 178989022Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 179089022Sps 179189022Sps if (n <= 0) 179289022Sps return; 179389022Sps 179489022Sps if (n >= sc_height - 1) 179589022Sps { 179689022Sps win32_clear(); 179789022Sps _settextposition(1,1); 179889022Sps return; 179989022Sps } 180089022Sps 180189022Sps /* Get the extent of what will remain visible after scrolling. */ 180289022Sps GetConsoleScreenBufferInfo(con_out, &csbi); 180389022Sps rcSrc.Left = csbi.srWindow.Left; 180489022Sps rcSrc.Top = csbi.srWindow.Top + n; 180589022Sps rcSrc.Right = csbi.srWindow.Right; 180689022Sps rcSrc.Bottom = csbi.srWindow.Bottom; 180789022Sps 180889022Sps /* Get the clip rectangle. */ 180989022Sps rcClip.Left = rcSrc.Left; 181089022Sps rcClip.Top = csbi.srWindow.Top; 181189022Sps rcClip.Right = rcSrc.Right; 181289022Sps rcClip.Bottom = rcSrc.Bottom ; 181389022Sps 181489022Sps /* Move the source text to the top of the screen. */ 181589022Sps new_org.X = rcSrc.Left; 1816221715Sdelphij new_org.Y = rcClip.Top; 181789022Sps 181889022Sps /* Fill the right character and attributes. */ 181989022Sps fillchar.Char.AsciiChar = ' '; 182089022Sps fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color); 182189022Sps 182289022Sps /* Scroll the window. */ 182389022Sps SetConsoleTextAttribute(con_out, fillchar.Attributes); 182489022Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 182589022Sps 182689022Sps /* Clear remaining lines at bottom. */ 182789022Sps topleft.X = csbi.dwCursorPosition.X; 182889022Sps topleft.Y = rcSrc.Bottom - n; 182989022Sps size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X); 183089022Sps FillConsoleOutputCharacter(con_out, ' ', size, topleft, 183189022Sps &nchars); 183289022Sps FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft, 183389022Sps &nchars); 183489022Sps SetConsoleTextAttribute(con_out, curr_attr); 183589022Sps 183689022Sps /* Move cursor n lines up from where it was. */ 183789022Sps csbi.dwCursorPosition.Y -= n; 183889022Sps SetConsoleCursorPosition(con_out, csbi.dwCursorPosition); 183989022Sps} 184089022Sps#endif 184189022Sps 184289022Sps/* 184360786Sps * Move cursor to lower left corner of screen. 184460786Sps */ 184560786Sps public void 184660786Spslower_left() 184760786Sps{ 1848330571Sdelphij if (!init_done) 1849330571Sdelphij return; 185060786Sps#if !MSDOS_COMPILER 185160786Sps tputs(sc_lower_left, 1, putchr); 185260786Sps#else 185360786Sps flush(); 185460786Sps _settextposition(sc_height, 1); 185560786Sps#endif 185660786Sps} 185760786Sps 185860786Sps/* 1859170259Sdelphij * Move cursor to left position of current line. 1860170259Sdelphij */ 1861170259Sdelphij public void 1862170259Sdelphijline_left() 1863170259Sdelphij{ 1864170259Sdelphij#if !MSDOS_COMPILER 1865170259Sdelphij tputs(sc_return, 1, putchr); 1866170259Sdelphij#else 1867170259Sdelphij int row; 1868170259Sdelphij flush(); 1869170259Sdelphij#if MSDOS_COMPILER==WIN32C 1870170259Sdelphij { 1871170259Sdelphij CONSOLE_SCREEN_BUFFER_INFO scr; 1872170259Sdelphij GetConsoleScreenBufferInfo(con_out, &scr); 1873170259Sdelphij row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 1874170259Sdelphij } 1875170259Sdelphij#else 1876173685Sdelphij#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 1877173685Sdelphij row = wherey(); 1878173685Sdelphij#else 1879170259Sdelphij { 1880170259Sdelphij struct rccoord tpos = _gettextposition(); 1881170259Sdelphij row = tpos.row; 1882170259Sdelphij } 1883170259Sdelphij#endif 1884173685Sdelphij#endif 1885170259Sdelphij _settextposition(row, 1); 1886170259Sdelphij#endif 1887170259Sdelphij} 1888170259Sdelphij 1889170259Sdelphij/* 189060786Sps * Check if the console size has changed and reset internals 189160786Sps * (in lieu of SIGWINCH for WIN32). 189260786Sps */ 189360786Sps public void 189460786Spscheck_winch() 189560786Sps{ 189660786Sps#if MSDOS_COMPILER==WIN32C 189760786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 189860786Sps COORD size; 189960786Sps 190060786Sps if (con_out == INVALID_HANDLE_VALUE) 190160786Sps return; 190260786Sps 190360786Sps flush(); 190460786Sps GetConsoleScreenBufferInfo(con_out, &scr); 190560786Sps size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 190660786Sps size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 190760786Sps if (size.Y != sc_height || size.X != sc_width) 190860786Sps { 190960786Sps sc_height = size.Y; 191060786Sps sc_width = size.X; 191160786Sps if (!no_init && con_out_ours == con_out) 191260786Sps SetConsoleScreenBufferSize(con_out, size); 191360786Sps pos_init(); 191460786Sps wscroll = (sc_height + 1) / 2; 191560786Sps screen_trashed = 1; 191660786Sps } 191760786Sps#endif 191860786Sps} 191960786Sps 192060786Sps/* 192160786Sps * Goto a specific line on the screen. 192260786Sps */ 192360786Sps public void 1924330571Sdelphijgoto_line(sindex) 1925330571Sdelphij int sindex; 192660786Sps{ 192760786Sps#if !MSDOS_COMPILER 1928330571Sdelphij tputs(tgoto(sc_move, 0, sindex), 1, putchr); 192960786Sps#else 193060786Sps flush(); 1931330571Sdelphij _settextposition(sindex+1, 1); 193260786Sps#endif 193360786Sps} 193460786Sps 193560786Sps#if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC 193660786Sps/* 193760786Sps * Create an alternate screen which is all white. 193860786Sps * This screen is used to create a "flash" effect, by displaying it 193960786Sps * briefly and then switching back to the normal screen. 194060786Sps * {{ Yuck! There must be a better way to get a visual bell. }} 194160786Sps */ 194260786Sps static void 194360786Spscreate_flash() 194460786Sps{ 194560786Sps#if MSDOS_COMPILER==MSOFTC 194660786Sps struct videoconfig w; 194760786Sps char *blanks; 194860786Sps int row, col; 194960786Sps 195060786Sps _getvideoconfig(&w); 195160786Sps videopages = w.numvideopages; 195260786Sps if (videopages < 2) 195360786Sps { 1954161478Sdelphij at_enter(AT_STANDOUT); 1955161478Sdelphij at_exit(); 195660786Sps } else 195760786Sps { 195860786Sps _setactivepage(1); 1959161478Sdelphij at_enter(AT_STANDOUT); 196060786Sps blanks = (char *) ecalloc(w.numtextcols, sizeof(char)); 196160786Sps for (col = 0; col < w.numtextcols; col++) 196260786Sps blanks[col] = ' '; 196360786Sps for (row = w.numtextrows; row > 0; row--) 196460786Sps _outmem(blanks, w.numtextcols); 196560786Sps _setactivepage(0); 196660786Sps _setvisualpage(0); 196760786Sps free(blanks); 1968161478Sdelphij at_exit(); 196960786Sps } 197060786Sps#else 197160786Sps#if MSDOS_COMPILER==BORLANDC 1972330571Sdelphij int n; 197360786Sps 197460786Sps whitescreen = (unsigned short *) 197560786Sps malloc(sc_width * sc_height * sizeof(short)); 197660786Sps if (whitescreen == NULL) 197760786Sps return; 197860786Sps for (n = 0; n < sc_width * sc_height; n++) 197960786Sps whitescreen[n] = 0x7020; 198060786Sps#else 198160786Sps#if MSDOS_COMPILER==WIN32C 1982330571Sdelphij int n; 198360786Sps 198460786Sps whitescreen = (WORD *) 198560786Sps malloc(sc_height * sc_width * sizeof(WORD)); 198660786Sps if (whitescreen == NULL) 198760786Sps return; 198860786Sps /* Invert the standard colors. */ 198960786Sps for (n = 0; n < sc_width * sc_height; n++) 199060786Sps whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color); 199160786Sps#endif 199260786Sps#endif 199360786Sps#endif 199460786Sps flash_created = 1; 199560786Sps} 199660786Sps#endif /* MSDOS_COMPILER */ 199760786Sps 199860786Sps/* 199960786Sps * Output the "visual bell", if there is one. 200060786Sps */ 200160786Sps public void 200260786Spsvbell() 200360786Sps{ 200460786Sps#if !MSDOS_COMPILER 200560786Sps if (*sc_visual_bell == '\0') 200660786Sps return; 200760786Sps tputs(sc_visual_bell, sc_height, putchr); 200860786Sps#else 200960786Sps#if MSDOS_COMPILER==DJGPPC 201060786Sps ScreenVisualBell(); 201160786Sps#else 201260786Sps#if MSDOS_COMPILER==MSOFTC 201360786Sps /* 201460786Sps * Create a flash screen on the second video page. 201560786Sps * Switch to that page, then switch back. 201660786Sps */ 201760786Sps if (!flash_created) 201860786Sps create_flash(); 201960786Sps if (videopages < 2) 202060786Sps return; 202160786Sps _setvisualpage(1); 202260786Sps delay(100); 202360786Sps _setvisualpage(0); 202460786Sps#else 202560786Sps#if MSDOS_COMPILER==BORLANDC 202660786Sps unsigned short *currscreen; 202760786Sps 202860786Sps /* 202960786Sps * Get a copy of the current screen. 203060786Sps * Display the flash screen. 203160786Sps * Then restore the old screen. 203260786Sps */ 203360786Sps if (!flash_created) 203460786Sps create_flash(); 203560786Sps if (whitescreen == NULL) 203660786Sps return; 203760786Sps currscreen = (unsigned short *) 203860786Sps malloc(sc_width * sc_height * sizeof(short)); 203960786Sps if (currscreen == NULL) return; 204060786Sps gettext(1, 1, sc_width, sc_height, currscreen); 204160786Sps puttext(1, 1, sc_width, sc_height, whitescreen); 204260786Sps delay(100); 204360786Sps puttext(1, 1, sc_width, sc_height, currscreen); 204460786Sps free(currscreen); 204560786Sps#else 204660786Sps#if MSDOS_COMPILER==WIN32C 204760786Sps /* paint screen with an inverse color */ 204860786Sps clear(); 204960786Sps 205060786Sps /* leave it displayed for 100 msec. */ 205160786Sps Sleep(100); 205260786Sps 205360786Sps /* restore with a redraw */ 205460786Sps repaint(); 205560786Sps#endif 205660786Sps#endif 205760786Sps#endif 205860786Sps#endif 205960786Sps#endif 206060786Sps} 206160786Sps 206260786Sps/* 206360786Sps * Make a noise. 206460786Sps */ 206560786Sps static void 206660786Spsbeep() 206760786Sps{ 206860786Sps#if !MSDOS_COMPILER 206989022Sps putchr(CONTROL('G')); 207060786Sps#else 207160786Sps#if MSDOS_COMPILER==WIN32C 207260786Sps MessageBeep(0); 207360786Sps#else 207460786Sps write(1, "\7", 1); 207560786Sps#endif 207660786Sps#endif 207760786Sps} 207860786Sps 207960786Sps/* 208060786Sps * Ring the terminal bell. 208160786Sps */ 208260786Sps public void 208360786Spsbell() 208460786Sps{ 208560786Sps if (quiet == VERY_QUIET) 208660786Sps vbell(); 208760786Sps else 208860786Sps beep(); 208960786Sps} 209060786Sps 209160786Sps/* 209260786Sps * Clear the screen. 209360786Sps */ 209460786Sps public void 209560786Spsclear() 209660786Sps{ 209760786Sps#if !MSDOS_COMPILER 209860786Sps tputs(sc_clear, sc_height, putchr); 209960786Sps#else 210060786Sps flush(); 210160786Sps#if MSDOS_COMPILER==WIN32C 210289022Sps win32_clear(); 210360786Sps#else 210460786Sps _clearscreen(_GCLEARSCREEN); 210560786Sps#endif 210660786Sps#endif 210760786Sps} 210860786Sps 210960786Sps/* 211060786Sps * Clear from the cursor to the end of the cursor's line. 211160786Sps * {{ This must not move the cursor. }} 211260786Sps */ 211360786Sps public void 211460786Spsclear_eol() 211560786Sps{ 211660786Sps#if !MSDOS_COMPILER 211760786Sps tputs(sc_eol_clear, 1, putchr); 211860786Sps#else 211960786Sps#if MSDOS_COMPILER==MSOFTC 212060786Sps short top, left; 212160786Sps short bot, right; 212260786Sps struct rccoord tpos; 212360786Sps 212460786Sps flush(); 212560786Sps /* 212660786Sps * Save current state. 212760786Sps */ 212860786Sps tpos = _gettextposition(); 212960786Sps _gettextwindow(&top, &left, &bot, &right); 213060786Sps /* 213160786Sps * Set a temporary window to the current line, 213260786Sps * from the cursor's position to the right edge of the screen. 213360786Sps * Then clear that window. 213460786Sps */ 213560786Sps _settextwindow(tpos.row, tpos.col, tpos.row, sc_width); 213660786Sps _clearscreen(_GWINDOW); 213760786Sps /* 213860786Sps * Restore state. 213960786Sps */ 214060786Sps _settextwindow(top, left, bot, right); 214160786Sps _settextposition(tpos.row, tpos.col); 214260786Sps#else 214360786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 214460786Sps flush(); 214560786Sps clreol(); 214660786Sps#else 214760786Sps#if MSDOS_COMPILER==WIN32C 214860786Sps DWORD nchars; 214960786Sps COORD cpos; 215060786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 215160786Sps 215260786Sps flush(); 215360786Sps memset(&scr, 0, sizeof(scr)); 215460786Sps GetConsoleScreenBufferInfo(con_out, &scr); 215560786Sps cpos.X = scr.dwCursorPosition.X; 215660786Sps cpos.Y = scr.dwCursorPosition.Y; 215760786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 215860786Sps FillConsoleOutputAttribute(con_out, curr_attr, 215960786Sps scr.dwSize.X - cpos.X, cpos, &nchars); 216060786Sps FillConsoleOutputCharacter(con_out, ' ', 216160786Sps scr.dwSize.X - cpos.X, cpos, &nchars); 216260786Sps#endif 216360786Sps#endif 216460786Sps#endif 216560786Sps#endif 216660786Sps} 216760786Sps 216860786Sps/* 216960786Sps * Clear the current line. 217060786Sps * Clear the screen if there's off-screen memory below the display. 217160786Sps */ 217260786Sps static void 217360786Spsclear_eol_bot() 217460786Sps{ 217560786Sps#if MSDOS_COMPILER 217660786Sps clear_eol(); 217760786Sps#else 217860786Sps if (below_mem) 217960786Sps tputs(sc_eos_clear, 1, putchr); 218060786Sps else 218160786Sps tputs(sc_eol_clear, 1, putchr); 218260786Sps#endif 218360786Sps} 218460786Sps 218560786Sps/* 218660786Sps * Clear the bottom line of the display. 218760786Sps * Leave the cursor at the beginning of the bottom line. 218860786Sps */ 218960786Sps public void 219060786Spsclear_bot() 219160786Sps{ 219260786Sps /* 219360786Sps * If we're in a non-normal attribute mode, temporarily exit 219460786Sps * the mode while we do the clear. Some terminals fill the 219560786Sps * cleared area with the current attribute. 219660786Sps */ 2197170259Sdelphij if (oldbot) 2198170259Sdelphij lower_left(); 2199170259Sdelphij else 2200170259Sdelphij line_left(); 2201170259Sdelphij 2202161478Sdelphij if (attrmode == AT_NORMAL) 2203161478Sdelphij clear_eol_bot(); 2204161478Sdelphij else 220560786Sps { 2206161478Sdelphij int saved_attrmode = attrmode; 2207161478Sdelphij 2208161478Sdelphij at_exit(); 220960786Sps clear_eol_bot(); 2210161478Sdelphij at_enter(saved_attrmode); 221160786Sps } 221260786Sps} 221360786Sps 221460786Sps public void 2215161478Sdelphijat_enter(attr) 2216161478Sdelphij int attr; 221760786Sps{ 2218161478Sdelphij attr = apply_at_specials(attr); 221960786Sps 222060786Sps#if !MSDOS_COMPILER 2221161478Sdelphij /* The one with the most priority is last. */ 2222161478Sdelphij if (attr & AT_UNDERLINE) 2223161478Sdelphij tputs(sc_u_in, 1, putchr); 2224161478Sdelphij if (attr & AT_BOLD) 2225161478Sdelphij tputs(sc_b_in, 1, putchr); 2226161478Sdelphij if (attr & AT_BLINK) 2227161478Sdelphij tputs(sc_bl_in, 1, putchr); 2228161478Sdelphij if (attr & AT_STANDOUT) 2229161478Sdelphij tputs(sc_s_in, 1, putchr); 223060786Sps#else 223160786Sps flush(); 2232161478Sdelphij /* The one with the most priority is first. */ 2233161478Sdelphij if (attr & AT_STANDOUT) 2234161478Sdelphij { 2235161478Sdelphij SETCOLORS(so_fg_color, so_bg_color); 2236161478Sdelphij } else if (attr & AT_BLINK) 2237161478Sdelphij { 2238161478Sdelphij SETCOLORS(bl_fg_color, bl_bg_color); 2239161478Sdelphij } 2240161478Sdelphij else if (attr & AT_BOLD) 2241161478Sdelphij { 2242161478Sdelphij SETCOLORS(bo_fg_color, bo_bg_color); 2243161478Sdelphij } 2244161478Sdelphij else if (attr & AT_UNDERLINE) 2245161478Sdelphij { 2246161478Sdelphij SETCOLORS(ul_fg_color, ul_bg_color); 2247161478Sdelphij } 224860786Sps#endif 224960786Sps 2250161478Sdelphij attrmode = attr; 225160786Sps} 225260786Sps 225360786Sps public void 2254161478Sdelphijat_exit() 225560786Sps{ 225660786Sps#if !MSDOS_COMPILER 2257161478Sdelphij /* Undo things in the reverse order we did them. */ 2258161478Sdelphij if (attrmode & AT_STANDOUT) 2259161478Sdelphij tputs(sc_s_out, 1, putchr); 2260161478Sdelphij if (attrmode & AT_BLINK) 2261161478Sdelphij tputs(sc_bl_out, 1, putchr); 2262161478Sdelphij if (attrmode & AT_BOLD) 2263161478Sdelphij tputs(sc_b_out, 1, putchr); 2264161478Sdelphij if (attrmode & AT_UNDERLINE) 2265161478Sdelphij tputs(sc_u_out, 1, putchr); 226660786Sps#else 226760786Sps flush(); 226860786Sps SETCOLORS(nm_fg_color, nm_bg_color); 226960786Sps#endif 2270161478Sdelphij 227160786Sps attrmode = AT_NORMAL; 227260786Sps} 227360786Sps 227460786Sps public void 2275161478Sdelphijat_switch(attr) 2276161478Sdelphij int attr; 227760786Sps{ 2278170259Sdelphij int new_attrmode = apply_at_specials(attr); 2279170259Sdelphij int ignore_modes = AT_ANSI; 2280170259Sdelphij 2281170259Sdelphij if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes)) 2282161478Sdelphij { 2283161478Sdelphij at_exit(); 2284161478Sdelphij at_enter(attr); 2285161478Sdelphij } 228660786Sps} 228760786Sps 2288161478Sdelphij public int 2289161478Sdelphijis_at_equiv(attr1, attr2) 2290161478Sdelphij int attr1; 2291161478Sdelphij int attr2; 229260786Sps{ 2293161478Sdelphij attr1 = apply_at_specials(attr1); 2294161478Sdelphij attr2 = apply_at_specials(attr2); 2295161478Sdelphij 2296161478Sdelphij return (attr1 == attr2); 229760786Sps} 229860786Sps 2299161478Sdelphij public int 2300161478Sdelphijapply_at_specials(attr) 2301161478Sdelphij int attr; 230260786Sps{ 2303161478Sdelphij if (attr & AT_BINARY) 2304161478Sdelphij attr |= binattr; 2305161478Sdelphij if (attr & AT_HILITE) 2306161478Sdelphij attr |= AT_STANDOUT; 2307161478Sdelphij attr &= ~(AT_BINARY|AT_HILITE); 230860786Sps 2309161478Sdelphij return attr; 231060786Sps} 231160786Sps 231260786Sps#if 0 /* No longer used */ 231360786Sps/* 231460786Sps * Erase the character to the left of the cursor 231560786Sps * and move the cursor left. 231660786Sps */ 231760786Sps public void 231860786Spsbackspace() 231960786Sps{ 232060786Sps#if !MSDOS_COMPILER 232160786Sps /* 232260786Sps * Erase the previous character by overstriking with a space. 232360786Sps */ 232460786Sps tputs(sc_backspace, 1, putchr); 232560786Sps putchr(' '); 232660786Sps tputs(sc_backspace, 1, putchr); 232760786Sps#else 232860786Sps#if MSDOS_COMPILER==MSOFTC 232960786Sps struct rccoord tpos; 233060786Sps 233160786Sps flush(); 233260786Sps tpos = _gettextposition(); 233360786Sps if (tpos.col <= 1) 233460786Sps return; 233560786Sps _settextposition(tpos.row, tpos.col-1); 233660786Sps _outtext(" "); 233760786Sps _settextposition(tpos.row, tpos.col-1); 233860786Sps#else 233960786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 234060786Sps cputs("\b"); 234160786Sps#else 234260786Sps#if MSDOS_COMPILER==WIN32C 234360786Sps COORD cpos; 234460786Sps DWORD cChars; 234560786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 234660786Sps 234760786Sps flush(); 234860786Sps GetConsoleScreenBufferInfo(con_out, &scr); 234960786Sps cpos = scr.dwCursorPosition; 235060786Sps if (cpos.X <= 0) 235160786Sps return; 235260786Sps cpos.X--; 235360786Sps SetConsoleCursorPosition(con_out, cpos); 235460786Sps FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars); 235560786Sps SetConsoleCursorPosition(con_out, cpos); 235660786Sps#endif 235760786Sps#endif 235860786Sps#endif 235960786Sps#endif 236060786Sps} 236160786Sps#endif /* 0 */ 236260786Sps 236360786Sps/* 236460786Sps * Output a plain backspace, without erasing the previous char. 236560786Sps */ 236660786Sps public void 236760786Spsputbs() 236860786Sps{ 236960786Sps#if !MSDOS_COMPILER 237060786Sps tputs(sc_backspace, 1, putchr); 237160786Sps#else 237260786Sps int row, col; 237360786Sps 237460786Sps flush(); 237560786Sps { 237660786Sps#if MSDOS_COMPILER==MSOFTC 237760786Sps struct rccoord tpos; 237860786Sps tpos = _gettextposition(); 237960786Sps row = tpos.row; 238060786Sps col = tpos.col; 238160786Sps#else 238260786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 238360786Sps row = wherey(); 238460786Sps col = wherex(); 238560786Sps#else 238660786Sps#if MSDOS_COMPILER==WIN32C 238760786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 238860786Sps GetConsoleScreenBufferInfo(con_out, &scr); 238960786Sps row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 239060786Sps col = scr.dwCursorPosition.X - scr.srWindow.Left + 1; 239160786Sps#endif 239260786Sps#endif 239360786Sps#endif 239460786Sps } 239560786Sps if (col <= 1) 239660786Sps return; 239760786Sps _settextposition(row, col-1); 239860786Sps#endif /* MSDOS_COMPILER */ 239960786Sps} 240060786Sps 240160786Sps#if MSDOS_COMPILER==WIN32C 240260786Sps/* 240360786Sps * Determine whether an input character is waiting to be read. 240460786Sps */ 240560786Sps static int 240660786Spswin32_kbhit(tty) 240760786Sps HANDLE tty; 240860786Sps{ 240960786Sps INPUT_RECORD ip; 241060786Sps DWORD read; 241160786Sps 241260786Sps if (keyCount > 0) 241360786Sps return (TRUE); 241460786Sps 241560786Sps currentKey.ascii = 0; 241660786Sps currentKey.scan = 0; 241760786Sps 241860786Sps /* 241960786Sps * Wait for a real key-down event, but 242060786Sps * ignore SHIFT and CONTROL key events. 242160786Sps */ 242260786Sps do 242360786Sps { 242460786Sps PeekConsoleInput(tty, &ip, 1, &read); 242560786Sps if (read == 0) 242660786Sps return (FALSE); 242760786Sps ReadConsoleInput(tty, &ip, 1, &read); 242860786Sps } while (ip.EventType != KEY_EVENT || 242960786Sps ip.Event.KeyEvent.bKeyDown != TRUE || 243060786Sps ip.Event.KeyEvent.wVirtualScanCode == 0 || 243160786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT || 243260786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL || 243360786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU); 243460786Sps 243560786Sps currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar; 243660786Sps currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode; 243760786Sps keyCount = ip.Event.KeyEvent.wRepeatCount; 243860786Sps 243960786Sps if (ip.Event.KeyEvent.dwControlKeyState & 244060786Sps (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) 244160786Sps { 244260786Sps switch (currentKey.scan) 244360786Sps { 244460786Sps case PCK_ALT_E: /* letter 'E' */ 244560786Sps currentKey.ascii = 0; 244660786Sps break; 244760786Sps } 244860786Sps } else if (ip.Event.KeyEvent.dwControlKeyState & 244960786Sps (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 245060786Sps { 245160786Sps switch (currentKey.scan) 245260786Sps { 245360786Sps case PCK_RIGHT: /* right arrow */ 245460786Sps currentKey.scan = PCK_CTL_RIGHT; 245560786Sps break; 245660786Sps case PCK_LEFT: /* left arrow */ 245760786Sps currentKey.scan = PCK_CTL_LEFT; 245860786Sps break; 245960786Sps case PCK_DELETE: /* delete */ 246060786Sps currentKey.scan = PCK_CTL_DELETE; 246160786Sps break; 246260786Sps } 2463330571Sdelphij } else if (ip.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) 2464330571Sdelphij { 2465330571Sdelphij switch (currentKey.scan) 2466330571Sdelphij { 2467330571Sdelphij case PCK_SHIFT_TAB: /* tab */ 2468330571Sdelphij currentKey.ascii = 0; 2469330571Sdelphij break; 2470330571Sdelphij } 247160786Sps } 2472330571Sdelphij 247360786Sps return (TRUE); 247460786Sps} 247560786Sps 247660786Sps/* 247760786Sps * Read a character from the keyboard. 247860786Sps */ 247960786Sps public char 248060786SpsWIN32getch(tty) 248160786Sps int tty; 248260786Sps{ 248360786Sps int ascii; 248460786Sps 248560786Sps if (pending_scancode) 248660786Sps { 248760786Sps pending_scancode = 0; 248860786Sps return ((char)(currentKey.scan & 0x00FF)); 248960786Sps } 249060786Sps 249160786Sps while (win32_kbhit((HANDLE)tty) == FALSE) 249260786Sps { 249360786Sps Sleep(20); 249460786Sps if (ABORT_SIGS()) 249560786Sps return ('\003'); 249660786Sps continue; 249760786Sps } 249860786Sps keyCount --; 249960786Sps ascii = currentKey.ascii; 250060786Sps /* 250160786Sps * On PC's, the extended keys return a 2 byte sequence beginning 250260786Sps * with '00', so if the ascii code is 00, the next byte will be 250360786Sps * the lsb of the scan code. 250460786Sps */ 250560786Sps pending_scancode = (ascii == 0x00); 250660786Sps return ((char)ascii); 250760786Sps} 250860786Sps#endif 2509191930Sdelphij 2510191930Sdelphij#if MSDOS_COMPILER 2511191930Sdelphij/* 2512191930Sdelphij */ 2513191930Sdelphij public void 2514191930SdelphijWIN32setcolors(fg, bg) 2515191930Sdelphij int fg; 2516191930Sdelphij int bg; 2517191930Sdelphij{ 2518191930Sdelphij SETCOLORS(fg, bg); 2519191930Sdelphij} 2520191930Sdelphij 2521191930Sdelphij/* 2522191930Sdelphij */ 2523191930Sdelphij public void 2524191930SdelphijWIN32textout(text, len) 2525191930Sdelphij char *text; 2526191930Sdelphij int len; 2527191930Sdelphij{ 2528191930Sdelphij#if MSDOS_COMPILER==WIN32C 2529191930Sdelphij DWORD written; 2530330571Sdelphij if (utf_mode == 2) 2531330571Sdelphij { 2532330571Sdelphij /* 2533330571Sdelphij * We've got UTF-8 text in a non-UTF-8 console. Convert it to 2534330571Sdelphij * wide and use WriteConsoleW. 2535330571Sdelphij */ 2536330571Sdelphij WCHAR wtext[1024]; 2537330571Sdelphij len = MultiByteToWideChar(CP_UTF8, 0, text, len, wtext, 2538330571Sdelphij sizeof(wtext)/sizeof(*wtext)); 2539330571Sdelphij WriteConsoleW(con_out, wtext, len, &written, NULL); 2540330571Sdelphij } else 2541330571Sdelphij WriteConsole(con_out, text, len, &written, NULL); 2542191930Sdelphij#else 2543191930Sdelphij char c = text[len]; 2544191930Sdelphij text[len] = '\0'; 2545191930Sdelphij cputs(text); 2546191930Sdelphij text[len] = c; 2547191930Sdelphij#endif 2548191930Sdelphij} 2549191930Sdelphij#endif 2550