]> code.delx.au - gnu-emacs/blobdiff - src/term.c
Merge from trunk after a lot of time.
[gnu-emacs] / src / term.c
index f66a0bddc334693e1295c18440bde03c456cb8a8..73d7585e8f56d79aa0aeb897a6783a13895ea781 100644 (file)
@@ -56,6 +56,8 @@ static int been_here = -1;
 #include "xterm.h"
 #endif
 
+#include "menu.h"
+
 /* The name of the default console device.  */
 #ifdef WINDOWSNT
 #define DEV_TTY  "CONOUT$"
@@ -71,13 +73,13 @@ 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, int);
+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);
 static void delete_tty (struct terminal *);
-static _Noreturn void maybe_fatal (int must_succeed, struct terminal *terminal,
-                                  const char *str1, const char *str2, ...)
+static _Noreturn void maybe_fatal (bool, struct terminal *,
+                                  const char *, const char *, ...)
   ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5);
 static _Noreturn void vfatal (const char *str, va_list ap)
   ATTRIBUTE_FORMAT_PRINTF (1, 0);
@@ -85,8 +87,7 @@ static _Noreturn void vfatal (const char *str, va_list ap)
 
 #define OUTPUT(tty, a)                                          \
   emacs_tputs ((tty), a,                                        \
-               (int) (FRAME_LINES (XFRAME (selected_frame))     \
-                      - curY (tty)),                            \
+               FRAME_LINES (XFRAME (selected_frame)) - curY (tty),     \
                cmputc)
 
 #define OUTPUT1(tty, a) emacs_tputs ((tty), a, 1, cmputc)
