(mmap_enlarge): Don't print a message on stderr
[bpt/emacs.git] / src / buffer.c
index 533103c..1e31c93 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
        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,7 @@ extern int errno;
 #include "region-cache.h"
 #include "indent.h"
 #include "blockinput.h"
+#include "keyboard.h"
 #include "frame.h"
 
 struct buffer *current_buffer;         /* the current buffer */
@@ -73,8 +77,8 @@ static Lisp_Object Vbuffer_defaults;
    The value has only one nonzero bit.
 
    When a buffer has its own local value for a slot,
-   the bit for that slot (found in the same slot in this structure)
-   is turned on in the buffer's local_var_flags slot.
+   the entry for that slot (found in the same slot in this structure)
+   is turned on in the buffer's local_flags array.
 
    If a slot in this structure is -1, then even though there may
    be a DEFVAR_PER_BUFFER for the slot, there is no default value for it;
@@ -112,7 +116,11 @@ struct buffer buffer_local_types;
 
 /* Flags indicating which built-in buffer-local variables
    are permanent locals.  */
-static int buffer_permanent_local_flags;
+static char buffer_permanent_local_flags[MAX_PER_BUFFER_VARS];
+
+/* Number of per-buffer variables used.  */
+
+int last_per_buffer_idx;
 
 Lisp_Object Fset_buffer ();
 void set_buffer_internal ();
@@ -127,8 +135,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;
 
@@ -171,6 +177,10 @@ 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));
+
+
 /* For debugging; temporary.  See set_buffer_internal.  */
 /* Lisp_Object Qlisp_mode, Vcheck_symbol; */
 
@@ -330,7 +340,7 @@ The value is never nil.")
   if (XSTRING (name)->size == 0)
     error ("Empty string for buffer name is not allowed");
 
-  b = (struct buffer *) xmalloc (sizeof (struct buffer));
+  b = (struct buffer *) allocate_buffer ();
 
   b->size = sizeof (struct buffer) / sizeof (EMACS_INT);
 
@@ -342,7 +352,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 ();
@@ -383,7 +393,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] != ' ')
@@ -404,16 +414,61 @@ The value is never nil.")
   return buf;
 }
 
-DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer, 2, 2,
+
+/* 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;
+    }
+
+  to->overlays_after = Fcopy_sequence (from->overlays_after);
+  to->overlays_before = Fcopy_sequence (to->overlays_before);
+  bcopy (from->local_flags, to->local_flags, sizeof to->local_flags);
+}
+
+
+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))
@@ -427,8 +482,7 @@ NAME should be a string which is not the name of an existing buffer.")
   if (XSTRING (name)->size == 0)
     error ("Empty string for buffer name is not allowed");
 
-  b = (struct buffer *) xmalloc (sizeof (struct buffer));
-
+  b = (struct buffer *) allocate_buffer ();
   b->size = sizeof (struct buffer) / sizeof (EMACS_INT);
 
   if (XBUFFER (base_buffer)->base_buffer)
@@ -455,7 +509,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);
@@ -495,14 +549,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;
 }
@@ -537,9 +596,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.
@@ -557,13 +616,7 @@ reset_buffer_local_variables (b, permanent_too)
      int permanent_too;
 {
   register int offset;
-  int dont_reset;
-
-  /* Decide which built-in local variables to reset.  */
-  if (permanent_too)
-    dont_reset = 0;
-  else
-    dont_reset = buffer_permanent_local_flags;
+  int i;
 
   /* Reset the major mode to Fundamental, together with all the
      things that depend on the major mode.
@@ -598,22 +651,24 @@ reset_buffer_local_variables (b, permanent_too)
 
   /* Reset all (or most) per-buffer variables to their defaults.  */
   b->local_var_alist = Qnil;
-  b->local_var_flags &= dont_reset;
+  for (i = 0; i < last_per_buffer_idx; ++i)
+    if (permanent_too || buffer_permanent_local_flags[i] == 0)
+      SET_PER_BUFFER_VALUE_P (b, i, 0);
 
   /* For each slot that has a default value,
      copy that into the slot.  */
 
