(temp_output_buffer_show): Copy default-directory from current buffer.
[bpt/emacs.git] / src / term.c
index f701007..1fbc4d8 100644 (file)
@@ -1,5 +1,5 @@
 /* terminal control module for terminals described by TERMCAP
-   Copyright (C) 1985, 1986, 1987, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 93, 94, 95 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <config.h>
@@ -26,20 +27,27 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "cm.h"
 #undef NULL
 #include "lisp.h"
+#include "charset.h"
+#include "coding.h"
 #include "frame.h"
 #include "disptab.h"
 #include "termhooks.h"
 #include "keyboard.h"
 
+extern Lisp_Object Fmake_sparse_keymap ();
+
 #define max(a, b) ((a) > (b) ? (a) : (b))
 #define min(a, b) ((a) < (b) ? (a) : (b))
 
-#define OUTPUT(a) tputs (a, FRAME_HEIGHT (selected_frame) - curY, cmputc)
+#define OUTPUT(a) tputs (a, (int) (FRAME_HEIGHT (selected_frame) - curY), cmputc)
 #define OUTPUT1(a) tputs (a, 1, cmputc)
 #define OUTPUTL(a, lines) tputs (a, lines, cmputc)
-#define OUTPUT_IF(a) { if (a) tputs (a, FRAME_HEIGHT (selected_frame) - curY, cmputc); }
+#define OUTPUT_IF(a) { if (a) tputs (a, (int) (FRAME_HEIGHT (selected_frame) - curY), cmputc); }
 #define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); }
 
+/* Function to use to ring the bell.  */
+Lisp_Object Vring_bell_function;
+
 /* Terminal characteristics that higher levels want to look at.
    These are all extern'd in termchar.h */
 
@@ -52,13 +60,12 @@ int line_ins_del_ok;                /* Terminal can insert and delete lines */
 int char_ins_del_ok;           /* Terminal can insert and delete chars */
 int scroll_region_ok;          /* Terminal supports setting the
                                   scroll window */
+int scroll_region_cost;                /* Cost of setting a scroll window,
+                                  measured in characters */
 int memory_below_frame;                /* Terminal remembers lines
                                   scrolled off bottom */
 int fast_clear_end_of_line;    /* Terminal has a `ce' string */
 
-int dont_calculate_costs;      /* Nonzero means don't bother computing */
-                               /* various cost tables; we won't use them.  */
-
 /* Nonzero means no need to redraw the entire frame on resuming
    a suspended Emacs.  This is useful on terminals with multiple pages,
    where one page is used for Emacs and another for all else. */
@@ -113,7 +120,7 @@ int (*frame_up_to_date_hook) ();
 
    This should clear mouse_moved until the next motion
    event arrives.  */
-void (*mouse_position_hook) ( /* FRAME_PTR *f,
+void (*mouse_position_hook) ( /* FRAME_PTR *f, int insist,
                                 Lisp_Object *bar_window,
                                 enum scroll_bar_part *part,
                                 Lisp_Object *x,
@@ -155,7 +162,7 @@ void (*set_vertical_scroll_bar_hook)
    away is a real pain - can you say set-window-configuration?
    Instead, we just assert at the beginning of redisplay that *all*
    scroll bars are to be removed, and then save scroll bars from the
-   firey pit when we actually redisplay their window.  */
+   fiery pit when we actually redisplay their window.  */
 
 /* Arrange for all scroll bars on FRAME to be removed at the next call
    to `*judge_scroll_bars_hook'.  A scroll bar may be spared if
@@ -191,7 +198,9 @@ void (*judge_scroll_bars_hook)( /* FRAME_PTR *FRAME */ );
 
 /* Strings, numbers and flags taken from the termcap entry.  */
 
-char *TS_ins_line;             /* termcap "al" */
+char *TS_end_italic_mode;      /* termcap "ae" */
+char *TS_ins_line;             /* "al" */
+char *TS_italic_mode;          /* "as" */
 char *TS_ins_multi_lines;      /* "AL" (one parameter, # lines to insert) */
 char *TS_bell;                 /* "bl" */
 char *TS_clr_to_bottom;                /* "cd" */
@@ -214,6 +223,8 @@ char *TS_insert_mode;               /* "im", enter character-insert mode */
 char *TS_pad_inserted_char;    /* "ip".  Just padding, no commands.  */
 char *TS_end_keypad_mode;      /* "ke" */
 char *TS_keypad_mode;          /* "ks" */
