(unchain_marker): Allow differing buffers
[bpt/emacs.git] / src / buffer.c
index 34558e2..c7caf2a 100644 (file)
@@ -1,5 +1,5 @@
 /* Buffer manipulation primitives for GNU Emacs.
-   Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994
+   Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995
        Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -255,12 +255,18 @@ The value is never nil.")
 
   b = (struct buffer *) xmalloc (sizeof (struct buffer));
 
+  b->size = sizeof (struct buffer) / sizeof (EMACS_INT);
+
+  /* An ordinary buffer uses its own struct buffer_text.  */
+  b->text = &b->own_text;
+  b->base_buffer = 0;
+
   BUF_GAP_SIZE (b) = 20;
   BLOCK_INPUT;
   BUFFER_ALLOC (BUF_BEG_ADDR (b), BUF_GAP_SIZE (b));
   UNBLOCK_INPUT;
   if (! BUF_BEG_ADDR (b))
-    memory_full ();
+    buffer_memory_full ();
 
   BUF_PT (b) = 1;
   BUF_GPT (b) = 1;
@@ -268,6 +274,8 @@ The value is never nil.")
   BUF_ZV (b) = 1;
   BUF_Z (b) = 1;
   BUF_MODIFF (b) = 1;
+  BUF_SAVE_MODIFF (b) = 1;
+  BUF_INTERVALS (b) = 0;
 
   b->newline_cache = 0;
   b->width_run_cache = 0;
@@ -277,8 +285,11 @@ The value is never nil.")
   b->next = all_buffers;
   all_buffers = b;
 
-  b->mark = Fmake_marker ();
-  /*b->number = make_number (++buffer_count);*/
+  /* An ordinary buffer normally doesn't need markers
+     to handle BEGV and ZV.  */
+  b->pt_marker = Qnil;
+  b->begv_marker = Qnil;
+  b->zv_marker = Qnil;
 
   name = Fcopy_sequence (name);
   INITIALIZE_INTERVAL (XSTRING (name), NULL_INTERVAL);
@@ -297,11 +308,100 @@ The value is never nil.")
   Vbuffer_alist = nconc2 (Vbuffer_alist, Fcons (Fcons (name, buf), Qnil));
 
   b->mark = Fmake_marker ();
-  b->markers = Qnil;
+  BUF_MARKERS (b) = Qnil;
   b->name = name;
   return buf;
 }
 
+DEFUN ("make-indirect-buffer",
+       Fmake_indirect_buffer, Smake_indirect_buffer, 2, 2,
+       "BMake indirect buffer: \nbIndirect to base buffer: ",
+  "Create and return an indirect buffer named NAME, with base buffer BASE.\n\
+BASE should be an existing buffer (or buffer name).")
+  (name, base_buffer)
+     register Lisp_Object name, base_buffer;
+{
+  register Lisp_Object buf;
+  register struct buffer *b;
+
+  buf = Fget_buffer (name);
+  if (!NILP (buf))
+    error ("Buffer name `%s' is in use", XSTRING (name)->data);
+
+  base_buffer = Fget_buffer (base_buffer);
+  if (NILP (base_buffer))
+    error ("No such buffer: `%s'",
+          XSTRING (XBUFFER (base_buffer)->name)->data);
+
+  if (XSTRING (name)->size == 0)
+    error ("Empty string for buffer name is not allowed");
+
+  b = (struct buffer *) xmalloc (sizeof (struct buffer));
+
+  b->size = sizeof (struct buffer) / sizeof (EMACS_INT);
+
+  if (XBUFFER (base_buffer)->base_buffer)
+    b->base_buffer = XBUFFER (base_buffer)->base_buffer;
+  else
+    b->base_buffer = XBUFFER (base_buffer);
+
+  /* Use the base buffer's text object.  */
+  b->text = b->base_buffer->text;
+
+  BUF_BEGV (b) = BUF_BEGV (b->base_buffer);
+  BUF_ZV (b) = BUF_ZV (b->base_buffer);
+  BUF_PT (b) = BUF_PT (b->base_buffer);
+
+  b->newline_cache = 0;
+  b->width_run_cache = 0;
+  b->width_table = Qnil;
+
+  /* Put this on the chain of all buffers including killed ones.  */
+  b->next = all_buffers;
+  all_buffers = b;
+
+  name = Fcopy_sequence (name);
+  INITIALIZE_INTERVAL (XSTRING (name), NULL_INTERVAL);
+  b->name = name;
+
+  reset_buffer (b);
+  reset_buffer_local_variables (b);
+
+  /* Put this in the alist of all live buffers.  */
+  XSETBUFFER (buf, b);
+  Vbuffer_alist = nconc2 (Vbuffer_alist, Fcons (Fcons (name, buf), Qnil));
+
+  b->mark = Fmake_marker ();
+  b->name = name;
+
+  /* Make sure the base buffer has markers for its narrowing.  */
+  if (NILP (b->base_buffer->pt_marker))
+    {
+      b->base_buffer->pt_marker = Fmake_marker ();
+      Fset_marker (b->base_buffer->pt_marker,
+                  make_number (BUF_PT (b->base_buffer)), base_buffer);
+    }
+  if (NILP (b->base_buffer->begv_marker))
+    {
+      b->base_buffer->begv_marker = Fmake_marker ();
+      Fset_marker (b->base_buffer->begv_marker,
+                  make_number (BUF_BEGV (b->base_buffer)), base_buffer);
+    }
+  if (NILP (b->base_buffer->zv_marker))
+    {
+      b->base_buffer->zv_marker = Fmake_marker ();
+      Fset_marker (b->base_buffer->zv_marker,
+                  make_number (BUF_ZV (b->base_buffer)), base_buffer);
+    }
+
+  /* Give the indirect buffer markers for its narrowing.  */
+  b->pt_marker = Fpoint_marker ();
+  b->begv_marker = Fpoint_min_marker ();
+  b->zv_marker = Fpoint_max_marker ();
+
+  return buf;
+}
+
 /* Reinitialize everything about a buffer except its name and contents
    and local variables.  */
 