-  for (offset = (char *)&buffer_local_flags.name - (char *)&buffer_local_flags;
-       offset < sizeof (struct buffer);
-       offset += sizeof (Lisp_Object)) /* sizeof EMACS_INT == sizeof Lisp_Object */
+  for (offset = PER_BUFFER_VAR_OFFSET (name);
+       offset < sizeof *b;
+       offset += sizeof (Lisp_Object))
     {
-      int flag = XINT (*(Lisp_Object *)(offset + (char *)&buffer_local_flags));
-      if ((flag > 0
-          /* Don't reset a permanent local.  */
-          && ! (dont_reset & flag))
-         || flag == -2)
-       *(Lisp_Object *)(offset + (char *)b)
-         = *(Lisp_Object *)(offset + (char *)&buffer_defaults);
+      int idx = PER_BUFFER_IDX (offset);
+      if ((idx > 0
+          && (permanent_too
+              || buffer_permanent_local_flags[idx] == 0))
+         /* Is -2 used anywhere?  */
+         || idx == -2)
+       PER_BUFFER_VALUE (b, offset) = PER_BUFFER_DEFAULT (offset);
     }
 }
 
@@ -758,20 +813,19 @@ No argument or nil as argument means use current buffer as BUFFER.")
 
   /* Add on all the variables stored in special slots.  */
   {
-    register int offset, mask;
+    int offset, idx;
 
-    for (offset = (char *)&buffer_local_symbols.name - (char *)&buffer_local_symbols;
+    for (offset = PER_BUFFER_VAR_OFFSET (name);
         offset < sizeof (struct buffer);
-        offset += (sizeof (EMACS_INT))) /* sizeof EMACS_INT == sizeof Lisp_Object */
+        /* sizeof EMACS_INT == sizeof Lisp_Object */
+        offset += (sizeof (EMACS_INT)))
       {
-       mask = XINT (*(Lisp_Object *)(offset + (char *)&buffer_local_flags));
-       if (mask == -1 || (buf->local_var_flags & mask))
-         if (SYMBOLP (*(Lisp_Object *)(offset
-                                       + (char *)&buffer_local_symbols)))
-           result = Fcons (Fcons (*((Lisp_Object *)
-                                    (offset + (char *)&buffer_local_symbols)),
-                                  *(Lisp_Object *)(offset + (char *)buf)),
-                           result);
+       idx = PER_BUFFER_IDX (offset);
+       if ((idx == -1 || PER_BUFFER_VALUE_P (buf, idx))
+           && SYMBOLP (PER_BUFFER_SYMBOL (offset)))
+         result = Fcons (Fcons (PER_BUFFER_SYMBOL (offset),
+                                PER_BUFFER_VALUE (buf, offset)),
+                         result);
       }
   }
 
