]> code.delx.au - gnu-emacs/blobdiff - src/term.c
Avoid crashes due to insanely large columns in tabulated-list-format
[gnu-emacs] / src / term.c
index 8312491f2dec173b6e0e5566c6832f407217e675..43972109655ca360dfc3f8c32e95ee0b4ac680b2 100644 (file)
@@ -1,13 +1,13 @@
 /* Terminal control module for terminals described by TERMCAP
-   Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2015 Free Software
+   Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2016 Free Software
    Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -44,8 +44,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "keymap.h"
 #include "blockinput.h"
 #include "syssignal.h"
-#include "systty.h"
-#include "intervals.h"
 #ifdef MSDOS
 #include "msdos.h"
 static int been_here = -1;
@@ -56,10 +54,6 @@ static int been_here = -1;
 #endif
 
 #include "cm.h"
-#ifdef HAVE_X_WINDOWS
-#include "xterm.h"
-#endif
-
 #include "menu.h"
 
 /* The name of the default console device.  */
@@ -77,7 +71,6 @@ static void tty_turn_off_highlight (struct tty_display_info *);
 static void tty_show_cursor (struct tty_display_info *);
 static void tty_hide_cursor (struct tty_display_info *);
 static void tty_background_highlight (struct tty_display_info *tty);
-static struct terminal *get_tty_terminal (Lisp_Object, bool);
 static void clear_tty_hooks (struct terminal *terminal);
 static void set_tty_hooks (struct terminal *terminal);
 static void dissociate_if_controlling_tty (int fd);
@@ -91,7 +84,7 @@ static _Noreturn void vfatal (const char *str, va_list ap)
 
 #define OUTPUT(tty, a)                                          \
   emacs_tputs ((tty), a,                                        \
-               FRAME_LINES (XFRAME (selected_frame)) - curY (tty),     \
+               FRAME_TOTAL_LINES (XFRAME (selected_frame)) - curY (tty),       \
                cmputc)
 
 #define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
@@ -105,9 +98,9 @@ static _Noreturn void vfatal (const char *str, va_list ap)
 
 #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0)
 
-/* Display space properties */
+/* Display space properties */
 
-/* Chain of all tty device parameters. */
+/* Chain of all tty device parameters.  */
 struct tty_display_info *tty_list;
 
 /* Meaning of bits in no_color_video.  Each bit set means that the
@@ -161,6 +154,28 @@ tty_ring_bell (struct frame *f)
 
 /* Set up termcap modes for Emacs. */
 
+static void
+tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
+{
+  Lisp_Object lisp_terminal;
+  Lisp_Object extra_codes;
+  struct tty_display_info *tty = terminal->display_info.tty;
+
+  XSETTERMINAL (lisp_terminal, terminal);
+  for (extra_codes = Fterminal_parameter (lisp_terminal, sym);
+       CONSP (extra_codes);
+       extra_codes = XCDR (extra_codes))
+    {
+      Lisp_Object string = XCAR (extra_codes);
+      if (STRINGP (string))
+        {
+          fwrite (SDATA (string), 1, SBYTES (string), tty->output);
+          if (tty->termscript)
+            fwrite (SDATA (string), 1, SBYTES (string), tty->termscript);
+        }
+    }
+}
+
 static void
 tty_set_terminal_modes (struct terminal *terminal)
 {
@@ -176,13 +191,14 @@ tty_set_terminal_modes (struct terminal *terminal)
              off the screen, so it won't be overwritten and lost.  */
           int i;
           current_tty = tty;
-          for (i = 0; i < FRAME_LINES (XFRAME (selected_frame)); i++)
+          for (i = 0; i < FRAME_TOTAL_LINES (XFRAME (selected_frame)); i++)
             cmputc ('\n');
         }
 
       OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
       OUTPUT_IF (tty, tty->TS_keypad_mode);
       losecursor (tty);
+      tty_send_additional_strings (terminal, Qtty_mode_set_strings);
       fflush (tty->output);
     }
 }