@@ -310,9 +410,9 @@ reset_buffer (b)
      register struct buffer *b;
 {
   b->filename = Qnil;
+  b->file_truename = Qnil;
   b->directory = (current_buffer) ? current_buffer->directory : Qnil;
   b->modtime = 0;
-  b->save_modified = 1;
   XSETFASTINT (b->save_length, 0);
   b->last_window_start = 1;
   b->backed_up = Qnil;
@@ -324,9 +424,7 @@ reset_buffer (b)
   b->overlays_after = Qnil;
   XSETFASTINT (b->overlay_center, 1);
   b->mark_active = Qnil;
-
-  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  INITIALIZE_INTERVAL (b, NULL_INTERVAL);
+  b->point_before_scroll = Qnil;
 }
 
 /* Reset buffer B's local variables info.
@@ -352,6 +450,9 @@ reset_buffer_local_variables (b)
   b->upcase_table = Vascii_upcase_table;
   b->case_canon_table = Vascii_canon_table;
   b->case_eqv_table = Vascii_eqv_table;
+  b->buffer_file_type = Qnil;
+  b->invisibility_spec = Qt;
+
 #if 0
   b->sort_table = XSTRING (Vascii_sort_table);
   b->folding_sort_table = XSTRING (Vascii_folding_sort_table);
@@ -440,6 +541,30 @@ No argument or nil as argument means use the current buffer.")
   return XBUFFER (buffer)->filename;
 }
 
+DEFUN ("buffer-base-buffer", Fbuffer_base_buffer, Sbuffer_base_buffer,
+       0, 1, 0,
+  "Return the base buffer of indirect buffer BUFFER.\n\
+If BUFFER is not indirect, return nil.")
+  (buffer)
+     register Lisp_Object buffer;
+{
+  struct buffer *base;
+  Lisp_Object base_buffer;
+
+  if (NILP (buffer))
+    base = current_buffer->base_buffer;
+  else
+    {
+      CHECK_BUFFER (buffer, 0);
+      base = XBUFFER (buffer)->base_buffer;
+    }
+
+  if (! base)
+    return Qnil;
+  XSETBUFFER (base_buffer, base);
+  return base_buffer;
+}
+
 DEFUN ("buffer-local-variables", Fbuffer_local_variables,
   Sbuffer_local_variables, 0, 1, 0,
   "Return an alist of variables that are buffer-local in BUFFER.\n\
@@ -464,11 +589,6 @@ No argument or nil as argument means use current buffer as BUFFER.")
   result = Qnil;
 
   {
-    /* Reference each variable in the alist in our current buffer.
-       If inquiring about the current buffer, this gets the current values,
-       so store them into the alist so the alist is up to date.
-       If inquiring about some other buffer, this swaps out any values
-       for that buffer, making the alist up to date automatically.  */
     register Lisp_Object tail;
     for (tail = buf->local_var_alist; CONSP (tail); tail = XCONS (tail)->cdr)
       {
@@ -476,9 +596,14 @@ No argument or nil as argument means use current buffer as BUFFER.")
 
        elt = XCONS (tail)->car;
 
-       if (buf == current_buffer)
-         val = find_symbol_value (XCONS (elt)->car);
-       else
+       /* Reference each variable in the alist in buf.
+          If inquiring about the current buffer, this gets the current values,
+          so store them into the alist so the alist is up to date.
+          If inquiring about some other buffer, this swaps out any values
+          for that buffer, making the alist up to date automatically.  */
+       val = find_symbol_value (XCONS (elt)->car);
+       /* Use the current buffer value only if buf is the current buffer.  */
+       if (buf != current_buffer)
          val = XCONS (elt)->cdr;
 
        /* If symbol is unbound, put just the symbol in the list.  */
@@ -529,7 +654,7 @@ No argument or nil as argument means use current buffer as BUFFER.")
       buf = XBUFFER (buffer);
     }
 
