Include keymap.h.
[bpt/emacs.git] / src / buffer.c
index 37e0894..b5d1ab8 100644 (file)
@@ -1,5 +1,5 @@
 /* Buffer manipulation primitives for GNU Emacs.
-   Copyright (C) 1985,86,87,88,89,93,94,95,97,98, 1999
+   Copyright (C) 1985,86,87,88,89,93,94,95,97,98, 1999, 2000, 2001
        Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -25,8 +25,11 @@ Boston, MA 02111-1307, USA.  */
 #include <sys/stat.h>
 #include <sys/param.h>
 #include <errno.h>
+#include <stdio.h>
 
+#ifndef USE_CRT_DLL
 extern int errno;
+#endif
 
 #ifndef MAXPATHLEN
 /* in 4.1, param.h fails to define this. */
@@ -45,6 +48,8 @@ extern int errno;
 #include "region-cache.h"
 #include "indent.h"
 #include "blockinput.h"
+#include "keyboard.h"
+#include "keymap.h"
 #include "frame.h"
 
 struct buffer *current_buffer;         /* the current buffer */
@@ -131,8 +136,6 @@ static void reset_buffer_local_variables ();
 Lisp_Object Vbuffer_alist;
 
 /* Functions to call before and after each text change. */
-Lisp_Object Vbefore_change_function;
-Lisp_Object Vafter_change_function;
 Lisp_Object Vbefore_change_functions;
 Lisp_Object Vafter_change_functions;
 
@@ -175,6 +178,12 @@ Lisp_Object Qmodification_hooks;
 Lisp_Object Qinsert_in_front_hooks;
 Lisp_Object Qinsert_behind_hooks;
 
+static void alloc_buffer_text P_ ((struct buffer *, size_t));
+static void free_buffer_text P_ ((struct buffer *b));
+static Lisp_Object copy_overlays P_ ((struct buffer *, Lisp_Object));
+static void modify_overlay P_ ((struct buffer *, int, int));
+
+
 /* For debugging; temporary.  See set_buffer_internal.  */
 /* Lisp_Object Qlisp_mode, Vcheck_symbol; */
 
@@ -346,7 +355,7 @@ The value is never nil.")
   BLOCK_INPUT;
   /* We allocate extra 1-byte at the tail and keep it always '\0' for
      anchoring a search.  */
-  BUFFER_ALLOC (BUF_BEG_ADDR (b), (BUF_GAP_SIZE (b) + 1));
+  alloc_buffer_text (b, BUF_GAP_SIZE (b) + 1);
   UNBLOCK_INPUT;
   if (! BUF_BEG_ADDR (b))
     buffer_memory_full ();
@@ -387,7 +396,7 @@ The value is never nil.")
   b->zv_marker = Qnil;
 
   name = Fcopy_sequence (name);
-  INITIALIZE_INTERVAL (XSTRING (name), NULL_INTERVAL);
+  XSTRING (name)->intervals = NULL_INTERVAL;
   b->name = name;
 
   if (XSTRING (name)->data[0] != ' ')
@@ -408,16 +417,105 @@ The value is never nil.")
   return buf;
 }
 
-DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer, 2, 2,
+
+/* Return a list of overlays which is a copy of the overlay list
+   LIST, but for buffer B.  */
+
+static Lisp_Object
+copy_overlays (b, list)
+     struct buffer *b;
+     Lisp_Object list;
+{
+  Lisp_Object result, buffer;
+
+  XSETBUFFER (buffer, b);
+
+  for (result = Qnil; CONSP (list); list = XCDR (list))
+    {
+      Lisp_Object overlay, start, end, old_overlay;
+      int charpos;
+
+      old_overlay = XCAR (list);
+      charpos = marker_position (OVERLAY_START (old_overlay));
+      start = Fmake_marker ();
+      Fset_marker (start, make_number (charpos), buffer);
+      XMARKER (start)->insertion_type
+       = XMARKER (OVERLAY_START (old_overlay))->insertion_type;
+
+      charpos = marker_position (OVERLAY_END (old_overlay));
+      end = Fmake_marker ();
+      Fset_marker (end, make_number (charpos), buffer);
+      XMARKER (end)->insertion_type
+       = XMARKER (OVERLAY_END (old_overlay))->insertion_type;
+
+      overlay = allocate_misc ();
+      XMISCTYPE (overlay) = Lisp_Misc_Overlay;
+      OVERLAY_START (overlay) = start;
+      OVERLAY_END (overlay) = end;
+      OVERLAY_PLIST (overlay) = Fcopy_sequence (OVERLAY_PLIST (old_overlay));
+      
+      result = Fcons (overlay, result);
+    }
+
+  return Fnreverse (result);
+}
+     
+
+/* Clone per-buffer values of buffer FROM.
+
+   Buffer TO gets the same per-buffer values as FROM, with the
+   following exceptions: (1) TO's name is left untouched, (2) markers
+   are copied and made to refer to TO, and (3) overlay lists are
+   copied.  */
+
+static void
+clone_per_buffer_values (from, to)
+     struct buffer *from, *to;
+{
+  Lisp_Object to_buffer;
+  int offset;
+
+  XSETBUFFER (to_buffer, to);
+  
+  for (offset = PER_BUFFER_VAR_OFFSET (name) + sizeof (Lisp_Object);
+       offset < sizeof *to;
+       offset += sizeof (Lisp_Object))
+    {
+      Lisp_Object obj;
+
+      obj = PER_BUFFER_VALUE (from, offset);
+      if (MARKERP (obj))
+       {
+         struct Lisp_Marker *m = XMARKER (obj);
+         obj = Fmake_marker ();
+         XMARKER (obj)->insertion_type = m->insertion_type;
+         set_marker_both (obj, to_buffer, m->charpos, m->bytepos);
+       }
+
+      PER_BUFFER_VALUE (to, offset) = obj;
+    }
+
+  bcopy (from->local_flags, to->local_flags, sizeof to->local_flags);
+  
+  to->overlays_before = copy_overlays (to, from->overlays_before);
+  to->overlays_after = copy_overlays (to, from->overlays_after);
+}
+
+
+DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
+       2, 3,
        "bMake indirect buffer (to buffer): \nBName of indirect buffer: ",
   "Create and return an indirect buffer for buffer BASE-BUFFER, named NAME.\n\
 BASE-BUFFER should be an existing buffer (or buffer name).\n\
-NAME should be a string which is not the name of an existing buffer.")
-  (base_buffer, name)
-     register Lisp_Object base_buffer, name;
+NAME should be a string which is not the name of an existing buffer.\n\
+Optional argument CLONE non-nil means preserve BASE-BUFFER's state,\n\
+such as major and minor modes, in the indirect buffer.\n\
+CLONE nil means the indirect buffer's state is reset to default values.")
+  (base_buffer, name, clone)
+     Lisp_Object base_buffer, name, clone;
 {
-  register Lisp_Object buf;
-  register struct buffer *b;
+  Lisp_Object buf;
+  struct buffer *b;
 
   buf = Fget_buffer (name);
   if (!NILP (buf))
@@ -425,8 +523,7 @@ NAME should be a string which is not the name of an existing buffer.")
 
   base_buffer = Fget_buffer (base_buffer);
   if (NILP (base_buffer))
-    error ("No such buffer: `%s'",
-          XSTRING (XBUFFER (base_buffer)->name)->data);
+    error ("No such buffer: `%s'", XSTRING (name)->data);
 
   if (XSTRING (name)->size == 0)
     error ("Empty string for buffer name is not allowed");
@@ -458,7 +555,7 @@ NAME should be a string which is not the name of an existing buffer.")
   all_buffers = b;
 
   name = Fcopy_sequence (name);
-  INITIALIZE_INTERVAL (XSTRING (name), NULL_INTERVAL);
+  XSTRING (name)->intervals = NULL_INTERVAL;
   b->name = name;
 
   reset_buffer (b);
@@ -498,14 +595,19 @@ NAME should be a string which is not the name of an existing buffer.")
       XMARKER (b->base_buffer->zv_marker)->insertion_type = 1;
     }
 