@@ -695,7 +696,7 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len)
 {
   unsigned char *conversion_buffer;
   struct coding_system *coding;
-  size_t n, stringlen;
+  int n, stringlen;
 
   struct tty_display_info *tty = FRAME_TTY (f);
 
@@ -1321,7 +1322,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 < (sizeof (keys) / sizeof (keys[0])); i++)
     {
       char *sequence = tgetstr (keys[i].cap, address);
       if (sequence)
@@ -1431,7 +1432,7 @@ static void append_glyph (struct it *);
 static void append_composite_glyph (struct it *);
 static void produce_composite_glyph (struct it *);
 static void append_glyphless_glyph (struct it *, int, const char *);
-static void produce_glyphless_glyph (struct it *, int, Lisp_Object);
+static void produce_glyphless_glyph (struct it *, Lisp_Object);
 
 /* Append glyphs to IT's glyph_row.  Called from produce_glyphs for
    terminal frames if IT->glyph_row != NULL.  IT->char_to_display is
@@ -1551,7 +1552,7 @@ produce_glyphs (struct it *it)
 
   if (it->what == IT_GLYPHLESS)
     {
-      produce_glyphless_glyph (it, 0, Qnil);
+      produce_glyphless_glyph (it, Qnil);
       goto done;
     }
 
@@ -1620,7 +1621,7 @@ produce_glyphs (struct it *it)
          Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
 
          eassert (it->what == IT_GLYPHLESS);
-         produce_glyphless_glyph (it, 1, acronym);
+         produce_glyphless_glyph (it, acronym);
        }
     }
 
@@ -1794,14 +1795,12 @@ append_glyphless_glyph (struct it *it, int face_id, const char *str)
    the character.  See the description of enum
    glyphless_display_method in dispextern.h for the details.
 
-   FOR_NO_FONT is nonzero if and only if this is for a character that
-   is not supported by the coding system of the terminal.  ACRONYM, if
-   non-nil, is an acronym string for the character.
+   ACRONYM, if non-nil, is an acronym string for the character.
 
    The glyphs actually produced are of type CHAR_GLYPH.  */
 
 static void
-produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
+produce_glyphless_glyph (struct it *it, Lisp_Object acronym)
 {
   int face_id;
   int len;
@@ -1968,7 +1967,7 @@ turn_on_face (struct frame *f, int face_id)
       ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
       if (fg >= 0 && ts)
        {
-          p = tparam (ts, NULL, 0, (int) fg, 0, 0, 0);
+          p = tparam (ts, NULL, 0, fg, 0, 0, 0);
          OUTPUT (tty, p);
          xfree (p);
        }
@@ -1976,7 +1975,7 @@ turn_on_face (struct frame *f, int face_id)
       ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
       if (bg >= 0 && ts)
        {
-          p = tparam (ts, NULL, 0, (int) bg, 0, 0, 0);
+          p = tparam (ts, NULL, 0, bg, 0, 0, 0);
          OUTPUT (tty, p);
          xfree (p);
        }
@@ -2027,11 +2026,11 @@ turn_off_face (struct frame *f, int face_id)
 }
 
 
-/* Return non-zero if the terminal on frame F supports all of the
+/* Return true if the terminal on frame F supports all of the
    capabilities in CAPS simultaneously, with foreground and background
    colors FG and BG.  */
 
-int
+bool
 tty_capable_p (struct tty_display_info *tty, unsigned int caps,
               unsigned long fg, unsigned long bg)
 {
@@ -2099,7 +2098,7 @@ static char *default_set_background;
 /* Save or restore the default color-related capabilities of this
    terminal.  */
 static void
-tty_default_color_capabilities (struct tty_display_info *tty, int save)
+tty_default_color_capabilities (struct tty_display_info *tty, bool save)
 {
 
   if (save)
@@ -2209,7 +2208,7 @@ set_tty_color_mode (struct tty_display_info *tty, struct frame *f)
 /* Return the tty display object specified by TERMINAL. */
 
 static struct terminal *
-get_tty_terminal (Lisp_Object terminal, int throw)
+get_tty_terminal (Lisp_Object terminal, bool throw)
 {
   struct terminal *t = get_terminal (terminal, throw);
 
@@ -2236,8 +2235,7 @@ get_named_tty (const char *name)
 {
   struct terminal *t;
 
-  if (!name)
-    emacs_abort ();
+  eassert (name);
 
   for (t = terminal_list; t; t = t->next_terminal)
     {
@@ -2374,7 +2372,7 @@ A suspended tty may be resumed by calling `resume-tty' on it.  */)
       t->display_info.tty->output = 0;
 
       if (FRAMEP (t->display_info.tty->top_frame))
-        FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
+        SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0);
 
     }
 
@@ -2419,15 +2417,20 @@ frame's terminal). */)
       t->display_info.tty->input  = stdin;
 #else  /* !MSDOS */
       fd = emacs_open (t->display_info.tty->name, O_RDWR | O_NOCTTY, 0);
+      t->display_info.tty->input = t->display_info.tty->output
+       = fd < 0 ? 0 : fdopen (fd, "w+");
 
-      if (fd == -1)
-        error ("Can not reopen tty device %s: %s", t->display_info.tty->name, strerror (errno));
+      if (! t->display_info.tty->input)
+       {
+         int open_errno = errno;
+         emacs_close (fd);
+         report_file_errno ("Cannot reopen tty device",
+                            build_string (t->display_info.tty->name),
+                            open_errno);
+       }
 
       if (!O_IGNORE_CTTY && strcmp (t->display_info.tty->name, DEV_TTY) != 0)
         dissociate_if_controlling_tty (fd);
-
-      t->display_info.tty->output = fdopen (fd, "w+");
-      t->display_info.tty->input = t->display_info.tty->output;
 #endif
 
       add_keyboard_wait_descriptor (fd);
@@ -2444,7 +2447,7 @@ frame's terminal). */)
          get_tty_size (fileno (t->display_info.tty->input), &width, &height);
          if (width != old_width || height != old_height)
            change_frame_size (f, height, width, 0, 0, 0);
-         FRAME_SET_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
+         SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
        }
 
       set_tty_hooks (t);
@@ -2479,9 +2482,9 @@ term_mouse_moveto (int x, int y)
   const char *name;
   int fd;
   name = (const char *) ttyname (0);
-  fd = open (name, O_WRONLY);
+  fd = emacs_open (name, O_WRONLY, 0);
      SOME_FUNCTION (x, y, fd);
-  close (fd);
+  emacs_close (fd);
   last_mouse_x = x;
   last_mouse_y = y;  */
 }
@@ -2519,8 +2522,8 @@ tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
   cursor_to (f, save_y, save_x);
 }
 
-static int
-term_mouse_movement (FRAME_PTR frame, Gpm_Event *event)
+static bool
+term_mouse_movement (struct frame *frame, Gpm_Event *event)
 {
   /* Has the mouse moved off the glyph it was on at the last sighting?  */
   if (event->x != last_mouse_x || event->y != last_mouse_y)
@@ -2561,7 +2564,7 @@ timeval_to_Time (struct timeval const *t)
    This clears mouse_moved until the next motion
    event arrives.  */
 static void
-term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window,
+term_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
                     enum scroll_bar_part *part, Lisp_Object *x,
                     Lisp_Object *y, Time *timeptr)
 {
@@ -2649,7 +2652,7 @@ handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event, struct in
 {
   struct frame *f = XFRAME (tty->top_frame);
   struct input_event ie;
-  int do_help = 0;
+  bool do_help = 0;
   int count = 0;
 
   EVENT_INIT (ie);
@@ -2770,6 +2773,932 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
 }
 #endif /* HAVE_GPM */
 
+\f
+/***********************************************************************
+                              Menus
+ ***********************************************************************/
+
+#if defined (HAVE_MENUS) && !defined (MSDOS)
+
+/* TTY menu implementation and main ideas are borrowed from msdos.c.
+
+   However, unlike on MSDOS, where the menu text is drawn directly to
+   the screen, on a TTY we use display_string (see xdisp.c) to put the
+   glyphs produced from the menu items into the desired_matrix glyph
+   matrix, and then call update_frame to deliver the results to the
+   glass.  The previous contents of the screen, in the form of the
+   current_matrix, is stashed away, and used to restore screen
+   contents when the menu selection changes or when the final
+   selection is made and the menu should be popped down.
+
+   The idea of this implementation was suggested by Gerd Moellmann.  */
+
+#define TTYM_FAILURE -1
+#define TTYM_SUCCESS 1
+#define TTYM_NO_SELECT 2
+#define TTYM_IA_SELECT 3
+
+/* These hold text of the current and the previous menu help messages.  */
+static const char *menu_help_message, *prev_menu_help_message;
+/* Pane number and item number of the menu item which generated the
+   last menu help message.  */
+static int menu_help_paneno, menu_help_itemno;
+
+typedef struct tty_menu_struct
+{
+  int count;
+  char **text;
+  struct tty_menu_struct **submenu;
+  int *panenumber; /* Also used as enable.  */
+  int allocated;
+  int panecount;
+  int width;
+  const char **help_text;
+} tty_menu;
+
+/* Create a brand new menu structure.  */
+
+static tty_menu *
+tty_menu_create (void)
+{
+  tty_menu *menu;
+
+  menu = (tty_menu *) xmalloc (sizeof (tty_menu));
+  menu->allocated = menu->count = menu->panecount = menu->width = 0;
+  return menu;
+}
+
+/* Allocate some (more) memory for MENU ensuring that there is room for one
+   for item.  */
+
+static void
+tty_menu_make_room (tty_menu *menu)
+{
+  if (menu->allocated == 0)
+    {
+      int count = menu->allocated = 10;
+      menu->text = (char **) xmalloc (count * sizeof (char *));
+      menu->submenu = (tty_menu **) xmalloc (count * sizeof (tty_menu *));
+      menu->panenumber = (int *) xmalloc (count * sizeof (int));
+      menu->help_text = (const char **) xmalloc (count * sizeof (char *));
+    }
+  else if (menu->allocated == menu->count)
+    {
+      int count = menu->allocated = menu->allocated + 10;
+      menu->text
+       = (char **) xrealloc (menu->text, count * sizeof (char *));
+      menu->submenu
+       = (tty_menu **) xrealloc (menu->submenu, count * sizeof (tty_menu *));
+      menu->panenumber
+       = (int *) xrealloc (menu->panenumber, count * sizeof (int));
+      menu->help_text
+       = (const char **) xrealloc (menu->help_text, count * sizeof (char *));
+    }
+}
+
+/* Search the given menu structure for a given pane number.  */
+
+static tty_menu *
+tty_menu_search_pane (tty_menu *menu, int pane)
+{
+  int i;
+  tty_menu *try;
+
+  for (i = 0; i < menu->count; i++)
+    if (menu->submenu[i])
+      {
+       if (pane == menu->panenumber[i])
+         return menu->submenu[i];
+       if ((try = tty_menu_search_pane (menu->submenu[i], pane)))
+         return try;
+      }
+  return (tty_menu *) 0;
+}
+
+/* Determine how much screen space a given menu needs.  */
+
+static void
+tty_menu_calc_size (tty_menu *menu, int *width, int *height)
+{
+  int i, h2, w2, maxsubwidth, maxheight;
+
+  maxsubwidth = 0;
+  maxheight = menu->count;
+  for (i = 0; i < menu->count; i++)
+    {
+      if (menu->submenu[i])
+       {
+         tty_menu_calc_size (menu->submenu[i], &w2, &h2);
+         if (w2 > maxsubwidth) maxsubwidth = w2;
+         if (i + h2 > maxheight) maxheight = i + h2;
+       }
+    }
+  *width = menu->width + maxsubwidth;
+  *height = maxheight;
+}
+
+/* Display MENU at (X,Y) using FACES.  */
+
+static void
+tty_menu_display (tty_menu *menu, int y, int x, int pn, int *faces,
+                 int disp_help)
+{
+  int i, face, width,  mx = -1, my = -1, enabled, mousehere, row, col;
+  struct frame *sf = SELECTED_FRAME ();
+  struct tty_display_info *tty = FRAME_TTY (sf);
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
+  Lisp_Object lmx, lmy, lisp_dummy;
+  enum scroll_bar_part part_dummy;
+  Time time_dummy;
+
+  if (FRAME_TERMINAL (sf)->mouse_position_hook)
+    (*FRAME_TERMINAL (sf)->mouse_position_hook) (&sf, -1,
+                                                 &lispy_dummy, &party_dummy,
+                                                &lmx, &lmy,
+                                                &time_dummy);
+  if (!NILP (lmx))
+    {
+      mx = XINT (lmx);
+      my = XINT (lmy);
+    }
+  else
+    {
+      mx = x;
+      my = y;
+    }
+#else
+  /* FIXME: need to set mx and my from cursor movement commands.  */
+  mx = x;
+  my = y;
+#endif
+
+  menu_help_message = NULL;
+
+  width = menu->width;
+  col = curX (tty);
+  row = curY (tty);
+#if 0
+  IT_update_begin (sf);                /* FIXME: do we need an update_begin_hook? */
+#endif
+  for (i = 0; i < menu->count; i++)
+    {
+      int max_width = width + 2;
+
+      cursor_to (sf, y + i, x);
+      enabled
+       = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
+      mousehere = (y + i == my && x <= mx && mx < x + max_width);
+      face = faces[enabled + mousehere * 2];
+      /* Display the menu help string for the i-th menu item even if
+        the menu item is currently disabled.  That's what the GUI
+        code does.  */
+      if (disp_help && enabled + mousehere * 2 >= 2)
+       {
+         menu_help_message = menu->help_text[i];
+         menu_help_paneno = pn - 1;
+         menu_help_itemno = i;
+       }
+      display_tty_menu_item (menu->text[i], face, y + i, x,
+                            menu->submenu[i] != NULL);
+    }
+  update_frame_with_menu (sf);
+  cursor_to (sf, row, col);
+}
+
+/* --------------------------- X Menu emulation ---------------------- */
+
+/* Report availability of menus.  */
+
+int
+have_menus_p (void) {  return 1; }
+
+/* Create a new pane and place it on the outer-most level.  */
+
+int
+tty_menu_add_pane (Display *foo, tty_menu *menu, const char *txt)
+{
+  int len;
+  const char *p;
+
+  tty_menu_make_room (menu);
+  menu->submenu[menu->count] = tty_menu_create ();
+  menu->text[menu->count] = (char *)txt;
+  menu->panenumber[menu->count] = ++menu->panecount;
+  menu->help_text[menu->count] = NULL;
+  menu->count++;
+
+  /* Update the menu width, if necessary.  */
+  for (len = 0, p = txt; *p; )
+    {
+      int ch_len;
+      int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
+
+      len += CHAR_WIDTH (ch);
+      p += ch_len;
+    }
+
+  if (len > menu->width)
+    menu->width = len;
+
+  return menu->panecount;
+}
+
+/* Create a new item in a menu pane.  */
+
+int
+tty_menu_add_selection (tty_menu *menu, int pane,
+                       char *txt, int enable, char const *help_text)
+{
+  int len;
+  char *p;
+
+  if (pane)
+    if (!(menu = tty_menu_search_pane (menu, pane)))
+      return TTYM_FAILURE;
+  tty_menu_make_room (menu);
+  menu->submenu[menu->count] = (tty_menu *) 0;
+  menu->text[menu->count] = txt;
+  menu->panenumber[menu->count] = enable;
+  menu->help_text[menu->count] = help_text;
+  menu->count++;
+
+  /* Update the menu width, if necessary.  */
+  for (len = 0, p = txt; *p; )
+    {
+      int ch_len;
+      int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
+
+      len += CHAR_WIDTH (ch);
+      p += ch_len;
+    }
+
+  if (len > menu->width)
+    menu->width = len;
+
+  return TTYM_SUCCESS;
+}
+
+/* Decide where the menu would be placed if requested at (X,Y).  */
+
+void
+tty_menu_locate (tty_menu *menu, int x, int y,
+                int *ulx, int *uly, int *width, int *height)
+{
+  tty_menu_calc_size (menu, width, height);
+  *ulx = x + 1;
+  *uly = y;
+  *width += 2;
+}
+
+struct tty_menu_state
+{
+  struct glyph_matrix *screen_behind;
+  tty_menu *menu;
+  int pane;
+  int x, y;
+};
+
+/* Restore the contents of frame F's desired frame matrix from SAVED,
+   and free memory associated with SAVED.  */
+
+static void
+restore_desired_matrix (struct frame *f, struct glyph_matrix *saved)
+{
+  int i;
+
+  for (i = 0; i < saved->nrows; ++i)
+    {
+      struct glyph_row *from = saved->rows + i;
+      struct glyph_row *to = f->desired_matrix->rows + i;
+      ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
+
+      memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
+      to->used[TEXT_AREA] = from->used[TEXT_AREA];
+      xfree (from->glyphs[TEXT_AREA]);
+      nbytes = from->used[LEFT_MARGIN_AREA];
+      if (nbytes)
+       {
+         memcpy (to->glyphs[LEFT_MARGIN_AREA],
+                 from->glyphs[LEFT_MARGIN_AREA], nbytes);
+         to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
+         xfree (from->glyphs[LEFT_MARGIN_AREA]);
+       }
+      else
+       to->used[LEFT_MARGIN_AREA] = 0;
+      nbytes = from->used[RIGHT_MARGIN_AREA];
+      if (nbytes)
+       {
+         memcpy (to->glyphs[RIGHT_MARGIN_AREA],
+                 from->glyphs[RIGHT_MARGIN_AREA], nbytes);
+         to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
+         xfree (from->glyphs[RIGHT_MARGIN_AREA]);
+       }
+      else
+       to->used[RIGHT_MARGIN_AREA] = 0;
+    }
+
+  xfree (saved->rows);
+  xfree (saved);
+}
+
+static void
+free_saved_screen (struct glyph_matrix *saved)
+{
+  int i;
+
+  if (!saved)
+    return;    /* already freed */
+
+  for (i = 0; i < saved->nrows; ++i)
+    {
+      struct glyph_row *from = saved->rows + i;
+
+      xfree (from->glyphs[TEXT_AREA]);
+      nbytes = from->used[LEFT_MARGIN_AREA];
+      if (nbytes)
+       xfree (from->glyphs[LEFT_MARGIN_AREA]);
+      nbytes = from->used[RIGHT_MARGIN_AREA];
+      if (nbytes)
+       xfree (from->glyphs[RIGHT_MARGIN_AREA]);
+    }
+
+  xfree (saved->rows);
+  xfree (saved);
+}
+
+/* Update the display of frame F from its saved contents.  */
+static void
+screen_update (struct frame *f, struct glyph_matrix *mtx)
+{
+  restore_desired_matrix (f, mtx);
+  update_frame_with_menu (f);
+}
+
+/* Read user input and return X and Y coordinates where that input
+   puts us.  We only consider mouse movement and click events and
+   keyboard movement commands; the rest are ignored.  */
+static void
+read_menu_input (int *x, int *y)
+{
+  Lisp_Object c;
+
+  while (1)
+    {
+      do {
+       c = read_char (-2, 0, NULL, Qnil, NULL, NULL);
+      } while (BUFFERP (c) || (INTEGERP (c) && XINT (c) == -2));
+
+      if (INTEGERP (c))
+       {
+         int ch = XINT (c);
+         int usable_input = 1;
+
+         /* FIXME: Exceedingly primitive!  Can we support arrow keys?  */
+         switch (ch && ~CHAR_MODIFIER_MASK)
+           {
+           case 6:     /* ^F */
+             *x += 1;
+             break;
+           case 2:     /* ^B */
+             *x -= 1;
+             break;
+           case 14:    /* ^N */
+             *y += 1;
+             break;
+           case 16:    /* ^P */
+             *y -= 1;
+             break;
+           default:
+             usable_input = 0;
+             break;
+           }
+         if (usable_input)
+           return;
+       }
+
+      else if (EVENT_HAS_PARAMETERS (c))
+       {
+         if (EQ (EVENT_HEAD (c), Qmouse_movement))
+           {
+           }
+         else if (EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_click))
+           {
+           }
+       }
+    }
+}
+
+/* Display menu, wait for user's response, and return that response.  */
+int
+tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
+                  int x0, int y0, char **txt,
+                  void (*help_callback)(char const *, int, int))
+{
+  struct tty_menu_state *state;
+  int statecount, x, y, i, b, screensize, leave, result, onepane;
+  int title_faces[4];          /* face to display the menu title */
+  int faces[4], buffers_num_deleted = 0;
+  struct frame *sf = SELECTED_FRAME ();
+  Lisp_Object saved_echo_area_message, selectface;
+
+  /* Don't allow non-positive x0 and y0, lest the menu will wrap
+     around the display.  */
+  if (x0 <= 0)
+    x0 = 1;
+  if (y0 <= 0)
+    y0 = 1;
+
+  /* We will process all the mouse events directly.  */
+  mouse_preempted++;
+
+  state = alloca (menu->panecount * sizeof (struct tty_menu_state));
+  memset (state, 0, sizeof (*state));
+  screensize = screen_size * 2;
+  faces[0]
+    = lookup_derived_face (sf, intern ("tty-menu-disabled-face"),
+                          DEFAULT_FACE_ID, 1);
+  faces[1]
+    = lookup_derived_face (sf, intern ("tty-menu-enabled-face"),
+                          DEFAULT_FACE_ID, 1);
+  selectface = intern ("tty-menu-selected-face");
+  faces[2] = lookup_derived_face (sf, selectface,
+                                 faces[0], 1);
+  faces[3] = lookup_derived_face (sf, selectface,
+                                 faces[1], 1);
+
+  /* Make sure the menu title is always displayed with
+     `msdos-menu-active-face', no matter where the mouse pointer is.  */
+  for (i = 0; i < 4; i++)
+    title_faces[i] = faces[3];
+
+  statecount = 1;
+
+  /* Don't let the title for the "Buffers" popup menu include a
+     digit (which is ugly).
+
+     This is a terrible kludge, but I think the "Buffers" case is
+     the only one where the title includes a number, so it doesn't
+     seem to be necessary to make this more general.  */
+  if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
+    {
+      menu->text[0][7] = '\0';
+      buffers_num_deleted = 1;
+    }
+
+#if 0
+  /* We need to save the current echo area message, so that we could
+     restore it below, before we exit.  See the commentary below,
+     before the call to message_with_string.  */
+  saved_echo_area_message = Fcurrent_message ();
+#endif
+  /* Force update of the current frame, so that the desired and the
+     current matrices are identical.  */
+  update_frame_with_menu (sf);
+  state[0].menu = menu;
+  mouse_off ();        /* FIXME */
+  state[0].screen_behind = save_current_matrix (sf);
+
+  /* Turn off the cursor.  Otherwise it shows through the menu
+     panes, which is ugly.  */
+#if 0
+  show_cursor (0);     /* FIXME: need a new hook, for w32console.  */
+#endif
+
+  /* Display the menu title.  */
+  tty_menu_display (menu, y0 - 1, x0 - 1, 1, title_faces, 0);
+  if (buffers_num_deleted)
+    menu->text[0][7] = ' ';
+  if ((onepane = menu->count == 1 && menu->submenu[0]))
+    {
+      menu->width = menu->submenu[0]->width;
+      state[0].menu = menu->submenu[0];
+    }
+  else
+    {
+      state[0].menu = menu;
+    }
+  state[0].x = x0 - 1;
+  state[0].y = y0;
+  state[0].pane = onepane;
+
+  x = state[0].x;
+  y = state[0].y;
+
+  leave = 0;
+  while (!leave)
+    {
+      if (!mouse_visible) mouse_on ();
+      read_menu_input (&x, &y);
+      if (sf->mouse_moved)
+       {
+         sf->mouse_moved = 0;
+         result = TTYM_IA_SELECT;
+         for (i = 0; i < statecount; i++)
+           if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
+             {
+               int dy = y - state[i].y;
+               if (0 <= dy && dy < state[i].menu->count)
+                 {
+                   if (!state[i].menu->submenu[dy])
+                     {
+                       if (state[i].menu->panenumber[dy])
+                         result = TTYM_SUCCESS;
+                       else
+                         result = TTYM_IA_SELECT;
+                     }
+                   *pane = state[i].pane - 1;
+                   *selidx = dy;
+                   /* We hit some part of a menu, so drop extra menus that
+                      have been opened.  That does not include an open and
+                      active submenu.  */
+                   if (i != statecount - 2
+                       || state[i].menu->submenu[dy] != state[i+1].menu)
+                     while (i != statecount - 1)
+                       {
+                         statecount--;
+                         mouse_off (); /* FIXME */
+                         screen_update (state[statecount].screen_behind);
+                         state[statecount].screen_behind = NULL;
+                       }
+                   if (i == statecount - 1 && state[i].menu->submenu[dy])
+                     {
+                       tty_menu_display (state[i].menu,
+                                         state[i].y,
+                                         state[i].x,
+                                         state[i].pane,
+                                         faces, 1);
+                       state[statecount].menu = state[i].menu->submenu[dy];
+                       state[statecount].pane = state[i].menu->panenumber[dy];
+                       mouse_off (); /* FIXME */
+                       state[statecount].screen_behind
+                         = save_current_matrix (sf);
+                       state[statecount].x
+                         = state[i].x + state[i].menu->width + 2;
+                       state[statecount].y = y;
+                       statecount++;
+                     }
+                 }
+             }
+         tty_menu_display (state[statecount - 1].menu,
+                           state[statecount - 1].y,
+                           state[statecount - 1].x,
+                           state[statecount - 1].pane,
+                           faces, 1);
+       }
+      else
+       {
+         if ((menu_help_message || prev_menu_help_message)
+             && menu_help_message != prev_menu_help_message)
+           {
+             help_callback (menu_help_message,
+                            menu_help_paneno, menu_help_itemno);
+#if 0
+             show_cursor (0);  /* FIXME */
+#endif
+             prev_menu_help_message = menu_help_message;
+           }
+         /* We are busy-waiting for the mouse to move, so let's be nice
+            to other Windows applications by releasing our time slice.  */
+         Sleep (20);   /* FIXME */
+       }
+      for (b = 0; b < mouse_button_count && !leave; b++)
+       {
+         /* Only leave if user both pressed and released the mouse, and in
+            that order.  This avoids popping down the menu pane unless
+            the user is really done with it.  */
+         if (mouse_pressed (b, &x, &y))
+           {
+             while (mouse_button_depressed (b, &x, &y))
+               Sleep (20);     /* FIXME */
+             leave = 1;
+           }
+         (void) mouse_released (b, &x, &y);
+       }
+    }
+
+  mouse_off ();                        /* FIXME */
+  screen_update (sf, state[0].screen_behind);
+  state[0].screen_behind = NULL;
+#if 0
+  /* We have a situation here.  ScreenUpdate has just restored the
+     screen contents as it was before we started drawing this menu.
+     That includes any echo area message that could have been
+     displayed back then.  (In reality, that echo area message will
+     almost always be the ``keystroke echo'' that echoes the sequence
+     of menu items chosen by the user.)  However, if the menu had some
+     help messages, then displaying those messages caused Emacs to
+     forget about the original echo area message.  So when
+     ScreenUpdate restored it, it created a discrepancy between the
+     actual screen contents and what Emacs internal data structures
+     know about it.
+
+     To avoid this conflict, we force Emacs to restore the original
+     echo area message as we found it when we entered this function.
+     The irony of this is that we then erase the restored message
+     right away, so the only purpose of restoring it is so that
+     erasing it works correctly...  */
+  if (! NILP (saved_echo_area_message))
+    message_with_string ("%s", saved_echo_area_message, 0);
+  message (0);
+#endif
+  while (statecount--)
+    free_saved_screen (state[statecount].screen_behind);
+#if 0
+  show_cursor (1);     /* turn cursor back on */
+#endif
+  /* Clean up any mouse events that are waiting inside Emacs event queue.
+     These events are likely to be generated before the menu was even
+     displayed, probably because the user pressed and released the button
+     (which invoked the menu) too quickly.  If we don't remove these events,
+     Emacs will process them after we return and surprise the user.  */
+  discard_mouse_events ();
+  mouse_clear_clicks ();
+  if (!kbd_buffer_events_waiting (1))
+    clear_input_pending ();
+  /* Allow mouse events generation by dos_rawgetc.  */
+  mouse_preempted--;
+  return result;
+}
+
+/* Dispose of a menu.  */
+
+void
+tty_menu_destroy (tty_menu *menu)
+{
+  int i;
+  if (menu->allocated)
+    {
+      for (i = 0; i < menu->count; i++)
+       if (menu->submenu[i])
+         tty_menu_destroy (menu->submenu[i]);
+      xfree (menu->text);
+      xfree (menu->submenu);
+      xfree (menu->panenumber);
+      xfree (menu->help_text);
+    }
+  xfree (menu);
+  menu_help_message = prev_menu_help_message = NULL;
+}
+
+Lisp_Object
+tty_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
+              Lisp_Object title, const char **error_name)
+{
+  tty_menu *menu;
+  int pane, selidx, lpane, status;
+  Lisp_Object entry, pane_prefix;
+  char *datap;
+  int ulx, uly, width, height;
+  int dispwidth, dispheight;
+  int i, j, lines, maxlines;
+  int maxwidth;
+  int dummy_int;
+  unsigned int dummy_uint;
+  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+
+  if (! FRAME_TERMCAP_P (f))
+    abort ();
+
+  *error_name = 0;
+  if (menu_items_n_panes == 0)
+    return Qnil;
+
+  if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
+    {
+      *error_name = "Empty menu";
+      return Qnil;
+    }
+
+  /* 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.  */
+  inhibit_garbage_collection ();
+
+  /* Adjust coordinates to be root-window-relative.  */
+  x += f->left_pos;
+  y += f->top_pos;
+
+  /* Create all the necessary panes and their items.  */
+  maxwidth = maxlines = lines = i = 0;
+  lpane = TTYM_FAILURE;
+  while (i < menu_items_used)
+    {
+      if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+       {
+         /* Create a new pane.  */
+         Lisp_Object pane_name, prefix;
+         const char *pane_string;
+
+          maxlines = max (maxlines, lines);
+          lines = 0;
+         pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
+         prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+         pane_string = (NILP (pane_name)
+                        ? "" : SSDATA (pane_name));
+         if (keymaps && !NILP (prefix))
+           pane_string++;
+
+         lpane = tty_menu_add_pane (menu, pane_string);
+         if (lpane == TTYM_FAILURE)
+           {
+             tty_menu_destroy (menu);
+             *error_name = "Can't create pane";
+             return Qnil;
+           }
+         i += MENU_ITEMS_PANE_LENGTH;
+
+         /* Find the width of the widest item in this pane.  */
+         j = i;
+         while (j < menu_items_used)
+           {
+             Lisp_Object item;
+             item = XVECTOR (menu_items)->contents[j];
+             if (EQ (item, Qt))
+               break;
+             if (NILP (item))
+               {
+                 j++;
+                 continue;
+               }
+             width = SBYTES (item);
+             if (width > maxwidth)
+               maxwidth = width;
+
+             j += MENU_ITEMS_ITEM_LENGTH;
+           }
+       }
+      /* Ignore a nil in the item list.
+        It's meaningful only for dialog boxes.  */
+      else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+       i += 1;
+      else
+       {
+         /* Create a new item within current pane.  */
+         Lisp_Object item_name, enable, descrip, help;
+         char *item_data;
+         char const *help_string;
+
+         item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
+         enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
+         descrip
+           = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
+         help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
+         help_string = STRINGP (help) ? SSDATA (help) : NULL;
+
+         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);
+             memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
+             for (j = SCHARS (item_name); j < maxwidth; j++)
+               item_data[j] = ' ';
+             memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
+             item_data[j + SBYTES (descrip)] = 0;
+           }
+         else
+           item_data = SSDATA (item_name);
+
+         if (lpane == TTYM_FAILURE
+             || (tty_menu_add_selection (menu, lpane, item_data,
+                                         !NILP (enable), help_string)
+                 == TTYM_FAILURE))
+           {
+             tty_menu_destroy (menu);
+             *error_name = "Can't add selection to menu";
+             return Qnil;
+           }
+         i += MENU_ITEMS_ITEM_LENGTH;
+          lines++;
+       }
+    }
+
+  maxlines = max (maxlines, lines);
+
+  /* All set and ready to fly.  */
+  dispwidth = f->text_cols;
+  dispheight = f->text_lines;
+  x = min (x, dispwidth);
+  y = min (y, dispheight);
+  x = max (x, 1);
+  y = max (y, 1);
+  tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
+  if (ulx+width > dispwidth)
+    {
+      x -= (ulx + width) - dispwidth;
+      ulx = dispwidth - width;
+    }
+  if (uly+height > dispheight)
+    {
+      y -= (uly + height) - dispheight;
+      uly = dispheight - height;
+    }
+
+  if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
+    {
+      /* Move the menu away of the echo area, to avoid overwriting the
+        menu with help echo messages or vice versa.  */
+      if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
+       {
+         y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
+         uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
+       }
+      else
+       {
+         y--;
+         uly--;
+       }
+    }
+
+  if (ulx < 0) x -= ulx;
+  if (uly < 0) y -= uly;
+
+  if (! for_click)
+    {
+      /* If position was not given by a mouse click, adjust so upper left
+         corner of the menu as a whole ends up at given coordinates.  This
+         is what x-popup-menu says in its documentation.  */
+      x += width/2;
+      y += 1.5*height/(maxlines+2);
+    }
+
+  pane = selidx = 0;
+
+  record_unwind_protect (pop_down_menu,
+                         Fcons (make_save_value (f, 0),
+                                make_save_value (menu, 0)));
+
+  /* Help display under X won't work because XMenuActivate contains
+     a loop that doesn't give Emacs a chance to process it.  */
+  menu_help_frame = f;
+  status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
+                             menu_help_callback);
+  entry = pane_prefix = Qnil;
+
+  switch (status)
+    {
+    case TTYM_SUCCESS:
+      /* Find the item number SELIDX in pane number PANE.  */
+      i = 0;
+      while (i < menu_items_used)
+       {
+         if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+           {
+             if (pane == 0)
+               pane_prefix
+                 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+             pane--;
+             i += MENU_ITEMS_PANE_LENGTH;
+           }
+         else
+           {
+             if (pane == -1)
+               {
+                 if (selidx == 0)
+                   {
+                     entry
+                       = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
+                     if (keymaps != 0)
+                       {
+                         entry = Fcons (entry, Qnil);
+                         if (!NILP (pane_prefix))
+                           entry = Fcons (pane_prefix, entry);
+                       }
+                     break;
+                   }
+                 selidx--;
+               }
+             i += MENU_ITEMS_ITEM_LENGTH;
+           }
+       }
+      break;
+
+    case TTYM_FAILURE:
+      *error_name = "Can't activate menu";
+    case TTYM_IA_SELECT:
+      break;
+    case TTYM_NO_SELECT:
+      /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
+        the menu was invoked with a mouse event as POSITION).  */
+      if (! for_click)
+        Fsignal (Qquit, Qnil);
+      break;
+    }
+
+  unbind_to (specpdl_count, Qnil);
+
+  return entry;
+}
+
+#endif /* HAVE_MENUS && !MSDOS */
+
 \f
 #ifndef MSDOS
 /***********************************************************************
@@ -2784,8 +3713,7 @@ create_tty_output (struct frame *f)
 {
   struct tty_output *t = xzalloc (sizeof *t);
 
-  if (! FRAME_TERMCAP_P (f))
-    emacs_abort ();
+  eassert (FRAME_TERMCAP_P (f));
 
   t->display_info = FRAME_TERMINAL (f)->display_info.tty;
 
@@ -2797,8 +3725,7 @@ create_tty_output (struct frame *f)
 static void
 tty_free_frame_resources (struct frame *f)
 {
-  if (! FRAME_TERMCAP_P (f))
-    emacs_abort ();
+  eassert (FRAME_TERMCAP_P (f));
 
   if (FRAME_FACE_CACHE (f))
     free_frame_faces (f);
@@ -2813,8 +3740,7 @@ tty_free_frame_resources (struct frame *f)
 static void
 tty_free_frame_resources (struct frame *f)
 {
-  if (! FRAME_TERMCAP_P (f) && ! FRAME_MSDOS_P (f))
-    emacs_abort ();
+  eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
 
   if (FRAME_FACE_CACHE (f))
     free_frame_faces (f);
@@ -2909,7 +3835,7 @@ dissociate_if_controlling_tty (int fd)
 {
   /* If tcgetpgrp succeeds, fd is the controlling terminal,
      so dissociate it by invoking setsid.  */
