[BACK]Return to screen.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Diff for /src/usr.bin/less/screen.c between version 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 1996/09/21 05:39:41 version 1.1.1.2, 2003/04/13 18:21:21
Line 1 
Line 1 
 /*  /*
  * Copyright (c) 1984,1985,1989,1994,1995  Mark Nudelman   * Copyright (C) 1984-2002  Mark Nudelman
  * All rights reserved.  
  *   *
  * Redistribution and use in source and binary forms, with or without   * You may distribute under the terms of either the GNU General Public
  * modification, are permitted provided that the following conditions   * License or the Less License, as specified in the README file.
  * are met:  
  * 1. Redistributions of source code must retain the above copyright  
  *    notice, this list of conditions and the following disclaimer.  
  * 2. Redistributions in binary form must reproduce the above copyright  
  *    notice in the documentation and/or other materials provided with  
  *    the distribution.  
  *   *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY   * For more information about less, or for information on how to
  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE   * contact the author, see the README file.
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR  
  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE  
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN  
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
  */   */
   
   
 /*  /*
  * Routines which deal with the characteristics of the terminal.   * Routines which deal with the characteristics of the terminal.
  * Uses termcap to be as terminal-independent as possible.   * Uses termcap to be as terminal-independent as possible.
  *  
  * {{ Maybe someday this should be rewritten to use curses or terminfo. }}  
  */   */
   
 #include "less.h"  #include "less.h"
 #include "cmd.h"  #include "cmd.h"
   
   #if MSDOS_COMPILER
   #include "pckeys.h"
   #if MSDOS_COMPILER==MSOFTC
   #include <graph.h>
   #else
   #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
   #include <conio.h>
   #if MSDOS_COMPILER==DJGPPC
   #include <pc.h>
   extern int fd0;
   #endif
   #else
   #if MSDOS_COMPILER==WIN32C
   #include <windows.h>
   #endif
   #endif
   #endif
   #include <time.h>
   
   #else
   
 #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS  #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
 #include <termios.h>  #include <termios.h>
 #if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ)  #if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ)
Line 44 
Line 47 
 #if HAVE_TERMIO_H  #if HAVE_TERMIO_H
 #include <termio.h>  #include <termio.h>
 #else  #else
   #if HAVE_SGSTAT_H
   #include <sgstat.h>
   #else
 #include <sgtty.h>  #include <sgtty.h>
   #endif
 #if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD))  #if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD))
 #include <sys/ioctl.h>  #include <sys/ioctl.h>
 #endif  #endif
 #endif  #endif
 #endif  #endif
   
 #if HAVE_TERMCAP_H  #if HAVE_TERMCAP_H
 #include <termcap.h>  #include <termcap.h>
 #endif  #endif
   #ifdef _OSK
 #ifndef TIOCGWINSZ  #include <signal.h>
 /*  #endif
  * For the Unix PC (ATT 7300 & 3B1):  #if OS2
  * Since WIOCGETD is defined in sys/window.h, we can't use that to decide  
  * whether to include sys/window.h.  Use SIGPHONE from sys/signal.h instead.  
  */  
 #include <sys/signal.h>  #include <sys/signal.h>
 #ifdef SIGPHONE  #include "pckeys.h"
 #include <sys/window.h>  
 #endif  #endif
 #endif  
   
 #if HAVE_SYS_STREAM_H  #if HAVE_SYS_STREAM_H
 #include <sys/stream.h>  #include <sys/stream.h>
 #endif  #endif
Line 73 
Line 75 
 #include <sys/ptem.h>  #include <sys/ptem.h>
 #endif  #endif
   
   #endif /* MSDOS_COMPILER */
   
   /*
    * Check for broken termios package that forces you to manually
    * set the line discipline.
    */
   #ifdef __ultrix__
   #define MUST_SET_LINE_DISCIPLINE 1
   #else
   #define MUST_SET_LINE_DISCIPLINE 0
   #endif
   
 #if OS2  #if OS2
 #define DEFAULT_TERM            "ansi"  #define DEFAULT_TERM            "ansi"
   static char *windowid;
 #else  #else
 #define DEFAULT_TERM            "unknown"  #define DEFAULT_TERM            "unknown"
 #endif  #endif
   
   #if MSDOS_COMPILER==MSOFTC
   static int videopages;
   static long msec_loops;
   static int flash_created = 0;
   #define SETCOLORS(fg,bg)        { _settextcolor(fg); _setbkcolor(bg); }
   #endif
   
   #if MSDOS_COMPILER==BORLANDC
   static unsigned short *whitescreen;
   static int flash_created = 0;
   #endif
   #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
   #define _settextposition(y,x)   gotoxy(x,y)
   #define _clearscreen(m)         clrscr()
   #define _outtext(s)             cputs(s)
   #define SETCOLORS(fg,bg)        { textcolor(fg); textbackground(bg); }
   extern int sc_height;
   #endif
   
   #if MSDOS_COMPILER==WIN32C
   struct keyRecord
   {
           int ascii;
           int scan;
   } currentKey;
   
   static int keyCount = 0;
   static WORD curr_attr;
   static int pending_scancode = 0;
   static WORD *whitescreen;
   
   static HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */
   static HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */
   HANDLE con_out = INVALID_HANDLE_VALUE;             /* current console */
   
   extern int quitting;
   static void win32_init_term();
   static void win32_deinit_term();
   
   #define FG_COLORS       (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)
   #define BG_COLORS       (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY)
   #define MAKEATTR(fg,bg)         ((WORD)((fg)|((bg)<<4)))
   #define SETCOLORS(fg,bg)        { curr_attr = MAKEATTR(fg,bg); \
                                   if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \
                                   error("SETCOLORS failed"); }
   #endif
   
   #if MSDOS_COMPILER
   public int nm_fg_color;         /* Color of normal text */
   public int nm_bg_color;
   public int bo_fg_color;         /* Color of bold text */
   public int bo_bg_color;
   public int ul_fg_color;         /* Color of underlined text */
   public int ul_bg_color;
   public int so_fg_color;         /* Color of standout text */
   public int so_bg_color;
   public int bl_fg_color;         /* Color of blinking text */
   public int bl_bg_color;
   static int sy_fg_color;         /* Color of system text (before less) */
   static int sy_bg_color;
   
   #else
   
 /*  /*
  * Strings passed to tputs() to do various terminal functions.   * Strings passed to tputs() to do various terminal functions.
  */   */
Line 105 
Line 183 
         *sc_e_keypad,           /* End keypad mode */          *sc_e_keypad,           /* End keypad mode */
         *sc_init,               /* Startup terminal initialization */          *sc_init,               /* Startup terminal initialization */
         *sc_deinit;             /* Exit terminal de-initialization */          *sc_deinit;             /* Exit terminal de-initialization */
   #endif
   
 static int init_done = 0;  static int init_done = 0;
   
Line 119 
Line 198 
 public int bl_s_width, bl_e_width;      /* Printing width of blink seq */  public int bl_s_width, bl_e_width;      /* Printing width of blink seq */
 public int above_mem, below_mem;        /* Memory retained above/below screen */  public int above_mem, below_mem;        /* Memory retained above/below screen */
 public int can_goto_line;               /* Can move cursor to any line */  public int can_goto_line;               /* Can move cursor to any line */
   public int clear_bg;            /* Clear fills with background color */
   public int missing_cap = 0;     /* Some capability is missing */
   
   static int attrmode = AT_NORMAL;
   
   #if !MSDOS_COMPILER
 static char *cheaper();  static char *cheaper();
   static void tmodes();
   #endif
   
 /*  /*
  * These two variables are sometimes defined in,   * These two variables are sometimes defined in,
Line 130 
Line 216 
 extern short ospeed;    /* Terminal output baud rate */  extern short ospeed;    /* Terminal output baud rate */
 extern char PC;         /* Pad character */  extern char PC;         /* Pad character */
 #endif  #endif
   #ifdef _OSK
   short ospeed;
   char PC_, *UP, *BC;
   #endif
   
 extern int quiet;               /* If VERY_QUIET, use visual bell for bell */  extern int quiet;               /* If VERY_QUIET, use visual bell for bell */
 extern int know_dumb;           /* Don't complain about a dumb terminal */  extern int no_back_scroll;
 extern int back_scroll;  
 extern int swindow;  extern int swindow;
 extern int no_init;  extern int no_init;
   extern int no_keypad;
   extern int sigs;
   extern int wscroll;
   extern int screen_trashed;
   extern int tty;
 #if HILITE_SEARCH  #if HILITE_SEARCH
 extern int hilite_search;  extern int hilite_search;
 #endif  #endif