@@ -807,6 +861,7 @@ A non-nil FLAG means mark the buffer modified.")
 {
   register int already;
   register Lisp_Object fn;
+  Lisp_Object buffer, window;
 
 #ifdef CLASH_DETECTION
   /* If buffer becoming modified, lock the file.
@@ -825,7 +880,53 @@ A non-nil FLAG means mark the buffer modified.")
 #endif /* CLASH_DETECTION */
 
   SAVE_MODIFF = NILP (flag) ? MODIFF : 0;
-  update_mode_lines++;
+  
+  /* Set update_mode_lines only if buffer is displayed in some window.
+     Packages like jit-lock or lazy-lock preserve a buffer's modified
+     state by recording/restoring the state around blocks of code.
+     Setting update_mode_lines makes redisplay consider all windows
+     (on all frames).  Stealth fontification of buffers not displayed
+     would incur additional redisplay costs if we'd set
+     update_modes_lines unconditionally.
+
+     Ideally, I think there should be another mechanism for fontifying
+     buffers without "modifying" buffers, or redisplay should be
+     smarter about updating the `*' in mode lines.  --gerd  */
+  XSETBUFFER (buffer, current_buffer);
+  window = Fget_buffer_window (buffer, Qt);
+  if (WINDOWP (window))
+    update_mode_lines++;
+  
+  return flag;
+}
+
+DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p,
+       Srestore_buffer_modified_p, 1, 1, 0,
+   "Like `set-buffer-modified-p', with a differences concerning redisplay.\n\
+It is not ensured that mode lines will be updated to show the modified\n\
+state of the current buffer.  Use with care.")
+  (flag)
+     Lisp_Object flag;
+{
+#ifdef CLASH_DETECTION
+  Lisp_Object fn;
+  
+  /* If buffer becoming modified, lock the file.
+     If buffer becoming unmodified, unlock the file.  */
+
+  fn = current_buffer->file_truename;
+  /* Test buffer-file-name so that binding it to nil is effective.  */
+  if (!NILP (fn) && ! NILP (current_buffer->filename))
+    {
+      int already = SAVE_MODIFF < MODIFF;
+      if (!already && !NILP (flag))
+       lock_file (fn);
+      else if (already && NILP (flag))
+       unlock_file (fn);
+    }
+#endif /* CLASH_DETECTION */
+  
+  SAVE_MODIFF = NILP (flag) ? MODIFF : 0;
   return flag;
 }
 
@@ -871,14 +972,14 @@ This does not change the name of the visited file (if any).")
     error ("Empty string is invalid as a buffer name");
 
   tem = Fget_buffer (newname);
-  /* Don't short-circuit if UNIQUE is t.  That is a useful way to rename
-     the buffer automatically so you can create another with the original name.
-     It makes UNIQUE equivalent to
-     (rename-buffer (generate-new-buffer-name NEWNAME)).  */
-  if (NILP (unique) && XBUFFER (tem) == current_buffer)
-    return current_buffer->name;
   if (!NILP (tem))
     {
+      /* Don't short-circuit if UNIQUE is t.  That is a useful way to
+        rename the buffer automatically so you can create another
+        with the original name.  It makes UNIQUE equivalent to
+        (rename-buffer (generate-new-buffer-name NEWNAME)).  */
+      if (NILP (unique) && XBUFFER (tem) == current_buffer)
+       return current_buffer->name;
       if (!NILP (unique))
        newname = Fgenerate_new_buffer_name (newname, current_buffer->name);
       else
@@ -951,7 +1052,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))
@@ -961,8 +1062,12 @@ If BUFFER is omitted or nil, some interesting buffer is returned.")
     }
   if (!NILP (notsogood))
     return notsogood;
-  buf = Fget_buffer_create (build_string ("*scratch*"));
-  Fset_buffer_major_mode (buf);
+  buf = Fget_buffer (build_string ("*scratch*"));
+  if (NILP (buf))
+    {
+      buf = Fget_buffer_create (build_string ("*scratch*"));
+      Fset_buffer_major_mode (buf);
+    }
   return buf;
 }
 \f
@@ -1185,10 +1290,7 @@ with SIGHUP.")
          m->chain = Qnil;
        }
       BUF_MARKERS (b) = Qnil;
-
-#ifdef USE_TEXT_PROPERTIES
       BUF_INTERVALS (b) = NULL_INTERVAL;
-#endif
 
       /* Perhaps we should explicitly free the interval tree here... */
     }
@@ -1204,7 +1306,7 @@ with SIGHUP.")
 
   BLOCK_INPUT;
   if (! b->base_buffer)
-    BUFFER_FREE (BUF_BEG_ADDR (b));
+    free_buffer_text (b);
 
   if (b->newline_cache)
     {
@@ -1451,6 +1553,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;
 
@@ -1675,18 +1782,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;
 }
@@ -1745,8 +1854,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.  */
@@ -1767,6 +1885,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");
@@ -1777,14 +1899,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);
@@ -1798,17 +1926,59 @@ but the contents viewed as characters do change.")
       TEMP_SET_PT_BOTH (PT_BYTE, PT_BYTE);
 
       tail = BUF_MARKERS (current_buffer);