-  if (0 <= tcgetpgrp (fd) && setsid () < 0)
+  if (tcgetpgrp (fd) >= 0 && setsid () < 0)
     {
 #ifdef TIOCNOTTY
       /* setsid failed, presumably because Emacs is already a process
@@ -2931,18 +3857,21 @@ dissociate_if_controlling_tty (int fd)
 
    TERMINAL_TYPE is the termcap type of the device, e.g. "vt100".
 
-   If MUST_SUCCEED is true, then all errors are fatal. */
+   If MUST_SUCCEED is true, then all errors are fatal.  */
 
 struct terminal *
-init_tty (const char *name, const char *terminal_type, int must_succeed)
+init_tty (const char *name, const char *terminal_type, bool must_succeed)
 {
-  char *area = NULL;
+#ifdef TERMINFO
+  char **address = 0;
+#else
+  char *area;
   char **address = &area;
-  int buffer_size = 4096;
+#endif
   int status;
   struct tty_display_info *tty = NULL;
   struct terminal *terminal = NULL;
-  int ctty = 0;                 /* 1 if asked to open controlling tty. */
+  bool ctty = false;  /* True if asked to open controlling tty.  */
 
   if (!terminal_type)
     maybe_fatal (must_succeed, 0,
@@ -2993,7 +3922,6 @@ init_tty (const char *name, const char *terminal_type, int must_succeed)
 
   {
     /* Open the terminal device.  */
-    FILE *file;
 
     /* If !ctty, don't recognize it as our controlling terminal, and
        don't make it the controlling tty if we don't have one now.
@@ -3004,30 +3932,21 @@ init_tty (const char *name, const char *terminal_type, int 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->name = xstrdup (name);
-    terminal->name = xstrdup (name);
-
-    if (fd < 0)
-      maybe_fatal (must_succeed, terminal,
-                   "Could not open file: %s",
-                   "Could not open file: %s",
-                   name);
-    if (!isatty (fd))
+    if (! tty->input)
       {
-        close (fd);
-        maybe_fatal (must_succeed, terminal,
-                     "Not a tty device: %s",
-                     "Not a tty device: %s",
-                     name);
+       char const *diagnostic
+         = tty->input ? "Not a tty device: %s" : "Could not open file: %s";
+       emacs_close (fd);
+       maybe_fatal (must_succeed, terminal, diagnostic, diagnostic, name);
       }
 
+    tty->name = xstrdup (name);
+    terminal->name = xstrdup (name);
+
     if (!O_IGNORE_CTTY && !ctty)
       dissociate_if_controlling_tty (fd);
-
-    file = fdopen (fd, "w+");
-    tty->input = file;
-    tty->output = file;
   }
 
   tty->type = xstrdup (terminal_type);
@@ -3036,12 +3955,16 @@ init_tty (const char *name, const char *terminal_type, int must_succeed)
 
   Wcm_clear (tty);
 
-  tty->termcap_term_buffer = xmalloc (buffer_size);
-
   /* On some systems, tgetent tries to access the controlling
-     terminal. */
+     terminal.  */
   block_tty_out_signal ();
+#ifdef TERMINFO
+  status = tgetent (0, terminal_type);
+#else
   status = tgetent (tty->termcap_term_buffer, terminal_type);
+  if (tty->termcap_term_buffer[TERMCAP_BUFFER_SIZE - 1])
+    emacs_abort ();
+#endif
   unblock_tty_out_signal ();
 
   if (status < 0)
@@ -3073,11 +3996,8 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
     }
 
 #ifndef TERMINFO
-  if (strlen (tty->termcap_term_buffer) >= buffer_size)
-    emacs_abort ();
-  buffer_size = strlen (tty->termcap_term_buffer);
+  area = tty->termcap_strings_buffer;
 #endif
-  tty->termcap_strings_buffer = area = xmalloc (buffer_size);
   tty->TS_ins_line = tgetstr ("al", address);
   tty->TS_ins_multi_lines = tgetstr ("AL", address);
   tty->TS_bell = tgetstr ("bl", address);
@@ -3109,13 +4029,13 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
   Right (tty) = tgetstr ("nd", address);
   Down (tty) = tgetstr ("do", address);
   if (!Down (tty))
-    Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */
+    Down (tty) = tgetstr ("nl", address); /* Obsolete name for "do" */
   if (tgetflag ("bs"))
-    Left (tty) = "\b";           /* can't possibly be longer! */
-  else                           /* (Actually, "bs" is obsolete...) */
+    Left (tty) = "\b";           /* Can't possibly be longer!  */
+  else                           /* (Actually, "bs" is obsolete...)  */
     Left (tty) = tgetstr ("le", address);
   if (!Left (tty))
-    Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */
+    Left (tty) = tgetstr ("bc", address); /* Obsolete name for "le" */
   tty->TS_pad_char = tgetstr ("pc", address);
   tty->TS_repeat = tgetstr ("rp", address);
   tty->TS_end_standout_mode = tgetstr ("se", address);
@@ -3189,12 +4109,13 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
 #ifdef WINDOWSNT
   {
     struct frame *f = XFRAME (selected_frame);
+    int height, width;
 
-    initialize_w32_display (terminal);
+    initialize_w32_display (terminal, &width, &height);
 
-    FrameRows (tty) = FRAME_LINES (f);
-    FrameCols (tty) = FRAME_COLS (f);
-    tty->specified_window = FRAME_LINES (f);
+    FrameRows (tty) = height;
+    FrameCols (tty) = width;
+    tty->specified_window = height;
 
     FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
     terminal->char_ins_del_ok = 1;
@@ -3236,7 +4157,7 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
      don't think we're losing anything by turning it off.  */
   terminal->line_ins_del_ok = 0;
 
-  tty->TN_max_colors = 16;  /* Required to be non-zero for tty-display-color-p */
+  tty->TN_max_colors = 16;  /* Must be non-zero for tty-display-color-p.  */
 #endif /* DOS_NT */
 
 #ifdef HAVE_GPM
@@ -3332,16 +4253,16 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
       tty->Wcm->cm_tab = 0;
       /* We can't support standout mode, because it uses magic cookies.  */
       tty->TS_standout_mode = 0;
-      /* But that means we cannot rely on ^M to go to column zero! */
+      /* But that means we cannot rely on ^M to go to column zero!  */
       CR (tty) = 0;
-      /* LF can't be trusted either -- can alter hpos */
-      /* if move at column 0 thru a line with TS_standout_mode */
+      /* LF can't be trusted either -- can alter hpos */
+      /* If move at column 0 thru a line with TS_standout_mode.  */
       Down (tty) = 0;
     }
 
   tty->specified_window = FrameRows (tty);
 
-  if (Wcm_init (tty) == -1)    /* can't do cursor motion */
+  if (Wcm_init (tty) == -1)    /* Can't do cursor motion.  */
     {
       maybe_fatal (must_succeed, terminal,
                    "Terminal type \"%s\" is not powerful enough to run Emacs",
@@ -3411,10 +4332,10 @@ vfatal (const char *str, va_list ap)
 
 /* Auxiliary error-handling function for init_tty.
    Delete TERMINAL, then call error or fatal with str1 or str2,
-   respectively, according to whether MUST_SUCCEED is zero or not.  */
+   respectively, according to whether MUST_SUCCEED is true.  */
 
 static void
-maybe_fatal (int must_succeed, struct terminal *terminal,
+maybe_fatal (bool must_succeed, struct terminal *terminal,
             const char *str1, const char *str2, ...)
 {
   va_list ap;
@@ -3426,9 +4347,6 @@ maybe_fatal (int must_succeed, struct terminal *terminal,
     vfatal (str2, ap);
   else
     verror (str1, ap);
-
-  va_end (ap);
-  emacs_abort ();
 }
 
 void
@@ -3437,7 +4355,6 @@ fatal (const char *str, ...)
   va_list ap;
   va_start (ap, str);
   vfatal (str, ap);
-  va_end (ap);
 }
 
 \f
@@ -3454,8 +4371,7 @@ delete_tty (struct terminal *terminal)
   if (!terminal->name)
     return;
 
-  if (terminal->type != output_termcap)
-    emacs_abort ();
+  eassert (terminal->type == output_termcap);
 
   tty = terminal->display_info.tty;
 
@@ -3497,9 +4413,6 @@ delete_tty (struct terminal *terminal)
 
   xfree (tty->old_tty);
   xfree (tty->Wcm);
-  xfree (tty->termcap_strings_buffer);
-  xfree (tty->termcap_term_buffer);
-
   xfree (tty);
 }