-  /* Give the indirect buffer markers for its narrowing.  */
-  b->pt_marker = Fmake_marker ();
-  set_marker_both (b->pt_marker, buf, BUF_PT (b), BUF_PT_BYTE (b));
-  b->begv_marker = Fmake_marker ();
-  set_marker_both (b->begv_marker, buf, BUF_BEGV (b), BUF_BEGV_BYTE (b));
-  b->zv_marker = Fmake_marker ();
-  set_marker_both (b->zv_marker, buf, BUF_ZV (b), BUF_ZV_BYTE (b));
-  XMARKER (b->zv_marker)->insertion_type = 1;
+  if (NILP (clone))
+    {
+      /* Give the indirect buffer markers for its narrowing.  */
+      b->pt_marker = Fmake_marker ();
+      set_marker_both (b->pt_marker, buf, BUF_PT (b), BUF_PT_BYTE (b));
+      b->begv_marker = Fmake_marker ();
+      set_marker_both (b->begv_marker, buf, BUF_BEGV (b), BUF_BEGV_BYTE (b));
+      b->zv_marker = Fmake_marker ();
+      set_marker_both (b->zv_marker, buf, BUF_ZV (b), BUF_ZV_BYTE (b));
+      XMARKER (b->zv_marker)->insertion_type = 1;
+    }
+  else
+    clone_per_buffer_values (b->base_buffer, b);
 
   return buf;
 }
@@ -540,10 +642,9 @@ reset_buffer (b)
   b->last_selected_window = Qnil;
   XSETINT (b->display_count, 0);
   b->display_time = Qnil;
-  b->extra2 = Qnil;
-  b->extra3 = Qnil;
   b->enable_multibyte_characters = buffer_defaults.enable_multibyte_characters;
   b->cursor_type = buffer_defaults.cursor_type;
+  b->extra_line_spacing = buffer_defaults.extra_line_spacing;
 }
 
 /* Reset buffer B's local variables info.
@@ -840,7 +941,10 @@ A non-nil FLAG means mark the buffer modified.")
   XSETBUFFER (buffer, current_buffer);
   window = Fget_buffer_window (buffer, Qt);
   if (WINDOWP (window))
-    update_mode_lines++;
+    {
+      ++update_mode_lines;
+      current_buffer->prevent_redisplay_optimizations_p = 1;
+    }
   
   return flag;
 }
@@ -997,7 +1101,7 @@ If BUFFER is omitted or nil, some interesting buffer is returned.")
        }
 
       if (NILP (visible_ok))
-       tem = Fget_buffer_window (buf, Qt);
+       tem = Fget_buffer_window (buf, Qvisible);
       else
        tem = Qnil;
       if (NILP (tem))
@@ -1181,6 +1285,16 @@ with SIGHUP.")
        return Qnil;
     }
 
+  /* Notice if the buffer to kill is the sole visible buffer
+     when we're currently in the mini-buffer, and give up if so.  */
+  XSETBUFFER (tem, current_buffer);
+  if (EQ (tem, XWINDOW (minibuf_window)->buffer))
+    {
+      tem = Fother_buffer (buf, Qnil, Qnil);
+      if (EQ (buf, tem))
+       return Qnil;
+    }
+
   /* Now there is no question: we can kill the buffer.  */
 
 #ifdef CLASH_DETECTION
@@ -1251,7 +1365,7 @@ with SIGHUP.")
 
   BLOCK_INPUT;
   if (! b->base_buffer)