+char *TS_bold_mode;            /* "md" */
+char *TS_end_bold_mode;                /* "me" */
 char *TS_pad_char;             /* "pc", char to use as padding */
 char *TS_repeat;               /* "rp" (2 params, # times to repeat
                                   and character to be repeated) */
@@ -223,6 +234,8 @@ char *TS_standout_mode;             /* "so" */
 char *TS_rev_scroll;           /* "sr" */
 char *TS_end_termcap_modes;    /* "te" */
 char *TS_termcap_modes;                /* "ti" */
+char *TS_end_underscore_mode;  /* "ue" */
+char *TS_underscore_mode;      /* "us" */
 char *TS_visible_bell;         /* "vb" */
 char *TS_end_visual_mode;      /* "ve" */
 char *TS_visual_mode;          /* "vi" */
@@ -253,8 +266,14 @@ static int se_is_so;       /* 1 if same string both enters and leaves
 
 /* internal state */
 
+/* The largest frame width in any call to calculate_costs.  */
+int max_frame_width;
+/* The largest frame height in any call to calculate_costs.  */
+int max_frame_height;
+
 /* Number of chars of space used for standout marker at beginning of line,
    or'd with 0100.  Zero if no standout marker at all.
+   The length of these vectors is max_frame_height.
 
    Used IFF TN_standout_width >= 0. */
 
@@ -285,9 +304,43 @@ FRAME_PTR updating_frame;
 static int system_uses_terminfo;
 
 char *tparam ();
+
+extern char *tgetstr ();
 \f
