1238730Sdelphij/* 2238730Sdelphij * Copyright (C) 1984-2012 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 12960786Spsextern int quitting; 13060786Spsstatic void win32_init_term(); 13160786Spsstatic void win32_deinit_term(); 13260786Sps 13360786Sps#define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY) 13460786Sps#define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY) 13560786Sps#define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) 13660786Sps#define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \ 13760786Sps if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ 13860786Sps error("SETCOLORS failed"); } 13960786Sps#endif 14060786Sps 14160786Sps#if MSDOS_COMPILER 14260786Spspublic int nm_fg_color; /* Color of normal text */ 14360786Spspublic int nm_bg_color; 14460786Spspublic int bo_fg_color; /* Color of bold text */ 14560786Spspublic int bo_bg_color; 14660786Spspublic int ul_fg_color; /* Color of underlined text */ 14760786Spspublic int ul_bg_color; 14860786Spspublic int so_fg_color; /* Color of standout text */ 14960786Spspublic int so_bg_color; 15060786Spspublic int bl_fg_color; /* Color of blinking text */ 15160786Spspublic int bl_bg_color; 15260786Spsstatic int sy_fg_color; /* Color of system text (before less) */ 15360786Spsstatic int sy_bg_color; 15460786Sps 15560786Sps#else 15660786Sps 15760786Sps/* 15860786Sps * Strings passed to tputs() to do various terminal functions. 15960786Sps */ 16060786Spsstatic char 16160786Sps *sc_pad, /* Pad string */ 16260786Sps *sc_home, /* Cursor home */ 16360786Sps *sc_addline, /* Add line, scroll down following lines */ 16460786Sps *sc_lower_left, /* Cursor to last line, first column */ 165170259Sdelphij *sc_return, /* Cursor to beginning of current line */ 16660786Sps *sc_move, /* General cursor positioning */ 16760786Sps *sc_clear, /* Clear screen */ 16860786Sps *sc_eol_clear, /* Clear to end of line */ 16960786Sps *sc_eos_clear, /* Clear to end of screen */ 17060786Sps *sc_s_in, /* Enter standout (highlighted) mode */ 17160786Sps *sc_s_out, /* Exit standout mode */ 17260786Sps *sc_u_in, /* Enter underline mode */ 17360786Sps *sc_u_out, /* Exit underline mode */ 17460786Sps *sc_b_in, /* Enter bold mode */ 17560786Sps *sc_b_out, /* Exit bold mode */ 17660786Sps *sc_bl_in, /* Enter blink mode */ 17760786Sps *sc_bl_out, /* Exit blink mode */ 17860786Sps *sc_visual_bell, /* Visual bell (flash screen) sequence */ 17960786Sps *sc_backspace, /* Backspace cursor */ 18060786Sps *sc_s_keypad, /* Start keypad mode */ 18160786Sps *sc_e_keypad, /* End keypad mode */ 18260786Sps *sc_init, /* Startup terminal initialization */ 18360786Sps *sc_deinit; /* Exit terminal de-initialization */ 18460786Sps#endif 18560786Sps 18660786Spsstatic int init_done = 0; 18760786Sps 18860786Spspublic int auto_wrap; /* Terminal does \r\n when write past margin */ 18960786Spspublic int ignaw; /* Terminal ignores \n immediately after wrap */ 190161478Sdelphijpublic int erase_char; /* The user's erase char */ 191161478Sdelphijpublic int erase2_char; /* The user's other erase char */ 192161478Sdelphijpublic int kill_char; /* The user's line-kill char */ 19360786Spspublic int werase_char; /* The user's word-erase char */ 19460786Spspublic int sc_width, sc_height; /* Height & width of screen */ 19560786Spspublic int bo_s_width, bo_e_width; /* Printing width of boldface seq */ 19660786Spspublic int ul_s_width, ul_e_width; /* Printing width of underline seq */ 19760786Spspublic int so_s_width, so_e_width; /* Printing width of standout seq */ 19860786Spspublic int bl_s_width, bl_e_width; /* Printing width of blink seq */ 19960786Spspublic int above_mem, below_mem; /* Memory retained above/below screen */ 20060786Spspublic int can_goto_line; /* Can move cursor to any line */ 20160786Spspublic int clear_bg; /* Clear fills with background color */ 20260786Spspublic int missing_cap = 0; /* Some capability is missing */ 20360786Sps 20460786Spsstatic int attrmode = AT_NORMAL; 205161478Sdelphijextern int binattr; 20660786Sps 20760786Sps#if !MSDOS_COMPILER 20860786Spsstatic char *cheaper(); 20960786Spsstatic void tmodes(); 21060786Sps#endif 21160786Sps 21260786Sps/* 21360786Sps * These two variables are sometimes defined in, 21460786Sps * and needed by, the termcap library. 21560786Sps */ 21660786Sps#if MUST_DEFINE_OSPEED 21760786Spsextern short ospeed; /* Terminal output baud rate */ 21860786Spsextern char PC; /* Pad character */ 21960786Sps#endif 22060786Sps#ifdef _OSK 22160786Spsshort ospeed; 22260786Spschar PC_, *UP, *BC; 22360786Sps#endif 22460786Sps 22560786Spsextern int quiet; /* If VERY_QUIET, use visual bell for bell */ 22660786Spsextern int no_back_scroll; 22760786Spsextern int swindow; 22860786Spsextern int no_init; 22989022Spsextern int no_keypad; 23060786Spsextern int sigs; 23160786Spsextern int wscroll; 23260786Spsextern int screen_trashed; 233128348Stjrextern int tty; 234161478Sdelphijextern int top_scroll; 235170259Sdelphijextern int oldbot; 23660786Sps#if HILITE_SEARCH 23760786Spsextern int hilite_search; 23860786Sps#endif 23960786Sps 24060786Spsextern char *tgetstr(); 24160786Spsextern char *tgoto(); 24260786Sps 24360786Sps 24460786Sps/* 24560786Sps * Change terminal to "raw mode", or restore to "normal" mode. 24660786Sps * "Raw mode" means 24760786Sps * 1. An outstanding read will complete on receipt of a single keystroke. 24860786Sps * 2. Input is not echoed. 24960786Sps * 3. On output, \n is mapped to \r\n. 25060786Sps * 4. \t is NOT expanded into spaces. 25160786Sps * 5. Signal-causing characters such as ctrl-C (interrupt), 25260786Sps * etc. are NOT disabled. 25360786Sps * It doesn't matter whether an input \n is mapped to \r, or vice versa. 25460786Sps */ 25560786Sps public void 25660786Spsraw_mode(on) 25760786Sps int on; 25860786Sps{ 25960786Sps static int curr_on = 0; 26060786Sps 26160786Sps if (on == curr_on) 26260786Sps return; 263161478Sdelphij erase2_char = '\b'; /* in case OS doesn't know about erase2 */ 26460786Sps#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 26560786Sps { 26660786Sps struct termios s; 26760786Sps static struct termios save_term; 26860786Sps static int saved_term = 0; 26960786Sps 27060786Sps if (on) 27160786Sps { 27260786Sps /* 27360786Sps * Get terminal modes. 27460786Sps */ 275128348Stjr tcgetattr(tty, &s); 27660786Sps 27760786Sps /* 27860786Sps * Save modes and set certain variables dependent on modes. 27960786Sps */ 28060786Sps if (!saved_term) 28160786Sps { 28260786Sps save_term = s; 28360786Sps saved_term = 1; 28460786Sps } 28560786Sps#if HAVE_OSPEED 28660786Sps switch (cfgetospeed(&s)) 28760786Sps { 28860786Sps#ifdef B0 28960786Sps case B0: ospeed = 0; break; 29060786Sps#endif 29160786Sps#ifdef B50 29260786Sps case B50: ospeed = 1; break; 29360786Sps#endif 29460786Sps#ifdef B75 29560786Sps case B75: ospeed = 2; break; 29660786Sps#endif 29760786Sps#ifdef B110 29860786Sps case B110: ospeed = 3; break; 29960786Sps#endif 30060786Sps#ifdef B134 30160786Sps case B134: ospeed = 4; break; 30260786Sps#endif 30360786Sps#ifdef B150 30460786Sps case B150: ospeed = 5; break; 30560786Sps#endif 30660786Sps#ifdef B200 30760786Sps case B200: ospeed = 6; break; 30860786Sps#endif 30960786Sps#ifdef B300 31060786Sps case B300: ospeed = 7; break; 31160786Sps#endif 31260786Sps#ifdef B600 31360786Sps case B600: ospeed = 8; break; 31460786Sps#endif 31560786Sps#ifdef B1200 31660786Sps case B1200: ospeed = 9; break; 31760786Sps#endif 31860786Sps#ifdef B1800 31960786Sps case B1800: ospeed = 10; break; 32060786Sps#endif 32160786Sps#ifdef B2400 32260786Sps case B2400: ospeed = 11; break; 32360786Sps#endif 32460786Sps#ifdef B4800 32560786Sps case B4800: ospeed = 12; break; 32660786Sps#endif 32760786Sps#ifdef B9600 32860786Sps case B9600: ospeed = 13; break; 32960786Sps#endif 33060786Sps#ifdef EXTA 33160786Sps case EXTA: ospeed = 14; break; 33260786Sps#endif 33360786Sps#ifdef EXTB 33460786Sps case EXTB: ospeed = 15; break; 33560786Sps#endif 33660786Sps#ifdef B57600 33760786Sps case B57600: ospeed = 16; break; 33860786Sps#endif 33960786Sps#ifdef B115200 34060786Sps case B115200: ospeed = 17; break; 34160786Sps#endif 34260786Sps default: ; 34360786Sps } 34460786Sps#endif 34560786Sps erase_char = s.c_cc[VERASE]; 346161478Sdelphij#ifdef VERASE2 347161478Sdelphij erase2_char = s.c_cc[VERASE2]; 348161478Sdelphij#endif 34960786Sps kill_char = s.c_cc[VKILL]; 35060786Sps#ifdef VWERASE 35160786Sps werase_char = s.c_cc[VWERASE]; 35260786Sps#else 35360786Sps werase_char = CONTROL('W'); 35460786Sps#endif 35560786Sps 35660786Sps /* 35760786Sps * Set the modes to the way we want them. 35860786Sps */ 35960786Sps s.c_lflag &= ~(0 36060786Sps#ifdef ICANON 36160786Sps | ICANON 36260786Sps#endif 36360786Sps#ifdef ECHO 36460786Sps | ECHO 36560786Sps#endif 36660786Sps#ifdef ECHOE 36760786Sps | ECHOE 36860786Sps#endif 36960786Sps#ifdef ECHOK 37060786Sps | ECHOK 37160786Sps#endif 37260786Sps#if ECHONL 37360786Sps | ECHONL 37460786Sps#endif 37560786Sps ); 37660786Sps 37760786Sps s.c_oflag |= (0 37860786Sps#ifdef OXTABS 37960786Sps | OXTABS 38060786Sps#else 38160786Sps#ifdef TAB3 38260786Sps | TAB3 38360786Sps#else 38460786Sps#ifdef XTABS 38560786Sps | XTABS 38660786Sps#endif 38760786Sps#endif 38860786Sps#endif 38960786Sps#ifdef OPOST 39060786Sps | OPOST 39160786Sps#endif 39260786Sps#ifdef ONLCR 39360786Sps | ONLCR 39460786Sps#endif 39560786Sps ); 39660786Sps 39760786Sps s.c_oflag &= ~(0 39860786Sps#ifdef ONOEOT 39960786Sps | ONOEOT 40060786Sps#endif 40160786Sps#ifdef OCRNL 40260786Sps | OCRNL 40360786Sps#endif 40460786Sps#ifdef ONOCR 40560786Sps | ONOCR 40660786Sps#endif 40760786Sps#ifdef ONLRET 40860786Sps | ONLRET 40960786Sps#endif 41060786Sps ); 41160786Sps s.c_cc[VMIN] = 1; 41260786Sps s.c_cc[VTIME] = 0; 41360786Sps#ifdef VLNEXT 41460786Sps s.c_cc[VLNEXT] = 0; 41560786Sps#endif 41660786Sps#ifdef VDSUSP 41760786Sps s.c_cc[VDSUSP] = 0; 41860786Sps#endif 41960786Sps#if MUST_SET_LINE_DISCIPLINE 42060786Sps /* 42160786Sps * System's termios is broken; need to explicitly 42260786Sps * request TERMIODISC line discipline. 42360786Sps */ 42460786Sps s.c_line = TERMIODISC; 42560786Sps#endif 42660786Sps } else 42760786Sps { 42860786Sps /* 42960786Sps * Restore saved modes. 43060786Sps */ 43160786Sps s = save_term; 43260786Sps } 43389022Sps#if HAVE_FSYNC 434128348Stjr fsync(tty); 43589022Sps#endif 436128348Stjr tcsetattr(tty, TCSADRAIN, &s); 43760786Sps#if MUST_SET_LINE_DISCIPLINE 43860786Sps if (!on) 43960786Sps { 44060786Sps /* 44160786Sps * Broken termios *ignores* any line discipline 44260786Sps * except TERMIODISC. A different old line discipline 44360786Sps * is therefore not restored, yet. Restore the old 44460786Sps * line discipline by hand. 44560786Sps */ 446128348Stjr ioctl(tty, TIOCSETD, &save_term.c_line); 44760786Sps } 44860786Sps#endif 44960786Sps } 45060786Sps#else 45160786Sps#ifdef TCGETA 45260786Sps { 45360786Sps struct termio s; 45460786Sps static struct termio save_term; 45560786Sps static int saved_term = 0; 45660786Sps 45760786Sps if (on) 45860786Sps { 45960786Sps /* 46060786Sps * Get terminal modes. 46160786Sps */ 462128348Stjr ioctl(tty, TCGETA, &s); 46360786Sps 46460786Sps /* 46560786Sps * Save modes and set certain variables dependent on modes. 46660786Sps */ 46760786Sps if (!saved_term) 46860786Sps { 46960786Sps save_term = s; 47060786Sps saved_term = 1; 47160786Sps } 47260786Sps#if HAVE_OSPEED 47360786Sps ospeed = s.c_cflag & CBAUD; 47460786Sps#endif 47560786Sps erase_char = s.c_cc[VERASE]; 47660786Sps kill_char = s.c_cc[VKILL]; 47760786Sps#ifdef VWERASE 47860786Sps werase_char = s.c_cc[VWERASE]; 47960786Sps#else 48060786Sps werase_char = CONTROL('W'); 48160786Sps#endif 48260786Sps 48360786Sps /* 48460786Sps * Set the modes to the way we want them. 48560786Sps */ 48660786Sps s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); 48760786Sps s.c_oflag |= (OPOST|ONLCR|TAB3); 48860786Sps s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); 48960786Sps s.c_cc[VMIN] = 1; 49060786Sps s.c_cc[VTIME] = 0; 49160786Sps } else 49260786Sps { 49360786Sps /* 49460786Sps * Restore saved modes. 49560786Sps */ 49660786Sps s = save_term; 49760786Sps } 498128348Stjr ioctl(tty, TCSETAW, &s); 49960786Sps } 50060786Sps#else 50160786Sps#ifdef TIOCGETP 50260786Sps { 50360786Sps struct sgttyb s; 50460786Sps static struct sgttyb save_term; 50560786Sps static int saved_term = 0; 50660786Sps 50760786Sps if (on) 50860786Sps { 50960786Sps /* 51060786Sps * Get terminal modes. 51160786Sps */ 512128348Stjr ioctl(tty, TIOCGETP, &s); 51360786Sps 51460786Sps /* 51560786Sps * Save modes and set certain variables dependent on modes. 51660786Sps */ 51760786Sps if (!saved_term) 51860786Sps { 51960786Sps save_term = s; 52060786Sps saved_term = 1; 52160786Sps } 52260786Sps#if HAVE_OSPEED 52360786Sps ospeed = s.sg_ospeed; 52460786Sps#endif 52560786Sps erase_char = s.sg_erase; 52660786Sps kill_char = s.sg_kill; 52760786Sps werase_char = CONTROL('W'); 52860786Sps 52960786Sps /* 53060786Sps * Set the modes to the way we want them. 53160786Sps */ 53260786Sps s.sg_flags |= CBREAK; 53360786Sps s.sg_flags &= ~(ECHO|XTABS); 53460786Sps } else 53560786Sps { 53660786Sps /* 53760786Sps * Restore saved modes. 53860786Sps */ 53960786Sps s = save_term; 54060786Sps } 541128348Stjr ioctl(tty, TIOCSETN, &s); 54260786Sps } 54360786Sps#else 54460786Sps#ifdef _OSK 54560786Sps { 54660786Sps struct sgbuf s; 54760786Sps static struct sgbuf save_term; 54860786Sps static int saved_term = 0; 54960786Sps 55060786Sps if (on) 55160786Sps { 55260786Sps /* 55360786Sps * Get terminal modes. 55460786Sps */ 555128348Stjr _gs_opt(tty, &s); 55660786Sps 55760786Sps /* 55860786Sps * Save modes and set certain variables dependent on modes. 55960786Sps */ 56060786Sps if (!saved_term) 56160786Sps { 56260786Sps save_term = s; 56360786Sps saved_term = 1; 56460786Sps } 56560786Sps erase_char = s.sg_bspch; 56660786Sps kill_char = s.sg_dlnch; 56760786Sps werase_char = CONTROL('W'); 56860786Sps 56960786Sps /* 57060786Sps * Set the modes to the way we want them. 57160786Sps */ 57260786Sps s.sg_echo = 0; 57360786Sps s.sg_eofch = 0; 57460786Sps s.sg_pause = 0; 57560786Sps s.sg_psch = 0; 57660786Sps } else 57760786Sps { 57860786Sps /* 57960786Sps * Restore saved modes. 58060786Sps */ 58160786Sps s = save_term; 58260786Sps } 583128348Stjr _ss_opt(tty, &s); 58460786Sps } 58560786Sps#else 58660786Sps /* MS-DOS, Windows, or OS2 */ 58760786Sps#if OS2 58860786Sps /* OS2 */ 58960786Sps LSIGNAL(SIGINT, SIG_IGN); 59060786Sps#endif 59160786Sps erase_char = '\b'; 59260786Sps#if MSDOS_COMPILER==DJGPPC 59360786Sps kill_char = CONTROL('U'); 59460786Sps /* 59560786Sps * So that when we shell out or run another program, its 59660786Sps * stdin is in cooked mode. We do not switch stdin to binary 59760786Sps * mode if fd0 is zero, since that means we were called before 59860786Sps * tty was reopened in open_getchr, in which case we would be 59960786Sps * changing the original stdin device outside less. 60060786Sps */ 60160786Sps if (fd0 != 0) 60260786Sps setmode(0, on ? O_BINARY : O_TEXT); 60360786Sps#else 60460786Sps kill_char = ESC; 60560786Sps#endif 60660786Sps werase_char = CONTROL('W'); 60760786Sps#endif 60860786Sps#endif 60960786Sps#endif 61060786Sps#endif 61160786Sps curr_on = on; 61260786Sps} 61360786Sps 61460786Sps#if !MSDOS_COMPILER 61560786Sps/* 61660786Sps * Some glue to prevent calling termcap functions if tgetent() failed. 61760786Sps */ 61860786Spsstatic int hardcopy; 61960786Sps 62060786Sps static char * 62160786Spsltget_env(capname) 62260786Sps char *capname; 62360786Sps{ 62460786Sps char name[16]; 625170967Sdelphij char *s; 62660786Sps 627170967Sdelphij s = lgetenv("LESS_TERMCAP_DEBUG"); 628170967Sdelphij if (s != NULL && *s != '\0') 629170967Sdelphij { 630170967Sdelphij struct env { struct env *next; char *name; char *value; }; 631170967Sdelphij static struct env *envs = NULL; 632170967Sdelphij struct env *p; 633170967Sdelphij for (p = envs; p != NULL; p = p->next) 634170967Sdelphij if (strcmp(p->name, capname) == 0) 635170967Sdelphij return p->value; 636170967Sdelphij p = (struct env *) ecalloc(1, sizeof(struct env)); 637170967Sdelphij p->name = save(capname); 638170967Sdelphij p->value = (char *) ecalloc(strlen(capname)+3, sizeof(char)); 639170967Sdelphij sprintf(p->value, "<%s>", capname); 640170967Sdelphij p->next = envs; 641170967Sdelphij envs = p; 642170967Sdelphij return p->value; 643170967Sdelphij } 64460786Sps strcpy(name, "LESS_TERMCAP_"); 64560786Sps strcat(name, capname); 64660786Sps return (lgetenv(name)); 64760786Sps} 64860786Sps 64960786Sps static int 65060786Spsltgetflag(capname) 65160786Sps char *capname; 65260786Sps{ 65360786Sps char *s; 65460786Sps 65560786Sps if ((s = ltget_env(capname)) != NULL) 65660786Sps return (*s != '\0' && *s != '0'); 65760786Sps if (hardcopy) 65860786Sps return (0); 65960786Sps return (tgetflag(capname)); 66060786Sps} 66160786Sps 66260786Sps static int 66360786Spsltgetnum(capname) 66460786Sps char *capname; 66560786Sps{ 66660786Sps char *s; 66760786Sps 66860786Sps if ((s = ltget_env(capname)) != NULL) 66960786Sps return (atoi(s)); 67060786Sps if (hardcopy) 67160786Sps return (-1); 67260786Sps return (tgetnum(capname)); 67360786Sps} 67460786Sps 67560786Sps static char * 67660786Spsltgetstr(capname, pp) 67760786Sps char *capname; 67860786Sps char **pp; 67960786Sps{ 68060786Sps char *s; 68160786Sps 68260786Sps if ((s = ltget_env(capname)) != NULL) 68360786Sps return (s); 68460786Sps if (hardcopy) 68560786Sps return (NULL); 68660786Sps return (tgetstr(capname, pp)); 68760786Sps} 68860786Sps#endif /* MSDOS_COMPILER */ 68960786Sps 69060786Sps/* 69160786Sps * Get size of the output screen. 69260786Sps */ 69360786Sps public void 69460786Spsscrsize() 69560786Sps{ 69660786Sps register char *s; 69760786Sps int sys_height; 69860786Sps int sys_width; 69960786Sps#if !MSDOS_COMPILER 70060786Sps int n; 70160786Sps#endif 70260786Sps 70360786Sps#define DEF_SC_WIDTH 80 70460786Sps#if MSDOS_COMPILER 70560786Sps#define DEF_SC_HEIGHT 25 70660786Sps#else 70760786Sps#define DEF_SC_HEIGHT 24 70860786Sps#endif 70960786Sps 71060786Sps 71160786Sps sys_width = sys_height = 0; 71260786Sps 71360786Sps#if MSDOS_COMPILER==MSOFTC 71460786Sps { 71560786Sps struct videoconfig w; 71660786Sps _getvideoconfig(&w); 71760786Sps sys_height = w.numtextrows; 71860786Sps sys_width = w.numtextcols; 71960786Sps } 72060786Sps#else 72160786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 72260786Sps { 72360786Sps struct text_info w; 72460786Sps gettextinfo(&w); 72560786Sps sys_height = w.screenheight; 72660786Sps sys_width = w.screenwidth; 72760786Sps } 72860786Sps#else 72960786Sps#if MSDOS_COMPILER==WIN32C 73060786Sps { 73160786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 73260786Sps GetConsoleScreenBufferInfo(con_out, &scr); 73360786Sps sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1; 73460786Sps sys_width = scr.srWindow.Right - scr.srWindow.Left + 1; 73560786Sps } 73660786Sps#else 73760786Sps#if OS2 73860786Sps { 73960786Sps int s[2]; 74060786Sps _scrsize(s); 74160786Sps sys_width = s[0]; 74260786Sps sys_height = s[1]; 74389022Sps /* 74489022Sps * When using terminal emulators for XFree86/OS2, the 74589022Sps * _scrsize function does not work well. 74689022Sps * Call the scrsize.exe program to get the window size. 74789022Sps */ 74889022Sps windowid = getenv("WINDOWID"); 74989022Sps if (windowid != NULL) 75089022Sps { 75189022Sps FILE *fd = popen("scrsize", "rt"); 75289022Sps if (fd != NULL) 75389022Sps { 75489022Sps int w, h; 75589022Sps fscanf(fd, "%i %i", &w, &h); 75689022Sps if (w > 0 && h > 0) 75789022Sps { 75889022Sps sys_width = w; 75989022Sps sys_height = h; 76089022Sps } 76189022Sps pclose(fd); 76289022Sps } 76389022Sps } 76460786Sps } 76560786Sps#else 76660786Sps#ifdef TIOCGWINSZ 76760786Sps { 76860786Sps struct winsize w; 76960786Sps if (ioctl(2, TIOCGWINSZ, &w) == 0) 77060786Sps { 77160786Sps if (w.ws_row > 0) 77260786Sps sys_height = w.ws_row; 77360786Sps if (w.ws_col > 0) 77460786Sps sys_width = w.ws_col; 77560786Sps } 77660786Sps } 77760786Sps#else 77860786Sps#ifdef WIOCGETD 77960786Sps { 78060786Sps struct uwdata w; 78160786Sps if (ioctl(2, WIOCGETD, &w) == 0) 78260786Sps { 78360786Sps if (w.uw_height > 0) 78460786Sps sys_height = w.uw_height / w.uw_vs; 78560786Sps if (w.uw_width > 0) 78660786Sps sys_width = w.uw_width / w.uw_hs; 78760786Sps } 78860786Sps } 78960786Sps#endif 79060786Sps#endif 79160786Sps#endif 79260786Sps#endif 79360786Sps#endif 79460786Sps#endif 79560786Sps 79660786Sps if (sys_height > 0) 79760786Sps sc_height = sys_height; 79860786Sps else if ((s = lgetenv("LINES")) != NULL) 79960786Sps sc_height = atoi(s); 80060786Sps#if !MSDOS_COMPILER 80160786Sps else if ((n = ltgetnum("li")) > 0) 80260786Sps sc_height = n; 80360786Sps#endif 804242584Sdelphij if (sc_height <= 0) 80560786Sps sc_height = DEF_SC_HEIGHT; 80660786Sps 80760786Sps if (sys_width > 0) 80860786Sps sc_width = sys_width; 80960786Sps else if ((s = lgetenv("COLUMNS")) != NULL) 81060786Sps sc_width = atoi(s); 81160786Sps#if !MSDOS_COMPILER 81260786Sps else if ((n = ltgetnum("co")) > 0) 81360786Sps sc_width = n; 81460786Sps#endif 815242584Sdelphij if (sc_width <= 0) 81660786Sps sc_width = DEF_SC_WIDTH; 81760786Sps} 81860786Sps 81960786Sps#if MSDOS_COMPILER==MSOFTC 82060786Sps/* 82160786Sps * Figure out how many empty loops it takes to delay a millisecond. 82260786Sps */ 82360786Sps static void 82460786Spsget_clock() 82560786Sps{ 82660786Sps clock_t start; 82760786Sps 82860786Sps /* 82960786Sps * Get synchronized at the start of a tick. 83060786Sps */ 83160786Sps start = clock(); 83260786Sps while (clock() == start) 83360786Sps ; 83460786Sps /* 83560786Sps * Now count loops till the next tick. 83660786Sps */ 83760786Sps start = clock(); 83860786Sps msec_loops = 0; 83960786Sps while (clock() == start) 84060786Sps msec_loops++; 84160786Sps /* 84260786Sps * Convert from (loops per clock) to (loops per millisecond). 84360786Sps */ 84460786Sps msec_loops *= CLOCKS_PER_SEC; 84560786Sps msec_loops /= 1000; 84660786Sps} 84760786Sps 84860786Sps/* 84960786Sps * Delay for a specified number of milliseconds. 85060786Sps */ 85160786Sps static void 85260786Spsdummy_func() 85360786Sps{ 85460786Sps static long delay_dummy = 0; 85560786Sps delay_dummy++; 85660786Sps} 85760786Sps 85860786Sps static void 85960786Spsdelay(msec) 86060786Sps int msec; 86160786Sps{ 86260786Sps long i; 86360786Sps 86460786Sps while (msec-- > 0) 86560786Sps { 86660786Sps for (i = 0; i < msec_loops; i++) 86760786Sps { 86860786Sps /* 86960786Sps * Make it look like we're doing something here, 87060786Sps * so the optimizer doesn't remove the whole loop. 87160786Sps */ 87260786Sps dummy_func(); 87360786Sps } 87460786Sps } 87560786Sps} 87660786Sps#endif 87760786Sps 87860786Sps/* 87960786Sps * Return the characters actually input by a "special" key. 88060786Sps */ 88160786Sps public char * 88260786Spsspecial_key_str(key) 88360786Sps int key; 88460786Sps{ 88560786Sps static char tbuf[40]; 88660786Sps char *s; 88789022Sps#if MSDOS_COMPILER || OS2 88860786Sps static char k_right[] = { '\340', PCK_RIGHT, 0 }; 88960786Sps static char k_left[] = { '\340', PCK_LEFT, 0 }; 89060786Sps static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; 89160786Sps static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; 89260786Sps static char k_insert[] = { '\340', PCK_INSERT, 0 }; 89360786Sps static char k_delete[] = { '\340', PCK_DELETE, 0 }; 89460786Sps static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; 89560786Sps static char k_ctl_backspace[] = { '\177', 0 }; 89660786Sps static char k_home[] = { '\340', PCK_HOME, 0 }; 89760786Sps static char k_end[] = { '\340', PCK_END, 0 }; 89860786Sps static char k_up[] = { '\340', PCK_UP, 0 }; 89960786Sps static char k_down[] = { '\340', PCK_DOWN, 0 }; 90060786Sps static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; 90160786Sps static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; 90260786Sps static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; 90360786Sps static char k_f1[] = { '\340', PCK_F1, 0 }; 90489022Sps#endif 90589022Sps#if !MSDOS_COMPILER 90660786Sps char *sp = tbuf; 90760786Sps#endif 90860786Sps 90960786Sps switch (key) 91060786Sps { 91189022Sps#if OS2 91289022Sps /* 91389022Sps * If windowid is not NULL, assume less is executed in 91489022Sps * the XFree86 environment. 91589022Sps */ 91689022Sps case SK_RIGHT_ARROW: 91789022Sps s = windowid ? ltgetstr("kr", &sp) : k_right; 91889022Sps break; 91989022Sps case SK_LEFT_ARROW: 92089022Sps s = windowid ? ltgetstr("kl", &sp) : k_left; 92189022Sps break; 92289022Sps case SK_UP_ARROW: 92389022Sps s = windowid ? ltgetstr("ku", &sp) : k_up; 92489022Sps break; 92589022Sps case SK_DOWN_ARROW: 92689022Sps s = windowid ? ltgetstr("kd", &sp) : k_down; 92789022Sps break; 92889022Sps case SK_PAGE_UP: 92989022Sps s = windowid ? ltgetstr("kP", &sp) : k_pageup; 93089022Sps break; 93189022Sps case SK_PAGE_DOWN: 93289022Sps s = windowid ? ltgetstr("kN", &sp) : k_pagedown; 93389022Sps break; 93489022Sps case SK_HOME: 93589022Sps s = windowid ? ltgetstr("kh", &sp) : k_home; 93689022Sps break; 93789022Sps case SK_END: 93889022Sps s = windowid ? ltgetstr("@7", &sp) : k_end; 93989022Sps break; 94089022Sps case SK_DELETE: 94189022Sps if (windowid) 94289022Sps { 94389022Sps s = ltgetstr("kD", &sp); 94489022Sps if (s == NULL) 94589022Sps { 94689022Sps tbuf[0] = '\177'; 94789022Sps tbuf[1] = '\0'; 94889022Sps s = tbuf; 94989022Sps } 95089022Sps } else 95189022Sps s = k_delete; 95289022Sps break; 95389022Sps#endif 95460786Sps#if MSDOS_COMPILER 95560786Sps case SK_RIGHT_ARROW: 95660786Sps s = k_right; 95760786Sps break; 95860786Sps case SK_LEFT_ARROW: 95960786Sps s = k_left; 96060786Sps break; 96160786Sps case SK_UP_ARROW: 96260786Sps s = k_up; 96360786Sps break; 96460786Sps case SK_DOWN_ARROW: 96560786Sps s = k_down; 96660786Sps break; 96760786Sps case SK_PAGE_UP: 96860786Sps s = k_pageup; 96960786Sps break; 97060786Sps case SK_PAGE_DOWN: 97160786Sps s = k_pagedown; 97260786Sps break; 97360786Sps case SK_HOME: 97460786Sps s = k_home; 97560786Sps break; 97660786Sps case SK_END: 97760786Sps s = k_end; 97860786Sps break; 97960786Sps case SK_DELETE: 98060786Sps s = k_delete; 98160786Sps break; 98289022Sps#endif 98389022Sps#if MSDOS_COMPILER || OS2 98460786Sps case SK_INSERT: 98560786Sps s = k_insert; 98660786Sps break; 98760786Sps case SK_CTL_LEFT_ARROW: 98860786Sps s = k_ctl_left; 98960786Sps break; 99060786Sps case SK_CTL_RIGHT_ARROW: 99160786Sps s = k_ctl_right; 99260786Sps break; 99360786Sps case SK_CTL_BACKSPACE: 99460786Sps s = k_ctl_backspace; 99560786Sps break; 99660786Sps case SK_CTL_DELETE: 99760786Sps s = k_ctl_delete; 99860786Sps break; 99960786Sps case SK_F1: 100060786Sps s = k_f1; 100160786Sps break; 100260786Sps case SK_BACKTAB: 100360786Sps s = k_backtab; 100460786Sps break; 100560786Sps#else 100660786Sps case SK_RIGHT_ARROW: 100760786Sps s = ltgetstr("kr", &sp); 100860786Sps break; 100960786Sps case SK_LEFT_ARROW: 101060786Sps s = ltgetstr("kl", &sp); 101160786Sps break; 101260786Sps case SK_UP_ARROW: 101360786Sps s = ltgetstr("ku", &sp); 101460786Sps break; 101560786Sps case SK_DOWN_ARROW: 101660786Sps s = ltgetstr("kd", &sp); 101760786Sps break; 101860786Sps case SK_PAGE_UP: 101960786Sps s = ltgetstr("kP", &sp); 102060786Sps break; 102160786Sps case SK_PAGE_DOWN: 102260786Sps s = ltgetstr("kN", &sp); 102360786Sps break; 102460786Sps case SK_HOME: 102560786Sps s = ltgetstr("kh", &sp); 102660786Sps break; 102760786Sps case SK_END: 102860786Sps s = ltgetstr("@7", &sp); 102960786Sps break; 103060786Sps case SK_DELETE: 103160786Sps s = ltgetstr("kD", &sp); 103260786Sps if (s == NULL) 103360786Sps { 103460786Sps tbuf[0] = '\177'; 103560786Sps tbuf[1] = '\0'; 103660786Sps s = tbuf; 103760786Sps } 103860786Sps break; 103960786Sps#endif 104060786Sps case SK_CONTROL_K: 104160786Sps tbuf[0] = CONTROL('K'); 104260786Sps tbuf[1] = '\0'; 104360786Sps s = tbuf; 104460786Sps break; 104560786Sps default: 104660786Sps return (NULL); 104760786Sps } 104860786Sps return (s); 104960786Sps} 105060786Sps 105160786Sps/* 105260786Sps * Get terminal capabilities via termcap. 105360786Sps */ 105460786Sps public void 105560786Spsget_term() 105660786Sps{ 105760786Sps#if MSDOS_COMPILER 105860786Sps auto_wrap = 1; 105960786Sps ignaw = 0; 106060786Sps can_goto_line = 1; 106160786Sps clear_bg = 1; 106260786Sps /* 106360786Sps * Set up default colors. 106460786Sps * The xx_s_width and xx_e_width vars are already initialized to 0. 106560786Sps */ 106660786Sps#if MSDOS_COMPILER==MSOFTC 106760786Sps sy_bg_color = _getbkcolor(); 106860786Sps sy_fg_color = _gettextcolor(); 106960786Sps get_clock(); 107060786Sps#else 107160786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 107260786Sps { 107360786Sps struct text_info w; 107460786Sps gettextinfo(&w); 107560786Sps sy_bg_color = (w.attribute >> 4) & 0x0F; 107660786Sps sy_fg_color = (w.attribute >> 0) & 0x0F; 107760786Sps } 107860786Sps#else 107960786Sps#if MSDOS_COMPILER==WIN32C 108060786Sps { 108160786Sps DWORD nread; 108260786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 108360786Sps 108460786Sps con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE); 108560786Sps /* 108660786Sps * Always open stdin in binary. Note this *must* be done 108760786Sps * before any file operations have been done on fd0. 108860786Sps */ 108960786Sps SET_BINARY(0); 109060786Sps GetConsoleScreenBufferInfo(con_out, &scr); 109160786Sps ReadConsoleOutputAttribute(con_out, &curr_attr, 109260786Sps 1, scr.dwCursorPosition, &nread); 109360786Sps sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */ 109460786Sps sy_fg_color = curr_attr & FG_COLORS; 109560786Sps } 109660786Sps#endif 109760786Sps#endif 109860786Sps#endif 109960786Sps nm_fg_color = sy_fg_color; 110060786Sps nm_bg_color = sy_bg_color; 110160786Sps bo_fg_color = 11; 110260786Sps bo_bg_color = 0; 110360786Sps ul_fg_color = 9; 110460786Sps ul_bg_color = 0; 110560786Sps so_fg_color = 15; 110660786Sps so_bg_color = 9; 110760786Sps bl_fg_color = 15; 110860786Sps bl_bg_color = 0; 110960786Sps 111060786Sps /* 111160786Sps * Get size of the screen. 111260786Sps */ 111360786Sps scrsize(); 111460786Sps pos_init(); 111560786Sps 111660786Sps 111760786Sps#else /* !MSDOS_COMPILER */ 111860786Sps 111960786Sps char *sp; 112060786Sps register char *t1, *t2; 112160786Sps char *term; 112260786Sps char termbuf[TERMBUF_SIZE]; 112360786Sps 112460786Sps static char sbuf[TERMSBUF_SIZE]; 112560786Sps 112660786Sps#if OS2 112760786Sps /* 112860786Sps * Make sure the termcap database is available. 112960786Sps */ 113060786Sps sp = lgetenv("TERMCAP"); 113160786Sps if (sp == NULL || *sp == '\0') 113260786Sps { 113360786Sps char *termcap; 113460786Sps if ((sp = homefile("termcap.dat")) != NULL) 113560786Sps { 113660786Sps termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char)); 113760786Sps sprintf(termcap, "TERMCAP=%s", sp); 113860786Sps free(sp); 113960786Sps putenv(termcap); 114060786Sps } 114160786Sps } 114260786Sps#endif 114360786Sps /* 114460786Sps * Find out what kind of terminal this is. 114560786Sps */ 114660786Sps if ((term = lgetenv("TERM")) == NULL) 114760786Sps term = DEFAULT_TERM; 114860786Sps hardcopy = 0; 1149170259Sdelphij if (tgetent(termbuf, term) != TGETENT_OK) 115060786Sps hardcopy = 1; 115160786Sps if (ltgetflag("hc")) 115260786Sps hardcopy = 1; 115360786Sps 115460786Sps /* 115560786Sps * Get size of the screen. 115660786Sps */ 115760786Sps scrsize(); 115860786Sps pos_init(); 115960786Sps 116060786Sps auto_wrap = ltgetflag("am"); 116160786Sps ignaw = ltgetflag("xn"); 116260786Sps above_mem = ltgetflag("da"); 116360786Sps below_mem = ltgetflag("db"); 116460786Sps clear_bg = ltgetflag("ut"); 116560786Sps 116660786Sps /* 116760786Sps * Assumes termcap variable "sg" is the printing width of: 116860786Sps * the standout sequence, the end standout sequence, 116960786Sps * the underline sequence, the end underline sequence, 117060786Sps * the boldface sequence, and the end boldface sequence. 117160786Sps */ 117260786Sps if ((so_s_width = ltgetnum("sg")) < 0) 117360786Sps so_s_width = 0; 117460786Sps so_e_width = so_s_width; 117560786Sps 117660786Sps bo_s_width = bo_e_width = so_s_width; 117760786Sps ul_s_width = ul_e_width = so_s_width; 117860786Sps bl_s_width = bl_e_width = so_s_width; 117960786Sps 118060786Sps#if HILITE_SEARCH 118160786Sps if (so_s_width > 0 || so_e_width > 0) 118260786Sps /* 118360786Sps * Disable highlighting by default on magic cookie terminals. 118460786Sps * Turning on highlighting might change the displayed width 118560786Sps * of a line, causing the display to get messed up. 118660786Sps * The user can turn it back on with -g, 118760786Sps * but she won't like the results. 118860786Sps */ 118960786Sps hilite_search = 0; 119060786Sps#endif 119160786Sps 119260786Sps /* 119360786Sps * Get various string-valued capabilities. 119460786Sps */ 119560786Sps sp = sbuf; 119660786Sps 119760786Sps#if HAVE_OSPEED 119860786Sps sc_pad = ltgetstr("pc", &sp); 119960786Sps if (sc_pad != NULL) 120060786Sps PC = *sc_pad; 120160786Sps#endif 120260786Sps 120360786Sps sc_s_keypad = ltgetstr("ks", &sp); 120460786Sps if (sc_s_keypad == NULL) 120560786Sps sc_s_keypad = ""; 120660786Sps sc_e_keypad = ltgetstr("ke", &sp); 120760786Sps if (sc_e_keypad == NULL) 120860786Sps sc_e_keypad = ""; 120960786Sps 1210171009Sdelphij sc_init = ltgetstr("ti", &sp); 121160786Sps if (sc_init == NULL) 121260786Sps sc_init = ""; 121360786Sps 1214171009Sdelphij sc_deinit= ltgetstr("te", &sp); 121560786Sps if (sc_deinit == NULL) 121660786Sps sc_deinit = ""; 121760786Sps 121860786Sps sc_eol_clear = ltgetstr("ce", &sp); 121960786Sps if (sc_eol_clear == NULL || *sc_eol_clear == '\0') 122060786Sps { 122160786Sps missing_cap = 1; 122260786Sps sc_eol_clear = ""; 122360786Sps } 122460786Sps 122560786Sps sc_eos_clear = ltgetstr("cd", &sp); 122660786Sps if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0')) 122760786Sps { 122860786Sps missing_cap = 1; 1229161478Sdelphij sc_eos_clear = ""; 123060786Sps } 123160786Sps 123260786Sps sc_clear = ltgetstr("cl", &sp); 123360786Sps if (sc_clear == NULL || *sc_clear == '\0') 123460786Sps { 123560786Sps missing_cap = 1; 123660786Sps sc_clear = "\n\n"; 123760786Sps } 123860786Sps 123960786Sps sc_move = ltgetstr("cm", &sp); 124060786Sps if (sc_move == NULL || *sc_move == '\0') 124160786Sps { 124260786Sps /* 124360786Sps * This is not an error here, because we don't 124460786Sps * always need sc_move. 124560786Sps * We need it only if we don't have home or lower-left. 124660786Sps */ 124760786Sps sc_move = ""; 124860786Sps can_goto_line = 0; 124960786Sps } else 125060786Sps can_goto_line = 1; 125160786Sps 125260786Sps tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp); 125360786Sps tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp); 125460786Sps tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp); 125560786Sps tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp); 125660786Sps 125760786Sps sc_visual_bell = ltgetstr("vb", &sp); 125860786Sps if (sc_visual_bell == NULL) 125960786Sps sc_visual_bell = ""; 126060786Sps 126160786Sps if (ltgetflag("bs")) 126260786Sps sc_backspace = "\b"; 126360786Sps else 126460786Sps { 126560786Sps sc_backspace = ltgetstr("bc", &sp); 126660786Sps if (sc_backspace == NULL || *sc_backspace == '\0') 126760786Sps sc_backspace = "\b"; 126860786Sps } 126960786Sps 127060786Sps /* 127160786Sps * Choose between using "ho" and "cm" ("home" and "cursor move") 127260786Sps * to move the cursor to the upper left corner of the screen. 127360786Sps */ 127460786Sps t1 = ltgetstr("ho", &sp); 127560786Sps if (t1 == NULL) 127660786Sps t1 = ""; 127760786Sps if (*sc_move == '\0') 127860786Sps t2 = ""; 127960786Sps else 128060786Sps { 128160786Sps strcpy(sp, tgoto(sc_move, 0, 0)); 128260786Sps t2 = sp; 128360786Sps sp += strlen(sp) + 1; 128460786Sps } 128560786Sps sc_home = cheaper(t1, t2, "|\b^"); 128660786Sps 128760786Sps /* 128860786Sps * Choose between using "ll" and "cm" ("lower left" and "cursor move") 128960786Sps * to move the cursor to the lower left corner of the screen. 129060786Sps */ 129160786Sps t1 = ltgetstr("ll", &sp); 129260786Sps if (t1 == NULL) 129360786Sps t1 = ""; 129460786Sps if (*sc_move == '\0') 129560786Sps t2 = ""; 129660786Sps else 129760786Sps { 129860786Sps strcpy(sp, tgoto(sc_move, 0, sc_height-1)); 129960786Sps t2 = sp; 130060786Sps sp += strlen(sp) + 1; 130160786Sps } 130260786Sps sc_lower_left = cheaper(t1, t2, "\r"); 130360786Sps 130460786Sps /* 1305170259Sdelphij * Get carriage return string. 1306170259Sdelphij */ 1307170259Sdelphij sc_return = ltgetstr("cr", &sp); 1308170259Sdelphij if (sc_return == NULL) 1309170259Sdelphij sc_return = "\r"; 1310170259Sdelphij 1311170259Sdelphij /* 131260786Sps * Choose between using "al" or "sr" ("add line" or "scroll reverse") 131360786Sps * to add a line at the top of the screen. 131460786Sps */ 131560786Sps t1 = ltgetstr("al", &sp); 131660786Sps if (t1 == NULL) 131760786Sps t1 = ""; 131860786Sps t2 = ltgetstr("sr", &sp); 131960786Sps if (t2 == NULL) 132060786Sps t2 = ""; 132160786Sps#if OS2 132260786Sps if (*t1 == '\0' && *t2 == '\0') 132360786Sps sc_addline = ""; 132460786Sps else 132560786Sps#endif 132660786Sps if (above_mem) 132760786Sps sc_addline = t1; 132860786Sps else 132960786Sps sc_addline = cheaper(t1, t2, ""); 133060786Sps if (*sc_addline == '\0') 133160786Sps { 133260786Sps /* 133360786Sps * Force repaint on any backward movement. 133460786Sps */ 133560786Sps no_back_scroll = 1; 133660786Sps } 133760786Sps#endif /* MSDOS_COMPILER */ 133860786Sps} 133960786Sps 134060786Sps#if !MSDOS_COMPILER 134160786Sps/* 134260786Sps * Return the cost of displaying a termcap string. 134360786Sps * We use the trick of calling tputs, but as a char printing function 134460786Sps * we give it inc_costcount, which just increments "costcount". 134560786Sps * This tells us how many chars would be printed by using this string. 134660786Sps * {{ Couldn't we just use strlen? }} 134760786Sps */ 134860786Spsstatic int costcount; 134960786Sps 135060786Sps/*ARGSUSED*/ 135160786Sps static int 135260786Spsinc_costcount(c) 135360786Sps int c; 135460786Sps{ 135560786Sps costcount++; 135660786Sps return (c); 135760786Sps} 135860786Sps 135960786Sps static int 136060786Spscost(t) 136160786Sps char *t; 136260786Sps{ 136360786Sps costcount = 0; 136460786Sps tputs(t, sc_height, inc_costcount); 136560786Sps return (costcount); 136660786Sps} 136760786Sps 136860786Sps/* 136960786Sps * Return the "best" of the two given termcap strings. 137060786Sps * The best, if both exist, is the one with the lower 137160786Sps * cost (see cost() function). 137260786Sps */ 137360786Sps static char * 137460786Spscheaper(t1, t2, def) 137560786Sps char *t1, *t2; 137660786Sps char *def; 137760786Sps{ 137860786Sps if (*t1 == '\0' && *t2 == '\0') 137960786Sps { 138060786Sps missing_cap = 1; 138160786Sps return (def); 138260786Sps } 138360786Sps if (*t1 == '\0') 138460786Sps return (t2); 138560786Sps if (*t2 == '\0') 138660786Sps return (t1); 138760786Sps if (cost(t1) < cost(t2)) 138860786Sps return (t1); 138960786Sps return (t2); 139060786Sps} 139160786Sps 139260786Sps static void 139360786Spstmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp) 139460786Sps char *incap; 139560786Sps char *outcap; 139660786Sps char **instr; 139760786Sps char **outstr; 139860786Sps char *def_instr; 139960786Sps char *def_outstr; 140060786Sps char **spp; 140160786Sps{ 140260786Sps *instr = ltgetstr(incap, spp); 140360786Sps if (*instr == NULL) 140460786Sps { 140560786Sps /* Use defaults. */ 140660786Sps *instr = def_instr; 140760786Sps *outstr = def_outstr; 140860786Sps return; 140960786Sps } 141060786Sps 141160786Sps *outstr = ltgetstr(outcap, spp); 141260786Sps if (*outstr == NULL) 141360786Sps /* No specific out capability; use "me". */ 141460786Sps *outstr = ltgetstr("me", spp); 141560786Sps if (*outstr == NULL) 141660786Sps /* Don't even have "me"; use a null string. */ 141760786Sps *outstr = ""; 141860786Sps} 141960786Sps 142060786Sps#endif /* MSDOS_COMPILER */ 142160786Sps 142260786Sps 142360786Sps/* 142460786Sps * Below are the functions which perform all the 142560786Sps * terminal-specific screen manipulation. 142660786Sps */ 142760786Sps 142860786Sps 142960786Sps#if MSDOS_COMPILER 143060786Sps 143160786Sps#if MSDOS_COMPILER==WIN32C 143260786Sps static void 143360786Sps_settextposition(int row, int col) 143460786Sps{ 143560786Sps COORD cpos; 143660786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 143760786Sps 143860786Sps GetConsoleScreenBufferInfo(con_out, &csbi); 143960786Sps cpos.X = csbi.srWindow.Left + (col - 1); 144060786Sps cpos.Y = csbi.srWindow.Top + (row - 1); 144160786Sps SetConsoleCursorPosition(con_out, cpos); 144260786Sps} 144360786Sps#endif 144460786Sps 144560786Sps/* 144660786Sps * Initialize the screen to the correct color at startup. 144760786Sps */ 144860786Sps static void 144960786Spsinitcolor() 145060786Sps{ 145160786Sps SETCOLORS(nm_fg_color, nm_bg_color); 145260786Sps#if 0 145360786Sps /* 145460786Sps * This clears the screen at startup. This is different from 145560786Sps * the behavior of other versions of less. Disable it for now. 145660786Sps */ 145760786Sps char *blanks; 145860786Sps int row; 145960786Sps int col; 146060786Sps 146160786Sps /* 146260786Sps * Create a complete, blank screen using "normal" colors. 146360786Sps */ 146460786Sps SETCOLORS(nm_fg_color, nm_bg_color); 146560786Sps blanks = (char *) ecalloc(width+1, sizeof(char)); 146660786Sps for (col = 0; col < sc_width; col++) 146760786Sps blanks[col] = ' '; 146860786Sps blanks[sc_width] = '\0'; 146960786Sps for (row = 0; row < sc_height; row++) 147060786Sps _outtext(blanks); 147160786Sps free(blanks); 147260786Sps#endif 147360786Sps} 147460786Sps#endif 147560786Sps 147660786Sps#if MSDOS_COMPILER==WIN32C 147760786Sps 147860786Sps/* 147960786Sps * Termcap-like init with a private win32 console. 148060786Sps */ 148160786Sps static void 148260786Spswin32_init_term() 148360786Sps{ 148460786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 148560786Sps COORD size; 148660786Sps 148760786Sps if (con_out_save == INVALID_HANDLE_VALUE) 148860786Sps return; 148960786Sps 149060786Sps GetConsoleScreenBufferInfo(con_out_save, &scr); 149160786Sps 149260786Sps if (con_out_ours == INVALID_HANDLE_VALUE) 149360786Sps { 149460786Sps /* 149560786Sps * Create our own screen buffer, so that we 149660786Sps * may restore the original when done. 149760786Sps */ 149860786Sps con_out_ours = CreateConsoleScreenBuffer( 149960786Sps GENERIC_WRITE | GENERIC_READ, 150060786Sps FILE_SHARE_WRITE | FILE_SHARE_READ, 150160786Sps (LPSECURITY_ATTRIBUTES) NULL, 150260786Sps CONSOLE_TEXTMODE_BUFFER, 150360786Sps (LPVOID) NULL); 150460786Sps } 150560786Sps 150660786Sps size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 150760786Sps size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 150860786Sps SetConsoleScreenBufferSize(con_out_ours, size); 150960786Sps SetConsoleActiveScreenBuffer(con_out_ours); 151060786Sps con_out = con_out_ours; 151160786Sps} 151260786Sps 151360786Sps/* 151460786Sps * Restore the startup console. 151560786Sps */ 151660786Spsstatic void 151760786Spswin32_deinit_term() 151860786Sps{ 151960786Sps if (con_out_save == INVALID_HANDLE_VALUE) 152060786Sps return; 152160786Sps if (quitting) 152260786Sps (void) CloseHandle(con_out_ours); 152360786Sps SetConsoleActiveScreenBuffer(con_out_save); 152460786Sps con_out = con_out_save; 152560786Sps} 152660786Sps 152760786Sps#endif 152860786Sps 152960786Sps/* 153060786Sps * Initialize terminal 153160786Sps */ 153260786Sps public void 153360786Spsinit() 153460786Sps{ 153560786Sps#if !MSDOS_COMPILER 153689022Sps if (!no_init) 153789022Sps tputs(sc_init, sc_height, putchr); 153889022Sps if (!no_keypad) 153989022Sps tputs(sc_s_keypad, sc_height, putchr); 1540161478Sdelphij if (top_scroll) 1541161478Sdelphij { 1542161478Sdelphij int i; 1543161478Sdelphij 1544161478Sdelphij /* 1545161478Sdelphij * This is nice to terminals with no alternate screen, 1546161478Sdelphij * but with saved scrolled-off-the-top lines. This way, 1547161478Sdelphij * no previous line is lost, but we start with a whole 1548161478Sdelphij * screen to ourself. 1549161478Sdelphij */ 1550161478Sdelphij for (i = 1; i < sc_height; i++) 1551161478Sdelphij putchr('\n'); 1552191930Sdelphij } else 1553191930Sdelphij line_left(); 155460786Sps#else 155560786Sps#if MSDOS_COMPILER==WIN32C 155689022Sps if (!no_init) 155789022Sps win32_init_term(); 155860786Sps#endif 155960786Sps initcolor(); 156060786Sps flush(); 156160786Sps#endif 156260786Sps init_done = 1; 156360786Sps} 156460786Sps 156560786Sps/* 156660786Sps * Deinitialize terminal 156760786Sps */ 156860786Sps public void 156960786Spsdeinit() 157060786Sps{ 157160786Sps if (!init_done) 157260786Sps return; 157360786Sps#if !MSDOS_COMPILER 157489022Sps if (!no_keypad) 157589022Sps tputs(sc_e_keypad, sc_height, putchr); 157689022Sps if (!no_init) 157789022Sps tputs(sc_deinit, sc_height, putchr); 157860786Sps#else 157989022Sps /* Restore system colors. */ 158060786Sps SETCOLORS(sy_fg_color, sy_bg_color); 158160786Sps#if MSDOS_COMPILER==WIN32C 158289022Sps if (!no_init) 158389022Sps win32_deinit_term(); 158489022Sps#else 158589022Sps /* Need clreol to make SETCOLORS take effect. */ 158689022Sps clreol(); 158760786Sps#endif 158860786Sps#endif 158960786Sps init_done = 0; 159060786Sps} 159160786Sps 159260786Sps/* 159360786Sps * Home cursor (move to upper left corner of screen). 159460786Sps */ 159560786Sps public void 159660786Spshome() 159760786Sps{ 159860786Sps#if !MSDOS_COMPILER 159960786Sps tputs(sc_home, 1, putchr); 160060786Sps#else 160160786Sps flush(); 160260786Sps _settextposition(1,1); 160360786Sps#endif 160460786Sps} 160560786Sps 160660786Sps/* 160760786Sps * Add a blank line (called with cursor at home). 160860786Sps * Should scroll the display down. 160960786Sps */ 161060786Sps public void 161160786Spsadd_line() 161260786Sps{ 161360786Sps#if !MSDOS_COMPILER 161460786Sps tputs(sc_addline, sc_height, putchr); 161560786Sps#else 161660786Sps flush(); 161760786Sps#if MSDOS_COMPILER==MSOFTC 161860786Sps _scrolltextwindow(_GSCROLLDOWN); 161960786Sps _settextposition(1,1); 162060786Sps#else 162160786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 162260786Sps movetext(1,1, sc_width,sc_height-1, 1,2); 162360786Sps gotoxy(1,1); 162460786Sps clreol(); 162560786Sps#else 162660786Sps#if MSDOS_COMPILER==WIN32C 162760786Sps { 162860786Sps CHAR_INFO fillchar; 162960786Sps SMALL_RECT rcSrc, rcClip; 163060786Sps COORD new_org; 163160786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 163260786Sps 163360786Sps GetConsoleScreenBufferInfo(con_out,&csbi); 163460786Sps 163560786Sps /* The clip rectangle is the entire visible screen. */ 163660786Sps rcClip.Left = csbi.srWindow.Left; 163760786Sps rcClip.Top = csbi.srWindow.Top; 163860786Sps rcClip.Right = csbi.srWindow.Right; 163960786Sps rcClip.Bottom = csbi.srWindow.Bottom; 164060786Sps 164160786Sps /* The source rectangle is the visible screen minus the last line. */ 164260786Sps rcSrc = rcClip; 164360786Sps rcSrc.Bottom--; 164460786Sps 164560786Sps /* Move the top left corner of the source window down one row. */ 164660786Sps new_org.X = rcSrc.Left; 164760786Sps new_org.Y = rcSrc.Top + 1; 164860786Sps 164960786Sps /* Fill the right character and attributes. */ 165060786Sps fillchar.Char.AsciiChar = ' '; 165160786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 165260786Sps fillchar.Attributes = curr_attr; 165360786Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 165460786Sps _settextposition(1,1); 165560786Sps } 165660786Sps#endif 165760786Sps#endif 165860786Sps#endif 165960786Sps#endif 166060786Sps} 166160786Sps 166289022Sps#if 0 166360786Sps/* 166460786Sps * Remove the n topmost lines and scroll everything below it in the 166560786Sps * window upward. This is needed to stop leaking the topmost line 166660786Sps * into the scrollback buffer when we go down-one-line (in WIN32). 166760786Sps */ 166860786Sps public void 166960786Spsremove_top(n) 167060786Sps int n; 167160786Sps{ 167260786Sps#if MSDOS_COMPILER==WIN32C 167360786Sps SMALL_RECT rcSrc, rcClip; 167460786Sps CHAR_INFO fillchar; 167560786Sps COORD new_org; 167660786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 167760786Sps 167860786Sps if (n >= sc_height - 1) 167960786Sps { 168060786Sps clear(); 168160786Sps home(); 168260786Sps return; 168360786Sps } 168460786Sps 168560786Sps flush(); 168660786Sps 168760786Sps GetConsoleScreenBufferInfo(con_out, &csbi); 168860786Sps 168960786Sps /* Get the extent of all-visible-rows-but-the-last. */ 169060786Sps rcSrc.Left = csbi.srWindow.Left; 169160786Sps rcSrc.Top = csbi.srWindow.Top + n; 169260786Sps rcSrc.Right = csbi.srWindow.Right; 169360786Sps rcSrc.Bottom = csbi.srWindow.Bottom; 169460786Sps 169560786Sps /* Get the clip rectangle. */ 169660786Sps rcClip.Left = rcSrc.Left; 169760786Sps rcClip.Top = csbi.srWindow.Top; 169860786Sps rcClip.Right = rcSrc.Right; 169960786Sps rcClip.Bottom = rcSrc.Bottom ; 170060786Sps 170160786Sps /* Move the source window up n rows. */ 170260786Sps new_org.X = rcSrc.Left; 170360786Sps new_org.Y = rcSrc.Top - n; 170460786Sps 170560786Sps /* Fill the right character and attributes. */ 170660786Sps fillchar.Char.AsciiChar = ' '; 170760786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 170860786Sps fillchar.Attributes = curr_attr; 170960786Sps 171060786Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 171160786Sps 171260786Sps /* Position cursor on first blank line. */ 171360786Sps goto_line(sc_height - n - 1); 171460786Sps#endif 171560786Sps} 171689022Sps#endif 171760786Sps 171889022Sps#if MSDOS_COMPILER==WIN32C 171960786Sps/* 172089022Sps * Clear the screen. 172189022Sps */ 172289022Sps static void 172389022Spswin32_clear() 172489022Sps{ 172589022Sps /* 172689022Sps * This will clear only the currently visible rows of the NT 172789022Sps * console buffer, which means none of the precious scrollback 172889022Sps * rows are touched making for faster scrolling. Note that, if 172989022Sps * the window has fewer columns than the console buffer (i.e. 173089022Sps * there is a horizontal scrollbar as well), the entire width 173189022Sps * of the visible rows will be cleared. 173289022Sps */ 173389022Sps COORD topleft; 173489022Sps DWORD nchars; 173589022Sps DWORD winsz; 173689022Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 173789022Sps 173889022Sps /* get the number of cells in the current buffer */ 173989022Sps GetConsoleScreenBufferInfo(con_out, &csbi); 174089022Sps winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); 174189022Sps topleft.X = 0; 174289022Sps topleft.Y = csbi.srWindow.Top; 174389022Sps 174489022Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 174589022Sps FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars); 174689022Sps FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars); 174789022Sps} 174889022Sps 174989022Sps/* 175089022Sps * Remove the n topmost lines and scroll everything below it in the 175189022Sps * window upward. 175289022Sps */ 175389022Sps public void 175489022Spswin32_scroll_up(n) 175589022Sps int n; 175689022Sps{ 175789022Sps SMALL_RECT rcSrc, rcClip; 175889022Sps CHAR_INFO fillchar; 175989022Sps COORD topleft; 176089022Sps COORD new_org; 176189022Sps DWORD nchars; 176289022Sps DWORD size; 176389022Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 176489022Sps 176589022Sps if (n <= 0) 176689022Sps return; 176789022Sps 176889022Sps if (n >= sc_height - 1) 176989022Sps { 177089022Sps win32_clear(); 177189022Sps _settextposition(1,1); 177289022Sps return; 177389022Sps } 177489022Sps 177589022Sps /* Get the extent of what will remain visible after scrolling. */ 177689022Sps GetConsoleScreenBufferInfo(con_out, &csbi); 177789022Sps rcSrc.Left = csbi.srWindow.Left; 177889022Sps rcSrc.Top = csbi.srWindow.Top + n; 177989022Sps rcSrc.Right = csbi.srWindow.Right; 178089022Sps rcSrc.Bottom = csbi.srWindow.Bottom; 178189022Sps 178289022Sps /* Get the clip rectangle. */ 178389022Sps rcClip.Left = rcSrc.Left; 178489022Sps rcClip.Top = csbi.srWindow.Top; 178589022Sps rcClip.Right = rcSrc.Right; 178689022Sps rcClip.Bottom = rcSrc.Bottom ; 178789022Sps 178889022Sps /* Move the source text to the top of the screen. */ 178989022Sps new_org.X = rcSrc.Left; 1790221715Sdelphij new_org.Y = rcClip.Top; 179189022Sps 179289022Sps /* Fill the right character and attributes. */ 179389022Sps fillchar.Char.AsciiChar = ' '; 179489022Sps fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color); 179589022Sps 179689022Sps /* Scroll the window. */ 179789022Sps SetConsoleTextAttribute(con_out, fillchar.Attributes); 179889022Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 179989022Sps 180089022Sps /* Clear remaining lines at bottom. */ 180189022Sps topleft.X = csbi.dwCursorPosition.X; 180289022Sps topleft.Y = rcSrc.Bottom - n; 180389022Sps size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X); 180489022Sps FillConsoleOutputCharacter(con_out, ' ', size, topleft, 180589022Sps &nchars); 180689022Sps FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft, 180789022Sps &nchars); 180889022Sps SetConsoleTextAttribute(con_out, curr_attr); 180989022Sps 181089022Sps /* Move cursor n lines up from where it was. */ 181189022Sps csbi.dwCursorPosition.Y -= n; 181289022Sps SetConsoleCursorPosition(con_out, csbi.dwCursorPosition); 181389022Sps} 181489022Sps#endif 181589022Sps 181689022Sps/* 181760786Sps * Move cursor to lower left corner of screen. 181860786Sps */ 181960786Sps public void 182060786Spslower_left() 182160786Sps{ 182260786Sps#if !MSDOS_COMPILER 182360786Sps tputs(sc_lower_left, 1, putchr); 182460786Sps#else 182560786Sps flush(); 182660786Sps _settextposition(sc_height, 1); 182760786Sps#endif 182860786Sps} 182960786Sps 183060786Sps/* 1831170259Sdelphij * Move cursor to left position of current line. 1832170259Sdelphij */ 1833170259Sdelphij public void 1834170259Sdelphijline_left() 1835170259Sdelphij{ 1836170259Sdelphij#if !MSDOS_COMPILER 1837170259Sdelphij tputs(sc_return, 1, putchr); 1838170259Sdelphij#else 1839170259Sdelphij int row; 1840170259Sdelphij flush(); 1841170259Sdelphij#if MSDOS_COMPILER==WIN32C 1842170259Sdelphij { 1843170259Sdelphij CONSOLE_SCREEN_BUFFER_INFO scr; 1844170259Sdelphij GetConsoleScreenBufferInfo(con_out, &scr); 1845170259Sdelphij row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 1846170259Sdelphij } 1847170259Sdelphij#else 1848173685Sdelphij#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 1849173685Sdelphij row = wherey(); 1850173685Sdelphij#else 1851170259Sdelphij { 1852170259Sdelphij struct rccoord tpos = _gettextposition(); 1853170259Sdelphij row = tpos.row; 1854170259Sdelphij } 1855170259Sdelphij#endif 1856173685Sdelphij#endif 1857170259Sdelphij _settextposition(row, 1); 1858170259Sdelphij#endif 1859170259Sdelphij} 1860170259Sdelphij 1861170259Sdelphij/* 186260786Sps * Check if the console size has changed and reset internals 186360786Sps * (in lieu of SIGWINCH for WIN32). 186460786Sps */ 186560786Sps public void 186660786Spscheck_winch() 186760786Sps{ 186860786Sps#if MSDOS_COMPILER==WIN32C 186960786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 187060786Sps COORD size; 187160786Sps 187260786Sps if (con_out == INVALID_HANDLE_VALUE) 187360786Sps return; 187460786Sps 187560786Sps flush(); 187660786Sps GetConsoleScreenBufferInfo(con_out, &scr); 187760786Sps size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 187860786Sps size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 187960786Sps if (size.Y != sc_height || size.X != sc_width) 188060786Sps { 188160786Sps sc_height = size.Y; 188260786Sps sc_width = size.X; 188360786Sps if (!no_init && con_out_ours == con_out) 188460786Sps SetConsoleScreenBufferSize(con_out, size); 188560786Sps pos_init(); 188660786Sps wscroll = (sc_height + 1) / 2; 188760786Sps screen_trashed = 1; 188860786Sps } 188960786Sps#endif 189060786Sps} 189160786Sps 189260786Sps/* 189360786Sps * Goto a specific line on the screen. 189460786Sps */ 189560786Sps public void 189660786Spsgoto_line(slinenum) 189760786Sps int slinenum; 189860786Sps{ 189960786Sps#if !MSDOS_COMPILER 190060786Sps tputs(tgoto(sc_move, 0, slinenum), 1, putchr); 190160786Sps#else 190260786Sps flush(); 190360786Sps _settextposition(slinenum+1, 1); 190460786Sps#endif 190560786Sps} 190660786Sps 190760786Sps#if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC 190860786Sps/* 190960786Sps * Create an alternate screen which is all white. 191060786Sps * This screen is used to create a "flash" effect, by displaying it 191160786Sps * briefly and then switching back to the normal screen. 191260786Sps * {{ Yuck! There must be a better way to get a visual bell. }} 191360786Sps */ 191460786Sps static void 191560786Spscreate_flash() 191660786Sps{ 191760786Sps#if MSDOS_COMPILER==MSOFTC 191860786Sps struct videoconfig w; 191960786Sps char *blanks; 192060786Sps int row, col; 192160786Sps 192260786Sps _getvideoconfig(&w); 192360786Sps videopages = w.numvideopages; 192460786Sps if (videopages < 2) 192560786Sps { 1926161478Sdelphij at_enter(AT_STANDOUT); 1927161478Sdelphij at_exit(); 192860786Sps } else 192960786Sps { 193060786Sps _setactivepage(1); 1931161478Sdelphij at_enter(AT_STANDOUT); 193260786Sps blanks = (char *) ecalloc(w.numtextcols, sizeof(char)); 193360786Sps for (col = 0; col < w.numtextcols; col++) 193460786Sps blanks[col] = ' '; 193560786Sps for (row = w.numtextrows; row > 0; row--) 193660786Sps _outmem(blanks, w.numtextcols); 193760786Sps _setactivepage(0); 193860786Sps _setvisualpage(0); 193960786Sps free(blanks); 1940161478Sdelphij at_exit(); 194160786Sps } 194260786Sps#else 194360786Sps#if MSDOS_COMPILER==BORLANDC 194460786Sps register int n; 194560786Sps 194660786Sps whitescreen = (unsigned short *) 194760786Sps malloc(sc_width * sc_height * sizeof(short)); 194860786Sps if (whitescreen == NULL) 194960786Sps return; 195060786Sps for (n = 0; n < sc_width * sc_height; n++) 195160786Sps whitescreen[n] = 0x7020; 195260786Sps#else 195360786Sps#if MSDOS_COMPILER==WIN32C 195460786Sps register int n; 195560786Sps 195660786Sps whitescreen = (WORD *) 195760786Sps malloc(sc_height * sc_width * sizeof(WORD)); 195860786Sps if (whitescreen == NULL) 195960786Sps return; 196060786Sps /* Invert the standard colors. */ 196160786Sps for (n = 0; n < sc_width * sc_height; n++) 196260786Sps whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color); 196360786Sps#endif 196460786Sps#endif 196560786Sps#endif 196660786Sps flash_created = 1; 196760786Sps} 196860786Sps#endif /* MSDOS_COMPILER */ 196960786Sps 197060786Sps/* 197160786Sps * Output the "visual bell", if there is one. 197260786Sps */ 197360786Sps public void 197460786Spsvbell() 197560786Sps{ 197660786Sps#if !MSDOS_COMPILER 197760786Sps if (*sc_visual_bell == '\0') 197860786Sps return; 197960786Sps tputs(sc_visual_bell, sc_height, putchr); 198060786Sps#else 198160786Sps#if MSDOS_COMPILER==DJGPPC 198260786Sps ScreenVisualBell(); 198360786Sps#else 198460786Sps#if MSDOS_COMPILER==MSOFTC 198560786Sps /* 198660786Sps * Create a flash screen on the second video page. 198760786Sps * Switch to that page, then switch back. 198860786Sps */ 198960786Sps if (!flash_created) 199060786Sps create_flash(); 199160786Sps if (videopages < 2) 199260786Sps return; 199360786Sps _setvisualpage(1); 199460786Sps delay(100); 199560786Sps _setvisualpage(0); 199660786Sps#else 199760786Sps#if MSDOS_COMPILER==BORLANDC 199860786Sps unsigned short *currscreen; 199960786Sps 200060786Sps /* 200160786Sps * Get a copy of the current screen. 200260786Sps * Display the flash screen. 200360786Sps * Then restore the old screen. 200460786Sps */ 200560786Sps if (!flash_created) 200660786Sps create_flash(); 200760786Sps if (whitescreen == NULL) 200860786Sps return; 200960786Sps currscreen = (unsigned short *) 201060786Sps malloc(sc_width * sc_height * sizeof(short)); 201160786Sps if (currscreen == NULL) return; 201260786Sps gettext(1, 1, sc_width, sc_height, currscreen); 201360786Sps puttext(1, 1, sc_width, sc_height, whitescreen); 201460786Sps delay(100); 201560786Sps puttext(1, 1, sc_width, sc_height, currscreen); 201660786Sps free(currscreen); 201760786Sps#else 201860786Sps#if MSDOS_COMPILER==WIN32C 201960786Sps /* paint screen with an inverse color */ 202060786Sps clear(); 202160786Sps 202260786Sps /* leave it displayed for 100 msec. */ 202360786Sps Sleep(100); 202460786Sps 202560786Sps /* restore with a redraw */ 202660786Sps repaint(); 202760786Sps#endif 202860786Sps#endif 202960786Sps#endif 203060786Sps#endif 203160786Sps#endif 203260786Sps} 203360786Sps 203460786Sps/* 203560786Sps * Make a noise. 203660786Sps */ 203760786Sps static void 203860786Spsbeep() 203960786Sps{ 204060786Sps#if !MSDOS_COMPILER 204189022Sps putchr(CONTROL('G')); 204260786Sps#else 204360786Sps#if MSDOS_COMPILER==WIN32C 204460786Sps MessageBeep(0); 204560786Sps#else 204660786Sps write(1, "\7", 1); 204760786Sps#endif 204860786Sps#endif 204960786Sps} 205060786Sps 205160786Sps/* 205260786Sps * Ring the terminal bell. 205360786Sps */ 205460786Sps public void 205560786Spsbell() 205660786Sps{ 205760786Sps if (quiet == VERY_QUIET) 205860786Sps vbell(); 205960786Sps else 206060786Sps beep(); 206160786Sps} 206260786Sps 206360786Sps/* 206460786Sps * Clear the screen. 206560786Sps */ 206660786Sps public void 206760786Spsclear() 206860786Sps{ 206960786Sps#if !MSDOS_COMPILER 207060786Sps tputs(sc_clear, sc_height, putchr); 207160786Sps#else 207260786Sps flush(); 207360786Sps#if MSDOS_COMPILER==WIN32C 207489022Sps win32_clear(); 207560786Sps#else 207660786Sps _clearscreen(_GCLEARSCREEN); 207760786Sps#endif 207860786Sps#endif 207960786Sps} 208060786Sps 208160786Sps/* 208260786Sps * Clear from the cursor to the end of the cursor's line. 208360786Sps * {{ This must not move the cursor. }} 208460786Sps */ 208560786Sps public void 208660786Spsclear_eol() 208760786Sps{ 208860786Sps#if !MSDOS_COMPILER 208960786Sps tputs(sc_eol_clear, 1, putchr); 209060786Sps#else 209160786Sps#if MSDOS_COMPILER==MSOFTC 209260786Sps short top, left; 209360786Sps short bot, right; 209460786Sps struct rccoord tpos; 209560786Sps 209660786Sps flush(); 209760786Sps /* 209860786Sps * Save current state. 209960786Sps */ 210060786Sps tpos = _gettextposition(); 210160786Sps _gettextwindow(&top, &left, &bot, &right); 210260786Sps /* 210360786Sps * Set a temporary window to the current line, 210460786Sps * from the cursor's position to the right edge of the screen. 210560786Sps * Then clear that window. 210660786Sps */ 210760786Sps _settextwindow(tpos.row, tpos.col, tpos.row, sc_width); 210860786Sps _clearscreen(_GWINDOW); 210960786Sps /* 211060786Sps * Restore state. 211160786Sps */ 211260786Sps _settextwindow(top, left, bot, right); 211360786Sps _settextposition(tpos.row, tpos.col); 211460786Sps#else 211560786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 211660786Sps flush(); 211760786Sps clreol(); 211860786Sps#else 211960786Sps#if MSDOS_COMPILER==WIN32C 212060786Sps DWORD nchars; 212160786Sps COORD cpos; 212260786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 212360786Sps 212460786Sps flush(); 212560786Sps memset(&scr, 0, sizeof(scr)); 212660786Sps GetConsoleScreenBufferInfo(con_out, &scr); 212760786Sps cpos.X = scr.dwCursorPosition.X; 212860786Sps cpos.Y = scr.dwCursorPosition.Y; 212960786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 213060786Sps FillConsoleOutputAttribute(con_out, curr_attr, 213160786Sps scr.dwSize.X - cpos.X, cpos, &nchars); 213260786Sps FillConsoleOutputCharacter(con_out, ' ', 213360786Sps scr.dwSize.X - cpos.X, cpos, &nchars); 213460786Sps#endif 213560786Sps#endif 213660786Sps#endif 213760786Sps#endif 213860786Sps} 213960786Sps 214060786Sps/* 214160786Sps * Clear the current line. 214260786Sps * Clear the screen if there's off-screen memory below the display. 214360786Sps */ 214460786Sps static void 214560786Spsclear_eol_bot() 214660786Sps{ 214760786Sps#if MSDOS_COMPILER 214860786Sps clear_eol(); 214960786Sps#else 215060786Sps if (below_mem) 215160786Sps tputs(sc_eos_clear, 1, putchr); 215260786Sps else 215360786Sps tputs(sc_eol_clear, 1, putchr); 215460786Sps#endif 215560786Sps} 215660786Sps 215760786Sps/* 215860786Sps * Clear the bottom line of the display. 215960786Sps * Leave the cursor at the beginning of the bottom line. 216060786Sps */ 216160786Sps public void 216260786Spsclear_bot() 216360786Sps{ 216460786Sps /* 216560786Sps * If we're in a non-normal attribute mode, temporarily exit 216660786Sps * the mode while we do the clear. Some terminals fill the 216760786Sps * cleared area with the current attribute. 216860786Sps */ 2169170259Sdelphij if (oldbot) 2170170259Sdelphij lower_left(); 2171170259Sdelphij else 2172170259Sdelphij line_left(); 2173170259Sdelphij 2174161478Sdelphij if (attrmode == AT_NORMAL) 2175161478Sdelphij clear_eol_bot(); 2176161478Sdelphij else 217760786Sps { 2178161478Sdelphij int saved_attrmode = attrmode; 2179161478Sdelphij 2180161478Sdelphij at_exit(); 218160786Sps clear_eol_bot(); 2182161478Sdelphij at_enter(saved_attrmode); 218360786Sps } 218460786Sps} 218560786Sps 218660786Sps public void 2187161478Sdelphijat_enter(attr) 2188161478Sdelphij int attr; 218960786Sps{ 2190161478Sdelphij attr = apply_at_specials(attr); 219160786Sps 219260786Sps#if !MSDOS_COMPILER 2193161478Sdelphij /* The one with the most priority is last. */ 2194161478Sdelphij if (attr & AT_UNDERLINE) 2195161478Sdelphij tputs(sc_u_in, 1, putchr); 2196161478Sdelphij if (attr & AT_BOLD) 2197161478Sdelphij tputs(sc_b_in, 1, putchr); 2198161478Sdelphij if (attr & AT_BLINK) 2199161478Sdelphij tputs(sc_bl_in, 1, putchr); 2200161478Sdelphij if (attr & AT_STANDOUT) 2201161478Sdelphij tputs(sc_s_in, 1, putchr); 220260786Sps#else 220360786Sps flush(); 2204161478Sdelphij /* The one with the most priority is first. */ 2205161478Sdelphij if (attr & AT_STANDOUT) 2206161478Sdelphij { 2207161478Sdelphij SETCOLORS(so_fg_color, so_bg_color); 2208161478Sdelphij } else if (attr & AT_BLINK) 2209161478Sdelphij { 2210161478Sdelphij SETCOLORS(bl_fg_color, bl_bg_color); 2211161478Sdelphij } 2212161478Sdelphij else if (attr & AT_BOLD) 2213161478Sdelphij { 2214161478Sdelphij SETCOLORS(bo_fg_color, bo_bg_color); 2215161478Sdelphij } 2216161478Sdelphij else if (attr & AT_UNDERLINE) 2217161478Sdelphij { 2218161478Sdelphij SETCOLORS(ul_fg_color, ul_bg_color); 2219161478Sdelphij } 222060786Sps#endif 222160786Sps 2222161478Sdelphij attrmode = attr; 222360786Sps} 222460786Sps 222560786Sps public void 2226161478Sdelphijat_exit() 222760786Sps{ 222860786Sps#if !MSDOS_COMPILER 2229161478Sdelphij /* Undo things in the reverse order we did them. */ 2230161478Sdelphij if (attrmode & AT_STANDOUT) 2231161478Sdelphij tputs(sc_s_out, 1, putchr); 2232161478Sdelphij if (attrmode & AT_BLINK) 2233161478Sdelphij tputs(sc_bl_out, 1, putchr); 2234161478Sdelphij if (attrmode & AT_BOLD) 2235161478Sdelphij tputs(sc_b_out, 1, putchr); 2236161478Sdelphij if (attrmode & AT_UNDERLINE) 2237161478Sdelphij tputs(sc_u_out, 1, putchr); 223860786Sps#else 223960786Sps flush(); 224060786Sps SETCOLORS(nm_fg_color, nm_bg_color); 224160786Sps#endif 2242161478Sdelphij 224360786Sps attrmode = AT_NORMAL; 224460786Sps} 224560786Sps 224660786Sps public void 2247161478Sdelphijat_switch(attr) 2248161478Sdelphij int attr; 224960786Sps{ 2250170259Sdelphij int new_attrmode = apply_at_specials(attr); 2251170259Sdelphij int ignore_modes = AT_ANSI; 2252170259Sdelphij 2253170259Sdelphij if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes)) 2254161478Sdelphij { 2255161478Sdelphij at_exit(); 2256161478Sdelphij at_enter(attr); 2257161478Sdelphij } 225860786Sps} 225960786Sps 2260161478Sdelphij public int 2261161478Sdelphijis_at_equiv(attr1, attr2) 2262161478Sdelphij int attr1; 2263161478Sdelphij int attr2; 226460786Sps{ 2265161478Sdelphij attr1 = apply_at_specials(attr1); 2266161478Sdelphij attr2 = apply_at_specials(attr2); 2267161478Sdelphij 2268161478Sdelphij return (attr1 == attr2); 226960786Sps} 227060786Sps 2271161478Sdelphij public int 2272161478Sdelphijapply_at_specials(attr) 2273161478Sdelphij int attr; 227460786Sps{ 2275161478Sdelphij if (attr & AT_BINARY) 2276161478Sdelphij attr |= binattr; 2277161478Sdelphij if (attr & AT_HILITE) 2278161478Sdelphij attr |= AT_STANDOUT; 2279161478Sdelphij attr &= ~(AT_BINARY|AT_HILITE); 228060786Sps 2281161478Sdelphij return attr; 228260786Sps} 228360786Sps 228460786Sps#if 0 /* No longer used */ 228560786Sps/* 228660786Sps * Erase the character to the left of the cursor 228760786Sps * and move the cursor left. 228860786Sps */ 228960786Sps public void 229060786Spsbackspace() 229160786Sps{ 229260786Sps#if !MSDOS_COMPILER 229360786Sps /* 229460786Sps * Erase the previous character by overstriking with a space. 229560786Sps */ 229660786Sps tputs(sc_backspace, 1, putchr); 229760786Sps putchr(' '); 229860786Sps tputs(sc_backspace, 1, putchr); 229960786Sps#else 230060786Sps#if MSDOS_COMPILER==MSOFTC 230160786Sps struct rccoord tpos; 230260786Sps 230360786Sps flush(); 230460786Sps tpos = _gettextposition(); 230560786Sps if (tpos.col <= 1) 230660786Sps return; 230760786Sps _settextposition(tpos.row, tpos.col-1); 230860786Sps _outtext(" "); 230960786Sps _settextposition(tpos.row, tpos.col-1); 231060786Sps#else 231160786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 231260786Sps cputs("\b"); 231360786Sps#else 231460786Sps#if MSDOS_COMPILER==WIN32C 231560786Sps COORD cpos; 231660786Sps DWORD cChars; 231760786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 231860786Sps 231960786Sps flush(); 232060786Sps GetConsoleScreenBufferInfo(con_out, &scr); 232160786Sps cpos = scr.dwCursorPosition; 232260786Sps if (cpos.X <= 0) 232360786Sps return; 232460786Sps cpos.X--; 232560786Sps SetConsoleCursorPosition(con_out, cpos); 232660786Sps FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars); 232760786Sps SetConsoleCursorPosition(con_out, cpos); 232860786Sps#endif 232960786Sps#endif 233060786Sps#endif 233160786Sps#endif 233260786Sps} 233360786Sps#endif /* 0 */ 233460786Sps 233560786Sps/* 233660786Sps * Output a plain backspace, without erasing the previous char. 233760786Sps */ 233860786Sps public void 233960786Spsputbs() 234060786Sps{ 234160786Sps#if !MSDOS_COMPILER 234260786Sps tputs(sc_backspace, 1, putchr); 234360786Sps#else 234460786Sps int row, col; 234560786Sps 234660786Sps flush(); 234760786Sps { 234860786Sps#if MSDOS_COMPILER==MSOFTC 234960786Sps struct rccoord tpos; 235060786Sps tpos = _gettextposition(); 235160786Sps row = tpos.row; 235260786Sps col = tpos.col; 235360786Sps#else 235460786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 235560786Sps row = wherey(); 235660786Sps col = wherex(); 235760786Sps#else 235860786Sps#if MSDOS_COMPILER==WIN32C 235960786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 236060786Sps GetConsoleScreenBufferInfo(con_out, &scr); 236160786Sps row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 236260786Sps col = scr.dwCursorPosition.X - scr.srWindow.Left + 1; 236360786Sps#endif 236460786Sps#endif 236560786Sps#endif 236660786Sps } 236760786Sps if (col <= 1) 236860786Sps return; 236960786Sps _settextposition(row, col-1); 237060786Sps#endif /* MSDOS_COMPILER */ 237160786Sps} 237260786Sps 237360786Sps#if MSDOS_COMPILER==WIN32C 237460786Sps/* 237560786Sps * Determine whether an input character is waiting to be read. 237660786Sps */ 237760786Sps static int 237860786Spswin32_kbhit(tty) 237960786Sps HANDLE tty; 238060786Sps{ 238160786Sps INPUT_RECORD ip; 238260786Sps DWORD read; 238360786Sps 238460786Sps if (keyCount > 0) 238560786Sps return (TRUE); 238660786Sps 238760786Sps currentKey.ascii = 0; 238860786Sps currentKey.scan = 0; 238960786Sps 239060786Sps /* 239160786Sps * Wait for a real key-down event, but 239260786Sps * ignore SHIFT and CONTROL key events. 239360786Sps */ 239460786Sps do 239560786Sps { 239660786Sps PeekConsoleInput(tty, &ip, 1, &read); 239760786Sps if (read == 0) 239860786Sps return (FALSE); 239960786Sps ReadConsoleInput(tty, &ip, 1, &read); 240060786Sps } while (ip.EventType != KEY_EVENT || 240160786Sps ip.Event.KeyEvent.bKeyDown != TRUE || 240260786Sps ip.Event.KeyEvent.wVirtualScanCode == 0 || 240360786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT || 240460786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL || 240560786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU); 240660786Sps 240760786Sps currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar; 240860786Sps currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode; 240960786Sps keyCount = ip.Event.KeyEvent.wRepeatCount; 241060786Sps 241160786Sps if (ip.Event.KeyEvent.dwControlKeyState & 241260786Sps (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) 241360786Sps { 241460786Sps switch (currentKey.scan) 241560786Sps { 241660786Sps case PCK_ALT_E: /* letter 'E' */ 241760786Sps currentKey.ascii = 0; 241860786Sps break; 241960786Sps } 242060786Sps } else if (ip.Event.KeyEvent.dwControlKeyState & 242160786Sps (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 242260786Sps { 242360786Sps switch (currentKey.scan) 242460786Sps { 242560786Sps case PCK_RIGHT: /* right arrow */ 242660786Sps currentKey.scan = PCK_CTL_RIGHT; 242760786Sps break; 242860786Sps case PCK_LEFT: /* left arrow */ 242960786Sps currentKey.scan = PCK_CTL_LEFT; 243060786Sps break; 243160786Sps case PCK_DELETE: /* delete */ 243260786Sps currentKey.scan = PCK_CTL_DELETE; 243360786Sps break; 243460786Sps } 243560786Sps } 243660786Sps return (TRUE); 243760786Sps} 243860786Sps 243960786Sps/* 244060786Sps * Read a character from the keyboard. 244160786Sps */ 244260786Sps public char 244360786SpsWIN32getch(tty) 244460786Sps int tty; 244560786Sps{ 244660786Sps int ascii; 244760786Sps 244860786Sps if (pending_scancode) 244960786Sps { 245060786Sps pending_scancode = 0; 245160786Sps return ((char)(currentKey.scan & 0x00FF)); 245260786Sps } 245360786Sps 245460786Sps while (win32_kbhit((HANDLE)tty) == FALSE) 245560786Sps { 245660786Sps Sleep(20); 245760786Sps if (ABORT_SIGS()) 245860786Sps return ('\003'); 245960786Sps continue; 246060786Sps } 246160786Sps keyCount --; 246260786Sps ascii = currentKey.ascii; 246360786Sps /* 246460786Sps * On PC's, the extended keys return a 2 byte sequence beginning 246560786Sps * with '00', so if the ascii code is 00, the next byte will be 246660786Sps * the lsb of the scan code. 246760786Sps */ 246860786Sps pending_scancode = (ascii == 0x00); 246960786Sps return ((char)ascii); 247060786Sps} 247160786Sps#endif 2472191930Sdelphij 2473191930Sdelphij#if MSDOS_COMPILER 2474191930Sdelphij/* 2475191930Sdelphij */ 2476191930Sdelphij public void 2477191930SdelphijWIN32setcolors(fg, bg) 2478191930Sdelphij int fg; 2479191930Sdelphij int bg; 2480191930Sdelphij{ 2481191930Sdelphij SETCOLORS(fg, bg); 2482191930Sdelphij} 2483191930Sdelphij 2484191930Sdelphij/* 2485191930Sdelphij */ 2486191930Sdelphij public void 2487191930SdelphijWIN32textout(text, len) 2488191930Sdelphij char *text; 2489191930Sdelphij int len; 2490191930Sdelphij{ 2491191930Sdelphij#if MSDOS_COMPILER==WIN32C 2492191930Sdelphij DWORD written; 2493191930Sdelphij WriteConsole(con_out, text, len, &written, NULL); 2494191930Sdelphij#else 2495191930Sdelphij char c = text[len]; 2496191930Sdelphij text[len] = '\0'; 2497191930Sdelphij cputs(text); 2498191930Sdelphij text[len] = c; 2499191930Sdelphij#endif 2500191930Sdelphij} 2501191930Sdelphij#endif 2502