-    BUFFER_FREE (BUF_BEG_ADDR (b));
+    free_buffer_text (b);
 
   if (b->newline_cache)
     {
@@ -1498,6 +1612,11 @@ set_buffer_internal_1 (b)
   register Lisp_Object tail, valcontents;
   Lisp_Object tem;
 
+#ifdef USE_MMAP_FOR_BUFFERS
+  if (b->text->beg == NULL)
+    enlarge_buffer_text (b, 0);
+#endif /* USE_MMAP_FOR_BUFFERS */
+  
   if (current_buffer == b)
     return;
 
@@ -1565,7 +1684,7 @@ set_buffer_internal_1 (b)
 
   for (tail = b->local_var_alist; !NILP (tail); tail = XCDR (tail))
     {
-      valcontents = XSYMBOL (XCAR (XCAR (tail)))->value;
+      valcontents = SYMBOL_VALUE (XCAR (XCAR (tail)));
       if ((BUFFER_LOCAL_VALUEP (valcontents)
           || SOME_BUFFER_LOCAL_VALUEP (valcontents))
          && (tem = XBUFFER_LOCAL_VALUE (valcontents)->realvalue,
@@ -1580,7 +1699,7 @@ set_buffer_internal_1 (b)
   if (old_buf)
     for (tail = old_buf->local_var_alist; !NILP (tail); tail = XCDR (tail))
       {
-       valcontents = XSYMBOL (XCAR (XCAR (tail)))->value;
+       valcontents = SYMBOL_VALUE (XCAR (XCAR (tail)));
        if ((BUFFER_LOCAL_VALUEP (valcontents)
             || SOME_BUFFER_LOCAL_VALUEP (valcontents))
            && (tem = XBUFFER_LOCAL_VALUE (valcontents)->realvalue,
@@ -1722,18 +1841,20 @@ selected window if it is displayed there.")
       buffer = buf1;
     }
 
-  /* Move buffer to the end of the buffer list.  */
-  {
-    register Lisp_Object aelt, link;
+  /* Move buffer to the end of the buffer list.  Do nothing if the
+     buffer is killed.  */
+  if (!NILP (XBUFFER (buffer)->name))
+    {
+      Lisp_Object aelt, link;
 
-    aelt = Frassq (buffer, Vbuffer_alist);
-    link = Fmemq (aelt, Vbuffer_alist);
-    Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
-    XCDR (link) = Qnil;
-    Vbuffer_alist = nconc2 (Vbuffer_alist, link);
-  }
+      aelt = Frassq (buffer, Vbuffer_alist);
+      link = Fmemq (aelt, Vbuffer_alist);
+      Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
+      XCDR (link) = Qnil;
+      Vbuffer_alist = nconc2 (Vbuffer_alist, link);
 
-  frames_bury_buffer (buffer);
+      frames_bury_buffer (buffer);
+    }
 
   return Qnil;
 }
@@ -1792,8 +1913,17 @@ advance_to_char_boundary (byte_pos)
     {
       /* We should advance BYTE_POS only when C is a constituent of a
          multibyte sequence.  */
-      DEC_POS (byte_pos);
+      int orig_byte_pos = byte_pos;
+
+      do
+       {
+         byte_pos--;
+         c = FETCH_BYTE (byte_pos);
+       }
+      while (! CHAR_HEAD_P (c) && byte_pos > BEG);
       INC_POS (byte_pos);
+      if (byte_pos < orig_byte_pos)
+       byte_pos = orig_byte_pos;
       /* If C is a constituent of a multibyte sequence, BYTE_POS was
          surely advance to the correct character boundary.  If C is
          not, BYTE_POS was unchanged.  */
@@ -1814,6 +1944,10 @@ but the contents viewed as characters do change.")
 {
   Lisp_Object tail, markers;
   struct buffer *other;
+  int undo_enabled_p = !EQ (current_buffer->undo_list, Qt);
+  int begv = BEGV, zv = ZV;
+  int narrowed = (BEG != begv || Z != zv);
+  int modified_p = !NILP (Fbuffer_modified_p (Qnil));
 
   if (current_buffer->base_buffer)
     error ("Cannot do `set-buffer-multibyte' on an indirect buffer");
@@ -1824,14 +1958,20 @@ but the contents viewed as characters do change.")
 
   /* It would be better to update the list,
      but this is good enough for now.  */
-  if (! EQ (current_buffer->undo_list, Qt))
-    current_buffer->undo_list = Qnil;
+  if (undo_enabled_p)
+    current_buffer->undo_list = Qt;
 
   /* If the cached position is for this buffer, clear it out.  */
   clear_charpos_cache (current_buffer);
 
+  if (narrowed)
+    Fwiden ();
+
   if (NILP (flag))
     {
+      int pos, stop;
+      unsigned char *p;
+
       /* Do this first, so it can use CHAR_TO_BYTE
         to calculate the old correspondences.  */
       set_intervals_multibyte (0);
@@ -1850,12 +1990,54 @@ but the contents viewed as characters do change.")
          XMARKER (tail)->charpos = XMARKER (tail)->bytepos;
          tail = XMARKER (tail)->chain;
        }
+
+      /* Convert multibyte form of 8-bit characters to unibyte.  */
+      pos = BEG;
+      stop = GPT;
+      p = BEG_ADDR;
+      while (1)
+       {
+         int c, bytes;
+
+         if (pos == stop)
+           {
+             if (pos == Z)
+               break;
+             p = GAP_END_ADDR;
+             stop = Z;
+           }
+         if (MULTIBYTE_STR_AS_UNIBYTE_P (p, bytes))
+           p += bytes, pos += bytes;
+         else
+           {
+             c = STRING_CHAR (p, stop - pos);
+             /* Delete all bytes for this 8-bit character but the
+                last one, and change the last one to the charcter
+                code.  */
+             bytes--;
+             del_range_2 (pos, pos, pos + bytes, pos + bytes, 0);
+             p = GAP_END_ADDR;
+             *p++ = c;
+             pos++;
+             if (begv > pos)
+               begv -= bytes;
+             if (zv > pos)
+               zv -= bytes;
+             stop = Z;
+           }
+       }
+      if (narrowed)
+       Fnarrow_to_region (make_number (begv), make_number (zv));
     }
   else
     {
+      int pt = PT;
+      int pos, stop;
+      unsigned char *p;
+
       /* Be sure not to have a multibyte sequence striding over the GAP.
-        Ex: We change this: "...abc\201\241\241 _GAP_ \241\241\241..."
-            to: "...abc _GAP_ \201\241\241\241\241\241..."  */
+        Ex: We change this: "...abc\201 _GAP_ \241def..."
+            to: "...abc _GAP_ \201\241def..."  */
 
       if (GPT_BYTE > 1 && GPT_BYTE < Z_BYTE
          && ! CHAR_HEAD_P (*(GAP_END_ADDR)))
@@ -1871,6 +2053,53 @@ but the contents viewed as characters do change.")
            }
        }
 
+      /* Make the buffer contents valid as multibyte by converting
+        8-bit characters to multibyte form.  */
+      pos = BEG;
+      stop = GPT;
+      p = BEG_ADDR;
+      while (1)
+       {
+         int bytes;
+
+         if (pos == stop)
+           {
+             if (pos == Z)
+               break;
+             p = GAP_END_ADDR;
+             stop = Z;
+           }
+             
+         if (UNIBYTE_STR_AS_MULTIBYTE_P (p, stop - pos, bytes))
+           p += bytes, pos += bytes;
+         else
+           {
+             unsigned char tmp[MAX_MULTIBYTE_LENGTH];
+
+             bytes = CHAR_STRING (*p, tmp);
+             *p = tmp[0];
+             TEMP_SET_PT_BOTH (pos + 1, pos + 1);
+             bytes--;
+             insert_1_both (tmp + 1, bytes, bytes, 1, 0, 0);
+             /* Now the gap is after the just inserted data.  */
+             pos = GPT;
+             p = GAP_END_ADDR;
+             if (pos <= begv)
+               begv += bytes;
+             if (pos <= zv)
+               zv += bytes;
+             if (pos <= pt)
+               pt += bytes;
+             stop = Z;
+           }
+       }
+
+      if (pt != PT)
+       TEMP_SET_PT (pt);
+
+      if (narrowed)
+       Fnarrow_to_region (make_number (begv), make_number (zv));
+
       /* Do this first, so that chars_in_text asks the right question.
         set_intervals_multibyte needs it too.  */
       current_buffer->enable_multibyte_characters = Qt;
@@ -1931,6 +2160,9 @@ but the contents viewed as characters do change.")
       set_intervals_multibyte (1);
     }
 
+  if (undo_enabled_p)
+    current_buffer->undo_list = Qnil;
+
   /* Changing the multibyteness of a buffer means that all windows
      showing that buffer must be updated thoroughly.  */
   current_buffer->prevent_redisplay_optimizations_p = 1;
@@ -1946,6 +2178,10 @@ but the contents viewed as characters do change.")
        other->prevent_redisplay_optimizations_p = 1;
       }
 
+  /* Restore the modifiedness of the buffer.  */
+  if (!modified_p && !NILP (Fbuffer_modified_p (Qnil)))
+    Fset_buffer_modified_p (Qnil);
+
   return flag;
 }
 \f
@@ -2025,27 +2261,27 @@ swap_out_buffer_local_variables (b)
       sym = XCAR (XCAR (alist));
 
       /* Need not do anything if some other buffer's binding is now encached.  */
-      tem = XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->buffer;
+      tem = XBUFFER_LOCAL_VALUE (SYMBOL_VALUE (sym))->buffer;
       if (BUFFERP (tem) && XBUFFER (tem) == current_buffer)
        {
          /* Symbol is set up for this buffer's old local value.
             Set it up for the current buffer with the default value.  */
 
-         tem = XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->cdr;
+         tem = XBUFFER_LOCAL_VALUE (SYMBOL_VALUE (sym))->cdr;
          /* Store the symbol's current value into the alist entry
             it is currently set up for.  This is so that, if the
             local is marked permanent, and we make it local again
             later in Fkill_all_local_variables, we don't lose the value.  */
          XCDR (XCAR (tem))
-           = do_symval_forwarding (XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->realvalue);
+           = do_symval_forwarding (XBUFFER_LOCAL_VALUE (SYMBOL_VALUE (sym))->realvalue);
          /* Switch to the symbol's default-value alist entry.  */
          XCAR (tem) = tem;
          /* Mark it as current for buffer B.  */
-         XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->buffer = buffer;
+         XBUFFER_LOCAL_VALUE (SYMBOL_VALUE (sym))->buffer = buffer;
          /* Store the current value into any forwarding in the symbol.  */
          store_symval_forwarding (sym,
-                                  XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->realvalue,
-                                  XCDR (tem));
+                                  XBUFFER_LOCAL_VALUE (SYMBOL_VALUE (sym))->realvalue,
+                                  XCDR (tem), NULL);
        }
     }
 }
