home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / less_332.lzh / less_332 / screen.c < prev    next >
Text File  |  1998-03-03  |  46KB  |  2,299 lines

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