home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / git-4.3 / git-4 / git-4.3.11 / src / tty.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-02  |  46.9 KB  |  2,058 lines

  1. /* tty.c -- The tty management file.  */
  2.  
  3. /* Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /* Written by Tudor Hulubei and Andrei Pitis.  */
  20.  
  21.  
  22. #ifdef HAVE_CONFIG_H
  23. #include <config.h>
  24. #endif
  25.  
  26. #include <stdio.h>
  27.  
  28. #ifdef HAVE_STDLIB_H
  29. #include <stdlib.h>
  30. #else /* !HAVE_STDLIB_H */
  31. #include "ansi_stdlib.h"
  32. #endif /* !HAVE_STDLIB_H */
  33.  
  34. #include <sys/types.h>
  35. #include <ctype.h>
  36. #include "file.h"
  37. #include <sys/ioctl.h>
  38.  
  39. #ifdef HAVE_UNISTD_H
  40. #include <unistd.h>
  41. #endif /* HAVE_UNISTD_H */
  42.  
  43. #include "stdc.h"
  44. #include "xstring.h"
  45. #include "xmalloc.h"
  46. #include "xio.h"
  47. #include "tty.h"
  48. #include "misc.h"
  49.  
  50.  
  51. /* Stolen from GNU Emacs.  */
  52. #ifdef _POSIX_VDISABLE
  53. #define CDISABLE _POSIX_VDISABLE
  54. #else /* not _POSIX_VDISABLE */
  55. #ifdef CDEL
  56. #undef CDISABLE
  57. #define CDISABLE CDEL
  58. #else /* not CDEL */
  59. #define CDISABLE 255
  60. #endif /* not CDEL */
  61. #endif /* not _POSIX_VDISABLE */
  62.  
  63. #define MAX_TTY_COLUMNS         512
  64. #define MIN_TTY_COLUMNS         80
  65. #define MAX_TTY_LINES           512
  66. #define MIN_TTY_LINES           8
  67.  
  68.  
  69. /* I want to avoid including curses.h or any other header file that
  70.    defines these.  I think it's safer because I couldn't find 2
  71.    similar curses.h files in the entire world...  */
  72.  
  73. int tputs     PROTO ((const char *__string, int __nlines, int (*outfun)()));
  74. int tgetent   PROTO ((void *__buffer, const char *__termtype));
  75. char *tgetstr PROTO ((const char *__name, char **__area));
  76. int tgetnum   PROTO ((const char *__name));
  77. int tgetflag  PROTO ((const char *__name));
  78. char *tgoto   PROTO ((const char *__cstring, int __hpos, int __vpos));
  79.  
  80.  
  81. #define TTY_INPUT       0
  82. #define TTY_OUTPUT      1
  83.  
  84. #ifdef HAVE_LINUX
  85. #define VCS_READ    1
  86. #define VCS_WRITE    2
  87. #endif
  88.  
  89. #ifdef HAVE_LINUX
  90. static int vcs_read_ok;
  91. static int vcs_is_bw;
  92. #endif
  93.  
  94. /* If tty_kbdmode == 1, single characters are inserted in the linked list.
  95.    This feature is used by gitps (it has no command line).  */
  96. static int tty_kbdmode;
  97.  
  98. #ifdef HAVE_POSIX_TTY
  99. static struct termios old_term;
  100. static struct termios new_term;
  101. #else
  102. #ifdef HAVE_SYSTEMV_TTY
  103. static struct termio old_term;
  104. static struct termio new_term;
  105. #else
  106. static struct sgttyb  old_arg;
  107. static struct tchars  old_targ;
  108. static struct ltchars old_ltarg;
  109. static struct sgttyb  new_arg;
  110. static struct tchars  new_targ;
  111. static struct ltchars new_ltarg;
  112.  
  113. /* NextStep doesn't define TILDE.  */
  114. #ifndef TILDE
  115. #define TILDE 0
  116. #endif
  117.  
  118. #endif /* HAVE_SYSTEMV_TTY */
  119. #endif /* HAVE_POSIX_TTY */
  120.  
  121. static int lines, columns;
  122.  
  123. static tty_last_char_flag;
  124.  
  125. static int tty_cursor_x;
  126. static int tty_cursor_y;
  127.  
  128. /*
  129.  * tty_*_current_attribute:    bit 7:        reverse video
  130.  *                bit 6:        brightness
  131.  *                bits 5,4,3:    background color
  132.  *                bits 2,1,0:    foreground color
  133.  */
  134. static unsigned char tty_current_attribute;
  135. static unsigned char tty_io_current_attribute;
  136.  
  137. #define INVALID_CACHE 0
  138. #define VALID_CACHE   1
  139.  
  140. static int fg_cache = INVALID_CACHE;
  141. static int bg_cache = INVALID_CACHE;
  142. static int br_cache = INVALID_CACHE;
  143. static int rv_cache = INVALID_CACHE;
  144.  
  145. /* tty_scr the current status of the screen, while tty_atr is used to
  146.    keep the current status of the attributes.  */
  147. static unsigned char *tty_scr = NULL;
  148. static unsigned char *tty_atr = NULL;
  149.  
  150. /* tty_prev_scr will always contain the copy of the previous screen,
  151.    while tty_atr will contain the copy of the previous attributes.  */
  152. static unsigned char *tty_prev_scr = NULL;
  153. static unsigned char *tty_prev_atr = NULL;
  154.  
  155.  
  156. /* The ANSI color sequences.  */
  157. static char ansi_foreground[] = { 0x1b, '[', '3', '0', 'm' };
  158. static char ansi_background[] = { 0x1b, '[', '4', '0', 'm' };
  159. static char ansi_defaults[]   = { 0x1b, '[', '0', 'm' };
  160.  
  161. /* These variable tells us if we should use standard ANSI color sequences.
  162.    Its value is taken from the configuration file.  */
  163. extern int AnsiColors;
  164.  
  165. #define FOREGROUND_MASK 0x07
  166. #define BACKGROUND_MASK 0x38
  167. #define BRIGHTNESS_MASK 0x40
  168. #define REVERSEVID_MASK 0x80
  169.  
  170.  
  171. #define _TTY_FOREGROUND(attributes) (((attributes) & FOREGROUND_MASK) >> 0)
  172. #define _TTY_BACKGROUND(attributes) (((attributes) & BACKGROUND_MASK) >> 3)
  173. #define _TTY_BRIGHTNESS(attributes) (((attributes) & BRIGHTNESS_MASK) >> 6)
  174. #define _TTY_REVERSEVID(attributes) (((attributes) & REVERSEVID_MASK) >> 7)
  175.  
  176. #define TTY_IO_FOREGROUND _TTY_FOREGROUND(tty_io_current_attribute)
  177. #define TTY_IO_BACKGROUND _TTY_BACKGROUND(tty_io_current_attribute)
  178. #define TTY_IO_BRIGHTNESS _TTY_BRIGHTNESS(tty_io_current_attribute)
  179. #define TTY_IO_REVERSEVID _TTY_REVERSEVID(tty_io_current_attribute)
  180.  
  181. #define TTY_FOREGROUND _TTY_FOREGROUND(tty_current_attribute)
  182. #define TTY_BACKGROUND _TTY_BACKGROUND(tty_current_attribute)
  183. #define TTY_BRIGHTNESS _TTY_BRIGHTNESS(tty_current_attribute)
  184. #define TTY_REVERSEVID _TTY_REVERSEVID(tty_current_attribute)
  185.  
  186. #define _TTY_SET_FOREGROUND(attributes, color)\
  187.     ((attributes) = ((attributes) & ~FOREGROUND_MASK) | (((color) & 7) << 0))
  188. #define _TTY_SET_BACKGROUND(attributes, color)\
  189.     ((attributes) = ((attributes) & ~BACKGROUND_MASK) | (((color) & 7) << 3))
  190. #define _TTY_SET_BRIGHTNESS(attributes, status)\
  191.     ((attributes) = ((attributes) & ~BRIGHTNESS_MASK) | (((status) & 1) << 6))
  192. #define _TTY_SET_REVERSEVID(attributes, status)\
  193.     ((attributes) = ((attributes) & ~REVERSEVID_MASK) | (((status) & 1) << 7))
  194.  
  195. #define TTY_IO_SET_FOREGROUND(color)\
  196.     _TTY_SET_FOREGROUND(tty_io_current_attribute, (color))
  197. #define TTY_IO_SET_BACKGROUND(color)\
  198.     _TTY_SET_BACKGROUND(tty_io_current_attribute, (color))
  199. #define TTY_IO_SET_BRIGHTNESS(status)\
  200.     _TTY_SET_BRIGHTNESS(tty_io_current_attribute, (status))
  201. #define TTY_IO_SET_REVERSEVID(status)\
  202.     _TTY_SET_REVERSEVID(tty_io_current_attribute, (status))
  203.  
  204. #define TTY_SET_FOREGROUND(color)\
  205.     _TTY_SET_FOREGROUND(tty_current_attribute, (color))
  206. #define TTY_SET_BACKGROUND(color)\
  207.     _TTY_SET_BACKGROUND(tty_current_attribute, (color))
  208. #define TTY_SET_BRIGHTNESS(status)\
  209.     _TTY_SET_BRIGHTNESS(tty_current_attribute, (status))
  210. #define TTY_SET_REVERSEVID(status)\
  211.     _TTY_SET_REVERSEVID(tty_current_attribute, (status))
  212.  
  213.  
  214. #ifdef HAVE_LINUX
  215. /* These variable tells us if we are using a Linux console.  */
  216. int LinuxConsole;
  217. #endif /* HAVE_LINUX */
  218.  
  219.  
  220. /* Structures for keys management.  */
  221. tty_key_t *key_list_head = NULL;
  222. tty_key_t *current_key;
  223. tty_key_t default_key;
  224.  
  225. /* 10 Kb of cache memory for terminal optimizations.  */
  226. #define TTY_CACHE_SIZE 10240
  227.  
  228. static char tty_cache[TTY_CACHE_SIZE];
  229. static unsigned int tty_index;
  230.  
  231. static char term_buf[2048];
  232. static char vt100[] = "vt100";
  233.  
  234. /* The terminal mode. TTY_CANONIC at the begining.  */
  235. int tty_mode = TTY_CANONIC;
  236.  
  237. char *tty_type;
  238.  
  239. char PC;        /* For tputs.  */
  240. char *BC;       /* For tgoto/tparm.  */
  241. char *UP;
  242.  
  243. #ifdef HAVE_LINUX
  244. speed_t ospeed;
  245. #else   /* !HAVE_LINUX */
  246. short ospeed;
  247. #endif  /* !HAVE_LINUX */
  248.  
  249.  
  250. /* A structure describing some attributes we need to know about each
  251.    capability. See below for greater detail.  */
  252. typedef struct
  253. {
  254.     char *name;        /* the capability name.  */
  255.  
  256.     /* These ones should be in an union, but the HP-UX non ANSI compiler
  257.        complains about union initialization being an ANSI feature and I
  258.        care more for portability than for the memory used.  */
  259.     char *string;    /* The string  value of the capability.  */
  260.     int  integer;    /* The integer value of the capability.  */
  261.  
  262.     int required;    /* This capability is required.  */
  263.     char *symbol;    /* The human readable form of the key name.  */
  264. } TTY_CAPABILITY;
  265.  
  266.  
  267. #define TTY_USED_CAPABILITIES   34
  268. #define TTY_FIRST_SYMBOL_KEY    13
  269.  
  270. static TTY_CAPABILITY tty_capability[TTY_USED_CAPABILITIES] =
  271. {
  272.     { "me", NULL, 0, 0, NULL },        /* turn off all attributes */
  273.     { "mr", NULL, 0, 0, NULL },        /* turn on reverse video mode */
  274.     { "md", NULL, 0, 0, NULL },        /* turn on bold */
  275.     { "vi", NULL, 0, 0, NULL },        /* make the cursor invisible */
  276.     { "ve", NULL, 0, 0, NULL },        /* make the cursor appear normal */
  277.     { "cl", NULL, 0, 1, NULL },        /* clear screen & home the cursor */
  278.     { "cm", NULL, 0, 1, NULL },        /* move the cursor */
  279.     { "pc", NULL, 0, 0, NULL },        /* padding character */
  280.     { "up", NULL, 0, 0, NULL },        /* up one line */
  281.     { "le", NULL, 0, 0, NULL },        /* move left one space */
  282.     { "so", NULL, 0, 0, NULL },        /* enter standout mode.  */
  283.     { "sg", NULL, 0, 0, NULL },        /* this is a magic-cookie terminal.  */
  284.     { "ms", NULL, 0, 0, NULL },        /* safe to move in standout mode.  */
  285.     { "ku", NULL, 0, 0, "UP" },        /* (UP) */
  286.     { "kd", NULL, 0, 0, "DOWN" },    /* (DOWN) */
  287.     { "kr", NULL, 0, 0, "RIGHT" },    /* (RIGHT) */
  288.     { "kl", NULL, 0, 0, "LEFT" },    /* (LEFT) */
  289.     { "kI", NULL, 0, 0, "INS" },    /* (INS) */
  290.     { "kD", NULL, 0, 0, "DEL" },    /* (DEL) */
  291.     { "kh", NULL, 0, 0, "HOME" },    /* (HOME) */
  292.     { "kH", NULL, 0, 0, "END" },    /* (END) */
  293.     { "kP", NULL, 0, 0, "PGUP" },    /* (PGUP) */
  294.     { "kN", NULL, 0, 0, "PGDOWN" },    /* (PGDOWN) */
  295.     { "k0", NULL, 0, 0, "F0" },        /* (F0) */
  296.     { "k1", NULL, 0, 0, "F1" },        /* (F1) */
  297.     { "k2", NULL, 0, 0, "F2" },        /* (F2) */
  298.     { "k3", NULL, 0, 0, "F3" },        /* (F3) */
  299.     { "k4", NULL, 0, 0, "F4" },        /* (F4) */
  300.     { "k5", NULL, 0, 0, "F5" },        /* (F5) */
  301.     { "k6", NULL, 0, 0, "F6" },        /* (F6) */
  302.     { "k7", NULL, 0, 0, "F7" },        /* (F7) */
  303.     { "k8", NULL, 0, 0, "F8" },        /* (F8) */
  304.     { "k9", NULL, 0, 0, "F9" },        /* (F9) */
  305.     { "k;", NULL, 0, 0, "F10" },    /* (F10) */
  306. };
  307.  
  308.  
  309. /* Some nice aliases...  */
  310. #define TTY_ATTRIBUTES_OFF      (tty_capability[0].string)
  311. #define TTY_REVERSE_ON          (tty_capability[1].string)
  312. #define TTY_BRIGHT_ON           (tty_capability[2].string)
  313. #define TTY_CURSOR_OFF          (tty_capability[3].string)
  314. #define TTY_CURSOR_ON           (tty_capability[4].string)
  315. #define TTY_CLEAR_SCREEN        (tty_capability[5].string)
  316. #define TTY_CURSOR_MOVE         (tty_capability[6].string)
  317. #define TTY_PAD_CHAR            (tty_capability[7].string)
  318. #define TTY_UP_ONE_LINE         (tty_capability[8].string)
  319. #define TTY_LEFT_ONE_SPACE      (tty_capability[9].string)
  320. #define TTY_STANDOUT_ON        (tty_capability[10].string)
  321. #define TTY_MAGIC_COOKIE    (tty_capability[11].integer)
  322. #define TTY_MS_FLAG        (tty_capability[12].integer)
  323.  
  324.  
  325. /* Some more nice aliases.  */
  326. #define TTY_ATTRIBUTES_OFF_NAME (tty_capability[0].name)
  327. #define TTY_REVERSE_ON_NAME     (tty_capability[1].name)
  328. #define TTY_BRIGHT_ON_NAME      (tty_capability[2].name)
  329. #define TTY_CURSOR_OFF_NAME     (tty_capability[3].name)
  330. #define TTY_CURSOR_ON_NAME      (tty_capability[4].name)
  331. #define TTY_CLEAR_SCREEN_NAME   (tty_capability[5].name)
  332. #define TTY_CURSOR_MOVE_NAME    (tty_capability[6].name)
  333. #define TTY_PAD_CHAR_NAME       (tty_capability[7].name)
  334. #define TTY_UP_ONE_LINE_NAME    (tty_capability[8].name)
  335. #define TTY_LEFT_ONE_SPACE_NAME (tty_capability[9].name)
  336. #define TTY_STANDOUT_ON_NAME    (tty_capability[10].name)
  337. #define TTY_MAGIC_COOKIE_NAME    (tty_capability[11].name)
  338. #define TTY_MS_FLAG_NAME    (tty_capability[12].name)
  339.  
  340.  
  341. #ifdef HAVE_LIBTERMCAP
  342.  
  343. static char term_database[] = "termcap";
  344. static char term_env[]      = "TERMCAP";
  345.  
  346. #else   /* !HAVE_LIBTERMCAP */
  347.  
  348. static char term_database[] = "terminfo";
  349. static char term_env[]      = "TERMINFO";
  350.  
  351. #endif  /* !HAVE_LIBTERMCAP */
  352.  
  353.  
  354. static void tty_io_goto        PROTO ((int, int));
  355. static void tty_io_foreground     PROTO ((int));
  356. static void tty_io_background     PROTO ((int));
  357. static void tty_io_brightness     PROTO ((int));
  358. static void tty_io_reversevid     PROTO ((int));
  359. static void tty_io_colors    PROTO ((unsigned char));
  360.  
  361.  
  362. void fatal PROTO ((char *));
  363.  
  364.  
  365. /* ANSI colors. OFF & ON are here because we need them when we read the
  366.    configuration file. Don't bother...  */
  367. static char *colors[10] =
  368. {
  369.     "BLACK",
  370.     "RED",
  371.     "GREEN",
  372.     "YELLOW",
  373.     "BLUE",
  374.     "MAGENTA",
  375.     "CYAN",
  376.     "WHITE",
  377.     "OFF",
  378.     "ON"
  379. };
  380.  
  381.  
  382. /* Control keys description. C-a, C-b, C-c and so on...  */
  383. unsigned char key_ctrl_table[0x5f] =
  384. {
  385.     0x20,                       /* 0x20 ( ) */
  386.     0x21,                       /* 0x21 (!) */
  387.     0x22,                       /* 0x22 (") */
  388.     0x23,                       /* 0x23 (#) */
  389.     0xff,                       /* 0x24 ($) */
  390.     0x25,                       /* 0x25 (%) */
  391.     0x26,                       /* 0x26 (&) */
  392.     0x07,                       /* 0x27 (') */
  393.     0x28,                       /* 0x28 (() */
  394.     0x29,                       /* 0x29 ()) */
  395.     0x2a,                       /* 0x2a (*) */
  396.     0x2b,                       /* 0x2b (+) */
  397.     0x2c,                       /* 0x2c (,) */
  398.     0x2d,                       /* 0x2d (-) */
  399.     0x2e,                       /* 0x2e (.) */
  400.     0x2f,                       /* 0x2f (/) */
  401.     0x20,                       /* 0x30 (0) */
  402.     0x20,                       /* 0x31 (1) */
  403.     0xff,                       /* 0x32 (2) */
  404.     0x1b,                       /* 0x33 (3) */
  405.     0x1c,                       /* 0x34 (4) */
  406.     0x1d,                       /* 0x35 (5) */
  407.     0x1e,                       /* 0x36 (6) */
  408.     0x1f,                       /* 0x37 (7) */
  409.     0x7f,                       /* 0x38 (8) */
  410.     0x39,                       /* 0x39 (9) */
  411.     0x3a,                       /* 0x3a (:) */
  412.     0x3b,                       /* 0x3b (;) */
  413.     0x3c,                       /* 0x3c (<) */
  414.     0x20,                       /* 0x3d (=) */
  415.     0x3e,                       /* 0x3e (>) */
  416.     0x20,                       /* 0x3f (?) */
  417.     0x20,                       /* 0x40 (@) */
  418.     0x01,                       /* 0x41 (A) */
  419.     0x02,                       /* 0x42 (B) */
  420.     0x03,                       /* 0x43 (C) */
  421.     0x04,                       /* 0x44 (D) */
  422.     0x05,                       /* 0x45 (E) */
  423.     0x06,                       /* 0x46 (F) */
  424.     0x07,                       /* 0x47 (G) */
  425.     0x08,                       /* 0x48 (H) */
  426.     0x09,                       /* 0x49 (I) */
  427.     0x0a,                       /* 0x4a (J) */
  428.     0x0b,                       /* 0x4b (K) */
  429.     0x0c,                       /* 0x4c (L) */
  430.     0x0d,                       /* 0x4d (M) */
  431.     0x0e,                       /* 0x4e (N) */
  432.     0x0f,                       /* 0x4f (O) */
  433.     0x10,                       /* 0x50 (P) */
  434.     0x11,                       /* 0x51 (Q) */
  435.     0x12,                       /* 0x52 (R) */
  436.     0x13,                       /* 0x53 (S) */
  437.     0x14,                       /* 0x54 (T) */
  438.     0x15,                       /* 0x55 (U) */
  439.     0x16,                       /* 0x56 (V) */
  440.     0x17,                       /* 0x57 (W) */
  441.     0x18,                       /* 0x58 (X) */
  442.     0x19,                       /* 0x59 (Y) */
  443.     0x1a,                       /* 0x5a (Z) */
  444.     0x1b,                       /* 0x5b ([) */
  445.     0x1c,                       /* 0x5c (\) */
  446.     0x1d,                       /* 0x5d (]) */
  447.     0x5e,                       /* 0x5e (^) */
  448.     0x7f,                       /* 0x5f (_) */
  449.     0x20,                       /* 0x60 (`) */
  450.     0x01,                       /* 0x61 (a) */
  451.     0x02,                       /* 0x62 (b) */
  452.     0x03,                       /* 0x63 (c) */
  453.     0x04,                       /* 0x64 (d) */
  454.     0x05,                       /* 0x65 (e) */
  455.     0x06,                       /* 0x66 (f) */
  456.     0x07,                       /* 0x67 (g) */
  457.     0x08,                       /* 0x68 (h) */
  458.     0x09,                       /* 0x69 (i) */
  459.     0x0a,                       /* 0x6a (j) */
  460.     0x0b,                       /* 0x6b (k) */
  461.     0x0c,                       /* 0x6c (l) */
  462.     0x0d,                       /* 0x6d (m) */
  463.     0x0e,                       /* 0x6e (n) */
  464.     0x0f,                       /* 0x6f (o) */
  465.     0x10,                       /* 0x70 (p) */
  466.     0x11,                       /* 0x71 (q) */
  467.     0x12,                       /* 0x72 (r) */
  468.     0x13,                       /* 0x73 (s) */
  469.     0x14,                       /* 0x74 (t) */
  470.     0x15,                       /* 0x75 (u) */
  471.     0x16,                       /* 0x76 (v) */
  472.     0x17,                       /* 0x77 (w) */
  473.     0x18,                       /* 0x78 (x) */
  474.     0x19,                       /* 0x79 (y) */
  475.     0x1a,                       /* 0x7a (z) */
  476.     0x20,                       /* 0x7b ({) */
  477.     0x20,                       /* 0x7c (|) */
  478.     0x20,                       /* 0x7d (}) */
  479.     0x20,                       /* 0x7e (~) */
  480. };
  481.  
  482.  
  483. #define NO      0
  484. #define YES     1
  485.  
  486. #define MAX_KEY_LENGTH    15
  487.  
  488. /* Major number for Linux virtual console devices (/dev/tty*).  */
  489. #define LINUX_VC_MAJOR  4
  490.  
  491.  
  492. static int  keyno    = 0;
  493. static int  keyindex = 0;
  494. static char keybuf[1024];
  495.  
  496.  
  497. /* Hooks that get called when we are going idle and when we stop
  498.    being idle.  */
  499. void (* tty_enter_idle_hook)() = NULL;
  500. void (* tty_exit_idle_hook)()  = NULL;
  501.  
  502.  
  503. void
  504. tty_startup(last_char)
  505.     int last_char;
  506. {
  507.     /* Fail if stdin or stdout are not real terminals.  */
  508.     if (!isatty(TTY_INPUT) || !isatty(TTY_OUTPUT))
  509.     fatal("only standard error can be redirected");
  510.  
  511.     /* Get calloc-ed memory for tty_scr & tty_atr.  */
  512.     tty_scr = (unsigned char *)xcalloc(columns * lines,
  513.                        sizeof(unsigned char));
  514.     tty_atr = (unsigned char *)xcalloc(columns * lines,
  515.                        sizeof(unsigned char));
  516.  
  517.     /* Get calloc-ed memory for tty_prev_scr & tty_prev_atr.  */
  518.     tty_prev_scr = (unsigned char *)xcalloc(columns * lines,
  519.                         sizeof(unsigned char));
  520.     tty_prev_atr = (unsigned char *)xcalloc(columns * lines,
  521.                         sizeof(unsigned char));
  522.  
  523.     /* Store the terminal settings in old_term. it will be used to restore
  524.        them later.  */
  525. #ifdef HAVE_POSIX_TTY
  526.     tcgetattr(TTY_OUTPUT, &old_term);
  527. #else
  528. #ifdef HAVE_SYSTEMV_TTY
  529.     ioctl(TTY_OUTPUT, TCGETA, &old_term);
  530. #else
  531.     ioctl(TTY_OUTPUT, TIOCGETP, &old_arg);
  532.     ioctl(TTY_OUTPUT, TIOCGETC, &old_targ);
  533.     ioctl(TTY_OUTPUT, TIOCGLTC, &old_ltarg);
  534. #endif /* HAVE_SYSTEMV_TTY */
  535. #endif /* HAVE_POSIX_TTY */
  536.  
  537.     tty_last_char_flag = last_char;
  538. }
  539.  
  540.  
  541. /*
  542.  * Initialize some keybord stuff.
  543.  */
  544.  
  545. void
  546. tty_kbdinit(kbd_mode)
  547.     int kbd_mode;
  548. {
  549.     default_key.key_seq  = (unsigned char *)xmalloc(16);
  550.     default_key.aux_data = NULL;
  551.     default_key.next     = NULL;
  552.     tty_kbdmode          = kbd_mode;
  553. }
  554.  
  555.  
  556. /*
  557.  * This function is used to switch between canonical and noncanonical
  558.  * terminal modes.
  559.  */
  560.  
  561. void
  562. tty_set_mode(mode)
  563.     int mode;
  564. {
  565.     if (mode == TTY_NONCANONIC)
  566.     {
  567. #ifdef HAVE_POSIX_TTY
  568.     new_term = old_term;
  569.     new_term.c_iflag &= ~(IXON | ICRNL | IGNCR | INLCR | IGNBRK | BRKINT);
  570.     new_term.c_oflag &= ~OPOST;
  571.     new_term.c_lflag |= ISIG | NOFLSH;
  572.     new_term.c_lflag &= ~(ICANON | ECHO);
  573.  
  574.     /* I think we will always have these ones:  */
  575.  
  576.     new_term.c_cc[VINTR] = key_INTERRUPT;        /* Ctrl-G */
  577.     new_term.c_cc[VQUIT] = key_INTERRUPT;        /* Ctrl-G */
  578.  
  579. #ifdef VSTART
  580.     new_term.c_cc[VSTART] = CDISABLE;        /* START (^Q) */
  581. #endif
  582.  
  583. #ifdef VSTOP
  584.     new_term.c_cc[VSTOP]  = CDISABLE;        /* STOP (^S) */
  585. #endif
  586.  
  587.     new_term.c_cc[VMIN]  = 1;
  588.     new_term.c_cc[VTIME] = 0;
  589.  
  590.     /* ... but not always these ones: (in fact I am not sure if I
  591.        really need to overwrite all these, but just in case... */
  592.  
  593. #ifdef VERASE
  594.     new_term.c_cc[VERASE] = CDISABLE;
  595. #endif
  596.  
  597. #ifdef VKILL
  598.     new_term.c_cc[VKILL] = CDISABLE;
  599. #endif
  600.  
  601. #ifdef VEOL
  602.     new_term.c_cc[VEOL] = CDISABLE;
  603. #endif
  604.  
  605. #ifdef VEOL2
  606.     new_term.c_cc[VEOL2] = CDISABLE;
  607. #endif
  608.  
  609. #ifdef VSWTCH
  610.     new_term.c_cc[VSWTCH] = CDISABLE;
  611. #endif
  612.  
  613. #ifdef VSUSP
  614.     new_term.c_cc[VSUSP] = key_SUSPEND;             /* Ctrl-Z */
  615. #endif
  616.  
  617. #ifdef VDSUSP
  618.     new_term.c_cc[VDSUSP] = CDISABLE;
  619. #endif
  620.  
  621. #ifdef VREPRINT
  622.     new_term.c_cc[VREPRINT] = CDISABLE;
  623. #endif
  624.  
  625. #ifdef VDISCARD
  626.     new_term.c_cc[VDISCARD] = CDISABLE;
  627. #endif
  628.  
  629. #ifdef VWERASE
  630.     new_term.c_cc[VWERASE] = CDISABLE;
  631. #endif
  632.  
  633. #ifdef VLNEXT
  634.     new_term.c_cc[VLNEXT] = CDISABLE;
  635. #endif
  636.  
  637.     tcsetattr(TTY_OUTPUT, TCSADRAIN, &new_term);
  638.     ospeed = cfgetospeed(&new_term);
  639. #else
  640. #ifdef HAVE_SYSTEMV_TTY
  641.     new_term = old_term;
  642.     new_term.c_iflag &= ~(IXON | ICRNL | IGNCR | INLCR);
  643.     new_term.c_oflag = 0;
  644.     new_term.c_lflag = 0;
  645.  
  646.     /* I think we will always have these:  */
  647.  
  648.     new_term.c_cc[VINTR]  = key_INTERRUPT;    /* Ctrl-G */
  649.     new_term.c_cc[VQUIT]  = key_INTERRUPT;    /* Ctrl-G */
  650.  
  651. #ifdef VSTART
  652.     new_term.c_cc[VSTART] = CDISABLE;    /* START (^Q) */
  653. #endif
  654.  
  655. #ifdef VSTOP
  656.     new_term.c_cc[VSTOP]  = CDISABLE;    /* STOP (^S) */
  657. #endif
  658.  
  659.     new_term.c_cc[VMIN]   = 1;
  660.     new_term.c_cc[VTIME]  = 0;
  661.  
  662.     /* ... but not always these:  (in fact I am not sure if I really
  663.        need to overwrite all these, but just in case... */
  664.  
  665. #ifdef VERASE
  666.     new_term.c_cc[VERASE] = CDISABLE;
  667. #endif
  668.  
  669. #ifdef VKILL
  670.     new_term.c_cc[VKILL] = CDISABLE;
  671. #endif
  672.  
  673. #ifdef VEOL
  674.     new_term.c_cc[VEOL] = CDISABLE;
  675. #endif
  676.  
  677. #ifdef VEOL2
  678.     new_term.c_cc[VEOL2] = CDISABLE;
  679. #endif
  680.  
  681. #ifdef VSWTCH
  682.     new_term.c_cc[VSWTCH] = CDISABLE;
  683. #endif
  684.  
  685. #ifdef VSUSP
  686.     new_term.c_cc[VSUSP] = key_SUSPEND;             /* Ctrl-Z */
  687. #endif
  688.  
  689. #ifdef VDSUSP
  690.     new_term.c_cc[VDSUSP] = CDISABLE;
  691. #endif
  692.  
  693. #ifdef VREPRINT
  694.     new_term.c_cc[VREPRINT] = CDISABLE;
  695. #endif
  696.  
  697. #ifdef VDISCARD
  698.     new_term.c_cc[VDISCARD] = CDISABLE;
  699. #endif
  700.  
  701. #ifdef VWERASE
  702.     new_term.c_cc[VWERASE] = CDISABLE;
  703. #endif
  704.  
  705. #ifdef VLNEXT
  706.     new_term.c_cc[VLNEXT] = CDISABLE;
  707. #endif
  708.  
  709.     ioctl(TTY_OUTPUT, TCSETAW, &new_term);
  710.     ospeed = new_term.c_cflag & CBAUD;
  711. #else
  712.     new_arg   = old_arg;
  713.     new_targ  = old_targ;
  714.     new_ltarg = old_ltarg;
  715.     new_arg.sg_flags = ((old_arg.sg_flags &
  716.              ~(ECHO | CRMOD | XTABS | ALLDELAY | TILDE)) | CBREAK);
  717.     new_targ.t_intrc   = key_INTERRUPT;     /* Ctrl-G */
  718.     new_targ.t_quitc   = key_INTERRUPT;     /* Ctrl-G */
  719.     new_targ.t_stopc   = CDISABLE;        /* Ctrl-G */
  720.     new_targ.t_startc  = CDISABLE;        /* Ctrl-G */
  721.     new_targ.t_eofc    = CDISABLE;
  722.     new_targ.t_brkc    = CDISABLE;
  723.     new_ltarg.t_lnextc = CDISABLE;
  724.     new_ltarg.t_flushc = CDISABLE;
  725.     new_ltarg.t_werasc = CDISABLE;
  726.     new_ltarg.t_rprntc = CDISABLE;
  727.     new_ltarg.t_dsuspc = CDISABLE;       /* DSUSPC (delayed SUSPC,^Y) */
  728.     new_ltarg.t_suspc  = key_SUSPEND;
  729.  
  730.     ioctl(TTY_OUTPUT, TIOCSETN, &new_arg);
  731.     ioctl(TTY_OUTPUT, TIOCSETC, &new_targ);
  732.     ioctl(TTY_OUTPUT, TIOCSLTC, &new_ltarg);
  733.     ospeed = new_arg.sg_ospeed;
  734. #endif /* HAVE_SYSTEMV_TTY */
  735. #endif /* HAVE_POSIX_TTY */
  736.  
  737. /* Try to make sure the terminal is not locked.  */
  738. #ifdef TCXONC
  739. #ifdef __QNX__
  740.     {
  741.         int value = 1;
  742.         ioctl (TTY_OUTPUT, TCXONC, &value);
  743.     }
  744. #else
  745.     ioctl(TTY_OUTPUT, TCXONC, 1);
  746. #endif
  747. #endif
  748.  
  749. #ifndef APOLLO
  750. #ifdef TIOCSTART
  751.     ioctl(TTY_OUTPUT, TIOCSTART, 0);
  752. #endif
  753. #endif
  754.  
  755. #ifdef HAVE_POSIX_TTY
  756. #ifdef TCOON
  757.     tcflow(TTY_OUTPUT, TCOON);
  758. #endif
  759. #endif
  760.     }
  761.     else
  762.     {
  763. #ifdef HAVE_POSIX_TTY
  764.     tcsetattr(TTY_OUTPUT, TCSADRAIN, &old_term);
  765. #else
  766. #ifdef HAVE_SYSTEMV_TTY
  767.     ioctl(TTY_OUTPUT, TCSETAW, &old_term);
  768. #else
  769.     ioctl(TTY_OUTPUT, TIOCSETN, &old_arg);
  770.     ioctl(TTY_OUTPUT, TIOCSETC, &old_targ);
  771.     ioctl(TTY_OUTPUT, TIOCSLTC, &old_ltarg);
  772. #endif /* HAVE_SYSTEMV_TTY */
  773. #endif /* HAVE_POSIX_TTY */
  774.     }
  775.  
  776.     tty_mode = mode;
  777. }
  778.  
  779.  
  780. /*
  781.  * Set the interrupt character.
  782.  */
  783.  
  784. void
  785. tty_set_interrupt_char(c)
  786.     unsigned char c;
  787. {
  788. #ifdef HAVE_POSIX_TTY
  789.     struct termios current_term;
  790.  
  791.     tcgetattr(TTY_OUTPUT, ¤t_term);
  792.     current_term.c_cc[VINTR] = c;
  793.     current_term.c_cc[VQUIT] = c;
  794.     tcsetattr(TTY_OUTPUT, TCSADRAIN, ¤t_term);
  795. #else
  796. #ifdef HAVE_SYSTEMV_TTY
  797.     struct termio current_term;
  798.  
  799.     ioctl(TTY_OUTPUT, TCGETA, ¤t_term);
  800.     current_term.c_cc[VINTR] = c;
  801.     current_term.c_cc[VQUIT] = c;
  802.     ioctl(TTY_OUTPUT, TCSETAW, ¤t_term);
  803. #else
  804.     struct tchars current_targ;
  805.  
  806.     ioctl(TTY_OUTPUT, TIOCGETC, ¤t_targ);
  807.     current_targ.t_intrc = c;
  808.     current_targ.t_quitc = c;
  809.     ioctl(TTY_OUTPUT, TIOCSETC, ¤t_targ);
  810. #endif /* HAVE_SYSTEMV_TTY */
  811. #endif /* HAVE_POSIX_TTY */
  812. }
  813.  
  814.  
  815. /*
  816.  * Write a character to the screen.  Used by tputs() to output
  817.  * characters.  Actually we are only storing them in a buffer
  818.  * (tty_cache[]) and flush them later (in tty_flush()).
  819.  */
  820.  
  821. int
  822. tty_writec(c)
  823.     int c;
  824. {
  825.     tty_cache[tty_index++] = (char)c;
  826.     return 1;
  827. }
  828.  
  829.  
  830. /*
  831.  * Send the `cl' sequence to the terminal.
  832.  */
  833.  
  834. void
  835. tty_io_clear()
  836. {
  837.     tputs(TTY_CLEAR_SCREEN, lines, tty_writec);
  838.     tty_flush();
  839. }
  840.  
  841.  
  842. /*
  843.  * This function is called to restore the canonic mode at exit.  It also
  844.  * clears the screen (or restore it, if possible) and sets the default
  845.  * attributes.  If screen is NULL, there was an error, so don't try to
  846.  * restore it.
  847.  */
  848.  
  849. void
  850. tty_exit(screen)
  851.     char *screen;
  852. {
  853.     if (tty_mode == TTY_NONCANONIC)
  854.     tty_set_mode(TTY_CANONIC);
  855.  
  856.     tty_defaults();
  857.  
  858.     if (screen)
  859.     {
  860. #ifdef HAVE_LINUX
  861.     if (LinuxConsole)
  862.         tty_put_screen(screen);
  863.     else
  864.         tty_io_clear();
  865. #endif
  866.     }
  867.     else
  868.     tty_io_clear();
  869. }
  870.  
  871.  
  872. /*
  873.  * Converts a key sequence from the human readable, '^' based form into a
  874.  * computer usable form.
  875.  */
  876.  
  877. char *
  878. tty_key_convert(key_seq)
  879.     unsigned char *key_seq;
  880. {
  881.     unsigned char *first;
  882.     unsigned char *second;
  883.  
  884.  
  885.     first = second = key_seq;
  886.  
  887.     if (tty_kbdmode == 0 && *key_seq != '^')
  888.     return NULL;
  889.  
  890.     while (*second)
  891.     {
  892.     if (*second == '^')
  893.     {
  894.         if (*++second)
  895.         *first++ = key_ctrl_table[(*second++ & 0x7F) - ' '];
  896.         else
  897.         return NULL;
  898.     }
  899.     else
  900.         *first++ = *second++;
  901.     }
  902.  
  903.     *first = 0;
  904.     return (char *)key_seq;
  905. }
  906.  
  907.  
  908. /*
  909.  * Flush the tty cache.
  910.  */
  911.  
  912. void
  913. tty_flush()
  914. {
  915.     xwrite(TTY_OUTPUT, tty_cache, tty_index);
  916.     tty_index = 0;
  917. }
  918.  
  919.  
  920. /*
  921.  * Update the tty screen.
  922.  */
  923.  
  924. void
  925. tty_update()
  926. {
  927.     int pos, x, y;
  928.     int tty_io_cursor_x = -1;
  929.     int tty_io_cursor_y = -1;
  930.     int last_pos = SCREEN_X * SCREEN_Y;
  931.  
  932.     /* Check if we should display the last character on the screen.  */
  933.     if (tty_last_char_flag == OFF)
  934.     last_pos--;
  935.  
  936.     /* Make the cursor invisible.  */
  937.     tty_cursor(OFF);
  938.  
  939.     for (pos = 0; pos < last_pos; pos++)
  940.     if (tty_scr[pos] != tty_prev_scr[pos] ||
  941.         tty_atr[pos] != tty_prev_atr[pos])
  942.     {
  943.         /* Move the cursor to the appropriate position, if
  944.            necessary.  */
  945.         y = pos / SCREEN_X;
  946.         x = pos % SCREEN_X;
  947.  
  948.         if (x != tty_io_cursor_x || y != tty_io_cursor_y)
  949.         tty_io_goto(tty_io_cursor_y = y, tty_io_cursor_x = x);
  950.  
  951.         /* Output the color sequence, if necessary.  */
  952.         tty_io_colors(tty_atr[pos]);
  953.  
  954.         if (TTY_CACHE_SIZE - tty_index < 128)
  955.         tty_flush();
  956.  
  957.         tty_writec(tty_scr[pos]);
  958.  
  959.         if (++tty_io_cursor_x == SCREEN_X)
  960.         {
  961.         /* Force a call to tty_io_goto().  Don't trust the tty.  */
  962.         tty_io_cursor_x = 0;
  963.         tty_io_cursor_y = -1;
  964.         }
  965.     }
  966.  
  967.     /* Update the latest cursor position.  */
  968.     tty_io_goto(tty_cursor_y, tty_cursor_x);
  969.  
  970.     /* Make the cursor visible again.  */
  971.     tty_cursor(ON);
  972.  
  973.     if (tty_index)
  974.     tty_flush();
  975.  
  976.     /* Synchronize the screen copies.  */
  977.     memcpy(tty_prev_scr, tty_scr, columns * lines * sizeof(char));
  978.     memcpy(tty_prev_atr, tty_atr, columns * lines * sizeof(char));
  979. }
  980.  
  981.  
  982. /*
  983.  * Add a string to the tty cache.
  984.  */
  985.  
  986. int
  987. tty_writes(s, len)
  988.     char *s;
  989.     size_t len;
  990. {
  991.     memcpy(tty_cache + tty_index, s, len);
  992.     tty_index += len;
  993.     return len;
  994. }
  995.  
  996.  
  997. /*
  998.  * Write a string to the screen, at the current cursor position.  The
  999.  * string should be short enough to fit into the current position and
  1000.  * the end of the line.
  1001.  */
  1002.  
  1003. int
  1004. tty_puts(buf, length)
  1005.     char *buf;
  1006.     size_t length;
  1007. {
  1008.     int tty_offset = (tty_cursor_y * columns) + tty_cursor_x;
  1009.  
  1010.     memcpy(tty_scr + tty_offset, buf, length);
  1011.     memset(tty_atr + tty_offset, tty_current_attribute, length);
  1012.  
  1013.     tty_cursor_x += length;
  1014.     return length;
  1015. }
  1016.  
  1017.  
  1018. /*
  1019.  * Write a character to the screen.
  1020.  */
  1021.  
  1022. int
  1023. tty_putc(c)
  1024.     unsigned char c;
  1025. {
  1026.     return tty_puts(&c, 1);
  1027. }
  1028.  
  1029.  
  1030. /*
  1031.  * Read data from the terminal.
  1032.  */
  1033.  
  1034. size_t
  1035. tty_read(buf, length)
  1036.     char *buf;
  1037.     size_t length;
  1038. {
  1039.     size_t bytes;
  1040.  
  1041.     tty_update();
  1042.  
  1043.     if (tty_enter_idle_hook)
  1044.     (*tty_enter_idle_hook)();
  1045.  
  1046.     bytes = xread(TTY_INPUT, buf, length);
  1047.  
  1048.     if (tty_exit_idle_hook)
  1049.     (*tty_exit_idle_hook)();
  1050.  
  1051.     return bytes;
  1052. }
  1053.  
  1054.  
  1055. /*
  1056.  * Clear the screen using the current color attributes.  When the
  1057.  * Linux console receives the 'cl' (clear screen) escape sequence, it
  1058.  * clears the screen using the current color attributes, while all the
  1059.  * xterms I've seen seem not to do so.  Therefore, we won't rely on
  1060.  * this feature under Linux, to avoid potential problems, because I
  1061.  * don't know which approach is correct.
  1062.  */
  1063.  
  1064. void
  1065. tty_clear()
  1066. {
  1067.     tty_io_clear();
  1068.  
  1069.     memset(tty_scr,      '\0', lines * columns * sizeof(unsigned char));
  1070.     memset(tty_atr,      '\0', lines * columns * sizeof(unsigned char));
  1071.     memset(tty_prev_scr, '\0', lines * columns * sizeof(unsigned char));
  1072.     memset(tty_prev_atr, '\0', lines * columns * sizeof(unsigned char));
  1073.  
  1074.     tty_cursor_x = 0;
  1075.     tty_cursor_y = 0;
  1076. }
  1077.  
  1078.  
  1079. /*
  1080.  * Fill the terminal screen with spaces & the current attribute.
  1081.  */
  1082.  
  1083. void
  1084. tty_fill()
  1085. {
  1086.     memset(tty_scr, ' ',
  1087.        lines * columns * sizeof(unsigned char));
  1088.     memset(tty_atr, tty_current_attribute,
  1089.        lines * columns * sizeof(unsigned char));
  1090.  
  1091.     tty_touch();
  1092. }
  1093.  
  1094.  
  1095. /*
  1096.  * Touch the tty, getting rid of any possible optimization.  The
  1097.  * current content of the screen will be completely different at
  1098.  * update time so that the entire screen will be updated.
  1099.  */
  1100.  
  1101. void
  1102. tty_touch()
  1103. {
  1104.     memset(tty_prev_scr, '\0', lines * columns * sizeof(unsigned char));
  1105. }
  1106.  
  1107.  
  1108. /*
  1109.  * Move the cursor.
  1110.  */
  1111.  
  1112. static void
  1113. tty_io_goto(y, x)
  1114.     int y, x;
  1115. {
  1116.     /* If the 'ms' flag is present, reset all the attributes before moving
  1117.        the cursor.  */
  1118.  
  1119.     if (TTY_MS_FLAG == 0)
  1120.     tty_defaults();
  1121.  
  1122.     tputs(tgoto(TTY_CURSOR_MOVE, x, y), 1, tty_writec);
  1123. }
  1124.  
  1125.  
  1126. /*
  1127.  * Set the foreground color. Use the ANSI color sequence where possible or
  1128.  * tty_reverse() for monochrome terminals.
  1129.  */
  1130.  
  1131. static void
  1132. tty_io_foreground(color)
  1133.     int color;
  1134. {
  1135.     char str[16];
  1136.  
  1137.     if (fg_cache == VALID_CACHE && color == TTY_IO_FOREGROUND)
  1138.     return;
  1139.  
  1140.     if (AnsiColors == ON)
  1141.     {
  1142.     memcpy(str, ansi_foreground, sizeof(ansi_foreground));
  1143.     str[3] += color;
  1144.     tty_writes(str, sizeof(ansi_foreground));
  1145.     }
  1146.     else
  1147.     tty_io_reversevid(color != WHITE);
  1148.  
  1149.     fg_cache = VALID_CACHE;
  1150.  
  1151.     TTY_IO_SET_FOREGROUND(color);
  1152. }
  1153.  
  1154.  
  1155. /*
  1156.  * Set the background color. Use the ANSI color sequence where possible or
  1157.  * tty_reverse() for monochrome terminals.
  1158.  */
  1159.  
  1160. static void
  1161. tty_io_background(color)
  1162.     int color;
  1163. {
  1164.     char str[16];
  1165.  
  1166.     if (bg_cache == VALID_CACHE && color == TTY_IO_BACKGROUND)
  1167.     return;
  1168.  
  1169.     if (AnsiColors == ON)
  1170.     {
  1171.     memcpy(str, ansi_background, sizeof(ansi_background));
  1172.     str[3] += color;
  1173.     tty_writes(str, sizeof(ansi_background));
  1174.     }
  1175.     else
  1176.     tty_io_reversevid(color != BLACK);
  1177.  
  1178.     bg_cache = VALID_CACHE;
  1179.  
  1180.     TTY_IO_SET_BACKGROUND(color);
  1181. }
  1182.  
  1183.  
  1184. /*
  1185.  * Set the brightness status. See the comment below.
  1186.  */
  1187.  
  1188. static void
  1189. tty_io_brightness(status)
  1190.     int status;
  1191. {
  1192.     if (br_cache == VALID_CACHE && status == TTY_IO_BRIGHTNESS)
  1193.     return;
  1194.  
  1195.     if (status == ON)
  1196.     {
  1197.     if (TTY_BRIGHT_ON)
  1198.         tputs(TTY_BRIGHT_ON, 1, tty_writec);
  1199.     }
  1200.     else
  1201.     {
  1202.     if (TTY_ATTRIBUTES_OFF)
  1203.         tputs(TTY_ATTRIBUTES_OFF, 1, tty_writec);
  1204.  
  1205.     fg_cache = INVALID_CACHE;
  1206.     bg_cache = INVALID_CACHE;
  1207.  
  1208.     TTY_IO_SET_BRIGHTNESS(OFF);
  1209.  
  1210.     /* There is no terminal capability to turn the brightness off
  1211.        (or the bold mode off).  We are using the 'me' capability
  1212.        (where available) which turns off all attributes so we must
  1213.        restore the reverse status after that.
  1214.  
  1215.        There is no need to restore the foreground & background
  1216.        *colors because we've always put tty_io_brightness(status)
  1217.        *BEFORE* tty_io_foreground(color) or
  1218.        *tty_io_background(color).  */
  1219.  
  1220.     if (TTY_IO_REVERSEVID == ON)
  1221.     {
  1222.         rv_cache = INVALID_CACHE;
  1223.         tty_io_reversevid(ON);
  1224.     }
  1225.     }
  1226.  
  1227.     br_cache = VALID_CACHE;
  1228.  
  1229.     TTY_IO_SET_BRIGHTNESS(status);
  1230. }
  1231.  
  1232.  
  1233. /*
  1234.  * Set the reverse video status. This is only used internally by the
  1235.  * code in this file therefore it is declared 'static'.
  1236.  */
  1237.  
  1238. static void
  1239. tty_io_reversevid(status)
  1240.     int status;
  1241. {
  1242.     if (rv_cache == VALID_CACHE && status == TTY_IO_REVERSEVID)
  1243.     return;
  1244.  
  1245.     if (status == ON)
  1246.     {
  1247.     if (TTY_REVERSE_ON)
  1248.         tputs(TTY_REVERSE_ON, 1, tty_writec);
  1249.     }
  1250.     else
  1251.     {
  1252.     if (TTY_ATTRIBUTES_OFF)
  1253.         tputs(TTY_ATTRIBUTES_OFF, 1, tty_writec);
  1254.  
  1255.     fg_cache = INVALID_CACHE;
  1256.     bg_cache = INVALID_CACHE;
  1257.  
  1258.     TTY_IO_SET_REVERSEVID(OFF);
  1259.  
  1260.     /* Same comment as in tty_brightness().  */
  1261.     if (TTY_IO_BRIGHTNESS == ON)
  1262.     {
  1263.         br_cache = INVALID_CACHE;
  1264.         tty_io_brightness(ON);
  1265.     }
  1266.     }
  1267.  
  1268.     rv_cache = VALID_CACHE;
  1269.  
  1270.     TTY_IO_SET_REVERSEVID(status);
  1271. }
  1272.  
  1273.  
  1274. /*
  1275.  * Set the brightness, foreground and background all together.
  1276.  */
  1277.  
  1278. static void
  1279. tty_io_colors(attributes)
  1280.     unsigned char attributes;
  1281. {
  1282.     tty_io_brightness(_TTY_BRIGHTNESS(attributes));
  1283.     tty_io_foreground(_TTY_FOREGROUND(attributes));
  1284.     tty_io_background(_TTY_BACKGROUND(attributes));
  1285. }
  1286.  
  1287.  
  1288. /*
  1289.  * Move the cursor.
  1290.  */
  1291.  
  1292. void
  1293. tty_goto(y, x)
  1294.     int y, x;
  1295. {
  1296.     tty_cursor_y = y;
  1297.     tty_cursor_x = x;
  1298. }
  1299.  
  1300.  
  1301. /*
  1302.  * Set the foreground color.
  1303.  */
  1304.  
  1305. void
  1306. tty_foreground(color)
  1307.     int color;
  1308. {
  1309.     TTY_SET_FOREGROUND(color);
  1310. }
  1311.  
  1312.  
  1313. /*
  1314.  * Set the background color.
  1315.  */
  1316.  
  1317. void
  1318. tty_background(color)
  1319.     int color;
  1320. {
  1321.     TTY_SET_BACKGROUND(color);
  1322. }
  1323.  
  1324.  
  1325. /*
  1326.  * Set the brightness status. See the comment below.
  1327.  */
  1328.  
  1329. void
  1330. tty_brightness(status)
  1331.     int status;
  1332. {
  1333.     TTY_SET_BRIGHTNESS(status);
  1334. }
  1335.  
  1336.  
  1337. /*
  1338.  * Set the reverse video status. This is only used internally by the
  1339.  * code in this file therefore it is declared 'static'.
  1340.  */
  1341.  
  1342. void
  1343. tty_reversevid(status)
  1344.     int status;
  1345. {
  1346.     TTY_SET_REVERSEVID(status);
  1347. }
  1348.  
  1349.  
  1350. /*
  1351.  * Set the brightness, foreground and background all together.
  1352.  */
  1353.  
  1354. void
  1355. tty_colors(brightness, foreground, background)
  1356.     int brightness, foreground, background;
  1357. {
  1358.     tty_brightness(brightness);
  1359.     tty_foreground(foreground);
  1360.     tty_background(background);
  1361. }
  1362.  
  1363.  
  1364. /*
  1365.  * Beep :-)
  1366.  */
  1367.  
  1368. void
  1369. tty_beep()
  1370. {
  1371.     tty_writec(7);
  1372.     tty_flush();
  1373. }
  1374.  
  1375.  
  1376. /*
  1377.  * Set the cursor status (where possible). Make it invisible during screen
  1378.  * refreshes and restore it afterward.
  1379.  */
  1380.  
  1381. void
  1382. tty_cursor(status)
  1383.     int status;
  1384. {
  1385.     if (status)
  1386.     {
  1387.     if (TTY_CURSOR_ON)
  1388.         tputs(TTY_CURSOR_ON, 1, tty_writec);
  1389.     }
  1390.     else
  1391.     {
  1392.     if (TTY_CURSOR_OFF)
  1393.         tputs(TTY_CURSOR_OFF, 1, tty_writec);
  1394.     }
  1395. }
  1396.  
  1397.  
  1398. /*
  1399.  * Store the software terminal status in a tty_status_t structure.
  1400.  */
  1401.  
  1402. void
  1403. tty_save(status)
  1404.     tty_status_t *status;
  1405. {
  1406.     *status = tty_current_attribute;
  1407. }
  1408.  
  1409.  
  1410. /*
  1411.  * Restore the software terminal status from a tty_status_t structure.
  1412.  */
  1413.  
  1414. void
  1415. tty_restore(status)
  1416.     tty_status_t *status;
  1417. {
  1418.     tty_current_attribute = *status;
  1419. }
  1420.  
  1421.  
  1422. /*
  1423.  * Restore the terminal to its default state.
  1424.  */
  1425.  
  1426. void
  1427. tty_defaults()
  1428. {
  1429.     if (AnsiColors == ON)
  1430.     tty_writes(ansi_defaults, sizeof(ansi_defaults));
  1431.  
  1432.     if (TTY_ATTRIBUTES_OFF)
  1433.     tputs(TTY_ATTRIBUTES_OFF, 1, tty_writec);
  1434.  
  1435.     fg_cache = INVALID_CACHE;
  1436.     bg_cache = INVALID_CACHE;
  1437.     br_cache = INVALID_CACHE;
  1438.     rv_cache = INVALID_CACHE;
  1439. }
  1440.  
  1441.  
  1442. /*
  1443.  * Get a character from the terminal. For better performance on high loaded
  1444.  * systems, read all the data available.
  1445.  */
  1446.  
  1447. int
  1448. tty_getc()
  1449. {
  1450.     if (keyno)
  1451.     return keybuf[keyno--, keyindex++];
  1452.  
  1453.     /* No interrupt/quit character.  */
  1454.     tty_set_interrupt_char(-1);
  1455.  
  1456.     for (keyindex = 0; (keyno = tty_read(keybuf, 1024)) < 0;);
  1457.  
  1458.     /* Restore ^G as the interrupt/quit character.  */
  1459.     tty_set_interrupt_char(key_INTERRUPT);
  1460.  
  1461.     return keyno ? keybuf[keyno--, keyindex++] : -1;
  1462. }
  1463.  
  1464.  
  1465. /*
  1466.  * Insert a key sequence into the list.
  1467.  */
  1468.  
  1469. void
  1470. tty_key_list_insert_sequence(key, key_seq, aux_data)
  1471.     tty_key_t **key;
  1472.     unsigned char *key_seq;
  1473.     void *aux_data;
  1474. {
  1475.     tty_key_t *new_key;
  1476.  
  1477.     new_key = (tty_key_t *)xmalloc(sizeof(tty_key_t));
  1478.     new_key->key_seq = (unsigned char *)xstrdup((char *)key_seq);
  1479.     new_key->aux_data = aux_data;
  1480.     new_key->next = *key;
  1481.     *key = new_key;
  1482. }
  1483.  
  1484.  
  1485. /*
  1486.  * Parse the key list, inserting the new key sequence in the proper
  1487.  * position.
  1488.  */
  1489.  
  1490. void
  1491. tty_key_list_insert(key_seq, aux_data)
  1492.     unsigned char *key_seq;
  1493.     void *aux_data;
  1494. {
  1495.     static tty_key_t **key = NULL;
  1496.  
  1497.     if (*key_seq == 0)
  1498.     return;               /* bad key sequence !  */
  1499.  
  1500.     /* Try to optimize by checking if the current entry should be added
  1501.        after the current position.  Avoid re-parsing the entire list if
  1502.        so.  */
  1503.     if (key == NULL || strcmp((char *)key_seq, (char *)(*key)->key_seq) <= 0)
  1504.     key = &key_list_head;
  1505.  
  1506.     for (; *key; key = &(*key)->next)
  1507.     if (strcmp((char *)key_seq, (char *)(*key)->key_seq) <= 0)
  1508.     {
  1509.         tty_key_list_insert_sequence(key, key_seq, aux_data);
  1510.         return;
  1511.     }
  1512.  
  1513.     tty_key_list_insert_sequence(key, key_seq, aux_data);
  1514. }
  1515.  
  1516.  
  1517. /*
  1518.  * Incremental searches a key in the list. Returns a pointer to the first
  1519.  * sequence that matches.
  1520.  */
  1521.  
  1522. tty_key_t *
  1523. tty_key_search(key_seq)
  1524.     char *key_seq;
  1525. {
  1526.     int cmp;
  1527.  
  1528.     if (current_key == NULL)
  1529.     return NULL;
  1530.  
  1531.     for (; current_key; current_key = current_key->next)
  1532.     {
  1533.     cmp = strcmp(key_seq, (char *)current_key->key_seq);
  1534.  
  1535.     if (cmp == 0)
  1536.         return current_key;
  1537.  
  1538.     if (cmp  < 0)
  1539.         break;
  1540.     }
  1541.  
  1542.     if (current_key == NULL ||
  1543.     strncmp(key_seq, (char *)current_key->key_seq, strlen(key_seq)))
  1544.     return (tty_key_t *)-1;
  1545.     else
  1546.     return NULL;
  1547. }
  1548.  
  1549.  
  1550. /*
  1551.  * Force the next key search to start from the begining of the list.
  1552.  */
  1553.  
  1554. void
  1555. tty_key_search_restart()
  1556. {
  1557.     current_key = key_list_head;
  1558. }
  1559.  
  1560.  
  1561. #if 0
  1562. /* Delete a key from the list. Don't remove this function, God only knows
  1563.    when I'll gonna need it...  */
  1564.  
  1565. void
  1566. tty_key_list_delete()
  1567. {
  1568.     tty_key_t *key, *next_key;
  1569.  
  1570.     for (key = key_list_head; key; key = next_key)
  1571.     {
  1572.     next_key = key->next;
  1573.     xfree(key->key_seq);
  1574.     xfree(key);
  1575.     }
  1576. }
  1577. #endif
  1578.  
  1579.  
  1580. /*
  1581.  * Get the first key available, returning also the repeat count, that
  1582.  * is, the number of times the key has been pressed.  These feature is
  1583.  * mainly used by the calling routines to perform optimizations.  For
  1584.  * example, if you press the down arrow several times, the caller can
  1585.  * display only the final position, saving a lot of time. If you have
  1586.  * ever worked with git on high loaded systems, I'm sure you know what
  1587.  * I mean.
  1588.  */
  1589.  
  1590. tty_key_t *
  1591. tty_get_key(repeat_count)
  1592.     int *repeat_count;
  1593. {
  1594.     int i, c;
  1595.     tty_key_t *key;
  1596.     unsigned char key_seq[64];
  1597.  
  1598.  
  1599.   restart:
  1600.  
  1601.     while ((c = tty_getc()) == -1);
  1602.  
  1603.     if (repeat_count)
  1604.     *repeat_count = 1;
  1605.  
  1606.     /* Handle ^SPC.  */
  1607.     if (c == 0)
  1608.     c = 0xff;
  1609.  
  1610.     if (!tty_kbdmode)
  1611.     {
  1612.     if (c == '\n' || c == '\r')
  1613.         c = key_ENTER;
  1614.  
  1615.     if (is_print(c) || c == key_INTERRUPT)
  1616.     {
  1617.         default_key.key_seq[0] = c;
  1618.         default_key.key_seq[1] = 0;
  1619.         return &default_key;
  1620.     }
  1621.     }
  1622.  
  1623.     tty_key_search_restart();
  1624.  
  1625.     for (i = 0; i < MAX_KEY_LENGTH; i++)
  1626.     {
  1627.     /* Handle brain-damaged key sequences correctly.  If  a  0  is
  1628.        found, transform it in a 0xff.  I don't know how smart this
  1629.        is, but right know I don't feel like doing it otherwise.  */
  1630.     if (c == 0)
  1631.         c = 0xff;
  1632.  
  1633.     key_seq[i    ] = c;
  1634.     key_seq[i + 1] = 0;
  1635.  
  1636.     key = tty_key_search((char *)key_seq);
  1637.  
  1638.     if (key == (tty_key_t *)-1)
  1639.         goto restart;
  1640.  
  1641.     if (key)
  1642.         break;
  1643.  
  1644.     while ((c = tty_getc()) == -1);
  1645.     }
  1646.  
  1647.     if (i == MAX_KEY_LENGTH)
  1648.     goto restart;
  1649.  
  1650.     if (repeat_count)
  1651.     while (keyno > i && (memcmp(key_seq, &keybuf[keyindex], i + 1) == 0))
  1652.     {
  1653.         keyindex += i + 1;
  1654.         keyno    -= i + 1;
  1655.         (*repeat_count)++;
  1656.     }
  1657.  
  1658.     return key;
  1659. }
  1660.  
  1661.  
  1662. /*
  1663.  * Retreive the screen size. Try ioctl(TIOCGWINSZ, ...) and, if it fails
  1664.  * or it is not supported, use the environment variables LINES & COLUMNS
  1665.  * (if possible). If both methods fail, use the default 80x24.
  1666.  */
  1667.  
  1668. void
  1669. tty_get_size(_columns, _lines)
  1670.     int *_columns, *_lines;
  1671. {
  1672.     char *env;
  1673.  
  1674. #ifdef HAVE_WINSZ
  1675.     int result;
  1676.     struct winsize winsz;
  1677.     int winsz_lines = 0, winsz_columns = 0;
  1678. #endif /* HAVE_WINSZ */
  1679.  
  1680.     columns = lines = 0;
  1681.  
  1682. #ifdef HAVE_WINSZ
  1683.  
  1684. #if defined TIOCGSIZE && !defined TIOCGWINSZ
  1685. #define TIOCGWINSZ TIOCGSIZE
  1686. #endif
  1687.  
  1688.     result = ioctl(TTY_OUTPUT, TIOCGWINSZ, &winsz);
  1689.  
  1690.     if (result == 0)
  1691.     if (winsz.ws_col && winsz.ws_row)
  1692.     {
  1693.         winsz_columns = winsz.ws_col;
  1694.         winsz_lines   = winsz.ws_row;
  1695.     }
  1696.  
  1697.     if (winsz_columns < MIN_TTY_COLUMNS || winsz_columns > MAX_TTY_COLUMNS)
  1698.     winsz_columns = 80;
  1699.  
  1700.     if (winsz_lines < MIN_TTY_LINES || winsz_lines > MAX_TTY_LINES)
  1701.     winsz_lines = 24;
  1702.  
  1703. #endif /* HAVE_WINSZ */
  1704.  
  1705.     if ((env = getenv("COLUMNS")))
  1706.     sscanf(env, "%d", &columns);
  1707.  
  1708.     if ((env = getenv("LINES")))
  1709.     sscanf(env, "%d", &lines);
  1710.  
  1711.     if (columns < MIN_TTY_COLUMNS || columns > MAX_TTY_COLUMNS)
  1712.     {
  1713. #ifdef HAVE_WINSZ
  1714.     columns = winsz_columns;
  1715. #else
  1716.     columns = 80;
  1717. #endif /* HAVE_WINSZ */
  1718.     }
  1719.  
  1720.     if (lines < MIN_TTY_LINES || lines > MAX_TTY_LINES)
  1721.     {
  1722. #ifdef HAVE_WINSZ
  1723.     lines = winsz_lines;
  1724. #else
  1725.     lines = 24;
  1726. #endif /* HAVE_WINSZ */
  1727.     }
  1728.  
  1729.     *_columns = columns;
  1730.     *_lines   = lines;
  1731. }
  1732.  
  1733.  
  1734. #ifdef HAVE_LINUX
  1735. /*
  1736.  * Read and write the screen contents via a Linux virtual console.
  1737.  * Returns 0 on failure, non-zero otherwise.  Handle both /dev/vcsaX
  1738.  * and /dev/vcsX.  op specifies the operation to be performed: VCS_READ
  1739.  * or VCS_WRITE.  We check first for /dev/vcs?X since it makes debugging
  1740.  * easier (using /de/vcsa0 when debugging dumps the screen on the
  1741.  * debugger's console; not funny).
  1742.  */
  1743.  
  1744. int
  1745. vcs_io(buf, op)
  1746.     char *buf;
  1747.     int op;
  1748. {
  1749.     int (*fn)();
  1750.     int vcsfd, flag;
  1751.     char vcs_name[16]  = "/dev/vcsX";
  1752.     char vcsa_name[16] = "/dev/vcsaX";
  1753.  
  1754.     if (op == VCS_READ)
  1755.     {
  1756.     flag = O_RDONLY;
  1757.     fn   = read;
  1758.     }
  1759.     else
  1760.     {
  1761.     flag = O_WRONLY;
  1762.     fn = write;
  1763.  
  1764.     if (vcs_is_bw)
  1765.         goto bw_label;
  1766.     }
  1767.  
  1768.     vcs_is_bw = 0;
  1769.  
  1770.     /* First attempt: /dev/vcsaX.  */
  1771.     vcsa_name[9] = tty_name[tty_name_len - 1];
  1772.     vcsfd = open(vcsa_name, flag);
  1773.  
  1774.     if (vcsfd != -1)
  1775.     {
  1776.       vcsa_label:
  1777.     (*fn)(vcsfd, buf, 4 + lines * columns * 2);
  1778.     close(vcsfd);
  1779.  
  1780.     if (op == VCS_WRITE)
  1781.     {
  1782.         tty_io_goto(buf[3], buf[2]);
  1783.         tty_flush();
  1784.     }
  1785.  
  1786.     return 1;
  1787.     }
  1788.  
  1789.     /* Second attempt: /dev/vcsa0.  */
  1790.     vcsa_name[9] = '0';
  1791.     vcsfd = open(vcsa_name, flag);
  1792.  
  1793.     if (vcsfd != -1)
  1794.     goto vcsa_label;
  1795.  
  1796.   bw_label:
  1797.  
  1798.     /* We failed to access a /dev/vcsa* device.  */
  1799.     vcs_is_bw = 1;
  1800.  
  1801.     /* This is important in order to clear the screen attributes.  */
  1802.     if (op == VCS_WRITE)
  1803.     tty_clear();
  1804.  
  1805.     /* Third attempt: /dev/vcsX (B/W).  */
  1806.     vcs_name[8] = tty_name[tty_name_len - 1];
  1807.     vcsfd = open(vcs_name, flag);
  1808.  
  1809.     if (vcsfd != -1)
  1810.     {
  1811.       vcs_label:
  1812.     (*fn)(vcsfd, buf, 4 + lines * columns);
  1813.     close(vcsfd);
  1814.  
  1815.     /* Unfortunately, the b/w devices do not provide the 4 bytes header
  1816.        with screen size & cursor position information.  */
  1817.  
  1818.     if (op == VCS_WRITE)
  1819.     {
  1820.         tty_io_goto(lines - 1, 0);
  1821.         tty_flush();
  1822.     }
  1823.     return 1;
  1824.     }
  1825.  
  1826.     /* Fourth attempt: /dev/vcs0 (B/W).  */
  1827.     vcs_name[8] = '0';
  1828.     vcsfd = open(vcs_name, flag);
  1829.  
  1830.     if (vcsfd != -1)
  1831.     goto vcs_label;
  1832.  
  1833.     return 0;
  1834. }
  1835. #endif
  1836.  
  1837.  
  1838. /*
  1839.  * Dump the screen. Only used in Linux if the terminal is a virtual
  1840.  * console.
  1841.  */
  1842.  
  1843. void
  1844. tty_get_screen(buf)
  1845.     char *buf;
  1846. {
  1847. #ifdef HAVE_LINUX
  1848.     if (LinuxConsole)
  1849.     vcs_read_ok = vcs_io(buf, VCS_READ);
  1850. #endif  /* HAVE_LINUX */
  1851. }
  1852.  
  1853.  
  1854. /*
  1855.  * Restore the screen. If the terminal is not a Linux virtual console, just
  1856.  * restore it to the default state.
  1857.  */
  1858.  
  1859. void
  1860. tty_put_screen(buf)
  1861.     char *buf;
  1862. {
  1863.     tty_defaults();
  1864.  
  1865. #ifdef HAVE_LINUX
  1866.     if (LinuxConsole)
  1867.     {
  1868.     /* If we were unable to read from /dev/vcs*, then we should not
  1869.        try to restore it.  */
  1870.     if (vcs_read_ok)
  1871.     {
  1872.         tty_touch();
  1873.  
  1874.         /* We might have the permission to read the contents of the
  1875.            virtual console, but not the permission to write it.  */
  1876.         if (vcs_io(buf, VCS_WRITE) == 0)
  1877.         tty_clear();
  1878.         else
  1879.         memset(tty_scr, '\0', lines * columns * sizeof(unsigned char));
  1880.     }
  1881.     else
  1882.         tty_clear();
  1883.     }
  1884.     else
  1885.     tty_clear();
  1886. #else   /* !HAVE_LINUX */
  1887.     tty_clear();
  1888. #endif  /* !HAVE_LINUX */
  1889. }
  1890.  
  1891.  
  1892. /*
  1893.  * Get the color index from the colors[] index table.
  1894.  */
  1895.  
  1896. int
  1897. tty_get_color_index(colorname)
  1898.     char *colorname;
  1899. {
  1900.     int i;
  1901.  
  1902.     for (i = 0; i < 10; i++)
  1903.     if (strcmp(colors[i], colorname) == 0)
  1904.         return (i < 8) ? i : (i - 8);
  1905.  
  1906.     return -1;
  1907. }
  1908.  
  1909.  
  1910. /*
  1911.  * Return the capability of a given termcap symbol.
  1912.  */
  1913.  
  1914. char *
  1915. tty_get_symbol_key_seq(symbol)
  1916.     char *symbol;
  1917. {
  1918.     int i;
  1919.  
  1920.     for (i = TTY_FIRST_SYMBOL_KEY; i < TTY_USED_CAPABILITIES; i++)
  1921.     if (strcmp(tty_capability[i].symbol, symbol) == 0)
  1922.         return tty_capability[i].string;
  1923.  
  1924.     return NULL;
  1925. }
  1926.  
  1927.  
  1928. /*
  1929.  * Get the entire set of requiresd termcap/terminfo capabilities. It performs
  1930.  * consistency checkings trying to recover as well as possible.
  1931.  */
  1932.  
  1933. void
  1934. tty_get_capabilities()
  1935. {
  1936. #ifdef HAVE_LINUX
  1937.     struct stat statbuf;
  1938. #endif /* HAVE_LINUX */
  1939.     char *capability_buf, *tmp;
  1940.     int err, i, term_errors = 0;
  1941.     char *termtype = getenv("TERM");
  1942.  
  1943. #ifdef HAVE_LINUX
  1944.     fstat(TTY_OUTPUT, &statbuf);
  1945.     if ((statbuf.st_rdev >> 8) == LINUX_VC_MAJOR &&
  1946.     ((unsigned)(statbuf.st_rdev & 0xFF)) <= 8)
  1947.     LinuxConsole = 1;
  1948.     else
  1949.     LinuxConsole = 0;
  1950. #endif /* HAVE_LINUX */
  1951.  
  1952.     if (termtype == NULL)
  1953.     {
  1954.     fprintf(stderr, "%s: can't find the TERM environment variable, ",
  1955.         program);
  1956.     goto switch_to_vt100;
  1957.     }
  1958.  
  1959.     if (strlen(termtype) > 63)
  1960.     {
  1961.     fprintf(stderr, "%s: the TERM environment variable is too long, ",
  1962.         program);
  1963.       switch_to_vt100:
  1964.     fprintf(stderr, "trying vt100 ...\n");
  1965.     termtype = vt100;
  1966.     }
  1967.  
  1968.     err = tgetent(term_buf, termtype);
  1969.  
  1970.     if (err == -1)
  1971.     {
  1972.     fprintf(stderr, "%s: can't find the %s database.\n",
  1973.         program, term_database);
  1974.     fprintf(stderr, "%s: check your %s environment variable ...\n",
  1975.         program, term_env);
  1976.     exit(1);
  1977.     }
  1978.  
  1979.     if (err == 0)
  1980.     {
  1981.     fprintf(stderr,
  1982.         "%s: can't find the terminal type %s in the %s database.\n",
  1983.         program, termtype, term_database);
  1984.     exit(1);
  1985.     }
  1986.  
  1987.     tty_type = xstrdup(termtype);
  1988.  
  1989.     capability_buf = xmalloc(2048);
  1990.  
  1991.     tmp = tgetstr(TTY_PAD_CHAR_NAME, &capability_buf);
  1992.     PC = tmp ? *tmp : 0;
  1993.  
  1994.     BC = tgetstr(TTY_LEFT_ONE_SPACE_NAME, &capability_buf);
  1995.     UP = tgetstr(TTY_UP_ONE_LINE_NAME,    &capability_buf);
  1996.  
  1997.     if (BC == NULL || UP == NULL)
  1998.     BC = UP = NULL;
  1999.  
  2000.     TTY_ATTRIBUTES_OFF = tgetstr(TTY_ATTRIBUTES_OFF_NAME, &capability_buf);
  2001.     TTY_BRIGHT_ON      = tgetstr(TTY_BRIGHT_ON_NAME,      &capability_buf);
  2002.     TTY_REVERSE_ON     = tgetstr(TTY_REVERSE_ON_NAME,     &capability_buf);
  2003.  
  2004.     if (TTY_ATTRIBUTES_OFF == NULL)
  2005.     TTY_REVERSE_ON = TTY_BRIGHT_ON = NULL;
  2006.  
  2007.     TTY_STANDOUT_ON  = tgetstr(TTY_STANDOUT_ON_NAME,  &capability_buf);
  2008.  
  2009.     if (TTY_STANDOUT_ON == NULL)
  2010.     {
  2011.     TTY_STANDOUT_ON = NULL;
  2012.     TTY_MS_FLAG = 0;
  2013.     }
  2014.     else
  2015.     {
  2016.     /* Use standout instead of reverse video whenever possible.  */
  2017.     TTY_REVERSE_ON = TTY_STANDOUT_ON;
  2018.     TTY_MS_FLAG = tgetflag(TTY_MS_FLAG_NAME);
  2019.     }
  2020.  
  2021.     /* Check for magic-cookie terminals.  Not supported yet.  */
  2022.     TTY_MAGIC_COOKIE = tgetnum(TTY_MAGIC_COOKIE_NAME);
  2023.  
  2024.     if (TTY_MAGIC_COOKIE >= 0)
  2025.     TTY_ATTRIBUTES_OFF = TTY_REVERSE_ON = TTY_BRIGHT_ON = NULL;
  2026.  
  2027.  
  2028.     TTY_CURSOR_OFF = tgetstr(TTY_CURSOR_OFF_NAME, &capability_buf);
  2029.     TTY_CURSOR_ON  = tgetstr(TTY_CURSOR_ON_NAME,  &capability_buf);
  2030.  
  2031.     if (TTY_CURSOR_OFF == NULL || TTY_CURSOR_ON == NULL)
  2032.     TTY_CURSOR_ON = TTY_CURSOR_OFF = NULL;
  2033.  
  2034.     TTY_CLEAR_SCREEN = tgetstr(TTY_CLEAR_SCREEN_NAME, &capability_buf);
  2035.     TTY_CURSOR_MOVE  = tgetstr(TTY_CURSOR_MOVE_NAME,  &capability_buf);
  2036.  
  2037.     for (i = TTY_FIRST_SYMBOL_KEY; i < TTY_USED_CAPABILITIES; i++)
  2038.     tty_capability[i].string = tgetstr(tty_capability[i].name,
  2039.                          &capability_buf);
  2040.  
  2041.     for (i = 0; i < TTY_USED_CAPABILITIES; i++)
  2042.     if (tty_capability[i].string == NULL)
  2043.         if (tty_capability[i].required)
  2044.         {
  2045.         term_errors++;
  2046.         fprintf(stderr,
  2047.             "%s: can't find the '%s' terminal capability.\n",
  2048.             program, tty_capability[i].name);
  2049.         }
  2050.  
  2051.     if (term_errors)
  2052.     {
  2053.     fprintf(stderr, "%s: %d errors. Your terminal is too dumb :-< .\n",
  2054.         program, term_errors);
  2055.     exit(1);
  2056.     }
  2057. }
  2058.