@@ -2066,16 +2302,21 @@ swap_out_buffer_local_variables (b)
    If EXTEND is non-zero, we make the vector bigger if necessary.
    If EXTEND is zero, we never extend the vector,
    and we store only as many overlays as will fit.
-   But we still return the total number of overlays.  */
+   But we still return the total number of overlays.
+
+   If CHANGE_REQ is true, then any position written into *PREV_PTR or
+   *NEXT_PTR is guaranteed to be not equal to POS, unless it is the
+   default (BEGV or ZV).  */
 
 int
-overlays_at (pos, extend, vec_ptr, len_ptr, next_ptr, prev_ptr)
+overlays_at (pos, extend, vec_ptr, len_ptr, next_ptr, prev_ptr, change_req)
      int pos;
      int extend;
      Lisp_Object **vec_ptr;
      int *len_ptr;
      int *next_ptr;
      int *prev_ptr;
+     int change_req;
 {
   Lisp_Object tail, overlay, start, end;
   int idx = 0;
@@ -2181,7 +2422,8 @@ overlays_at (pos, extend, vec_ptr, len_ptr, next_ptr, prev_ptr)
        }
       else if (endpos < pos && endpos > prev)
        prev = endpos;
-      else if (endpos == pos && startpos > prev)
+      else if (endpos == pos && startpos > prev
+              && (!change_req || startpos < pos))
        prev = startpos;
     }
 
@@ -2323,6 +2565,39 @@ overlays_in (beg, end, extend, vec_ptr, len_ptr, next_ptr, prev_ptr)
     *prev_ptr = prev;
   return idx;
 }
+
+
+/* Return non-zero if there exists an overlay with a non-nil
+   `mouse-face' property overlapping OVERLAY.  */
+
+int
+mouse_face_overlay_overlaps (overlay)
+     Lisp_Object overlay;
+{
+  int start = OVERLAY_POSITION (OVERLAY_START (overlay));
+  int end = OVERLAY_POSITION (OVERLAY_END (overlay));
+  int n, i, size;
+  Lisp_Object *v, tem;
+  
+  size = 10;
+  v = (Lisp_Object *) alloca (size * sizeof *v);
+  n = overlays_in (start, end, 0, &v, &size, NULL, NULL);
+  if (n > size)
+    {
+      v = (Lisp_Object *) alloca (n * sizeof *v);
+      overlays_in (start, end, 0, &v, &n, NULL, NULL);
+    }
+
+  for (i = 0; i < n; ++i)
+    if (!EQ (v[i], overlay)
+       && (tem = Foverlay_get (overlay, Qmouse_face),
+           !NILP (tem)))
+      break;
+
+  return i < n;
+}
+
+
 \f
 /* Fast function to just test if we're at an overlay boundary.  */
 int
@@ -3129,13 +3404,11 @@ modify_overlay (buf, start, end)
      struct buffer *buf;
      int start, end;
 {
-  if (start == end)
-    return;
-
   if (start > end)
     {
       int temp = start;
-      start = end; end = temp;
+      start = end;
+      end = temp;
     }
 
   BUF_COMPUTE_UNCHANGED (buf, start, end);
@@ -3274,19 +3547,25 @@ DEFUN ("delete-overlay", Fdelete_overlay, Sdelete_overlay, 1, 1, 0,
     return Qnil;
 
   b = XBUFFER (buffer);
-
   specbind (Qinhibit_quit, Qt);
-
+  
   b->overlays_before = Fdelq (overlay, b->overlays_before);
-  b->overlays_after  = Fdelq (overlay, b->overlays_after);
-
+  b->overlays_after = Fdelq (overlay, b->overlays_after);
   modify_overlay (b,
                  marker_position (OVERLAY_START (overlay)),
                  marker_position (OVERLAY_END   (overlay)));
-
   Fset_marker (OVERLAY_START (overlay), Qnil, Qnil);
   Fset_marker (OVERLAY_END   (overlay), Qnil, Qnil);
 
+  /* When deleting an overlay with before or after strings, turn off
+     display optimizations for the affected buffer, on the basis that
+     these strings may contain newlines.  This is easier to do than to
+     check for that situation during redisplay.  */
+  if (!windows_or_buffers_changed
+      && (!NILP (Foverlay_get (overlay, Qbefore_string))
+         || !NILP (Foverlay_get (overlay, Qafter_string))))
+    b->prevent_redisplay_optimizations_p = 1;
+
   return unbind_to (count, Qnil);
 }
 \f
@@ -3348,12 +3627,13 @@ DEFUN ("overlays-at", Foverlays_at, Soverlays_at, 1, 1, 0,
   CHECK_NUMBER_COERCE_MARKER (pos, 0);
 
   len = 10;
+  /* We can't use alloca here because overlays_at can call xrealloc.  */
   overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
 
   /* Put all the overlays we want in a vector in overlay_vec.
      Store the length in len.  */
   noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
-                          (int *) 0, (int *) 0);
+                          (int *) 0, (int *) 0, 0);
 
   /* Make a list of them all.  */
   result = Flist (noverlays, overlay_vec);
@@ -3416,7 +3696,7 @@ If there are no more overlay boundaries after POS, return (point-max).")
      Store the length in len.
      endpos gets the position where the next overlay starts.  */
   noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