+
+#ifdef WINDOWSNT
+/* We aren't X windows, but we aren't termcap either.  This makes me
+   uncertain as to what value to use for frame.output_method.  For
+   this file, we'll define FRAME_TERMCAP_P to be zero so that our
+   output hooks get called instead of the termcap functions.  Probably
+   the best long-term solution is to define an output_windows_nt...  */
+
+#undef FRAME_TERMCAP_P
+#define FRAME_TERMCAP_P(_f_) 0
+#endif /* WINDOWSNT */
+
 ring_bell ()
 {
+  if (! NILP (Vring_bell_function))
+    {
+      Lisp_Object function;
+
+      /* Temporarily set the global variable to nil
+        so that if we get an error, it stays nil
+        and we don't call it over and over.
+
+        We don't specbind it, because that would carefully
+        restore the bad value if there's an error
+        and make the loop of errors happen anyway.  */
+      function = Vring_bell_function;
+      Vring_bell_function = Qnil;
+
+      call0 (function);
+
+      Vring_bell_function = function;
+      return;
+    }
+
   if (! FRAME_TERMCAP_P (selected_frame))
     {
       (*ring_bell_hook) ();
@@ -556,6 +609,11 @@ cursor_to (row, col)
       return;
     }
 
+  /* Detect the case where we are called from reset_sys_modes
+     and the costs have never been calculated.  Do nothing.  */
+  if (chars_wasted == 0)
+    return;
+
   col += chars_wasted[row] & 077;
   if (curY == row && curX == col)
     return;
@@ -592,7 +650,7 @@ clear_to_end ()
 {
   register int i;
 
-  if (clear_to_end_hook && FRAME_TERMCAP_P (updating_frame))
+  if (clear_to_end_hook && FRAME_TERMCAP_P (updating_frame))
     {
       (*clear_to_end_hook) ();
       return;
@@ -649,6 +707,7 @@ clear_end_of_line (first_unused_hpos)
 {
   static GLYPH buf = SPACEGLYPH;
   if (FRAME_TERMCAP_P (selected_frame)
+      && chars_wasted != 0
       && TN_standout_width == 0 && curX == 0 && chars_wasted[curY] != 0)
     write_glyphs (&buf, 1);
   clear_end_of_line_raw (first_unused_hpos);
@@ -674,6 +733,11 @@ clear_end_of_line_raw (first_unused_hpos)
       return;
     }
 
+  /* Detect the case where we are called from reset_sys_modes
+     and the costs have never been calculated.  Do nothing.  */
+  if (chars_wasted == 0)
+    return;
+
   first_unused_hpos += chars_wasted[curY] & 077;
   if (curX >= first_unused_hpos)
     return;
@@ -704,6 +768,79 @@ clear_end_of_line_raw (first_unused_hpos)
     }
 }
 \f
+/* Encode SRC_LEN glyphs starting at SRC to terminal output codes and
+   store them at DST.  Do not write more than DST_LEN bytes.  That may
+   require stopping before all SRC_LEN input glyphs have been
+   converted.
+
+   We store the number of glyphs actually converted in *CONSUMED.  The
+   return value is the number of bytes store in DST.  */
+
+int
+encode_terminal_code (src, dst, src_len, dst_len, consumed)
+     GLYPH *src;
+     int src_len;
+     unsigned char *dst;
+     int dst_len, *consumed;
+{
+  GLYPH *src_start = src, *src_end = src + src_len;
+  unsigned char *dst_start = dst, *dst_end = dst + dst_len;
+  register GLYPH g;
+  unsigned int c;
+  unsigned char workbuf[4], *buf;
+  int len, produced, processed;
+  register int tlen = GLYPH_TABLE_LENGTH;
+  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
+
+  while (src < src_end)
+    {
+      g = *src;
+      /* We must skip glyphs to be padded for a wide character.  */
+      if (! (g & GLYPH_MASK_PADDING))
+       {
+         if ((c = GLYPH_CHAR (selected_frame, g)) > MAX_CHAR)
+           {
+             c = ' ';
+             g = MAKE_GLYPH (selected_frame, c,
+                             GLYPH_FACE (selected_frame, g));
+           }
+         if (COMPOSITE_CHAR_P (c))
+           {
+             /* If C is a composite character, we can display
+                only the first component.  */
+             g = cmpchar_table[COMPOSITE_CHAR_ID (c)]->glyph[0],
+             c = GLYPH_CHAR (selected_frame, g);
+           }
+         if (c < tlen)
+           {
+             /* G has an entry in Vglyph_table,
+                so process any alias before testing for simpleness.  */
+             GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
+             c = GLYPH_CHAR (selected_frame, g);
+           }
+         if (GLYPH_SIMPLE_P (tbase, tlen, g))
+           /* We set the multi-byte form of C at BUF.  */
+           len = CHAR_STRING (c, workbuf, buf);
+         else
+           /* We have a string in Vglyph_table.  */
+           len = GLYPH_LENGTH (tbase, g), buf = GLYPH_STRING (tbase, g);
+         
+         produced = encode_coding (&terminal_coding, buf, dst,
+                                    len, dst_end - dst, &processed);
+         if (processed < len)
+           /* We get a carryover because the remaining output
+              buffer is too short.  We must break the loop here
+              without increasing SRC so that the next call of
+              this function start from the same glyph.  */
+           break;
+         dst += produced;
+       }
+      src++;
+    }
+  *consumed = src - src_start;
+  return (dst - dst_start);
+}
+
 
 write_glyphs (string, len)
      register GLYPH *string;
@@ -712,6 +849,7 @@ write_glyphs (string, len)
   register GLYPH g;
   register int tlen = GLYPH_TABLE_LENGTH;
   register Lisp_Object *tbase = GLYPH_TABLE_BASE;
+  int produced, consumed;
 
   if (write_glyphs_hook
       && ! FRAME_TERMCAP_P ((updating_frame ? updating_frame : selected_frame)))
@@ -731,43 +869,44 @@ write_glyphs (string, len)
       && (curX + len - (chars_wasted[curY] & 077)
          == FRAME_WIDTH (selected_frame)))
     len --;
+  if (len <= 0)
+    return;
 
   cmplus (len);
-  while (--len >= 0)
+  /* The field `last_block' should be set to 1 only at the tail.  */
+  terminal_coding.last_block = 0;
+  while (len > 0)
     {
-      g = *string++;
-      /* Check quickly for G beyond length of table.
-        That implies it isn't an alias and is simple.  */
-      if (g >= tlen)
+      /* We use shared conversion buffer of the current size (1024
+        bytes at least).  Usually it is sufficient, but if not, we
+        just repeat the loop.  */
+      produced = encode_terminal_code (string, conversion_buffer,
+                                      len, conversion_buffer_size, &consumed);
+      if (produced > 0)
        {
-       simple:
-         putc (g & 0xff, stdout);
+         fwrite (conversion_buffer, 1, produced, stdout);
          if (ferror (stdout))
            clearerr (stdout);
          if (termscript)
-           putc (g & 0xff, termscript);
-       }
-      else
-       {
-         /* G has an entry in Vglyph_table,
-            so process any alias and then test for simpleness.  */
-         while (GLYPH_ALIAS_P (tbase, tlen, g))
-           g = GLYPH_ALIAS (tbase, g);
-         if (GLYPH_SIMPLE_P (tbase, tlen, g))
-           goto simple;
-         else
-           {
-             /* Here if G (or its definition as an alias) is not simple.  */
-             fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
-                     stdout);
-             if (ferror (stdout))
-               clearerr (stdout);
-             if (termscript)
-               fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
-                       termscript);
-           }
+           fwrite (conversion_buffer, 1, produced, termscript);
        }