@@ -196,6 +212,7 @@ tty_reset_terminal_modes (struct terminal *terminal)
 
   if (tty->output)
     {
+      tty_send_additional_strings (terminal, Qtty_mode_reset_strings);
       tty_turn_off_highlight (tty);
       tty_turn_off_insert (tty);
       OUTPUT_IF (tty, tty->TS_end_keypad_mode);
@@ -230,7 +247,7 @@ tty_set_terminal_window (struct frame *f, int size)
 {
   struct tty_display_info *tty = FRAME_TTY (f);
 
-  tty->specified_window = size ? size : FRAME_LINES (f);
+  tty->specified_window = size ? size : FRAME_TOTAL_LINES (f);
   if (FRAME_SCROLL_REGION_OK (f))
     tty_set_scroll_region (f, 0, tty->specified_window);
 }
@@ -245,9 +262,9 @@ tty_set_scroll_region (struct frame *f, int start, int stop)
     buf = tparam (tty->TS_set_scroll_region, 0, 0, start, stop - 1, 0, 0);
   else if (tty->TS_set_scroll_region_1)
     buf = tparam (tty->TS_set_scroll_region_1, 0, 0,
-                 FRAME_LINES (f), start,
-                 FRAME_LINES (f) - stop,
-                 FRAME_LINES (f));
+                 FRAME_TOTAL_LINES (f), start,
+                 FRAME_TOTAL_LINES (f) - stop,
+                 FRAME_TOTAL_LINES (f));
   else
     buf = tparam (tty->TS_set_window, 0, 0, start, 0, stop, FRAME_COLS (f));
 
@@ -419,7 +436,7 @@ tty_clear_to_end (struct frame *f)
     }
   else
     {
-      for (i = curY (tty); i < FRAME_LINES (f); i++)
+      for (i = curY (tty); i < FRAME_TOTAL_LINES (f); i++)
        {
          cursor_to (f, i, 0);
          clear_end_of_line (f, FRAME_COLS (f));
@@ -500,9 +517,6 @@ static ptrdiff_t encode_terminal_dst_size;
    Set CODING->produced to the byte-length of the resulting byte
    sequence, and return a pointer to that byte sequence.  */
 
-#ifndef DOS_NT
-static
-#endif
 unsigned char *
 encode_terminal_code (struct glyph *src, int src_len,
                      struct coding_system *coding)
@@ -518,15 +532,13 @@ encode_terminal_code (struct glyph *src, int src_len,
      multibyte-form.  But, it may be enlarged on demand if
      Vglyph_table contains a string or a composite glyph is
      encountered.  */
-  if (min (PTRDIFF_MAX, SIZE_MAX) / MAX_MULTIBYTE_LENGTH < src_len)
+  if (INT_MULTIPLY_WRAPV (src_len, MAX_MULTIBYTE_LENGTH, &required))
     memory_full (SIZE_MAX);
-  required = src_len;
-  required *= MAX_MULTIBYTE_LENGTH;
   if (encode_terminal_src_size < required)
-    {
-      encode_terminal_src = xrealloc (encode_terminal_src, required);
-      encode_terminal_src_size = required;
-    }
+    encode_terminal_src = xpalloc (encode_terminal_src,
+                                  &encode_terminal_src_size,
+                                  required - encode_terminal_src_size,
+                                  -1, sizeof *encode_terminal_src);
 
   charset_list = coding_charset_list (coding);
 
@@ -724,7 +736,7 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len)
      since that would scroll the whole frame on some terminals.  */
 
   if (AutoWrap (tty)
-      && curY (tty) + 1 == FRAME_LINES (f)
+      && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
       && (curX (tty) + len) == FRAME_COLS (f))
     len --;
   if (len <= 0)
@@ -796,7 +808,7 @@ tty_write_glyphs_with_face (register struct frame *f, register struct glyph *str
      since that would scroll the whole frame on some terminals.  */
 
   if (AutoWrap (tty)
-      && curY (tty) + 1 == FRAME_LINES (f)
+      && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
       && (curX (tty) + len) == FRAME_COLS (f))
     len --;
   if (len <= 0)
@@ -985,7 +997,7 @@ tty_ins_del_lines (struct frame *f, int vpos, int n)
       && vpos + i >= tty->specified_window)
     return;
   if (!FRAME_MEMORY_BELOW_FRAME (f)
-      && vpos + i >= FRAME_LINES (f))
+      && vpos + i >= FRAME_TOTAL_LINES (f))
     return;
 
   if (multi)
@@ -1022,7 +1034,7 @@ tty_ins_del_lines (struct frame *f, int vpos, int n)
       && FRAME_MEMORY_BELOW_FRAME (f)
       && n < 0)
     {
-      cursor_to (f, FRAME_LINES (f) + n, 0);
+      cursor_to (f, FRAME_TOTAL_LINES (f) + n, 0);
       clear_to_end (f);
     }
 }
@@ -1339,7 +1351,7 @@ term_get_fkeys_1 (void)
   if (!KEYMAPP (KVAR (kboard, Vinput_decode_map)))
     kset_input_decode_map (kboard, Fmake_sparse_keymap (Qnil));
 
