"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "less-424/screen.c" of archive less-424.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*
    2  * Copyright (C) 1984-2008  Mark Nudelman
    3  *
    4  * You may distribute under the terms of either the GNU General Public
    5  * License or the Less License, as specified in the README file.
    6  *
    7  * For more information about less, or for information on how to
    8  * contact the author, see the README file.
    9  */
   10 
   11 
   12 /*
   13  * Routines which deal with the characteristics of the terminal.
   14  * Uses termcap to be as terminal-independent as possible.
   15  */
   16 
   17 #include "less.h"
   18 #include "cmd.h"
   19 
   20 #if MSDOS_COMPILER
   21 #include "pckeys.h"
   22 #if MSDOS_COMPILER==MSOFTC
   23 #include <graph.h>
   24 #else
   25 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
   26 #include <conio.h>
   27 #if MSDOS_COMPILER==DJGPPC
   28 #include <pc.h>
   29 extern int fd0;
   30 #endif
   31 #else
   32 #if MSDOS_COMPILER==WIN32C
   33 #include <windows.h>
   34 #endif
   35 #endif
   36 #endif
   37 #include <time.h>
   38 
   39 #else
   40 
   41 #if HAVE_SYS_IOCTL_H
   42 #include <sys/ioctl.h>
   43 #endif
   44 
   45 #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
   46 #include <termios.h>
   47 #else
   48 #if HAVE_TERMIO_H
   49 #include <termio.h>
   50 #else
   51 #if HAVE_SGSTAT_H
   52 #include <sgstat.h>
   53 #else
   54 #include <sgtty.h>
   55 #endif
   56 #endif
   57 #endif
   58 
   59 #if HAVE_TERMCAP_H
   60 #include <termcap.h>
   61 #endif
   62 #ifdef _OSK
   63 #include <signal.h>
   64 #endif
   65 #if OS2
   66 #include <sys/signal.h>
   67 #include "pckeys.h"
   68 #endif
   69 #if HAVE_SYS_STREAM_H
   70 #include <sys/stream.h>
   71 #endif
   72 #if HAVE_SYS_PTEM_H
   73 #include <sys/ptem.h>
   74 #endif
   75 
   76 #endif /* MSDOS_COMPILER */
   77 
   78 /*
   79  * Check for broken termios package that forces you to manually
   80  * set the line discipline.
   81  */
   82 #ifdef __ultrix__
   83 #define MUST_SET_LINE_DISCIPLINE 1
   84 #else
   85 #define MUST_SET_LINE_DISCIPLINE 0
   86 #endif
   87 
   88 #if OS2
   89 #define	DEFAULT_TERM		"ansi"
   90 static char *windowid;
   91 #else
   92 #define	DEFAULT_TERM		"unknown"
   93 #endif
   94 
   95 #if MSDOS_COMPILER==MSOFTC
   96 static int videopages;
   97 static long msec_loops;
   98 static int flash_created = 0;
   99 #define	SETCOLORS(fg,bg)	{ _settextcolor(fg); _setbkcolor(bg); }
  100 #endif
  101 
  102 #if MSDOS_COMPILER==BORLANDC
  103 static unsigned short *whitescreen;
  104 static int flash_created = 0;
  105 #endif
  106 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  107 #define _settextposition(y,x)   gotoxy(x,y)
  108 #define _clearscreen(m)         clrscr()
  109 #define _outtext(s)             cputs(s)
  110 #define	SETCOLORS(fg,bg)	{ textcolor(fg); textbackground(bg); }
  111 extern int sc_height;
  112 #endif
  113 
  114 #if MSDOS_COMPILER==WIN32C
  115 struct keyRecord
  116 {
  117 	int ascii;
  118 	int scan;
  119 } currentKey;
  120 
  121 static int keyCount = 0;
  122 static WORD curr_attr;
  123 static int pending_scancode = 0;
  124 static WORD *whitescreen;
  125 
  126 static HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */
  127 static HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */
  128 HANDLE con_out = INVALID_HANDLE_VALUE;             /* current console */
  129 
  130 extern int quitting;
  131 static void win32_init_term();
  132 static void win32_deinit_term();
  133 
  134 #define FG_COLORS       (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)
  135 #define BG_COLORS       (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY)
  136 #define	MAKEATTR(fg,bg)		((WORD)((fg)|((bg)<<4)))
  137 #define	SETCOLORS(fg,bg)	{ curr_attr = MAKEATTR(fg,bg); \
  138 				if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \
  139 				error("SETCOLORS failed"); }
  140 #endif
  141 
  142 #if MSDOS_COMPILER
  143 public int nm_fg_color;		/* Color of normal text */
  144 public int nm_bg_color;
  145 public int bo_fg_color;		/* Color of bold text */
  146 public int bo_bg_color;
  147 public int ul_fg_color;		/* Color of underlined text */
  148 public int ul_bg_color;
  149 public int so_fg_color;		/* Color of standout text */
  150 public int so_bg_color;
  151 public int bl_fg_color;		/* Color of blinking text */
  152 public int bl_bg_color;
  153 static int sy_fg_color;		/* Color of system text (before less) */
  154 static int sy_bg_color;
  155 
  156 #else
  157 
  158 /*
  159  * Strings passed to tputs() to do various terminal functions.
  160  */
  161 static char
  162 	*sc_pad,		/* Pad string */
  163 	*sc_home,		/* Cursor home */
  164 	*sc_addline,		/* Add line, scroll down following lines */
  165 	*sc_lower_left,		/* Cursor to last line, first column */
  166 	*sc_return,		/* Cursor to beginning of current line */
  167 	*sc_move,		/* General cursor positioning */
  168 	*sc_clear,		/* Clear screen */
  169 	*sc_eol_clear,		/* Clear to end of line */
  170 	*sc_eos_clear,		/* Clear to end of screen */
  171 	*sc_s_in,		/* Enter standout (highlighted) mode */
  172 	*sc_s_out,		/* Exit standout mode */
  173 	*sc_u_in,		/* Enter underline mode */
  174 	*sc_u_out,		/* Exit underline mode */
  175 	*sc_b_in,		/* Enter bold mode */
  176 	*sc_b_out,		/* Exit bold mode */
  177 	*sc_bl_in,		/* Enter blink mode */
  178 	*sc_bl_out,		/* Exit blink mode */
  179 	*sc_visual_bell,	/* Visual bell (flash screen) sequence */
  180 	*sc_backspace,		/* Backspace cursor */
  181 	*sc_s_keypad,		/* Start keypad mode */
  182 	*sc_e_keypad,		/* End keypad mode */
  183 	*sc_init,		/* Startup terminal initialization */
  184 	*sc_deinit;		/* Exit terminal de-initialization */
  185 #endif
  186 
  187 static int init_done = 0;
  188 
  189 public int auto_wrap;		/* Terminal does \r\n when write past margin */
  190 public int ignaw;		/* Terminal ignores \n immediately after wrap */
  191 public int erase_char;		/* The user's erase char */
  192 public int erase2_char;		/* The user's other erase char */
  193 public int kill_char;		/* The user's line-kill char */
  194 public int werase_char;		/* The user's word-erase char */
  195 public int sc_width, sc_height;	/* Height & width of screen */
  196 public int bo_s_width, bo_e_width;	/* Printing width of boldface seq */
  197 public int ul_s_width, ul_e_width;	/* Printing width of underline seq */
  198 public int so_s_width, so_e_width;	/* Printing width of standout seq */
  199 public int bl_s_width, bl_e_width;	/* Printing width of blink seq */
  200 public int above_mem, below_mem;	/* Memory retained above/below screen */
  201 public int can_goto_line;		/* Can move cursor to any line */
  202 public int clear_bg;		/* Clear fills with background color */
  203 public int missing_cap = 0;	/* Some capability is missing */
  204 
  205 static int attrmode = AT_NORMAL;
  206 extern int binattr;
  207 
  208 #if !MSDOS_COMPILER
  209 static char *cheaper();
  210 static void tmodes();
  211 #endif
  212 
  213 /*
  214  * These two variables are sometimes defined in,
  215  * and needed by, the termcap library.
  216  */
  217 #if MUST_DEFINE_OSPEED
  218 extern short ospeed;	/* Terminal output baud rate */
  219 extern char PC;		/* Pad character */
  220 #endif
  221 #ifdef _OSK
  222 short ospeed;
  223 char PC_, *UP, *BC;
  224 #endif
  225 
  226 extern int quiet;		/* If VERY_QUIET, use visual bell for bell */
  227 extern int no_back_scroll;
  228 extern int swindow;
  229 extern int no_init;
  230 extern int no_keypad;
  231 extern int sigs;
  232 extern int wscroll;
  233 extern int screen_trashed;
  234 extern int tty;
  235 extern int top_scroll;
  236 extern int oldbot;
  237 #if HILITE_SEARCH
  238 extern int hilite_search;
  239 #endif
  240 
  241 extern char *tgetstr();
  242 extern char *tgoto();
  243 
  244 
  245 /*
  246  * Change terminal to "raw mode", or restore to "normal" mode.
  247  * "Raw mode" means
  248  *	1. An outstanding read will complete on receipt of a single keystroke.
  249  *	2. Input is not echoed.
  250  *	3. On output, \n is mapped to \r\n.
  251  *	4. \t is NOT expanded into spaces.
  252  *	5. Signal-causing characters such as ctrl-C (interrupt),
  253  *	   etc. are NOT disabled.
  254  * It doesn't matter whether an input \n is mapped to \r, or vice versa.
  255  */
  256 	public void
  257 raw_mode(on)
  258 	int on;
  259 {
  260 	static int curr_on = 0;
  261 
  262 	if (on == curr_on)
  263 		return;
  264 	erase2_char = '\b'; /* in case OS doesn't know about erase2 */
  265 #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
  266     {
  267 	struct termios s;
  268 	static struct termios save_term;
  269 	static int saved_term = 0;
  270 
  271 	if (on)
  272 	{
  273 		/*
  274 		 * Get terminal modes.
  275 		 */
  276 		tcgetattr(tty, &s);
  277 
  278 		/*
  279 		 * Save modes and set certain variables dependent on modes.
  280 		 */
  281 		if (!saved_term)
  282 		{
  283 			save_term = s;
  284 			saved_term = 1;
  285 		}
  286 #if HAVE_OSPEED
  287 		switch (cfgetospeed(&s))
  288 		{
  289 #ifdef B0
  290 		case B0: ospeed = 0; break;
  291 #endif
  292 #ifdef B50
  293 		case B50: ospeed = 1; break;
  294 #endif
  295 #ifdef B75
  296 		case B75: ospeed = 2; break;
  297 #endif
  298 #ifdef B110
  299 		case B110: ospeed = 3; break;
  300 #endif
  301 #ifdef B134
  302 		case B134: ospeed = 4; break;
  303 #endif
  304 #ifdef B150
  305 		case B150: ospeed = 5; break;
  306 #endif
  307 #ifdef B200
  308 		case B200: ospeed = 6; break;
  309 #endif
  310 #ifdef B300
  311 		case B300: ospeed = 7; break;
  312 #endif
  313 #ifdef B600
  314 		case B600: ospeed = 8; break;
  315 #endif
  316 #ifdef B1200
  317 		case B1200: ospeed = 9; break;
  318 #endif
  319 #ifdef B1800
  320 		case B1800: ospeed = 10; break;
  321 #endif
  322 #ifdef B2400
  323 		case B2400: ospeed = 11; break;
  324 #endif
  325 #ifdef B4800
  326 		case B4800: ospeed = 12; break;
  327 #endif
  328 #ifdef B9600
  329 		case B9600: ospeed = 13; break;
  330 #endif
  331 #ifdef EXTA
  332 		case EXTA: ospeed = 14; break;
  333 #endif
  334 #ifdef EXTB
  335 		case EXTB: ospeed = 15; break;
  336 #endif
  337 #ifdef B57600
  338 		case B57600: ospeed = 16; break;
  339 #endif
  340 #ifdef B115200
  341 		case B115200: ospeed = 17; break;
  342 #endif
  343 		default: ;
  344 		}
  345 #endif
  346 		erase_char = s.c_cc[VERASE];
  347 #ifdef VERASE2
  348 		erase2_char = s.c_cc[VERASE2];
  349 #endif
  350 		kill_char = s.c_cc[VKILL];
  351 #ifdef VWERASE
  352 		werase_char = s.c_cc[VWERASE];
  353 #else
  354 		werase_char = CONTROL('W');
  355 #endif
  356 
  357 		/*
  358 		 * Set the modes to the way we want them.
  359 		 */
  360 		s.c_lflag &= ~(0
  361 #ifdef ICANON
  362 			| ICANON
  363 #endif
  364 #ifdef ECHO
  365 			| ECHO
  366 #endif
  367 #ifdef ECHOE
  368 			| ECHOE
  369 #endif
  370 #ifdef ECHOK
  371 			| ECHOK
  372 #endif
  373 #if ECHONL
  374 			| ECHONL
  375 #endif
  376 		);
  377 
  378 		s.c_oflag |= (0
  379 #ifdef OXTABS
  380 			| OXTABS
  381 #else
  382 #ifdef TAB3
  383 			| TAB3
  384 #else
  385 #ifdef XTABS
  386 			| XTABS
  387 #endif
  388 #endif
  389 #endif
  390 #ifdef OPOST
  391 			| OPOST
  392 #endif
  393 #ifdef ONLCR
  394 			| ONLCR
  395 #endif
  396 		);
  397 
  398 		s.c_oflag &= ~(0
  399 #ifdef ONOEOT
  400 			| ONOEOT
  401 #endif
  402 #ifdef OCRNL
  403 			| OCRNL
  404 #endif
  405 #ifdef ONOCR
  406 			| ONOCR
  407 #endif
  408 #ifdef ONLRET
  409 			| ONLRET
  410 #endif
  411 		);
  412 		s.c_cc[VMIN] = 1;
  413 		s.c_cc[VTIME] = 0;
  414 #ifdef VLNEXT
  415 		s.c_cc[VLNEXT] = 0;
  416 #endif
  417 #ifdef VDSUSP
  418 		s.c_cc[VDSUSP] = 0;
  419 #endif
  420 #if MUST_SET_LINE_DISCIPLINE
  421 		/*
  422 		 * System's termios is broken; need to explicitly
  423 		 * request TERMIODISC line discipline.
  424 		 */
  425 		s.c_line = TERMIODISC;
  426 #endif
  427 	} else
  428 	{
  429 		/*
  430 		 * Restore saved modes.
  431 		 */
  432 		s = save_term;
  433 	}
  434 #if HAVE_FSYNC
  435 	fsync(tty);
  436 #endif
  437 	tcsetattr(tty, TCSADRAIN, &s);
  438 #if MUST_SET_LINE_DISCIPLINE
  439 	if (!on)
  440 	{
  441 		/*
  442 		 * Broken termios *ignores* any line discipline
  443 		 * except TERMIODISC.  A different old line discipline
  444 		 * is therefore not restored, yet.  Restore the old
  445 		 * line discipline by hand.
  446 		 */
  447 		ioctl(tty, TIOCSETD, &save_term.c_line);
  448 	}
  449 #endif
  450     }
  451 #else
  452 #ifdef TCGETA
  453     {
  454 	struct termio s;
  455 	static struct termio save_term;
  456 	static int saved_term = 0;
  457 
  458 	if (on)
  459 	{
  460 		/*
  461 		 * Get terminal modes.
  462 		 */
  463 		ioctl(tty, TCGETA, &s);
  464 
  465 		/*
  466 		 * Save modes and set certain variables dependent on modes.
  467 		 */
  468 		if (!saved_term)
  469 		{
  470 			save_term = s;
  471 			saved_term = 1;
  472 		}
  473 #if HAVE_OSPEED
  474 		ospeed = s.c_cflag & CBAUD;
  475 #endif
  476 		erase_char = s.c_cc[VERASE];
  477 		kill_char = s.c_cc[VKILL];
  478 #ifdef VWERASE
  479 		werase_char = s.c_cc[VWERASE];
  480 #else
  481 		werase_char = CONTROL('W');
  482 #endif
  483 
  484 		/*
  485 		 * Set the modes to the way we want them.
  486 		 */
  487 		s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  488 		s.c_oflag |=  (OPOST|ONLCR|TAB3);
  489 		s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
  490 		s.c_cc[VMIN] = 1;
  491 		s.c_cc[VTIME] = 0;
  492 	} else
  493 	{
  494 		/*
  495 		 * Restore saved modes.
  496 		 */
  497 		s = save_term;
  498 	}
  499 	ioctl(tty, TCSETAW, &s);
  500     }
  501 #else
  502 #ifdef TIOCGETP
  503     {
  504 	struct sgttyb s;
  505 	static struct sgttyb save_term;
  506 	static int saved_term = 0;
  507 
  508 	if (on)
  509 	{
  510 		/*
  511 		 * Get terminal modes.
  512 		 */
  513 		ioctl(tty, TIOCGETP, &s);
  514 
  515 		/*
  516 		 * Save modes and set certain variables dependent on modes.
  517 		 */
  518 		if (!saved_term)
  519 		{
  520 			save_term = s;
  521 			saved_term = 1;
  522 		}
  523 #if HAVE_OSPEED
  524 		ospeed = s.sg_ospeed;
  525 #endif
  526 		erase_char = s.sg_erase;
  527 		kill_char = s.sg_kill;
  528 		werase_char = CONTROL('W');
  529 
  530 		/*
  531 		 * Set the modes to the way we want them.
  532 		 */
  533 		s.sg_flags |= CBREAK;
  534 		s.sg_flags &= ~(ECHO|XTABS);
  535 	} else
  536 	{
  537 		/*
  538 		 * Restore saved modes.
  539 		 */
  540 		s = save_term;
  541 	}
  542 	ioctl(tty, TIOCSETN, &s);
  543     }
  544 #else
  545 #ifdef _OSK
  546     {
  547 	struct sgbuf s;
  548 	static struct sgbuf save_term;
  549 	static int saved_term = 0;
  550 
  551 	if (on)
  552 	{
  553 		/*
  554 		 * Get terminal modes.
  555 		 */
  556 		_gs_opt(tty, &s);
  557 
  558 		/*
  559 		 * Save modes and set certain variables dependent on modes.
  560 		 */
  561 		if (!saved_term)
  562 		{
  563 			save_term = s;
  564 			saved_term = 1;
  565 		}
  566 		erase_char = s.sg_bspch;
  567 		kill_char = s.sg_dlnch;
  568 		werase_char = CONTROL('W');
  569 
  570 		/*
  571 		 * Set the modes to the way we want them.
  572 		 */
  573 		s.sg_echo = 0;
  574 		s.sg_eofch = 0;
  575 		s.sg_pause = 0;
  576 		s.sg_psch = 0;
  577 	} else
  578 	{
  579 		/*
  580 		 * Restore saved modes.
  581 		 */
  582 		s = save_term;
  583 	}
  584 	_ss_opt(tty, &s);
  585     }
  586 #else
  587 	/* MS-DOS, Windows, or OS2 */
  588 #if OS2
  589 	/* OS2 */
  590 	LSIGNAL(SIGINT, SIG_IGN);
  591 #endif
  592 	erase_char = '\b';
  593 #if MSDOS_COMPILER==DJGPPC
  594 	kill_char = CONTROL('U');
  595 	/*
  596 	 * So that when we shell out or run another program, its
  597 	 * stdin is in cooked mode.  We do not switch stdin to binary
  598 	 * mode if fd0 is zero, since that means we were called before
  599 	 * tty was reopened in open_getchr, in which case we would be
  600 	 * changing the original stdin device outside less.
  601 	 */
  602 	if (fd0 != 0)
  603 		setmode(0, on ? O_BINARY : O_TEXT);
  604 #else
  605 	kill_char = ESC;
  606 #endif
  607 	werase_char = CONTROL('W');
  608 #endif
  609 #endif
  610 #endif
  611 #endif
  612 	curr_on = on;
  613 }
  614 
  615 #if !MSDOS_COMPILER
  616 /*
  617  * Some glue to prevent calling termcap functions if tgetent() failed.
  618  */
  619 static int hardcopy;
  620 
  621 	static char *
  622 ltget_env(capname)
  623 	char *capname;
  624 {
  625 	char name[16];
  626 	char *s;
  627 
  628 	s = lgetenv("LESS_TERMCAP_DEBUG");
  629 	if (s != NULL && *s != '\0')
  630 	{
  631 		struct env { struct env *next; char *name; char *value; };
  632 		static struct env *envs = NULL;
  633 		struct env *p;
  634 		for (p = envs;  p != NULL;  p = p->next)
  635 			if (strcmp(p->name, capname) == 0)
  636 				return p->value;
  637 		p = (struct env *) ecalloc(1, sizeof(struct env));
  638 		p->name = save(capname);
  639 		p->value = (char *) ecalloc(strlen(capname)+3, sizeof(char));
  640 		sprintf(p->value, "<%s>", capname);
  641 		p->next = envs;
  642 		envs = p;
  643 		return p->value;
  644 	}
  645 	strcpy(name, "LESS_TERMCAP_");
  646 	strcat(name, capname);
  647 	return (lgetenv(name));
  648 }
  649 
  650 	static int
  651 ltgetflag(capname)
  652 	char *capname;
  653 {
  654 	char *s;
  655 
  656 	if ((s = ltget_env(capname)) != NULL)
  657 		return (*s != '\0' && *s != '0');
  658 	if (hardcopy)
  659 		return (0);
  660 	return (tgetflag(capname));
  661 }
  662 
  663 	static int
  664 ltgetnum(capname)
  665 	char *capname;
  666 {
  667 	char *s;
  668 
  669 	if ((s = ltget_env(capname)) != NULL)
  670 		return (atoi(s));
  671 	if (hardcopy)
  672 		return (-1);
  673 	return (tgetnum(capname));
  674 }
  675 
  676 	static char *
  677 ltgetstr(capname, pp)
  678 	char *capname;
  679 	char **pp;
  680 {
  681 	char *s;
  682 
  683 	if ((s = ltget_env(capname)) != NULL)
  684 		return (s);
  685 	if (hardcopy)
  686 		return (NULL);
  687 	return (tgetstr(capname, pp));
  688 }
  689 #endif /* MSDOS_COMPILER */
  690 
  691 /*
  692  * Get size of the output screen.
  693  */
  694 	public void
  695 scrsize()
  696 {
  697 	register char *s;
  698 	int sys_height;
  699 	int sys_width;
  700 #if !MSDOS_COMPILER
  701 	int n;
  702 #endif
  703 
  704 #define	DEF_SC_WIDTH	80
  705 #if MSDOS_COMPILER
  706 #define	DEF_SC_HEIGHT	25
  707 #else
  708 #define	DEF_SC_HEIGHT	24
  709 #endif
  710 
  711 
  712 	sys_width = sys_height = 0;
  713 
  714 #if MSDOS_COMPILER==MSOFTC
  715 	{
  716 		struct videoconfig w;
  717 		_getvideoconfig(&w);
  718 		sys_height = w.numtextrows;
  719 		sys_width = w.numtextcols;
  720 	}
  721 #else
  722 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  723 	{
  724 		struct text_info w;
  725 		gettextinfo(&w);
  726 		sys_height = w.screenheight;
  727 		sys_width = w.screenwidth;
  728 	}
  729 #else
  730 #if MSDOS_COMPILER==WIN32C
  731 	{
  732 		CONSOLE_SCREEN_BUFFER_INFO scr;
  733 		GetConsoleScreenBufferInfo(con_out, &scr);
  734 		sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1;
  735 		sys_width = scr.srWindow.Right - scr.srWindow.Left + 1;
  736 	}
  737 #else
  738 #if OS2
  739 	{
  740 		int s[2];
  741 		_scrsize(s);
  742 		sys_width = s[0];
  743 		sys_height = s[1];
  744 		/*
  745 		 * When using terminal emulators for XFree86/OS2, the
  746 		 * _scrsize function does not work well.
  747 		 * Call the scrsize.exe program to get the window size.
  748 		 */
  749 		windowid = getenv("WINDOWID");
  750 		if (windowid != NULL)
  751 		{
  752 			FILE *fd = popen("scrsize", "rt");
  753 			if (fd != NULL)
  754 			{
  755 				int w, h;
  756 				fscanf(fd, "%i %i", &w, &h);
  757 				if (w > 0 && h > 0)
  758 				{
  759 					sys_width = w;
  760 					sys_height = h;
  761 				}
  762 				pclose(fd);
  763 			}
  764 		}
  765 	}
  766 #else
  767 #ifdef TIOCGWINSZ
  768 	{
  769 		struct winsize w;
  770 		if (ioctl(2, TIOCGWINSZ, &w) == 0)
  771 		{
  772 			if (w.ws_row > 0)
  773 				sys_height = w.ws_row;
  774 			if (w.ws_col > 0)
  775 				sys_width = w.ws_col;
  776 		}
  777 	}
  778 #else
  779 #ifdef WIOCGETD
  780 	{
  781 		struct uwdata w;
  782 		if (ioctl(2, WIOCGETD, &w) == 0)
  783 		{
  784 			if (w.uw_height > 0)
  785 				sys_height = w.uw_height / w.uw_vs;
  786 			if (w.uw_width > 0)
  787 				sys_width = w.uw_width / w.uw_hs;
  788 		}
  789 	}
  790 #endif
  791 #endif
  792 #endif
  793 #endif
  794 #endif
  795 #endif
  796 
  797 	if (sys_height > 0)
  798 		sc_height = sys_height;
  799 	else if ((s = lgetenv("LINES")) != NULL)
  800 		sc_height = atoi(s);
  801 #if !MSDOS_COMPILER
  802 	else if ((n = ltgetnum("li")) > 0)
  803  		sc_height = n;
  804 #endif
  805 	else
  806 		sc_height = DEF_SC_HEIGHT;
  807 
  808 	if (sys_width > 0)
  809 		sc_width = sys_width;
  810 	else if ((s = lgetenv("COLUMNS")) != NULL)
  811 		sc_width = atoi(s);
  812 #if !MSDOS_COMPILER
  813 	else if ((n = ltgetnum("co")) > 0)
  814  		sc_width = n;
  815 #endif
  816 	else
  817 		sc_width = DEF_SC_WIDTH;
  818 }
  819 
  820 #if MSDOS_COMPILER==MSOFTC
  821 /*
  822  * Figure out how many empty loops it takes to delay a millisecond.
  823  */
  824 	static void
  825 get_clock()
  826 {
  827 	clock_t start;
  828 
  829 	/*
  830 	 * Get synchronized at the start of a tick.
  831 	 */
  832 	start = clock();
  833 	while (clock() == start)
  834 		;
  835 	/*
  836 	 * Now count loops till the next tick.
  837 	 */
  838 	start = clock();
  839 	msec_loops = 0;
  840 	while (clock() == start)
  841 		msec_loops++;
  842 	/*
  843 	 * Convert from (loops per clock) to (loops per millisecond).
  844 	 */
  845 	msec_loops *= CLOCKS_PER_SEC;
  846 	msec_loops /= 1000;
  847 }
  848 
  849 /*
  850  * Delay for a specified number of milliseconds.
  851  */
  852 	static void
  853 dummy_func()
  854 {
  855 	static long delay_dummy = 0;
  856 	delay_dummy++;
  857 }
  858 
  859 	static void
  860 delay(msec)
  861 	int msec;
  862 {
  863 	long i;
  864 
  865 	while (msec-- > 0)
  866 	{
  867 		for (i = 0;  i < msec_loops;  i++)
  868 		{
  869 			/*
  870 			 * Make it look like we're doing something here,
  871 			 * so the optimizer doesn't remove the whole loop.
  872 			 */
  873 			dummy_func();
  874 		}
  875 	}
  876 }
  877 #endif
  878 
  879 /*
  880  * Return the characters actually input by a "special" key.
  881  */
  882 	public char *
  883 special_key_str(key)
  884 	int key;
  885 {
  886 	static char tbuf[40];
  887 	char *s;
  888 #if MSDOS_COMPILER || OS2
  889 	static char k_right[]		= { '\340', PCK_RIGHT, 0 };
  890 	static char k_left[]		= { '\340', PCK_LEFT, 0  };
  891 	static char k_ctl_right[]	= { '\340', PCK_CTL_RIGHT, 0  };
  892 	static char k_ctl_left[]	= { '\340', PCK_CTL_LEFT, 0  };
  893 	static char k_insert[]		= { '\340', PCK_INSERT, 0  };
  894 	static char k_delete[]		= { '\340', PCK_DELETE, 0  };
  895 	static char k_ctl_delete[]	= { '\340', PCK_CTL_DELETE, 0  };
  896 	static char k_ctl_backspace[]	= { '\177', 0 };
  897 	static char k_home[]		= { '\340', PCK_HOME, 0 };
  898 	static char k_end[]		= { '\340', PCK_END, 0 };
  899 	static char k_up[]		= { '\340', PCK_UP, 0 };
  900 	static char k_down[]		= { '\340', PCK_DOWN, 0 };
  901 	static char k_backtab[]		= { '\340', PCK_SHIFT_TAB, 0 };
  902 	static char k_pagedown[]	= { '\340', PCK_PAGEDOWN, 0 };
  903 	static char k_pageup[]		= { '\340', PCK_PAGEUP, 0 };
  904 	static char k_f1[]		= { '\340', PCK_F1, 0 };
  905 #endif
  906 #if !MSDOS_COMPILER
  907 	char *sp = tbuf;
  908 #endif
  909 
  910 	switch (key)
  911 	{
  912 #if OS2
  913 	/*
  914 	 * If windowid is not NULL, assume less is executed in
  915 	 * the XFree86 environment.
  916 	 */
  917 	case SK_RIGHT_ARROW:
  918 		s = windowid ? ltgetstr("kr", &sp) : k_right;
  919 		break;
  920 	case SK_LEFT_ARROW:
  921 		s = windowid ? ltgetstr("kl", &sp) : k_left;
  922 		break;
  923 	case SK_UP_ARROW:
  924 		s = windowid ? ltgetstr("ku", &sp) : k_up;
  925 		break;
  926 	case SK_DOWN_ARROW:
  927 		s = windowid ? ltgetstr("kd", &sp) : k_down;
  928 		break;
  929 	case SK_PAGE_UP:
  930 		s = windowid ? ltgetstr("kP", &sp) : k_pageup;
  931 		break;
  932 	case SK_PAGE_DOWN:
  933 		s = windowid ? ltgetstr("kN", &sp) : k_pagedown;
  934 		break;
  935 	case SK_HOME:
  936 		s = windowid ? ltgetstr("kh", &sp) : k_home;
  937 		break;
  938 	case SK_END:
  939 		s = windowid ? ltgetstr("@7", &sp) : k_end;
  940 		break;
  941 	case SK_DELETE:
  942 		if (windowid)
  943 		{
  944 			s = ltgetstr("kD", &sp);
  945 			if (s == NULL)
  946 			{
  947 				tbuf[0] = '\177';
  948 				tbuf[1] = '\0';
  949 				s = tbuf;
  950 			}
  951 		} else
  952 			s = k_delete;
  953 		break;
  954 #endif
  955 #if MSDOS_COMPILER
  956 	case SK_RIGHT_ARROW:
  957 		s = k_right;
  958 		break;
  959 	case SK_LEFT_ARROW:
  960 		s = k_left;
  961 		break;
  962 	case SK_UP_ARROW:
  963 		s = k_up;
  964 		break;
  965 	case SK_DOWN_ARROW:
  966 		s = k_down;
  967 		break;
  968 	case SK_PAGE_UP:
  969 		s = k_pageup;
  970 		break;
  971 	case SK_PAGE_DOWN:
  972 		s = k_pagedown;
  973 		break;
  974 	case SK_HOME:
  975 		s = k_home;
  976 		break;
  977 	case SK_END:
  978 		s = k_end;
  979 		break;
  980 	case SK_DELETE:
  981 		s = k_delete;
  982 		break;
  983 #endif
  984 #if MSDOS_COMPILER || OS2
  985 	case SK_INSERT:
  986 		s = k_insert;
  987 		break;
  988 	case SK_CTL_LEFT_ARROW:
  989 		s = k_ctl_left;
  990 		break;
  991 	case SK_CTL_RIGHT_ARROW:
  992 		s = k_ctl_right;
  993 		break;
  994 	case SK_CTL_BACKSPACE:
  995 		s = k_ctl_backspace;
  996 		break;
  997 	case SK_CTL_DELETE:
  998 		s = k_ctl_delete;
  999 		break;
 1000 	case SK_F1:
 1001 		s = k_f1;
 1002 		break;
 1003 	case SK_BACKTAB:
 1004 		s = k_backtab;
 1005 		break;
 1006 #else
 1007 	case SK_RIGHT_ARROW:
 1008 		s = ltgetstr("kr", &sp);
 1009 		break;
 1010 	case SK_LEFT_ARROW:
 1011 		s = ltgetstr("kl", &sp);
 1012 		break;
 1013 	case SK_UP_ARROW:
 1014 		s = ltgetstr("ku", &sp);
 1015 		break;
 1016 	case SK_DOWN_ARROW:
 1017 		s = ltgetstr("kd", &sp);
 1018 		break;
 1019 	case SK_PAGE_UP:
 1020 		s = ltgetstr("kP", &sp);
 1021 		break;
 1022 	case SK_PAGE_DOWN:
 1023 		s = ltgetstr("kN", &sp);
 1024 		break;
 1025 	case SK_HOME:
 1026 		s = ltgetstr("kh", &sp);
 1027 		break;
 1028 	case SK_END:
 1029 		s = ltgetstr("@7", &sp);
 1030 		break;
 1031 	case SK_DELETE:
 1032 		s = ltgetstr("kD", &sp);
 1033 		if (s == NULL)
 1034 		{
 1035 			tbuf[0] = '\177';
 1036 			tbuf[1] = '\0';
 1037 			s = tbuf;
 1038 		}
 1039 		break;
 1040 #endif
 1041 	case SK_CONTROL_K:
 1042 		tbuf[0] = CONTROL('K');
 1043 		tbuf[1] = '\0';
 1044 		s = tbuf;
 1045 		break;
 1046 	default:
 1047 		return (NULL);
 1048 	}
 1049 	return (s);
 1050 }
 1051 
 1052 /*
 1053  * Get terminal capabilities via termcap.
 1054  */
 1055 	public void
 1056 get_term()
 1057 {
 1058 #if MSDOS_COMPILER
 1059 	auto_wrap = 1;
 1060 	ignaw = 0;
 1061 	can_goto_line = 1;
 1062 	clear_bg = 1;
 1063 	/*
 1064 	 * Set up default colors.
 1065 	 * The xx_s_width and xx_e_width vars are already initialized to 0.
 1066 	 */
 1067 #if MSDOS_COMPILER==MSOFTC
 1068 	sy_bg_color = _getbkcolor();
 1069 	sy_fg_color = _gettextcolor();
 1070 	get_clock();
 1071 #else
 1072 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
 1073     {
 1074 	struct text_info w;
 1075 	gettextinfo(&w);
 1076 	sy_bg_color = (w.attribute >> 4) & 0x0F;
 1077 	sy_fg_color = (w.attribute >> 0) & 0x0F;
 1078     }
 1079 #else
 1080 #if MSDOS_COMPILER==WIN32C
 1081     {
 1082 	DWORD nread;
 1083 	CONSOLE_SCREEN_BUFFER_INFO scr;
 1084 
 1085 	con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE);
 1086 	/*
 1087 	 * Always open stdin in binary. Note this *must* be done
 1088 	 * before any file operations have been done on fd0.
 1089 	 */
 1090 	SET_BINARY(0);
 1091 	GetConsoleScreenBufferInfo(con_out, &scr);
 1092 	ReadConsoleOutputAttribute(con_out, &curr_attr,
 1093 					1, scr.dwCursorPosition