-      while (XSYMBOL (tail) != XSYMBOL (Qnil))
+      while (! NILP (tail))
        {
          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)))
@@ -1824,6 +1994,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;
@@ -1863,7 +2080,7 @@ but the contents viewed as characters do change.")
         It is also a signal that it should never create a marker.  */
       BUF_MARKERS (current_buffer) = Qnil;
 
-      while (XSYMBOL (tail) != XSYMBOL (Qnil))
+      while (! NILP (tail))
        {
          XMARKER (tail)->bytepos
            = advance_to_char_boundary (XMARKER (tail)->bytepos);
@@ -1884,12 +2101,27 @@ 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;
+  ++windows_or_buffers_changed;
+
   /* Copy this buffer's new multibyte status
      into all of its indirect buffers.  */
   for (other = all_buffers; other; other = other->next)
     if (other->base_buffer == current_buffer && !NILP (other->name))
-      other->enable_multibyte_characters
-       = current_buffer->enable_multibyte_characters;
+      {
+       other->enable_multibyte_characters
+         = current_buffer->enable_multibyte_characters;
+       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;
 }
@@ -1971,7 +2203,7 @@ swap_out_buffer_local_variables (b)
 
       /* Need not do anything if some other buffer's binding is now encached.  */
       tem = XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->buffer;
-      if (XBUFFER (tem) == current_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.  */
@@ -2011,16 +2243,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;
@@ -2126,7 +2363,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;
     }
 
@@ -3083,6 +3321,8 @@ modify_overlay (buf, start, end)
       start = end; end = temp;
     }
 
+  BUF_COMPUTE_UNCHANGED (buf, start, end);
+  
   /* If this is a buffer not in the selected window,
      we must do other windows.  */
   if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
@@ -3090,8 +3330,6 @@ modify_overlay (buf, start, end)
   /* If multiple windows show this buffer, we must do other windows.  */
   else if (buffer_shared > 1)
     windows_or_buffers_changed = 1;
-  else
-    BUF_COMPUTE_UNCHANGED (buf, start, end);
 
   ++BUF_OVERLAY_MODIFF (buf);
 }
@@ -3141,7 +3379,7 @@ buffer.")
 
   obuffer = Fmarker_buffer (OVERLAY_START (overlay));
   b = XBUFFER (buffer);
-  ob = XBUFFER (obuffer);
+  ob = BUFFERP (obuffer) ? XBUFFER (obuffer) : (struct buffer *) 0;
 
   /* If the overlay has changed buffers, do a thorough redisplay.  */
   if (!EQ (buffer, obuffer))
@@ -3293,12 +3531,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);
@@ -3361,7 +3600,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.  */
@@ -3394,19 +3633,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);
@@ -3797,25 +4036,574 @@ buffer_slot_type_mismatch (offset)
 {
   Lisp_Object sym;
   char *type_name;
-  sym = *(Lisp_Object *)(offset + (char *)&buffer_local_symbols);
-  switch (XINT (*(Lisp_Object *)(offset + (char *)&buffer_local_types)))
+  
+  switch (XINT (PER_BUFFER_TYPE (offset)))
     {
-    case Lisp_Int:     type_name = "integers";  break;
-    case Lisp_String:  type_name = "strings";   break;
-    case Lisp_Symbol:  type_name = "symbols";   break;
-
+    case Lisp_Int:
+      type_name = "integers";
+      break;
+      
+    case Lisp_String:
+      type_name = "strings";
+      break;
+      
+    case Lisp_Symbol:
+      type_name = "symbols";
+      break;
+      
     default:
       abort ();
     }
 
+  sym = PER_BUFFER_SYMBOL (offset);
   error ("Only %s should be stored in the buffer-local variable %s",
         type_name, XSYMBOL (sym)->name->data);
 }
+
 \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