-  for (i = 0; i < (sizeof (keys) / sizeof (keys[0])); i++)
+  for (i = 0; i < ARRAYELTS (keys); i++)
     {
       char *sequence = tgetstr (keys[i].cap, address);
       if (sequence)
@@ -1490,8 +1502,7 @@ append_glyph (struct it *it)
       if (it->bidi_p)
        {
          glyph->resolved_level = it->bidi_it.resolved_level;
-         if ((it->bidi_it.type & 7) != it->bidi_it.type)
-           emacs_abort ();
+         eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
          glyph->bidi_type = it->bidi_it.type;
        }
       else
@@ -1665,6 +1676,7 @@ append_composite_glyph (struct it *it)
          glyph = it->glyph_row->glyphs[it->area];
        }
       glyph->type = COMPOSITE_GLYPH;
+      eassert (it->pixel_width <= SHRT_MAX);
       glyph->pixel_width = it->pixel_width;
       glyph->u.cmp.id = it->cmp_it.id;
       if (it->cmp_it.ch < 0)
@@ -1687,8 +1699,7 @@ append_composite_glyph (struct it *it)
       if (it->bidi_p)
        {
          glyph->resolved_level = it->bidi_it.resolved_level;
-         if ((it->bidi_it.type & 7) != it->bidi_it.type)
-           emacs_abort ();
+         eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
          glyph->bidi_type = it->bidi_it.type;
        }
       else
@@ -1772,8 +1783,7 @@ append_glyphless_glyph (struct it *it, int face_id, const char *str)
   if (it->bidi_p)
     {
       glyph->resolved_level = it->bidi_it.resolved_level;
-      if ((it->bidi_it.type & 7) != it->bidi_it.type)
-       emacs_abort ();
+      eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
       glyph->bidi_type = it->bidi_it.type;
     }
   else
@@ -1837,7 +1847,7 @@ produce_glyphless_glyph (struct it *it, Lisp_Object acronym)
            acronym = XCDR (acronym);
          buf[0] = '[';
          str = STRINGP (acronym) ? SSDATA (acronym) : "";
-         for (len = 0; len < 6 && str[len] && ASCII_BYTE_P (str[len]); len++)
+         for (len = 0; len < 6 && str[len] && ASCII_CHAR_P (str[len]); len++)
            buf[1 + len] = str[len];
          buf[1 + len] = ']';
          len += 2;
@@ -1845,9 +1855,11 @@ produce_glyphless_glyph (struct it *it, Lisp_Object acronym)
       else
        {
          eassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE);
-         len = (it->c < 0x10000 ? sprintf (buf, "\\u%04X", it->c)
-                : it->c <= MAX_UNICODE_CHAR ? sprintf (buf, "\\U%06X", it->c)
-                : sprintf (buf, "\\x%06X", it->c));
+         len = sprintf (buf,
+                        (it->c < 0x10000 ? "\\u%04X"
+                         : it->c <= MAX_UNICODE_CHAR ? "\\U%06X"
+                         : "\\x%06X"),
+                        it->c + 0u);
        }
       str = buf;
     }
@@ -2008,11 +2020,9 @@ selected frame's terminal).  This function always returns nil if
 TERMINAL does not refer to a text terminal.  */)
   (Lisp_Object terminal)
 {
-  struct terminal *t = get_tty_terminal (terminal, 0);
-  if (!t)
-    return Qnil;
-  else
-    return t->display_info.tty->TN_max_colors > 0 ? Qt : Qnil;
+  struct terminal *t = decode_tty_terminal (terminal);
+
+  return (t && t->display_info.tty->TN_max_colors > 0) ? Qt : Qnil;
 }
 
 /* Return the number of supported colors.  */
@@ -2025,11 +2035,9 @@ selected frame's terminal).  This function always returns 0 if
 TERMINAL does not refer to a text terminal.  */)
   (Lisp_Object terminal)
 {
-  struct terminal *t = get_tty_terminal (terminal, 0);
-  if (!t)
-    return make_number (0);
-  else
-    return make_number (t->display_info.tty->TN_max_colors);
+  struct terminal *t = decode_tty_terminal (terminal);
+
+  return make_number (t ? t->display_info.tty->TN_max_colors : 0);
 }
 
 #ifndef DOS_NT
@@ -2144,52 +2152,6 @@ set_tty_color_mode (struct tty_display_info *tty, struct frame *f)
 
 #endif /* !DOS_NT */
 
