screen.c revision 60786
160786Sps/* 260786Sps * Copyright (C) 1984-2000 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 760786Sps * For more information about less, or for information on how to 860786Sps * contact the author, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * Routines which deal with the characteristics of the terminal. 1460786Sps * Uses termcap to be as terminal-independent as possible. 1560786Sps */ 1660786Sps 1760786Sps#include "less.h" 1860786Sps#include "cmd.h" 1960786Sps 2060786Sps#if MSDOS_COMPILER 2160786Sps#include "pckeys.h" 2260786Sps#if MSDOS_COMPILER==MSOFTC 2360786Sps#include <graph.h> 2460786Sps#else 2560786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 2660786Sps#include <conio.h> 2760786Sps#if MSDOS_COMPILER==DJGPPC 2860786Sps#include <pc.h> 2960786Spsextern int fd0; 3060786Sps#endif 3160786Sps#else 3260786Sps#if MSDOS_COMPILER==WIN32C 3360786Sps#include <windows.h> 3460786Sps#endif 3560786Sps#endif 3660786Sps#endif 3760786Sps#include <time.h> 3860786Sps 3960786Sps#else 4060786Sps 4160786Sps#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 4260786Sps#include <termios.h> 4360786Sps#if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ) 4460786Sps#include <sys/ioctl.h> 4560786Sps#endif 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#if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD)) 5660786Sps#include <sys/ioctl.h> 5760786Sps#endif 5860786Sps#endif 5960786Sps#endif 6060786Sps 6160786Sps#if HAVE_TERMCAP_H 6260786Sps#include <termcap.h> 6360786Sps#endif 6460786Sps#ifdef _OSK 6560786Sps#include <signal.h> 6660786Sps#endif 6760786Sps#if OS2 6860786Sps#include <sys/signal.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" 9160786Sps#else 9260786Sps#define DEFAULT_TERM "unknown" 9360786Sps#endif 9460786Sps 9560786Sps#if MSDOS_COMPILER==MSOFTC 9660786Spsstatic int videopages; 9760786Spsstatic long msec_loops; 9860786Spsstatic int flash_created = 0; 9960786Sps#define SETCOLORS(fg,bg) { _settextcolor(fg); _setbkcolor(bg); } 10060786Sps#endif 10160786Sps 10260786Sps#if MSDOS_COMPILER==BORLANDC 10360786Spsstatic unsigned short *whitescreen; 10460786Spsstatic int flash_created = 0; 10560786Sps#endif 10660786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 10760786Sps#define _settextposition(y,x) gotoxy(x,y) 10860786Sps#define _clearscreen(m) clrscr() 10960786Sps#define _outtext(s) cputs(s) 11060786Sps#define SETCOLORS(fg,bg) { textcolor(fg); textbackground(bg); } 11160786Spsextern int sc_height; 11260786Sps#endif 11360786Sps 11460786Sps#if MSDOS_COMPILER==WIN32C 11560786Spsstruct keyRecord 11660786Sps{ 11760786Sps int ascii; 11860786Sps int scan; 11960786Sps} currentKey; 12060786Sps 12160786Spsstatic int keyCount = 0; 12260786Spsstatic WORD curr_attr; 12360786Spsstatic int pending_scancode = 0; 12460786Spsstatic WORD *whitescreen; 12560786Sps 12660786Spsstatic HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */ 12760786Spsstatic HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */ 12860786SpsHANDLE con_out = INVALID_HANDLE_VALUE; /* current console */ 12960786Sps 13060786Spsextern int quitting; 13160786Spsstatic void win32_init_term(); 13260786Spsstatic void win32_deinit_term(); 13360786Sps 13460786Sps#define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY) 13560786Sps#define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY) 13660786Sps#define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) 13760786Sps#define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \ 13860786Sps if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ 13960786Sps error("SETCOLORS failed"); } 14060786Sps#endif 14160786Sps 14260786Sps#if MSDOS_COMPILER 14360786Spspublic int nm_fg_color; /* Color of normal text */ 14460786Spspublic int nm_bg_color; 14560786Spspublic int bo_fg_color; /* Color of bold text */ 14660786Spspublic int bo_bg_color; 14760786Spspublic int ul_fg_color; /* Color of underlined text */ 14860786Spspublic int ul_bg_color; 14960786Spspublic int so_fg_color; /* Color of standout text */ 15060786Spspublic int so_bg_color; 15160786Spspublic int bl_fg_color; /* Color of blinking text */ 15260786Spspublic int bl_bg_color; 15360786Spsstatic int sy_fg_color; /* Color of system text (before less) */ 15460786Spsstatic int sy_bg_color; 15560786Sps 15660786Sps#else 15760786Sps 15860786Sps/* 15960786Sps * Strings passed to tputs() to do various terminal functions. 16060786Sps */ 16160786Spsstatic char 16260786Sps *sc_pad, /* Pad string */ 16360786Sps *sc_home, /* Cursor home */ 16460786Sps *sc_addline, /* Add line, scroll down following lines */ 16560786Sps *sc_lower_left, /* Cursor to last line, first column */ 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 */ 19060786Spspublic int erase_char, kill_char; /* The user's erase and line-kill chars */ 19160786Spspublic int werase_char; /* The user's word-erase char */ 19260786Spspublic int sc_width, sc_height; /* Height & width of screen */ 19360786Spspublic int bo_s_width, bo_e_width; /* Printing width of boldface seq */ 19460786Spspublic int ul_s_width, ul_e_width; /* Printing width of underline seq */ 19560786Spspublic int so_s_width, so_e_width; /* Printing width of standout seq */ 19660786Spspublic int bl_s_width, bl_e_width; /* Printing width of blink seq */ 19760786Spspublic int above_mem, below_mem; /* Memory retained above/below screen */ 19860786Spspublic int can_goto_line; /* Can move cursor to any line */ 19960786Spspublic int clear_bg; /* Clear fills with background color */ 20060786Spspublic int missing_cap = 0; /* Some capability is missing */ 20160786Sps 20260786Spsstatic int attrmode = AT_NORMAL; 20360786Sps 20460786Sps#if !MSDOS_COMPILER 20560786Spsstatic char *cheaper(); 20660786Spsstatic void tmodes(); 20760786Sps#endif 20860786Sps 20960786Sps/* 21060786Sps * These two variables are sometimes defined in, 21160786Sps * and needed by, the termcap library. 21260786Sps */ 21360786Sps#if MUST_DEFINE_OSPEED 21460786Spsextern short ospeed; /* Terminal output baud rate */ 21560786Spsextern char PC; /* Pad character */ 21660786Sps#endif 21760786Sps#ifdef _OSK 21860786Spsshort ospeed; 21960786Spschar PC_, *UP, *BC; 22060786Sps#endif 22160786Sps 22260786Spsextern int quiet; /* If VERY_QUIET, use visual bell for bell */ 22360786Spsextern int no_back_scroll; 22460786Spsextern int swindow; 22560786Spsextern int no_init; 22660786Spsextern int sigs; 22760786Spsextern int wscroll; 22860786Spsextern int screen_trashed; 22960786Sps#if HILITE_SEARCH 23060786Spsextern int hilite_search; 23160786Sps#endif 23260786Sps 23360786Spsextern char *tgetstr(); 23460786Spsextern char *tgoto(); 23560786Sps 23660786Sps 23760786Sps/* 23860786Sps * Change terminal to "raw mode", or restore to "normal" mode. 23960786Sps * "Raw mode" means 24060786Sps * 1. An outstanding read will complete on receipt of a single keystroke. 24160786Sps * 2. Input is not echoed. 24260786Sps * 3. On output, \n is mapped to \r\n. 24360786Sps * 4. \t is NOT expanded into spaces. 24460786Sps * 5. Signal-causing characters such as ctrl-C (interrupt), 24560786Sps * etc. are NOT disabled. 24660786Sps * It doesn't matter whether an input \n is mapped to \r, or vice versa. 24760786Sps */ 24860786Sps public void 24960786Spsraw_mode(on) 25060786Sps int on; 25160786Sps{ 25260786Sps static int curr_on = 0; 25360786Sps 25460786Sps if (on == curr_on) 25560786Sps return; 25660786Sps#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 25760786Sps { 25860786Sps struct termios s; 25960786Sps static struct termios save_term; 26060786Sps static int saved_term = 0; 26160786Sps 26260786Sps if (on) 26360786Sps { 26460786Sps /* 26560786Sps * Get terminal modes. 26660786Sps */ 26760786Sps tcgetattr(2, &s); 26860786Sps 26960786Sps /* 27060786Sps * Save modes and set certain variables dependent on modes. 27160786Sps */ 27260786Sps if (!saved_term) 27360786Sps { 27460786Sps save_term = s; 27560786Sps saved_term = 1; 27660786Sps } 27760786Sps#if HAVE_OSPEED 27860786Sps switch (cfgetospeed(&s)) 27960786Sps { 28060786Sps#ifdef B0 28160786Sps case B0: ospeed = 0; break; 28260786Sps#endif 28360786Sps#ifdef B50 28460786Sps case B50: ospeed = 1; break; 28560786Sps#endif 28660786Sps#ifdef B75 28760786Sps case B75: ospeed = 2; break; 28860786Sps#endif 28960786Sps#ifdef B110 29060786Sps case B110: ospeed = 3; break; 29160786Sps#endif 29260786Sps#ifdef B134 29360786Sps case B134: ospeed = 4; break; 29460786Sps#endif 29560786Sps#ifdef B150 29660786Sps case B150: ospeed = 5; break; 29760786Sps#endif 29860786Sps#ifdef B200 29960786Sps case B200: ospeed = 6; break; 30060786Sps#endif 30160786Sps#ifdef B300 30260786Sps case B300: ospeed = 7; break; 30360786Sps#endif 30460786Sps#ifdef B600 30560786Sps case B600: ospeed = 8; break; 30660786Sps#endif 30760786Sps#ifdef B1200 30860786Sps case B1200: ospeed = 9; break; 30960786Sps#endif 31060786Sps#ifdef B1800 31160786Sps case B1800: ospeed = 10; break; 31260786Sps#endif 31360786Sps#ifdef B2400 31460786Sps case B2400: ospeed = 11; break; 31560786Sps#endif 31660786Sps#ifdef B4800 31760786Sps case B4800: ospeed = 12; break; 31860786Sps#endif 31960786Sps#ifdef B9600 32060786Sps case B9600: ospeed = 13; break; 32160786Sps#endif 32260786Sps#ifdef EXTA 32360786Sps case EXTA: ospeed = 14; break; 32460786Sps#endif 32560786Sps#ifdef EXTB 32660786Sps case EXTB: ospeed = 15; break; 32760786Sps#endif 32860786Sps#ifdef B57600 32960786Sps case B57600: ospeed = 16; break; 33060786Sps#endif 33160786Sps#ifdef B115200 33260786Sps case B115200: ospeed = 17; break; 33360786Sps#endif 33460786Sps default: ; 33560786Sps } 33660786Sps#endif 33760786Sps erase_char = s.c_cc[VERASE]; 33860786Sps kill_char = s.c_cc[VKILL]; 33960786Sps#ifdef VWERASE 34060786Sps werase_char = s.c_cc[VWERASE]; 34160786Sps#else 34260786Sps werase_char = CONTROL('W'); 34360786Sps#endif 34460786Sps 34560786Sps /* 34660786Sps * Set the modes to the way we want them. 34760786Sps */ 34860786Sps s.c_lflag &= ~(0 34960786Sps#ifdef ICANON 35060786Sps | ICANON 35160786Sps#endif 35260786Sps#ifdef ECHO 35360786Sps | ECHO 35460786Sps#endif 35560786Sps#ifdef ECHOE 35660786Sps | ECHOE 35760786Sps#endif 35860786Sps#ifdef ECHOK 35960786Sps | ECHOK 36060786Sps#endif 36160786Sps#if ECHONL 36260786Sps | ECHONL 36360786Sps#endif 36460786Sps ); 36560786Sps 36660786Sps s.c_oflag |= (0 36760786Sps#ifdef OXTABS 36860786Sps | OXTABS 36960786Sps#else 37060786Sps#ifdef TAB3 37160786Sps | TAB3 37260786Sps#else 37360786Sps#ifdef XTABS 37460786Sps | XTABS 37560786Sps#endif 37660786Sps#endif 37760786Sps#endif 37860786Sps#ifdef OPOST 37960786Sps | OPOST 38060786Sps#endif 38160786Sps#ifdef ONLCR 38260786Sps | ONLCR 38360786Sps#endif 38460786Sps ); 38560786Sps 38660786Sps s.c_oflag &= ~(0 38760786Sps#ifdef ONOEOT 38860786Sps | ONOEOT 38960786Sps#endif 39060786Sps#ifdef OCRNL 39160786Sps | OCRNL 39260786Sps#endif 39360786Sps#ifdef ONOCR 39460786Sps | ONOCR 39560786Sps#endif 39660786Sps#ifdef ONLRET 39760786Sps | ONLRET 39860786Sps#endif 39960786Sps ); 40060786Sps s.c_cc[VMIN] = 1; 40160786Sps s.c_cc[VTIME] = 0; 40260786Sps#ifdef VLNEXT 40360786Sps s.c_cc[VLNEXT] = 0; 40460786Sps#endif 40560786Sps#ifdef VDSUSP 40660786Sps s.c_cc[VDSUSP] = 0; 40760786Sps#endif 40860786Sps#if MUST_SET_LINE_DISCIPLINE 40960786Sps /* 41060786Sps * System's termios is broken; need to explicitly 41160786Sps * request TERMIODISC line discipline. 41260786Sps */ 41360786Sps s.c_line = TERMIODISC; 41460786Sps#endif 41560786Sps } else 41660786Sps { 41760786Sps /* 41860786Sps * Restore saved modes. 41960786Sps */ 42060786Sps s = save_term; 42160786Sps } 42260786Sps tcsetattr(2, TCSADRAIN, &s); 42360786Sps#if MUST_SET_LINE_DISCIPLINE 42460786Sps if (!on) 42560786Sps { 42660786Sps /* 42760786Sps * Broken termios *ignores* any line discipline 42860786Sps * except TERMIODISC. A different old line discipline 42960786Sps * is therefore not restored, yet. Restore the old 43060786Sps * line discipline by hand. 43160786Sps */ 43260786Sps ioctl(2, TIOCSETD, &save_term.c_line); 43360786Sps } 43460786Sps#endif 43560786Sps } 43660786Sps#else 43760786Sps#ifdef TCGETA 43860786Sps { 43960786Sps struct termio s; 44060786Sps static struct termio save_term; 44160786Sps static int saved_term = 0; 44260786Sps 44360786Sps if (on) 44460786Sps { 44560786Sps /* 44660786Sps * Get terminal modes. 44760786Sps */ 44860786Sps ioctl(2, TCGETA, &s); 44960786Sps 45060786Sps /* 45160786Sps * Save modes and set certain variables dependent on modes. 45260786Sps */ 45360786Sps if (!saved_term) 45460786Sps { 45560786Sps save_term = s; 45660786Sps saved_term = 1; 45760786Sps } 45860786Sps#if HAVE_OSPEED 45960786Sps ospeed = s.c_cflag & CBAUD; 46060786Sps#endif 46160786Sps erase_char = s.c_cc[VERASE]; 46260786Sps kill_char = s.c_cc[VKILL]; 46360786Sps#ifdef VWERASE 46460786Sps werase_char = s.c_cc[VWERASE]; 46560786Sps#else 46660786Sps werase_char = CONTROL('W'); 46760786Sps#endif 46860786Sps 46960786Sps /* 47060786Sps * Set the modes to the way we want them. 47160786Sps */ 47260786Sps s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); 47360786Sps s.c_oflag |= (OPOST|ONLCR|TAB3); 47460786Sps s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); 47560786Sps s.c_cc[VMIN] = 1; 47660786Sps s.c_cc[VTIME] = 0; 47760786Sps } else 47860786Sps { 47960786Sps /* 48060786Sps * Restore saved modes. 48160786Sps */ 48260786Sps s = save_term; 48360786Sps } 48460786Sps ioctl(2, TCSETAW, &s); 48560786Sps } 48660786Sps#else 48760786Sps#ifdef TIOCGETP 48860786Sps { 48960786Sps struct sgttyb s; 49060786Sps static struct sgttyb save_term; 49160786Sps static int saved_term = 0; 49260786Sps 49360786Sps if (on) 49460786Sps { 49560786Sps /* 49660786Sps * Get terminal modes. 49760786Sps */ 49860786Sps ioctl(2, TIOCGETP, &s); 49960786Sps 50060786Sps /* 50160786Sps * Save modes and set certain variables dependent on modes. 50260786Sps */ 50360786Sps if (!saved_term) 50460786Sps { 50560786Sps save_term = s; 50660786Sps saved_term = 1; 50760786Sps } 50860786Sps#if HAVE_OSPEED 50960786Sps ospeed = s.sg_ospeed; 51060786Sps#endif 51160786Sps erase_char = s.sg_erase; 51260786Sps kill_char = s.sg_kill; 51360786Sps werase_char = CONTROL('W'); 51460786Sps 51560786Sps /* 51660786Sps * Set the modes to the way we want them. 51760786Sps */ 51860786Sps s.sg_flags |= CBREAK; 51960786Sps s.sg_flags &= ~(ECHO|XTABS); 52060786Sps } else 52160786Sps { 52260786Sps /* 52360786Sps * Restore saved modes. 52460786Sps */ 52560786Sps s = save_term; 52660786Sps } 52760786Sps ioctl(2, TIOCSETN, &s); 52860786Sps } 52960786Sps#else 53060786Sps#ifdef _OSK 53160786Sps { 53260786Sps struct sgbuf s; 53360786Sps static struct sgbuf save_term; 53460786Sps static int saved_term = 0; 53560786Sps 53660786Sps if (on) 53760786Sps { 53860786Sps /* 53960786Sps * Get terminal modes. 54060786Sps */ 54160786Sps _gs_opt(2, &s); 54260786Sps 54360786Sps /* 54460786Sps * Save modes and set certain variables dependent on modes. 54560786Sps */ 54660786Sps if (!saved_term) 54760786Sps { 54860786Sps save_term = s; 54960786Sps saved_term = 1; 55060786Sps } 55160786Sps erase_char = s.sg_bspch; 55260786Sps kill_char = s.sg_dlnch; 55360786Sps werase_char = CONTROL('W'); 55460786Sps 55560786Sps /* 55660786Sps * Set the modes to the way we want them. 55760786Sps */ 55860786Sps s.sg_echo = 0; 55960786Sps s.sg_eofch = 0; 56060786Sps s.sg_pause = 0; 56160786Sps s.sg_psch = 0; 56260786Sps } else 56360786Sps { 56460786Sps /* 56560786Sps * Restore saved modes. 56660786Sps */ 56760786Sps s = save_term; 56860786Sps } 56960786Sps _ss_opt(2, &s); 57060786Sps } 57160786Sps#else 57260786Sps /* MS-DOS, Windows, or OS2 */ 57360786Sps#if OS2 57460786Sps /* OS2 */ 57560786Sps LSIGNAL(SIGINT, SIG_IGN); 57660786Sps#endif 57760786Sps erase_char = '\b'; 57860786Sps#if MSDOS_COMPILER==DJGPPC 57960786Sps kill_char = CONTROL('U'); 58060786Sps /* 58160786Sps * So that when we shell out or run another program, its 58260786Sps * stdin is in cooked mode. We do not switch stdin to binary 58360786Sps * mode if fd0 is zero, since that means we were called before 58460786Sps * tty was reopened in open_getchr, in which case we would be 58560786Sps * changing the original stdin device outside less. 58660786Sps */ 58760786Sps if (fd0 != 0) 58860786Sps setmode(0, on ? O_BINARY : O_TEXT); 58960786Sps#else 59060786Sps kill_char = ESC; 59160786Sps#endif 59260786Sps werase_char = CONTROL('W'); 59360786Sps#endif 59460786Sps#endif 59560786Sps#endif 59660786Sps#endif 59760786Sps curr_on = on; 59860786Sps} 59960786Sps 60060786Sps#if !MSDOS_COMPILER 60160786Sps/* 60260786Sps * Some glue to prevent calling termcap functions if tgetent() failed. 60360786Sps */ 60460786Spsstatic int hardcopy; 60560786Sps 60660786Sps static char * 60760786Spsltget_env(capname) 60860786Sps char *capname; 60960786Sps{ 61060786Sps char name[16]; 61160786Sps 61260786Sps strcpy(name, "LESS_TERMCAP_"); 61360786Sps strcat(name, capname); 61460786Sps return (lgetenv(name)); 61560786Sps} 61660786Sps 61760786Sps static int 61860786Spsltgetflag(capname) 61960786Sps char *capname; 62060786Sps{ 62160786Sps char *s; 62260786Sps 62360786Sps if ((s = ltget_env(capname)) != NULL) 62460786Sps return (*s != '\0' && *s != '0'); 62560786Sps if (hardcopy) 62660786Sps return (0); 62760786Sps return (tgetflag(capname)); 62860786Sps} 62960786Sps 63060786Sps static int 63160786Spsltgetnum(capname) 63260786Sps char *capname; 63360786Sps{ 63460786Sps char *s; 63560786Sps 63660786Sps if ((s = ltget_env(capname)) != NULL) 63760786Sps return (atoi(s)); 63860786Sps if (hardcopy) 63960786Sps return (-1); 64060786Sps return (tgetnum(capname)); 64160786Sps} 64260786Sps 64360786Sps static char * 64460786Spsltgetstr(capname, pp) 64560786Sps char *capname; 64660786Sps char **pp; 64760786Sps{ 64860786Sps char *s; 64960786Sps 65060786Sps if ((s = ltget_env(capname)) != NULL) 65160786Sps return (s); 65260786Sps if (hardcopy) 65360786Sps return (NULL); 65460786Sps return (tgetstr(capname, pp)); 65560786Sps} 65660786Sps#endif /* MSDOS_COMPILER */ 65760786Sps 65860786Sps/* 65960786Sps * Get size of the output screen. 66060786Sps */ 66160786Sps public void 66260786Spsscrsize() 66360786Sps{ 66460786Sps register char *s; 66560786Sps int sys_height; 66660786Sps int sys_width; 66760786Sps#if !MSDOS_COMPILER 66860786Sps int n; 66960786Sps#endif 67060786Sps 67160786Sps#define DEF_SC_WIDTH 80 67260786Sps#if MSDOS_COMPILER 67360786Sps#define DEF_SC_HEIGHT 25 67460786Sps#else 67560786Sps#define DEF_SC_HEIGHT 24 67660786Sps#endif 67760786Sps 67860786Sps 67960786Sps sys_width = sys_height = 0; 68060786Sps 68160786Sps#if MSDOS_COMPILER==MSOFTC 68260786Sps { 68360786Sps struct videoconfig w; 68460786Sps _getvideoconfig(&w); 68560786Sps sys_height = w.numtextrows; 68660786Sps sys_width = w.numtextcols; 68760786Sps } 68860786Sps#else 68960786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 69060786Sps { 69160786Sps struct text_info w; 69260786Sps gettextinfo(&w); 69360786Sps sys_height = w.screenheight; 69460786Sps sys_width = w.screenwidth; 69560786Sps } 69660786Sps#else 69760786Sps#if MSDOS_COMPILER==WIN32C 69860786Sps { 69960786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 70060786Sps GetConsoleScreenBufferInfo(con_out, &scr); 70160786Sps sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1; 70260786Sps sys_width = scr.srWindow.Right - scr.srWindow.Left + 1; 70360786Sps } 70460786Sps#else 70560786Sps#if OS2 70660786Sps { 70760786Sps int s[2]; 70860786Sps _scrsize(s); 70960786Sps sys_width = s[0]; 71060786Sps sys_height = s[1]; 71160786Sps } 71260786Sps#else 71360786Sps#ifdef TIOCGWINSZ 71460786Sps { 71560786Sps struct winsize w; 71660786Sps if (ioctl(2, TIOCGWINSZ, &w) == 0) 71760786Sps { 71860786Sps if (w.ws_row > 0) 71960786Sps sys_height = w.ws_row; 72060786Sps if (w.ws_col > 0) 72160786Sps sys_width = w.ws_col; 72260786Sps } 72360786Sps } 72460786Sps#else 72560786Sps#ifdef WIOCGETD 72660786Sps { 72760786Sps struct uwdata w; 72860786Sps if (ioctl(2, WIOCGETD, &w) == 0) 72960786Sps { 73060786Sps if (w.uw_height > 0) 73160786Sps sys_height = w.uw_height / w.uw_vs; 73260786Sps if (w.uw_width > 0) 73360786Sps sys_width = w.uw_width / w.uw_hs; 73460786Sps } 73560786Sps } 73660786Sps#endif 73760786Sps#endif 73860786Sps#endif 73960786Sps#endif 74060786Sps#endif 74160786Sps#endif 74260786Sps 74360786Sps if (sys_height > 0) 74460786Sps sc_height = sys_height; 74560786Sps else if ((s = lgetenv("LINES")) != NULL) 74660786Sps sc_height = atoi(s); 74760786Sps#if !MSDOS_COMPILER 74860786Sps else if ((n = ltgetnum("li")) > 0) 74960786Sps sc_height = n; 75060786Sps#endif 75160786Sps else 75260786Sps sc_height = DEF_SC_HEIGHT; 75360786Sps 75460786Sps if (sys_width > 0) 75560786Sps sc_width = sys_width; 75660786Sps else if ((s = lgetenv("COLUMNS")) != NULL) 75760786Sps sc_width = atoi(s); 75860786Sps#if !MSDOS_COMPILER 75960786Sps else if ((n = ltgetnum("co")) > 0) 76060786Sps sc_width = n; 76160786Sps#endif 76260786Sps else 76360786Sps sc_width = DEF_SC_WIDTH; 76460786Sps} 76560786Sps 76660786Sps#if MSDOS_COMPILER==MSOFTC 76760786Sps/* 76860786Sps * Figure out how many empty loops it takes to delay a millisecond. 76960786Sps */ 77060786Sps static void 77160786Spsget_clock() 77260786Sps{ 77360786Sps clock_t start; 77460786Sps 77560786Sps /* 77660786Sps * Get synchronized at the start of a tick. 77760786Sps */ 77860786Sps start = clock(); 77960786Sps while (clock() == start) 78060786Sps ; 78160786Sps /* 78260786Sps * Now count loops till the next tick. 78360786Sps */ 78460786Sps start = clock(); 78560786Sps msec_loops = 0; 78660786Sps while (clock() == start) 78760786Sps msec_loops++; 78860786Sps /* 78960786Sps * Convert from (loops per clock) to (loops per millisecond). 79060786Sps */ 79160786Sps msec_loops *= CLOCKS_PER_SEC; 79260786Sps msec_loops /= 1000; 79360786Sps} 79460786Sps 79560786Sps/* 79660786Sps * Delay for a specified number of milliseconds. 79760786Sps */ 79860786Sps static void 79960786Spsdummy_func() 80060786Sps{ 80160786Sps static long delay_dummy = 0; 80260786Sps delay_dummy++; 80360786Sps} 80460786Sps 80560786Sps static void 80660786Spsdelay(msec) 80760786Sps int msec; 80860786Sps{ 80960786Sps long i; 81060786Sps 81160786Sps while (msec-- > 0) 81260786Sps { 81360786Sps for (i = 0; i < msec_loops; i++) 81460786Sps { 81560786Sps /* 81660786Sps * Make it look like we're doing something here, 81760786Sps * so the optimizer doesn't remove the whole loop. 81860786Sps */ 81960786Sps dummy_func(); 82060786Sps } 82160786Sps } 82260786Sps} 82360786Sps#endif 82460786Sps 82560786Sps/* 82660786Sps * Return the characters actually input by a "special" key. 82760786Sps */ 82860786Sps public char * 82960786Spsspecial_key_str(key) 83060786Sps int key; 83160786Sps{ 83260786Sps static char tbuf[40]; 83360786Sps char *s; 83460786Sps#if MSDOS_COMPILER 83560786Sps static char k_right[] = { '\340', PCK_RIGHT, 0 }; 83660786Sps static char k_left[] = { '\340', PCK_LEFT, 0 }; 83760786Sps static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; 83860786Sps static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; 83960786Sps static char k_insert[] = { '\340', PCK_INSERT, 0 }; 84060786Sps static char k_delete[] = { '\340', PCK_DELETE, 0 }; 84160786Sps static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; 84260786Sps static char k_ctl_backspace[] = { '\177', 0 }; 84360786Sps static char k_home[] = { '\340', PCK_HOME, 0 }; 84460786Sps static char k_end[] = { '\340', PCK_END, 0 }; 84560786Sps static char k_up[] = { '\340', PCK_UP, 0 }; 84660786Sps static char k_down[] = { '\340', PCK_DOWN, 0 }; 84760786Sps static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; 84860786Sps static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; 84960786Sps static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; 85060786Sps static char k_f1[] = { '\340', PCK_F1, 0 }; 85160786Sps#else 85260786Sps char *sp = tbuf; 85360786Sps#endif 85460786Sps 85560786Sps switch (key) 85660786Sps { 85760786Sps#if MSDOS_COMPILER 85860786Sps case SK_RIGHT_ARROW: 85960786Sps s = k_right; 86060786Sps break; 86160786Sps case SK_LEFT_ARROW: 86260786Sps s = k_left; 86360786Sps break; 86460786Sps case SK_UP_ARROW: 86560786Sps s = k_up; 86660786Sps break; 86760786Sps case SK_DOWN_ARROW: 86860786Sps s = k_down; 86960786Sps break; 87060786Sps case SK_PAGE_UP: 87160786Sps s = k_pageup; 87260786Sps break; 87360786Sps case SK_PAGE_DOWN: 87460786Sps s = k_pagedown; 87560786Sps break; 87660786Sps case SK_HOME: 87760786Sps s = k_home; 87860786Sps break; 87960786Sps case SK_END: 88060786Sps s = k_end; 88160786Sps break; 88260786Sps case SK_DELETE: 88360786Sps s = k_delete; 88460786Sps break; 88560786Sps case SK_INSERT: 88660786Sps s = k_insert; 88760786Sps break; 88860786Sps case SK_CTL_LEFT_ARROW: 88960786Sps s = k_ctl_left; 89060786Sps break; 89160786Sps case SK_CTL_RIGHT_ARROW: 89260786Sps s = k_ctl_right; 89360786Sps break; 89460786Sps case SK_CTL_BACKSPACE: 89560786Sps s = k_ctl_backspace; 89660786Sps break; 89760786Sps case SK_CTL_DELETE: 89860786Sps s = k_ctl_delete; 89960786Sps break; 90060786Sps case SK_F1: 90160786Sps s = k_f1; 90260786Sps break; 90360786Sps case SK_BACKTAB: 90460786Sps s = k_backtab; 90560786Sps break; 90660786Sps#else 90760786Sps case SK_RIGHT_ARROW: 90860786Sps s = ltgetstr("kr", &sp); 90960786Sps break; 91060786Sps case SK_LEFT_ARROW: 91160786Sps s = ltgetstr("kl", &sp); 91260786Sps break; 91360786Sps case SK_UP_ARROW: 91460786Sps s = ltgetstr("ku", &sp); 91560786Sps break; 91660786Sps case SK_DOWN_ARROW: 91760786Sps s = ltgetstr("kd", &sp); 91860786Sps break; 91960786Sps case SK_PAGE_UP: 92060786Sps s = ltgetstr("kP", &sp); 92160786Sps break; 92260786Sps case SK_PAGE_DOWN: 92360786Sps s = ltgetstr("kN", &sp); 92460786Sps break; 92560786Sps case SK_HOME: 92660786Sps s = ltgetstr("kh", &sp); 92760786Sps break; 92860786Sps case SK_END: 92960786Sps s = ltgetstr("@7", &sp); 93060786Sps break; 93160786Sps case SK_DELETE: 93260786Sps s = ltgetstr("kD", &sp); 93360786Sps if (s == NULL) 93460786Sps { 93560786Sps tbuf[0] = '\177'; 93660786Sps tbuf[1] = '\0'; 93760786Sps s = tbuf; 93860786Sps } 93960786Sps break; 94060786Sps#endif 94160786Sps case SK_CONTROL_K: 94260786Sps tbuf[0] = CONTROL('K'); 94360786Sps tbuf[1] = '\0'; 94460786Sps s = tbuf; 94560786Sps break; 94660786Sps default: 94760786Sps return (NULL); 94860786Sps } 94960786Sps return (s); 95060786Sps} 95160786Sps 95260786Sps/* 95360786Sps * Get terminal capabilities via termcap. 95460786Sps */ 95560786Sps public void 95660786Spsget_term() 95760786Sps{ 95860786Sps#if MSDOS_COMPILER 95960786Sps auto_wrap = 1; 96060786Sps ignaw = 0; 96160786Sps can_goto_line = 1; 96260786Sps clear_bg = 1; 96360786Sps /* 96460786Sps * Set up default colors. 96560786Sps * The xx_s_width and xx_e_width vars are already initialized to 0. 96660786Sps */ 96760786Sps#if MSDOS_COMPILER==MSOFTC 96860786Sps sy_bg_color = _getbkcolor(); 96960786Sps sy_fg_color = _gettextcolor(); 97060786Sps get_clock(); 97160786Sps#else 97260786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 97360786Sps { 97460786Sps struct text_info w; 97560786Sps gettextinfo(&w); 97660786Sps sy_bg_color = (w.attribute >> 4) & 0x0F; 97760786Sps sy_fg_color = (w.attribute >> 0) & 0x0F; 97860786Sps } 97960786Sps#else 98060786Sps#if MSDOS_COMPILER==WIN32C 98160786Sps { 98260786Sps DWORD nread; 98360786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 98460786Sps 98560786Sps con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE); 98660786Sps /* 98760786Sps * Always open stdin in binary. Note this *must* be done 98860786Sps * before any file operations have been done on fd0. 98960786Sps */ 99060786Sps SET_BINARY(0); 99160786Sps GetConsoleScreenBufferInfo(con_out, &scr); 99260786Sps ReadConsoleOutputAttribute(con_out, &curr_attr, 99360786Sps 1, scr.dwCursorPosition, &nread); 99460786Sps sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */ 99560786Sps sy_fg_color = curr_attr & FG_COLORS; 99660786Sps } 99760786Sps#endif 99860786Sps#endif 99960786Sps#endif 100060786Sps nm_fg_color = sy_fg_color; 100160786Sps nm_bg_color = sy_bg_color; 100260786Sps bo_fg_color = 11; 100360786Sps bo_bg_color = 0; 100460786Sps ul_fg_color = 9; 100560786Sps ul_bg_color = 0; 100660786Sps so_fg_color = 15; 100760786Sps so_bg_color = 9; 100860786Sps bl_fg_color = 15; 100960786Sps bl_bg_color = 0; 101060786Sps 101160786Sps /* 101260786Sps * Get size of the screen. 101360786Sps */ 101460786Sps scrsize(); 101560786Sps pos_init(); 101660786Sps 101760786Sps 101860786Sps#else /* !MSDOS_COMPILER */ 101960786Sps 102060786Sps char *sp; 102160786Sps register char *t1, *t2; 102260786Sps char *term; 102360786Sps char termbuf[TERMBUF_SIZE]; 102460786Sps 102560786Sps static char sbuf[TERMSBUF_SIZE]; 102660786Sps 102760786Sps#if OS2 102860786Sps /* 102960786Sps * Make sure the termcap database is available. 103060786Sps */ 103160786Sps sp = lgetenv("TERMCAP"); 103260786Sps if (sp == NULL || *sp == '\0') 103360786Sps { 103460786Sps char *termcap; 103560786Sps if ((sp = homefile("termcap.dat")) != NULL) 103660786Sps { 103760786Sps termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char)); 103860786Sps sprintf(termcap, "TERMCAP=%s", sp); 103960786Sps free(sp); 104060786Sps putenv(termcap); 104160786Sps } 104260786Sps } 104360786Sps#endif 104460786Sps /* 104560786Sps * Find out what kind of terminal this is. 104660786Sps */ 104760786Sps if ((term = lgetenv("TERM")) == NULL) 104860786Sps term = DEFAULT_TERM; 104960786Sps hardcopy = 0; 105060786Sps if (tgetent(termbuf, term) <= 0) 105160786Sps hardcopy = 1; 105260786Sps if (ltgetflag("hc")) 105360786Sps hardcopy = 1; 105460786Sps 105560786Sps /* 105660786Sps * Get size of the screen. 105760786Sps */ 105860786Sps scrsize(); 105960786Sps pos_init(); 106060786Sps 106160786Sps auto_wrap = ltgetflag("am"); 106260786Sps ignaw = ltgetflag("xn"); 106360786Sps above_mem = ltgetflag("da"); 106460786Sps below_mem = ltgetflag("db"); 106560786Sps clear_bg = ltgetflag("ut"); 106660786Sps 106760786Sps /* 106860786Sps * Assumes termcap variable "sg" is the printing width of: 106960786Sps * the standout sequence, the end standout sequence, 107060786Sps * the underline sequence, the end underline sequence, 107160786Sps * the boldface sequence, and the end boldface sequence. 107260786Sps */ 107360786Sps if ((so_s_width = ltgetnum("sg")) < 0) 107460786Sps so_s_width = 0; 107560786Sps so_e_width = so_s_width; 107660786Sps 107760786Sps bo_s_width = bo_e_width = so_s_width; 107860786Sps ul_s_width = ul_e_width = so_s_width; 107960786Sps bl_s_width = bl_e_width = so_s_width; 108060786Sps 108160786Sps#if HILITE_SEARCH 108260786Sps if (so_s_width > 0 || so_e_width > 0) 108360786Sps /* 108460786Sps * Disable highlighting by default on magic cookie terminals. 108560786Sps * Turning on highlighting might change the displayed width 108660786Sps * of a line, causing the display to get messed up. 108760786Sps * The user can turn it back on with -g, 108860786Sps * but she won't like the results. 108960786Sps */ 109060786Sps hilite_search = 0; 109160786Sps#endif 109260786Sps 109360786Sps /* 109460786Sps * Get various string-valued capabilities. 109560786Sps */ 109660786Sps sp = sbuf; 109760786Sps 109860786Sps#if HAVE_OSPEED 109960786Sps sc_pad = ltgetstr("pc", &sp); 110060786Sps if (sc_pad != NULL) 110160786Sps PC = *sc_pad; 110260786Sps#endif 110360786Sps 110460786Sps sc_s_keypad = ltgetstr("ks", &sp); 110560786Sps if (sc_s_keypad == NULL) 110660786Sps sc_s_keypad = ""; 110760786Sps sc_e_keypad = ltgetstr("ke", &sp); 110860786Sps if (sc_e_keypad == NULL) 110960786Sps sc_e_keypad = ""; 111060786Sps 111160786Sps sc_init = ltgetstr("ti", &sp); 111260786Sps if (sc_init == NULL) 111360786Sps sc_init = ""; 111460786Sps 111560786Sps sc_deinit= ltgetstr("te", &sp); 111660786Sps if (sc_deinit == NULL) 111760786Sps sc_deinit = ""; 111860786Sps 111960786Sps sc_eol_clear = ltgetstr("ce", &sp); 112060786Sps if (sc_eol_clear == NULL || *sc_eol_clear == '\0') 112160786Sps { 112260786Sps missing_cap = 1; 112360786Sps sc_eol_clear = ""; 112460786Sps } 112560786Sps 112660786Sps sc_eos_clear = ltgetstr("cd", &sp); 112760786Sps if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0')) 112860786Sps { 112960786Sps missing_cap = 1; 113060786Sps sc_eol_clear = ""; 113160786Sps } 113260786Sps 113360786Sps sc_clear = ltgetstr("cl", &sp); 113460786Sps if (sc_clear == NULL || *sc_clear == '\0') 113560786Sps { 113660786Sps missing_cap = 1; 113760786Sps sc_clear = "\n\n"; 113860786Sps } 113960786Sps 114060786Sps sc_move = ltgetstr("cm", &sp); 114160786Sps if (sc_move == NULL || *sc_move == '\0') 114260786Sps { 114360786Sps /* 114460786Sps * This is not an error here, because we don't 114560786Sps * always need sc_move. 114660786Sps * We need it only if we don't have home or lower-left. 114760786Sps */ 114860786Sps sc_move = ""; 114960786Sps can_goto_line = 0; 115060786Sps } else 115160786Sps can_goto_line = 1; 115260786Sps 115360786Sps tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp); 115460786Sps tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp); 115560786Sps tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp); 115660786Sps tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp); 115760786Sps 115860786Sps sc_visual_bell = ltgetstr("vb", &sp); 115960786Sps if (sc_visual_bell == NULL) 116060786Sps sc_visual_bell = ""; 116160786Sps 116260786Sps if (ltgetflag("bs")) 116360786Sps sc_backspace = "\b"; 116460786Sps else 116560786Sps { 116660786Sps sc_backspace = ltgetstr("bc", &sp); 116760786Sps if (sc_backspace == NULL || *sc_backspace == '\0') 116860786Sps sc_backspace = "\b"; 116960786Sps } 117060786Sps 117160786Sps /* 117260786Sps * Choose between using "ho" and "cm" ("home" and "cursor move") 117360786Sps * to move the cursor to the upper left corner of the screen. 117460786Sps */ 117560786Sps t1 = ltgetstr("ho", &sp); 117660786Sps if (t1 == NULL) 117760786Sps t1 = ""; 117860786Sps if (*sc_move == '\0') 117960786Sps t2 = ""; 118060786Sps else 118160786Sps { 118260786Sps strcpy(sp, tgoto(sc_move, 0, 0)); 118360786Sps t2 = sp; 118460786Sps sp += strlen(sp) + 1; 118560786Sps } 118660786Sps sc_home = cheaper(t1, t2, "|\b^"); 118760786Sps 118860786Sps /* 118960786Sps * Choose between using "ll" and "cm" ("lower left" and "cursor move") 119060786Sps * to move the cursor to the lower left corner of the screen. 119160786Sps */ 119260786Sps t1 = ltgetstr("ll", &sp); 119360786Sps if (t1 == NULL) 119460786Sps t1 = ""; 119560786Sps if (*sc_move == '\0') 119660786Sps t2 = ""; 119760786Sps else 119860786Sps { 119960786Sps strcpy(sp, tgoto(sc_move, 0, sc_height-1)); 120060786Sps t2 = sp; 120160786Sps sp += strlen(sp) + 1; 120260786Sps } 120360786Sps sc_lower_left = cheaper(t1, t2, "\r"); 120460786Sps 120560786Sps /* 120660786Sps * Choose between using "al" or "sr" ("add line" or "scroll reverse") 120760786Sps * to add a line at the top of the screen. 120860786Sps */ 120960786Sps t1 = ltgetstr("al", &sp); 121060786Sps if (t1 == NULL) 121160786Sps t1 = ""; 121260786Sps t2 = ltgetstr("sr", &sp); 121360786Sps if (t2 == NULL) 121460786Sps t2 = ""; 121560786Sps#if OS2 121660786Sps if (*t1 == '\0' && *t2 == '\0') 121760786Sps sc_addline = ""; 121860786Sps else 121960786Sps#endif 122060786Sps if (above_mem) 122160786Sps sc_addline = t1; 122260786Sps else 122360786Sps sc_addline = cheaper(t1, t2, ""); 122460786Sps if (*sc_addline == '\0') 122560786Sps { 122660786Sps /* 122760786Sps * Force repaint on any backward movement. 122860786Sps */ 122960786Sps no_back_scroll = 1; 123060786Sps } 123160786Sps#endif /* MSDOS_COMPILER */ 123260786Sps} 123360786Sps 123460786Sps#if !MSDOS_COMPILER 123560786Sps/* 123660786Sps * Return the cost of displaying a termcap string. 123760786Sps * We use the trick of calling tputs, but as a char printing function 123860786Sps * we give it inc_costcount, which just increments "costcount". 123960786Sps * This tells us how many chars would be printed by using this string. 124060786Sps * {{ Couldn't we just use strlen? }} 124160786Sps */ 124260786Spsstatic int costcount; 124360786Sps 124460786Sps/*ARGSUSED*/ 124560786Sps static int 124660786Spsinc_costcount(c) 124760786Sps int c; 124860786Sps{ 124960786Sps costcount++; 125060786Sps return (c); 125160786Sps} 125260786Sps 125360786Sps static int 125460786Spscost(t) 125560786Sps char *t; 125660786Sps{ 125760786Sps costcount = 0; 125860786Sps tputs(t, sc_height, inc_costcount); 125960786Sps return (costcount); 126060786Sps} 126160786Sps 126260786Sps/* 126360786Sps * Return the "best" of the two given termcap strings. 126460786Sps * The best, if both exist, is the one with the lower 126560786Sps * cost (see cost() function). 126660786Sps */ 126760786Sps static char * 126860786Spscheaper(t1, t2, def) 126960786Sps char *t1, *t2; 127060786Sps char *def; 127160786Sps{ 127260786Sps if (*t1 == '\0' && *t2 == '\0') 127360786Sps { 127460786Sps missing_cap = 1; 127560786Sps return (def); 127660786Sps } 127760786Sps if (*t1 == '\0') 127860786Sps return (t2); 127960786Sps if (*t2 == '\0') 128060786Sps return (t1); 128160786Sps if (cost(t1) < cost(t2)) 128260786Sps return (t1); 128360786Sps return (t2); 128460786Sps} 128560786Sps 128660786Sps static void 128760786Spstmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp) 128860786Sps char *incap; 128960786Sps char *outcap; 129060786Sps char **instr; 129160786Sps char **outstr; 129260786Sps char *def_instr; 129360786Sps char *def_outstr; 129460786Sps char **spp; 129560786Sps{ 129660786Sps *instr = ltgetstr(incap, spp); 129760786Sps if (*instr == NULL) 129860786Sps { 129960786Sps /* Use defaults. */ 130060786Sps *instr = def_instr; 130160786Sps *outstr = def_outstr; 130260786Sps return; 130360786Sps } 130460786Sps 130560786Sps *outstr = ltgetstr(outcap, spp); 130660786Sps if (*outstr == NULL) 130760786Sps /* No specific out capability; use "me". */ 130860786Sps *outstr = ltgetstr("me", spp); 130960786Sps if (*outstr == NULL) 131060786Sps /* Don't even have "me"; use a null string. */ 131160786Sps *outstr = ""; 131260786Sps} 131360786Sps 131460786Sps#endif /* MSDOS_COMPILER */ 131560786Sps 131660786Sps 131760786Sps/* 131860786Sps * Below are the functions which perform all the 131960786Sps * terminal-specific screen manipulation. 132060786Sps */ 132160786Sps 132260786Sps 132360786Sps#if MSDOS_COMPILER 132460786Sps 132560786Sps#if MSDOS_COMPILER==WIN32C 132660786Sps static void 132760786Sps_settextposition(int row, int col) 132860786Sps{ 132960786Sps COORD cpos; 133060786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 133160786Sps 133260786Sps GetConsoleScreenBufferInfo(con_out, &csbi); 133360786Sps cpos.X = csbi.srWindow.Left + (col - 1); 133460786Sps cpos.Y = csbi.srWindow.Top + (row - 1); 133560786Sps SetConsoleCursorPosition(con_out, cpos); 133660786Sps} 133760786Sps#endif 133860786Sps 133960786Sps/* 134060786Sps * Initialize the screen to the correct color at startup. 134160786Sps */ 134260786Sps static void 134360786Spsinitcolor() 134460786Sps{ 134560786Sps SETCOLORS(nm_fg_color, nm_bg_color); 134660786Sps#if 0 134760786Sps /* 134860786Sps * This clears the screen at startup. This is different from 134960786Sps * the behavior of other versions of less. Disable it for now. 135060786Sps */ 135160786Sps char *blanks; 135260786Sps int row; 135360786Sps int col; 135460786Sps 135560786Sps /* 135660786Sps * Create a complete, blank screen using "normal" colors. 135760786Sps */ 135860786Sps SETCOLORS(nm_fg_color, nm_bg_color); 135960786Sps blanks = (char *) ecalloc(width+1, sizeof(char)); 136060786Sps for (col = 0; col < sc_width; col++) 136160786Sps blanks[col] = ' '; 136260786Sps blanks[sc_width] = '\0'; 136360786Sps for (row = 0; row < sc_height; row++) 136460786Sps _outtext(blanks); 136560786Sps free(blanks); 136660786Sps#endif 136760786Sps} 136860786Sps#endif 136960786Sps 137060786Sps#if MSDOS_COMPILER==WIN32C 137160786Sps 137260786Sps/* 137360786Sps * Termcap-like init with a private win32 console. 137460786Sps */ 137560786Sps static void 137660786Spswin32_init_term() 137760786Sps{ 137860786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 137960786Sps COORD size; 138060786Sps 138160786Sps if (con_out_save == INVALID_HANDLE_VALUE) 138260786Sps return; 138360786Sps 138460786Sps GetConsoleScreenBufferInfo(con_out_save, &scr); 138560786Sps 138660786Sps if (con_out_ours == INVALID_HANDLE_VALUE) 138760786Sps { 138860786Sps /* 138960786Sps * Create our own screen buffer, so that we 139060786Sps * may restore the original when done. 139160786Sps */ 139260786Sps con_out_ours = CreateConsoleScreenBuffer( 139360786Sps GENERIC_WRITE | GENERIC_READ, 139460786Sps FILE_SHARE_WRITE | FILE_SHARE_READ, 139560786Sps (LPSECURITY_ATTRIBUTES) NULL, 139660786Sps CONSOLE_TEXTMODE_BUFFER, 139760786Sps (LPVOID) NULL); 139860786Sps } 139960786Sps 140060786Sps size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 140160786Sps size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 140260786Sps SetConsoleScreenBufferSize(con_out_ours, size); 140360786Sps SetConsoleActiveScreenBuffer(con_out_ours); 140460786Sps con_out = con_out_ours; 140560786Sps} 140660786Sps 140760786Sps/* 140860786Sps * Restore the startup console. 140960786Sps */ 141060786Spsstatic void 141160786Spswin32_deinit_term() 141260786Sps{ 141360786Sps if (con_out_save == INVALID_HANDLE_VALUE) 141460786Sps return; 141560786Sps if (quitting) 141660786Sps (void) CloseHandle(con_out_ours); 141760786Sps SetConsoleActiveScreenBuffer(con_out_save); 141860786Sps con_out = con_out_save; 141960786Sps} 142060786Sps 142160786Sps#endif 142260786Sps 142360786Sps/* 142460786Sps * Initialize terminal 142560786Sps */ 142660786Sps public void 142760786Spsinit() 142860786Sps{ 142960786Sps if (no_init) 143060786Sps { 143160786Sps#if MSDOS_COMPILER==WIN32C 143260786Sps /* no_init or not, never trash win32 console colors. */ 143360786Sps initcolor(); 143460786Sps flush(); 143560786Sps#endif 143660786Sps return; 143760786Sps } 143860786Sps#if !MSDOS_COMPILER 143960786Sps tputs(sc_init, sc_height, putchr); 144060786Sps tputs(sc_s_keypad, sc_height, putchr); 144160786Sps#else 144260786Sps#if MSDOS_COMPILER==WIN32C 144360786Sps win32_init_term(); 144460786Sps#endif 144560786Sps initcolor(); 144660786Sps flush(); 144760786Sps#endif 144860786Sps init_done = 1; 144960786Sps} 145060786Sps 145160786Sps/* 145260786Sps * Deinitialize terminal 145360786Sps */ 145460786Sps public void 145560786Spsdeinit() 145660786Sps{ 145760786Sps if (no_init) 145860786Sps { 145960786Sps#if MSDOS_COMPILER==WIN32C 146060786Sps /* no_init or not, never trash win32 console colors. */ 146160786Sps SETCOLORS(sy_fg_color, sy_bg_color); 146260786Sps#endif 146360786Sps return; 146460786Sps } 146560786Sps 146660786Sps if (!init_done) 146760786Sps return; 146860786Sps#if !MSDOS_COMPILER 146960786Sps tputs(sc_e_keypad, sc_height, putchr); 147060786Sps tputs(sc_deinit, sc_height, putchr); 147160786Sps#else 147260786Sps SETCOLORS(sy_fg_color, sy_bg_color); 147360786Sps#if MSDOS_COMPILER==WIN32C 147460786Sps win32_deinit_term(); 147560786Sps#endif 147660786Sps#endif 147760786Sps init_done = 0; 147860786Sps} 147960786Sps 148060786Sps/* 148160786Sps * Home cursor (move to upper left corner of screen). 148260786Sps */ 148360786Sps public void 148460786Spshome() 148560786Sps{ 148660786Sps#if !MSDOS_COMPILER 148760786Sps tputs(sc_home, 1, putchr); 148860786Sps#else 148960786Sps flush(); 149060786Sps _settextposition(1,1); 149160786Sps#endif 149260786Sps} 149360786Sps 149460786Sps/* 149560786Sps * Add a blank line (called with cursor at home). 149660786Sps * Should scroll the display down. 149760786Sps */ 149860786Sps public void 149960786Spsadd_line() 150060786Sps{ 150160786Sps#if !MSDOS_COMPILER 150260786Sps tputs(sc_addline, sc_height, putchr); 150360786Sps#else 150460786Sps flush(); 150560786Sps#if MSDOS_COMPILER==MSOFTC 150660786Sps _scrolltextwindow(_GSCROLLDOWN); 150760786Sps _settextposition(1,1); 150860786Sps#else 150960786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 151060786Sps movetext(1,1, sc_width,sc_height-1, 1,2); 151160786Sps gotoxy(1,1); 151260786Sps clreol(); 151360786Sps#else 151460786Sps#if MSDOS_COMPILER==WIN32C 151560786Sps { 151660786Sps CHAR_INFO fillchar; 151760786Sps SMALL_RECT rcSrc, rcClip; 151860786Sps COORD new_org; 151960786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 152060786Sps 152160786Sps GetConsoleScreenBufferInfo(con_out,&csbi); 152260786Sps 152360786Sps /* The clip rectangle is the entire visible screen. */ 152460786Sps rcClip.Left = csbi.srWindow.Left; 152560786Sps rcClip.Top = csbi.srWindow.Top; 152660786Sps rcClip.Right = csbi.srWindow.Right; 152760786Sps rcClip.Bottom = csbi.srWindow.Bottom; 152860786Sps 152960786Sps /* The source rectangle is the visible screen minus the last line. */ 153060786Sps rcSrc = rcClip; 153160786Sps rcSrc.Bottom--; 153260786Sps 153360786Sps /* Move the top left corner of the source window down one row. */ 153460786Sps new_org.X = rcSrc.Left; 153560786Sps new_org.Y = rcSrc.Top + 1; 153660786Sps 153760786Sps /* Fill the right character and attributes. */ 153860786Sps fillchar.Char.AsciiChar = ' '; 153960786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 154060786Sps fillchar.Attributes = curr_attr; 154160786Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 154260786Sps _settextposition(1,1); 154360786Sps } 154460786Sps#endif 154560786Sps#endif 154660786Sps#endif 154760786Sps#endif 154860786Sps} 154960786Sps 155060786Sps/* 155160786Sps * Remove the n topmost lines and scroll everything below it in the 155260786Sps * window upward. This is needed to stop leaking the topmost line 155360786Sps * into the scrollback buffer when we go down-one-line (in WIN32). 155460786Sps */ 155560786Sps public void 155660786Spsremove_top(n) 155760786Sps int n; 155860786Sps{ 155960786Sps#if MSDOS_COMPILER==WIN32C 156060786Sps SMALL_RECT rcSrc, rcClip; 156160786Sps CHAR_INFO fillchar; 156260786Sps COORD new_org; 156360786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 156460786Sps 156560786Sps if (n >= sc_height - 1) 156660786Sps { 156760786Sps clear(); 156860786Sps home(); 156960786Sps return; 157060786Sps } 157160786Sps 157260786Sps flush(); 157360786Sps 157460786Sps GetConsoleScreenBufferInfo(con_out, &csbi); 157560786Sps 157660786Sps /* Get the extent of all-visible-rows-but-the-last. */ 157760786Sps rcSrc.Left = csbi.srWindow.Left; 157860786Sps rcSrc.Top = csbi.srWindow.Top + n; 157960786Sps rcSrc.Right = csbi.srWindow.Right; 158060786Sps rcSrc.Bottom = csbi.srWindow.Bottom; 158160786Sps 158260786Sps /* Get the clip rectangle. */ 158360786Sps rcClip.Left = rcSrc.Left; 158460786Sps rcClip.Top = csbi.srWindow.Top; 158560786Sps rcClip.Right = rcSrc.Right; 158660786Sps rcClip.Bottom = rcSrc.Bottom ; 158760786Sps 158860786Sps /* Move the source window up n rows. */ 158960786Sps new_org.X = rcSrc.Left; 159060786Sps new_org.Y = rcSrc.Top - n; 159160786Sps 159260786Sps /* Fill the right character and attributes. */ 159360786Sps fillchar.Char.AsciiChar = ' '; 159460786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 159560786Sps fillchar.Attributes = curr_attr; 159660786Sps 159760786Sps ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 159860786Sps 159960786Sps /* Position cursor on first blank line. */ 160060786Sps goto_line(sc_height - n - 1); 160160786Sps#endif 160260786Sps} 160360786Sps 160460786Sps/* 160560786Sps * Move cursor to lower left corner of screen. 160660786Sps */ 160760786Sps public void 160860786Spslower_left() 160960786Sps{ 161060786Sps#if !MSDOS_COMPILER 161160786Sps tputs(sc_lower_left, 1, putchr); 161260786Sps#else 161360786Sps flush(); 161460786Sps _settextposition(sc_height, 1); 161560786Sps#endif 161660786Sps} 161760786Sps 161860786Sps/* 161960786Sps * Check if the console size has changed and reset internals 162060786Sps * (in lieu of SIGWINCH for WIN32). 162160786Sps */ 162260786Sps public void 162360786Spscheck_winch() 162460786Sps{ 162560786Sps#if MSDOS_COMPILER==WIN32C 162660786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 162760786Sps COORD size; 162860786Sps 162960786Sps if (con_out == INVALID_HANDLE_VALUE) 163060786Sps return; 163160786Sps 163260786Sps flush(); 163360786Sps GetConsoleScreenBufferInfo(con_out, &scr); 163460786Sps size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 163560786Sps size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 163660786Sps if (size.Y != sc_height || size.X != sc_width) 163760786Sps { 163860786Sps sc_height = size.Y; 163960786Sps sc_width = size.X; 164060786Sps if (!no_init && con_out_ours == con_out) 164160786Sps SetConsoleScreenBufferSize(con_out, size); 164260786Sps pos_init(); 164360786Sps wscroll = (sc_height + 1) / 2; 164460786Sps screen_trashed = 1; 164560786Sps } 164660786Sps#endif 164760786Sps} 164860786Sps 164960786Sps/* 165060786Sps * Goto a specific line on the screen. 165160786Sps */ 165260786Sps public void 165360786Spsgoto_line(slinenum) 165460786Sps int slinenum; 165560786Sps{ 165660786Sps#if !MSDOS_COMPILER 165760786Sps tputs(tgoto(sc_move, 0, slinenum), 1, putchr); 165860786Sps#else 165960786Sps flush(); 166060786Sps _settextposition(slinenum+1, 1); 166160786Sps#endif 166260786Sps} 166360786Sps 166460786Sps#if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC 166560786Sps/* 166660786Sps * Create an alternate screen which is all white. 166760786Sps * This screen is used to create a "flash" effect, by displaying it 166860786Sps * briefly and then switching back to the normal screen. 166960786Sps * {{ Yuck! There must be a better way to get a visual bell. }} 167060786Sps */ 167160786Sps static void 167260786Spscreate_flash() 167360786Sps{ 167460786Sps#if MSDOS_COMPILER==MSOFTC 167560786Sps struct videoconfig w; 167660786Sps char *blanks; 167760786Sps int row, col; 167860786Sps 167960786Sps _getvideoconfig(&w); 168060786Sps videopages = w.numvideopages; 168160786Sps if (videopages < 2) 168260786Sps { 168360786Sps so_enter(); 168460786Sps so_exit(); 168560786Sps } else 168660786Sps { 168760786Sps _setactivepage(1); 168860786Sps so_enter(); 168960786Sps blanks = (char *) ecalloc(w.numtextcols, sizeof(char)); 169060786Sps for (col = 0; col < w.numtextcols; col++) 169160786Sps blanks[col] = ' '; 169260786Sps for (row = w.numtextrows; row > 0; row--) 169360786Sps _outmem(blanks, w.numtextcols); 169460786Sps _setactivepage(0); 169560786Sps _setvisualpage(0); 169660786Sps free(blanks); 169760786Sps so_exit(); 169860786Sps } 169960786Sps#else 170060786Sps#if MSDOS_COMPILER==BORLANDC 170160786Sps register int n; 170260786Sps 170360786Sps whitescreen = (unsigned short *) 170460786Sps malloc(sc_width * sc_height * sizeof(short)); 170560786Sps if (whitescreen == NULL) 170660786Sps return; 170760786Sps for (n = 0; n < sc_width * sc_height; n++) 170860786Sps whitescreen[n] = 0x7020; 170960786Sps#else 171060786Sps#if MSDOS_COMPILER==WIN32C 171160786Sps register int n; 171260786Sps 171360786Sps whitescreen = (WORD *) 171460786Sps malloc(sc_height * sc_width * sizeof(WORD)); 171560786Sps if (whitescreen == NULL) 171660786Sps return; 171760786Sps /* Invert the standard colors. */ 171860786Sps for (n = 0; n < sc_width * sc_height; n++) 171960786Sps whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color); 172060786Sps#endif 172160786Sps#endif 172260786Sps#endif 172360786Sps flash_created = 1; 172460786Sps} 172560786Sps#endif /* MSDOS_COMPILER */ 172660786Sps 172760786Sps/* 172860786Sps * Output the "visual bell", if there is one. 172960786Sps */ 173060786Sps public void 173160786Spsvbell() 173260786Sps{ 173360786Sps#if !MSDOS_COMPILER 173460786Sps if (*sc_visual_bell == '\0') 173560786Sps return; 173660786Sps tputs(sc_visual_bell, sc_height, putchr); 173760786Sps#else 173860786Sps#if MSDOS_COMPILER==DJGPPC 173960786Sps ScreenVisualBell(); 174060786Sps#else 174160786Sps#if MSDOS_COMPILER==MSOFTC 174260786Sps /* 174360786Sps * Create a flash screen on the second video page. 174460786Sps * Switch to that page, then switch back. 174560786Sps */ 174660786Sps if (!flash_created) 174760786Sps create_flash(); 174860786Sps if (videopages < 2) 174960786Sps return; 175060786Sps _setvisualpage(1); 175160786Sps delay(100); 175260786Sps _setvisualpage(0); 175360786Sps#else 175460786Sps#if MSDOS_COMPILER==BORLANDC 175560786Sps unsigned short *currscreen; 175660786Sps 175760786Sps /* 175860786Sps * Get a copy of the current screen. 175960786Sps * Display the flash screen. 176060786Sps * Then restore the old screen. 176160786Sps */ 176260786Sps if (!flash_created) 176360786Sps create_flash(); 176460786Sps if (whitescreen == NULL) 176560786Sps return; 176660786Sps currscreen = (unsigned short *) 176760786Sps malloc(sc_width * sc_height * sizeof(short)); 176860786Sps if (currscreen == NULL) return; 176960786Sps gettext(1, 1, sc_width, sc_height, currscreen); 177060786Sps puttext(1, 1, sc_width, sc_height, whitescreen); 177160786Sps delay(100); 177260786Sps puttext(1, 1, sc_width, sc_height, currscreen); 177360786Sps free(currscreen); 177460786Sps#else 177560786Sps#if MSDOS_COMPILER==WIN32C 177660786Sps /* paint screen with an inverse color */ 177760786Sps clear(); 177860786Sps 177960786Sps /* leave it displayed for 100 msec. */ 178060786Sps Sleep(100); 178160786Sps 178260786Sps /* restore with a redraw */ 178360786Sps repaint(); 178460786Sps#endif 178560786Sps#endif 178660786Sps#endif 178760786Sps#endif 178860786Sps#endif 178960786Sps} 179060786Sps 179160786Sps/* 179260786Sps * Make a noise. 179360786Sps */ 179460786Sps static void 179560786Spsbeep() 179660786Sps{ 179760786Sps#if !MSDOS_COMPILER 179860786Sps putchr('\7'); 179960786Sps#else 180060786Sps#if MSDOS_COMPILER==WIN32C 180160786Sps MessageBeep(0); 180260786Sps#else 180360786Sps write(1, "\7", 1); 180460786Sps#endif 180560786Sps#endif 180660786Sps} 180760786Sps 180860786Sps/* 180960786Sps * Ring the terminal bell. 181060786Sps */ 181160786Sps public void 181260786Spsbell() 181360786Sps{ 181460786Sps if (quiet == VERY_QUIET) 181560786Sps vbell(); 181660786Sps else 181760786Sps beep(); 181860786Sps} 181960786Sps 182060786Sps/* 182160786Sps * Clear the screen. 182260786Sps */ 182360786Sps public void 182460786Spsclear() 182560786Sps{ 182660786Sps#if !MSDOS_COMPILER 182760786Sps tputs(sc_clear, sc_height, putchr); 182860786Sps#else 182960786Sps flush(); 183060786Sps#if MSDOS_COMPILER==WIN32C 183160786Sps /* 183260786Sps * This will clear only the currently visible rows of the NT 183360786Sps * console buffer, which means none of the precious scrollback 183460786Sps * rows are touched making for faster scrolling. Note that, if 183560786Sps * the window has fewer columns than the console buffer (i.e. 183660786Sps * there is a horizontal scrollbar as well), the entire width 183760786Sps * of the visible rows will be cleared. 183860786Sps */ 183960786Sps { 184060786Sps COORD topleft; 184160786Sps DWORD nchars; 184260786Sps DWORD winsz; 184360786Sps CONSOLE_SCREEN_BUFFER_INFO csbi; 184460786Sps 184560786Sps /* get the number of cells in the current buffer */ 184660786Sps GetConsoleScreenBufferInfo(con_out, &csbi); 184760786Sps winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); 184860786Sps topleft.X = 0; 184960786Sps topleft.Y = csbi.srWindow.Top; 185060786Sps 185160786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 185260786Sps FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars); 185360786Sps FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars); 185460786Sps } 185560786Sps#else 185660786Sps _clearscreen(_GCLEARSCREEN); 185760786Sps#endif 185860786Sps#endif 185960786Sps} 186060786Sps 186160786Sps/* 186260786Sps * Clear from the cursor to the end of the cursor's line. 186360786Sps * {{ This must not move the cursor. }} 186460786Sps */ 186560786Sps public void 186660786Spsclear_eol() 186760786Sps{ 186860786Sps#if !MSDOS_COMPILER 186960786Sps tputs(sc_eol_clear, 1, putchr); 187060786Sps#else 187160786Sps#if MSDOS_COMPILER==MSOFTC 187260786Sps short top, left; 187360786Sps short bot, right; 187460786Sps struct rccoord tpos; 187560786Sps 187660786Sps flush(); 187760786Sps /* 187860786Sps * Save current state. 187960786Sps */ 188060786Sps tpos = _gettextposition(); 188160786Sps _gettextwindow(&top, &left, &bot, &right); 188260786Sps /* 188360786Sps * Set a temporary window to the current line, 188460786Sps * from the cursor's position to the right edge of the screen. 188560786Sps * Then clear that window. 188660786Sps */ 188760786Sps _settextwindow(tpos.row, tpos.col, tpos.row, sc_width); 188860786Sps _clearscreen(_GWINDOW); 188960786Sps /* 189060786Sps * Restore state. 189160786Sps */ 189260786Sps _settextwindow(top, left, bot, right); 189360786Sps _settextposition(tpos.row, tpos.col); 189460786Sps#else 189560786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 189660786Sps flush(); 189760786Sps clreol(); 189860786Sps#else 189960786Sps#if MSDOS_COMPILER==WIN32C 190060786Sps DWORD nchars; 190160786Sps COORD cpos; 190260786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 190360786Sps 190460786Sps flush(); 190560786Sps memset(&scr, 0, sizeof(scr)); 190660786Sps GetConsoleScreenBufferInfo(con_out, &scr); 190760786Sps cpos.X = scr.dwCursorPosition.X; 190860786Sps cpos.Y = scr.dwCursorPosition.Y; 190960786Sps curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 191060786Sps FillConsoleOutputAttribute(con_out, curr_attr, 191160786Sps scr.dwSize.X - cpos.X, cpos, &nchars); 191260786Sps FillConsoleOutputCharacter(con_out, ' ', 191360786Sps scr.dwSize.X - cpos.X, cpos, &nchars); 191460786Sps#endif 191560786Sps#endif 191660786Sps#endif 191760786Sps#endif 191860786Sps} 191960786Sps 192060786Sps/* 192160786Sps * Clear the current line. 192260786Sps * Clear the screen if there's off-screen memory below the display. 192360786Sps */ 192460786Sps static void 192560786Spsclear_eol_bot() 192660786Sps{ 192760786Sps#if MSDOS_COMPILER 192860786Sps clear_eol(); 192960786Sps#else 193060786Sps if (below_mem) 193160786Sps tputs(sc_eos_clear, 1, putchr); 193260786Sps else 193360786Sps tputs(sc_eol_clear, 1, putchr); 193460786Sps#endif 193560786Sps} 193660786Sps 193760786Sps/* 193860786Sps * Clear the bottom line of the display. 193960786Sps * Leave the cursor at the beginning of the bottom line. 194060786Sps */ 194160786Sps public void 194260786Spsclear_bot() 194360786Sps{ 194460786Sps /* 194560786Sps * If we're in a non-normal attribute mode, temporarily exit 194660786Sps * the mode while we do the clear. Some terminals fill the 194760786Sps * cleared area with the current attribute. 194860786Sps */ 194960786Sps lower_left(); 195060786Sps switch (attrmode) 195160786Sps { 195260786Sps case AT_STANDOUT: 195360786Sps so_exit(); 195460786Sps clear_eol_bot(); 195560786Sps so_enter(); 195660786Sps break; 195760786Sps case AT_UNDERLINE: 195860786Sps ul_exit(); 195960786Sps clear_eol_bot(); 196060786Sps ul_enter(); 196160786Sps break; 196260786Sps case AT_BOLD: 196360786Sps bo_exit(); 196460786Sps clear_eol_bot(); 196560786Sps bo_enter(); 196660786Sps break; 196760786Sps case AT_BLINK: 196860786Sps bl_exit(); 196960786Sps clear_eol_bot(); 197060786Sps bl_enter(); 197160786Sps break; 197260786Sps default: 197360786Sps clear_eol_bot(); 197460786Sps break; 197560786Sps } 197660786Sps} 197760786Sps 197860786Sps/* 197960786Sps * Begin "standout" (bold, underline, or whatever). 198060786Sps */ 198160786Sps public void 198260786Spsso_enter() 198360786Sps{ 198460786Sps#if !MSDOS_COMPILER 198560786Sps tputs(sc_s_in, 1, putchr); 198660786Sps#else 198760786Sps flush(); 198860786Sps SETCOLORS(so_fg_color, so_bg_color); 198960786Sps#endif 199060786Sps attrmode = AT_STANDOUT; 199160786Sps} 199260786Sps 199360786Sps/* 199460786Sps * End "standout". 199560786Sps */ 199660786Sps public void 199760786Spsso_exit() 199860786Sps{ 199960786Sps#if !MSDOS_COMPILER 200060786Sps tputs(sc_s_out, 1, putchr); 200160786Sps#else 200260786Sps flush(); 200360786Sps SETCOLORS(nm_fg_color, nm_bg_color); 200460786Sps#endif 200560786Sps attrmode = AT_NORMAL; 200660786Sps} 200760786Sps 200860786Sps/* 200960786Sps * Begin "underline" (hopefully real underlining, 201060786Sps * otherwise whatever the terminal provides). 201160786Sps */ 201260786Sps public void 201360786Spsul_enter() 201460786Sps{ 201560786Sps#if !MSDOS_COMPILER 201660786Sps tputs(sc_u_in, 1, putchr); 201760786Sps#else 201860786Sps flush(); 201960786Sps SETCOLORS(ul_fg_color, ul_bg_color); 202060786Sps#endif 202160786Sps attrmode = AT_UNDERLINE; 202260786Sps} 202360786Sps 202460786Sps/* 202560786Sps * End "underline". 202660786Sps */ 202760786Sps public void 202860786Spsul_exit() 202960786Sps{ 203060786Sps#if !MSDOS_COMPILER 203160786Sps tputs(sc_u_out, 1, putchr); 203260786Sps#else 203360786Sps flush(); 203460786Sps SETCOLORS(nm_fg_color, nm_bg_color); 203560786Sps#endif 203660786Sps attrmode = AT_NORMAL; 203760786Sps} 203860786Sps 203960786Sps/* 204060786Sps * Begin "bold" 204160786Sps */ 204260786Sps public void 204360786Spsbo_enter() 204460786Sps{ 204560786Sps#if !MSDOS_COMPILER 204660786Sps tputs(sc_b_in, 1, putchr); 204760786Sps#else 204860786Sps flush(); 204960786Sps SETCOLORS(bo_fg_color, bo_bg_color); 205060786Sps#endif 205160786Sps attrmode = AT_BOLD; 205260786Sps} 205360786Sps 205460786Sps/* 205560786Sps * End "bold". 205660786Sps */ 205760786Sps public void 205860786Spsbo_exit() 205960786Sps{ 206060786Sps#if !MSDOS_COMPILER 206160786Sps tputs(sc_b_out, 1, putchr); 206260786Sps#else 206360786Sps flush(); 206460786Sps SETCOLORS(nm_fg_color, nm_bg_color); 206560786Sps#endif 206660786Sps attrmode = AT_NORMAL; 206760786Sps} 206860786Sps 206960786Sps/* 207060786Sps * Begin "blink" 207160786Sps */ 207260786Sps public void 207360786Spsbl_enter() 207460786Sps{ 207560786Sps#if !MSDOS_COMPILER 207660786Sps tputs(sc_bl_in, 1, putchr); 207760786Sps#else 207860786Sps flush(); 207960786Sps SETCOLORS(bl_fg_color, bl_bg_color); 208060786Sps#endif 208160786Sps attrmode = AT_BLINK; 208260786Sps} 208360786Sps 208460786Sps/* 208560786Sps * End "blink". 208660786Sps */ 208760786Sps public void 208860786Spsbl_exit() 208960786Sps{ 209060786Sps#if !MSDOS_COMPILER 209160786Sps tputs(sc_bl_out, 1, putchr); 209260786Sps#else 209360786Sps flush(); 209460786Sps SETCOLORS(nm_fg_color, nm_bg_color); 209560786Sps#endif 209660786Sps attrmode = AT_NORMAL; 209760786Sps} 209860786Sps 209960786Sps#if 0 /* No longer used */ 210060786Sps/* 210160786Sps * Erase the character to the left of the cursor 210260786Sps * and move the cursor left. 210360786Sps */ 210460786Sps public void 210560786Spsbackspace() 210660786Sps{ 210760786Sps#if !MSDOS_COMPILER 210860786Sps /* 210960786Sps * Erase the previous character by overstriking with a space. 211060786Sps */ 211160786Sps tputs(sc_backspace, 1, putchr); 211260786Sps putchr(' '); 211360786Sps tputs(sc_backspace, 1, putchr); 211460786Sps#else 211560786Sps#if MSDOS_COMPILER==MSOFTC 211660786Sps struct rccoord tpos; 211760786Sps 211860786Sps flush(); 211960786Sps tpos = _gettextposition(); 212060786Sps if (tpos.col <= 1) 212160786Sps return; 212260786Sps _settextposition(tpos.row, tpos.col-1); 212360786Sps _outtext(" "); 212460786Sps _settextposition(tpos.row, tpos.col-1); 212560786Sps#else 212660786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 212760786Sps cputs("\b"); 212860786Sps#else 212960786Sps#if MSDOS_COMPILER==WIN32C 213060786Sps COORD cpos; 213160786Sps DWORD cChars; 213260786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 213360786Sps 213460786Sps flush(); 213560786Sps GetConsoleScreenBufferInfo(con_out, &scr); 213660786Sps cpos = scr.dwCursorPosition; 213760786Sps if (cpos.X <= 0) 213860786Sps return; 213960786Sps cpos.X--; 214060786Sps SetConsoleCursorPosition(con_out, cpos); 214160786Sps FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars); 214260786Sps SetConsoleCursorPosition(con_out, cpos); 214360786Sps#endif 214460786Sps#endif 214560786Sps#endif 214660786Sps#endif 214760786Sps} 214860786Sps#endif /* 0 */ 214960786Sps 215060786Sps/* 215160786Sps * Output a plain backspace, without erasing the previous char. 215260786Sps */ 215360786Sps public void 215460786Spsputbs() 215560786Sps{ 215660786Sps#if !MSDOS_COMPILER 215760786Sps tputs(sc_backspace, 1, putchr); 215860786Sps#else 215960786Sps int row, col; 216060786Sps 216160786Sps flush(); 216260786Sps { 216360786Sps#if MSDOS_COMPILER==MSOFTC 216460786Sps struct rccoord tpos; 216560786Sps tpos = _gettextposition(); 216660786Sps row = tpos.row; 216760786Sps col = tpos.col; 216860786Sps#else 216960786Sps#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 217060786Sps row = wherey(); 217160786Sps col = wherex(); 217260786Sps#else 217360786Sps#if MSDOS_COMPILER==WIN32C 217460786Sps CONSOLE_SCREEN_BUFFER_INFO scr; 217560786Sps GetConsoleScreenBufferInfo(con_out, &scr); 217660786Sps row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 217760786Sps col = scr.dwCursorPosition.X - scr.srWindow.Left + 1; 217860786Sps#endif 217960786Sps#endif 218060786Sps#endif 218160786Sps } 218260786Sps if (col <= 1) 218360786Sps return; 218460786Sps _settextposition(row, col-1); 218560786Sps#endif /* MSDOS_COMPILER */ 218660786Sps} 218760786Sps 218860786Sps#if MSDOS_COMPILER==WIN32C 218960786Sps/* 219060786Sps * Determine whether an input character is waiting to be read. 219160786Sps */ 219260786Sps static int 219360786Spswin32_kbhit(tty) 219460786Sps HANDLE tty; 219560786Sps{ 219660786Sps INPUT_RECORD ip; 219760786Sps DWORD read; 219860786Sps 219960786Sps if (keyCount > 0) 220060786Sps return (TRUE); 220160786Sps 220260786Sps currentKey.ascii = 0; 220360786Sps currentKey.scan = 0; 220460786Sps 220560786Sps /* 220660786Sps * Wait for a real key-down event, but 220760786Sps * ignore SHIFT and CONTROL key events. 220860786Sps */ 220960786Sps do 221060786Sps { 221160786Sps PeekConsoleInput(tty, &ip, 1, &read); 221260786Sps if (read == 0) 221360786Sps return (FALSE); 221460786Sps ReadConsoleInput(tty, &ip, 1, &read); 221560786Sps } while (ip.EventType != KEY_EVENT || 221660786Sps ip.Event.KeyEvent.bKeyDown != TRUE || 221760786Sps ip.Event.KeyEvent.wVirtualScanCode == 0 || 221860786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT || 221960786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL || 222060786Sps ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU); 222160786Sps 222260786Sps currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar; 222360786Sps currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode; 222460786Sps keyCount = ip.Event.KeyEvent.wRepeatCount; 222560786Sps 222660786Sps if (ip.Event.KeyEvent.dwControlKeyState & 222760786Sps (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) 222860786Sps { 222960786Sps switch (currentKey.scan) 223060786Sps { 223160786Sps case PCK_ALT_E: /* letter 'E' */ 223260786Sps currentKey.ascii = 0; 223360786Sps break; 223460786Sps } 223560786Sps } else if (ip.Event.KeyEvent.dwControlKeyState & 223660786Sps (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 223760786Sps { 223860786Sps switch (currentKey.scan) 223960786Sps { 224060786Sps case PCK_RIGHT: /* right arrow */ 224160786Sps currentKey.scan = PCK_CTL_RIGHT; 224260786Sps break; 224360786Sps case PCK_LEFT: /* left arrow */ 224460786Sps currentKey.scan = PCK_CTL_LEFT; 224560786Sps break; 224660786Sps case PCK_DELETE: /* delete */ 224760786Sps currentKey.scan = PCK_CTL_DELETE; 224860786Sps break; 224960786Sps } 225060786Sps } 225160786Sps return (TRUE); 225260786Sps} 225360786Sps 225460786Sps/* 225560786Sps * Read a character from the keyboard. 225660786Sps */ 225760786Sps public char 225860786SpsWIN32getch(tty) 225960786Sps int tty; 226060786Sps{ 226160786Sps int ascii; 226260786Sps 226360786Sps if (pending_scancode) 226460786Sps { 226560786Sps pending_scancode = 0; 226660786Sps return ((char)(currentKey.scan & 0x00FF)); 226760786Sps } 226860786Sps 226960786Sps while (win32_kbhit((HANDLE)tty) == FALSE) 227060786Sps { 227160786Sps Sleep(20); 227260786Sps if (ABORT_SIGS()) 227360786Sps return ('\003'); 227460786Sps continue; 227560786Sps } 227660786Sps keyCount --; 227760786Sps ascii = currentKey.ascii; 227860786Sps /* 227960786Sps * On PC's, the extended keys return a 2 byte sequence beginning 228060786Sps * with '00', so if the ascii code is 00, the next byte will be 228160786Sps * the lsb of the scan code. 228260786Sps */ 228360786Sps pending_scancode = (ascii == 0x00); 228460786Sps return ((char)ascii); 228560786Sps} 228660786Sps#endif 2287