-                          &endpos, (int *) 0);
+                          &endpos, (int *) 0, 1);
 
   /* If any of these overlays ends before endpos,
      use its ending point instead.  */
@@ -3449,19 +3729,19 @@ If there are no more overlay boundaries before POS, return (point-min).")
 
   CHECK_NUMBER_COERCE_MARKER (pos, 0);
 
-  len = 10;
-  overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
-
   /* At beginning of buffer, we know the answer;
      avoid bug subtracting 1 below.  */
   if (XINT (pos) == BEGV)
     return pos;
 
+  len = 10;
+  overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
+
   /* Put all the overlays we want in a vector in overlay_vec.
      Store the length in len.
      prevpos gets the position of the previous change.  */
   noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
-                          (int *) 0, &prevpos);
+                          (int *) 0, &prevpos, 1);
 
   xfree (overlay_vec);
   return make_number (prevpos);
@@ -3559,8 +3839,8 @@ DEFUN ("overlay-put", Foverlay_put, Soverlay_put, 3, 3, 0,
     {
       if (changed)
        modify_overlay (XBUFFER (buffer),
-                         marker_position (OVERLAY_START (overlay)),
-                         marker_position (OVERLAY_END   (overlay)));
+                       marker_position (OVERLAY_START (overlay)),
+                       marker_position (OVERLAY_END   (overlay)));
       if (EQ (prop, Qevaporate) && ! NILP (value)
          && (OVERLAY_POSITION (OVERLAY_START (overlay))
              == OVERLAY_POSITION (OVERLAY_END (overlay))))
@@ -3877,6 +4157,547 @@ buffer_slot_type_mismatch (offset)
 }
 
 \f