+      len -= consumed;
+      string += consumed;
+    }
+  /* We may have to output some codes to terminate the writing.  */
+  terminal_coding.last_block = 1;
+  produced = encode_coding (&terminal_coding, (char *)0, conversion_buffer,
+                           0, conversion_buffer_size,
+                           &consumed);
+  if (produced > 0)
+    {
+      fwrite (conversion_buffer, 1, produced, stdout);
+      if (ferror (stdout))
+       clearerr (stdout);
+      if (termscript)
+       fwrite (conversion_buffer, 1, produced, termscript);
     }
+  cmcheckmagic ();
 }
 
 /* If start is zero, insert blanks instead of a string at start */
@@ -777,10 +916,13 @@ insert_glyphs (start, len)
      register int len;
 {
   char *buf;
-  register GLYPH g;
+  GLYPH g;
   register int tlen = GLYPH_TABLE_LENGTH;
   register Lisp_Object *tbase = GLYPH_TABLE_BASE;
 
+  if (len <= 0)
+    return;
+
   if (insert_glyphs_hook && ! FRAME_TERMCAP_P (updating_frame))
     {
       (*insert_glyphs_hook) (start, len);
@@ -800,34 +942,47 @@ insert_glyphs (start, len)
 
   turn_on_insert ();
   cmplus (len);
-  while (--len >= 0)
+  /* The field `last_block' should be set to 1 only at the tail.  */
+  terminal_coding.last_block = 0;
+  while (len-- > 0)
     {
+      int produced, consumed;
+
       OUTPUT1_IF (TS_ins_char);
       if (!start)
        g = SPACEGLYPH;
       else
-       g = *start++;
-
-      if (GLYPH_SIMPLE_P (tbase, tlen, g))
        {
-         putc (g & 0xff, stdout);
-         if (ferror (stdout))
-           clearerr (stdout);
-         if (termscript)
-           putc (g & 0xff, termscript);
+         g = *start++;
+         /* We must open sufficient space for a character which
+            occupies more than one column.  */
+         while (*start & GLYPH_MASK_PADDING)
+           {
+             OUTPUT1_IF (TS_ins_char);
+             start++, len--;
+           }
        }
-      else
+
+      if (len <= 0)
+       /* This is the last glyph.  */
+       terminal_coding.last_block = 1;
+
+      /* We use shared conversion buffer of the current size (1024
+        bytes at least).  It is surely sufficient for just one glyph.  */
+      produced = encode_terminal_code (&g, conversion_buffer,
+                                      1, conversion_buffer_size, &consumed);
+      if (produced > 0)
        {
-         fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g), stdout);
+         fwrite (conversion_buffer, 1, produced, stdout);
          if (ferror (stdout))
            clearerr (stdout);
          if (termscript)
-           fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
-                   termscript);
+           fwrite (conversion_buffer, 1, produced, termscript);
        }
 
-       OUTPUT1_IF (TS_pad_inserted_char);
-      }
+      OUTPUT1_IF (TS_pad_inserted_char);
+    }
+  cmcheckmagic ();
 }
 
 delete_glyphs (n)
@@ -997,7 +1152,8 @@ per_line_cost (str)
 
 #ifndef old
 /* char_ins_del_cost[n] is cost of inserting N characters.
-   char_ins_del_cost[-n] is cost of deleting N characters. */
+   char_ins_del_cost[-n] is cost of deleting N characters.
+   The length of this vector is based on max_frame_width.  */
 
 int *char_ins_del_vector;
 
@@ -1054,7 +1210,7 @@ calculate_ins_del_char_costs (frame)
 
   /* Delete costs are at negative offsets */
   p = &char_ins_del_cost (frame)[0];