+
+#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 (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 ()
 {
-  buffer_permanent_local_flags = 0;
+  int idx;
+
+  bzero (buffer_permanent_local_flags, sizeof buffer_permanent_local_flags);
 
   /* Make sure all markable slots in buffer_defaults
      are initialized reasonably, so mark_buffer won't choke.  */
@@ -3826,17 +4614,15 @@ init_buffer_once ()
   /* Prevent GC from getting confused.  */
   buffer_defaults.text = &buffer_defaults.own_text;
   buffer_local_symbols.text = &buffer_local_symbols.own_text;
-#ifdef USE_TEXT_PROPERTIES
   BUF_INTERVALS (&buffer_defaults) = 0;
   BUF_INTERVALS (&buffer_local_symbols) = 0;
-#endif
   XSETBUFFER (Vbuffer_defaults, &buffer_defaults);
   XSETBUFFER (Vbuffer_local_symbols, &buffer_local_symbols);
 
   /* 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;
@@ -3860,6 +4646,8 @@ init_buffer_once ()
   buffer_defaults.truncate_lines = Qnil;
   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 */
@@ -3904,40 +4692,48 @@ init_buffer_once ()
   XSETINT (buffer_local_flags.display_time, -1);
   XSETINT (buffer_local_flags.enable_multibyte_characters, -1);
 
-  XSETFASTINT (buffer_local_flags.mode_line_format, 1);
-  XSETFASTINT (buffer_local_flags.abbrev_mode, 2);
-  XSETFASTINT (buffer_local_flags.overwrite_mode, 4);
-  XSETFASTINT (buffer_local_flags.case_fold_search, 8);
-  XSETFASTINT (buffer_local_flags.auto_fill_function, 0x10);
-  XSETFASTINT (buffer_local_flags.selective_display, 0x20);
+  idx = 1;
+  XSETFASTINT (buffer_local_flags.mode_line_format, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.abbrev_mode, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.overwrite_mode, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.case_fold_search, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.auto_fill_function, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.selective_display, idx); ++idx;
 #ifndef old
-  XSETFASTINT (buffer_local_flags.selective_display_ellipses, 0x40);
+  XSETFASTINT (buffer_local_flags.selective_display_ellipses, idx); ++idx;
 #endif
-  XSETFASTINT (buffer_local_flags.tab_width, 0x80);
-  XSETFASTINT (buffer_local_flags.truncate_lines, 0x100);
-  XSETFASTINT (buffer_local_flags.ctl_arrow, 0x200);
-  XSETFASTINT (buffer_local_flags.fill_column, 0x400);
-  XSETFASTINT (buffer_local_flags.left_margin, 0x800);
-  XSETFASTINT (buffer_local_flags.abbrev_table, 0x1000);
-  XSETFASTINT (buffer_local_flags.display_table, 0x2000);
+  XSETFASTINT (buffer_local_flags.tab_width, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.truncate_lines, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.ctl_arrow, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.fill_column, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.left_margin, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.abbrev_table, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.display_table, idx); ++idx;
 #ifdef DOS_NT
-  XSETFASTINT (buffer_local_flags.buffer_file_type, 0x4000);
+  XSETFASTINT (buffer_local_flags.buffer_file_type, idx);
   /* Make this one a permanent local.  */
-  buffer_permanent_local_flags |= 0x4000;
+  buffer_permanent_local_flags[idx++] = 1;
 #endif
-  XSETFASTINT (buffer_local_flags.syntax_table, 0x8000);
-  XSETFASTINT (buffer_local_flags.cache_long_line_scans, 0x10000);
-  XSETFASTINT (buffer_local_flags.category_table, 0x20000);
-  XSETFASTINT (buffer_local_flags.direction_reversed, 0x40000);
-  XSETFASTINT (buffer_local_flags.buffer_file_coding_system, 0x80000);
+  XSETFASTINT (buffer_local_flags.syntax_table, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.cache_long_line_scans, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.category_table, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.direction_reversed, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.buffer_file_coding_system, idx); 
   /* Make this one a permanent local.  */
-  buffer_permanent_local_flags |= 0x80000;
-  XSETFASTINT (buffer_local_flags.left_margin_width, 0x100000);
-  XSETFASTINT (buffer_local_flags.right_margin_width, 0x200000);
-  XSETFASTINT (buffer_local_flags.indicate_empty_lines, 0x400000);
-  XSETFASTINT (buffer_local_flags.scroll_up_aggressively, 0x800000);
-  XSETFASTINT (buffer_local_flags.scroll_down_aggressively, 0x1000000);
-  XSETFASTINT (buffer_local_flags.header_line_format, 0x2000000);
+  buffer_permanent_local_flags[idx++] = 1;
+  XSETFASTINT (buffer_local_flags.left_margin_width, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.right_margin_width, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.indicate_empty_lines, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.scroll_up_aggressively, idx); ++idx;
+  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)
+    abort ();
+  last_per_buffer_idx = idx;
   
   Vbuffer_alist = Qnil;
   current_buffer = 0;