-\f
-
-/* Return the tty display object specified by TERMINAL. */
-
-static struct terminal *
-get_tty_terminal (Lisp_Object terminal, bool throw)
-{
-  struct terminal *t = get_terminal (terminal, throw);
-
-  if (t && t->type != output_termcap && t->type != output_msdos_raw)
-    {
-      if (throw)
-        error ("Device %d is not a termcap terminal device", t->id);
-      else
-        return NULL;
-    }
-
-  return t;
-}
-
-/* Return an active termcap device that uses the tty device with the
-   given name.
-
-   This function ignores suspended devices.
-
-   Returns NULL if the named terminal device is not opened.  */
-
-struct terminal *
-get_named_tty (const char *name)
-{
-  struct terminal *t;
-
-  eassert (name);
-
-  for (t = terminal_list; t; t = t->next_terminal)
-    {
-      if ((t->type == output_termcap || t->type == output_msdos_raw)
-          && !strcmp (t->display_info.tty->name, name)
-          && TERMINAL_ACTIVE_P (t))
-        return t;
-    }
-
-  return 0;
-}
-
-\f
 DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
        doc: /* Return the type of the tty device that TERMINAL uses.
 Returns nil if TERMINAL is not on a tty device.
@@ -2198,15 +2160,10 @@ TERMINAL can be a terminal object, a frame, or nil (meaning the
 selected frame's terminal).  */)
   (Lisp_Object terminal)
 {
-  struct terminal *t = get_terminal (terminal, 1);
+  struct terminal *t = decode_tty_terminal (terminal);
 
-  if (t->type != output_termcap && t->type != output_msdos_raw)
-    return Qnil;
-
-  if (t->display_info.tty->type)
-    return build_string (t->display_info.tty->type);
-  else
-    return Qnil;
+  return (t && t->display_info.tty->type
+         ? build_string (t->display_info.tty->type) : Qnil);
 }
 
 DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
@@ -2217,13 +2174,9 @@ selected frame's terminal).  This function always returns nil if
 TERMINAL is not on a tty device.  */)
   (Lisp_Object terminal)
 {
-  struct terminal *t = get_terminal (terminal, 1);
+  struct terminal *t = decode_tty_terminal (terminal);
 
-  if ((t->type != output_termcap && t->type != output_msdos_raw)
-      || strcmp (t->display_info.tty->name, DEV_TTY) != 0)
-    return Qnil;
-  else
-    return Qt;
+  return (t && !strcmp (t->display_info.tty->name, DEV_TTY) ? Qt : Qnil);
 }
 
 DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
@@ -2237,7 +2190,7 @@ selected frame's terminal).  This function always returns nil if
 TERMINAL does not refer to a text terminal.  */)
   (Lisp_Object terminal)
 {
-  struct terminal *t = get_terminal (terminal, 1);
+  struct terminal *t = decode_live_terminal (terminal);
 
   if (t->type == output_termcap)
     t->display_info.tty->TS_enter_underline_mode = 0;
@@ -2252,7 +2205,7 @@ does not refer to a text terminal.  Otherwise, it returns the
 top-most frame on the text terminal.  */)
   (Lisp_Object terminal)
 {
-  struct terminal *t = get_terminal (terminal, 1);
+  struct terminal *t = decode_live_terminal (terminal);
 
   if (t->type == output_termcap)
     return t->display_info.tty->top_frame;
@@ -2282,11 +2235,11 @@ suspended.
 A suspended tty may be resumed by calling `resume-tty' on it.  */)
   (Lisp_Object tty)
 {
-  struct terminal *t = get_tty_terminal (tty, 1);
+  struct terminal *t = decode_tty_terminal (tty);
   FILE *f;
 
   if (!t)
-    error ("Unknown tty device");
+    error ("Attempt to suspend a non-text terminal device");
 
   f = t->display_info.tty->input;
 
@@ -2295,10 +2248,9 @@ A suspended tty may be resumed by calling `resume-tty' on it.  */)
       /* First run `suspend-tty-functions' and then clean up the tty
         state because `suspend-tty-functions' might need to change
         the tty state.  */
-      Lisp_Object args[2];
-      args[0] = intern ("suspend-tty-functions");
-      XSETTERMINAL (args[1], t);
-      Frun_hook_with_args (2, args);
+      Lisp_Object term;
+      XSETTERMINAL (term, t);
+      CALLN (Frun_hook_with_args, intern ("suspend-tty-functions"), term);
 
       reset_sys_modes (t->display_info.tty);
       delete_keyboard_wait_descriptor (fileno (f));
@@ -2342,15 +2294,15 @@ TTY may be a terminal object, a frame, or nil (meaning the selected
 frame's terminal). */)
   (Lisp_Object tty)
 {
-  struct terminal *t = get_tty_terminal (tty, 1);
+  struct terminal *t = decode_tty_terminal (tty);
   int fd;
 
   if (!t)
-    error ("Unknown tty device");
+    error ("Attempt to resume a non-text terminal device");
 
   if (!t->display_info.tty->input)
     {
-      if (get_named_tty (t->display_info.tty->name))
+      if (get_named_terminal (t->display_info.tty->name))
         error ("Cannot resume display while another display is active on the same device");
 
 #ifdef MSDOS
@@ -2381,26 +2333,24 @@ frame's terminal). */)
          struct frame *f = XFRAME (t->display_info.tty->top_frame);
          int width, height;
          int old_height = FRAME_COLS (f);
-         int old_width = FRAME_LINES (f);
+         int old_width = FRAME_TOTAL_LINES (f);
 
          /* Check if terminal/window size has changed while the frame
             was suspended.  */
          get_tty_size (fileno (t->display_info.tty->input), &width, &height);
          if (width != old_width || height != old_height)
-           change_frame_size (f, width, height, 0, 0, 0, 0);
+           change_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f),
+                              0, 0, 0, 0);
          SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
        }
 
       set_tty_hooks (t);
       init_sys_modes (t->display_info.tty);
 
-      {
-        /* Run `resume-tty-functions'.  */
-        Lisp_Object args[2];
-        args[0] = intern ("resume-tty-functions");
-        XSETTERMINAL (args[1], t);
-        Frun_hook_with_args (2, args);
-      }
+      /* Run `resume-tty-functions'.  */
+      Lisp_Object term;
+      XSETTERMINAL (term, t);
+      CALLN (Frun_hook_with_args, intern ("resume-tty-functions"), term);
     }
 
   set_tty_hooks (t);