Line 163 
Line 257 
   
         if (on == curr_on)          if (on == curr_on)
                 return;                  return;
 #if OS2  
         signal(SIGINT, SIG_IGN);  
         erase_char = '\b';  
         kill_char = '\033';  
 #else  
 #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS  #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
     {      {
         struct termios s;          struct termios s;
         static struct termios save_term;          static struct termios save_term;
           static int saved_term = 0;
   
         if (on)          if (on)
         {          {
                 /*                  /*
                  * Get terminal modes.                   * Get terminal modes.
                  */                   */
                 tcgetattr(2, &s);                  tcgetattr(tty, &s);
   
                 /*                  /*
                  * Save modes and set certain variables dependent on modes.                   * Save modes and set certain variables dependent on modes.
                  */                   */
                 save_term = s;                  if (!saved_term)
                   {
                           save_term = s;
                           saved_term = 1;
                   }
 #if HAVE_OSPEED  #if HAVE_OSPEED
                 switch (cfgetospeed(&s))                  switch (cfgetospeed(&s))
                 {                  {
Line 249 
Line 343 
 #ifdef VWERASE  #ifdef VWERASE
                 werase_char = s.c_cc[VWERASE];                  werase_char = s.c_cc[VWERASE];
 #else  #else
                 werase_char = 0;                  werase_char = CONTROL('W');
 #endif  #endif
   
                 /*                  /*
Line 274 
Line 368 
                 );                  );
   
                 s.c_oflag |= (0                  s.c_oflag |= (0
 #ifdef XTABS  #ifdef OXTABS
                         | XTABS                          | OXTABS
 #else  #else
 #ifdef TAB3  #ifdef TAB3
                         | TAB3                          | TAB3
 #else  #else
 #ifdef OXTABS  #ifdef XTABS
                         | OXTABS                          | XTABS
 #endif  #endif
 #endif  #endif
 #endif  #endif
Line 309 
Line 403 
                 );                  );
                 s.c_cc[VMIN] = 1;                  s.c_cc[VMIN] = 1;
                 s.c_cc[VTIME] = 0;                  s.c_cc[VTIME] = 0;
   #ifdef VLNEXT
                   s.c_cc[VLNEXT] = 0;
   #endif
   #ifdef VDSUSP
                   s.c_cc[VDSUSP] = 0;
   #endif
   #if MUST_SET_LINE_DISCIPLINE
                   /*
                    * System's termios is broken; need to explicitly
                    * request TERMIODISC line discipline.
                    */
                   s.c_line = TERMIODISC;
   #endif
         } else          } else
         {          {
                 /*                  /*
Line 316 
Line 423 
                  */                   */
                 s = save_term;                  s = save_term;
         }          }
         tcsetattr(2, TCSADRAIN, &s);  #if HAVE_FSYNC
           fsync(tty);
   #endif
           tcsetattr(tty, TCSADRAIN, &s);
   #if MUST_SET_LINE_DISCIPLINE
           if (!on)
           {
                   /*
                    * Broken termios *ignores* any line discipline
                    * except TERMIODISC.  A different old line discipline
                    * is therefore not restored, yet.  Restore the old
                    * line discipline by hand.
                    */
                   ioctl(tty, TIOCSETD, &save_term.c_line);
           }
   #endif
     }      }
 #else  #else
 #ifdef TCGETA  #ifdef TCGETA
     {      {
         struct termio s;          struct termio s;
         static struct termio save_term;          static struct termio save_term;
           static int saved_term = 0;
   
         if (on)          if (on)
         {          {
                 /*                  /*
                  * Get terminal modes.                   * Get terminal modes.
                  */                   */
                 ioctl(2, TCGETA, &s);                  ioctl(tty, TCGETA, &s);
   
                 /*                  /*
                  * Save modes and set certain variables dependent on modes.                   * Save modes and set certain variables dependent on modes.
                  */                   */
                 save_term = s;                  if (!saved_term)
                   {
                           save_term = s;
                           saved_term = 1;
                   }
 #if HAVE_OSPEED  #if HAVE_OSPEED
                 ospeed = s.c_cflag & CBAUD;                  ospeed = s.c_cflag & CBAUD;
 #endif  #endif
Line 343 
Line 470 
 #ifdef VWERASE  #ifdef VWERASE
                 werase_char = s.c_cc[VWERASE];                  werase_char = s.c_cc[VWERASE];
 #else  #else
                 werase_char = 0;                  werase_char = CONTROL('W');
 #endif  #endif
   
                 /*                  /*
Line 361 
Line 488 
                  */                   */
                 s = save_term;                  s = save_term;
         }          }
         ioctl(2, TCSETAW, &s);          ioctl(tty, TCSETAW, &s);
     }      }
 #else  #else
   #ifdef TIOCGETP
     {      {
         struct sgttyb s;          struct sgttyb s;
         static struct sgttyb save_term;          static struct sgttyb save_term;
           static int saved_term = 0;
   
         if (on)          if (on)
         {          {
                 /*                  /*
                  * Get terminal modes.                   * Get terminal modes.
                  */                   */
                 ioctl(2, TIOCGETP, &s);                  ioctl(tty, TIOCGETP, &s);
   
                 /*                  /*
                  * Save modes and set certain variables dependent on modes.                   * Save modes and set certain variables dependent on modes.
                  */                   */
                 save_term = s;                  if (!saved_term)
                   {
                           save_term = s;
                           saved_term = 1;
                   }
 #if HAVE_OSPEED  #if HAVE_OSPEED
                 ospeed = s.sg_ospeed;                  ospeed = s.sg_ospeed;
 #endif  #endif
                 erase_char = s.sg_erase;                  erase_char = s.sg_erase;
                 kill_char = s.sg_kill;                  kill_char = s.sg_kill;
                 werase_char = 0;                  werase_char = CONTROL('W');
   
                 /*                  /*
                  * Set the modes to the way we want them.                   * Set the modes to the way we want them.
Line 398 
Line 531 
                  */                   */
                 s = save_term;                  s = save_term;
         }          }
         ioctl(2, TIOCSETN, &s);          ioctl(tty, TIOCSETN, &s);
     }      }
   #else
   #ifdef _OSK
       {
           struct sgbuf s;
           static struct sgbuf save_term;
           static int saved_term = 0;
   
           if (on)
           {
                   /*
                    * Get terminal modes.
                    */
                   _gs_opt(tty, &s);
   
                   /*
                    * Save modes and set certain variables dependent on modes.
                    */
                   if (!saved_term)
                   {
                           save_term = s;
                           saved_term = 1;
                   }
                   erase_char = s.sg_bspch;
                   kill_char = s.sg_dlnch;
                   werase_char = CONTROL('W');
   
                   /*
                    * Set the modes to the way we want them.
                    */
                   s.sg_echo = 0;
                   s.sg_eofch = 0;
                   s.sg_pause = 0;
                   s.sg_psch = 0;
           } else
           {
                   /*
                    * Restore saved modes.
                    */
                   s = save_term;
           }
           _ss_opt(tty, &s);
       }
   #else
           /* MS-DOS, Windows, or OS2 */
   #if OS2
           /* OS2 */
           LSIGNAL(SIGINT, SIG_IGN);
 #endif  #endif
           erase_char = '\b';
   #if MSDOS_COMPILER==DJGPPC
           kill_char = CONTROL('U');
           /*
            * So that when we shell out or run another program, its
            * stdin is in cooked mode.  We do not switch stdin to binary
            * mode if fd0 is zero, since that means we were called before
            * tty was reopened in open_getchr, in which case we would be
            * changing the original stdin device outside less.
            */
           if (fd0 != 0)
                   setmode(0, on ? O_BINARY : O_TEXT);
   #else
           kill_char = ESC;
 #endif  #endif
           werase_char = CONTROL('W');
 #endif  #endif
   #endif
   #endif
   #endif
         curr_on = on;          curr_on = on;
 }  }
   
         static void  #if !MSDOS_COMPILER
 cannot(s)  /*
         char *s;   * Some glue to prevent calling termcap functions if tgetent() failed.
    */
   static int hardcopy;
   
           static char *
   ltget_env(capname)
           char *capname;
 {  {
         PARG parg;          char name[16];
   
         if (know_dumb)          strcpy(name, "LESS_TERMCAP_");
                 /*          strcat(name, capname);
                  * User knows this is a dumb terminal, so don't tell him.          return (lgetenv(name));
                  */  
                 return;  
   
         parg.p_string = s;  
         error("WARNING: terminal cannot %s", &parg);  
 }  }
   
 /*          static int
  * Get size of the output screen.  ltgetflag(capname)
  */          char *capname;
 #if OS2  
         public void  
 scrsize()  
 {  {
         int s[2];          char *s;
   
         _scrsize(s);          if ((s = ltget_env(capname)) != NULL)
         sc_width = s[0];                  return (*s != '\0' && *s != '0');
         sc_height = s[1];          if (hardcopy)
                   return (0);
           return (tgetflag(capname));
 }  }
   
 #else          static int
   ltgetnum(capname)
         public void          char *capname;
 scrsize()  
 {  {
         register char *s;          char *s;
 #ifdef TIOCGWINSZ  
         struct winsize w;  
 #else  
 #ifdef WIOCGETD  
         struct uwdata w;  
 #endif  
 #endif  
   
 #ifdef TIOCGWINSZ          if ((s = ltget_env(capname)) != NULL)
         if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)                  return (atoi(s));
                 sc_height = w.ws_row;          if (hardcopy)
         else                  return (-1);
 #else          return (tgetnum(capname));
 #ifdef WIOCGETD  }
         if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_height > 0)  
                 sc_height = w.uw_height/w.uw_vs;  
         else  
 #endif  
 #endif  
         if ((s = getenv("LINES")) != NULL)  
                 sc_height = atoi(s);  
         else  
                 sc_height = tgetnum("li");  
   
         if (sc_height <= 0)          static char *
                 sc_height = 24;  ltgetstr(capname, pp)
           char *capname;
           char **pp;
   {
           char *s;
   
 #ifdef TIOCGWINSZ          if ((s = ltget_env(capname)) != NULL)
         if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)                  return (s);
                 sc_width = w.ws_col;          if (hardcopy)
         else                  return (NULL);
 #ifdef WIOCGETD          return (tgetstr(capname, pp));
         if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_width > 0)  
                 sc_width = w.uw_width/w.uw_hs;  
         else  
 #endif  
 #endif  
         if ((s = getenv("COLUMNS")) != NULL)  
                 sc_width = atoi(s);  
         else  
                 sc_width = tgetnum("co");  
   
         if (sc_width <= 0)  
                 sc_width = 80;  
 }  }
 #endif /* OS2 */  #endif /* MSDOS_COMPILER */
   
 /*  /*
  * Take care of the "variable" keys.   * Get size of the output screen.
  * Certain keys send escape sequences which differ on different terminals  
  * (such as the arrow keys, INSERT, DELETE, etc.)  
  * Construct the commands based on these keys.  
  */   */
         public void          public void
 get_editkeys()  scrsize()
 {  {
         char *sp;          register char *s;
         char *s;          int sys_height;
         char tbuf[40];          int sys_width;
   #if !MSDOS_COMPILER
           int n;
   #endif
   
         static char kfcmdtable[400];  #define DEF_SC_WIDTH    80
         int sz_kfcmdtable = 0;  #if MSDOS_COMPILER
         static char kecmdtable[400];  #define DEF_SC_HEIGHT   25
         int sz_kecmdtable = 0;  #else
   #define DEF_SC_HEIGHT   24
   #endif
   
 #define put_cmd(str,action,tbl,sz) { \  
         strcpy(tbl+sz, str);    \  
         sz += strlen(str) + 1;  \  
         tbl[sz++] = action; }  
 #define put_esc_cmd(str,action,tbl,sz) { \  
         tbl[sz++] = ESC; \  
         put_cmd(str,action,tbl,sz); }  
   
 #define put_fcmd(str,action)    put_cmd(str,action,kfcmdtable,sz_kfcmdtable)          sys_width = sys_height = 0;
 #define put_ecmd(str,action)    put_cmd(str,action,kecmdtable,sz_kecmdtable)  
 #define put_esc_fcmd(str,action) put_esc_cmd(str,action,kfcmdtable,sz_kfcmdtable)  
 #define put_esc_ecmd(str,action) put_esc_cmd(str,action,kecmdtable,sz_kecmdtable)  
   
         /*  #if MSDOS_COMPILER==MSOFTC
          * Look at some interesting keys and see what strings they send.  
          * Create commands (both command keys and line-edit keys).  
          */  
   
         /* RIGHT ARROW */  
         sp = tbuf;  
         if ((s = tgetstr("kr", &sp)) != NULL)  
         {          {
                 put_ecmd(s, EC_RIGHT);                  struct videoconfig w;
                 put_esc_ecmd(s, EC_W_RIGHT);                  _getvideoconfig(&w);
                   sys_height = w.numtextrows;
                   sys_width = w.numtextcols;
         }          }
   #else
         /* LEFT ARROW */  #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
         sp = tbuf;  
         if ((s = tgetstr("kl", &sp)) != NULL)  
         {          {
                 put_ecmd(s, EC_LEFT);                  struct text_info w;
                 put_esc_ecmd(s, EC_W_LEFT);                  gettextinfo(&w);
                   sys_height = w.screenheight;
                   sys_width = w.screenwidth;
         }          }
   #else
         /* UP ARROW */  #if MSDOS_COMPILER==WIN32C
         sp = tbuf;  
         if ((s = tgetstr("ku", &sp)) != NULL)  
         {          {
                 put_ecmd(s, EC_UP);                  CONSOLE_SCREEN_BUFFER_INFO scr;
                 put_fcmd(s, A_B_LINE);                  GetConsoleScreenBufferInfo(con_out, &scr);
                   sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1;
                   sys_width = scr.srWindow.Right - scr.srWindow.Left + 1;
         }          }
   #else
         /* DOWN ARROW */  #if OS2
         sp = tbuf;  
         if ((s = tgetstr("kd", &sp)) != NULL)  
         {          {
                 put_ecmd(s, EC_DOWN);                  int s[2];
                 put_fcmd(s, A_F_LINE);                  _scrsize(s);
                   sys_width = s[0];
                   sys_height = s[1];
                   /*
                    * When using terminal emulators for XFree86/OS2, the
                    * _scrsize function does not work well.
                    * Call the scrsize.exe program to get the window size.
                    */
                   windowid = getenv("WINDOWID");
                   if (windowid != NULL)
                   {
                           FILE *fd = popen("scrsize", "rt");
                           if (fd != NULL)
                           {
                                   int w, h;
                                   fscanf(fd, "%i %i", &w, &h);
                                   if (w > 0 && h > 0)
                                   {
                                           sys_width = w;
                                           sys_height = h;
                                   }
                                   pclose(fd);
                           }
                   }
         }          }
   #else
         /* PAGE UP */  #ifdef TIOCGWINSZ
         sp = tbuf;  
         if ((s = tgetstr("kP", &sp)) != NULL)  
         {          {
                 put_fcmd(s, A_B_SCREEN);                  struct winsize w;
                   if (ioctl(2, TIOCGWINSZ, &w) == 0)
                   {
                           if (w.ws_row > 0)
                                   sys_height = w.ws_row;
                           if (w.ws_col > 0)
                                   sys_width = w.ws_col;
                   }
         }          }
   #else
         /* PAGE DOWN */  #ifdef WIOCGETD
         sp = tbuf;  
         if ((s = tgetstr("kN", &sp)) != NULL)  
         {          {
                 put_fcmd(s, A_F_SCREEN);                  struct uwdata w;
                   if (ioctl(2, WIOCGETD, &w) == 0)
                   {
                           if (w.uw_height > 0)
                                   sys_height = w.uw_height / w.uw_vs;
                           if (w.uw_width > 0)
                                   sys_width = w.uw_width / w.uw_hs;
                   }
         }          }
   #endif
         /* HOME */  #endif
         sp = tbuf;  #endif
         if ((s = tgetstr("kh", &sp)) != NULL)  #endif
         {  #endif
                 put_ecmd(s, EC_HOME);  #endif
         }  
   
         /* END */          if (sys_height > 0)
         sp = tbuf;                  sc_height = sys_height;
         if ((s = tgetstr("@7", &sp)) != NULL)          else if ((s = lgetenv("LINES")) != NULL)
         {                  sc_height = atoi(s);
                 put_ecmd(s, EC_END);  #if !MSDOS_COMPILER
         }          else if ((n = ltgetnum("li")) > 0)
                   sc_height = n;
   #endif
           else
                   sc_height = DEF_SC_HEIGHT;
   
         /* DELETE */          if (sys_width > 0)
         sp = tbuf;                  sc_width = sys_width;
         if ((s = tgetstr("kD", &sp)) == NULL)          else if ((s = lgetenv("COLUMNS")) != NULL)
         {                  sc_width = atoi(s);
                 /* Use DEL (\177) if no "kD" termcap. */  #if !MSDOS_COMPILER
                 tbuf[1] = '\177';          else if ((n = ltgetnum("co")) > 0)
                 tbuf[2] = '\0';                  sc_width = n;
                 s = tbuf+1;  #endif
         }          else
         put_ecmd(s, EC_DELETE);                  sc_width = DEF_SC_WIDTH;
         put_esc_ecmd(s, EC_W_DELETE);  }
   
         /* BACKSPACE */  
         tbuf[0] = ESC;  
         tbuf[1] = erase_char;  
         tbuf[2] = '\0';  
         put_ecmd(tbuf, EC_W_BACKSPACE);  
   
         if (werase_char != 0)  #if MSDOS_COMPILER==MSOFTC
         {  /*
                 tbuf[0] = werase_char;   * Figure out how many empty loops it takes to delay a millisecond.
                 tbuf[1] = '\0';   */
                 put_ecmd(tbuf, EC_W_BACKSPACE);          static void
         }  get_clock()
   {
           clock_t start;
   
         /*          /*
          * Register the two tables.           * Get synchronized at the start of a tick.
          */           */
         add_fcmd_table(kfcmdtable, sz_kfcmdtable);          start = clock();
         add_ecmd_table(kecmdtable, sz_kecmdtable);          while (clock() == start)
                   ;
           /*
            * Now count loops till the next tick.
            */
           start = clock();
           msec_loops = 0;
           while (clock() == start)
                   msec_loops++;
           /*
            * Convert from (loops per clock) to (loops per millisecond).
            */
           msec_loops *= CLOCKS_PER_SEC;
           msec_loops /= 1000;
 }  }
   
 #if DEBUG  /*
    * Delay for a specified number of milliseconds.
    */
         static void          static void
 get_debug_term()  dummy_func()
 {  {
         auto_wrap = 1;          static long delay_dummy = 0;
         ignaw = 1;          delay_dummy++;
         so_s_width = so_e_width = 0;  
         bo_s_width = bo_e_width = 0;  
         ul_s_width = ul_e_width = 0;  
         bl_s_width = bl_e_width = 0;  
         sc_s_keypad =   "(InitKey)";  
         sc_e_keypad =   "(DeinitKey)";  
         sc_init =       "(InitTerm)";  
         sc_deinit =     "(DeinitTerm)";  
         sc_eol_clear =  "(ClearEOL)";  
         sc_eos_clear =  "(ClearEOS)";  
         sc_clear =      "(ClearScreen)";  
         sc_move =       "(Move<%d,%d>)";  
         sc_s_in =       "(SO+)";  
         sc_s_out =      "(SO-)";  
         sc_u_in =       "(UL+)";  
         sc_u_out =      "(UL-)";  
         sc_b_in =       "(BO+)";  
         sc_b_out =      "(BO-)";  
         sc_bl_in =      "(BL+)";  
         sc_bl_out =     "(BL-)";  
         sc_visual_bell ="(VBell)";  
         sc_backspace =  "(BS)";  
         sc_home =       "(Home)";  
         sc_lower_left = "(LL)";  
         sc_addline =    "(AddLine)";  
 }  }
   
           static void
   delay(msec)
           int msec;
   {
           long i;
   
           while (msec-- > 0)
           {
                   for (i = 0;  i < msec_loops;  i++)
                   {
                           /*
                            * Make it look like we're doing something here,
                            * so the optimizer doesn't remove the whole loop.
                            */
                           dummy_func();
                   }
           }
   }
 #endif  #endif
   
 /*  /*
    * Return the characters actually input by a "special" key.
    */
           public char *
   special_key_str(key)
           int key;
   {
           static char tbuf[40];
           char *s;
   #if MSDOS_COMPILER || OS2
           static char k_right[]           = { '\340', PCK_RIGHT, 0 };
           static char k_left[]            = { '\340', PCK_LEFT, 0  };
           static char k_ctl_right[]       = { '\340', PCK_CTL_RIGHT, 0  };
           static char k_ctl_left[]        = { '\340', PCK_CTL_LEFT, 0  };
           static char k_insert[]          = { '\340', PCK_INSERT, 0  };
           static char k_delete[]          = { '\340', PCK_DELETE, 0  };
           static char k_ctl_delete[]      = { '\340', PCK_CTL_DELETE, 0  };
           static char k_ctl_backspace[]   = { '\177', 0 };
           static char k_home[]            = { '\340', PCK_HOME, 0 };
           static char k_end[]             = { '\340', PCK_END, 0 };
           static char k_up[]              = { '\340', PCK_UP, 0 };
           static char k_down[]            = { '\340', PCK_DOWN, 0 };
           static char k_backtab[]         = { '\340', PCK_SHIFT_TAB, 0 };
           static char k_pagedown[]        = { '\340', PCK_PAGEDOWN, 0 };
           static char k_pageup[]          = { '\340', PCK_PAGEUP, 0 };
           static char k_f1[]              = { '\340', PCK_F1, 0 };
   #endif
   #if !MSDOS_COMPILER
           char *sp = tbuf;
   #endif
   
           switch (key)
           {
   #if OS2
           /*
            * If windowid is not NULL, assume less is executed in
            * the XFree86 environment.
            */
           case SK_RIGHT_ARROW:
                   s = windowid ? ltgetstr("kr", &sp) : k_right;
                   break;
           case SK_LEFT_ARROW:
                   s = windowid ? ltgetstr("kl", &sp) : k_left;
                   break;
           case SK_UP_ARROW:
                   s = windowid ? ltgetstr("ku", &sp) : k_up;
                   break;
           case SK_DOWN_ARROW:
                   s = windowid ? ltgetstr("kd", &sp) : k_down;
                   break;
           case SK_PAGE_UP:
                   s = windowid ? ltgetstr("kP", &sp) : k_pageup;
                   break;
           case SK_PAGE_DOWN:
                   s = windowid ? ltgetstr("kN", &sp) : k_pagedown;
                   break;
           case SK_HOME:
                   s = windowid ? ltgetstr("kh", &sp) : k_home;
                   break;
           case SK_END:
                   s = windowid ? ltgetstr("@7", &sp) : k_end;
                   break;
           case SK_DELETE:
                   if (windowid)
                   {
                           s = ltgetstr("kD", &sp);
                           if (s == NULL)
                           {
                                   tbuf[0] = '\177';
                                   tbuf[1] = '\0';
                                   s = tbuf;
                           }
                   } else
                           s = k_delete;
                   break;
   #endif
   #if MSDOS_COMPILER
           case SK_RIGHT_ARROW:
                   s = k_right;
                   break;
           case SK_LEFT_ARROW:
                   s = k_left;
                   break;
           case SK_UP_ARROW:
                   s = k_up;
                   break;
           case SK_DOWN_ARROW:
                   s = k_down;
                   break;
           case SK_PAGE_UP:
                   s = k_pageup;
                   break;
           case SK_PAGE_DOWN:
                   s = k_pagedown;
                   break;
           case SK_HOME:
                   s = k_home;
                   break;
           case SK_END:
                   s = k_end;
                   break;
           case SK_DELETE:
                   s = k_delete;
                   break;
   #endif
   #if MSDOS_COMPILER || OS2
           case SK_INSERT:
                   s = k_insert;
                   break;
           case SK_CTL_LEFT_ARROW:
                   s = k_ctl_left;
                   break;
           case SK_CTL_RIGHT_ARROW:
                   s = k_ctl_right;
                   break;
           case SK_CTL_BACKSPACE:
                   s = k_ctl_backspace;
                   break;
           case SK_CTL_DELETE:
                   s = k_ctl_delete;
                   break;
           case SK_F1:
                   s = k_f1;
                   break;
           case SK_BACKTAB:
                   s = k_backtab;
                   break;
   #else
           case SK_RIGHT_ARROW:
                   s = ltgetstr("kr", &sp);
                   break;
           case SK_LEFT_ARROW:
                   s = ltgetstr("kl", &sp);
                   break;
           case SK_UP_ARROW:
                   s = ltgetstr("ku", &sp);
                   break;
           case SK_DOWN_ARROW:
                   s = ltgetstr("kd", &sp);
                   break;
           case SK_PAGE_UP:
                   s = ltgetstr("kP", &sp);
                   break;
           case SK_PAGE_DOWN:
                   s = ltgetstr("kN", &sp);
                   break;
           case SK_HOME:
                   s = ltgetstr("kh", &sp);
                   break;
           case SK_END:
                   s = ltgetstr("@7", &sp);
                   break;
           case SK_DELETE:
                   s = ltgetstr("kD", &sp);
                   if (s == NULL)
                   {
                           tbuf[0] = '\177';
                           tbuf[1] = '\0';
                           s = tbuf;
                   }
                   break;
   #endif
           case SK_CONTROL_K:
                   tbuf[0] = CONTROL('K');
                   tbuf[1] = '\0';
                   s = tbuf;
                   break;
           default:
                   return (NULL);
           }
           return (s);
   }
   
   /*
  * Get terminal capabilities via termcap.   * Get terminal capabilities via termcap.
  */   */
         public void          public void
 get_term()  get_term()
 {  {
   #if MSDOS_COMPILER
           auto_wrap = 1;
           ignaw = 0;
           can_goto_line = 1;
           clear_bg = 1;
           /*
            * Set up default colors.
            * The xx_s_width and xx_e_width vars are already initialized to 0.
            */
   #if MSDOS_COMPILER==MSOFTC
           sy_bg_color = _getbkcolor();
           sy_fg_color = _gettextcolor();
           get_clock();
   #else
   #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
       {
           struct text_info w;
           gettextinfo(&w);
           sy_bg_color = (w.attribute >> 4) & 0x0F;
           sy_fg_color = (w.attribute >> 0) & 0x0F;
       }
   #else
   #if MSDOS_COMPILER==WIN32C
       {
           DWORD nread;
           CONSOLE_SCREEN_BUFFER_INFO scr;
   
           con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE);
           /*
            * Always open stdin in binary. Note this *must* be done
            * before any file operations have been done on fd0.
            */
           SET_BINARY(0);
           GetConsoleScreenBufferInfo(con_out, &scr);
           ReadConsoleOutputAttribute(con_out, &curr_attr,
                                           1, scr.dwCursorPosition, &nread);
           sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */
           sy_fg_color = curr_attr & FG_COLORS;
       }
   #endif
   #endif
   #endif
           nm_fg_color = sy_fg_color;
           nm_bg_color = sy_bg_color;
           bo_fg_color = 11;
           bo_bg_color = 0;
           ul_fg_color = 9;
           ul_bg_color = 0;
           so_fg_color = 15;
           so_bg_color = 9;
           bl_fg_color = 15;
           bl_bg_color = 0;
   
           /*
            * Get size of the screen.
            */
           scrsize();
           pos_init();
   
   
   #else /* !MSDOS_COMPILER */
   
         char *sp;          char *sp;
         register char *t1, *t2;          register char *t1, *t2;
         register int hard;  
         char *term;          char *term;
         char termbuf[2048];          char termbuf[TERMBUF_SIZE];
   
         static char sbuf[1024];          static char sbuf[TERMSBUF_SIZE];
   
 #ifdef OS2  #if OS2
         /*          /*
          * Make sure the termcap database is available.           * Make sure the termcap database is available.
          */           */
         sp = getenv("TERMCAP");          sp = lgetenv("TERMCAP");
         if (sp == NULL || *sp == '\0')          if (sp == NULL || *sp == '\0')
         {          {
                 char *termcap;                  char *termcap;
Line 685 
Line 1118 
         /*          /*
          * Find out what kind of terminal this is.           * Find out what kind of terminal this is.
          */           */
         if ((term = getenv("TERM")) == NULL)          if ((term = lgetenv("TERM")) == NULL)
                 term = DEFAULT_TERM;                  term = DEFAULT_TERM;
           hardcopy = 0;
         if (tgetent(termbuf, term) <= 0)          if (tgetent(termbuf, term) <= 0)
                 strcpy(termbuf, "dumb:hc:");                  hardcopy = 1;
           if (ltgetflag("hc"))
                   hardcopy = 1;
   
         hard = tgetflag("hc");  
   
         /*          /*
          * Get size of the screen.           * Get size of the screen.
          */           */
         scrsize();          scrsize();
         pos_init();          pos_init();
   
 #if DEBUG          auto_wrap = ltgetflag("am");
         if (strncmp(term,"LESSDEBUG",9) == 0)          ignaw = ltgetflag("xn");
         {          above_mem = ltgetflag("da");
                 get_debug_term();          below_mem = ltgetflag("db");
                 return;          clear_bg = ltgetflag("ut");
         }  
 #endif /* DEBUG */  
   
         auto_wrap = tgetflag("am");  
         ignaw = tgetflag("xn");  
         above_mem = tgetflag("da");  
         below_mem = tgetflag("db");  
   
         /*          /*
          * Assumes termcap variable "sg" is the printing width of:           * Assumes termcap variable "sg" is the printing width of:
          * the standout sequence, the end standout sequence,           * the standout sequence, the end standout sequence,
          * the underline sequence, the end underline sequence,           * the underline sequence, the end underline sequence,
          * the boldface sequence, and the end boldface sequence.           * the boldface sequence, and the end boldface sequence.
          */           */
         if ((so_s_width = tgetnum("sg")) < 0)          if ((so_s_width = ltgetnum("sg")) < 0)
                 so_s_width = 0;                  so_s_width = 0;
         so_e_width = so_s_width;          so_e_width = so_s_width;
   
Line 743 
Line 1170 
         sp = sbuf;          sp = sbuf;
   
 #if HAVE_OSPEED  #if HAVE_OSPEED
         sc_pad = tgetstr("pc", &sp);          sc_pad = ltgetstr("pc", &sp);
         if (sc_pad != NULL)          if (sc_pad != NULL)
                 PC = *sc_pad;                  PC = *sc_pad;
 #endif  #endif
   
         sc_s_keypad = tgetstr("ks", &sp);          sc_s_keypad = ltgetstr("ks", &sp);
         if (sc_s_keypad == NULL)          if (sc_s_keypad == NULL)
                 sc_s_keypad = "";                  sc_s_keypad = "";
         sc_e_keypad = tgetstr("ke", &sp);          sc_e_keypad = ltgetstr("ke", &sp);
         if (sc_e_keypad == NULL)          if (sc_e_keypad == NULL)
                 sc_e_keypad = "";                  sc_e_keypad = "";
   
         sc_init = tgetstr("ti", &sp);          sc_init = ltgetstr("ti", &sp);
         if (sc_init == NULL)          if (sc_init == NULL)
                 sc_init = "";                  sc_init = "";
   
         sc_deinit= tgetstr("te", &sp);          sc_deinit= ltgetstr("te", &sp);
         if (sc_deinit == NULL)          if (sc_deinit == NULL)
                 sc_deinit = "";                  sc_deinit = "";
   
         sc_eol_clear = tgetstr("ce", &sp);          sc_eol_clear = ltgetstr("ce", &sp);
         if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')          if (sc_eol_clear == NULL || *sc_eol_clear == '\0')
         {          {
                 cannot("clear to end of line");                  missing_cap = 1;
                 sc_eol_clear = "";                  sc_eol_clear = "";
         }          }
   
         sc_eos_clear = tgetstr("cd", &sp);          sc_eos_clear = ltgetstr("cd", &sp);
         if (below_mem &&          if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0'))
                 (hard || sc_eos_clear == NULL || *sc_eos_clear == '\0'))  
         {          {
                 cannot("clear to end of screen");                  missing_cap = 1;
                 sc_eol_clear = "";                  sc_eol_clear = "";
         }          }
   
         sc_clear = tgetstr("cl", &sp);          sc_clear = ltgetstr("cl", &sp);
         if (hard || sc_clear == NULL || *sc_clear == '\0')          if (sc_clear == NULL || *sc_clear == '\0')
         {          {
                 cannot("clear screen");                  missing_cap = 1;
                 sc_clear = "\n\n";                  sc_clear = "\n\n";
         }          }
   
         sc_move = tgetstr("cm", &sp);          sc_move = ltgetstr("cm", &sp);
         if (hard || sc_move == NULL || *sc_move == '\0')          if (sc_move == NULL || *sc_move == '\0')
         {          {
                 /*                  /*
                  * This is not an error here, because we don't                   * This is not an error here, because we don't
Line 798 
Line 1224 
         } else          } else
                 can_goto_line = 1;                  can_goto_line = 1;
   
         sc_s_in = tgetstr("so", &sp);          tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp);
         if (hard || sc_s_in == NULL)          tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp);
                 sc_s_in = "";          tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp);
           tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp);
   
         sc_s_out = tgetstr("se", &sp);          sc_visual_bell = ltgetstr("vb", &sp);
         if (hard || sc_s_out == NULL)          if (sc_visual_bell == NULL)
                 sc_s_out = "";  
   
         sc_u_in = tgetstr("us", &sp);  
         if (hard || sc_u_in == NULL)  
                 sc_u_in = sc_s_in;  
   
         sc_u_out = tgetstr("ue", &sp);  
         if (hard || sc_u_out == NULL)  
                 sc_u_out = sc_s_out;  
   
         sc_b_in = tgetstr("md", &sp);  
         if (hard || sc_b_in == NULL)  
         {  
                 sc_b_in = sc_s_in;  
                 sc_b_out = sc_s_out;  
         } else  
         {  
                 sc_b_out = tgetstr("me", &sp);  
                 if (hard || sc_b_out == NULL)  
                         sc_b_out = "";  
         }  
   
         sc_bl_in = tgetstr("mb", &sp);  
         if (hard || sc_bl_in == NULL)  
         {  
                 sc_bl_in = sc_s_in;  
                 sc_bl_out = sc_s_out;  
         } else  
         {  
                 sc_bl_out = tgetstr("me", &sp);  
                 if (hard || sc_bl_out == NULL)  
                         sc_bl_out = "";  
         }  
   
         sc_visual_bell = tgetstr("vb", &sp);  
         if (hard || sc_visual_bell == NULL)  
                 sc_visual_bell = "";                  sc_visual_bell = "";
   
         if (tgetflag("bs"))          if (ltgetflag("bs"))
                 sc_backspace = "\b";                  sc_backspace = "\b";
         else          else
         {          {
                 sc_backspace = tgetstr("bc", &sp);                  sc_backspace = ltgetstr("bc", &sp);
                 if (sc_backspace == NULL || *sc_backspace == '\0')                  if (sc_backspace == NULL || *sc_backspace == '\0')
                         sc_backspace = "\b";                          sc_backspace = "\b";
         }          }
Line 855 
Line 1246 
          * Choose between using "ho" and "cm" ("home" and "cursor move")           * Choose between using "ho" and "cm" ("home" and "cursor move")
          * to move the cursor to the upper left corner of the screen.           * to move the cursor to the upper left corner of the screen.
          */           */
         t1 = tgetstr("ho", &sp);          t1 = ltgetstr("ho", &sp);
         if (hard || t1 == NULL)          if (t1 == NULL)
                 t1 = "";                  t1 = "";
         if (*sc_move == '\0')          if (*sc_move == '\0')
                 t2 = "";                  t2 = "";
Line 866 
Line 1257 
                 t2 = sp;                  t2 = sp;
                 sp += strlen(sp) + 1;                  sp += strlen(sp) + 1;
         }          }
         sc_home = cheaper(t1, t2, "home cursor", "|\b^");          sc_home = cheaper(t1, t2, "|\b^");
   
         /*          /*
          * Choose between using "ll" and "cm"  ("lower left" and "cursor move")           * Choose between using "ll" and "cm"  ("lower left" and "cursor move")
          * to move the cursor to the lower left corner of the screen.           * to move the cursor to the lower left corner of the screen.
          */           */
         t1 = tgetstr("ll", &sp);          t1 = ltgetstr("ll", &sp);
         if (hard || t1 == NULL)          if (t1 == NULL)
                 t1 = "";                  t1 = "";
         if (*sc_move == '\0')          if (*sc_move == '\0')
                 t2 = "";                  t2 = "";
Line 883 
Line 1274 
                 t2 = sp;                  t2 = sp;
                 sp += strlen(sp) + 1;                  sp += strlen(sp) + 1;
         }          }
         sc_lower_left = cheaper(t1, t2,          sc_lower_left = cheaper(t1, t2, "\r");
                 "move cursor to lower left of screen", "\r");  
   
         /*          /*
          * Choose between using "al" or "sr" ("add line" or "scroll reverse")           * Choose between using "al" or "sr" ("add line" or "scroll reverse")
          * to add a line at the top of the screen.           * to add a line at the top of the screen.
          */           */
         t1 = tgetstr("al", &sp);          t1 = ltgetstr("al", &sp);
         if (hard || t1 == NULL)          if (t1 == NULL)
                 t1 = "";                  t1 = "";
         t2 = tgetstr("sr", &sp);          t2 = ltgetstr("sr", &sp);
         if (hard || t2 == NULL)          if (t2 == NULL)
                 t2 = "";                  t2 = "";
 #if OS2  #if OS2
         if (*t1 == '\0' && *t2 == '\0')          if (*t1 == '\0' && *t2 == '\0')
Line 904 
Line 1294 
         if (above_mem)          if (above_mem)
                 sc_addline = t1;                  sc_addline = t1;
         else          else
                 sc_addline = cheaper(t1, t2, "scroll backwards", "");                  sc_addline = cheaper(t1, t2, "");
         if (*sc_addline == '\0')          if (*sc_addline == '\0')
         {          {
                 /*                  /*
                  * Force repaint on any backward movement.                   * Force repaint on any backward movement.
                  */                   */
                 back_scroll = 0;                  no_back_scroll = 1;
         }          }
   #endif /* MSDOS_COMPILER */
 }  }
   
   #if !MSDOS_COMPILER
 /*  /*
  * Return the cost of displaying a termcap string.   * Return the cost of displaying a termcap string.
  * We use the trick of calling tputs, but as a char printing function   * We use the trick of calling tputs, but as a char printing function
Line 947 
Line 1339 
  * cost (see cost() function).   * cost (see cost() function).
  */   */
         static char *          static char *
 cheaper(t1, t2, doit, def)  cheaper(t1, t2, def)
         char *t1, *t2;          char *t1, *t2;
         char *doit;  
         char *def;          char *def;
 {  {
         if (*t1 == '\0' && *t2 == '\0')          if (*t1 == '\0' && *t2 == '\0')
         {          {
                 cannot(doit);                  missing_cap = 1;
                 return (def);                  return (def);
         }          }
         if (*t1 == '\0')          if (*t1 == '\0')
Line 966 
Line 1357 
         return (t2);          return (t2);
 }  }
   
           static void
   tmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp)
           char *incap;
           char *outcap;
           char **instr;
           char **outstr;
           char *def_instr;
           char *def_outstr;
           char **spp;
   {
           *instr = ltgetstr(incap, spp);
           if (*instr == NULL)
           {
                   /* Use defaults. */
                   *instr = def_instr;
                   *outstr = def_outstr;
                   return;
           }
   
           *outstr = ltgetstr(outcap, spp);
           if (*outstr == NULL)
                   /* No specific out capability; use "me". */
                   *outstr = ltgetstr("me", spp);
           if (*outstr == NULL)
                   /* Don't even have "me"; use a null string. */
                   *outstr = "";
   }
   
   #endif /* MSDOS_COMPILER */
   
   
 /*  /*
  * Below are the functions which perform all the   * Below are the functions which perform all the
  * terminal-specific screen manipulation.   * terminal-specific screen manipulation.
  */   */
   
   
   #if MSDOS_COMPILER
   
   #if MSDOS_COMPILER==WIN32C
           static void
   _settextposition(int row, int col)
   {
           COORD cpos;
           CONSOLE_SCREEN_BUFFER_INFO csbi;
   
           GetConsoleScreenBufferInfo(con_out, &csbi);
           cpos.X = csbi.srWindow.Left + (col - 1);
           cpos.Y = csbi.srWindow.Top + (row - 1);
           SetConsoleCursorPosition(con_out, cpos);
   }
   #endif
   
 /*  /*
    * Initialize the screen to the correct color at startup.
    */
           static void
   initcolor()
   {
           SETCOLORS(nm_fg_color, nm_bg_color);
   #if 0
           /*
            * This clears the screen at startup.  This is different from
            * the behavior of other versions of less.  Disable it for now.
            */
           char *blanks;
           int row;
           int col;
   
           /*
            * Create a complete, blank screen using "normal" colors.
            */
           SETCOLORS(nm_fg_color, nm_bg_color);
           blanks = (char *) ecalloc(width+1, sizeof(char));
           for (col = 0;  col < sc_width;  col++)
                   blanks[col] = ' ';
           blanks[sc_width] = '\0';
           for (row = 0;  row < sc_height;  row++)
                   _outtext(blanks);
           free(blanks);
   #endif
   }
   #endif
   
   #if MSDOS_COMPILER==WIN32C
   
   /*
    * Termcap-like init with a private win32 console.
    */
           static void
   win32_init_term()
   {
           CONSOLE_SCREEN_BUFFER_INFO scr;
           COORD size;
   
           if (con_out_save == INVALID_HANDLE_VALUE)
                   return;
   
           GetConsoleScreenBufferInfo(con_out_save, &scr);
   
           if (con_out_ours == INVALID_HANDLE_VALUE)
           {
                   /*
                    * Create our own screen buffer, so that we
                    * may restore the original when done.
                    */
                   con_out_ours = CreateConsoleScreenBuffer(
                           GENERIC_WRITE | GENERIC_READ,
                           FILE_SHARE_WRITE | FILE_SHARE_READ,
                           (LPSECURITY_ATTRIBUTES) NULL,
                           CONSOLE_TEXTMODE_BUFFER,
                           (LPVOID) NULL);
           }
   
           size.X = scr.srWindow.Right - scr.srWindow.Left + 1;
           size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1;
           SetConsoleScreenBufferSize(con_out_ours, size);
           SetConsoleActiveScreenBuffer(con_out_ours);
           con_out = con_out_ours;
   }
   
   /*
    * Restore the startup console.
    */
   static void
   win32_deinit_term()
   {
           if (con_out_save == INVALID_HANDLE_VALUE)
                   return;
           if (quitting)
                   (void) CloseHandle(con_out_ours);
           SetConsoleActiveScreenBuffer(con_out_save);
           con_out = con_out_save;
   }
   
   #endif
   
   /*
  * Initialize terminal   * Initialize terminal
  */   */
         public void          public void
 init()  init()
 {  {
         if (no_init)  #if !MSDOS_COMPILER
                 return;          if (!no_init)
         tputs(sc_init, sc_height, putchr);                  tputs(sc_init, sc_height, putchr);
         tputs(sc_s_keypad, sc_height, putchr);          if (!no_keypad)
                   tputs(sc_s_keypad, sc_height, putchr);
   #else
   #if MSDOS_COMPILER==WIN32C
           if (!no_init)
                   win32_init_term();
   #endif
           initcolor();
           flush();
   #endif
         init_done = 1;          init_done = 1;
 }  }
   