-  return buf->save_modified < BUF_MODIFF (buf) ? Qt : Qnil;
+  return BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf) ? Qt : Qnil;
 }
 
 DEFUN ("set-buffer-modified-p", Fset_buffer_modified_p, Sset_buffer_modified_p,
@@ -549,7 +674,7 @@ A non-nil FLAG means mark the buffer modified.")
   fn = current_buffer->filename;
   if (!NILP (fn))
     {
-      already = current_buffer->save_modified < MODIFF;
+      already = SAVE_MODIFF < MODIFF;
       if (!already && !NILP (flag))
        lock_file (fn);
       else if (already && NILP (flag))
@@ -557,7 +682,7 @@ A non-nil FLAG means mark the buffer modified.")
     }
 #endif /* CLASH_DETECTION */
 
-  current_buffer->save_modified = NILP (flag) ? MODIFF : 0;
+  SAVE_MODIFF = NILP (flag) ? MODIFF : 0;
   update_mode_lines++;
   return flag;
 }
@@ -762,7 +887,7 @@ with `delete-process'.")
 
   /* Query if the buffer is still modified.  */
   if (INTERACTIVE && !NILP (b->filename)
-      && BUF_MODIFF (b) > b->save_modified)
+      && BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
     {
       GCPRO2 (buf, bufname);
       tem = do_yes_or_no_p (format1 ("Buffer %s modified; kill anyway? ",
@@ -807,6 +932,26 @@ with `delete-process'.")
   if (NILP (b->name))
     return Qnil;
 
+  /* When we kill a base buffer, kill all its indirect buffers.
+     We do it at this stage so nothing terrible happens if they
+     ask questions or their hooks get errors.  */
+  if (! b->base_buffer)
+    {
+      struct buffer *other;
+
+      GCPRO1 (buf);
+
+      for (other = all_buffers; other; other = other->next)
+       if (other->base_buffer == b)
+         {
+           Lisp_Object buf;
+           XSETBUFFER (buf, other);
+           Fkill_buffer (buf);
+         }
+
+      UNGCPRO;
+    }
+  
   /* Make this buffer not be current.
      In the process, notice if this is the sole visible buffer
      and give up if so.  */