@@ -2515,7 +2465,7 @@ term_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
   (*fp)->mouse_moved = 0;
 
   *bar_window = Qnil;
-  *part = 0;
+  *part = scroll_bar_above_handle;
 
   XSETINT (*x, last_mouse_x);
   XSETINT (*y, last_mouse_y);
@@ -2748,12 +2698,6 @@ static const char *menu_help_message, *prev_menu_help_message;
    last menu help message.  */
 static int menu_help_paneno, menu_help_itemno;
 
-static Lisp_Object Qtty_menu_navigation_map, Qtty_menu_exit;
-static Lisp_Object Qtty_menu_prev_item, Qtty_menu_next_item;
-static Lisp_Object Qtty_menu_next_menu, Qtty_menu_prev_menu;
-static Lisp_Object Qtty_menu_select, Qtty_menu_ignore;
-static Lisp_Object Qtty_menu_mouse_movement;
-
 typedef struct tty_menu_struct
 {
   int count;
@@ -2870,7 +2814,7 @@ tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
   /* Don't try to display more menu items than the console can display
      using the available screen lines.  Exclude the echo area line, as
      it will be overwritten by the help-echo anyway.  */
-  int max_items = min (menu->count - first_item, FRAME_LINES (sf) - 1 - y);
+  int max_items = min (menu->count - first_item, FRAME_TOTAL_LINES (sf) - 1 - y);
 
   menu_help_message = NULL;
 
@@ -2918,7 +2862,6 @@ static int
 tty_menu_add_pane (tty_menu *menu, const char *txt)
 {
   int len;
-  const unsigned char *p;
 
   tty_menu_make_room (menu);
   menu->submenu[menu->count] = tty_menu_create ();
@@ -2928,15 +2871,7 @@ tty_menu_add_pane (tty_menu *menu, const char *txt)
   menu->count++;
 
   /* Update the menu width, if necessary.  */
-  for (len = 0, p = (unsigned char *) txt; *p; )
-    {
-      int ch_len;
-      int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
-
-      len += CHAR_WIDTH (ch);
-      p += ch_len;
-    }
-
+  len = menu_item_width ((const unsigned char *) txt);
   if (len > menu->width)
     menu->width = len;
 
@@ -2950,7 +2885,6 @@ tty_menu_add_selection (tty_menu *menu, int pane,
                        char *txt, bool enable, char const *help_text)
 {
   int len;
-  unsigned char *p;
 
   if (pane)
     {
@@ -2966,15 +2900,7 @@ tty_menu_add_selection (tty_menu *menu, int pane,
   menu->count++;
 
   /* Update the menu width, if necessary.  */
-  for (len = 0, p = (unsigned char *) txt; *p; )
-    {
-      int ch_len;
-      int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
-
-      len += CHAR_WIDTH (ch);
-      p += ch_len;
-    }
-
+  len = menu_item_width ((const unsigned char *) txt);
   if (len > menu->width)
     menu->width = len;
 
@@ -3184,6 +3110,8 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
   Lisp_Object selectface;
   int first_item = 0;
   int col, row;
+  Lisp_Object prev_inhibit_redisplay = Vinhibit_redisplay;
+  USE_SAFE_ALLOCA;
 
   /* Don't allow non-positive x0 and y0, lest the menu will wrap
      around the display.  */
@@ -3192,7 +3120,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
   if (y0 <= 0)
     y0 = 1;
 
-  state = alloca (menu->panecount * sizeof (struct tty_menu_state));
+  SAFE_NALLOCA (state, 1, menu->panecount);
   memset (state, 0, sizeof (*state));
   faces[0]
     = lookup_derived_face (sf, intern ("tty-menu-disabled-face"),
@@ -3225,6 +3153,11 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
       buffers_num_deleted = 1;
     }
 
+  /* Inhibit redisplay for as long as the menu is active, to avoid
+     messing the screen if some timer calls sit-for or a similar
+     function.  */
+  Vinhibit_redisplay = Qt;
+
   /* Force update of the current frame, so that the desired and the
      current matrices are identical.  */
   update_frame_with_menu (sf, -1, -1);
@@ -3268,7 +3201,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
     {
       mi_result input_status;
       int min_y = state[0].y;
-      int max_y = min (min_y + state[0].menu->count, FRAME_LINES (sf) - 1) - 1;
+      int max_y = min (min_y + state[0].menu->count, FRAME_TOTAL_LINES (sf) - 1) - 1;
 
       input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
       if (input_status)
@@ -3414,6 +3347,8 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
   discard_mouse_events ();
   if (!kbd_buffer_events_waiting ())
     clear_input_pending ();
+  SAFE_FREE ();
+  Vinhibit_redisplay = prev_inhibit_redisplay;
   return result;
 }
 
@@ -3468,9 +3403,11 @@ static void
 tty_pop_down_menu (Lisp_Object arg)
 {
   tty_menu *menu = XSAVE_POINTER (arg, 0);
+  struct buffer *orig_buffer = XSAVE_POINTER (arg, 1);
 
   block_input ();
   tty_menu_destroy (menu);
+  set_buffer_internal (orig_buffer);
   unblock_input ();
 }
 
@@ -3555,9 +3492,10 @@ tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
     }
 }
 
+/* WINDOWSNT uses this as menu_show_hook, see w32console.c.  */
 Lisp_Object
-tty_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
-              Lisp_Object title, bool kbd_navigation, const char **error_name)
+tty_menu_show (struct frame *f, int x, int y, int menuflags,
+              Lisp_Object title, const char **error_name)
 {
   tty_menu *menu;
   int pane, selidx, lpane, status;
@@ -3584,21 +3522,21 @@ tty_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
 
   /* Make the menu on that window.  */
   menu = tty_menu_create ();
-  if (menu == NULL)
-    {
-      *error_name = "Can't create menu";
-      return Qnil;
-    }
 
   /* Don't GC while we prepare and show the menu, because we give the
      menu functions pointers to the contents of strings.  */
   specpdl_count = inhibit_garbage_collection ();
 
+  /* Avoid crashes if, e.g., another client will connect while we
+     are in a menu.  */
+  temporarily_switch_to_single_kboard (f);
+
   /* Adjust coordinates to be root-window-relative.  */
   item_x = x += f->left_pos;
   item_y = y += f->top_pos;
 
   /* Create all the necessary panes and their items.  */
+  USE_SAFE_ALLOCA;
   maxwidth = maxlines = lines = i = 0;
   lpane = TTYM_FAILURE;
   while (i < menu_items_used)
@@ -3615,7 +3553,7 @@ tty_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
          prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
          pane_string = (NILP (pane_name)
                         ? "" : SSDATA (pane_name));
-         if (keymaps && !NILP (prefix))
+         if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
            pane_string++;
 
          lpane = tty_menu_add_pane (menu, pane_string);
@@ -3667,9 +3605,7 @@ tty_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
 
          if (!NILP (descrip))
            {
-             /* If alloca is fast, use that to make the space,
-                to reduce gc needs.  */
-             item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1);
+             item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
              memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
              for (j = SCHARS (item_name); j < maxwidth; j++)
                item_data[j] = ' ';
@@ -3750,12 +3686,16 @@ tty_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
 
   pane = selidx = 0;
 
-  record_unwind_protect (tty_pop_down_menu, make_save_ptr (menu));
+  /* We save and restore the current buffer because tty_menu_activate
+     triggers redisplay, which switches buffers at will.  */
+  record_unwind_protect (tty_pop_down_menu,
+                        make_save_ptr_ptr (menu, current_buffer));
 
   specbind (Qoverriding_terminal_local_map,
            Fsymbol_value (Qtty_menu_navigation_map));
   status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
-                             tty_menu_help_callback, kbd_navigation);
+                             tty_menu_help_callback,
+                             menuflags & MENU_KBD_NAVIGATION);
   entry = pane_prefix = Qnil;
 
   switch (status)
@@ -3781,7 +3721,7 @@ tty_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
                    {
                      entry
                        = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
-                     if (keymaps != 0)
+                     if (menuflags & MENU_KEYMAPS)
                        {
                          entry = Fcons (entry, Qnil);
                          if (!NILP (pane_prefix))
@@ -3814,13 +3754,14 @@ tty_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
        Ftop_level ();
       /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
         the menu was invoked with a mouse event as POSITION).  */
-      if (! for_click)
+      if (!(menuflags & MENU_FOR_CLICK))
         Fsignal (Qquit, Qnil);
       break;
     }
 
  tty_menu_end:
 
+  SAFE_FREE ();
   unbind_to (specpdl_count, Qnil);
   return entry;
 }
