screen.c revision 170967
160812Sps/* $FreeBSD: head/contrib/less/screen.c 170967 2007-06-21 10:44:50Z delphij $ */ 260786Sps/* 3170259Sdelphij * Copyright (C) 1984-2007 Mark Nudelman 460786Sps * 560786Sps * You may distribute under the terms of either the GNU General Public 660786Sps * License or the Less License, as specified in the README file. 760786Sps * 860786Sps * For more information about less, or for information on how to 960786Sps * contact the author, see the README file. 1060786Sps */ 1160786Sps 1260786Sps 1360786Sps/* 1460786Sps * Routines which deal with the characteristics of the terminal. 1560786Sps * Uses termcap to be as terminal-independent as possible. 1660786Sps */ 1760786Sps 1860786Sps#include "less.h" 1960786Sps#include "cmd.h" 2060786Sps 2160786Sps#if MSDOS_COMPILER 2260786Sps#include "pckeys.h" 2360786Sps#if MSDOS_COMPILER==MSOFTC 2460786Sps#include <graph.h> 2560786Sps#else 2660786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 2760786Sps#include <conio.h> 2860786Sps#if MSDOS_COMPILER==DJGPPC 2960786Sps#include <pc.h> 3060786Spsextern int fd0; 3160786Sps#endif 3260786Sps#else 3360786Sps#if MSDOS_COMPILER==WIN32C 3460786Sps#include <windows.h> 3560786Sps#endif 3660786Sps#endif 3760786Sps#endif 3860786Sps#include <time.h> 3960786Sps 4060786Sps#else 4160786Sps 42161478Sdelphij#if HAVE_SYS_IOCTL_H 43161478Sdelphij#include <sys/ioctl.h> 44161478Sdelphij#endif 45161478Sdelphij 4660786Sps#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 4760786Sps#include <termios.h> 4860786Sps#else 4960786Sps#if HAVE_TERMIO_H 5060786Sps#include <termio.h> 5160786Sps#else 5260786Sps#if HAVE_SGSTAT_H 5360786Sps#include <sgstat.h> 5460786Sps#else 5560786Sps#include <sgtty.h> 5660786Sps#endif 5760786Sps#endif 5860786Sps#endif 5960786Sps 6060786Sps#if HAVE_TERMCAP_H 6160786Sps#include <termcap.h> 6260786Sps#endif 6360786Sps#ifdef _OSK 6460786Sps#include <signal.h> 6560786Sps#endif 6660786Sps#if OS2 6760786Sps#include <sys/signal.h> 6889022Sps#include "pckeys.h" 6960786Sps#endif 7060786Sps#if HAVE_SYS_STREAM_H 7160786Sps#include <sys/stream.h> 7260786Sps#endif 7360786Sps#if HAVE_SYS_PTEM_H 7460786Sps#include <sys/ptem.h> 7560786Sps#endif 7660786Sps 7760786Sps#endif /* MSDOS_COMPILER */ 7860786Sps 7960786Sps/* 8060786Sps * Check for broken termios package that forces you to manually 8160786Sps * set the line discipline. 8260786Sps */ 8360786Sps#ifdef __ultrix__ 8460786Sps#define MUST_SET_LINE_DISCIPLINE 1 8560786Sps#else 8660786Sps#define MUST_SET_LINE_DISCIPLINE 0 8760786Sps#endif 8860786Sps 8960786Sps#if OS2 9060786Sps#define DEFAULT_TERM "ansi" 9189022Spsstatic char *windowid; 9260786Sps#else 9360786Sps#define DEFAULT_TERM "unknown" 9460786Sps#endif 9560786Sps 9660786Sps#if MSDOS_COMPILER==MSOFTC 9760786Spsstatic int videopages; 9860786Spsstatic long msec_loops; 9960786Spsstatic int flash_created = 0; 10060786Sps#define SETCOLORS(fg,bg) { _settextcolor(fg); _setbkcolor(bg); } 10160786Sps#endif 10260786Sps 10360786Sps#if MSDOS_COMPILER==BORLANDC 10460786Spsstatic unsigned short *whitescreen; 10560786Spsstatic int flash_created = 0; 10660786Sps#endif 10760786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 10860786Sps#define _settextposition(y,x) gotoxy(x,y) 10960786Sps#define _clearscreen(m) clrscr() 11060786Sps#define _outtext(s) cputs(s) 11160786Sps#define SETCOLORS(fg,bg) { textcolor(fg); textbackground(bg); } 11260786Spsextern int sc_height; 11360786Sps#endif 11460786Sps 11560786Sps#if MSDOS_COMPILER==WIN32C 11660786Spsstruct keyRecord 11760786Sps{ 11860786Sps int ascii; 11960786Sps int scan; 12060786Sps} currentKey; 12160786Sps 12260786Spsstatic int keyCount = 0; 12360786Spsstatic WORD curr_attr; 12460786Spsstatic int pending_scancode = 0; 12560786Spsstatic WORD *whitescreen; 12660786Sps 12760786Spsstatic HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */ 12860786Spsstatic HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */ 12960786SpsHANDLE con_out = INVALID_HANDLE_VALUE; /* current console */ 13060786Sps 13160786Spsextern int quitting; 13260786Spsstatic void win32_init_term(); 13360786Spsstatic void win32_deinit_term(); 13460786Sps 13560786Sps#define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY) 13660786Sps#define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY) 13760786Sps#define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) 13860786Sps#define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \ 13960786Sps if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ 14060786Sps error("SETCOLORS failed"); } 14160786Sps#endif 14260786Sps 14360786Sps#if MSDOS_COMPILER 14460786Spspublic int nm_fg_color; /* Color of normal text */ 14560786Spspublic int nm_bg_color; 14660786Spspublic int bo_fg_color; /* Color of bold text */ 14760786Spspublic int bo_bg_color; 14860786Spspublic int ul_fg_color; /* Color of underlined text */ 14960786Spspublic int ul_bg_color; 15060786Spspublic int so_fg_color; /* Color of standout text */ 15160786Spspublic int so_bg_color; 15260786Spspublic int bl_fg_color; /* Color of blinking text */ 15360786Spspublic int bl_bg_color; 15460786Spsstatic int sy_fg_color; /* Color of system text (before less) */ 15560786Spsstatic int sy_bg_color; 15660786Sps 15760786Sps#else 15860786Sps 15960786Sps/* 16060786Sps * Strings passed to tputs() to do various terminal functions. 16160786Sps */ 16260786Spsstatic char 16360786Sps *sc_pad, /* Pad string */ 16460786Sps *sc_home, /* Cursor home */ 16560786Sps *sc_addline, /* Add line, scroll down following lines */ 16660786Sps *sc_lower_left, /* Cursor to last line, first column */ 167170259Sdelphij *sc_return, /* Cursor to beginning of current line */ 16860786Sps *sc_move, /* General cursor positioning */ 16960786Sps *sc_clear, /* Clear screen */ 17060786Sps *sc_eol_clear, /* Clear to end of line */ 17160786Sps *sc_eos_clear, /* Clear to end of screen */ 17260786Sps *sc_s_in, /* Enter standout (highlighted) mode */ 17360786Sps *sc_s_out, /* Exit standout mode */ 17460786Sps *sc_u_in, /* Enter underline mode */ 17560786Sps *sc_u_out, /* Exit underline mode */ 17660786Sps *sc_b_in, /* Enter bold mode */ 17760786Sps *sc_b_out, /* Exit bold mode */ 17860786Sps *sc_bl_in, /* Enter blink mode */ 17960786Sps *sc_bl_out, /* Exit blink mode */ 18060786Sps *sc_visual_bell, /* Visual bell (flash screen) sequence */ 18160786Sps *sc_backspace, /* Backspace cursor */ 18260786Sps *sc_s_keypad, /* Start keypad mode */ 18360786Sps *sc_e_keypad, /* End keypad mode */ 18460786Sps *sc_init, /* Startup terminal initialization */ 18560786Sps *sc_deinit; /* Exit terminal de-initialization */ 18660786Sps#endif 18760786Sps 18860786Spsstatic int init_done = 0; 18960786Sps 19060786Spspublic int auto_wrap; /* Terminal does \r\n when write past margin */ 19160786Spspublic int ignaw; /* Terminal ignores \n immediately after wrap */ 192161478Sdelphijpublic int erase_char; /* The user's erase char */ 193161478Sdelphijpublic int erase2_char; /* The user's other erase char */ 194161478Sdelphijpublic int kill_char; /* The user's line-kill char */ 19560786Spspublic int werase_char; /* The user's word-erase char */ 19660786Spspublic int sc_width, sc_height; /* Height & width of screen */ 19760786Spspublic int bo_s_width, bo_e_width; /* Printing width of boldface seq */ 19860786Spspublic int ul_s_width, ul_e_width; /* Printing width of underline seq */ 19960786Spspublic int so_s_width, so_e_width; /* Printing width of standout seq */ 20060786Spspublic int bl_s_width, bl_e_width; /* Printing width of blink seq */ 20160786Spspublic int above_mem, below_mem; /* Memory retained above/below screen */ 20260786Spspublic int can_goto_line; /* Can move cursor to any line */ 20360786Spspublic int clear_bg; /* Clear fills with background color */ 20460786Spspublic int missing_cap = 0; /* Some capability is missing */ 20560786Sps 20660786Spsstatic int attrmode = AT_NORMAL; 207161478Sdelphijextern int binattr; 20860786Sps 20960786Sps#if !MSDOS_COMPILER 21060786Spsstatic char *cheaper(); 21160786Spsstatic void tmodes(); 21260786Sps#endif 21360786Sps 21460786Sps/* 21560786Sps * These two variables are sometimes defined in, 21660786Sps * and needed by, the termcap library. 21760786Sps */ 21860786Sps#if MUST_DEFINE_OSPEED 21960786Spsextern short ospeed; /* Terminal output baud rate */ 22060786Spsextern char PC; /* Pad character */ 22160786Sps#endif 22260786Sps#ifdef _OSK 22360786Spsshort ospeed; 22460786Spschar PC_, *UP, *BC; 22560786Sps#endif 22660786Sps 22760786Spsextern int quiet; /* If VERY_QUIET, use visual bell for bell */ 22860786Spsextern int no_back_scroll; 22960786Spsextern int swindow; 23060786Spsextern int no_init; 23160812Spsextern int quit_at_eof; 232170259Sdelphijextern int less_is_more; 23389022Spsextern int no_keypad; 23460786Spsextern int sigs; 23560786Spsextern int wscroll; 23660786Spsextern int screen_trashed; 237128348Stjrextern int tty; 238161478Sdelphijextern int top_scroll; 239170259Sdelphijextern int oldbot; 24060786Sps#if HILITE_SEARCH 24160786Spsextern int hilite_search; 24260786Sps#endif 24360786Sps 24460786Spsextern char *tgetstr(); 24560786Spsextern char *tgoto(); 24660786Sps 24760786Sps 24860786Sps/* 24960786Sps * Change terminal to "raw mode", or restore to "normal" mode. 25060786Sps * "Raw mode" means 25160786Sps * 1. An outstanding read will complete on receipt of a single keystroke. 25260786Sps * 2. Input is not echoed. 25360786Sps * 3. On output, \n is mapped to \r\n. 25460786Sps * 4. \t is NOT expanded into spaces. 25560786Sps * 5. Signal-causing characters such as ctrl-C (interrupt), 25660786Sps * etc. are NOT disabled. 25760786Sps * It doesn't matter whether an input \n is mapped to \r, or vice versa. 25860786Sps */ 25960786Sps public void 26060786Spsraw_mode(on) 26160786Sps int on; 26260786Sps{ 26360786Sps static int curr_on = 0; 26460786Sps 26560786Sps if (on == curr_on) 26660786Sps return; 267161478Sdelphij erase2_char = '\b'; /* in case OS doesn't know about erase2 */ 26860786Sps#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 26960786Sps { 27060786Sps struct termios s; 27160786Sps static struct termios save_term; 27260786Sps static int saved_term = 0; 27360786Sps 27460786Sps if (on) 27560786Sps { 27660786Sps /* 27760786Sps * Get terminal modes. 27860786Sps */ 279128348Stjr tcgetattr(tty, &s); 28060786Sps 28160786Sps /* 28260786Sps * Save modes and set certain variables dependent on modes. 28360786Sps */ 28460786Sps if (!saved_term) 28560786Sps { 28660786Sps save_term = s; 28760786Sps saved_term = 1; 28860786Sps } 28960786Sps#if HAVE_OSPEED 29060786Sps switch (cfgetospeed(&s)) 29160786Sps { 29260786Sps#ifdef B0 29360786Sps case B0: ospeed = 0; break; 29460786Sps#endif 29560786Sps#ifdef B50 29660786Sps case B50: ospeed = 1; break; 29760786Sps#endif 29860786Sps#ifdef B75 29960786Sps case B75: ospeed = 2; break; 30060786Sps#endif 30160786Sps#ifdef B110 30260786Sps case B110: ospeed = 3; break; 30360786Sps#endif 30460786Sps#ifdef B134 30560786Sps case B134: ospeed = 4; break; 30660786Sps#endif 30760786Sps#ifdef B150 30860786Sps case B150: ospeed = 5; break; 30960786Sps#endif 31060786Sps#ifdef B200 31160786Sps case B200: ospeed = 6; break; 31260786Sps#endif 31360786Sps#ifdef B300 31460786Sps case B300: ospeed = 7; break; 31560786Sps#endif 31660786Sps#ifdef B600 31760786Sps case B600: ospeed = 8; break; 31860786Sps#endif 31960786Sps#ifdef B1200 32060786Sps case B1200: ospeed = 9; break; 32160786Sps#endif 32260786Sps#ifdef B1800 32360786Sps case B1800: ospeed = 10; break; 32460786Sps#endif 32560786Sps#ifdef B2400 32660786Sps case B2400: ospeed = 11; break; 32760786Sps#endif 32860786Sps#ifdef B4800 32960786Sps case B4800: ospeed = 12; break; 33060786Sps#endif 33160786Sps#ifdef B9600 33260786Sps case B9600: ospeed = 13; break; 33360786Sps#endif 33460786Sps#ifdef EXTA 33560786Sps case EXTA: ospeed = 14; break; 33660786Sps#endif 33760786Sps#ifdef EXTB 33860786Sps case EXTB: ospeed = 15; break; 33960786Sps#endif 34060786Sps#ifdef B57600 34160786Sps case B57600: ospeed = 16; break; 34260786Sps#endif 34360786Sps#ifdef B115200 34460786Sps case B115200: ospeed = 17; break; 34560786Sps#endif 34660786Sps default: ; 34760786Sps } 34860786Sps#endif 34960786Sps erase_char = s.c_cc[VERASE]; 350161478Sdelphij#ifdef VERASE2 351161478Sdelphij erase2_char = s.c_cc[VERASE2]; 352161478Sdelphij#endif 35360786Sps kill_char = s.c_cc[VKILL]; 35460786Sps#ifdef VWERASE 35560786Sps werase_char = s.c_cc[VWERASE]; 35660786Sps#else 35760786Sps werase_char = CONTROL('W'); 35860786Sps#endif 35960786Sps 36060786Sps /* 36160786Sps * Set the modes to the way we want them. 36260786Sps */ 36360786Sps s.c_lflag &= ~(0 36460786Sps#ifdef ICANON 36560786Sps | ICANON 36660786Sps#endif 36760786Sps#ifdef ECHO 36860786Sps | ECHO 36960786Sps#endif 37060786Sps#ifdef ECHOE 37160786Sps | ECHOE 37260786Sps#endif 37360786Sps#ifdef ECHOK 37460786Sps | ECHOK 37560786Sps#endif 37660786Sps#if ECHONL 37760786Sps | ECHONL 37860786Sps#endif 37960786Sps ); 38060786Sps 38160786Sps s.c_oflag |= (0 38260786Sps#ifdef OXTABS 38360786Sps | OXTABS 38460786Sps#else 38560786Sps#ifdef TAB3 38660786Sps | TAB3 38760786Sps#else 38860786Sps#ifdef XTABS 38960786Sps | XTABS 39060786Sps#endif 39160786Sps#endif 39260786Sps#endif 39360786Sps#ifdef OPOST 39460786Sps | OPOST 39560786Sps#endif 39660786Sps#ifdef ONLCR 39760786Sps | ONLCR 39860786Sps#endif 39960786Sps ); 40060786Sps 40160786Sps s.c_oflag &= ~(0 40260786Sps#ifdef ONOEOT 40360786Sps | ONOEOT 40460786Sps#endif 40560786Sps#ifdef OCRNL 40660786Sps | OCRNL 40760786Sps#endif 40860786Sps#ifdef ONOCR 40960786Sps | ONOCR 41060786Sps#endif 41160786Sps#ifdef ONLRET 41260786Sps | ONLRET 41360786Sps#endif 41460786Sps ); 41560786Sps s.c_cc[VMIN] = 1; 41660786Sps s.c_cc[VTIME] = 0; 41760786Sps#ifdef VLNEXT 41860786Sps s.c_cc[VLNEXT] = 0; 41960786Sps#endif 42060786Sps#ifdef VDSUSP 42160786Sps s.c_cc[VDSUSP] = 0; 42260786Sps#endif 42360786Sps#if MUST_SET_LINE_DISCIPLINE 42460786Sps /* 42560786Sps * System's termios is broken; need to explicitly 42660786Sps * request TERMIODISC line discipline. 42760786Sps */ 42860786Sps s.c_line = TERMIODISC; 42960786Sps#endif 43060786Sps } else 43160786Sps { 43260786Sps /* 43360786Sps * Restore saved modes. 43460786Sps */ 43560786Sps s = save_term; 43660786Sps } 43789022Sps#if HAVE_FSYNC 438128348Stjr fsync(tty); 43989022Sps#endif 440128348Stjr tcsetattr(tty, TCSADRAIN, &s); 44160786Sps#if MUST_SET_LINE_DISCIPLINE 44260786Sps if (!on) 44360786Sps { 44460786Sps /* 44560786Sps * Broken termios *ignores* any line discipline 44660786Sps * except TERMIODISC. A different old line discipline 44760786Sps * is therefore not restored, yet. Restore the old 44860786Sps * line discipline by hand. 44960786Sps */ 450128348Stjr ioctl(tty, TIOCSETD, &save_term.c_line); 45160786Sps } 45260786Sps#endif 45360786Sps } 45460786Sps#else 45560786Sps#ifdef TCGETA 45660786Sps { 45760786Sps struct termio s; 45860786Sps static struct termio save_term; 45960786Sps static int saved_term = 0; 46060786Sps 46160786Sps if (on) 46260786Sps { 46360786Sps /* 46460786Sps * Get terminal modes. 46560786Sps */ 466128348Stjr ioctl(tty, TCGETA, &s); 46760786Sps 46860786Sps /* 46960786Sps * Save modes and set certain variables dependent on modes. 47060786Sps */ 47160786Sps if (!saved_term) 47260786Sps { 47360786Sps save_term = s; 47460786Sps saved_term = 1; 47560786Sps } 47660786Sps#if HAVE_OSPEED 47760786Sps ospeed = s.c_cflag & CBAUD; 47860786Sps#endif 47960786Sps erase_char = s.c_cc[VERASE]; 48060786Sps kill_char = s.c_cc[VKILL]; 48160786Sps#ifdef VWERASE 48260786Sps werase_char = s.c_cc[VWERASE]; 48360786Sps#else 48460786Sps werase_char = CONTROL('W'); 48560786Sps#endif 48660786Sps 48760786Sps /* 48860786Sps * Set the modes to the way we want them. 48960786Sps */ 49060786Sps s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); 49160786Sps s.c_oflag |= (OPOST|ONLCR|TAB3); 49260786Sps s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); 49360786Sps s.c_cc[VMIN] = 1; 49460786Sps s.c_cc[VTIME] = 0; 49560786Sps } else 49660786Sps { 49760786Sps /* 49860786Sps * Restore saved modes. 49960786Sps */ 50060786Sps s = save_term; 50160786Sps } 502128348Stjr ioctl(tty, TCSETAW, &s); 50360786Sps } 50460786Sps#else 50560786Sps#ifdef TIOCGETP 50660786Sps { 50760786Sps struct sgttyb s; 50860786Sps static struct sgttyb save_term; 50960786Sps static int saved_term = 0; 51060786Sps 51160786Sps if (on) 51260786Sps { 51360786Sps /* 51460786Sps * Get terminal modes. 51560786Sps */ 516128348Stjr ioctl(tty, TIOCGETP, &s); 51760786Sps 51860786Sps /* 51960786Sps * Save modes and set certain variables dependent on modes. 52060786Sps */ 52160786Sps if (!saved_term) 52260786Sps { 52360786Sps save_term = s; 52460786Sps saved_term = 1; 52560786Sps } 52660786Sps#if HAVE_OSPEED 52760786Sps ospeed = s.sg_ospeed; 52860786Sps#endif 52960786Sps erase_char = s.sg_erase; 53060786Sps kill_char = s.sg_kill; 53160786Sps werase_char = CONTROL('W'); 53260786Sps 53360786Sps /* 53460786Sps * Set the modes to the way we want them. 53560786Sps */ 53660786Sps s.sg_flags |= CBREAK; 53760786Sps s.sg_flags &= ~(ECHO|XTABS); 53860786Sps } else 53960786Sps { 54060786Sps /* 54160786Sps * Restore saved modes. 54260786Sps */ 54360786Sps s = save_term; 54460786Sps } 545128348Stjr ioctl(tty, TIOCSETN, &s); 54660786Sps } 54760786Sps#else 54860786Sps#ifdef _OSK 54960786Sps { 55060786Sps struct sgbuf s; 55160786Sps static struct sgbuf save_term; 55260786Sps static int saved_term = 0; 55360786Sps 55460786Sps if (on) 55560786Sps { 55660786Sps /* 55760786Sps * Get terminal modes. 55860786Sps */ 559128348Stjr _gs_opt(tty, &s); 56060786Sps 56160786Sps /* 56260786Sps * Save modes and set certain variables dependent on modes. 56360786Sps */ 56460786Sps if (!saved_term) 56560786Sps { 56660786Sps save_term = s; 56760786Sps saved_term = 1; 56860786Sps } 56960786Sps erase_char = s.sg_bspch; 57060786Sps kill_char = s.sg_dlnch; 57160786Sps werase_char = CONTROL('W'); 57260786Sps 57360786Sps /* 57460786Sps * Set the modes to the way we want them. 57560786Sps */ 57660786Sps s.sg_echo = 0; 57760786Sps s.sg_eofch = 0; 57860786Sps s.sg_pause = 0; 57960786Sps s.sg_psch = 0; 58060786Sps } else 58160786Sps { 58260786Sps /* 58360786Sps * Restore saved modes. 58460786Sps */ 58560786Sps s = save_term; 58660786Sps } 587128348Stjr _ss_opt(tty, &s); 58860786Sps } 58960786Sps#else 59060786Sps /* MS-DOS, Windows, or OS2 */ 59160786Sps#if OS2 59260786Sps /* OS2 */ 59360786Sps LSIGNAL(SIGINT, SIG_IGN); 59460786Sps#endif 59560786Sps erase_char = '\b'; 59660786Sps#if MSDOS_COMPILER==DJGPPC 59760786Sps kill_char = CONTROL('U'); 59860786Sps /* 59960786Sps * So that when we shell out or run another program, its 60060786Sps * stdin is in cooked mode. We do not switch stdin to binary 60160786Sps * mode if fd0 is zero, since that means we were called before 60260786Sps * tty was reopened in open_getchr, in which case we would be 60360786Sps * changing the original stdin device outside less. 60460786Sps */ 60560786Sps if (fd0 != 0) 60660786Sps setmode(0, on ? O_BINARY : O_TEXT); 60760786Sps#else 60860786Sps kill_char = ESC; 60960786Sps#endif 61060786Sps werase_char = CONTROL('W'); 61160786Sps#endif 61260786Sps#endif 61360786Sps#endif 61460786Sps#endif 61560786Sps curr_on = on; 61660786Sps} 61760786Sps 61860786Sps#if !MSDOS_COMPILER 61960786Sps/* 62060786Sps * Some glue to prevent calling termcap functions if tgetent() failed. 62160786Sps */ 62260786Spsstatic int hardcopy; 62360786Sps 62460786Sps static char * 62560786Spsltget_env(capname) 62660786Sps char *capname; 62760786Sps{ 62860786Sps char name[16]; 629170967Sdelphij char *s; 63060786Sps 631170967Sdelphij s = lgetenv("LESS_TERMCAP_DEBUG"); 632170967Sdelphij if (s != NULL && *s != '\0') 633170967Sdelphij { 634170967Sdelphij struct env { struct env *next; char *name; char *value; }; 635170967Sdelphij static struct env *envs = NULL; 636170967Sdelphij struct env *p; 637170967Sdelphij for (p = envs; p != NULL; p = p->next) 638170967Sdelphij if (strcmp(p->name, capname) == 0) 639170967Sdelphij return p->value; 640170967Sdelphij p = (struct env *) ecalloc(1, sizeof(struct env)); 641170967Sdelphij p->name = save(capname); 642170967Sdelphij p->value = (char *) ecalloc(strlen(capname)+3, sizeof(char)); 643170967Sdelphij sprintf(p->value, "<%s>", capname); 644170967Sdelphij p->next = envs; 645170967Sdelphij envs = p; 646170967Sdelphij return p->value; 647170967Sdelphij } 64860786Sps strcpy(name, "LESS_TERMCAP_"); 64960786Sps strcat(name, capname); 65060786Sps return (lgetenv(name)); 65160786Sps} 65260786Sps 65360786Sps static int 65460786Spsltgetflag(capname) 65560786Sps char *capname; 65660786Sps{ 65760786Sps char *s; 65860786Sps 65960786Sps if ((s = ltget_env(capname)) != NULL) 66060786Sps return (*s != '\0' && *s != '0'); 66160786Sps if (hardcopy) 66260786Sps return (0); 66360786Sps return (tgetflag(capname)); 66460786Sps} 66560786Sps 66660786Sps static int 66760786Spsltgetnum(capname) 66860786Sps char *capname; 66960786Sps{ 67060786Sps char *s; 67160786Sps 67260786Sps if ((s = ltget_env(capname)) != NULL) 67360786Sps return (atoi(s)); 67460786Sps if (hardcopy) 67560786Sps return (-1); 67660786Sps return (tgetnum(capname)); 67760786Sps} 67860786Sps 67960786Sps static char * 68060786Spsltgetstr(capname, pp) 68160786Sps char *capname; 68260786Sps char **pp; 68360786Sps{ 68460786Sps char *s; 68560786Sps 68660786Sps if ((s = ltget_env(capname)) != NULL) 68760786Sps return (s); 68860786Sps if (hardcopy) 68960786Sps return (NULL); 69060786Sps return (tgetstr(capname, pp)); 69160786Sps} 69260786Sps#endif /* MSDOS_COMPILER */ 69360786Sps 69460786Sps/* 69560786Sps * Get size of the output screen. 69660786Sps */ 69760786Sps public void 69860786Spsscrsize() 69960786Sps{ 70060786Sps register char *s; 70160786Sps int sys_height; 70260786Sps int sys_width; 70360786Sps#if !MSDOS_COMPILER 70460786Sps int n; 70560786Sps#endif 70660786Sps 70760786Sps#define DEF_SC_WIDTH 80 70860786Sps#if MSDOS_COMPILER 70960786Sps#define DEF_SC_HEIGHT 25 71060786Sps#else 71160786Sps#define DEF_SC_HEIGHT 24 71260786Sps#endif 71360786Sps 71460786Sps 71560786Sps sys_width = sys_height = 0; 71660786Sps 71760786Sps#if MSDOS_COMPILER==MSOFTC 71860786Sps { 71960786Sps struct videoconfig w; 72060786Sps _getvideoconfig(&w); 72160786Sps sys_height = w.numtextrows; 72260786Sps sys_width = w.numtextcols; 72360786Sps } 72460786Sps#else 72560786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 72660786Sps { 72760786Sps struct text_info w; 72860786Sps gettextinfo(&w); 72960786Sps sys_height = w.screenheight; 73060786Sps sys_width = w.screenwidth; 73160786Sps } 73260786Sps#else 73360786Sps#if MSDOS_COMPILER==WIN32C 73460786Sps { 73560786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 73660786Sps GetConsoleScreenBufferInfo(con_out, &scr); 73760786Sps sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1; 73860786Sps sys_width = scr.srWindow.Right - scr.srWindow.Left + 1; 73960786Sps } 74060786Sps#else 74160786Sps#if OS2 74260786Sps { 74360786Sps int s[2]; 74460786Sps _scrsize(s); 74560786Sps sys_width = s[0]; 74660786Sps sys_height = s[1]; 74789022Sps /* 74889022Sps * When using terminal emulators for XFree86/OS2, the 74989022Sps * _scrsize function does not work well. 75089022Sps * Call the scrsize.exe program to get the window size. 75189022Sps */ 75289022Sps windowid = getenv("WINDOWID"); 75389022Sps if (windowid != NULL) 75489022Sps { 75589022Sps FILE *fd = popen("scrsize", "rt"); 75689022Sps if (fd != NULL) 75789022Sps { 75889022Sps int w, h; 75989022Sps fscanf(fd, "%i %i", &w, &h); 76089022Sps if (w > 0 && h > 0) 76189022Sps { 76289022Sps sys_width = w; 76389022Sps sys_height = h; 76489022Sps } 76589022Sps pclose(fd); 76689022Sps } 76789022Sps } 76860786Sps } 76960786Sps#else 77060786Sps#ifdef TIOCGWINSZ 77160786Sps { 77260786Sps struct winsize w; 77360786Sps if (ioctl(2, TIOCGWINSZ, &w) == 0) 77460786Sps { 77560786Sps if (w.ws_row > 0) 77660786Sps sys_height = w.ws_row; 77760786Sps if (w.ws_col > 0) 77860786Sps sys_width = w.ws_col; 77960786Sps } 78060786Sps } 78160786Sps#else 78260786Sps#ifdef WIOCGETD 78360786Sps { 78460786Sps struct uwdata w; 78560786Sps if (ioctl(2, WIOCGETD, &w) == 0) 78660786Sps { 78760786Sps if (w.uw_height > 0) 78860786Sps sys_height = w.uw_height / w.uw_vs; 78960786Sps if (w.uw_width > 0) 79060786Sps sys_width = w.uw_width / w.uw_hs; 79160786Sps } 79260786Sps } 79360786Sps#endif 79460786Sps#endif 79560786Sps#endif 79660786Sps#endif 79760786Sps#endif 79860786Sps#endif 79960786Sps 80060786Sps if (sys_height > 0) 80160786Sps sc_height = sys_height; 80260786Sps else if ((s = lgetenv("LINES")) != NULL) 80360786Sps sc_height = atoi(s); 80460786Sps#if !MSDOS_COMPILER 80560786Sps else if ((n = ltgetnum("li")) > 0) 80660786Sps sc_height = n; 80760786Sps#endif 80860786Sps else 80960786Sps sc_height = DEF_SC_HEIGHT; 81060786Sps 81160786Sps if (sys_width > 0) 81260786Sps sc_width = sys_width; 81360786Sps else if ((s = lgetenv("COLUMNS")) != NULL) 81460786Sps sc_width = atoi(s); 81560786Sps#if !MSDOS_COMPILER 81660786Sps else if ((n = ltgetnum("co")) > 0) 81760786Sps sc_width = n; 81860786Sps#endif 81960786Sps else 82060786Sps sc_width = DEF_SC_WIDTH; 82160786Sps} 82260786Sps 82360786Sps#if MSDOS_COMPILER==MSOFTC 82460786Sps/* 82560786Sps * Figure out how many empty loops it takes to delay a millisecond. 82660786Sps */ 82760786Sps static void 82860786Spsget_clock() 82960786Sps{ 83060786Sps clock_t start; 83160786Sps 83260786Sps /* 83360786Sps * Get synchronized at the start of a tick. 83460786Sps */ 83560786Sps start = clock(); 83660786Sps while (clock() == start) 83760786Sps ; 83860786Sps /* 83960786Sps * Now count loops till the next tick. 84060786Sps */ 84160786Sps start = clock(); 84260786Sps msec_loops = 0; 84360786Sps while (clock() == start) 84460786Sps msec_loops++; 84560786Sps /* 84660786Sps * Convert from (loops per clock) to (loops per millisecond). 84760786Sps */ 84860786Sps msec_loops *= CLOCKS_PER_SEC; 84960786Sps msec_loops /= 1000; 85060786Sps} 85160786Sps 85260786Sps/* 85360786Sps * Delay for a specified number of milliseconds. 85460786Sps */ 85560786Sps static void 85660786Spsdummy_func() 85760786Sps{ 85860786Sps static long delay_dummy = 0; 85960786Sps delay_dummy++; 86060786Sps} 86160786Sps 86260786Sps static void 86360786Spsdelay(msec) 86460786Sps int msec; 86560786Sps{ 86660786Sps long i; 86760786Sps 86860786Sps while (msec-- > 0) 86960786Sps { 87060786Sps for (i = 0; i < msec_loops; i++) 87160786Sps { 87260786Sps /* 87360786Sps * Make it look like we're doing something here, 87460786Sps * so the optimizer doesn't remove the whole loop. 87560786Sps */ 87660786Sps dummy_func(); 87760786Sps } 87860786Sps } 87960786Sps} 88060786Sps#endif 88160786Sps 88260786Sps/* 88360786Sps * Return the characters actually input by a "special" key. 88460786Sps */ 88560786Sps public char * 88660786Spsspecial_key_str(key) 88760786Sps int key; 88860786Sps{ 88960786Sps static char tbuf[40]; 89060786Sps char *s; 89189022Sps#if MSDOS_COMPILER || OS2 89260786Sps static char k_right[] = { '\340', PCK_RIGHT, 0 }; 89360786Sps static char k_left[] = { '\340', PCK_LEFT, 0 }; 89460786Sps static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; 89560786Sps static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; 89660786Sps static char k_insert[] = { '\340', PCK_INSERT, 0 }; 89760786Sps static char k_delete[] = { '\340', PCK_DELETE, 0 }; 89860786Sps static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; 89960786Sps static char k_ctl_backspace[] = { '\177', 0 }; 90060786Sps static char k_home[] = { '\340', PCK_HOME, 0 }; 90160786Sps static char k_end[] = { '\340', PCK_END, 0 }; 90260786Sps static char k_up[] = { '\340', PCK_UP, 0 }; 90360786Sps static char k_down[] = { '\340', PCK_DOWN, 0 }; 90460786Sps static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; 90560786Sps static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; 90660786Sps static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; 90760786Sps static char k_f1[] = { '\340', PCK_F1, 0 }; 90889022Sps#endif 90989022Sps#if !MSDOS_COMPILER 91060786Sps char *sp = tbuf; 91160786Sps#endif 91260786Sps 91360786Sps switch (key) 91460786Sps { 91589022Sps#if OS2 91689022Sps /* 91789022Sps * If windowid is not NULL, assume less is executed in 91889022Sps * the XFree86 environment. 91989022Sps */ 92089022Sps case SK_RIGHT_ARROW: 92189022Sps s = windowid ? ltgetstr("kr", &sp) : k_right; 92289022Sps break; 92389022Sps case SK_LEFT_ARROW: 92489022Sps s = windowid ? ltgetstr("kl", &sp) : k_left; 92589022Sps break; 92689022Sps case SK_UP_ARROW: 92789022Sps s = windowid ? ltgetstr("ku", &sp) : k_up; 92889022Sps break; 92989022Sps case SK_DOWN_ARROW: 93089022Sps s = windowid ? ltgetstr("kd", &sp) : k_down; 93189022Sps break; 93289022Sps case SK_PAGE_UP: 93389022Sps s = windowid ? ltgetstr("kP", &sp) : k_pageup; 93489022Sps break; 93589022Sps case SK_PAGE_DOWN: 93689022Sps s = windowid ? ltgetstr("kN", &sp) : k_pagedown; 93789022Sps break; 93889022Sps case SK_HOME: 93989022Sps s = windowid ? ltgetstr("kh", &sp) : k_home; 94089022Sps break; 94189022Sps case SK_END: 94289022Sps s = windowid ? ltgetstr("@7", &sp) : k_end; 94389022Sps break; 94489022Sps case SK_DELETE: 94589022Sps if (windowid) 94689022Sps { 94789022Sps s = ltgetstr("kD", &sp); 94889022Sps if (s == NULL) 94989022Sps { 95089022Sps tbuf[0] = '\177'; 95189022Sps tbuf[1] = '\0'; 95289022Sps s = tbuf; 95389022Sps } 95489022Sps } else 95589022Sps s = k_delete; 95689022Sps break; 95789022Sps#endif 95860786Sps#if MSDOS_COMPILER 95960786Sps case SK_RIGHT_ARROW: 96060786Sps s = k_right; 96160786Sps break; 96260786Sps case SK_LEFT_ARROW: 96360786Sps s = k_left; 96460786Sps break; 96560786Sps case SK_UP_ARROW: 96660786Sps s = k_up; 96760786Sps break; 96860786Sps case SK_DOWN_ARROW: 96960786Sps s = k_down; 97060786Sps break; 97160786Sps case SK_PAGE_UP: 97260786Sps s = k_pageup; 97360786Sps break; 97460786Sps case SK_PAGE_DOWN: 97560786Sps s = k_pagedown; 97660786Sps break; 97760786Sps case SK_HOME: 97860786Sps s = k_home; 97960786Sps break; 98060786Sps case SK_END: 98160786Sps s = k_end; 98260786Sps break; 98360786Sps case SK_DELETE: 98460786Sps s = k_delete; 98560786Sps break; 98689022Sps#endif 98789022Sps#if MSDOS_COMPILER || OS2 98860786Sps case SK_INSERT: 98960786Sps s = k_insert; 99060786Sps break; 99160786Sps case SK_CTL_LEFT_ARROW: 99260786Sps s = k_ctl_left; 99360786Sps break; 99460786Sps case SK_CTL_RIGHT_ARROW: 99560786Sps s = k_ctl_right; 99660786Sps break; 99760786Sps case SK_CTL_BACKSPACE: 99860786Sps s = k_ctl_backspace; 99960786Sps break; 100060786Sps case SK_CTL_DELETE: 100160786Sps s = k_ctl_delete; 100260786Sps break; 100360786Sps case SK_F1: 100460786Sps s = k_f1; 100560786Sps break; 100660786Sps case SK_BACKTAB: 100760786Sps s = k_backtab; 100860786Sps break; 100960786Sps#else 101060786Sps case SK_RIGHT_ARROW: 101160786Sps s = ltgetstr("kr", &sp); 101260786Sps break; 101360786Sps case SK_LEFT_ARROW: 101460786Sps s = ltgetstr("kl", &sp); 101560786Sps break; 101660786Sps case SK_UP_ARROW: 101760786Sps s = ltgetstr("ku", &sp); 101860786Sps break; 101960786Sps case SK_DOWN_ARROW: 102060786Sps s = ltgetstr("kd", &sp); 102160786Sps break; 102260786Sps case SK_PAGE_UP: 102360786Sps s = ltgetstr("kP", &sp); 102460786Sps break; 102560786Sps case SK_PAGE_DOWN: 102660786Sps s = ltgetstr("kN", &sp); 102760786Sps break; 102860786Sps case SK_HOME: 102960786Sps s = ltgetstr("kh", &sp); 103060786Sps break; 103160786Sps case SK_END: 103260786Sps s = ltgetstr("@7", &sp); 103360786Sps break; 103460786Sps case SK_DELETE: 103560786Sps s = ltgetstr("kD", &sp); 103660786Sps if (s == NULL) 103760786Sps { 103860786Sps tbuf[0] = '\177'; 103960786Sps tbuf[1] = '\0'; 104060786Sps s = tbuf; 104160786Sps } 104260786Sps break; 104360786Sps#endif 104460786Sps case SK_CONTROL_K: 104560786Sps tbuf[0] = CONTROL('K'); 104660786Sps tbuf[1] = '\0'; 104760786Sps s = tbuf; 104860786Sps break; 104960786Sps default: 105060786Sps return (NULL); 105160786Sps } 105260786Sps return (s); 105360786Sps} 105460786Sps 105560786Sps/* 105660786Sps * Get terminal capabilities via termcap. 105760786Sps */ 105860786Sps public void 105960786Spsget_term() 106060786Sps{ 106160786Sps#if MSDOS_COMPILER 106260786Sps auto_wrap = 1; 106360786Sps ignaw = 0; 106460786Sps can_goto_line = 1; 106560786Sps clear_bg = 1; 106660786Sps /* 106760786Sps * Set up default colors. 106860786Sps * The xx_s_width and xx_e_width vars are already initialized to 0. 106960786Sps */ 107060786Sps#if MSDOS_COMPILER==MSOFTC 107160786Sps sy_bg_color = _getbkcolor(); 107260786Sps sy_fg_color = _gettextcolor(); 107360786Sps get_clock(); 107460786Sps#else 107560786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 107660786Sps { 107760786Sps struct text_info w; 107860786Sps gettextinfo(&w); 107960786Sps sy_bg_color = (w.attribute >> 4) & 0x0F; 108060786Sps sy_fg_color = (w.attribute >> 0) & 0x0F; 108160786Sps } 108260786Sps#else 108360786Sps#if MSDOS_COMPILER==WIN32C 108460786Sps { 108560786Sps DWORD nread; 108660786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 108760786Sps 108860786Sps con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE); 108960786Sps /* 109060786Sps * Always open stdin in binary. Note this *must* be done 109160786Sps * before any file operations have been done on fd0. 109260786Sps */ 109360786Sps SET_BINARY(0); 109460786Sps GetConsoleScreenBufferInfo(con_out, &scr); 109560786Sps ReadConsoleOutputAttribute(con_out, &curr_attr, 109660786Sps 1, scr.dwCursorPosition, &nread); 109760786Sps sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */ 109860786Sps sy_fg_color = curr_attr & FG_COLORS; 109960786Sps } 110060786Sps#endif 110160786Sps#endif 110260786Sps#endif 110360786Sps nm_fg_color = sy_fg_color; 110460786Sps nm_bg_color = sy_bg_color; 110560786Sps bo_fg_color = 11; 110660786Sps bo_bg_color = 0; 110760786Sps ul_fg_color = 9; 110860786Sps ul_bg_color = 0; 110960786Sps so_fg_color = 15; 111060786Sps so_bg_color = 9; 111160786Sps bl_fg_color = 15; 111260786Sps bl_bg_color = 0; 111360786Sps 111460786Sps /* 111560786Sps * Get size of the screen. 111660786Sps */ 111760786Sps scrsize(); 111860786Sps pos_init(); 111960786Sps 112060786Sps 112160786Sps#else /* !MSDOS_COMPILER */ 112260786Sps 112360786Sps char *sp; 112460786Sps register char *t1, *t2; 112560786Sps char *term; 112660786Sps char termbuf[TERMBUF_SIZE]; 112760786Sps 112860786Sps static char sbuf[TERMSBUF_SIZE]; 112960786Sps 113060786Sps#if OS2 113160786Sps /* 113260786Sps * Make sure the termcap database is available. 113360786Sps */ 113460786Sps sp = lgetenv("TERMCAP"); 113560786Sps if (sp == NULL || *sp == '\0') 113660786Sps { 113760786Sps char *termcap; 113860786Sps if ((sp = homefile("termcap.dat")) != NULL) 113960786Sps { 114060786Sps termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char)); 114160786Sps sprintf(termcap, "TERMCAP=%s", sp); 114260786Sps free(sp); 114360786Sps putenv(termcap); 114460786Sps } 114560786Sps } 114660786Sps#endif 114760786Sps /* 114860786Sps * Find out what kind of terminal this is. 114960786Sps */ 115060786Sps if ((term = lgetenv("TERM")) == NULL) 115160786Sps term = DEFAULT_TERM; 115260786Sps hardcopy = 0; 1153170259Sdelphij if (tgetent(termbuf, term) != TGETENT_OK) 115460786Sps hardcopy = 1; 115560786Sps if (ltgetflag("hc")) 115660786Sps hardcopy = 1; 115760786Sps 115860786Sps /* 115960786Sps * Get size of the screen. 116060786Sps */ 116160786Sps scrsize(); 116260786Sps pos_init(); 116360786Sps 116460786Sps auto_wrap = ltgetflag("am"); 116560786Sps ignaw = ltgetflag("xn"); 116660786Sps above_mem = ltgetflag("da"); 116760786Sps below_mem = ltgetflag("db"); 116860786Sps clear_bg = ltgetflag("ut"); 116960786Sps 117060786Sps /* 117160786Sps * Assumes termcap variable "sg" is the printing width of: 117260786Sps * the standout sequence, the end standout sequence, 117360786Sps * the underline sequence, the end underline sequence, 117460786Sps * the boldface sequence, and the end boldface sequence. 117560786Sps */ 117660786Sps if ((so_s_width = ltgetnum("sg")) < 0) 117760786Sps so_s_width = 0; 117860786Sps so_e_width = so_s_width; 117960786Sps 118060786Sps bo_s_width = bo_e_width = so_s_width; 118160786Sps ul_s_width = ul_e_width = so_s_width; 118260786Sps bl_s_width = bl_e_width = so_s_width; 118360786Sps 118460786Sps#if HILITE_SEARCH 118560786Sps if (so_s_width > 0 || so_e_width > 0) 118660786Sps /* 118760786Sps * Disable highlighting by default on magic cookie terminals. 118860786Sps * Turning on highlighting might change the displayed width 118960786Sps * of a line, causing the display to get messed up. 119060786Sps * The user can turn it back on with -g, 119160786Sps * but she won't like the results. 119260786Sps */ 119360786Sps hilite_search = 0; 119460786Sps#endif 119560786Sps 119660786Sps /* 119760786Sps * Get various string-valued capabilities. 119860786Sps */ 119960786Sps sp = sbuf; 120060786Sps 120160786Sps#if HAVE_OSPEED 120260786Sps sc_pad = ltgetstr("pc", &sp); 120360786Sps if (sc_pad != NULL) 120460786Sps PC = *sc_pad; 120560786Sps#endif 120660786Sps 120760786Sps sc_s_keypad = ltgetstr("ks", &sp); 120860786Sps if (sc_s_keypad == NULL) 120960786Sps sc_s_keypad = ""; 121060786Sps sc_e_keypad = ltgetstr("ke", &sp); 121160786Sps if (sc_e_keypad == NULL) 121260786Sps sc_e_keypad = ""; 121360786Sps 121460812Sps /* 121560812Sps * This loses for terminals with termcap entries with ti/te strings 121660812Sps * that switch to/from an alternate screen, and we're in quit_at_eof 121760812Sps * (eg, more(1)). 121860812Sps */ 1219170259Sdelphij if (!quit_at_eof && !less_is_more) { 122060812Sps sc_init = ltgetstr("ti", &sp); 122160812Sps sc_deinit = ltgetstr("te", &sp); 122260812Sps } 122360812Sps 122460786Sps if (sc_init == NULL) 122560786Sps sc_init = ""; 122660786Sps 122760786Sps if (sc_deinit == NULL) 122860786Sps sc_deinit = ""; 122960786Sps 123060786Sps sc_eol_clear = ltgetstr("ce", &sp); 123160786Sps if (sc_eol_clear == NULL || *sc_eol_clear == '\0') 123260786Sps { 123360786Sps missing_cap = 1; 123460786Sps sc_eol_clear = ""; 123560786Sps } 123660786Sps 123760786Sps sc_eos_clear = ltgetstr("cd", &sp); 123860786Sps if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0')) 123960786Sps { 124060786Sps missing_cap = 1; 1241161478Sdelphij sc_eos_clear = ""; 124260786Sps } 124360786Sps 124460786Sps sc_clear = ltgetstr("cl", &sp); 124560786Sps if (sc_clear == NULL || *sc_clear == '\0') 124660786Sps { 124760786Sps missing_cap = 1; 124860786Sps sc_clear = "\n\n"; 124960786Sps } 125060786Sps 125160786Sps sc_move = ltgetstr("cm", &sp); 125260786Sps if (sc_move == NULL || *sc_move == '\0') 125360786Sps { 125460786Sps /* 125560786Sps * This is not an error here, because we don't 125660786Sps * always need sc_move. 125760786Sps * We need it only if we don't have home or lower-left. 125860786Sps */ 125960786Sps sc_move = ""; 126060786Sps can_goto_line = 0; 126160786Sps } else 126260786Sps can_goto_line = 1; 126360786Sps 126460786Sps tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp); 126560786Sps tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp); 126660786Sps tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp); 126760786Sps tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp); 126860786Sps 126960786Sps sc_visual_bell = ltgetstr("vb", &sp); 127060786Sps if (sc_visual_bell == NULL) 127160786Sps sc_visual_bell = ""; 127260786Sps 127360786Sps if (ltgetflag("bs")) 127460786Sps sc_backspace = "\b"; 127560786Sps else 127660786Sps { 127760786Sps sc_backspace = ltgetstr("bc", &sp); 127860786Sps if (sc_backspace == NULL || *sc_backspace == '\0') 127960786Sps sc_backspace = "\b"; 128060786Sps } 128160786Sps 128260786Sps /* 128360786Sps * Choose between using "ho" and "cm" ("home" and "cursor move") 128460786Sps * to move the cursor to the upper left corner of the screen. 128560786Sps */ 128660786Sps t1 = ltgetstr("ho", &sp); 128760786Sps if (t1 == NULL) 128860786Sps t1 = ""; 128960786Sps if (*sc_move == '\0') 129060786Sps t2 = ""; 129160786Sps else 129260786Sps { 129360786Sps strcpy(sp, tgoto(sc_move, 0, 0)); 129460786Sps t2 = sp; 129560786Sps sp += strlen(sp) + 1; 129660786Sps } 129760786Sps sc_home = cheaper(t1, t2, "|\b^"); 129860786Sps 129960786Sps /* 130060786Sps * Choose between using "ll" and "cm" ("lower left" and "cursor move") 130160786Sps * to move the cursor to the lower left corner of the screen. 130260786Sps */ 130360786Sps t1 = ltgetstr("ll", &sp); 130460786Sps if (t1 == NULL) 130560786Sps t1 = ""; 130660786Sps if (*sc_move == '\0') 130760786Sps t2 = ""; 130860786Sps else 130960786Sps { 131060786Sps strcpy(sp, tgoto(sc_move, 0, sc_height-1)); 131160786Sps t2 = sp; 131260786Sps sp += strlen(sp) + 1; 131360786Sps } 131460786Sps sc_lower_left = cheaper(t1, t2, "\r"); 131560786Sps 131660786Sps /* 1317170259Sdelphij * Get carriage return string. 1318170259Sdelphij */ 1319170259Sdelphij sc_return = ltgetstr("cr", &sp); 1320170259Sdelphij if (sc_return == NULL) 1321170259Sdelphij sc_return = "\r"; 1322170259Sdelphij 1323170259Sdelphij /* 132460786Sps * Choose between using "al" or "sr" ("add line" or "scroll reverse") 132560786Sps * to add a line at the top of the screen. 132660786Sps */ 132760786Sps t1 = ltgetstr("al", &sp); 132860786Sps if (t1 == NULL) 132960786Sps t1 = ""; 133060786Sps t2 = ltgetstr("sr", &sp); 133160786Sps if (t2 == NULL) 133260786Sps t2 = ""; 133360786Sps#if OS2 133460786Sps if (*t1 == '\0' && *t2 == '\0') 133560786Sps sc_addline = ""; 133660786Sps else 133760786Sps#endif 133860786Sps if (above_mem) 133960786Sps sc_addline = t1; 134060786Sps else 134160786Sps sc_addline = cheaper(t1, t2, ""); 134260786Sps if (*sc_addline == '\0') 134360786Sps { 134460786Sps /* 134560786Sps * Force repaint on any backward movement. 134660786Sps */ 134760786Sps no_back_scroll = 1; 134860786Sps } 134960786Sps#endif /* MSDOS_COMPILER */ 135060786Sps} 135160786Sps 135260786Sps#if !MSDOS_COMPILER 135360786Sps/* 135460786Sps * Return the cost of displaying a termcap string. 135560786Sps * We use the trick of calling tputs, but as a char printing function 135660786Sps * we give it inc_costcount, which just increments "costcount". 135760786Sps * This tells us how many chars would be printed by using this string. 135860786Sps * {{ Couldn't we just use strlen? }} 135960786Sps */ 136060786Spsstatic int costcount; 136160786Sps 136260786Sps/*ARGSUSED*/ 136360786Sps static int 136460786Spsinc_costcount(c) 136560786Sps int c; 136660786Sps{ 136760786Sps costcount++; 136860786Sps return (c); 136960786Sps} 137060786Sps 137160786Sps static int 137260786Spscost(t) 137360786Sps char *t; 137460786Sps{ 137560786Sps costcount = 0; 137660786Sps tputs(t, sc_height, inc_costcount); 137760786Sps return (costcount); 137860786Sps} 137960786Sps 138060786Sps/* 138160786Sps * Return the "best" of the two given termcap strings. 138260786Sps * The best, if both exist, is the one with the lower 138360786Sps * cost (see cost() function). 138460786Sps */ 138560786Sps static char * 138660786Spscheaper(t1, t2, def) 138760786Sps char *t1, *t2; 138860786Sps char *def; 138960786Sps{ 139060786Sps if (*t1 == '\0' && *t2 == '\0') 139160786Sps { 139260786Sps missing_cap = 1; 139360786Sps return (def); 139460786Sps } 139560786Sps if (*t1 == '\0') 139660786Sps return (t2); 139760786Sps if (*t2 == '\0') 139860786Sps return (t1); 139960786Sps if (cost(t1) < cost(t2)) 140060786Sps return (t1); 140160786Sps return (t2); 140260786Sps} 140360786Sps 140460786Sps static void 140560786Spstmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp) 140660786Sps char *incap; 140760786Sps char *outcap; 140860786Sps char **instr; 140960786Sps char **outstr; 141060786Sps char *def_instr; 141160786Sps char *def_outstr; 141260786Sps char **spp; 141360786Sps{ 141460786Sps *instr = ltgetstr(incap, spp); 141560786Sps if (*instr == NULL) 141660786Sps { 141760786Sps /* Use defaults. */ 141860786Sps *instr = def_instr; 141960786Sps *outstr = def_outstr; 142060786Sps return; 142160786Sps } 142260786Sps 142360786Sps *outstr = ltgetstr(outcap, spp); 142460786Sps if (*outstr == NULL) 142560786Sps /* No specific out capability; use "me". */ 142660786Sps *outstr = ltgetstr("me", spp); 142760786Sps if (*outstr == NULL) 142860786Sps /* Don't even have "me"; use a null string. */ 142960786Sps *outstr = ""; 143060786Sps} 143160786Sps 143260786Sps#endif /* MSDOS_COMPILER */ 143360786Sps 143460786Sps 143560786Sps/* 143660786Sps * Below are the functions which perform all the 143760786Sps * terminal-specific screen manipulation. 143860786Sps */ 143960786Sps 144060786Sps 144160786Sps#if MSDOS_COMPILER 144260786Sps 144360786Sps#if MSDOS_COMPILER==WIN32C 144460786Sps static void 144560786Sps_settextposition(int row, int col) 144660786Sps{ 144760786Sps COORD cpos; 144860786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 144960786Sps 145060786Sps GetConsoleScreenBufferInfo(con_out, &csbi); 145160786Sps cpos.X = csbi.srWindow.Left + (col - 1); 145260786Sps cpos.Y = csbi.srWindow.Top + (row - 1); 145360786Sps SetConsoleCursorPosition(con_out, cpos); 145460786Sps} 145560786Sps#endif 145660786Sps 145760786Sps/* 145860786Sps * Initialize the screen to the correct color at startup. 145960786Sps */ 146060786Sps static void 146160786Spsinitcolor() 146260786Sps{ 146360786Sps SETCOLORS(nm_fg_color, nm_bg_color); 146460786Sps#if 0 146560786Sps /* 146660786Sps * This clears the screen at startup. This is different from 146760786Sps * the behavior of other versions of less. Disable it for now. 146860786Sps */ 146960786Sps char *blanks; 147060786Sps int row; 147160786Sps int col; 147260786Sps 147360786Sps /* 147460786Sps * Create a complete, blank screen using "normal" colors. 147560786Sps */ 147660786Sps SETCOLORS(nm_fg_color, nm_bg_color); 147760786Sps blanks = (char *) ecalloc(width+1, sizeof(char)); 147860786Sps for (col = 0; col < sc_width; col++) 147960786Sps blanks[col] = ' '; 148060786Sps blanks[sc_width] = '\0'; 148160786Sps for (row = 0; row < sc_height; row++) 148260786Sps _outtext(blanks); 148360786Sps free(blanks); 148460786Sps#endif 148560786Sps} 148660786Sps#endif 148760786Sps 148860786Sps#if MSDOS_COMPILER==WIN32C 148960786Sps 149060786Sps/* 149160786Sps * Termcap-like init with a private win32 console. 149260786Sps */ 149360786Sps static void 149460786Spswin32_init_term() 149560786Sps{ 149660786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 149760786Sps COORD size; 149860786Sps 149960786Sps if (con_out_save == INVALID_HANDLE_VALUE) 150060786Sps return; 150160786Sps 150260786Sps GetConsoleScreenBufferInfo(con_out_save, &scr); 150360786Sps 150460786Sps if (con_out_ours == INVALID_HANDLE_VALUE) 150560786Sps { 150660786Sps /* 150760786Sps * Create our own screen buffer, so that we 150860786Sps * may restore the original when done. 150960786Sps */ 151060786Sps con_out_ours = CreateConsoleScreenBuffer( 151160786Sps GENERIC_WRITE | GENERIC_READ, 151260786Sps FILE_SHARE_WRITE | FILE_SHARE_READ, 151360786Sps (LPSECURITY_ATTRIBUTES) NULL, 151460786Sps CONSOLE_TEXTMODE_BUFFER, 151560786Sps (LPVOID) NULL); 151660786Sps } 151760786Sps 151860786Sps size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 151960786Sps size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 152060786Sps SetConsoleScreenBufferSize(con_out_ours, size); 152160786Sps SetConsoleActiveScreenBuffer(con_out_ours); 152260786Sps con_out = con_out_ours; 152360786Sps} 152460786Sps 152560786Sps/* 152660786Sps * Restore the startup console. 152760786Sps */ 152860786Spsstatic void 152960786Spswin32_deinit_term() 153060786Sps{ 153160786Sps if (con_out_save == INVALID_HANDLE_VALUE) 153260786Sps return; 153360786Sps if (quitting) 153460786Sps (void) CloseHandle(con_out_ours); 153560786Sps SetConsoleActiveScreenBuffer(con_out_save); 153660786Sps con_out = con_out_save; 153760786Sps} 153860786Sps 153960786Sps#endif 154060786Sps 154160786Sps/* 154260786Sps * Initialize terminal 154360786Sps */ 154460786Sps public void 154560786Spsinit() 154660786Sps{ 154760786Sps#if !MSDOS_COMPILER 154889022Sps if (!no_init) 154989022Sps tputs(sc_init, sc_height, putchr); 155089022Sps if (!no_keypad) 155189022Sps tputs(sc_s_keypad, sc_height, putchr); 1552161478Sdelphij if (top_scroll) 1553161478Sdelphij { 1554161478Sdelphij int i; 1555161478Sdelphij 1556161478Sdelphij /* 1557161478Sdelphij * This is nice to terminals with no alternate screen, 1558161478Sdelphij * but with saved scrolled-off-the-top lines. This way, 1559161478Sdelphij * no previous line is lost, but we start with a whole 1560161478Sdelphij * screen to ourself. 1561161478Sdelphij */ 1562161478Sdelphij for (i = 1; i < sc_height; i++) 1563161478Sdelphij putchr('\n'); 1564161478Sdelphij } 156560786Sps#else 156660786Sps#if MSDOS_COMPILER==WIN32C 156789022Sps if (!no_init) 156889022Sps win32_init_term(); 156960786Sps#endif 157060786Sps initcolor(); 157160786Sps flush(); 157260786Sps#endif 157360786Sps init_done = 1; 157460786Sps} 157560786Sps 157660786Sps/* 157760786Sps * Deinitialize terminal 157860786Sps */ 157960786Sps public void 158060786Spsdeinit() 158160786Sps{ 158260786Sps if (!init_done) 158360786Sps return; 158460786Sps#if !MSDOS_COMPILER 158589022Sps if (!no_keypad) 158689022Sps tputs(sc_e_keypad, sc_height, putchr); 158789022Sps if (!no_init) 158889022Sps tputs(sc_deinit, sc_height, putchr); 158960786Sps#else 159089022Sps /* Restore system colors. */ 159160786Sps SETCOLORS(sy_fg_color, sy_bg_color); 159260786Sps#if MSDOS_COMPILER==WIN32C 159389022Sps if (!no_init) 159489022Sps win32_deinit_term(); 159589022Sps#else 159689022Sps /* Need clreol to make SETCOLORS take effect. */ 159789022Sps clreol(); 159860786Sps#endif 159960786Sps#endif 160060786Sps init_done = 0; 160160786Sps} 160260786Sps 160360786Sps/* 160460786Sps * Home cursor (move to upper left corner of screen). 160560786Sps */ 160660786Sps public void 160760786Spshome() 160860786Sps{ 160960786Sps#if !MSDOS_COMPILER 161060786Sps tputs(sc_home, 1, putchr); 161160786Sps#else 161260786Sps flush(); 161360786Sps _settextposition(1,1); 161460786Sps#endif 161560786Sps} 161660786Sps 161760786Sps/* 161860786Sps * Add a blank line (called with cursor at home). 161960786Sps * Should scroll the display down. 162060786Sps */ 162160786Sps public void 162260786Spsadd_line() 162360786Sps{ 162460786Sps#if !MSDOS_COMPILER 162560786Sps tputs(sc_addline, sc_height, putchr); 162660786Sps#else 162760786Sps flush(); 162860786Sps#if MSDOS_COMPILER==MSOFTC 162960786Sps _scrolltextwindow(_GSCROLLDOWN); 163060786Sps _settextposition(1,1); 163160786Sps#else 163260786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 163360786Sps movetext(1,1, sc_width,sc_height-1, 1,2); 163460786Sps gotoxy(1,1); 163560786Sps clreol(); 163660786Sps#else 163760786Sps#if MSDOS_COMPILER==WIN32C 163860786Sps { 163960786Sps CHAR_INFO fillchar; 164060786Sps SMALL_RECT rcSrc, rcClip; 164160786Sps COORD new_org; 164260786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 164360786Sps 164460786Sps GetConsoleScreenBufferInfo(con_out,&csbi); 164560786Sps 164660786Sps /* The clip rectangle is the entire visible screen. */ 164760786Sps rcClip.Left = csbi.srWindow.Left; 164860786Sps rcClip.Top = csbi.srWindow.Top; 164960786Sps rcClip.Right = csbi.srWindow.Right; 165060786Sps rcClip.Bottom = csbi.srWindow.Bottom; 165160786Sps 165260786Sps /* The source rectangle is the visible screen minus the last line. */ 165360786Sps rcSrc = rcClip; 165460786Sps rcSrc.Bottom--; 165560786Sps 165660786Sps /* Move the top left corner of the source window down one row. */ 165760786Sps new_org.X = rcSrc.Left; 165860786Sps new_org.Y = rcSrc.Top + 1; 165960786Sps 166060786Sps /* Fill the right character and attributes. */ 166160786Sps fillchar.Char.AsciiChar = ' '; 166260786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 166360786Sps fillchar.Attributes = curr_attr; 166460786Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 166560786Sps _settextposition(1,1); 166660786Sps } 166760786Sps#endif 166860786Sps#endif 166960786Sps#endif 167060786Sps#endif 167160786Sps} 167260786Sps 167389022Sps#if 0 167460786Sps/* 167560786Sps * Remove the n topmost lines and scroll everything below it in the 167660786Sps * window upward. This is needed to stop leaking the topmost line 167760786Sps * into the scrollback buffer when we go down-one-line (in WIN32). 167860786Sps */ 167960786Sps public void 168060786Spsremove_top(n) 168160786Sps int n; 168260786Sps{ 168360786Sps#if MSDOS_COMPILER==WIN32C 168460786Sps SMALL_RECT rcSrc, rcClip; 168560786Sps CHAR_INFO fillchar; 168660786Sps COORD new_org; 168760786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 168860786Sps 168960786Sps if (n >= sc_height - 1) 169060786Sps { 169160786Sps clear(); 169260786Sps home(); 169360786Sps return; 169460786Sps } 169560786Sps 169660786Sps flush(); 169760786Sps 169860786Sps GetConsoleScreenBufferInfo(con_out, &csbi); 169960786Sps 170060786Sps /* Get the extent of all-visible-rows-but-the-last. */ 170160786Sps rcSrc.Left = csbi.srWindow.Left; 170260786Sps rcSrc.Top = csbi.srWindow.Top + n; 170360786Sps rcSrc.Right = csbi.srWindow.Right; 170460786Sps rcSrc.Bottom = csbi.srWindow.Bottom; 170560786Sps 170660786Sps /* Get the clip rectangle. */ 170760786Sps rcClip.Left = rcSrc.Left; 170860786Sps rcClip.Top = csbi.srWindow.Top; 170960786Sps rcClip.Right = rcSrc.Right; 171060786Sps rcClip.Bottom = rcSrc.Bottom ; 171160786Sps 171260786Sps /* Move the source window up n rows. */ 171360786Sps new_org.X = rcSrc.Left; 171460786Sps new_org.Y = rcSrc.Top - n; 171560786Sps 171660786Sps /* Fill the right character and attributes. */ 171760786Sps fillchar.Char.AsciiChar = ' '; 171860786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 171960786Sps fillchar.Attributes = curr_attr; 172060786Sps 172160786Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 172260786Sps 172360786Sps /* Position cursor on first blank line. */ 172460786Sps goto_line(sc_height - n - 1); 172560786Sps#endif 172660786Sps} 172789022Sps#endif 172860786Sps 172989022Sps#if MSDOS_COMPILER==WIN32C 173060786Sps/* 173189022Sps * Clear the screen. 173289022Sps */ 173389022Sps static void 173489022Spswin32_clear() 173589022Sps{ 173689022Sps /* 173789022Sps * This will clear only the currently visible rows of the NT 173889022Sps * console buffer, which means none of the precious scrollback 173989022Sps * rows are touched making for faster scrolling. Note that, if 174089022Sps * the window has fewer columns than the console buffer (i.e. 174189022Sps * there is a horizontal scrollbar as well), the entire width 174289022Sps * of the visible rows will be cleared. 174389022Sps */ 174489022Sps COORD topleft; 174589022Sps DWORD nchars; 174689022Sps DWORD winsz; 174789022Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 174889022Sps 174989022Sps /* get the number of cells in the current buffer */ 175089022Sps GetConsoleScreenBufferInfo(con_out, &csbi); 175189022Sps winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); 175289022Sps topleft.X = 0; 175389022Sps topleft.Y = csbi.srWindow.Top; 175489022Sps 175589022Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 175689022Sps FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars); 175789022Sps FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars); 175889022Sps} 175989022Sps 176089022Sps/* 176189022Sps * Remove the n topmost lines and scroll everything below it in the 176289022Sps * window upward. 176389022Sps */ 176489022Sps public void 176589022Spswin32_scroll_up(n) 176689022Sps int n; 176789022Sps{ 176889022Sps SMALL_RECT rcSrc, rcClip; 176989022Sps CHAR_INFO fillchar; 177089022Sps COORD topleft; 177189022Sps COORD new_org; 177289022Sps DWORD nchars; 177389022Sps DWORD size; 177489022Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 177589022Sps 177689022Sps if (n <= 0) 177789022Sps return; 177889022Sps 177989022Sps if (n >= sc_height - 1) 178089022Sps { 178189022Sps win32_clear(); 178289022Sps _settextposition(1,1); 178389022Sps return; 178489022Sps } 178589022Sps 178689022Sps /* Get the extent of what will remain visible after scrolling. */ 178789022Sps GetConsoleScreenBufferInfo(con_out, &csbi); 178889022Sps rcSrc.Left = csbi.srWindow.Left; 178989022Sps rcSrc.Top = csbi.srWindow.Top + n; 179089022Sps rcSrc.Right = csbi.srWindow.Right; 179189022Sps rcSrc.Bottom = csbi.srWindow.Bottom; 179289022Sps 179389022Sps /* Get the clip rectangle. */ 179489022Sps rcClip.Left = rcSrc.Left; 179589022Sps rcClip.Top = csbi.srWindow.Top; 179689022Sps rcClip.Right = rcSrc.Right; 179789022Sps rcClip.Bottom = rcSrc.Bottom ; 179889022Sps 179989022Sps /* Move the source text to the top of the screen. */ 180089022Sps new_org.X = rcSrc.Left; 180189022Sps new_org.Y = 0; 180289022Sps 180389022Sps /* Fill the right character and attributes. */ 180489022Sps fillchar.Char.AsciiChar = ' '; 180589022Sps fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color); 180689022Sps 180789022Sps /* Scroll the window. */ 180889022Sps SetConsoleTextAttribute(con_out, fillchar.Attributes); 180989022Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 181089022Sps 181189022Sps /* Clear remaining lines at bottom. */ 181289022Sps topleft.X = csbi.dwCursorPosition.X; 181389022Sps topleft.Y = rcSrc.Bottom - n; 181489022Sps size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X); 181589022Sps FillConsoleOutputCharacter(con_out, ' ', size, topleft, 181689022Sps &nchars); 181789022Sps FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft, 181889022Sps &nchars); 181989022Sps SetConsoleTextAttribute(con_out, curr_attr); 182089022Sps 182189022Sps /* Move cursor n lines up from where it was. */ 182289022Sps csbi.dwCursorPosition.Y -= n; 182389022Sps SetConsoleCursorPosition(con_out, csbi.dwCursorPosition); 182489022Sps} 182589022Sps#endif 182689022Sps 182789022Sps/* 182860786Sps * Move cursor to lower left corner of screen. 182960786Sps */ 183060786Sps public void 183160786Spslower_left() 183260786Sps{ 183360786Sps#if !MSDOS_COMPILER 183460786Sps tputs(sc_lower_left, 1, putchr); 183560786Sps#else 183660786Sps flush(); 183760786Sps _settextposition(sc_height, 1); 183860786Sps#endif 183960786Sps} 184060786Sps 184160786Sps/* 1842170259Sdelphij * Move cursor to left position of current line. 1843170259Sdelphij */ 1844170259Sdelphij public void 1845170259Sdelphijline_left() 1846170259Sdelphij{ 1847170259Sdelphij#if !MSDOS_COMPILER 1848170259Sdelphij tputs(sc_return, 1, putchr); 1849170259Sdelphij#else 1850170259Sdelphij int row; 1851170259Sdelphij flush(); 1852170259Sdelphij#if MSDOS_COMPILER==WIN32C 1853170259Sdelphij { 1854170259Sdelphij CONSOLE_SCREEN_BUFFER_INFO scr; 1855170259Sdelphij GetConsoleScreenBufferInfo(con_out, &scr); 1856170259Sdelphij row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 1857170259Sdelphij } 1858170259Sdelphij#else 1859170259Sdelphij { 1860170259Sdelphij struct rccoord tpos = _gettextposition(); 1861170259Sdelphij row = tpos.row; 1862170259Sdelphij } 1863170259Sdelphij#endif 1864170259Sdelphij _settextposition(row, 1); 1865170259Sdelphij#endif 1866170259Sdelphij} 1867170259Sdelphij 1868170259Sdelphij/* 186960786Sps * Check if the console size has changed and reset internals 187060786Sps * (in lieu of SIGWINCH for WIN32). 187160786Sps */ 187260786Sps public void 187360786Spscheck_winch() 187460786Sps{ 187560786Sps#if MSDOS_COMPILER==WIN32C 187660786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 187760786Sps COORD size; 187860786Sps 187960786Sps if (con_out == INVALID_HANDLE_VALUE) 188060786Sps return; 188160786Sps 188260786Sps flush(); 188360786Sps GetConsoleScreenBufferInfo(con_out, &scr); 188460786Sps size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 188560786Sps size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 188660786Sps if (size.Y != sc_height || size.X != sc_width) 188760786Sps { 188860786Sps sc_height = size.Y; 188960786Sps sc_width = size.X; 189060786Sps if (!no_init && con_out_ours == con_out) 189160786Sps SetConsoleScreenBufferSize(con_out, size); 189260786Sps pos_init(); 189360786Sps wscroll = (sc_height + 1) / 2; 189460786Sps screen_trashed = 1; 189560786Sps } 189660786Sps#endif 189760786Sps} 189860786Sps 189960786Sps/* 190060786Sps * Goto a specific line on the screen. 190160786Sps */ 190260786Sps public void 190360786Spsgoto_line(slinenum) 190460786Sps int slinenum; 190560786Sps{ 190660786Sps#if !MSDOS_COMPILER 190760786Sps tputs(tgoto(sc_move, 0, slinenum), 1, putchr); 190860786Sps#else 190960786Sps flush(); 191060786Sps _settextposition(slinenum+1, 1); 191160786Sps#endif 191260786Sps} 191360786Sps 191460786Sps#if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC 191560786Sps/* 191660786Sps * Create an alternate screen which is all white. 191760786Sps * This screen is used to create a "flash" effect, by displaying it 191860786Sps * briefly and then switching back to the normal screen. 191960786Sps * {{ Yuck! There must be a better way to get a visual bell. }} 192060786Sps */ 192160786Sps static void 192260786Spscreate_flash() 192360786Sps{ 192460786Sps#if MSDOS_COMPILER==MSOFTC 192560786Sps struct videoconfig w; 192660786Sps char *blanks; 192760786Sps int row, col; 192860786Sps 192960786Sps _getvideoconfig(&w); 193060786Sps videopages = w.numvideopages; 193160786Sps if (videopages < 2) 193260786Sps { 1933161478Sdelphij at_enter(AT_STANDOUT); 1934161478Sdelphij at_exit(); 193560786Sps } else 193660786Sps { 193760786Sps _setactivepage(1); 1938161478Sdelphij at_enter(AT_STANDOUT); 193960786Sps blanks = (char *) ecalloc(w.numtextcols, sizeof(char)); 194060786Sps for (col = 0; col < w.numtextcols; col++) 194160786Sps blanks[col] = ' '; 194260786Sps for (row = w.numtextrows; row > 0; row--) 194360786Sps _outmem(blanks, w.numtextcols); 194460786Sps _setactivepage(0); 194560786Sps _setvisualpage(0); 194660786Sps free(blanks); 1947161478Sdelphij at_exit(); 194860786Sps } 194960786Sps#else 195060786Sps#if MSDOS_COMPILER==BORLANDC 195160786Sps register int n; 195260786Sps 195360786Sps whitescreen = (unsigned short *) 195460786Sps malloc(sc_width * sc_height * sizeof(short)); 195560786Sps if (whitescreen == NULL) 195660786Sps return; 195760786Sps for (n = 0; n < sc_width * sc_height; n++) 195860786Sps whitescreen[n] = 0x7020; 195960786Sps#else 196060786Sps#if MSDOS_COMPILER==WIN32C 196160786Sps register int n; 196260786Sps 196360786Sps whitescreen = (WORD *) 196460786Sps malloc(sc_height * sc_width * sizeof(WORD)); 196560786Sps if (whitescreen == NULL) 196660786Sps return; 196760786Sps /* Invert the standard colors. */ 196860786Sps for (n = 0; n < sc_width * sc_height; n++) 196960786Sps whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color); 197060786Sps#endif 197160786Sps#endif 197260786Sps#endif 197360786Sps flash_created = 1; 197460786Sps} 197560786Sps#endif /* MSDOS_COMPILER */ 197660786Sps 197760786Sps/* 197860786Sps * Output the "visual bell", if there is one. 197960786Sps */ 198060786Sps public void 198160786Spsvbell() 198260786Sps{ 198360786Sps#if !MSDOS_COMPILER 198460786Sps if (*sc_visual_bell == '\0') 198560786Sps return; 198660786Sps tputs(sc_visual_bell, sc_height, putchr); 198760786Sps#else 198860786Sps#if MSDOS_COMPILER==DJGPPC 198960786Sps ScreenVisualBell(); 199060786Sps#else 199160786Sps#if MSDOS_COMPILER==MSOFTC 199260786Sps /* 199360786Sps * Create a flash screen on the second video page. 199460786Sps * Switch to that page, then switch back. 199560786Sps */ 199660786Sps if (!flash_created) 199760786Sps create_flash(); 199860786Sps if (videopages < 2) 199960786Sps return; 200060786Sps _setvisualpage(1); 200160786Sps delay(100); 200260786Sps _setvisualpage(0); 200360786Sps#else 200460786Sps#if MSDOS_COMPILER==BORLANDC 200560786Sps unsigned short *currscreen; 200660786Sps 200760786Sps /* 200860786Sps * Get a copy of the current screen. 200960786Sps * Display the flash screen. 201060786Sps * Then restore the old screen. 201160786Sps */ 201260786Sps if (!flash_created) 201360786Sps create_flash(); 201460786Sps if (whitescreen == NULL) 201560786Sps return; 201660786Sps currscreen = (unsigned short *) 201760786Sps malloc(sc_width * sc_height * sizeof(short)); 201860786Sps if (currscreen == NULL) return; 201960786Sps gettext(1, 1, sc_width, sc_height, currscreen); 202060786Sps puttext(1, 1, sc_width, sc_height, whitescreen); 202160786Sps delay(100); 202260786Sps puttext(1, 1, sc_width, sc_height, currscreen); 202360786Sps free(currscreen); 202460786Sps#else 202560786Sps#if MSDOS_COMPILER==WIN32C 202660786Sps /* paint screen with an inverse color */ 202760786Sps clear(); 202860786Sps 202960786Sps /* leave it displayed for 100 msec. */ 203060786Sps Sleep(100); 203160786Sps 203260786Sps /* restore with a redraw */ 203360786Sps repaint(); 203460786Sps#endif 203560786Sps#endif 203660786Sps#endif 203760786Sps#endif 203860786Sps#endif 203960786Sps} 204060786Sps 204160786Sps/* 204260786Sps * Make a noise. 204360786Sps */ 204460786Sps static void 204560786Spsbeep() 204660786Sps{ 204760786Sps#if !MSDOS_COMPILER 204889022Sps putchr(CONTROL('G')); 204960786Sps#else 205060786Sps#if MSDOS_COMPILER==WIN32C 205160786Sps MessageBeep(0); 205260786Sps#else 205360786Sps write(1, "\7", 1); 205460786Sps#endif 205560786Sps#endif 205660786Sps} 205760786Sps 205860786Sps/* 205960786Sps * Ring the terminal bell. 206060786Sps */ 206160786Sps public void 206260786Spsbell() 206360786Sps{ 206460786Sps if (quiet == VERY_QUIET) 206560786Sps vbell(); 206660786Sps else 206760786Sps beep(); 206860786Sps} 206960786Sps 207060786Sps/* 207160786Sps * Clear the screen. 207260786Sps */ 207360786Sps public void 207460786Spsclear() 207560786Sps{ 207660786Sps#if !MSDOS_COMPILER 207760786Sps tputs(sc_clear, sc_height, putchr); 207860786Sps#else 207960786Sps flush(); 208060786Sps#if MSDOS_COMPILER==WIN32C 208189022Sps win32_clear(); 208260786Sps#else 208360786Sps _clearscreen(_GCLEARSCREEN); 208460786Sps#endif 208560786Sps#endif 208660786Sps} 208760786Sps 208860786Sps/* 208960786Sps * Clear from the cursor to the end of the cursor's line. 209060786Sps * {{ This must not move the cursor. }} 209160786Sps */ 209260786Sps public void 209360786Spsclear_eol() 209460786Sps{ 209560786Sps#if !MSDOS_COMPILER 209660786Sps tputs(sc_eol_clear, 1, putchr); 209760786Sps#else 209860786Sps#if MSDOS_COMPILER==MSOFTC 209960786Sps short top, left; 210060786Sps short bot, right; 210160786Sps struct rccoord tpos; 210260786Sps 210360786Sps flush(); 210460786Sps /* 210560786Sps * Save current state. 210660786Sps */ 210760786Sps tpos = _gettextposition(); 210860786Sps _gettextwindow(&top, &left, &bot, &right); 210960786Sps /* 211060786Sps * Set a temporary window to the current line, 211160786Sps * from the cursor's position to the right edge of the screen. 211260786Sps * Then clear that window. 211360786Sps */ 211460786Sps _settextwindow(tpos.row, tpos.col, tpos.row, sc_width); 211560786Sps _clearscreen(_GWINDOW); 211660786Sps /* 211760786Sps * Restore state. 211860786Sps */ 211960786Sps _settextwindow(top, left, bot, right); 212060786Sps _settextposition(tpos.row, tpos.col); 212160786Sps#else 212260786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 212360786Sps flush(); 212460786Sps clreol(); 212560786Sps#else 212660786Sps#if MSDOS_COMPILER==WIN32C 212760786Sps DWORD nchars; 212860786Sps COORD cpos; 212960786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 213060786Sps 213160786Sps flush(); 213260786Sps memset(&scr, 0, sizeof(scr)); 213360786Sps GetConsoleScreenBufferInfo(con_out, &scr); 213460786Sps cpos.X = scr.dwCursorPosition.X; 213560786Sps cpos.Y = scr.dwCursorPosition.Y; 213660786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 213760786Sps FillConsoleOutputAttribute(con_out, curr_attr, 213860786Sps scr.dwSize.X - cpos.X, cpos, &nchars); 213960786Sps FillConsoleOutputCharacter(con_out, ' ', 214060786Sps scr.dwSize.X - cpos.X, cpos, &nchars); 214160786Sps#endif 214260786Sps#endif 214360786Sps#endif 214460786Sps#endif 214560786Sps} 214660786Sps 214760786Sps/* 214860786Sps * Clear the current line. 214960786Sps * Clear the screen if there's off-screen memory below the display. 215060786Sps */ 215160786Sps static void 215260786Spsclear_eol_bot() 215360786Sps{ 215460786Sps#if MSDOS_COMPILER 215560786Sps clear_eol(); 215660786Sps#else 215760786Sps if (below_mem) 215860786Sps tputs(sc_eos_clear, 1, putchr); 215960786Sps else 216060786Sps tputs(sc_eol_clear, 1, putchr); 216160786Sps#endif 216260786Sps} 216360786Sps 216460786Sps/* 216560786Sps * Clear the bottom line of the display. 216660786Sps * Leave the cursor at the beginning of the bottom line. 216760786Sps */ 216860786Sps public void 216960786Spsclear_bot() 217060786Sps{ 217160786Sps /* 217260786Sps * If we're in a non-normal attribute mode, temporarily exit 217360786Sps * the mode while we do the clear. Some terminals fill the 217460786Sps * cleared area with the current attribute. 217560786Sps */ 2176170259Sdelphij if (oldbot) 2177170259Sdelphij lower_left(); 2178170259Sdelphij else 2179170259Sdelphij line_left(); 2180170259Sdelphij 2181161478Sdelphij if (attrmode == AT_NORMAL) 2182161478Sdelphij clear_eol_bot(); 2183161478Sdelphij else 218460786Sps { 2185161478Sdelphij int saved_attrmode = attrmode; 2186161478Sdelphij 2187161478Sdelphij at_exit(); 218860786Sps clear_eol_bot(); 2189161478Sdelphij at_enter(saved_attrmode); 219060786Sps } 219160786Sps} 219260786Sps 219360786Sps public void 2194161478Sdelphijat_enter(attr) 2195161478Sdelphij int attr; 219660786Sps{ 2197161478Sdelphij attr = apply_at_specials(attr); 219860786Sps 219960786Sps#if !MSDOS_COMPILER 2200161478Sdelphij /* The one with the most priority is last. */ 2201161478Sdelphij if (attr & AT_UNDERLINE) 2202161478Sdelphij tputs(sc_u_in, 1, putchr); 2203161478Sdelphij if (attr & AT_BOLD) 2204161478Sdelphij tputs(sc_b_in, 1, putchr); 2205161478Sdelphij if (attr & AT_BLINK) 2206161478Sdelphij tputs(sc_bl_in, 1, putchr); 2207161478Sdelphij if (attr & AT_STANDOUT) 2208161478Sdelphij tputs(sc_s_in, 1, putchr); 220960786Sps#else 221060786Sps flush(); 2211161478Sdelphij /* The one with the most priority is first. */ 2212161478Sdelphij if (attr & AT_STANDOUT) 2213161478Sdelphij { 2214161478Sdelphij SETCOLORS(so_fg_color, so_bg_color); 2215161478Sdelphij } else if (attr & AT_BLINK) 2216161478Sdelphij { 2217161478Sdelphij SETCOLORS(bl_fg_color, bl_bg_color); 2218161478Sdelphij } 2219161478Sdelphij else if (attr & AT_BOLD) 2220161478Sdelphij { 2221161478Sdelphij SETCOLORS(bo_fg_color, bo_bg_color); 2222161478Sdelphij } 2223161478Sdelphij else if (attr & AT_UNDERLINE) 2224161478Sdelphij { 2225161478Sdelphij SETCOLORS(ul_fg_color, ul_bg_color); 2226161478Sdelphij } 222760786Sps#endif 222860786Sps 2229161478Sdelphij attrmode = attr; 223060786Sps} 223160786Sps 223260786Sps public void 2233161478Sdelphijat_exit() 223460786Sps{ 223560786Sps#if !MSDOS_COMPILER 2236161478Sdelphij /* Undo things in the reverse order we did them. */ 2237161478Sdelphij if (attrmode & AT_STANDOUT) 2238161478Sdelphij tputs(sc_s_out, 1, putchr); 2239161478Sdelphij if (attrmode & AT_BLINK) 2240161478Sdelphij tputs(sc_bl_out, 1, putchr); 2241161478Sdelphij if (attrmode & AT_BOLD) 2242161478Sdelphij tputs(sc_b_out, 1, putchr); 2243161478Sdelphij if (attrmode & AT_UNDERLINE) 2244161478Sdelphij tputs(sc_u_out, 1, putchr); 224560786Sps#else 224660786Sps flush(); 224760786Sps SETCOLORS(nm_fg_color, nm_bg_color); 224860786Sps#endif 2249161478Sdelphij 225060786Sps attrmode = AT_NORMAL; 225160786Sps} 225260786Sps 225360786Sps public void 2254161478Sdelphijat_switch(attr) 2255161478Sdelphij int attr; 225660786Sps{ 2257170259Sdelphij int new_attrmode = apply_at_specials(attr); 2258170259Sdelphij int ignore_modes = AT_ANSI; 2259170259Sdelphij 2260170259Sdelphij if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes)) 2261161478Sdelphij { 2262161478Sdelphij at_exit(); 2263161478Sdelphij at_enter(attr); 2264161478Sdelphij } 226560786Sps} 226660786Sps 2267161478Sdelphij public int 2268161478Sdelphijis_at_equiv(attr1, attr2) 2269161478Sdelphij int attr1; 2270161478Sdelphij int attr2; 227160786Sps{ 2272161478Sdelphij attr1 = apply_at_specials(attr1); 2273161478Sdelphij attr2 = apply_at_specials(attr2); 2274161478Sdelphij 2275161478Sdelphij return (attr1 == attr2); 227660786Sps} 227760786Sps 2278161478Sdelphij public int 2279161478Sdelphijapply_at_specials(attr) 2280161478Sdelphij int attr; 228160786Sps{ 2282161478Sdelphij if (attr & AT_BINARY) 2283161478Sdelphij attr |= binattr; 2284161478Sdelphij if (attr & AT_HILITE) 2285161478Sdelphij attr |= AT_STANDOUT; 2286161478Sdelphij attr &= ~(AT_BINARY|AT_HILITE); 228760786Sps 2288161478Sdelphij return attr; 228960786Sps} 229060786Sps 229160786Sps#if 0 /* No longer used */ 229260786Sps/* 229360786Sps * Erase the character to the left of the cursor 229460786Sps * and move the cursor left. 229560786Sps */ 229660786Sps public void 229760786Spsbackspace() 229860786Sps{ 229960786Sps#if !MSDOS_COMPILER 230060786Sps /* 230160786Sps * Erase the previous character by overstriking with a space. 230260786Sps */ 230360786Sps tputs(sc_backspace, 1, putchr); 230460786Sps putchr(' '); 230560786Sps tputs(sc_backspace, 1, putchr); 230660786Sps#else 230760786Sps#if MSDOS_COMPILER==MSOFTC 230860786Sps struct rccoord tpos; 230960786Sps 231060786Sps flush(); 231160786Sps tpos = _gettextposition(); 231260786Sps if (tpos.col <= 1) 231360786Sps return; 231460786Sps _settextposition(tpos.row, tpos.col-1); 231560786Sps _outtext(" "); 231660786Sps _settextposition(tpos.row, tpos.col-1); 231760786Sps#else 231860786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 231960786Sps cputs("\b"); 232060786Sps#else 232160786Sps#if MSDOS_COMPILER==WIN32C 232260786Sps COORD cpos; 232360786Sps DWORD cChars; 232460786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 232560786Sps 232660786Sps flush(); 232760786Sps GetConsoleScreenBufferInfo(con_out, &scr); 232860786Sps cpos = scr.dwCursorPosition; 232960786Sps if (cpos.X <= 0) 233060786Sps return; 233160786Sps cpos.X--; 233260786Sps SetConsoleCursorPosition(con_out, cpos); 233360786Sps FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars); 233460786Sps SetConsoleCursorPosition(con_out, cpos); 233560786Sps#endif 233660786Sps#endif 233760786Sps#endif 233860786Sps#endif 233960786Sps} 234060786Sps#endif /* 0 */ 234160786Sps 234260786Sps/* 234360786Sps * Output a plain backspace, without erasing the previous char. 234460786Sps */ 234560786Sps public void 234660786Spsputbs() 234760786Sps{ 234860786Sps#if !MSDOS_COMPILER 234960786Sps tputs(sc_backspace, 1, putchr); 235060786Sps#else 235160786Sps int row, col; 235260786Sps 235360786Sps flush(); 235460786Sps { 235560786Sps#if MSDOS_COMPILER==MSOFTC 235660786Sps struct rccoord tpos; 235760786Sps tpos = _gettextposition(); 235860786Sps row = tpos.row; 235960786Sps col = tpos.col; 236060786Sps#else 236160786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 236260786Sps row = wherey(); 236360786Sps col = wherex(); 236460786Sps#else 236560786Sps#if MSDOS_COMPILER==WIN32C 236660786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 236760786Sps GetConsoleScreenBufferInfo(con_out, &scr); 236860786Sps row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 236960786Sps col = scr.dwCursorPosition.X - scr.srWindow.Left + 1; 237060786Sps#endif 237160786Sps#endif 237260786Sps#endif 237360786Sps } 237460786Sps if (col <= 1) 237560786Sps return; 237660786Sps _settextposition(row, col-1); 237760786Sps#endif /* MSDOS_COMPILER */ 237860786Sps} 237960786Sps 238060786Sps#if MSDOS_COMPILER==WIN32C 238160786Sps/* 238260786Sps * Determine whether an input character is waiting to be read. 238360786Sps */ 238460786Sps static int 238560786Spswin32_kbhit(tty) 238660786Sps HANDLE tty; 238760786Sps{ 238860786Sps INPUT_RECORD ip; 238960786Sps DWORD read; 239060786Sps 239160786Sps if (keyCount > 0) 239260786Sps return (TRUE); 239360786Sps 239460786Sps currentKey.ascii = 0; 239560786Sps currentKey.scan = 0; 239660786Sps 239760786Sps /* 239860786Sps * Wait for a real key-down event, but 239960786Sps * ignore SHIFT and CONTROL key events. 240060786Sps */ 240160786Sps do 240260786Sps { 240360786Sps PeekConsoleInput(tty, &ip, 1, &read); 240460786Sps if (read == 0) 240560786Sps return (FALSE); 240660786Sps ReadConsoleInput(tty, &ip, 1, &read); 240760786Sps } while (ip.EventType != KEY_EVENT || 240860786Sps ip.Event.KeyEvent.bKeyDown != TRUE || 240960786Sps ip.Event.KeyEvent.wVirtualScanCode == 0 || 241060786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT || 241160786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL || 241260786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU); 241360786Sps 241460786Sps currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar; 241560786Sps currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode; 241660786Sps keyCount = ip.Event.KeyEvent.wRepeatCount; 241760786Sps 241860786Sps if (ip.Event.KeyEvent.dwControlKeyState & 241960786Sps (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) 242060786Sps { 242160786Sps switch (currentKey.scan) 242260786Sps { 242360786Sps case PCK_ALT_E: /* letter 'E' */ 242460786Sps currentKey.ascii = 0; 242560786Sps break; 242660786Sps } 242760786Sps } else if (ip.Event.KeyEvent.dwControlKeyState & 242860786Sps (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 242960786Sps { 243060786Sps switch (currentKey.scan) 243160786Sps { 243260786Sps case PCK_RIGHT: /* right arrow */ 243360786Sps currentKey.scan = PCK_CTL_RIGHT; 243460786Sps break; 243560786Sps case PCK_LEFT: /* left arrow */ 243660786Sps currentKey.scan = PCK_CTL_LEFT; 243760786Sps break; 243860786Sps case PCK_DELETE: /* delete */ 243960786Sps currentKey.scan = PCK_CTL_DELETE; 244060786Sps break; 244160786Sps } 244260786Sps } 244360786Sps return (TRUE); 244460786Sps} 244560786Sps 244660786Sps/* 244760786Sps * Read a character from the keyboard. 244860786Sps */ 244960786Sps public char 245060786SpsWIN32getch(tty) 245160786Sps int tty; 245260786Sps{ 245360786Sps int ascii; 245460786Sps 245560786Sps if (pending_scancode) 245660786Sps { 245760786Sps pending_scancode = 0; 245860786Sps return ((char)(currentKey.scan & 0x00FF)); 245960786Sps } 246060786Sps 246160786Sps while (win32_kbhit((HANDLE)tty) == FALSE) 246260786Sps { 246360786Sps Sleep(20); 246460786Sps if (ABORT_SIGS()) 246560786Sps return ('\003'); 246660786Sps continue; 246760786Sps } 246860786Sps keyCount --; 246960786Sps ascii = currentKey.ascii; 247060786Sps /* 247160786Sps * On PC's, the extended keys return a 2 byte sequence beginning 247260786Sps * with '00', so if the ascii code is 00, the next byte will be 247360786Sps * the lsb of the scan code. 247460786Sps */ 247560786Sps pending_scancode = (ascii == 0x00); 247660786Sps return ((char)ascii); 247760786Sps} 247860786Sps#endif 2479