Line 992 
Line 1522 
         public void          public void
 deinit()  deinit()
 {  {
         if (no_init)  
                 return;  
         if (!init_done)          if (!init_done)
                 return;                  return;
         tputs(sc_e_keypad, sc_height, putchr);  #if !MSDOS_COMPILER
         tputs(sc_deinit, sc_height, putchr);          if (!no_keypad)
                   tputs(sc_e_keypad, sc_height, putchr);
           if (!no_init)
                   tputs(sc_deinit, sc_height, putchr);
   #else
           /* Restore system colors. */
           SETCOLORS(sy_fg_color, sy_bg_color);
   #if MSDOS_COMPILER==WIN32C
           if (!no_init)
                   win32_deinit_term();
   #else
           /* Need clreol to make SETCOLORS take effect. */
           clreol();
   #endif
   #endif
         init_done = 0;          init_done = 0;
 }  }
   
Line 1007 
Line 1549 
         public void          public void
 home()  home()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_home, 1, putchr);          tputs(sc_home, 1, putchr);
   #else
           flush();
           _settextposition(1,1);
   #endif
 }  }
   
 /*  /*
Line 1017 
Line 1564 
         public void          public void
 add_line()  add_line()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_addline, sc_height, putchr);          tputs(sc_addline, sc_height, putchr);
   #else
           flush();
   #if MSDOS_COMPILER==MSOFTC
           _scrolltextwindow(_GSCROLLDOWN);
           _settextposition(1,1);
   #else
   #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
           movetext(1,1, sc_width,sc_height-1, 1,2);
           gotoxy(1,1);
           clreol();
   #else
   #if MSDOS_COMPILER==WIN32C
       {
           CHAR_INFO fillchar;
           SMALL_RECT rcSrc, rcClip;
           COORD new_org;
           CONSOLE_SCREEN_BUFFER_INFO csbi;
   
           GetConsoleScreenBufferInfo(con_out,&csbi);
   
           /* The clip rectangle is the entire visible screen. */
           rcClip.Left = csbi.srWindow.Left;
           rcClip.Top = csbi.srWindow.Top;
           rcClip.Right = csbi.srWindow.Right;
           rcClip.Bottom = csbi.srWindow.Bottom;
   
           /* The source rectangle is the visible screen minus the last line. */
           rcSrc = rcClip;
           rcSrc.Bottom--;
   
           /* Move the top left corner of the source window down one row. */
           new_org.X = rcSrc.Left;
           new_org.Y = rcSrc.Top + 1;
   
           /* Fill the right character and attributes. */
           fillchar.Char.AsciiChar = ' ';
           curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
           fillchar.Attributes = curr_attr;
           ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
           _settextposition(1,1);
       }
   #endif
   #endif
   #endif
   #endif
 }  }
   
   #if 0
 /*  /*
    * Remove the n topmost lines and scroll everything below it in the
    * window upward.  This is needed to stop leaking the topmost line
    * into the scrollback buffer when we go down-one-line (in WIN32).
    */
           public void
   remove_top(n)
           int n;
   {
   #if MSDOS_COMPILER==WIN32C
           SMALL_RECT rcSrc, rcClip;
           CHAR_INFO fillchar;
           COORD new_org;
           CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
   
           if (n >= sc_height - 1)
           {
                   clear();
                   home();
                   return;
           }
   
           flush();
   
           GetConsoleScreenBufferInfo(con_out, &csbi);
   
           /* Get the extent of all-visible-rows-but-the-last. */
           rcSrc.Left    = csbi.srWindow.Left;
           rcSrc.Top     = csbi.srWindow.Top + n;
           rcSrc.Right   = csbi.srWindow.Right;
           rcSrc.Bottom  = csbi.srWindow.Bottom;
   
           /* Get the clip rectangle. */
           rcClip.Left   = rcSrc.Left;
           rcClip.Top    = csbi.srWindow.Top;
           rcClip.Right  = rcSrc.Right;
           rcClip.Bottom = rcSrc.Bottom ;
   
           /* Move the source window up n rows. */
           new_org.X = rcSrc.Left;
           new_org.Y = rcSrc.Top - n;
   
           /* Fill the right character and attributes. */
           fillchar.Char.AsciiChar = ' ';
           curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
           fillchar.Attributes = curr_attr;
   
           ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
   
           /* Position cursor on first blank line. */
           goto_line(sc_height - n - 1);
   #endif
   }
   #endif
   
   #if MSDOS_COMPILER==WIN32C
   /*
    * Clear the screen.
    */
           static void
   win32_clear()
   {
           /*
            * This will clear only the currently visible rows of the NT
            * console buffer, which means none of the precious scrollback
            * rows are touched making for faster scrolling.  Note that, if
            * the window has fewer columns than the console buffer (i.e.
            * there is a horizontal scrollbar as well), the entire width
            * of the visible rows will be cleared.
            */
           COORD topleft;
           DWORD nchars;
           DWORD winsz;
           CONSOLE_SCREEN_BUFFER_INFO csbi;
   
           /* get the number of cells in the current buffer */
           GetConsoleScreenBufferInfo(con_out, &csbi);
           winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
           topleft.X = 0;
           topleft.Y = csbi.srWindow.Top;
   
           curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
           FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars);
           FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars);
   }
   
   /*
    * Remove the n topmost lines and scroll everything below it in the
    * window upward.
    */
           public void
   win32_scroll_up(n)
           int n;
   {
           SMALL_RECT rcSrc, rcClip;
           CHAR_INFO fillchar;
           COORD topleft;
           COORD new_org;
           DWORD nchars;
           DWORD size;
           CONSOLE_SCREEN_BUFFER_INFO csbi;
   
           if (n <= 0)
                   return;
   
           if (n >= sc_height - 1)
           {
                   win32_clear();
                   _settextposition(1,1);
                   return;
           }
   
           /* Get the extent of what will remain visible after scrolling. */
           GetConsoleScreenBufferInfo(con_out, &csbi);
           rcSrc.Left    = csbi.srWindow.Left;
           rcSrc.Top     = csbi.srWindow.Top + n;
           rcSrc.Right   = csbi.srWindow.Right;
           rcSrc.Bottom  = csbi.srWindow.Bottom;
   
           /* Get the clip rectangle. */
           rcClip.Left   = rcSrc.Left;
           rcClip.Top    = csbi.srWindow.Top;
           rcClip.Right  = rcSrc.Right;
           rcClip.Bottom = rcSrc.Bottom ;
   
           /* Move the source text to the top of the screen. */
           new_org.X = rcSrc.Left;
           new_org.Y = 0;
   
           /* Fill the right character and attributes. */
           fillchar.Char.AsciiChar = ' ';
           fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color);
   
           /* Scroll the window. */
           SetConsoleTextAttribute(con_out, fillchar.Attributes);
           ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
   
           /* Clear remaining lines at bottom. */
           topleft.X = csbi.dwCursorPosition.X;
           topleft.Y = rcSrc.Bottom - n;
           size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X);
           FillConsoleOutputCharacter(con_out, ' ', size, topleft,
                   &nchars);
           FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft,
                   &nchars);
           SetConsoleTextAttribute(con_out, curr_attr);
   
           /* Move cursor n lines up from where it was. */
           csbi.dwCursorPosition.Y -= n;
           SetConsoleCursorPosition(con_out, csbi.dwCursorPosition);
   }
   #endif
   
   /*
  * Move cursor to lower left corner of screen.   * Move cursor to lower left corner of screen.
  */   */
         public void          public void
 lower_left()  lower_left()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_lower_left, 1, putchr);          tputs(sc_lower_left, 1, putchr);
   #else
           flush();
           _settextposition(sc_height, 1);
   #endif
 }  }
   
 /*  /*
    * Check if the console size has changed and reset internals
    * (in lieu of SIGWINCH for WIN32).
    */
           public void
   check_winch()
   {
   #if MSDOS_COMPILER==WIN32C
           CONSOLE_SCREEN_BUFFER_INFO scr;
           COORD size;
   
           if (con_out == INVALID_HANDLE_VALUE)
                   return;
   
           flush();
           GetConsoleScreenBufferInfo(con_out, &scr);
           size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1;
           size.X = scr.srWindow.Right - scr.srWindow.Left + 1;
           if (size.Y != sc_height || size.X != sc_width)
           {
                   sc_height = size.Y;
                   sc_width = size.X;
                   if (!no_init && con_out_ours == con_out)
                           SetConsoleScreenBufferSize(con_out, size);
                   pos_init();
                   wscroll = (sc_height + 1) / 2;
                   screen_trashed = 1;
           }
   #endif
   }
   
   /*
  * Goto a specific line on the screen.   * Goto a specific line on the screen.
  */   */
         public void          public void
 goto_line(slinenum)  goto_line(slinenum)
         int slinenum;          int slinenum;
 {  {
         char *sc_goto;  #if !MSDOS_COMPILER
           tputs(tgoto(sc_move, 0, slinenum), 1, putchr);
         sc_goto = tgoto(sc_move, 0, slinenum);  #else
         tputs(sc_goto, 1, putchr);          flush();
           _settextposition(slinenum+1, 1);
   #endif
 }  }
   
   #if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC
 /*  /*
  * Ring the terminal bell.   * Create an alternate screen which is all white.
    * This screen is used to create a "flash" effect, by displaying it
    * briefly and then switching back to the normal screen.
    * {{ Yuck!  There must be a better way to get a visual bell. }}
  */   */
         public void          static void
 bell()  create_flash()
 {  {
         if (quiet == VERY_QUIET)  #if MSDOS_COMPILER==MSOFTC
                 vbell();          struct videoconfig w;
         else          char *blanks;
                 putchr('\7');          int row, col;
   
           _getvideoconfig(&w);
           videopages = w.numvideopages;
           if (videopages < 2)
           {
                   so_enter();
                   so_exit();
           } else
           {
                   _setactivepage(1);
                   so_enter();
                   blanks = (char *) ecalloc(w.numtextcols, sizeof(char));
                   for (col = 0;  col < w.numtextcols;  col++)
                           blanks[col] = ' ';
                   for (row = w.numtextrows;  row > 0;  row--)
                           _outmem(blanks, w.numtextcols);
                   _setactivepage(0);
                   _setvisualpage(0);
                   free(blanks);
                   so_exit();
           }
   #else
   #if MSDOS_COMPILER==BORLANDC
           register int n;
   
           whitescreen = (unsigned short *)
                   malloc(sc_width * sc_height * sizeof(short));
           if (whitescreen == NULL)
                   return;
           for (n = 0;  n < sc_width * sc_height;  n++)
                   whitescreen[n] = 0x7020;
   #else
   #if MSDOS_COMPILER==WIN32C
           register int n;
   
           whitescreen = (WORD *)
                   malloc(sc_height * sc_width * sizeof(WORD));
           if (whitescreen == NULL)
                   return;
           /* Invert the standard colors. */
           for (n = 0;  n < sc_width * sc_height;  n++)
                   whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color);
   #endif
   #endif
   #endif
           flash_created = 1;
 }  }
   #endif /* MSDOS_COMPILER */
   
 /*  /*
  * Output the "visual bell", if there is one.   * Output the "visual bell", if there is one.
Line 1060 
Line 1896 
         public void          public void
 vbell()  vbell()
 {  {
   #if !MSDOS_COMPILER
         if (*sc_visual_bell == '\0')          if (*sc_visual_bell == '\0')
                 return;                  return;
         tputs(sc_visual_bell, sc_height, putchr);          tputs(sc_visual_bell, sc_height, putchr);
   #else
   #if MSDOS_COMPILER==DJGPPC
           ScreenVisualBell();
   #else
   #if MSDOS_COMPILER==MSOFTC
           /*
            * Create a flash screen on the second video page.
            * Switch to that page, then switch back.
            */
           if (!flash_created)
                   create_flash();
           if (videopages < 2)
                   return;
           _setvisualpage(1);
           delay(100);
           _setvisualpage(0);
   #else
   #if MSDOS_COMPILER==BORLANDC
           unsigned short *currscreen;
   
           /*
            * Get a copy of the current screen.
            * Display the flash screen.
            * Then restore the old screen.
            */
           if (!flash_created)
                   create_flash();
           if (whitescreen == NULL)
                   return;
           currscreen = (unsigned short *)
                   malloc(sc_width * sc_height * sizeof(short));
           if (currscreen == NULL) return;
           gettext(1, 1, sc_width, sc_height, currscreen);
           puttext(1, 1, sc_width, sc_height, whitescreen);
           delay(100);
           puttext(1, 1, sc_width, sc_height, currscreen);
           free(currscreen);
   #else
   #if MSDOS_COMPILER==WIN32C
           /* paint screen with an inverse color */
           clear();
   
           /* leave it displayed for 100 msec. */
           Sleep(100);
   
           /* restore with a redraw */
           repaint();
   #endif
   #endif
   #endif
   #endif
   #endif
 }  }
   
 /*  /*
    * Make a noise.
    */
           static void
   beep()
   {
   #if !MSDOS_COMPILER
           putchr(CONTROL('G'));
   #else
   #if MSDOS_COMPILER==WIN32C
           MessageBeep(0);
   #else
           write(1, "\7", 1);
   #endif
   #endif
   }
   
   /*
    * Ring the terminal bell.
    */
           public void
   bell()
   {
           if (quiet == VERY_QUIET)
                   vbell();
           else
                   beep();
   }
   
   /*
  * Clear the screen.   * Clear the screen.
  */   */
         public void          public void
 clear()  clear()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_clear, sc_height, putchr);          tputs(sc_clear, sc_height, putchr);
   #else
           flush();
   #if MSDOS_COMPILER==WIN32C
           win32_clear();
   #else
           _clearscreen(_GCLEARSCREEN);
   #endif
   #endif
 }  }
   
 /*  /*
Line 1081 
Line 2008 
         public void          public void
 clear_eol()  clear_eol()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_eol_clear, 1, putchr);          tputs(sc_eol_clear, 1, putchr);
   #else
   #if MSDOS_COMPILER==MSOFTC
           short top, left;
           short bot, right;
           struct rccoord tpos;
   
           flush();
           /*
            * Save current state.
            */
           tpos = _gettextposition();
           _gettextwindow(&top, &left, &bot, &right);
           /*
            * Set a temporary window to the current line,
            * from the cursor's position to the right edge of the screen.
            * Then clear that window.
            */
           _settextwindow(tpos.row, tpos.col, tpos.row, sc_width);
           _clearscreen(_GWINDOW);
           /*
            * Restore state.
            */
           _settextwindow(top, left, bot, right);
           _settextposition(tpos.row, tpos.col);
   #else
   #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
           flush();
           clreol();
   #else
   #if MSDOS_COMPILER==WIN32C
           DWORD           nchars;
           COORD           cpos;
           CONSOLE_SCREEN_BUFFER_INFO scr;
   
           flush();
           memset(&scr, 0, sizeof(scr));
           GetConsoleScreenBufferInfo(con_out, &scr);
           cpos.X = scr.dwCursorPosition.X;
           cpos.Y = scr.dwCursorPosition.Y;
           curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
           FillConsoleOutputAttribute(con_out, curr_attr,
                   scr.dwSize.X - cpos.X, cpos, &nchars);
           FillConsoleOutputCharacter(con_out, ' ',
                   scr.dwSize.X - cpos.X, cpos, &nchars);
   #endif
   #endif
   #endif
   #endif
 }  }
   
 /*  /*
    * Clear the current line.
    * Clear the screen if there's off-screen memory below the display.
    */
           static void
   clear_eol_bot()
   {
   #if MSDOS_COMPILER
           clear_eol();
   #else
           if (below_mem)
                   tputs(sc_eos_clear, 1, putchr);
           else
                   tputs(sc_eol_clear, 1, putchr);
   #endif
   }
   
   /*
  * Clear the bottom line of the display.   * Clear the bottom line of the display.
  * Leave the cursor at the beginning of the bottom line.   * Leave the cursor at the beginning of the bottom line.
  */   */
         public void          public void
 clear_bot()  clear_bot()
 {  {
           /*
            * If we're in a non-normal attribute mode, temporarily exit
            * the mode while we do the clear.  Some terminals fill the
            * cleared area with the current attribute.
            */
         lower_left();          lower_left();
         if (below_mem)          switch (attrmode)
                 tputs(sc_eos_clear, 1, putchr);          {
         else          case AT_STANDOUT:
                 tputs(sc_eol_clear, 1, putchr);                  so_exit();
                   clear_eol_bot();
                   so_enter();
                   break;
           case AT_UNDERLINE:
                   ul_exit();
                   clear_eol_bot();
                   ul_enter();
                   break;
           case AT_BOLD:
                   bo_exit();
                   clear_eol_bot();
                   bo_enter();
                   break;
           case AT_BLINK:
                   bl_exit();
                   clear_eol_bot();
                   bl_enter();
                   break;
           default:
                   clear_eol_bot();
                   break;
           }
 }  }
   
 /*  /*
Line 1104 
Line 2124 
         public void          public void
 so_enter()  so_enter()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_s_in, 1, putchr);          tputs(sc_s_in, 1, putchr);
   #else
           flush();
           SETCOLORS(so_fg_color, so_bg_color);
   #endif
           attrmode = AT_STANDOUT;
 }  }
   
 /*  /*
Line 1113 
Line 2139 
         public void          public void
 so_exit()  so_exit()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_s_out, 1, putchr);          tputs(sc_s_out, 1, putchr);
   #else
           flush();
           SETCOLORS(nm_fg_color, nm_bg_color);
   #endif
           attrmode = AT_NORMAL;
 }  }
   
 /*  /*
Line 1123 
Line 2155 
         public void          public void
 ul_enter()  ul_enter()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_u_in, 1, putchr);          tputs(sc_u_in, 1, putchr);
   #else
           flush();
           SETCOLORS(ul_fg_color, ul_bg_color);
   #endif
           attrmode = AT_UNDERLINE;
 }  }
   
 /*  /*
Line 1132 
Line 2170 
         public void          public void
 ul_exit()  ul_exit()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_u_out, 1, putchr);          tputs(sc_u_out, 1, putchr);
   #else
           flush();
           SETCOLORS(nm_fg_color, nm_bg_color);
   #endif
           attrmode = AT_NORMAL;
 }  }
   
 /*  /*
Line 1141 
Line 2185 
         public void          public void
 bo_enter()  bo_enter()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_b_in, 1, putchr);          tputs(sc_b_in, 1, putchr);
   #else
           flush();
           SETCOLORS(bo_fg_color, bo_bg_color);
   #endif
           attrmode = AT_BOLD;
 }  }
   
 /*  /*
Line 1150 
Line 2200 
         public void          public void
 bo_exit()  bo_exit()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_b_out, 1, putchr);          tputs(sc_b_out, 1, putchr);
   #else
           flush();
           SETCOLORS(nm_fg_color, nm_bg_color);
   #endif
           attrmode = AT_NORMAL;
 }  }
   
 /*  /*
Line 1159 
Line 2215 
         public void          public void
 bl_enter()  bl_enter()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_bl_in, 1, putchr);          tputs(sc_bl_in, 1, putchr);
   #else
           flush();
           SETCOLORS(bl_fg_color, bl_bg_color);
   #endif
           attrmode = AT_BLINK;
 }  }
   
 /*  /*
Line 1168 
Line 2230 
         public void          public void
 bl_exit()  bl_exit()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_bl_out, 1, putchr);          tputs(sc_bl_out, 1, putchr);
   #else
           flush();
           SETCOLORS(nm_fg_color, nm_bg_color);
   #endif
           attrmode = AT_NORMAL;
 }  }
   
   #if 0 /* No longer used */
 /*  /*
  * Erase the character to the left of the cursor   * Erase the character to the left of the cursor
  * and move the cursor left.   * and move the cursor left.
Line 1178 
Line 2247 
         public void          public void
 backspace()  backspace()
 {  {
   #if !MSDOS_COMPILER
         /*          /*
          * Try to erase the previous character by overstriking with a space.           * Erase the previous character by overstriking with a space.
          */           */
         tputs(sc_backspace, 1, putchr);          tputs(sc_backspace, 1, putchr);
         putchr(' ');          putchr(' ');
         tputs(sc_backspace, 1, putchr);          tputs(sc_backspace, 1, putchr);
   #else
   #if MSDOS_COMPILER==MSOFTC
           struct rccoord tpos;
   
           flush();
           tpos = _gettextposition();
           if (tpos.col <= 1)
                   return;
           _settextposition(tpos.row, tpos.col-1);
           _outtext(" ");
           _settextposition(tpos.row, tpos.col-1);
   #else
   #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
           cputs("\b");
   #else
   #if MSDOS_COMPILER==WIN32C
           COORD cpos;
           DWORD cChars;
           CONSOLE_SCREEN_BUFFER_INFO scr;
   
           flush();
           GetConsoleScreenBufferInfo(con_out, &scr);
           cpos = scr.dwCursorPosition;
           if (cpos.X <= 0)
                   return;
           cpos.X--;
           SetConsoleCursorPosition(con_out, cpos);
           FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars);
           SetConsoleCursorPosition(con_out, cpos);
   #endif
   #endif
   #endif
   #endif
 }  }
   #endif /* 0 */
   
 /*  /*
  * Output a plain backspace, without erasing the previous char.   * Output a plain backspace, without erasing the previous char.
Line 1192 
Line 2296 
         public void          public void
 putbs()  putbs()
 {  {
   #if !MSDOS_COMPILER
         tputs(sc_backspace, 1, putchr);          tputs(sc_backspace, 1, putchr);
   #else
           int row, col;
   
           flush();
           {
   #if MSDOS_COMPILER==MSOFTC
                   struct rccoord tpos;
                   tpos = _gettextposition();
                   row = tpos.row;
                   col = tpos.col;
   #else
   #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
                   row = wherey();
                   col = wherex();
   #else
   #if MSDOS_COMPILER==WIN32C
                   CONSOLE_SCREEN_BUFFER_INFO scr;
                   GetConsoleScreenBufferInfo(con_out, &scr);
                   row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1;
                   col = scr.dwCursorPosition.X - scr.srWindow.Left + 1;
   #endif
   #endif
   #endif
           }
           if (col <= 1)
                   return;
           _settextposition(row, col-1);
   #endif /* MSDOS_COMPILER */
 }  }
   
   #if MSDOS_COMPILER==WIN32C
   /*
    * Determine whether an input character is waiting to be read.
    */
           static int
   win32_kbhit(tty)
           HANDLE tty;
   {
           INPUT_RECORD ip;
           DWORD read;
   
           if (keyCount > 0)
                   return (TRUE);
   
           currentKey.ascii = 0;
           currentKey.scan = 0;
   
           /*
            * Wait for a real key-down event, but
            * ignore SHIFT and CONTROL key events.
            */
           do
           {
                   PeekConsoleInput(tty, &ip, 1, &read);
                   if (read == 0)
                           return (FALSE);
                   ReadConsoleInput(tty, &ip, 1, &read);
           } while (ip.EventType != KEY_EVENT ||
                   ip.Event.KeyEvent.bKeyDown != TRUE ||
                   ip.Event.KeyEvent.wVirtualScanCode == 0 ||
                   ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
                   ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL ||
                   ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU);
   
           currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar;
           currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode;
           keyCount = ip.Event.KeyEvent.wRepeatCount;
   
           if (ip.Event.KeyEvent.dwControlKeyState &
                   (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
           {
                   switch (currentKey.scan)
                   {
                   case PCK_ALT_E:     /* letter 'E' */
                           currentKey.ascii = 0;
                           break;
                   }
           } else if (ip.Event.KeyEvent.dwControlKeyState &
                   (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
           {
                   switch (currentKey.scan)
                   {
                   case PCK_RIGHT: /* right arrow */
                           currentKey.scan = PCK_CTL_RIGHT;
                           break;
                   case PCK_LEFT: /* left arrow */
                           currentKey.scan = PCK_CTL_LEFT;
                           break;
                   case PCK_DELETE: /* delete */
                           currentKey.scan = PCK_CTL_DELETE;
                           break;
                   }
           }
           return (TRUE);
   }
   
   /*
    * Read a character from the keyboard.
    */
           public char
   WIN32getch(tty)
           int tty;
   {
           int ascii;
   
           if (pending_scancode)
           {
                   pending_scancode = 0;
                   return ((char)(currentKey.scan & 0x00FF));
           }
   
           while (win32_kbhit((HANDLE)tty) == FALSE)
           {
                   Sleep(20);
                   if (ABORT_SIGS())
                           return ('\003');
                   continue;
           }
           keyCount --;
           ascii = currentKey.ascii;
           /*
            * On PC's, the extended keys return a 2 byte sequence beginning
            * with '00', so if the ascii code is 00, the next byte will be
            * the lsb of the scan code.
            */
           pending_scancode = (ascii == 0x00);
           return ((char)ascii);
   }
   #endif

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2