-  for (i = FRAME_WIDTH (selected_frame); --i >= 0;)
+  for (i = FRAME_WIDTH (frame); --i >= 0;)
     *--p = (del_startup_cost += del_cost_per_char);
 
   /* Doing nothing is free */
@@ -1066,27 +1222,25 @@ calculate_ins_del_char_costs (frame)
     *p++ = (ins_startup_cost += ins_cost_per_char);
 }
 
-#ifdef HAVE_X_WINDOWS
-extern int x_screen_planes;
-#endif
-
 extern do_line_insertion_deletion_costs ();
 
 calculate_costs (frame)
      FRAME_PTR frame;
 {
-  register char *f = TS_set_scroll_region ?
-                       TS_set_scroll_region
-                    : TS_set_scroll_region_1;
+  register char *f = (TS_set_scroll_region
+                     ? TS_set_scroll_region
+                     : TS_set_scroll_region_1);
 
-  if (dont_calculate_costs)
-    return;
+  FRAME_COST_BAUD_RATE (frame) = baud_rate;
 
+  scroll_region_cost = string_cost (f);
 #ifdef HAVE_X_WINDOWS
   if (FRAME_X_P (frame))
     {
       do_line_insertion_deletion_costs (frame, 0, ".5*", 0, ".5*",
-                                       0, 0, x_screen_planes);
+                                       0, 0,
+                                       x_screen_planes (frame));
+      scroll_region_cost = 0;
       return;
     }
 #endif
@@ -1100,30 +1254,33 @@ calculate_costs (frame)
      chars_wasted and copybuf are only used here in term.c in cases where
      the term hook isn't called. */
 
+  max_frame_height = max (max_frame_height, FRAME_HEIGHT (frame));
+  max_frame_width = max (max_frame_width, FRAME_WIDTH (frame));
+
   if (chars_wasted != 0)
-    chars_wasted = (char *) xrealloc (chars_wasted, FRAME_HEIGHT (frame));
+    chars_wasted = (char *) xrealloc (chars_wasted, max_frame_height);
   else
-    chars_wasted = (char *) xmalloc (FRAME_HEIGHT (frame));
+    chars_wasted = (char *) xmalloc (max_frame_height);
 
   if (copybuf != 0)
-    copybuf = (char *) xrealloc (copybuf, FRAME_HEIGHT (frame));
+    copybuf = (char *) xrealloc (copybuf, max_frame_height);
   else
-    copybuf = (char *) xmalloc (FRAME_HEIGHT (frame));
+    copybuf = (char *) xmalloc (max_frame_height);
 
   if (char_ins_del_vector != 0)
     char_ins_del_vector
       = (int *) xrealloc (char_ins_del_vector,
                          (sizeof (int)
-                          + 2 * FRAME_WIDTH (frame) * sizeof (int)));
+                          + 2 * max_frame_width * sizeof (int)));
   else
     char_ins_del_vector
       = (int *) xmalloc (sizeof (int)
-                        + 2 * FRAME_WIDTH (frame) * sizeof (int));
+                        + 2 * max_frame_width * sizeof (int));
 