@@ -843,24 +988,32 @@ with `delete-process'.")
        internal_delete_file (b->auto_save_file_name);
     }
 
-  /* Unchain all markers of this buffer
-     and leave them pointing nowhere.  */
-  for (tem = b->markers; !EQ (tem, Qnil); )
+  if (! b->base_buffer)
     {
-      m = XMARKER (tem);
-      m->buffer = 0;
-      tem = m->chain;
-      m->chain = Qnil;
-    }
-  b->markers = Qnil;
+      /* Unchain all markers of this buffer
+        and leave them pointing nowhere.  */
+      for (tem = BUF_MARKERS (b); !EQ (tem, Qnil); )
+       {
+         m = XMARKER (tem);
+         m->buffer = 0;
+         tem = m->chain;
+         m->chain = Qnil;
+       }
+      BUF_MARKERS (b) = Qnil;
+
+#ifdef USE_TEXT_PROPERTIES
+      BUF_INTERVALS (b) = NULL_INTERVAL;
+#endif
 
-  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-  INITIALIZE_INTERVAL (b, NULL_INTERVAL);
-  /* Perhaps we should explicitly free the interval tree here... */
+      /* Perhaps we should explicitly free the interval tree here... */
+    }
 
   b->name = Qnil;
+
   BLOCK_INPUT;
-  BUFFER_FREE (BUF_BEG_ADDR (b));
+  if (! b->base_buffer)
+    BUFFER_FREE (BUF_BEG_ADDR (b));
+
   if (b->newline_cache)
     {
       free_region_cache (b->newline_cache);
@@ -995,7 +1148,14 @@ window even if BUFFER is already visible in the selected window.")
   if (NILP (bufname))
     buf = Fother_buffer (Fcurrent_buffer (), Qnil);
   else
-    buf = Fget_buffer_create (bufname);
+    {
+      buf = Fget_buffer (bufname);
+      if (NILP (buf))
+       {
+         buf = Fget_buffer_create (bufname);
+         Fset_buffer_major_mode (buf);
+       }
+    }
   Fset_buffer (buf);
   record_buffer (buf);
   Fselect_window (Fdisplay_buffer (buf, other));
@@ -1029,6 +1189,49 @@ set_buffer_internal (b)
   current_buffer = b;
   last_known_column_point = -1;   /* invalidate indentation cache */
 
+  if (old_buf)
+    {
+      /* Put the undo list back in the base buffer, so that it appears
+        that an indirect buffer shares the undo list of its base.  */
+      if (old_buf->base_buffer)
+       old_buf->base_buffer->undo_list = old_buf->undo_list;
+
+      /* If the old current buffer has markers to record PT, BEGV and ZV
+        when it is not current, update them now.  */
+      if (! NILP (old_buf->pt_marker))
+       {
+         Lisp_Object obuf;
+         XSETBUFFER (obuf, old_buf);
+         Fset_marker (old_buf->pt_marker, BUF_PT (old_buf), obuf);
+       }
+      if (! NILP (old_buf->begv_marker))
+       {
+         Lisp_Object obuf;
+         XSETBUFFER (obuf, old_buf);
+         Fset_marker (old_buf->begv_marker, BUF_BEGV (old_buf), obuf);
+       }
+      if (! NILP (old_buf->zv_marker))
+       {
+         Lisp_Object obuf;
+         XSETBUFFER (obuf, old_buf);
+         Fset_marker (old_buf->zv_marker, BUF_ZV (old_buf), obuf);
+       }
+    }
+
+  /* Get the undo list from the base buffer, so that it appears
+     that an indirect buffer shares the undo list of its base.  */
+  if (b->base_buffer)
+    b->undo_list = b->base_buffer->undo_list;
+
+  /* If the new current buffer has markers to record PT, BEGV and ZV
+     when it is not current, fetch them now.  */
+  if (! NILP (b->pt_marker))
+    BUF_PT (b) = marker_position (b->pt_marker);
+  if (! NILP (b->begv_marker))
+    BUF_BEGV (b) = marker_position (b->begv_marker);
+  if (! NILP (b->zv_marker))
+    BUF_ZV (b) = marker_position (b->zv_marker);
+
   /* Look down buffer's list of local Lisp variables
      to find and update any that forward into C variables. */
 
@@ -1060,6 +1263,55 @@ set_buffer_internal (b)
       }
 }
 
+/* Switch to buffer B temporarily for redisplay purposes.
+   This avoids certain things thatdon't need to be done within redisplay.  */
+
+void
+set_buffer_temp (b)
+     struct buffer *b;
+{
+  register struct buffer *old_buf;
+
+  if (current_buffer == b)
+    return;
+
+  old_buf = current_buffer;
+  current_buffer = b;
+
+  if (old_buf)
+    {
+      /* If the old current buffer has markers to record PT, BEGV and ZV
+        when it is not current, update them now.  */
+      if (! NILP (old_buf->pt_marker))
+       {
+         Lisp_Object obuf;
+         XSETBUFFER (obuf, old_buf);
+         Fset_marker (old_buf->pt_marker, BUF_PT (old_buf), obuf);
+       }
+      if (! NILP (old_buf->begv_marker))
+       {
+         Lisp_Object obuf;
+         XSETBUFFER (obuf, old_buf);
+         Fset_marker (old_buf->begv_marker, BUF_BEGV (old_buf), obuf);
+       }
+      if (! NILP (old_buf->zv_marker))
+       {
+         Lisp_Object obuf;
+         XSETBUFFER (obuf, old_buf);
+         Fset_marker (old_buf->zv_marker, BUF_ZV (old_buf), obuf);
+       }
+    }
+
+  /* If the new current buffer has markers to record PT, BEGV and ZV
+     when it is not current, fetch them now.  */
+  if (! NILP (b->pt_marker))
+    BUF_PT (b) = marker_position (b->pt_marker);
+  if (! NILP (b->begv_marker))
+    BUF_BEGV (b) = marker_position (b->begv_marker);
+  if (! NILP (b->zv_marker))
+    BUF_ZV (b) = marker_position (b->zv_marker);
+}
+
 DEFUN ("set-buffer", Fset_buffer, Sset_buffer, 1, 1, 0,
   "Make the buffer BUFFER current for editing operations.\n\
 BUFFER may be a buffer or the name of an existing buffer.\n\
@@ -1166,135 +1418,6 @@ validate_region (b, e)
     args_out_of_range (*b, *e);
 }
 \f
-static Lisp_Object
-list_buffers_1 (files)
-     Lisp_Object files;
-{
-  register Lisp_Object tail, tem, buf;
-  Lisp_Object col1, col2, col3, minspace;
-  register struct buffer *old = current_buffer, *b;
-  Lisp_Object desired_point;
-  Lisp_Object other_file_symbol;
-
-  desired_point = Qnil;
-  other_file_symbol = intern ("list-buffers-directory");
-
-  XSETFASTINT (col1, 17);
-  XSETFASTINT (col2, 28);
-  XSETFASTINT (col3, 40);
-  XSETFASTINT (minspace, 1);
-
-  Fset_buffer (Vstandard_output);
-  Fbuffer_disable_undo (Vstandard_output);
-  current_buffer->read_only = Qnil;
-
-  write_string ("\
- MR Buffer           Size Mode          File\n\
- -- ------           ---- ----          ----\n", -1);
-
-  for (tail = Vbuffer_alist; !NILP (tail); tail = Fcdr (tail))
-    {
-      buf = Fcdr (Fcar (tail));
-      b = XBUFFER (buf);
-      /* Don't mention the minibuffers. */
-      if (XSTRING (b->name)->data[0] == ' ')
-       continue;
-      /* Optionally don't mention buffers that lack files. */
-      if (!NILP (files) && NILP (b->filename))
-       continue;
-      /* Identify the current buffer. */
-      if (b == old)
-       XSETFASTINT (desired_point, PT);
-      write_string (b == old ? "." : " ", -1);
-      /* Identify modified buffers */
-      write_string (BUF_MODIFF (b) > b->save_modified ? "*" : " ", -1);
-      /* The current buffer is special-cased to be marked read-only.
-        It is actually made read-only by the call to
-        Buffer-menu-mode, below. */
-      write_string ((b != current_buffer && NILP (b->read_only))
-                   ? "  " : "% ", -1);
-      Fprinc (b->name, Qnil);
-      tem = Findent_to (col1, make_number (2));
-      {
-       char sizebuf[9];
-       int i;
-       char *p;
-
-       sprintf (sizebuf, "%8d", BUF_Z (b) - BUF_BEG (b));
-       /* Here's how many extra columns the buffer name used.  */
-       i = XFASTINT (tem) - XFASTINT (col1);
-       /* Skip that many spaces in the size, if it has that many,
-          to keep the size values right-aligned if possible.  */
-       p = sizebuf;
-       while (i > 0)
-         {
-           if (*p == ' ')
-             p++;
-           i--;
-         }
-
-       write_string (p, -1);
-      }
-      Findent_to (col2, minspace);
-      Fprinc (b->mode_name, Qnil);
-      Findent_to (col3, minspace);
-
-      if (!NILP (b->filename))
-       Fprinc (b->filename, Qnil);
-      else
-       {
-         /* No visited file; check local value of list-buffers-directory.  */
-         Lisp_Object tem;
-         set_buffer_internal (b);
-         tem = Fboundp (other_file_symbol);
-         if (!NILP (tem))
-           {
-             tem = Fsymbol_value (other_file_symbol);
-             Fset_buffer (Vstandard_output);
-             if (STRINGP (tem))
-               Fprinc (tem, Qnil);
-           }
-         else
-           Fset_buffer (Vstandard_output);
-       }
-      write_string ("\n", -1);
-    }
-
-  tail = intern ("Buffer-menu-mode");
-  if ((tem = Ffboundp (tail), !NILP (tem)))
-    call0 (tail);
-  set_buffer_internal (old);
-  return desired_point;
-}
-
-DEFUN ("list-buffers", Flist_buffers, Slist_buffers, 0, 1, "P",
-  "Display a list of names of existing buffers.\n\
-The list is displayed in a buffer named `*Buffer List*'.\n\
-Note that buffers with names starting with spaces are omitted.\n\
-Non-null optional arg FILES-ONLY means mention only file buffers.\n\
-\n\
-The M column contains a * for buffers that are modified.\n\
-The R column contains a % for buffers that are read-only.")
-  (files)
-     Lisp_Object files;
-{
-  Lisp_Object desired_point;
-
-  desired_point
-    = internal_with_output_to_temp_buffer ("*Buffer List*",
-                                          list_buffers_1, files);
-
-  if (NUMBERP (desired_point))
-    {
-      int count = specpdl_ptr - specpdl;
-      record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
-      Fset_buffer (build_string ("*Buffer List*"));
-      SET_PT (XINT (desired_point));
-      return unbind_to (count, Qnil);
-    }
-  return Qnil;
-}
-
 DEFUN ("kill-all-local-variables", Fkill_all_local_variables, Skill_all_local_variables,
   0, 0, 0,
   "Switch to Fundamental mode by killing current buffer's local variables.\n\
@@ -2540,6 +2663,13 @@ init_buffer_once ()
   reset_buffer_local_variables (&buffer_defaults);
   reset_buffer (&buffer_local_symbols);
   reset_buffer_local_variables (&buffer_local_symbols);
+  /* 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);
 
@@ -2574,6 +2704,7 @@ init_buffer_once ()
   XSETFASTINT (buffer_defaults.fill_column, 70);
   XSETFASTINT (buffer_defaults.left_margin, 0);
   buffer_defaults.cache_long_line_scans = Qnil;
+  buffer_defaults.file_truename = Qnil;
 
   /* Assign the local-flags to the slots that have default values.
      The local flag is a bit that is used in the buffer
@@ -2595,6 +2726,9 @@ init_buffer_once ()
   XSETINT (buffer_local_flags.mode_name, -1);
   XSETINT (buffer_local_flags.undo_list, -1);
   XSETINT (buffer_local_flags.mark_active, -1);
+  XSETINT (buffer_local_flags.point_before_scroll, -1);
+  XSETINT (buffer_local_flags.file_truename, -1);
+  XSETINT (buffer_local_flags.invisibility_spec, -1);
 
   XSETFASTINT (buffer_local_flags.mode_line_format, 1);
   XSETFASTINT (buffer_local_flags.abbrev_mode, 2);
@@ -2866,7 +3000,7 @@ and this buffer is not full-frame width.");
     "Non-nil if the visited file is a binary file.\n\
 This variable is meaningful on MS-DOG and Windows NT.\n\
 On those systems, it is automatically local in every buffer.\n\
-On other systems, this variable is normally always nil.")
+On other systems, this variable is normally always nil.");
 #endif
 
   DEFVAR_PER_BUFFER ("default-directory", &current_buffer->directory,
@@ -2887,6 +3021,12 @@ It may not be a list of functions.");
     "Name of file visited in current buffer, or nil if not visiting a file.\n\
 Each buffer has its own value of this variable.");
 
+  DEFVAR_PER_BUFFER ("buffer-file-truename", &current_buffer->file_truename,
+                    make_number (Lisp_String),
+    "Truename of file visited in current buffer, or nil if not visiting a file.\n\
+The truename of a file is calculated by `file-truename'.\n\
+Each buffer has its own value of this variable.");
+
   DEFVAR_PER_BUFFER ("buffer-auto-save-file-name",
                     &current_buffer->auto_save_file_name,
                     make_number (Lisp_String),
@@ -2928,7 +3068,9 @@ Automatically becomes buffer-local when set in any fashion.");
 
   DEFVAR_PER_BUFFER ("overwrite-mode", &current_buffer->overwrite_mode, Qnil,
     "Non-nil if self-insertion should replace existing text.\n\
-If non-nil and not `overwrite-mode-binary', self-insertion still\n\
+The value should be one of `overwrite-mode-textual',\n\
+`overwrite-mode-binary', or nil.\n\
+If it is `overwrite-mode-textual', self-insertion still\n\
 inserts at the end of a line, and inserts when point is before a tab,\n\
 until the tab is filled in.\n\
 If `overwrite-mode-binary', self-insertion replaces newlines and tabs too.\n\
@@ -3049,15 +3191,15 @@ An entry (TEXT . POSITION) represents the deletion of the string TEXT\n\
 from (abs POSITION).  If POSITION is positive, point was at the front\n\
 of the text being deleted; if negative, point was at the end.\n\
 \n\
-An entry (t HIGHWORD LOWWORD) indicates that the buffer had been\n\
-previously unmodified.  HIGHWORD and LOWWORD are the high and low\n\
-16-bit words of the buffer's modification count at the time.  If the\n\
-modification count of the most recent save is different, this entry is\n\
+An entry (t HIGH . LOW) indicates that the buffer previously had\n\
+\"unmodified\" status.  HIGH and LOW are the high and low 16-bit portions\n\
+of the visited file's modification time, as of that time.  If the\n\
+modification time of the most recent save is different, this entry is\n\
 obsolete.\n\
 \n\
-An entry (nil PROP VAL BEG . END) indicates that a text property\n\
-was modified between BEG and END.  PROP is the property name,\n\
-and VAL is the old value.\n\
+An entry (nil PROPERTY VALUE BEG . END) indicates that a text property\n\
+was modified between BEG and END.  PROPERTY is the property name,\n\
+and VALUE is the old value.\n\
 \n\
 An entry of the form POSITION indicates that point was at the buffer\n\
 location given by the integer.  Undoing an entry of this form places\n\
@@ -3104,6 +3246,20 @@ maintained internally by the Emacs primitives.  Enabling or disabling\n\
 the cache should not affect the behavior of any of the motion\n\
 functions; it should only affect their performance.");
 
+  DEFVAR_PER_BUFFER ("point-before-scroll", &current_buffer->point_before_scroll, Qnil,
+  "Value of point before the last series of scroll operations, or nil.");
+
+  DEFVAR_PER_BUFFER ("buffer-invisibility-spec",
+                    &current_buffer->invisibility_spec, Qnil,
+  "Invisibility spec of this buffer.\n\
+The default is t, which means that text is invisible\n\
+if it has a non-nil `invisible' property.\n\
+If the value is a list, a text character is invisible if its `invisible'\n\
+property is an element in that list.\n\
+If an element is a cons cell of the for (PROP . ELLIPSIS),\n\
+then characters with property value PROP is invisible,\n\
+and they have an ellipsis as well if ELLIPSIS is non-nil.");
+
   DEFVAR_LISP ("transient-mark-mode", &Vtransient_mark_mode,
     "*Non-nil means deactivate the mark when the buffer contents change.");
   Vtransient_mark_mode = Qnil;
@@ -3124,10 +3280,12 @@ is a member of the list.");
   defsubr (&Sget_buffer);
   defsubr (&Sget_file_buffer);
   defsubr (&Sget_buffer_create);
+  defsubr (&Smake_indirect_buffer);
   defsubr (&Sgenerate_new_buffer_name);
   defsubr (&Sbuffer_name);
 /*defsubr (&Sbuffer_number);*/
   defsubr (&Sbuffer_file_name);
+  defsubr (&Sbuffer_base_buffer);
   defsubr (&Sbuffer_local_variables);
   defsubr (&Sbuffer_modified_p);
   defsubr (&Sset_buffer_modified_p);
@@ -3145,7 +3303,6 @@ is a member of the list.");
   defsubr (&Sset_buffer);
   defsubr (&Sbarf_if_buffer_read_only);
   defsubr (&Sbury_buffer);
-  defsubr (&Slist_buffers);
   defsubr (&Skill_all_local_variables);
 
   defsubr (&Soverlayp);
@@ -3169,7 +3326,6 @@ keys_of_buffer ()
 {
   initial_define_key (control_x_map, 'b', "switch-to-buffer");
   initial_define_key (control_x_map, 'k', "kill-buffer");
-  initial_define_key (control_x_map, Ctl ('B'), "list-buffers");
 
   /* This must not be in syms_of_buffer, because Qdisabled is not
      initialized when that function gets called.  */