@@ -3969,12 +4765,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);
@@ -4088,6 +4897,15 @@ This is the same as (default-value 'mode-line-format).");
     "Default value of `header-line-format' for buffers that don't override it.\n\
 This is the same as (default-value 'header-line-format).");
 
+  DEFVAR_LISP_NOPRO ("default-cursor-type", &buffer_defaults.cursor_type,
+    "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\
@@ -4209,6 +5027,7 @@ A string is printed verbatim in the mode line except for %-constructs:\n\
   %b -- print buffer name.      %f -- print visited file name.\n\
   %F -- print frame name.\n\
   %* -- print %, * or hyphen.   %+ -- print *, % or hyphen.\n\
+       %& is like %*, but ignore read-only-ness.\n\
        % means buffer is read-only and * means it is modified.\n\
        For a modified read-only buffer, %* gives % and %+ gives *.\n\
   %s -- print process status.   %l -- print the current line number.\n\
@@ -4218,8 +5037,10 @@ A string is printed verbatim in the mode line except for %-constructs:\n\
   %p -- print percent of buffer above top of window, or Top, Bot or All.\n\
   %P -- print percent of buffer above bottom of window, perhaps plus Top,\n\
         or print Bottom or All.\n\
+  %m -- print the mode name.\n\
   %n -- print Narrow if appropriate.\n\
-  %t -- print T if file is text, B if binary.\n\
+  %z -- print mnemonics of buffer, terminal, and keyboard coding systems.\n\
+  %Z -- like %z, but including the end-of-line format.\n\
   %[ -- print one [ for each recursive editing level.  %] similar.\n\
   %% -- print %.   %- -- print infinitely many dashes.\n\
 Decimal digits after the % specify field width to which to pad.");
@@ -4328,7 +5149,8 @@ Each buffer has its own value of this variable.");
   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.");
@@ -4436,7 +5258,9 @@ A value of nil means no marginal area.");
   
   DEFVAR_PER_BUFFER ("indicate-empty-lines",
                     &current_buffer->indicate_empty_lines, Qnil,
-    "*Non-nil means visually indicate lines not displaying text.\n\
+    "*Visually indicate empty lines after the buffer end.\n\
+If non-nil, a bitmap is displayed in the left fringe of a window on\n\
+window-systems.\n\
 Automatically becomes buffer-local when set in any fashion.\n");
   
   DEFVAR_PER_BUFFER ("scroll-up-aggressively",
@@ -4444,7 +5268,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",
@@ -4452,45 +5276,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\
@@ -4660,6 +5451,21 @@ and disregard a `read-only' text property if the property value\n\
 is a member of the list.");
   Vinhibit_read_only = Qnil;
 
+  DEFVAR_PER_BUFFER ("cursor-type", &current_buffer->cursor_type, Qnil,
+    "Cursor to use in window displaying this buffer.\n\
+Values are interpreted as follows:\n\
+\n\
+  t            use the cursor specified for the frame\n\
+  nil          don't display a cursor\n\
+  `bar'                display a bar cursor with default width\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;
@@ -4711,6 +5517,7 @@ is a member of the list.");
   defsubr (&Soverlay_lists);
   defsubr (&Soverlay_get);
   defsubr (&Soverlay_put);
+  defsubr (&Srestore_buffer_modified_p);
 }
 
 void