-  bzero (chars_wasted, FRAME_HEIGHT (frame));
-  bzero (copybuf, FRAME_HEIGHT (frame));
+  bzero (chars_wasted, max_frame_height);
+  bzero (copybuf, max_frame_height);
   bzero (char_ins_del_vector, (sizeof (int)
-                              + 2 * FRAME_WIDTH (frame) * sizeof (int)));
+                              + 2 * max_frame_width * sizeof (int)));
 
   if (f && (!TS_ins_line && !TS_del_line))
     do_line_insertion_deletion_costs (frame,
@@ -1261,7 +1418,6 @@ term_get_fkeys (address)
 static Lisp_Object
 term_get_fkeys_1 ()
 {
-  extern char *tgetstr ();
   int i;
 
   char **address = term_get_fkeys_arg;
@@ -1311,9 +1467,9 @@ term_get_fkeys_1 ()
        if (i <= 19)
          fcap[1] = '1' + i - 11;
        else if (i <= 45)
-         fcap[1] = 'A' + i - 11;
+         fcap[1] = 'A' + i - 20;
        else
-         fcap[1] = 'a' + i - 11;
+         fcap[1] = 'a' + i - 46;
 
        {
          char *sequence = tgetstr (fcap, address);
@@ -1348,6 +1504,18 @@ term_get_fkeys_1 ()
       CONDITIONAL_REASSIGN ("%8", "kP", "prior");
       /* if there's no key_dc keycap, map key_ic to `insert' keysym */
       CONDITIONAL_REASSIGN ("kD", "kI", "insert");
+
+      /* IBM has their own non-standard dialect of terminfo.
+        If the standard name isn't found, try the IBM name.  */
+      CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
+      CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
+      CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
+      CONDITIONAL_REASSIGN ("%7", "ki", "menu");
+      CONDITIONAL_REASSIGN ("@7", "kw", "end");
+      CONDITIONAL_REASSIGN ("F1", "k<", "f11");
+      CONDITIONAL_REASSIGN ("F2", "k>", "f12");
+      CONDITIONAL_REASSIGN ("%1", "kq", "help");
+      CONDITIONAL_REASSIGN ("*6", "kU", "select");
 #undef CONDITIONAL_REASSIGN
   }
 }
@@ -1362,22 +1530,70 @@ term_init (terminal_type)
   register char *p;
   int status;
 
-  extern char *tgetstr ();
+#ifdef WINDOWSNT
+  initialize_w32_display ();
+
+  Wcm_clear ();
+
+  area = (char *) malloc (2044);
+
+  if (area == 0)
+    abort ();
+
+  FrameRows = FRAME_HEIGHT (selected_frame);
+  FrameCols = FRAME_WIDTH (selected_frame);
+  specified_window = FRAME_HEIGHT (selected_frame);
+
+  delete_in_insert_mode = 1;
+
+  UseTabs = 0;
+  scroll_region_ok = 0;
+
+  /* Seems to insert lines when it's not supposed to, messing
+     up the display.  In doing a trace, it didn't seem to be
+     called much, so I don't think we're losing anything by
+     turning it off.  */
+
+  line_ins_del_ok = 0;
+  char_ins_del_ok = 1;
+
+  baud_rate = 19200;
+
+  FRAME_CAN_HAVE_SCROLL_BARS (selected_frame) = 0;
+  FRAME_VERTICAL_SCROLL_BAR_TYPE (selected_frame) = vertical_scroll_bar_none;
+
+  return;
+#endif /* WINDOWSNT */
 
   Wcm_clear ();
-  dont_calculate_costs = 0;
 
   status = tgetent (buffer, terminal_type);
   if (status < 0)
-    fatal ("Cannot open termcap database file.\n");
+    {
+#ifdef TERMINFO
+      fatal ("Cannot open terminfo database file");
+#else
+      fatal ("Cannot open termcap database file");
+#endif
+    }
   if (status == 0)
-    fatal ("Terminal type %s is not defined.\n\
+    {
+#ifdef TERMINFO
+      fatal ("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\
-to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
-          terminal_type);
-
+to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
+            terminal_type);
+#else
+      fatal ("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\
+to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
+            terminal_type);
+#endif
+    }
 #ifdef TERMINFO
   area = (char *) malloc (2044);
 #else
@@ -1439,6 +1655,10 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
   Wcm.cm_tab = tgetstr ("ta", address);
   TS_end_termcap_modes = tgetstr ("te", address);
   TS_termcap_modes = tgetstr ("ti", address);
+  TS_bold_mode = tgetstr ("md", address);
+  TS_end_bold_mode = tgetstr ("me", address);
+  TS_underscore_mode = tgetstr ("us", address);
+  TS_end_underscore_mode = tgetstr ("ue", address);
   Up = tgetstr ("up", address);
   TS_visible_bell = tgetstr ("vb", address);
   TS_end_visual_mode = tgetstr ("ve", address);
@@ -1449,7 +1669,10 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
   MultiLeft = tgetstr ("LE", address);
   MultiRight = tgetstr ("RI", address);
 
-  AutoWrap = tgetflag ("am");
+  MagicWrap = tgetflag ("xn");
+  /* Since we make MagicWrap terminals look like AutoWrap, we need to have
+     the former flag imply the latter.  */
+  AutoWrap = MagicWrap || tgetflag ("am");
   memory_below_frame = tgetflag ("db");
   TF_hazeltine = tgetflag ("hz");
   must_write_spaces = tgetflag ("in");