@@ -3895,7 +3836,9 @@ clear_tty_hooks (struct terminal *terminal)
   terminal->frame_rehighlight_hook = 0;
   terminal->frame_raise_lower_hook = 0;
   terminal->fullscreen_hook = 0;
+  terminal->menu_show_hook = 0;
   terminal->set_vertical_scroll_bar_hook = 0;
+  terminal->set_horizontal_scroll_bar_hook = 0;
   terminal->condemn_scroll_bars_hook = 0;
   terminal->redeem_scroll_bar_hook = 0;
   terminal->judge_scroll_bars_hook = 0;
@@ -3913,43 +3856,29 @@ clear_tty_hooks (struct terminal *terminal)
 static void
 set_tty_hooks (struct terminal *terminal)
 {
-  terminal->rif = 0; /* ttys don't support window-based redisplay. */
-
   terminal->cursor_to_hook = &tty_cursor_to;
   terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
-
   terminal->clear_to_end_hook = &tty_clear_to_end;
   terminal->clear_frame_hook = &tty_clear_frame;
   terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
-
   terminal->ins_del_lines_hook = &tty_ins_del_lines;
-
   terminal->insert_glyphs_hook = &tty_insert_glyphs;
   terminal->write_glyphs_hook = &tty_write_glyphs;
   terminal->delete_glyphs_hook = &tty_delete_glyphs;
-
   terminal->ring_bell_hook = &tty_ring_bell;
-
   terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
   terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
-  terminal->update_begin_hook = 0; /* Not needed. */
   terminal->update_end_hook = &tty_update_end;
+#ifdef MSDOS
+  terminal->menu_show_hook = &x_menu_show;
+#else
+  terminal->menu_show_hook = &tty_menu_show;
+#endif
   terminal->set_terminal_window_hook = &tty_set_terminal_window;
-
-  terminal->mouse_position_hook = 0; /* Not needed. */
-  terminal->frame_rehighlight_hook = 0; /* Not needed. */
-  terminal->frame_raise_lower_hook = 0; /* Not needed. */
-
-  terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */
-  terminal->condemn_scroll_bars_hook = 0; /* Not needed. */
-  terminal->redeem_scroll_bar_hook = 0; /* Not needed. */
-  terminal->judge_scroll_bars_hook = 0; /* Not needed. */
-
   terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
-  terminal->frame_up_to_date_hook = 0; /* Not needed. */
-
   terminal->delete_frame_hook = &tty_free_frame_resources;
   terminal->delete_terminal_hook = &delete_tty;
+  /* Other hooks are NULL by default.  */
 }
 
 /* If FD is the controlling terminal, drop it.  */