+/***********************************************************************
+                        Allocation with mmap
+ ***********************************************************************/
+
+#ifdef USE_MMAP_FOR_BUFFERS
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#ifndef MAP_ANON
+#ifdef MAP_ANONYMOUS
+#define MAP_ANON MAP_ANONYMOUS
+#else
+#define MAP_ANON 0
+#endif
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#if MAP_ANON == 0
+#include <fcntl.h>
+#endif
+
+#include "coding.h"
+
+
+/* Memory is allocated in regions which are mapped using mmap(2).
+   The current implementation lets the system select mapped
+   addresses;  we're not using MAP_FIXED in general, except when
+   trying to enlarge regions.
+
+   Each mapped region starts with a mmap_region structure, the user
+   area starts after that structure, aligned to MEM_ALIGN.
+
+       +-----------------------+
+       | struct mmap_info +    |
+       | padding               |
+       +-----------------------+
+       | user data             |
+       |                       |
+       |                       |
+       +-----------------------+  */
+
+struct mmap_region
+{
+  /* User-specified size.  */
+  size_t nbytes_specified;
+  
+  /* Number of bytes mapped */
+  size_t nbytes_mapped;
+
+  /* Pointer to the location holding the address of the memory
+     allocated with the mmap'd block.  The variable actually points
+     after this structure.  */
+  POINTER_TYPE **var;
+
+  /* Next and previous in list of all mmap'd regions.  */
+  struct mmap_region *next, *prev;
+};
+
+/* Doubly-linked list of mmap'd regions.  */
+
+static struct mmap_region *mmap_regions;
+
+/* File descriptor for mmap.  If we don't have anonymous mapping,
+   /dev/zero will be opened on it.  */
+
+static int mmap_fd;
+
+/* Temporary storage for mmap_set_vars, see there.  */
+
+static struct mmap_region *mmap_regions_1;
+static int mmap_fd_1;
+
+/* Page size on this system.  */
+
+static int mmap_page_size;
+
+/* 1 means mmap has been intialized.  */
+
+static int mmap_initialized_p;
+
+/* Value is X rounded up to the next multiple of N.  */
+
+#define ROUND(X, N)    (((X) + (N) - 1) / (N) * (N))
+
+/* Size of mmap_region structure plus padding.  */
+
+#define MMAP_REGION_STRUCT_SIZE        \
+     ROUND (sizeof (struct mmap_region), MEM_ALIGN)
+
+/* Given a pointer P to the start of the user-visible part of a mapped
+   region, return a pointer to the start of the region.  */
+
+#define MMAP_REGION(P) \
+     ((struct mmap_region *) ((char *) (P) - MMAP_REGION_STRUCT_SIZE))
+
+/* Given a pointer P to the start of a mapped region, return a pointer
+   to the start of the user-visible part of the region.  */
+
+#define MMAP_USER_AREA(P) \
+     ((POINTER_TYPE *) ((char *) (P) + MMAP_REGION_STRUCT_SIZE))
+
+#define MEM_ALIGN      sizeof (double)
+
+/* Function prototypes.  */
+
+static int mmap_free_1 P_ ((struct mmap_region *));
+static int mmap_enlarge P_ ((struct mmap_region *, int));
+static struct mmap_region *mmap_find P_ ((POINTER_TYPE *, POINTER_TYPE *));
+static POINTER_TYPE *mmap_alloc P_ ((POINTER_TYPE **, size_t));
+static POINTER_TYPE *mmap_realloc P_ ((POINTER_TYPE **, size_t));
+static void mmap_free P_ ((POINTER_TYPE **ptr));
+static void mmap_init P_ ((void));
+
+
+/* Return a region overlapping address range START...END, or null if
+   none.  END is not including, i.e. the last byte in the range
+   is at END - 1.  */
+
+static struct mmap_region *
+mmap_find (start, end)
+     POINTER_TYPE *start, *end;
+{
+  struct mmap_region *r;
+  char *s = (char *) start, *e = (char *) end;
+  
+  for (r = mmap_regions; r; r = r->next)
+    {
+      char *rstart = (char *) r;
+      char *rend   = rstart + r->nbytes_mapped;
+
+      if (/* First byte of range, i.e. START, in this region?  */
+         (s >= rstart && s < rend)
+         /* Last byte of range, i.e. END - 1, in this region?  */
+         || (e > rstart && e <= rend)
+         /* First byte of this region in the range?  */
+         || (rstart >= s && rstart < e)
+         /* Last byte of this region in the range?  */
+         || (rend > s && rend <= e))
+       break;
+    }
+
+  return r;
+}
+
+
+/* Unmap a region.  P is a pointer to the start of the user-araa of
+   the region.  Value is non-zero if successful.  */
+
+static int
+mmap_free_1 (r)
+     struct mmap_region *r;
+{
+  if (r->next)
+    r->next->prev = r->prev;
+  if (r->prev)
+    r->prev->next = r->next;
+  else
+    mmap_regions = r->next;
+  
+  if (munmap ((POINTER_TYPE *) r, r->nbytes_mapped) == -1)
+    {
+      fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
+      return 0;
+    }
+
+  return 1;
+}
+
+
+/* Enlarge region R by NPAGES pages.  NPAGES < 0 means shrink R.
+   Value is non-zero if successful.  */
+
+static int
+mmap_enlarge (r, npages)
+     struct mmap_region *r;
+     int npages;
+{
+  char *region_end = (char *) r + r->nbytes_mapped;
+  size_t nbytes;
+  int success = 0;
+
+  if (npages < 0)
+    {
+      /* Unmap pages at the end of the region.  */
+      nbytes = - npages * mmap_page_size;
+      if (munmap (region_end - nbytes, nbytes) == -1)
+       fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
+      else
+       {
+         r->nbytes_mapped -= nbytes;
+         success = 1;
+       }
+    }
+  else if (npages > 0)
+    {
+      struct mmap_region *r2;
+      
+      nbytes = npages * mmap_page_size;
+      
+      /* Try to map additional pages at the end of the region.  We
+        cannot do this if the address range is already occupied by
+        something else because mmap deletes any previous mapping.
+        I'm not sure this is worth doing, let's see.  */
+      r2 = mmap_find (region_end, region_end + nbytes);
+      if (r2 == NULL)
+       {
+         POINTER_TYPE *p;
+      
+         p = mmap (region_end, nbytes, PROT_READ | PROT_WRITE,
+                   MAP_ANON | MAP_PRIVATE | MAP_FIXED, mmap_fd, 0);
+         if (p == MAP_FAILED)
+           ; /* fprintf (stderr, "mmap: %s\n", emacs_strerror (errno)); */
+         else if (p != (POINTER_TYPE *) region_end)
+           {
+             /* Kernels are free to choose a different address.  In
+                that case, unmap what we've mapped above; we have
+                no use for it.  */
+             if (munmap (p, nbytes) == -1)
+               fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
+           }
+         else
+           {
+             r->nbytes_mapped += nbytes;
+             success = 1;
+           }
+       }
+    }
+
+  return success;
+}
+
+
+/* Set or reset variables holding references to mapped regions.  If
+   RESTORE_P is zero, set all variables to null.  If RESTORE_P is
+   non-zero, set all variables to the start of the user-areas
+   of mapped regions.
+
+   This function is called from Fdump_emacs to ensure that the dumped
+   Emacs doesn't contain references to memory that won't be mapped
+   when Emacs starts.  */
+
+void
+mmap_set_vars (restore_p)
+     int restore_p;
+{
+  struct mmap_region *r;
+
+  if (restore_p)
+    {
+      mmap_regions = mmap_regions_1;
+      mmap_fd = mmap_fd_1;
+      for (r = mmap_regions; r; r = r->next)
+       *r->var = MMAP_USER_AREA (r);
+    }
+  else
+    {
+      for (r = mmap_regions; r; r = r->next)
+       *r->var = NULL;
+      mmap_regions_1 = mmap_regions;
+      mmap_regions = NULL;
+      mmap_fd_1 = mmap_fd;
+      mmap_fd = -1;
+    }
+}
+
+
+/* Allocate a block of storage large enough to hold NBYTES bytes of
+   data.  A pointer to the data is returned in *VAR.  VAR is thus the
+   address of some variable which will use the data area.
+
+   The allocation of 0 bytes is valid.
+
+   If we can't allocate the necessary memory, set *VAR to null, and
+   return null.  */
+
+static POINTER_TYPE *
+mmap_alloc (var, nbytes)
+     POINTER_TYPE **var;
+     size_t nbytes;
+{
+  void *p;
+  size_t map;
+
+  mmap_init ();
+
+  map = ROUND (nbytes + MMAP_REGION_STRUCT_SIZE, mmap_page_size);
+  p = mmap (NULL, map, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
+           mmap_fd, 0);
+  
+  if (p == MAP_FAILED)
+    {
+      if (errno != ENOMEM)
+       fprintf (stderr, "mmap: %s\n", emacs_strerror (errno));
+      p = NULL;
+    }
+  else
+    {
+      struct mmap_region *r = (struct mmap_region *) p;
+      
+      r->nbytes_specified = nbytes;
+      r->nbytes_mapped = map;
+      r->var = var;
+      r->prev = NULL;
+      r->next = mmap_regions;
+      if (r->next)
+       r->next->prev = r;
+      mmap_regions = r;
+      
+      p = MMAP_USER_AREA (p);
+    }
+  
+  return *var = p;
+}
+
+
+/* Given a pointer at address VAR to data allocated with mmap_alloc,
+   resize it to size NBYTES.  Change *VAR to reflect the new block,
+   and return this value.  If more memory cannot be allocated, then
+   leave *VAR unchanged, and return null.  */
+
+static POINTER_TYPE *
+mmap_realloc (var, nbytes)
+     POINTER_TYPE **var;
+     size_t nbytes;
+{
+  POINTER_TYPE *result;
+  
+  mmap_init ();
+
+  if (*var == NULL)
+    result = mmap_alloc (var, nbytes);
+  else if (nbytes == 0) 
+    {
+      mmap_free (var);
+      result = mmap_alloc (var, nbytes);
+    }
+  else
+    {
+      struct mmap_region *r = MMAP_REGION (*var);
+      size_t room = r->nbytes_mapped - MMAP_REGION_STRUCT_SIZE;
+      
+      if (room < nbytes)
+       {
+         /* Must enlarge.  */
+         POINTER_TYPE *old_ptr = *var;
+
+         /* Try to map additional pages at the end of the region.
+            If that fails, allocate a new region,  copy data
+            from the old region, then free it.  */
+         if (mmap_enlarge (r, (ROUND (nbytes - room, mmap_page_size)
+                               / mmap_page_size)))
+           {
+             r->nbytes_specified = nbytes;
+             *var = result = old_ptr;
+           }
+         else if (mmap_alloc (var, nbytes))
+           {
+             bcopy (old_ptr, *var, r->nbytes_specified);
+             mmap_free_1 (MMAP_REGION (old_ptr));
+             result = *var;
+             r = MMAP_REGION (result);
+             r->nbytes_specified = nbytes;
+           }
+         else
+           {
+             *var = old_ptr;
+             result = NULL;
+           }
+       }
+      else if (room - nbytes >= mmap_page_size)
+       {
+         /* Shrinking by at least a page.  Let's give some
+            memory back to the system.  */
+         mmap_enlarge (r, - (room - nbytes) / mmap_page_size);
+         result = *var;
+         r->nbytes_specified = nbytes;
+       }
+      else
+       {
+         /* Leave it alone.  */
+         result = *var;
+         r->nbytes_specified = nbytes;
+       }
+    }
+
+  return result;
+}
+
+
+/* Free a block of relocatable storage whose data is pointed to by
+   PTR.  Store 0 in *PTR to show there's no block allocated.  */
+
+static void
+mmap_free (var)
+     POINTER_TYPE **var;
+{
+  mmap_init ();
+  
+  if (*var)
+    {
+      mmap_free_1 (MMAP_REGION (*var));
+      *var = NULL;
+    }
+}
+
+
+/* Perform necessary intializations for the use of mmap.  */
+
+static void
+mmap_init ()
+{
+#if MAP_ANON == 0
+  /* The value of mmap_fd is initially 0 in temacs, and -1
+     in a dumped Emacs.  */
+  if (mmap_fd <= 0)
+    {
+      /* No anonymous mmap -- we need the file descriptor.  */
+      mmap_fd = open ("/dev/zero", O_RDONLY);
+      if (mmap_fd == -1)
+       fatal ("Cannot open /dev/zero: %s", emacs_strerror (errno));
+    }
+#endif /* MAP_ANON == 0 */
+
+  if (mmap_initialized_p)
+    return;
+  mmap_initialized_p = 1;
+  
+#if MAP_ANON != 0
+  mmap_fd = -1;
+#endif
+  
+  mmap_page_size = getpagesize ();
+}
+
+#endif /* USE_MMAP_FOR_BUFFERS */
+
+
+\f
+/***********************************************************************
+                           Buffer-text Allocation
+ ***********************************************************************/
+
+#ifdef REL_ALLOC
+extern POINTER_TYPE *r_alloc P_ ((POINTER_TYPE **, size_t));
+extern POINTER_TYPE *r_re_alloc P_ ((POINTER_TYPE **, size_t));
+extern void r_alloc_free P_ ((POINTER_TYPE **ptr));
+#endif /* REL_ALLOC */
+
+
+/* Allocate NBYTES bytes for buffer B's text buffer.  */
+
+static void
+alloc_buffer_text (b, nbytes)
+     struct buffer *b;
+     size_t nbytes;
+{
+  POINTER_TYPE *p;
+  
+  BLOCK_INPUT;
+#if defined USE_MMAP_FOR_BUFFERS
+  p = mmap_alloc ((POINTER_TYPE **) &b->text->beg, nbytes);
+#elif defined REL_ALLOC
+  p = r_alloc ((POINTER_TYPE **) &b->text->beg, nbytes);
+#else
+  p = xmalloc (nbytes);
+#endif
+  
+  if (p == NULL)
+    {
+      UNBLOCK_INPUT;
+      memory_full ();
+    }
+
+  b->text->beg = (unsigned char *) p;
+  UNBLOCK_INPUT;
+}
+
+/* Enlarge buffer B's text buffer by DELTA bytes.  DELTA < 0 means
+   shrink it.  */
+
+void
+enlarge_buffer_text (b, delta)
+     struct buffer *b;
+     int delta;
+{
+  POINTER_TYPE *p;
+  size_t nbytes = (BUF_Z_BYTE (b) - BUF_BEG_BYTE (b) + BUF_GAP_SIZE (b) + 1
+                  + delta);
+  BLOCK_INPUT;
+#if defined USE_MMAP_FOR_BUFFERS
+  p = mmap_realloc ((POINTER_TYPE **) &b->text->beg, nbytes);
+#elif defined REL_ALLOC
+  p = r_re_alloc ((POINTER_TYPE **) &b->text->beg, nbytes);
+#else
+  p = xrealloc (b->text->beg, nbytes);
+#endif
+  
+  if (p == NULL)
+    {
+      UNBLOCK_INPUT;
+      memory_full ();
+    }
+
+  BUF_BEG_ADDR (b) = (unsigned char *) p;
+  UNBLOCK_INPUT;
+}
+
+
+/* Free buffer B's text buffer.  */
+
+static void
+free_buffer_text (b)
+     struct buffer *b;
+{
+  BLOCK_INPUT;
+
+#if defined USE_MMAP_FOR_BUFFERS
+  mmap_free ((POINTER_TYPE **) &b->text->beg);
+#elif defined REL_ALLOC
+  r_alloc_free ((POINTER_TYPE **) &b->text->beg);
+#else
+  xfree (b->text->beg);
+#endif
+  
+  BUF_BEG_ADDR (b) = NULL;
+  UNBLOCK_INPUT;
+}
+
+
+\f
+/***********************************************************************
+                           Initialization
+ ***********************************************************************/
+
 void
 init_buffer_once ()
 {
@@ -3901,7 +4722,7 @@ init_buffer_once ()
   /* Set up the default values of various buffer slots.  */
   /* Must do these before making the first buffer! */
 
-  /* real setup is done in loaddefs.el */
+  /* real setup is done in bindings.el */
   buffer_defaults.mode_line_format = build_string ("%-");
   buffer_defaults.header_line_format = Qnil;
   buffer_defaults.abbrev_mode = Qnil;
@@ -3926,6 +4747,7 @@ init_buffer_once ()
   buffer_defaults.ctl_arrow = Qt;
   buffer_defaults.direction_reversed = Qnil;
   buffer_defaults.cursor_type = Qt;
+  buffer_defaults.extra_line_spacing = Qnil;
 
 #ifdef DOS_NT
   buffer_defaults.buffer_file_type = Qnil; /* TEXT */
@@ -4006,6 +4828,7 @@ init_buffer_once ()
   XSETFASTINT (buffer_local_flags.scroll_down_aggressively, idx); ++idx;
   XSETFASTINT (buffer_local_flags.header_line_format, idx); ++idx;
   XSETFASTINT (buffer_local_flags.cursor_type, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.extra_line_spacing, idx); ++idx;
 
   /* Need more room? */
   if (idx >= MAX_PER_BUFFER_VARS)
@@ -4042,12 +4865,25 @@ init_buffer_once ()
 void
 init_buffer ()
 {
-  char buf[MAXPATHLEN+1];
+  char buf[MAXPATHLEN + 1];
   char *pwd;
   struct stat dotstat, pwdstat;
   Lisp_Object temp;
   int rc;
 
+#ifdef USE_MMAP_FOR_BUFFERS
+ {
+   /* When using the ralloc implementation based on mmap(2), buffer
+      text pointers will have been set to null in the dumped Emacs.
+      Map new memory.  */
+   struct buffer *b;
+   
+   for (b = all_buffers; b; b = b->next)
+     if (b->text->beg == NULL)
+       enlarge_buffer_text (b, 0);
+ }
+#endif /* USE_MMAP_FOR_BUFFERS */
+  
   Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
   if (NILP (buffer_defaults.enable_multibyte_characters))
     Fset_buffer_multibyte (Qnil);
@@ -4165,6 +5001,11 @@ This is the same as (default-value 'header-line-format).");
     "Default value of `cursor-type' for buffers that don't override it.\n\
 This is the same as (default-value 'cursor-type).");
 
+  DEFVAR_LISP_NOPRO ("default-line-spacing",
+                    &buffer_defaults.extra_line_spacing,
+    "Default value of `line-spacing' for buffers that don't override it.\n\
+This is the same as (default-value 'line-spacing).");
+
   DEFVAR_LISP_NOPRO ("default-abbrev-mode",
              &buffer_defaults.abbrev_mode,
     "Default value of `abbrev-mode' for buffers that do not override it.\n\
@@ -4253,8 +5094,8 @@ don't override it.  This is the same as (default-value\n\
   DEFVAR_PER_BUFFER ("header-line-format",
                     &current_buffer->header_line_format, 
                     Qnil,
-   "Analogous to `mode-line-format', but for a mode line displayed\n\
-at the top of windows.");
+   "Analogous to `mode-line-format', but for the mode line that can be\n\
+displayed at the top of a window.");
   
   DEFVAR_PER_BUFFER ("mode-line-format", &current_buffer->mode_line_format, 
                     Qnil, 0);
@@ -4403,12 +5244,14 @@ On other systems, this variable is normally always nil.");
   DEFVAR_PER_BUFFER ("default-directory", &current_buffer->directory,
                     make_number (Lisp_String),
     "Name of default directory of current buffer.  Should end with slash.\n\
-Each buffer has its own value of this variable.");
+Each buffer has its own value of this variable.  To change the\n\
+default directory, use function `cd'.");
 
   DEFVAR_PER_BUFFER ("auto-fill-function", &current_buffer->auto_fill_function,
                     Qnil,
     "Function called (if non-nil) to perform auto-fill.\n\
-It is called after self-inserting a space or newline.\n\
+It is called after self-inserting any character specified in\n\
+the `auto-fill-chars' table.\n\
 Each buffer has its own value of this variable.\n\
 NOTE: This variable is not a hook;\n\
 its value may not be a list of functions.");
@@ -4480,11 +5323,27 @@ Automatically becomes buffer-local when set in any fashion.");
                     Qnil,
     "Display table that controls display of the contents of current buffer.\n\
 Automatically becomes buffer-local when set in any fashion.\n\
+\n\
+If this variable is nil, the value of `standard-display-table' is used.\n\
+Each window can have its own, overriding display table, see\n\
+`set-window-display-table' and `window-display-table'.\n\
+\n\
 The display table is a char-table created with `make-display-table'.\n\
-The ordinary char-table elements control how to display each possible text\n\
-character.  Each value should be a vector of characters or nil;\n\
-nil means display the character in the default fashion.\n\
-There are six extra slots to control the display of\n\
+A char-table is an array indexed by character codes.  Normal array\n\
+primitives `aref' and `aset' can be used to access elements of a char-table.\n\
+\n\
+Each of the char-table elements control how to display the corresponding\n\
+text character: the element at index C in the table says how to display\n\
+the character whose code is C.  Each element should be a vector of\n\
+characters or nil.  nil means display the character in the default fashion;\n\
+otherwise, the characters from the vector are delivered to the screen\n\
+instead of the original character.\n\
+\n\
+For example, (aset buffer-display-table ?X ?Y) will cause Emacs to display\n\
+a capital Y instead of each X character.\n\
+\n\
+In addition, a char-table has six extra slots to control the display of:\n\
+\n\
   the end of a truncated screen line (extra-slot 0, a single character);\n\
   the end of a continued line (extra-slot 1, a single character);\n\
   the escape character used to display character codes in octal\n\
@@ -4495,9 +5354,8 @@ There are six extra slots to control the display of\n\
     a vector of characters);\n\
   the character used to draw the border between side-by-side windows\n\
     (extra-slot 5, a single character).\n\
-See also the functions `display-table-slot' and `set-display-table-slot'.\n\
-If this variable is nil, the value of `standard-display-table' is used.\n\
-Each window can have its own, overriding display table.");
+\n\
+See also the functions `display-table-slot' and `set-display-table-slot'.");
 #endif
   DEFVAR_PER_BUFFER ("buffer-display-table", &current_buffer->display_table,
                     Qnil, 0);