@@ -1457,19 +1680,31 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
   TF_insmode_motion = tgetflag ("mi");
   TF_standout_motion = tgetflag ("ms");
   TF_underscore = tgetflag ("ul");
-  MagicWrap = tgetflag ("xn");
   TF_xs = tgetflag ("xs");
   TF_teleray = tgetflag ("xt");
 
   term_get_fkeys (address);
 
   /* Get frame size from system, or else from termcap.  */
-  get_frame_size (&FRAME_WIDTH (selected_frame),
-                  &FRAME_HEIGHT (selected_frame));
+  {
+    int height, width;
+    get_frame_size (&width, &height);
+    FRAME_WIDTH (selected_frame) = width;
+    FRAME_HEIGHT (selected_frame) = height;
+  }
+
   if (FRAME_WIDTH (selected_frame) <= 0)
-    FRAME_WIDTH (selected_frame) = tgetnum ("co");
+    SET_FRAME_WIDTH (selected_frame, tgetnum ("co"));
+  else
+    /* Keep width and external_width consistent */
+    SET_FRAME_WIDTH (selected_frame, FRAME_WIDTH (selected_frame));
   if (FRAME_HEIGHT (selected_frame) <= 0)
     FRAME_HEIGHT (selected_frame) = tgetnum ("li");
+  
+  if (FRAME_HEIGHT (selected_frame) < 3
+      || FRAME_WIDTH (selected_frame) < 3)
+    fatal ("Screen size %dx%d is too small",
+          FRAME_HEIGHT (selected_frame), FRAME_WIDTH (selected_frame));
 
   min_padding_speed = tgetnum ("pb");
   TN_standout_width = tgetnum ("sg");
@@ -1512,7 +1747,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
      If that fails, we can't use standout mode at all.  */
   if (TS_end_standout_mode == 0)
     {
-      char *s = tgetstr ("me");
+      char *s = tgetstr ("me", address);
       if (s != 0)
        TS_end_standout_mode = s;
       else
@@ -1592,20 +1827,30 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
 It lacks the ability to position the cursor.\n\
 If that is not the actual type of terminal you have, use either the\n\
 DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
-or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.\n",
+or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.",
            terminal_type);
-#else
+#else /* not VMS */
+# ifdef TERMINFO
     fatal ("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\
-to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
+to do `unset TERMINFO' (C-shell: `unsetenv TERMINFO') as well.",
           terminal_type);
-#endif
+# else /* TERMCAP */
+    fatal ("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\
+to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
+          terminal_type);
+# endif /* TERMINFO */
+#endif /*VMS */
   if (FRAME_HEIGHT (selected_frame) <= 0
       || FRAME_WIDTH (selected_frame) <= 0)
-    fatal ("The frame size has not been specified.");
+    fatal ("The frame size has not been specified");
 
   delete_in_insert_mode
     = TS_delete_mode && TS_insert_mode
@@ -1617,7 +1862,8 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
 
   /* Remove width of standout marker from usable width of line */
   if (TN_standout_width > 0)
-    FRAME_WIDTH (selected_frame) -= TN_standout_width;
+    SET_FRAME_WIDTH (selected_frame,
+                    FRAME_WIDTH (selected_frame) - TN_standout_width);
 
   UseTabs = tabs_safe_p () && TabWidth == 8;
 
@@ -1641,7 +1887,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
     baud_rate = 9600;
 
   FRAME_CAN_HAVE_SCROLL_BARS (selected_frame) = 0;
-  FRAME_HAS_VERTICAL_SCROLL_BARS (selected_frame) = 0;
+  FRAME_VERTICAL_SCROLL_BAR_TYPE (selected_frame) = vertical_scroll_bar_none;
 }
 
 /* VARARGS 1 */
@@ -1650,6 +1896,7 @@ fatal (str, arg1, arg2)
 {
   fprintf (stderr, "emacs: ");
   fprintf (stderr, str, arg1, arg2);
+  fprintf (stderr, "\n");
   fflush (stderr);
   exit (1);
 }
@@ -1664,4 +1911,9 @@ This variable can be used by terminal emulator packages.");
 #else
   system_uses_terminfo = 0;
 #endif
+
+  DEFVAR_LISP ("ring-bell-function", &Vring_bell_function,
+    "Non-nil means call this function to ring the bell.\n\
+The function should accept no arguments.");
+  Vring_bell_function = Qnil;
 }