@@ -3964,9 +3893,10 @@ dissociate_if_controlling_tty (int fd)
       /* setsid failed, presumably because Emacs is already a process
         group leader.  Fall back on the obsolescent way to dissociate
         a controlling tty.  */
-      block_tty_out_signal ();
+      sigset_t oldset;
+      block_tty_out_signal (&oldset);
       ioctl (fd, TIOCNOTTY, 0);
-      unblock_tty_out_signal ();
+      unblock_tty_out_signal (&oldset);
 #endif
     }
 }
@@ -3990,6 +3920,7 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
   int status;
   struct tty_display_info *tty = NULL;
   struct terminal *terminal = NULL;
+  sigset_t oldset;
   bool ctty = false;  /* True if asked to open controlling tty.  */
 
   if (!terminal_type)
@@ -4007,11 +3938,11 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
   /* XXX Perhaps this should be made explicit by having init_tty
      always create a new terminal and separating terminal and frame
      creation on Lisp level.  */
-  terminal = get_named_tty (name);
+  terminal = get_named_terminal (name);
   if (terminal)
     return terminal;
 
-  terminal = create_terminal ();
+  terminal = create_terminal (output_termcap, NULL);
 #ifdef MSDOS
   if (been_here > 0)
     maybe_fatal (0, 0, "Attempt to create another terminal %s", "",
@@ -4025,7 +3956,6 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
   tty->next = tty_list;
   tty_list = tty;
 
-  terminal->type = output_termcap;
   terminal->display_info.tty = tty;
   tty->terminal = terminal;
 
@@ -4051,12 +3981,15 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
        open a frame on the same terminal.  */
     int flags = O_RDWR | O_NOCTTY | (ctty ? 0 : O_IGNORE_CTTY);
     int fd = emacs_open (name, flags, 0);
-    tty->input = tty->output = fd < 0 || ! isatty (fd) ? 0 : fdopen (fd, "w+");
+    tty->input = tty->output
+      = ((fd < 0 || ! isatty (fd))
+        ? NULL
+        : fdopen (fd, "w+"));
 
     if (! tty->input)
       {
        char const *diagnostic
-         = tty->input ? "Not a tty device: %s" : "Could not open file: %s";
+         = (fd < 0) ? "Could not open file: %s" : "Not a tty device: %s";
        emacs_close (fd);
        maybe_fatal (must_succeed, terminal, diagnostic, diagnostic, name);
       }
@@ -4076,11 +4009,11 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
 
   /* On some systems, tgetent tries to access the controlling
      terminal.  */
-  block_tty_out_signal ();
+  block_tty_out_signal (&oldset);
   status = tgetent (tty->termcap_term_buffer, terminal_type);
   if (tty->termcap_term_buffer[TERMCAP_BUFFER_SIZE - 1])
     emacs_abort ();
-  unblock_tty_out_signal ();
+  unblock_tty_out_signal (&oldset);
 
   if (status < 0)
     {
@@ -4100,12 +4033,12 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
                    "Terminal type %s is not defined",
                    "Terminal type %s is not defined.\n\
 If that is not the actual type of terminal you have,\n\
-use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
-`setenv TERM ...') to specify the correct type.  It may be necessary\n"
+use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\
+'setenv TERM ...') to specify the correct type.  It may be necessary\n"
 #ifdef TERMINFO
-"to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
+"to do 'unset TERMINFO' (C-shell: 'unsetenv TERMINFO') as well.",
 #else
-"to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
+"to do 'unset TERMCAP' (C-shell: 'unsetenv TERMCAP') as well.",
 #endif
                    terminal_type);
     }
@@ -4231,6 +4164,7 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
     tty->specified_window = height;
 
     FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
+    FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) = 0;
     tty->char_ins_del_ok = 1;
     baud_rate = 19200;
   }
@@ -4378,12 +4312,12 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
                    "Terminal type \"%s\" is not powerful enough to run Emacs.\n\
 It lacks the ability to position the cursor.\n\
 If that is not the actual type of terminal you have,\n\
-use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
-`setenv TERM ...') to specify the correct type.  It may be necessary\n"
+use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\
+'setenv TERM ...') to specify the correct type.  It may be necessary\n"
 # ifdef TERMINFO
-"to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
+"to do 'unset TERMINFO' (C-shell: 'unsetenv TERMINFO') as well.",
 # else /* TERMCAP */
-"to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
+"to do 'unset TERMCAP' (C-shell: 'unsetenv TERMCAP') as well.",
 # endif /* TERMINFO */
                    terminal_type);
     }
@@ -4466,7 +4400,7 @@ fatal (const char *str, ...)
 
 \f
 
-/* Delete the given tty terminal, closing all frames on it. */
+/* Delete the given tty terminal, closing all frames on it.  */
 
 static void
 delete_tty (struct terminal *terminal)
@@ -4491,7 +4425,7 @@ delete_tty (struct terminal *terminal)
         ;
 
       if (! p)
-        /* This should not happen. */
+        /* This should not happen.  */
         emacs_abort ();
 
       p->next = tty->next;
@@ -4499,7 +4433,7 @@ delete_tty (struct terminal *terminal)
     }
 
   /* reset_sys_modes needs a valid device, so this call needs to be
-     before delete_terminal. */
+     before delete_terminal.  */
   reset_sys_modes (tty);
 
   delete_terminal (terminal);
@@ -4577,6 +4511,9 @@ bigger, or it may make it blink, or it may do nothing at all.  */);
   encode_terminal_src = NULL;
   encode_terminal_dst = NULL;
 
+  DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings");
+  DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings");
+
 #ifndef MSDOS
   DEFSYM (Qtty_menu_next_item, "tty-menu-next-item");
   DEFSYM (Qtty_menu_prev_item, "tty-menu-prev-item");