@@ -4526,7 +5384,7 @@ Automatically becomes buffer-local when set in any fashion.\n");
     "*If a number, scroll display up aggressively.\n\
 If scrolling a window because point is above the window start, choose\n\
 a new window start so that point ends up that fraction of the window's\n\
-height from the bottom of the window.\n\
+height from the top of the window.\n\
 Automatically becomes buffer-local when set in any fashion.");
   
   DEFVAR_PER_BUFFER ("scroll-down-aggressively",
@@ -4534,45 +5392,12 @@ Automatically becomes buffer-local when set in any fashion.");
     "*If a number, scroll display down aggressively.\n\
 If scrolling a window because point is below the window end, choose\n\
 a new window start so that point ends up that fraction of the window's\n\
-height from the top of the window.\n\
+height from the bottom of the window.\n\
 Automatically becomes buffer-local when set in any fashion.");
   
 /*DEFVAR_LISP ("debug-check-symbol", &Vcheck_symbol,
     "Don't ask.");
 */
-  DEFVAR_LISP ("before-change-function", &Vbefore_change_function,
-      "If non-nil, a function to call before each text change (obsolete).\n\
-Two arguments are passed to the function: the positions of\n\
-the beginning and end of the range of old text to be changed.\n\
-\(For an insertion, the beginning and end are at the same place.)\n\
-No information is given about the length of the text after the change.\n\
-\n\
-Buffer changes made while executing the `before-change-function'\n\
-don't call any before-change or after-change functions.\n\
-That's because these variables are temporarily set to nil.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-these variables.  See the Emacs Lisp manual for a way of\n\
-accomplishing an equivalent result by using other variables.\n\n\
-This variable is obsolete; use `before-change-functions' instead.");
-  Vbefore_change_function = Qnil;
-
-  DEFVAR_LISP ("after-change-function", &Vafter_change_function,
-      "If non-nil, a Function to call after each text change (obsolete).\n\
-Three arguments are passed to the function: the positions of\n\
-the beginning and end of the range of changed text,\n\
-and the length of the pre-change text replaced by that range.\n\
-\(For an insertion, the pre-change length is zero;\n\
-for a deletion, that length is the number of bytes deleted,\n\
-and the post-change beginning and end are at the same place.)\n\
-\n\
-Buffer changes made while executing the `after-change-function'\n\
-don't call any before-change or after-change functions.\n\
-That's because these variables are temporarily set to nil.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-these variables.  See the Emacs Lisp manual for a way of\n\
-accomplishing an equivalent result by using other variables.\n\n\
-This variable is obsolete; use `after-change-functions' instead.");
-  Vafter_change_function = Qnil;
 
   DEFVAR_LISP ("before-change-functions", &Vbefore_change_functions,
               "List of functions to call before each text change.\n\
@@ -4752,6 +5577,11 @@ Values are interpreted as follows:\n\
   (bar . WIDTH)        display a bar cursor with width WIDTH\n\
   others       display a box cursor.");
 
+  DEFVAR_PER_BUFFER ("line-spacing",
+                    &current_buffer->extra_line_spacing, Qnil,
+    "Additional space to put between lines when displaying a buffer.\n\
+The space is measured in pixels, and put below lines on window systems.");
+
   DEFVAR_LISP ("kill-buffer-query-functions", &Vkill_buffer_query_functions,
     "List of functions called with no args to query before killing a buffer.");
   Vkill_buffer_query_functions = Qnil;