home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / less373.zip / screen.c < prev    next >
C/C++ Source or Header  |  2002-01-14  |  48KB  |  2,429 lines

  1. /*
  2.  * Copyright (C) 1984-2000  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_TERMIOS_H && HAVE_TERMIOS_FUNCS
  42. #include <termios.h>
  43. #if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ)
  44. #include <sys/ioctl.h>
  45. #endif
  46. #else
  47. #if HAVE_TERMIO_H
  48. #include <termio.h>
  49. #else
  50. #if HAVE_SGSTAT_H
  51. #include <sgstat.h>
  52. #else
  53. #include <sgtty.h>
  54. #endif
  55. #if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD))
  56. #include <sys/ioctl.h>
  57. #endif
  58. #endif
  59. #endif
  60.  
  61. #if HAVE_TERMCAP_H
  62. #include <termcap.h>
  63. #endif
  64. #ifdef _OSK
  65. #include <signal.h>
  66. #endif
  67. #if OS2
  68. #include <sys/signal.h>
  69. #include "pckeys.h"
  70. #endif
  71. #if HAVE_SYS_STREAM_H
  72. #include <sys/stream.h>
  73. #endif
  74. #if HAVE_SYS_PTEM_H
  75. #include <sys/ptem.h>
  76. #endif
  77.  
  78. #endif /* MSDOS_COMPILER */
  79.  
  80. /*
  81.  * Check for broken termios package that forces you to manually
  82.  * set the line discipline.
  83.  */
  84. #ifdef __ultrix__
  85. #define MUST_SET_LINE_DISCIPLINE 1
  86. #else
  87. #define MUST_SET_LINE_DISCIPLINE 0
  88. #endif
  89.  
  90. #if OS2
  91. #define    DEFAULT_TERM        "ansi"
  92. static char *windowid;
  93. #else
  94. #define    DEFAULT_TERM        "unknown"
  95. #endif
  96.  
  97. #if MSDOS_COMPILER==MSOFTC
  98. static int videopages;
  99. static long msec_loops;
  100. static int flash_created = 0;
  101. #define    SETCOLORS(fg,bg)    { _settextcolor(fg); _setbkcolor(bg); }
  102. #endif
  103.  
  104. #if MSDOS_COMPILER==BORLANDC
  105. static unsigned short *whitescreen;
  106. static int flash_created = 0;
  107. #endif
  108. #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  109. #define _settextposition(y,x)   gotoxy(x,y)
  110. #define _clearscreen(m)         clrscr()
  111. #define _outtext(s)             cputs(s)
  112. #define    SETCOLORS(fg,bg)    { textcolor(fg); textbackground(bg); }
  113. extern int sc_height;
  114. #endif
  115.  
  116. #if MSDOS_COMPILER==WIN32C
  117. struct keyRecord
  118. {
  119.     int ascii;
  120.     int scan;
  121. } currentKey;
  122.  
  123. static int keyCount = 0;
  124. static WORD curr_attr;
  125. static int pending_scancode = 0;
  126. static WORD *whitescreen;
  127.  
  128. static HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */
  129. static HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */
  130. HANDLE con_out = INVALID_HANDLE_VALUE;             /* current console */
  131.  
  132. extern int quitting;
  133. static void win32_init_term();
  134. static void win32_deinit_term();
  135.  
  136. #define FG_COLORS       (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)
  137. #define BG_COLORS       (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY)
  138. #define    MAKEATTR(fg,bg)        ((WORD)((fg)|((bg)<<4)))
  139. #define    SETCOLORS(fg,bg)    { curr_attr = MAKEATTR(fg,bg); \
  140.                 if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \
  141.                 error("SETCOLORS failed"); }
  142. #endif
  143.  
  144. #if MSDOS_COMPILER
  145. public int nm_fg_color;        /* Color of normal text */
  146. public int nm_bg_color;
  147. public int bo_fg_color;        /* Color of bold text */
  148. public int bo_bg_color;
  149. public int ul_fg_color;        /* Color of underlined text */
  150. public int ul_bg_color;
  151. public int so_fg_color;        /* Color of standout text */
  152. public int so_bg_color;
  153. public int bl_fg_color;        /* Color of blinking text */
  154. public int bl_bg_color;
  155. static int sy_fg_color;        /* Color of system text (before less) */
  156. static int sy_bg_color;
  157.  
  158. #else
  159.  
  160. /*
  161.  * Strings passed to tputs() to do various terminal functions.
  162.  */
  163. static char
  164.     *sc_pad,        /* Pad string */
  165.     *sc_home,        /* Cursor home */
  166.     *sc_addline,        /* Add line, scroll down following lines */
  167.     *sc_lower_left,        /* Cursor to last line, first column */
  168.     *sc_move,        /* General cursor positioning */
  169.     *sc_clear,        /* Clear screen */
  170.     *sc_eol_clear,        /* Clear to end of line */
  171.     *sc_eos_clear,        /* Clear to end of screen */
  172.     *sc_s_in,        /* Enter standout (highlighted) mode */
  173.     *sc_s_out,        /* Exit standout mode */
  174.     *sc_u_in,        /* Enter underline mode */
  175.     *sc_u_out,        /* Exit underline mode */
  176.     *sc_b_in,        /* Enter bold mode */
  177.     *sc_b_out,        /* Exit bold mode */
  178.     *sc_bl_in,        /* Enter blink mode */
  179.     *sc_bl_out,        /* Exit blink mode */
  180.     *sc_visual_bell,    /* Visual bell (flash screen) sequence */
  181.     *sc_backspace,        /* Backspace cursor */
  182.     *sc_s_keypad,        /* Start keypad mode */
  183.     *sc_e_keypad,        /* End keypad mode */
  184.     *sc_init,        /* Startup terminal initialization */
  185.     *sc_deinit;        /* Exit terminal de-initialization */
  186. #endif
  187.  
  188. static int init_done = 0;
  189.  
  190. public int auto_wrap;        /* Terminal does \r\n when write past margin */
  191. public int ignaw;        /* Terminal ignores \n immediately after wrap */
  192. public int erase_char, kill_char; /* The user's erase and line-kill chars */
  193. public int werase_char;        /* The user's word-erase char */
  194. public int sc_width, sc_height;    /* Height & width of screen */
  195. public int bo_s_width, bo_e_width;    /* Printing width of boldface seq */
  196. public int ul_s_width, ul_e_width;    /* Printing width of underline seq */
  197. public int so_s_width, so_e_width;    /* Printing width of standout seq */
  198. public int bl_s_width, bl_e_width;    /* Printing width of blink seq */
  199. public int above_mem, below_mem;    /* Memory retained above/below screen */
  200. public int can_goto_line;        /* Can move cursor to any line */
  201. public int clear_bg;        /* Clear fills with background color */
  202. public int missing_cap = 0;    /* Some capability is missing */
  203.  
  204. static int attrmode = AT_NORMAL;
  205.  
  206. #if !MSDOS_COMPILER
  207. static char *cheaper();
  208. static void tmodes();
  209. #endif
  210.  
  211. /*
  212.  * These two variables are sometimes defined in,
  213.  * and needed by, the termcap library.
  214.  */
  215. #if MUST_DEFINE_OSPEED
  216. extern short ospeed;    /* Terminal output baud rate */
  217. extern char PC;        /* Pad character */
  218. #endif
  219. #ifdef _OSK
  220. short ospeed;
  221. char PC_, *UP, *BC;
  222. #endif
  223.  
  224. extern int quiet;        /* If VERY_QUIET, use visual bell for bell */
  225. extern int no_back_scroll;
  226. extern int swindow;
  227. extern int no_init;
  228. extern int no_keypad;
  229. extern int sigs;
  230. extern int wscroll;
  231. extern int screen_trashed;
  232. #if HILITE_SEARCH
  233. extern int hilite_search;
  234. #endif
  235.  
  236. extern char *tgetstr();
  237. extern char *tgoto();
  238.  
  239.  
  240. /*
  241.  * Change terminal to "raw mode", or restore to "normal" mode.
  242.  * "Raw mode" means 
  243.  *    1. An outstanding read will complete on receipt of a single keystroke.
  244.  *    2. Input is not echoed.  
  245.  *    3. On output, \n is mapped to \r\n.
  246.  *    4. \t is NOT expanded into spaces.
  247.  *    5. Signal-causing characters such as ctrl-C (interrupt),
  248.  *       etc. are NOT disabled.
  249.  * It doesn't matter whether an input \n is mapped to \r, or vice versa.
  250.  */
  251.     public void
  252. raw_mode(on)
  253.     int on;
  254. {
  255.     static int curr_on = 0;
  256.  
  257.     if (on == curr_on)
  258.         return;
  259. #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
  260.     {
  261.     struct termios s;
  262.     static struct termios save_term;
  263.     static int saved_term = 0;
  264.  
  265.     if (on) 
  266.     {
  267.         /*
  268.          * Get terminal modes.
  269.          */
  270.         tcgetattr(2, &s);
  271.  
  272.         /*
  273.          * Save modes and set certain variables dependent on modes.
  274.          */
  275.         if (!saved_term)
  276.         {
  277.             save_term = s;
  278.             saved_term = 1;
  279.         }
  280. #if HAVE_OSPEED
  281.         switch (cfgetospeed(&s))
  282.         {
  283. #ifdef B0
  284.         case B0: ospeed = 0; break;
  285. #endif
  286. #ifdef B50
  287.         case B50: ospeed = 1; break;
  288. #endif
  289. #ifdef B75
  290.         case B75: ospeed = 2; break;
  291. #endif
  292. #ifdef B110
  293.         case B110: ospeed = 3; break;
  294. #endif
  295. #ifdef B134
  296.         case B134: ospeed = 4; break;
  297. #endif
  298. #ifdef B150
  299.         case B150: ospeed = 5; break;
  300. #endif
  301. #ifdef B200
  302.         case B200: ospeed = 6; break;
  303. #endif
  304. #ifdef B300
  305.         case B300: ospeed = 7; break;
  306. #endif
  307. #ifdef B600
  308.         case B600: ospeed = 8; break;
  309. #endif
  310. #ifdef B1200
  311.         case B1200: ospeed = 9; break;
  312. #endif
  313. #ifdef B1800
  314.         case B1800: ospeed = 10; break;
  315. #endif
  316. #ifdef B2400
  317.         case B2400: ospeed = 11; break;
  318. #endif
  319. #ifdef B4800
  320.         case B4800: ospeed = 12; break;
  321. #endif
  322. #ifdef B9600
  323.         case B9600: ospeed = 13; break;
  324. #endif
  325. #ifdef EXTA
  326.         case EXTA: ospeed = 14; break;
  327. #endif
  328. #ifdef EXTB
  329.         case EXTB: ospeed = 15; break;
  330. #endif
  331. #ifdef B57600
  332.         case B57600: ospeed = 16; break;
  333. #endif
  334. #ifdef B115200
  335.         case B115200: ospeed = 17; break;
  336. #endif
  337.         default: ;
  338.         }
  339. #endif
  340.         erase_char = s.c_cc[VERASE];
  341.         kill_char = s.c_cc[VKILL];
  342. #ifdef VWERASE
  343.         werase_char = s.c_cc[VWERASE];
  344. #else
  345.         werase_char = CONTROL('W');
  346. #endif
  347.  
  348.         /*
  349.          * Set the modes to the way we want them.
  350.          */
  351.         s.c_lflag &= ~(0
  352. #ifdef ICANON
  353.             | ICANON
  354. #endif
  355. #ifdef ECHO
  356.             | ECHO
  357. #endif
  358. #ifdef ECHOE
  359.             | ECHOE
  360. #endif
  361. #ifdef ECHOK
  362.             | ECHOK
  363. #endif
  364. #if ECHONL
  365.             | ECHONL
  366. #endif
  367.         );
  368.  
  369.         s.c_oflag |= (0
  370. #ifdef OXTABS
  371.             | OXTABS
  372. #else
  373. #ifdef TAB3
  374.             | TAB3
  375. #else
  376. #ifdef XTABS
  377.             | XTABS
  378. #endif
  379. #endif
  380. #endif
  381. #ifdef OPOST
  382.             | OPOST
  383. #endif
  384. #ifdef ONLCR
  385.             | ONLCR
  386. #endif
  387.         );
  388.  
  389.         s.c_oflag &= ~(0
  390. #ifdef ONOEOT
  391.             | ONOEOT
  392. #endif
  393. #ifdef OCRNL
  394.             | OCRNL
  395. #endif
  396. #ifdef ONOCR
  397.             | ONOCR
  398. #endif
  399. #ifdef ONLRET
  400.             | ONLRET
  401. #endif
  402.         );
  403.         s.c_cc[VMIN] = 1;
  404.         s.c_cc[VTIME] = 0;
  405. #ifdef VLNEXT
  406.         s.c_cc[VLNEXT] = 0;
  407. #endif
  408. #ifdef VDSUSP
  409.         s.c_cc[VDSUSP] = 0;
  410. #endif
  411. #if MUST_SET_LINE_DISCIPLINE
  412.         /*
  413.          * System's termios is broken; need to explicitly 
  414.          * request TERMIODISC line discipline.
  415.          */
  416.         s.c_line = TERMIODISC;
  417. #endif
  418.     } else
  419.     {
  420.         /*
  421.          * Restore saved modes.
  422.          */
  423.         s = save_term;
  424.     }
  425. #if HAVE_FSYNC
  426.     fsync(2);
  427. #endif
  428.     tcsetattr(2, TCSADRAIN, &s);
  429. #if MUST_SET_LINE_DISCIPLINE
  430.     if (!on)
  431.     {
  432.         /*
  433.          * Broken termios *ignores* any line discipline
  434.          * except TERMIODISC.  A different old line discipline
  435.          * is therefore not restored, yet.  Restore the old
  436.          * line discipline by hand.
  437.          */
  438.         ioctl(2, TIOCSETD, &save_term.c_line);
  439.     }
  440. #endif
  441.     }
  442. #else
  443. #ifdef TCGETA
  444.     {
  445.     struct termio s;
  446.     static struct termio save_term;
  447.     static int saved_term = 0;
  448.  
  449.     if (on)
  450.     {
  451.         /*
  452.          * Get terminal modes.
  453.          */
  454.         ioctl(2, TCGETA, &s);
  455.  
  456.         /*
  457.          * Save modes and set certain variables dependent on modes.
  458.          */
  459.         if (!saved_term)
  460.         {
  461.             save_term = s;
  462.             saved_term = 1;
  463.         }
  464. #if HAVE_OSPEED
  465.         ospeed = s.c_cflag & CBAUD;
  466. #endif
  467.         erase_char = s.c_cc[VERASE];
  468.         kill_char = s.c_cc[VKILL];
  469. #ifdef VWERASE
  470.         werase_char = s.c_cc[VWERASE];
  471. #else
  472.         werase_char = CONTROL('W');
  473. #endif
  474.  
  475.         /*
  476.          * Set the modes to the way we want them.
  477.          */
  478.         s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  479.         s.c_oflag |=  (OPOST|ONLCR|TAB3);
  480.         s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
  481.         s.c_cc[VMIN] = 1;
  482.         s.c_cc[VTIME] = 0;
  483.     } else
  484.     {
  485.         /*
  486.          * Restore saved modes.
  487.          */
  488.         s = save_term;
  489.     }
  490.     ioctl(2, TCSETAW, &s);
  491.     }
  492. #else
  493. #ifdef TIOCGETP
  494.     {
  495.     struct sgttyb s;
  496.     static struct sgttyb save_term;
  497.     static int saved_term = 0;
  498.  
  499.     if (on)
  500.     {
  501.         /*
  502.          * Get terminal modes.
  503.          */
  504.         ioctl(2, TIOCGETP, &s);
  505.  
  506.         /*
  507.          * Save modes and set certain variables dependent on modes.
  508.          */
  509.         if (!saved_term)
  510.         {
  511.             save_term = s;
  512.             saved_term = 1;
  513.         }
  514. #if HAVE_OSPEED
  515.         ospeed = s.sg_ospeed;
  516. #endif
  517.         erase_char = s.sg_erase;
  518.         kill_char = s.sg_kill;
  519.         werase_char = CONTROL('W');
  520.  
  521.         /*
  522.          * Set the modes to the way we want them.
  523.          */
  524.         s.sg_flags |= CBREAK;
  525.         s.sg_flags &= ~(ECHO|XTABS);
  526.     } else
  527.     {
  528.         /*
  529.          * Restore saved modes.
  530.          */
  531.         s = save_term;
  532.     }
  533.     ioctl(2, TIOCSETN, &s);
  534.     }
  535. #else
  536. #ifdef _OSK
  537.     {
  538.     struct sgbuf s;
  539.     static struct sgbuf save_term;
  540.     static int saved_term = 0;
  541.  
  542.     if (on)
  543.     {
  544.         /*
  545.          * Get terminal modes.
  546.          */
  547.         _gs_opt(2, &s);
  548.  
  549.         /*
  550.          * Save modes and set certain variables dependent on modes.
  551.          */
  552.         if (!saved_term)
  553.         {
  554.             save_term = s;
  555.             saved_term = 1;
  556.         }
  557.         erase_char = s.sg_bspch;
  558.         kill_char = s.sg_dlnch;
  559.         werase_char = CONTROL('W');
  560.  
  561.         /*
  562.          * Set the modes to the way we want them.
  563.          */
  564.         s.sg_echo = 0;
  565.         s.sg_eofch = 0;
  566.         s.sg_pause = 0;
  567.         s.sg_psch = 0;
  568.     } else
  569.     {
  570.         /*
  571.          * Restore saved modes.
  572.          */
  573.         s = save_term;
  574.     }
  575.     _ss_opt(2, &s);
  576.     }
  577. #else
  578.     /* MS-DOS, Windows, or OS2 */
  579. #if OS2
  580.     /* OS2 */
  581.     LSIGNAL(SIGINT, SIG_IGN);
  582. #endif
  583.     erase_char = '\b';
  584. #if MSDOS_COMPILER==DJGPPC
  585.     kill_char = CONTROL('U');
  586.     /*
  587.      * So that when we shell out or run another program, its
  588.      * stdin is in cooked mode.  We do not switch stdin to binary 
  589.      * mode if fd0 is zero, since that means we were called before
  590.      * tty was reopened in open_getchr, in which case we would be
  591.      * changing the original stdin device outside less.
  592.      */
  593.     if (fd0 != 0)
  594.         setmode(0, on ? O_BINARY : O_TEXT);
  595. #else
  596.     kill_char = ESC;
  597. #endif
  598.     werase_char = CONTROL('W');
  599. #endif
  600. #endif
  601. #endif
  602. #endif
  603.     curr_on = on;
  604. }
  605.  
  606. #if !MSDOS_COMPILER
  607. /*
  608.  * Some glue to prevent calling termcap functions if tgetent() failed.
  609.  */
  610. static int hardcopy;
  611.  
  612.     static char *
  613. ltget_env(capname)
  614.     char *capname;
  615. {
  616.     char name[16];
  617.  
  618.     strcpy(name, "LESS_TERMCAP_");
  619.     strcat(name, capname);
  620.     return (lgetenv(name));
  621. }
  622.  
  623.     static int
  624. ltgetflag(capname)
  625.     char *capname;
  626. {
  627.     char *s;
  628.  
  629.     if ((s = ltget_env(capname)) != NULL)
  630.         return (*s != '\0' && *s != '0');
  631.     if (hardcopy)
  632.         return (0);
  633.     return (tgetflag(capname));
  634. }
  635.  
  636.     static int
  637. ltgetnum(capname)
  638.     char *capname;
  639. {
  640.     char *s;
  641.  
  642.     if ((s = ltget_env(capname)) != NULL)
  643.         return (atoi(s));
  644.     if (hardcopy)
  645.         return (-1);
  646.     return (tgetnum(capname));
  647. }
  648.  
  649.     static char *
  650. ltgetstr(capname, pp)
  651.     char *capname;
  652.     char **pp;
  653. {
  654.     char *s;
  655.  
  656.     if ((s = ltget_env(capname)) != NULL)
  657.         return (s);
  658.     if (hardcopy)
  659.         return (NULL);
  660.     return (tgetstr(capname, pp));
  661. }
  662. #endif /* MSDOS_COMPILER */
  663.  
  664. /*
  665.  * Get size of the output screen.
  666.  */
  667.     public void
  668. scrsize()
  669. {
  670.     register char *s;
  671.     int sys_height;
  672.     int sys_width;
  673. #if !MSDOS_COMPILER
  674.     int n;
  675. #endif
  676.  
  677. #define    DEF_SC_WIDTH    80
  678. #if MSDOS_COMPILER
  679. #define    DEF_SC_HEIGHT    25
  680. #else
  681. #define    DEF_SC_HEIGHT    24
  682. #endif
  683.  
  684.  
  685.     sys_width = sys_height = 0;
  686.  
  687. #if MSDOS_COMPILER==MSOFTC
  688.     {
  689.         struct videoconfig w;
  690.         _getvideoconfig(&w);
  691.         sys_height = w.numtextrows;
  692.         sys_width = w.numtextcols;
  693.     }
  694. #else
  695. #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  696.     {
  697.         struct text_info w;
  698.         gettextinfo(&w);
  699.         sys_height = w.screenheight;
  700.         sys_width = w.screenwidth;
  701.     }
  702. #else
  703. #if MSDOS_COMPILER==WIN32C
  704.     {
  705.         CONSOLE_SCREEN_BUFFER_INFO scr;
  706.         GetConsoleScreenBufferInfo(con_out, &scr);
  707.         sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1;
  708.         sys_width = scr.srWindow.Right - scr.srWindow.Left + 1;
  709.     }
  710. #else
  711. #if OS2
  712.     {
  713.         int s[2];
  714.         _scrsize(s);
  715.         sys_width = s[0];
  716.         sys_height = s[1];
  717.         /*
  718.          * When using terminal emulators for XFree86/OS2, the
  719.          * _scrsize function does not work well.
  720.          * Call the scrsize.exe program to get the window size.
  721.          */
  722.         windowid = getenv("WINDOWID");
  723.         if (windowid != NULL)
  724.         {
  725.             FILE *fd = popen("scrsize", "rt");
  726.             if (fd != NULL)
  727.             {
  728.                 int w, h;
  729.                 fscanf(fd, "%i %i", &w, &h);
  730.                 if (w > 0 && h > 0)
  731.                 {
  732.                     sys_width = w;
  733.                     sys_height = h;
  734.                 }
  735.                 pclose(fd);
  736.             }
  737.         }
  738.     }
  739. #else
  740. #ifdef TIOCGWINSZ
  741.     {
  742.         struct winsize w;
  743.         if (ioctl(2, TIOCGWINSZ, &w) == 0)
  744.         {
  745.             if (w.ws_row > 0)
  746.                 sys_height = w.ws_row;
  747.             if (w.ws_col > 0)
  748.                 sys_width = w.ws_col;
  749.         }
  750.     }
  751. #else
  752. #ifdef WIOCGETD
  753.     {
  754.         struct uwdata w;
  755.         if (ioctl(2, WIOCGETD, &w) == 0)
  756.         {
  757.             if (w.uw_height > 0)
  758.                 sys_height = w.uw_height / w.uw_vs;
  759.             if (w.uw_width > 0)
  760.                 sys_width = w.uw_width / w.uw_hs;
  761.         }
  762.     }
  763. #endif
  764. #endif
  765. #endif
  766. #endif
  767. #endif
  768. #endif
  769.  
  770.     if (sys_height > 0)
  771.         sc_height = sys_height;
  772.     else if ((s = lgetenv("LINES")) != NULL)
  773.         sc_height = atoi(s);
  774. #if !MSDOS_COMPILER
  775.     else if ((n = ltgetnum("li")) > 0)
  776.          sc_height = n;
  777. #endif
  778.     else
  779.         sc_height = DEF_SC_HEIGHT;
  780.  
  781.     if (sys_width > 0)
  782.         sc_width = sys_width;
  783.     else if ((s = lgetenv("COLUMNS")) != NULL)
  784.         sc_width = atoi(s);
  785. #if !MSDOS_COMPILER
  786.     else if ((n = ltgetnum("co")) > 0)
  787.          sc_width = n;
  788. #endif
  789.     else
  790.         sc_width = DEF_SC_WIDTH;
  791. }
  792.  
  793. #if MSDOS_COMPILER==MSOFTC
  794. /*
  795.  * Figure out how many empty loops it takes to delay a millisecond.
  796.  */
  797.     static void
  798. get_clock()
  799. {
  800.     clock_t start;
  801.     
  802.     /*
  803.      * Get synchronized at the start of a tick.
  804.      */
  805.     start = clock();
  806.     while (clock() == start)
  807.         ;
  808.     /*
  809.      * Now count loops till the next tick.
  810.      */
  811.     start = clock();
  812.     msec_loops = 0;
  813.     while (clock() == start)
  814.         msec_loops++;
  815.     /*
  816.      * Convert from (loops per clock) to (loops per millisecond).
  817.      */
  818.     msec_loops *= CLOCKS_PER_SEC;
  819.     msec_loops /= 1000;
  820. }
  821.  
  822. /*
  823.  * Delay for a specified number of milliseconds.
  824.  */
  825.     static void
  826. dummy_func()
  827. {
  828.     static long delay_dummy = 0;
  829.     delay_dummy++;
  830. }
  831.  
  832.     static void
  833. delay(msec)
  834.     int msec;
  835. {
  836.     long i;
  837.     
  838.     while (msec-- > 0)
  839.     {
  840.         for (i = 0;  i < msec_loops;  i++)
  841.         {
  842.             /*
  843.              * Make it look like we're doing something here,
  844.              * so the optimizer doesn't remove the whole loop.
  845.              */
  846.             dummy_func();
  847.         }
  848.     }
  849. }
  850. #endif
  851.  
  852. /*
  853.  * Return the characters actually input by a "special" key.
  854.  */
  855.     public char *
  856. special_key_str(key)
  857.     int key;
  858. {
  859.     static char tbuf[40];
  860.     char *s;
  861. #if MSDOS_COMPILER || OS2
  862.     static char k_right[]        = { '\340', PCK_RIGHT, 0 };
  863.     static char k_left[]        = { '\340', PCK_LEFT, 0  };
  864.     static char k_ctl_right[]    = { '\340', PCK_CTL_RIGHT, 0  };
  865.     static char k_ctl_left[]    = { '\340', PCK_CTL_LEFT, 0  };
  866.     static char k_insert[]        = { '\340', PCK_INSERT, 0  };
  867.     static char k_delete[]        = { '\340', PCK_DELETE, 0  };
  868.     static char k_ctl_delete[]    = { '\340', PCK_CTL_DELETE, 0  };
  869.     static char k_ctl_backspace[]    = { '\177', 0 };
  870.     static char k_home[]        = { '\340', PCK_HOME, 0 };
  871.     static char k_end[]        = { '\340', PCK_END, 0 };
  872.     static char k_up[]        = { '\340', PCK_UP, 0 };
  873.     static char k_down[]        = { '\340', PCK_DOWN, 0 };
  874.     static char k_backtab[]        = { '\340', PCK_SHIFT_TAB, 0 };
  875.     static char k_pagedown[]    = { '\340', PCK_PAGEDOWN, 0 };
  876.     static char k_pageup[]        = { '\340', PCK_PAGEUP, 0 };
  877.     static char k_f1[]        = { '\340', PCK_F1, 0 };
  878. #endif
  879. #if !MSDOS_COMPILER
  880.     char *sp = tbuf;
  881. #endif
  882.  
  883.     switch (key)
  884.     {
  885. #if OS2
  886.     /*
  887.      * If windowid is not NULL, assume less is executed in 
  888.      * the XFree86 environment.
  889.      */
  890.     case SK_RIGHT_ARROW:
  891.         s = windowid ? ltgetstr("kr", &sp) : k_right;
  892.         break;
  893.     case SK_LEFT_ARROW:
  894.         s = windowid ? ltgetstr("kl", &sp) : k_left;
  895.         break;
  896.     case SK_UP_ARROW:
  897.         s = windowid ? ltgetstr("ku", &sp) : k_up;
  898.         break;
  899.     case SK_DOWN_ARROW:
  900.         s = windowid ? ltgetstr("kd", &sp) : k_down;
  901.         break;
  902.     case SK_PAGE_UP:
  903.         s = windowid ? ltgetstr("kP", &sp) : k_pageup;
  904.         break;
  905.     case SK_PAGE_DOWN:
  906.         s = windowid ? ltgetstr("kN", &sp) : k_pagedown;
  907.         break;
  908.     case SK_HOME:
  909.         s = windowid ? ltgetstr("kh", &sp) : k_home;
  910.         break;
  911.     case SK_END:
  912.         s = windowid ? ltgetstr("@7", &sp) : k_end;
  913.         break;
  914.     case SK_DELETE:
  915.         if (windowid)
  916.         {
  917.             s = ltgetstr("kD", &sp);
  918.             if (s == NULL)
  919.             {
  920.                 tbuf[0] = '\177';
  921.                 tbuf[1] = '\0';
  922.                 s = tbuf;
  923.             }
  924.         } else
  925.             s = k_delete;
  926.         break;
  927. #endif
  928. #if MSDOS_COMPILER
  929.     case SK_RIGHT_ARROW:
  930.         s = k_right;
  931.         break;
  932.     case SK_LEFT_ARROW:
  933.         s = k_left;
  934.         break;
  935.     case SK_UP_ARROW:
  936.         s = k_up;
  937.         break;
  938.     case SK_DOWN_ARROW:
  939.         s = k_down;
  940.         break;
  941.     case SK_PAGE_UP:
  942.         s = k_pageup;
  943.         break;
  944.     case SK_PAGE_DOWN:
  945.         s = k_pagedown;
  946.         break;
  947.     case SK_HOME:
  948.         s = k_home;
  949.         break;
  950.     case SK_END:
  951.         s = k_end;
  952.         break;
  953.     case SK_DELETE:
  954.         s = k_delete;
  955.         break;
  956. #endif
  957. #if MSDOS_COMPILER || OS2
  958.     case SK_INSERT:
  959.         s = k_insert;
  960.         break;
  961.     case SK_CTL_LEFT_ARROW:
  962.         s = k_ctl_left;
  963.         break;
  964.     case SK_CTL_RIGHT_ARROW:
  965.         s = k_ctl_right;
  966.         break;
  967.     case SK_CTL_BACKSPACE:
  968.         s = k_ctl_backspace;
  969.         break;
  970.     case SK_CTL_DELETE:
  971.         s = k_ctl_delete;
  972.         break;
  973.     case SK_F1:
  974.         s = k_f1;
  975.         break;
  976.     case SK_BACKTAB:
  977.         s = k_backtab;
  978.         break;
  979. #else
  980.     case SK_RIGHT_ARROW:
  981.         s = ltgetstr("kr", &sp);
  982.         break;
  983.     case SK_LEFT_ARROW:
  984.         s = ltgetstr("kl", &sp);
  985.         break;
  986.     case SK_UP_ARROW:
  987.         s = ltgetstr("ku", &sp);
  988.         break;
  989.     case SK_DOWN_ARROW:
  990.         s = ltgetstr("kd", &sp);
  991.         break;
  992.     case SK_PAGE_UP:
  993.         s = ltgetstr("kP", &sp);
  994.         break;
  995.     case SK_PAGE_DOWN:
  996.         s = ltgetstr("kN", &sp);
  997.         break;
  998.     case SK_HOME:
  999.         s = ltgetstr("kh", &sp);
  1000.         break;
  1001.     case SK_END:
  1002.         s = ltgetstr("@7", &sp);
  1003.         break;
  1004.     case SK_DELETE:
  1005.         s = ltgetstr("kD", &sp);
  1006.         if (s == NULL)
  1007.         {
  1008.             tbuf[0] = '\177';
  1009.             tbuf[1] = '\0';
  1010.             s = tbuf;
  1011.         }
  1012.         break;
  1013. #endif
  1014.     case SK_CONTROL_K:
  1015.         tbuf[0] = CONTROL('K');
  1016.         tbuf[1] = '\0';
  1017.         s = tbuf;
  1018.         break;
  1019.     default:
  1020.         return (NULL);
  1021.     }
  1022.     return (s);
  1023. }
  1024.  
  1025. /*
  1026.  * Get terminal capabilities via termcap.
  1027.  */
  1028.     public void
  1029. get_term()
  1030. {
  1031. #if MSDOS_COMPILER
  1032.     auto_wrap = 1;
  1033.     ignaw = 0;
  1034.     can_goto_line = 1;
  1035.     clear_bg = 1;
  1036.     /*
  1037.      * Set up default colors.
  1038.      * The xx_s_width and xx_e_width vars are already initialized to 0.
  1039.      */
  1040. #if MSDOS_COMPILER==MSOFTC
  1041.     sy_bg_color = _getbkcolor();
  1042.     sy_fg_color = _gettextcolor();
  1043.     get_clock();
  1044. #else
  1045. #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  1046.     {
  1047.     struct text_info w;
  1048.     gettextinfo(&w);
  1049.     sy_bg_color = (w.attribute >> 4) & 0x0F;
  1050.     sy_fg_color = (w.attribute >> 0) & 0x0F;
  1051.     }
  1052. #else
  1053. #if MSDOS_COMPILER==WIN32C
  1054.     {
  1055.     DWORD nread;
  1056.     CONSOLE_SCREEN_BUFFER_INFO scr;
  1057.  
  1058.     con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE);
  1059.     /*
  1060.      * Always open stdin in binary. Note this *must* be done
  1061.      * before any file operations have been done on fd0.
  1062.      */
  1063.     SET_BINARY(0);
  1064.     GetConsoleScreenBufferInfo(con_out, &scr);
  1065.     ReadConsoleOutputAttribute(con_out, &curr_attr, 
  1066.                     1, scr.dwCursorPosition, &nread);
  1067.     sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */
  1068.     sy_fg_color = curr_attr & FG_COLORS;
  1069.     }
  1070. #endif
  1071. #endif
  1072. #endif
  1073.     nm_fg_color = sy_fg_color;
  1074.     nm_bg_color = sy_bg_color;
  1075.     bo_fg_color = 11;
  1076.     bo_bg_color = 0;
  1077.     ul_fg_color = 9;
  1078.     ul_bg_color = 0;
  1079.     so_fg_color = 15;
  1080.     so_bg_color = 9;
  1081.     bl_fg_color = 15;
  1082.     bl_bg_color = 0;
  1083.  
  1084.     /*
  1085.      * Get size of the screen.
  1086.      */
  1087.     scrsize();
  1088.     pos_init();
  1089.  
  1090.  
  1091. #else /* !MSDOS_COMPILER */
  1092.  
  1093.     char *sp;
  1094.     register char *t1, *t2;
  1095.     char *term;
  1096.     char termbuf[TERMBUF_SIZE];
  1097.  
  1098.     static char sbuf[TERMSBUF_SIZE];
  1099.  
  1100. #if OS2
  1101.     /*
  1102.      * Make sure the termcap database is available.
  1103.      */
  1104.     sp = lgetenv("TERMCAP");
  1105.     if (sp == NULL || *sp == '\0')
  1106.     {
  1107.         char *termcap;
  1108.         if ((sp = homefile("termcap.dat")) != NULL)
  1109.         {
  1110.             termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char));
  1111.             sprintf(termcap, "TERMCAP=%s", sp);
  1112.             free(sp);
  1113.             putenv(termcap);
  1114.         }
  1115.     }
  1116. #endif
  1117.     /*
  1118.      * Find out what kind of terminal this is.
  1119.      */
  1120.      if ((term = lgetenv("TERM")) == NULL)
  1121.          term = DEFAULT_TERM;
  1122.     hardcopy = 0;
  1123.      if (tgetent(termbuf, term) <= 0)
  1124.          hardcopy = 1;
  1125.      if (ltgetflag("hc"))
  1126.         hardcopy = 1;
  1127.  
  1128.     /*
  1129.      * Get size of the screen.
  1130.      */
  1131.     scrsize();
  1132.     pos_init();
  1133.  
  1134.     auto_wrap = ltgetflag("am");
  1135.     ignaw = ltgetflag("xn");
  1136.     above_mem = ltgetflag("da");
  1137.     below_mem = ltgetflag("db");
  1138.     clear_bg = ltgetflag("ut");
  1139.  
  1140.     /*
  1141.      * Assumes termcap variable "sg" is the printing width of:
  1142.      * the standout sequence, the end standout sequence,
  1143.      * the underline sequence, the end underline sequence,
  1144.      * the boldface sequence, and the end boldface sequence.
  1145.      */
  1146.     if ((so_s_width = ltgetnum("sg")) < 0)
  1147.         so_s_width = 0;
  1148.     so_e_width = so_s_width;
  1149.  
  1150.     bo_s_width = bo_e_width = so_s_width;
  1151.     ul_s_width = ul_e_width = so_s_width;
  1152.     bl_s_width = bl_e_width = so_s_width;
  1153.  
  1154. #if HILITE_SEARCH
  1155.     if (so_s_width > 0 || so_e_width > 0)
  1156.         /*
  1157.          * Disable highlighting by default on magic cookie terminals.
  1158.          * Turning on highlighting might change the displayed width
  1159.          * of a line, causing the display to get messed up.
  1160.          * The user can turn it back on with -g, 
  1161.          * but she won't like the results.
  1162.          */
  1163.         hilite_search = 0;
  1164. #endif
  1165.  
  1166.     /*
  1167.      * Get various string-valued capabilities.
  1168.      */
  1169.     sp = sbuf;
  1170.  
  1171. #if HAVE_OSPEED
  1172.     sc_pad = ltgetstr("pc", &sp);
  1173.     if (sc_pad != NULL)
  1174.         PC = *sc_pad;
  1175. #endif
  1176.  
  1177.     sc_s_keypad = ltgetstr("ks", &sp);
  1178.     if (sc_s_keypad == NULL)
  1179.         sc_s_keypad = "";
  1180.     sc_e_keypad = ltgetstr("ke", &sp);
  1181.     if (sc_e_keypad == NULL)
  1182.         sc_e_keypad = "";
  1183.         
  1184.     sc_init = ltgetstr("ti", &sp);
  1185.     if (sc_init == NULL)
  1186.         sc_init = "";
  1187.  
  1188.     sc_deinit= ltgetstr("te", &sp);
  1189.     if (sc_deinit == NULL)
  1190.         sc_deinit = "";
  1191.  
  1192.     sc_eol_clear = ltgetstr("ce", &sp);
  1193.     if (sc_eol_clear == NULL || *sc_eol_clear == '\0')
  1194.     {
  1195.         missing_cap = 1;
  1196.         sc_eol_clear = "";
  1197.     }
  1198.  
  1199.     sc_eos_clear = ltgetstr("cd", &sp);
  1200.     if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0'))
  1201.     {
  1202.         missing_cap = 1;
  1203.         sc_eol_clear = "";
  1204.     }
  1205.  
  1206.     sc_clear = ltgetstr("cl", &sp);
  1207.     if (sc_clear == NULL || *sc_clear == '\0')
  1208.     {
  1209.         missing_cap = 1;
  1210.         sc_clear = "\n\n";
  1211.     }
  1212.  
  1213.     sc_move = ltgetstr("cm", &sp);
  1214.     if (sc_move == NULL || *sc_move == '\0')
  1215.     {
  1216.         /*
  1217.          * This is not an error here, because we don't 
  1218.          * always need sc_move.
  1219.          * We need it only if we don't have home or lower-left.
  1220.          */
  1221.         sc_move = "";
  1222.         can_goto_line = 0;
  1223.     } else
  1224.         can_goto_line = 1;
  1225.  
  1226.     tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp);
  1227.     tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp);
  1228.     tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp);
  1229.     tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp);
  1230.  
  1231.     sc_visual_bell = ltgetstr("vb", &sp);
  1232.     if (sc_visual_bell == NULL)
  1233.         sc_visual_bell = "";
  1234.  
  1235.     if (ltgetflag("bs"))
  1236.         sc_backspace = "\b";
  1237.     else
  1238.     {
  1239.         sc_backspace = ltgetstr("bc", &sp);
  1240.         if (sc_backspace == NULL || *sc_backspace == '\0')
  1241.             sc_backspace = "\b";
  1242.     }
  1243.  
  1244.     /*
  1245.      * Choose between using "ho" and "cm" ("home" and "cursor move")
  1246.      * to move the cursor to the upper left corner of the screen.
  1247.      */
  1248.     t1 = ltgetstr("ho", &sp);
  1249.     if (t1 == NULL)
  1250.         t1 = "";
  1251.     if (*sc_move == '\0')
  1252.         t2 = "";
  1253.     else
  1254.     {
  1255.         strcpy(sp, tgoto(sc_move, 0, 0));
  1256.         t2 = sp;
  1257.         sp += strlen(sp) + 1;
  1258.     }
  1259.     sc_home = cheaper(t1, t2, "|\b^");
  1260.  
  1261.     /*
  1262.      * Choose between using "ll" and "cm"  ("lower left" and "cursor move")
  1263.      * to move the cursor to the lower left corner of the screen.
  1264.      */
  1265.     t1 = ltgetstr("ll", &sp);
  1266.     if (t1 == NULL)
  1267.         t1 = "";
  1268.     if (*sc_move == '\0')
  1269.         t2 = "";
  1270.     else
  1271.     {
  1272.         strcpy(sp, tgoto(sc_move, 0, sc_height-1));
  1273.         t2 = sp;
  1274.         sp += strlen(sp) + 1;
  1275.     }
  1276.     sc_lower_left = cheaper(t1, t2, "\r");
  1277.  
  1278.     /*
  1279.      * Choose between using "al" or "sr" ("add line" or "scroll reverse")
  1280.      * to add a line at the top of the screen.
  1281.      */
  1282.     t1 = ltgetstr("al", &sp);
  1283.     if (t1 == NULL)
  1284.         t1 = "";
  1285.     t2 = ltgetstr("sr", &sp);
  1286.     if (t2 == NULL)
  1287.         t2 = "";
  1288. #if OS2
  1289.     if (*t1 == '\0' && *t2 == '\0')
  1290.         sc_addline = "";
  1291.     else
  1292. #endif
  1293.     if (above_mem)
  1294.         sc_addline = t1;
  1295.     else
  1296.         sc_addline = cheaper(t1, t2, "");
  1297.     if (*sc_addline == '\0')
  1298.     {
  1299.         /*
  1300.          * Force repaint on any backward movement.
  1301.          */
  1302.         no_back_scroll = 1;
  1303.     }
  1304. #endif /* MSDOS_COMPILER */
  1305. }
  1306.  
  1307. #if !MSDOS_COMPILER
  1308. /*
  1309.  * Return the cost of displaying a termcap string.
  1310.  * We use the trick of calling tputs, but as a char printing function
  1311.  * we give it inc_costcount, which just increments "costcount".
  1312.  * This tells us how many chars would be printed by using this string.
  1313.  * {{ Couldn't we just use strlen? }}
  1314.  */
  1315. static int costcount;
  1316.  
  1317. /*ARGSUSED*/
  1318.     static int
  1319. inc_costcount(c)
  1320.     int c;
  1321. {
  1322.     costcount++;
  1323.     return (c);
  1324. }
  1325.  
  1326.     static int
  1327. cost(t)
  1328.     char *t;
  1329. {
  1330.     costcount = 0;
  1331.     tputs(t, sc_height, inc_costcount);
  1332.     return (costcount);
  1333. }
  1334.  
  1335. /*
  1336.  * Return the "best" of the two given termcap strings.
  1337.  * The best, if both exist, is the one with the lower 
  1338.  * cost (see cost() function).
  1339.  */
  1340.     static char *
  1341. cheaper(t1, t2, def)
  1342.     char *t1, *t2;
  1343.     char *def;
  1344. {
  1345.     if (*t1 == '\0' && *t2 == '\0')
  1346.     {
  1347.         missing_cap = 1;
  1348.         return (def);
  1349.     }
  1350.     if (*t1 == '\0')
  1351.         return (t2);
  1352.     if (*t2 == '\0')
  1353.         return (t1);
  1354.     if (cost(t1) < cost(t2))
  1355.         return (t1);
  1356.     return (t2);
  1357. }
  1358.  
  1359.     static void
  1360. tmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp)
  1361.     char *incap;
  1362.     char *outcap;
  1363.     char **instr;
  1364.     char **outstr;
  1365.     char *def_instr;
  1366.     char *def_outstr;
  1367.     char **spp;
  1368. {
  1369.     *instr = ltgetstr(incap, spp);
  1370.     if (*instr == NULL)
  1371.     {
  1372.         /* Use defaults. */
  1373.         *instr = def_instr;
  1374.         *outstr = def_outstr;
  1375.         return;
  1376.     }
  1377.  
  1378.     *outstr = ltgetstr(outcap, spp);
  1379.     if (*outstr == NULL)
  1380.         /* No specific out capability; use "me". */
  1381.         *outstr = ltgetstr("me", spp);
  1382.     if (*outstr == NULL)
  1383.         /* Don't even have "me"; use a null string. */
  1384.         *outstr = "";
  1385. }
  1386.  
  1387. #endif /* MSDOS_COMPILER */
  1388.  
  1389.  
  1390. /*
  1391.  * Below are the functions which perform all the 
  1392.  * terminal-specific screen manipulation.
  1393.  */
  1394.  
  1395.  
  1396. #if MSDOS_COMPILER
  1397.  
  1398. #if MSDOS_COMPILER==WIN32C
  1399.     static void
  1400. _settextposition(int row, int col)
  1401. {
  1402.     COORD cpos;
  1403.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  1404.  
  1405.     GetConsoleScreenBufferInfo(con_out, &csbi);
  1406.     cpos.X = csbi.srWindow.Left + (col - 1);
  1407.     cpos.Y = csbi.srWindow.Top + (row - 1);
  1408.     SetConsoleCursorPosition(con_out, cpos);
  1409. }
  1410. #endif
  1411.  
  1412. /*
  1413.  * Initialize the screen to the correct color at startup.
  1414.  */
  1415.     static void
  1416. initcolor()
  1417. {
  1418.     SETCOLORS(nm_fg_color, nm_bg_color);
  1419. #if 0
  1420.     /*
  1421.      * This clears the screen at startup.  This is different from
  1422.      * the behavior of other versions of less.  Disable it for now.
  1423.      */
  1424.     char *blanks;
  1425.     int row;
  1426.     int col;
  1427.     
  1428.     /*
  1429.      * Create a complete, blank screen using "normal" colors.
  1430.      */
  1431.     SETCOLORS(nm_fg_color, nm_bg_color);
  1432.     blanks = (char *) ecalloc(width+1, sizeof(char));
  1433.     for (col = 0;  col < sc_width;  col++)
  1434.         blanks[col] = ' ';
  1435.     blanks[sc_width] = '\0';
  1436.     for (row = 0;  row < sc_height;  row++)
  1437.         _outtext(blanks);
  1438.     free(blanks);
  1439. #endif
  1440. }
  1441. #endif
  1442.  
  1443. #if MSDOS_COMPILER==WIN32C
  1444.  
  1445. /*
  1446.  * Termcap-like init with a private win32 console.
  1447.  */
  1448.     static void
  1449. win32_init_term()
  1450. {
  1451.     CONSOLE_SCREEN_BUFFER_INFO scr;
  1452.     COORD size;
  1453.  
  1454.     if (con_out_save == INVALID_HANDLE_VALUE)
  1455.         return;
  1456.  
  1457.     GetConsoleScreenBufferInfo(con_out_save, &scr);
  1458.  
  1459.     if (con_out_ours == INVALID_HANDLE_VALUE)
  1460.     {
  1461.         /*
  1462.          * Create our own screen buffer, so that we
  1463.          * may restore the original when done.
  1464.          */
  1465.         con_out_ours = CreateConsoleScreenBuffer(
  1466.             GENERIC_WRITE | GENERIC_READ,
  1467.             FILE_SHARE_WRITE | FILE_SHARE_READ,
  1468.             (LPSECURITY_ATTRIBUTES) NULL,
  1469.             CONSOLE_TEXTMODE_BUFFER,
  1470.             (LPVOID) NULL);
  1471.     }
  1472.  
  1473.     size.X = scr.srWindow.Right - scr.srWindow.Left + 1;
  1474.     size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1;
  1475.     SetConsoleScreenBufferSize(con_out_ours, size);
  1476.     SetConsoleActiveScreenBuffer(con_out_ours);
  1477.     con_out = con_out_ours;
  1478. }
  1479.  
  1480. /*
  1481.  * Restore the startup console.
  1482.  */
  1483. static void
  1484. win32_deinit_term()
  1485. {
  1486.     if (con_out_save == INVALID_HANDLE_VALUE)
  1487.         return;
  1488.     if (quitting)
  1489.         (void) CloseHandle(con_out_ours);
  1490.     SetConsoleActiveScreenBuffer(con_out_save);
  1491.     con_out = con_out_save;
  1492. }
  1493.  
  1494. #endif
  1495.  
  1496. /*
  1497.  * Initialize terminal
  1498.  */
  1499.     public void
  1500. init()
  1501. {
  1502. #if !MSDOS_COMPILER
  1503.     if (!no_init)
  1504.         tputs(sc_init, sc_height, putchr);
  1505.     if (!no_keypad)
  1506.         tputs(sc_s_keypad, sc_height, putchr);
  1507. #else
  1508. #if MSDOS_COMPILER==WIN32C
  1509.     if (!no_init)
  1510.         win32_init_term();
  1511. #endif
  1512.     initcolor();
  1513.     flush();
  1514. #endif
  1515.     init_done = 1;
  1516. }
  1517.  
  1518. /*
  1519.  * Deinitialize terminal
  1520.  */
  1521.     public void
  1522. deinit()
  1523. {
  1524.     if (!init_done)
  1525.         return;
  1526. #if !MSDOS_COMPILER
  1527.     if (!no_keypad)
  1528.         tputs(sc_e_keypad, sc_height, putchr);
  1529.     if (!no_init)
  1530.         tputs(sc_deinit, sc_height, putchr);
  1531. #else
  1532.     /* Restore system colors. */
  1533.     SETCOLORS(sy_fg_color, sy_bg_color);
  1534. #if MSDOS_COMPILER==WIN32C
  1535.     if (!no_init)
  1536.         win32_deinit_term();
  1537. #else
  1538.     /* Need clreol to make SETCOLORS take effect. */
  1539.     clreol();
  1540. #endif
  1541. #endif
  1542.     init_done = 0;
  1543. }
  1544.  
  1545. /*
  1546.  * Home cursor (move to upper left corner of screen).
  1547.  */
  1548.     public void
  1549. home()
  1550. {
  1551. #if !MSDOS_COMPILER
  1552.     tputs(sc_home, 1, putchr);
  1553. #else
  1554.     flush();
  1555.     _settextposition(1,1);
  1556. #endif
  1557. }
  1558.  
  1559. /*
  1560.  * Add a blank line (called with cursor at home).
  1561.  * Should scroll the display down.
  1562.  */
  1563.     public void
  1564. add_line()
  1565. {
  1566. #if !MSDOS_COMPILER
  1567.     tputs(sc_addline, sc_height, putchr);
  1568. #else
  1569.     flush();
  1570. #if MSDOS_COMPILER==MSOFTC
  1571.     _scrolltextwindow(_GSCROLLDOWN);
  1572.     _settextposition(1,1);
  1573. #else
  1574. #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  1575.     movetext(1,1, sc_width,sc_height-1, 1,2);
  1576.     gotoxy(1,1);
  1577.     clreol();
  1578. #else
  1579. #if MSDOS_COMPILER==WIN32C
  1580.     {
  1581.     CHAR_INFO fillchar;
  1582.     SMALL_RECT rcSrc, rcClip;
  1583.     COORD new_org;
  1584.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  1585.  
  1586.     GetConsoleScreenBufferInfo(con_out,&csbi);
  1587.  
  1588.     /* The clip rectangle is the entire visible screen. */
  1589.     rcClip.Left = csbi.srWindow.Left;
  1590.     rcClip.Top = csbi.srWindow.Top;
  1591.     rcClip.Right = csbi.srWindow.Right;
  1592.     rcClip.Bottom = csbi.srWindow.Bottom;
  1593.  
  1594.     /* The source rectangle is the visible screen minus the last line. */
  1595.     rcSrc = rcClip;
  1596.     rcSrc.Bottom--;
  1597.  
  1598.     /* Move the top left corner of the source window down one row. */
  1599.     new_org.X = rcSrc.Left;
  1600.     new_org.Y = rcSrc.Top + 1;
  1601.  
  1602.     /* Fill the right character and attributes. */
  1603.     fillchar.Char.AsciiChar = ' ';
  1604.     curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
  1605.     fillchar.Attributes = curr_attr;
  1606.     ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
  1607.     _settextposition(1,1);
  1608.     }
  1609. #endif
  1610. #endif
  1611. #endif
  1612. #endif
  1613. }
  1614.  
  1615. #if 0
  1616. /*
  1617.  * Remove the n topmost lines and scroll everything below it in the 
  1618.  * window upward.  This is needed to stop leaking the topmost line 
  1619.  * into the scrollback buffer when we go down-one-line (in WIN32).
  1620.  */
  1621.     public void
  1622. remove_top(n)
  1623.     int n;
  1624. {
  1625. #if MSDOS_COMPILER==WIN32C
  1626.     SMALL_RECT rcSrc, rcClip;
  1627.     CHAR_INFO fillchar;
  1628.     COORD new_org;
  1629.     CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
  1630.  
  1631.     if (n >= sc_height - 1)
  1632.     {
  1633.         clear();
  1634.         home();
  1635.         return;
  1636.     }
  1637.  
  1638.     flush();
  1639.  
  1640.     GetConsoleScreenBufferInfo(con_out, &csbi);
  1641.  
  1642.     /* Get the extent of all-visible-rows-but-the-last. */
  1643.     rcSrc.Left    = csbi.srWindow.Left;
  1644.     rcSrc.Top     = csbi.srWindow.Top + n;
  1645.     rcSrc.Right   = csbi.srWindow.Right;
  1646.     rcSrc.Bottom  = csbi.srWindow.Bottom;
  1647.  
  1648.     /* Get the clip rectangle. */
  1649.     rcClip.Left   = rcSrc.Left;
  1650.     rcClip.Top    = csbi.srWindow.Top;
  1651.     rcClip.Right  = rcSrc.Right;
  1652.     rcClip.Bottom = rcSrc.Bottom ;
  1653.  
  1654.     /* Move the source window up n rows. */
  1655.     new_org.X = rcSrc.Left;
  1656.     new_org.Y = rcSrc.Top - n;
  1657.  
  1658.     /* Fill the right character and attributes. */
  1659.     fillchar.Char.AsciiChar = ' ';
  1660.     curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
  1661.     fillchar.Attributes = curr_attr;
  1662.  
  1663.     ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
  1664.  
  1665.     /* Position cursor on first blank line. */
  1666.     goto_line(sc_height - n - 1);
  1667. #endif
  1668. }
  1669. #endif
  1670.  
  1671. #if MSDOS_COMPILER==WIN32C
  1672. /*
  1673.  * Clear the screen.
  1674.  */
  1675.     static void
  1676. win32_clear()
  1677. {
  1678.     /*
  1679.      * This will clear only the currently visible rows of the NT
  1680.      * console buffer, which means none of the precious scrollback
  1681.      * rows are touched making for faster scrolling.  Note that, if
  1682.      * the window has fewer columns than the console buffer (i.e.
  1683.      * there is a horizontal scrollbar as well), the entire width
  1684.      * of the visible rows will be cleared.
  1685.      */
  1686.     COORD topleft;
  1687.     DWORD nchars;
  1688.     DWORD winsz;
  1689.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  1690.  
  1691.     /* get the number of cells in the current buffer */
  1692.     GetConsoleScreenBufferInfo(con_out, &csbi);
  1693.     winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
  1694.     topleft.X = 0;
  1695.     topleft.Y = csbi.srWindow.Top;
  1696.  
  1697.     curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
  1698.     FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars);
  1699.     FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars);
  1700. }
  1701.  
  1702. /*
  1703.  * Remove the n topmost lines and scroll everything below it in the 
  1704.  * window upward.
  1705.  */
  1706.     public void
  1707. win32_scroll_up(n)
  1708.     int n;
  1709. {
  1710.     SMALL_RECT rcSrc, rcClip;
  1711.     CHAR_INFO fillchar;
  1712.     COORD topleft;
  1713.     COORD new_org;
  1714.     DWORD nchars;
  1715.     DWORD size;
  1716.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  1717.  
  1718.     if (n <= 0)
  1719.         return;
  1720.  
  1721.     if (n >= sc_height - 1)
  1722.     {
  1723.         win32_clear();
  1724.         _settextposition(1,1);
  1725.         return;
  1726.     }
  1727.  
  1728.     /* Get the extent of what will remain visible after scrolling. */
  1729.     GetConsoleScreenBufferInfo(con_out, &csbi);
  1730.     rcSrc.Left    = csbi.srWindow.Left;
  1731.     rcSrc.Top     = csbi.srWindow.Top + n;
  1732.     rcSrc.Right   = csbi.srWindow.Right;
  1733.     rcSrc.Bottom  = csbi.srWindow.Bottom;
  1734.  
  1735.     /* Get the clip rectangle. */
  1736.     rcClip.Left   = rcSrc.Left;
  1737.     rcClip.Top    = csbi.srWindow.Top;
  1738.     rcClip.Right  = rcSrc.Right;
  1739.     rcClip.Bottom = rcSrc.Bottom ;
  1740.  
  1741.     /* Move the source text to the top of the screen. */
  1742.     new_org.X = rcSrc.Left;
  1743.     new_org.Y = 0;
  1744.  
  1745.     /* Fill the right character and attributes. */
  1746.     fillchar.Char.AsciiChar = ' ';
  1747.     fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color);
  1748.  
  1749.     /* Scroll the window. */
  1750.     SetConsoleTextAttribute(con_out, fillchar.Attributes);
  1751.     ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
  1752.  
  1753.     /* Clear remaining lines at bottom. */
  1754.     topleft.X = csbi.dwCursorPosition.X;
  1755.     topleft.Y = rcSrc.Bottom - n;
  1756.     size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X);
  1757.     FillConsoleOutputCharacter(con_out, ' ', size, topleft,
  1758.         &nchars);
  1759.     FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft,
  1760.         &nchars);
  1761.     SetConsoleTextAttribute(con_out, curr_attr);
  1762.  
  1763.     /* Move cursor n lines up from where it was. */
  1764.     csbi.dwCursorPosition.Y -= n;
  1765.     SetConsoleCursorPosition(con_out, csbi.dwCursorPosition);
  1766. }
  1767. #endif
  1768.  
  1769. /*
  1770.  * Move cursor to lower left corner of screen.
  1771.  */
  1772.     public void
  1773. lower_left()
  1774. {
  1775. #if !MSDOS_COMPILER
  1776.     tputs(sc_lower_left, 1, putchr);
  1777. #else
  1778.     flush();
  1779.     _settextposition(sc_height, 1);
  1780. #endif
  1781. }
  1782.  
  1783. /*
  1784.  * Check if the console size has changed and reset internals 
  1785.  * (in lieu of SIGWINCH for WIN32).
  1786.  */
  1787.     public void
  1788. check_winch()
  1789. {
  1790. #if MSDOS_COMPILER==WIN32C
  1791.     CONSOLE_SCREEN_BUFFER_INFO scr;
  1792.     COORD size;
  1793.  
  1794.     if (con_out == INVALID_HANDLE_VALUE)
  1795.         return;
  1796.  
  1797.     flush();
  1798.     GetConsoleScreenBufferInfo(con_out, &scr);
  1799.     size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1;
  1800.     size.X = scr.srWindow.Right - scr.srWindow.Left + 1;
  1801.     if (size.Y != sc_height || size.X != sc_width)
  1802.     {
  1803.         sc_height = size.Y;
  1804.         sc_width = size.X;
  1805.         if (!no_init && con_out_ours == con_out)
  1806.             SetConsoleScreenBufferSize(con_out, size);
  1807.         pos_init();
  1808.         wscroll = (sc_height + 1) / 2;
  1809.         screen_trashed = 1;
  1810.     }
  1811. #endif
  1812. }
  1813.  
  1814. /*
  1815.  * Goto a specific line on the screen.
  1816.  */
  1817.     public void
  1818. goto_line(slinenum)
  1819.     int slinenum;
  1820. {
  1821. #if !MSDOS_COMPILER
  1822.     tputs(tgoto(sc_move, 0, slinenum), 1, putchr);
  1823. #else
  1824.     flush();
  1825.     _settextposition(slinenum+1, 1);
  1826. #endif
  1827. }
  1828.  
  1829. #if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC
  1830. /*
  1831.  * Create an alternate screen which is all white.
  1832.  * This screen is used to create a "flash" effect, by displaying it
  1833.  * briefly and then switching back to the normal screen.
  1834.  * {{ Yuck!  There must be a better way to get a visual bell. }}
  1835.  */
  1836.     static void
  1837. create_flash()
  1838. {
  1839. #if MSDOS_COMPILER==MSOFTC
  1840.     struct videoconfig w;
  1841.     char *blanks;
  1842.     int row, col;
  1843.     
  1844.     _getvideoconfig(&w);
  1845.     videopages = w.numvideopages;
  1846.     if (videopages < 2)
  1847.     {
  1848.         so_enter();
  1849.         so_exit();
  1850.     } else
  1851.     {
  1852.         _setactivepage(1);
  1853.         so_enter();
  1854.         blanks = (char *) ecalloc(w.numtextcols, sizeof(char));
  1855.         for (col = 0;  col < w.numtextcols;  col++)
  1856.             blanks[col] = ' ';
  1857.         for (row = w.numtextrows;  row > 0;  row--)
  1858.             _outmem(blanks, w.numtextcols);
  1859.         _setactivepage(0);
  1860.         _setvisualpage(0);
  1861.         free(blanks);
  1862.         so_exit();
  1863.     }
  1864. #else
  1865. #if MSDOS_COMPILER==BORLANDC
  1866.     register int n;
  1867.  
  1868.     whitescreen = (unsigned short *) 
  1869.         malloc(sc_width * sc_height * sizeof(short));
  1870.     if (whitescreen == NULL)
  1871.         return;
  1872.     for (n = 0;  n < sc_width * sc_height;  n++)
  1873.         whitescreen[n] = 0x7020;
  1874. #else
  1875. #if MSDOS_COMPILER==WIN32C
  1876.     register int n;
  1877.  
  1878.     whitescreen = (WORD *)
  1879.         malloc(sc_height * sc_width * sizeof(WORD));
  1880.     if (whitescreen == NULL)
  1881.         return;
  1882.     /* Invert the standard colors. */
  1883.     for (n = 0;  n < sc_width * sc_height;  n++)
  1884.         whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color);
  1885. #endif
  1886. #endif
  1887. #endif
  1888.     flash_created = 1;
  1889. }
  1890. #endif /* MSDOS_COMPILER */
  1891.  
  1892. /*
  1893.  * Output the "visual bell", if there is one.
  1894.  */
  1895.     public void
  1896. vbell()
  1897. {
  1898. #if !MSDOS_COMPILER
  1899.     if (*sc_visual_bell == '\0')
  1900.         return;
  1901.     tputs(sc_visual_bell, sc_height, putchr);
  1902. #else
  1903. #if MSDOS_COMPILER==DJGPPC
  1904.     ScreenVisualBell();
  1905. #else
  1906. #if MSDOS_COMPILER==MSOFTC
  1907.     /*
  1908.      * Create a flash screen on the second video page.
  1909.      * Switch to that page, then switch back.
  1910.      */
  1911.     if (!flash_created)
  1912.         create_flash();
  1913.     if (videopages < 2)
  1914.         return;
  1915.     _setvisualpage(1);
  1916.     delay(100);
  1917.     _setvisualpage(0);
  1918. #else
  1919. #if MSDOS_COMPILER==BORLANDC
  1920.     unsigned short *currscreen;
  1921.  
  1922.     /*
  1923.      * Get a copy of the current screen.
  1924.      * Display the flash screen.
  1925.      * Then restore the old screen.
  1926.      */
  1927.     if (!flash_created)
  1928.         create_flash();
  1929.     if (whitescreen == NULL)
  1930.         return;
  1931.     currscreen = (unsigned short *) 
  1932.         malloc(sc_width * sc_height * sizeof(short));
  1933.     if (currscreen == NULL) return;
  1934.     gettext(1, 1, sc_width, sc_height, currscreen);
  1935.     puttext(1, 1, sc_width, sc_height, whitescreen);
  1936.     delay(100);
  1937.     puttext(1, 1, sc_width, sc_height, currscreen);
  1938.     free(currscreen);
  1939. #else
  1940. #if MSDOS_COMPILER==WIN32C
  1941.     /* paint screen with an inverse color */
  1942.     clear();
  1943.  
  1944.     /* leave it displayed for 100 msec. */
  1945.     Sleep(100);
  1946.  
  1947.     /* restore with a redraw */
  1948.     repaint();
  1949. #endif
  1950. #endif
  1951. #endif
  1952. #endif
  1953. #endif
  1954. }
  1955.  
  1956. /*
  1957.  * Make a noise.
  1958.  */
  1959.     static void
  1960. beep()
  1961. {
  1962. #if !MSDOS_COMPILER
  1963.     putchr(CONTROL('G'));
  1964. #else
  1965. #if MSDOS_COMPILER==WIN32C
  1966.     MessageBeep(0);
  1967. #else
  1968.     write(1, "\7", 1);
  1969. #endif
  1970. #endif
  1971. }
  1972.  
  1973. /*
  1974.  * Ring the terminal bell.
  1975.  */
  1976.     public void
  1977. bell()
  1978. {
  1979.     if (quiet == VERY_QUIET)
  1980.         vbell();
  1981.     else
  1982.         beep();
  1983. }
  1984.  
  1985. /*
  1986.  * Clear the screen.
  1987.  */
  1988.     public void
  1989. clear()
  1990. {
  1991. #if !MSDOS_COMPILER
  1992.     tputs(sc_clear, sc_height, putchr);
  1993. #else
  1994.     flush();
  1995. #if MSDOS_COMPILER==WIN32C
  1996.     win32_clear();
  1997. #else
  1998.     _clearscreen(_GCLEARSCREEN);
  1999. #endif
  2000. #endif
  2001. }
  2002.  
  2003. /*
  2004.  * Clear from the cursor to the end of the cursor's line.
  2005.  * {{ This must not move the cursor. }}
  2006.  */
  2007.     public void
  2008. clear_eol()
  2009. {
  2010. #if !MSDOS_COMPILER
  2011.     tputs(sc_eol_clear, 1, putchr);
  2012. #else
  2013. #if MSDOS_COMPILER==MSOFTC
  2014.     short top, left;
  2015.     short bot, right;
  2016.     struct rccoord tpos;
  2017.     
  2018.     flush();
  2019.     /*
  2020.      * Save current state.
  2021.      */
  2022.     tpos = _gettextposition();
  2023.     _gettextwindow(&top, &left, &bot, &right);
  2024.     /*
  2025.      * Set a temporary window to the current line,
  2026.      * from the cursor's position to the right edge of the screen.
  2027.      * Then clear that window.
  2028.      */
  2029.     _settextwindow(tpos.row, tpos.col, tpos.row, sc_width);
  2030.     _clearscreen(_GWINDOW);
  2031.     /*
  2032.      * Restore state.
  2033.      */
  2034.     _settextwindow(top, left, bot, right);
  2035.     _settextposition(tpos.row, tpos.col);
  2036. #else
  2037. #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  2038.     flush();
  2039.     clreol();
  2040. #else
  2041. #if MSDOS_COMPILER==WIN32C
  2042.     DWORD           nchars;
  2043.     COORD           cpos;
  2044.     CONSOLE_SCREEN_BUFFER_INFO scr;
  2045.  
  2046.     flush();
  2047.     memset(&scr, 0, sizeof(scr));
  2048.     GetConsoleScreenBufferInfo(con_out, &scr);
  2049.     cpos.X = scr.dwCursorPosition.X;
  2050.     cpos.Y = scr.dwCursorPosition.Y;
  2051.     curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
  2052.     FillConsoleOutputAttribute(con_out, curr_attr,
  2053.         scr.dwSize.X - cpos.X, cpos, &nchars);
  2054.     FillConsoleOutputCharacter(con_out, ' ',
  2055.         scr.dwSize.X - cpos.X, cpos, &nchars);
  2056. #endif
  2057. #endif
  2058. #endif
  2059. #endif
  2060. }
  2061.  
  2062. /*
  2063.  * Clear the current line.
  2064.  * Clear the screen if there's off-screen memory below the display.
  2065.  */
  2066.     static void
  2067. clear_eol_bot()
  2068. {
  2069. #if MSDOS_COMPILER
  2070.     clear_eol();
  2071. #else
  2072.     if (below_mem)
  2073.         tputs(sc_eos_clear, 1, putchr);
  2074.     else
  2075.         tputs(sc_eol_clear, 1, putchr);
  2076. #endif
  2077. }
  2078.  
  2079. /*
  2080.  * Clear the bottom line of the display.
  2081.  * Leave the cursor at the beginning of the bottom line.
  2082.  */
  2083.     public void
  2084. clear_bot()
  2085. {
  2086.     /*
  2087.      * If we're in a non-normal attribute mode, temporarily exit
  2088.      * the mode while we do the clear.  Some terminals fill the
  2089.      * cleared area with the current attribute.
  2090.      */
  2091.     lower_left();
  2092.     switch (attrmode)
  2093.     {
  2094.     case AT_STANDOUT:
  2095.         so_exit();
  2096.         clear_eol_bot();
  2097.         so_enter();
  2098.         break;
  2099.     case AT_UNDERLINE:
  2100.         ul_exit();
  2101.         clear_eol_bot();
  2102.         ul_enter();
  2103.         break;
  2104.     case AT_BOLD:
  2105.         bo_exit();
  2106.         clear_eol_bot();
  2107.         bo_enter();
  2108.         break;
  2109.     case AT_BLINK:
  2110.         bl_exit();
  2111.         clear_eol_bot();
  2112.         bl_enter();
  2113.         break;
  2114.     default:
  2115.         clear_eol_bot();
  2116.         break;
  2117.     }
  2118. }
  2119.  
  2120. /*
  2121.  * Begin "standout" (bold, underline, or whatever).
  2122.  */
  2123.     public void
  2124. so_enter()
  2125. {
  2126. #if !MSDOS_COMPILER
  2127.     tputs(sc_s_in, 1, putchr);
  2128. #else
  2129.     flush();
  2130.     SETCOLORS(so_fg_color, so_bg_color);
  2131. #endif
  2132.     attrmode = AT_STANDOUT;
  2133. }
  2134.  
  2135. /*
  2136.  * End "standout".
  2137.  */
  2138.     public void
  2139. so_exit()
  2140. {
  2141. #if !MSDOS_COMPILER
  2142.     tputs(sc_s_out, 1, putchr);
  2143. #else
  2144.     flush();
  2145.     SETCOLORS(nm_fg_color, nm_bg_color);
  2146. #endif
  2147.     attrmode = AT_NORMAL;
  2148. }
  2149.  
  2150. /*
  2151.  * Begin "underline" (hopefully real underlining, 
  2152.  * otherwise whatever the terminal provides).
  2153.  */
  2154.     public void
  2155. ul_enter()
  2156. {
  2157. #if !MSDOS_COMPILER
  2158.     tputs(sc_u_in, 1, putchr);
  2159. #else
  2160.     flush();
  2161.     SETCOLORS(ul_fg_color, ul_bg_color);
  2162. #endif
  2163.     attrmode = AT_UNDERLINE;
  2164. }
  2165.  
  2166. /*
  2167.  * End "underline".
  2168.  */
  2169.     public void
  2170. ul_exit()
  2171. {
  2172. #if !MSDOS_COMPILER
  2173.     tputs(sc_u_out, 1, putchr);
  2174. #else
  2175.     flush();
  2176.     SETCOLORS(nm_fg_color, nm_bg_color);
  2177. #endif
  2178.     attrmode = AT_NORMAL;
  2179. }
  2180.  
  2181. /*
  2182.  * Begin "bold"
  2183.  */
  2184.     public void
  2185. bo_enter()
  2186. {
  2187. #if !MSDOS_COMPILER
  2188.     tputs(sc_b_in, 1, putchr);
  2189. #else
  2190.     flush();
  2191.     SETCOLORS(bo_fg_color, bo_bg_color);
  2192. #endif
  2193.     attrmode = AT_BOLD;
  2194. }
  2195.  
  2196. /*
  2197.  * End "bold".
  2198.  */
  2199.     public void
  2200. bo_exit()
  2201. {
  2202. #if !MSDOS_COMPILER
  2203.     tputs(sc_b_out, 1, putchr);
  2204. #else
  2205.     flush();
  2206.     SETCOLORS(nm_fg_color, nm_bg_color);
  2207. #endif
  2208.     attrmode = AT_NORMAL;
  2209. }
  2210.  
  2211. /*
  2212.  * Begin "blink"
  2213.  */
  2214.     public void
  2215. bl_enter()
  2216. {
  2217. #if !MSDOS_COMPILER
  2218.     tputs(sc_bl_in, 1, putchr);
  2219. #else
  2220.     flush();
  2221.     SETCOLORS(bl_fg_color, bl_bg_color);
  2222. #endif
  2223.     attrmode = AT_BLINK;
  2224. }
  2225.  
  2226. /*
  2227.  * End "blink".
  2228.  */
  2229.     public void
  2230. bl_exit()
  2231. {
  2232. #if !MSDOS_COMPILER
  2233.     tputs(sc_bl_out, 1, putchr);
  2234. #else
  2235.     flush();
  2236.     SETCOLORS(nm_fg_color, nm_bg_color);
  2237. #endif
  2238.     attrmode = AT_NORMAL;
  2239. }
  2240.  
  2241. #if 0 /* No longer used */
  2242. /*
  2243.  * Erase the character to the left of the cursor 
  2244.  * and move the cursor left.
  2245.  */
  2246.     public void
  2247. backspace()
  2248. {
  2249. #if !MSDOS_COMPILER
  2250.     /* 
  2251.      * Erase the previous character by overstriking with a space.
  2252.      */
  2253.     tputs(sc_backspace, 1, putchr);
  2254.     putchr(' ');
  2255.     tputs(sc_backspace, 1, putchr);
  2256. #else
  2257. #if MSDOS_COMPILER==MSOFTC
  2258.     struct rccoord tpos;
  2259.     
  2260.     flush();
  2261.     tpos = _gettextposition();
  2262.     if (tpos.col <= 1)
  2263.         return;
  2264.     _settextposition(tpos.row, tpos.col-1);
  2265.     _outtext(" ");
  2266.     _settextposition(tpos.row, tpos.col-1);
  2267. #else
  2268. #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  2269.     cputs("\b");
  2270. #else
  2271. #if MSDOS_COMPILER==WIN32C
  2272.     COORD cpos;
  2273.     DWORD cChars;
  2274.     CONSOLE_SCREEN_BUFFER_INFO scr;
  2275.  
  2276.     flush();
  2277.     GetConsoleScreenBufferInfo(con_out, &scr);
  2278.     cpos = scr.dwCursorPosition;
  2279.     if (cpos.X <= 0)
  2280.         return;
  2281.     cpos.X--;
  2282.     SetConsoleCursorPosition(con_out, cpos);
  2283.     FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars);
  2284.     SetConsoleCursorPosition(con_out, cpos);
  2285. #endif
  2286. #endif
  2287. #endif
  2288. #endif
  2289. }
  2290. #endif /* 0 */
  2291.  
  2292. /*
  2293.  * Output a plain backspace, without erasing the previous char.
  2294.  */
  2295.     public void
  2296. putbs()
  2297. {
  2298. #if !MSDOS_COMPILER
  2299.     tputs(sc_backspace, 1, putchr);
  2300. #else
  2301.     int row, col;
  2302.  
  2303.     flush();
  2304.     {
  2305. #if MSDOS_COMPILER==MSOFTC
  2306.         struct rccoord tpos;
  2307.         tpos = _gettextposition();
  2308.         row = tpos.row;
  2309.         col = tpos.col;
  2310. #else
  2311. #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
  2312.         row = wherey();
  2313.         col = wherex();
  2314. #else
  2315. #if MSDOS_COMPILER==WIN32C
  2316.         CONSOLE_SCREEN_BUFFER_INFO scr;
  2317.         GetConsoleScreenBufferInfo(con_out, &scr);
  2318.         row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1;
  2319.         col = scr.dwCursorPosition.X - scr.srWindow.Left + 1;
  2320. #endif
  2321. #endif
  2322. #endif
  2323.     }
  2324.     if (col <= 1)
  2325.         return;
  2326.     _settextposition(row, col-1);
  2327. #endif /* MSDOS_COMPILER */
  2328. }
  2329.  
  2330. #if MSDOS_COMPILER==WIN32C
  2331. /*
  2332.  * Determine whether an input character is waiting to be read.
  2333.  */
  2334.     static int
  2335. win32_kbhit(tty)
  2336.     HANDLE tty;
  2337. {
  2338.     INPUT_RECORD ip;
  2339.     DWORD read;
  2340.  
  2341.     if (keyCount > 0)
  2342.         return (TRUE);
  2343.  
  2344.     currentKey.ascii = 0;
  2345.     currentKey.scan = 0;
  2346.  
  2347.     /*
  2348.      * Wait for a real key-down event, but
  2349.      * ignore SHIFT and CONTROL key events.
  2350.      */
  2351.     do
  2352.     {
  2353.         PeekConsoleInput(tty, &ip, 1, &read);
  2354.         if (read == 0)
  2355.             return (FALSE);
  2356.         ReadConsoleInput(tty, &ip, 1, &read);
  2357.     } while (ip.EventType != KEY_EVENT ||
  2358.         ip.Event.KeyEvent.bKeyDown != TRUE ||
  2359.         ip.Event.KeyEvent.wVirtualScanCode == 0 ||
  2360.         ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
  2361.         ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL ||
  2362.         ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU);
  2363.         
  2364.     currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar;
  2365.     currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode;
  2366.     keyCount = ip.Event.KeyEvent.wRepeatCount;
  2367.  
  2368.     if (ip.Event.KeyEvent.dwControlKeyState & 
  2369.         (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
  2370.     {
  2371.         switch (currentKey.scan)
  2372.         {
  2373.         case PCK_ALT_E:     /* letter 'E' */
  2374.             currentKey.ascii = 0;
  2375.             break;
  2376.         }
  2377.     } else if (ip.Event.KeyEvent.dwControlKeyState & 
  2378.         (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
  2379.     {
  2380.         switch (currentKey.scan)
  2381.         {
  2382.         case PCK_RIGHT: /* right arrow */
  2383.             currentKey.scan = PCK_CTL_RIGHT;
  2384.             break;
  2385.         case PCK_LEFT: /* left arrow */
  2386.             currentKey.scan = PCK_CTL_LEFT;
  2387.             break;
  2388.         case PCK_DELETE: /* delete */
  2389.             currentKey.scan = PCK_CTL_DELETE;
  2390.             break;
  2391.         }
  2392.     }
  2393.     return (TRUE);
  2394. }
  2395.  
  2396. /*
  2397.  * Read a character from the keyboard.
  2398.  */
  2399.     public char
  2400. WIN32getch(tty)
  2401.     int tty;
  2402. {
  2403.     int ascii;
  2404.  
  2405.     if (pending_scancode)
  2406.     {
  2407.         pending_scancode = 0;
  2408.         return ((char)(currentKey.scan & 0x00FF));
  2409.     }
  2410.  
  2411.     while (win32_kbhit((HANDLE)tty) == FALSE)
  2412.     {
  2413.         Sleep(20);
  2414.         if (ABORT_SIGS())
  2415.             return ('\003');
  2416.         continue;
  2417.     }
  2418.     keyCount --;
  2419.     ascii = currentKey.ascii;
  2420.     /*
  2421.      * On PC's, the extended keys return a 2 byte sequence beginning 
  2422.      * with '00', so if the ascii code is 00, the next byte will be 
  2423.      * the lsb of the scan code.
  2424.      */
  2425.     pending_scancode = (ascii == 0x00);
  2426.     return ((char)ascii);
  2427. }
  2428. #endif
  2429.