(Ferase_buffer): Added interactive spec.
[bpt/emacs.git] / src / buffer.c
index 68575d8..6617ee9 100644 (file)
@@ -1,11 +1,12 @@
 /* Buffer manipulation primitives for GNU Emacs.
-   Copyright (C) 1985, 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1989, 1992, 1993
+       Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -18,6 +19,8 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/param.h>
 
 #ifndef MAXPATHLEN
@@ -25,11 +28,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define MAXPATHLEN 1024
 #endif /* not MAXPATHLEN */
 
-#ifdef NULL
-#undef NULL
-#endif
 #include "config.h"
 #include "lisp.h"
+#include "intervals.h"
 #include "window.h"
 #include "commands.h"
 #include "buffer.h"
@@ -88,6 +89,14 @@ struct buffer buffer_local_symbols;
 /* A Lisp_Object pointer to the above, used for staticpro */
 static Lisp_Object Vbuffer_local_symbols;
 
+/* This structure holds the required types for the values in the
+   buffer-local slots.  If a slot contains Qnil, then the
+   corresponding buffer slot may contain a value of any type.  If a
+   slot contains an integer, then prospective values' tags must be
+   equal to that integer.  When a tag does not match, the function
+   buffer_slot_type_mismatch will signal an error.  */
+struct buffer buffer_local_types;
+
 /* Nonzero means don't allow modification of protected fields.  */
 
 int check_protected_fields;
@@ -104,8 +113,9 @@ Lisp_Object Vbuffer_alist;
 Lisp_Object Vbefore_change_function;
 Lisp_Object Vafter_change_function;
 
-/* Function to call before changing an unmodified buffer.  */
-Lisp_Object Vfirst_change_function;
+/* List of functions to call before changing an unmodified buffer.  */
+Lisp_Object Vfirst_change_hook;
+Lisp_Object Qfirst_change_hook;
 
 Lisp_Object Qfundamental_mode, Qmode_class, Qpermanent_local;
 
@@ -163,7 +173,7 @@ If there is no such live buffer, return nil.")
       if (XTYPE (buf) != Lisp_Buffer) continue;
       if (XTYPE (XBUFFER (buf)->filename) != Lisp_String) continue;
       tem = Fstring_equal (XBUFFER (buf)->filename, filename);
-      if (!NULL (tem))
+      if (!NILP (tem))
        return buf;
     }
   return Qnil;
@@ -175,6 +185,7 @@ int buffer_count;
 DEFUN ("get-buffer-create", Fget_buffer_create, Sget_buffer_create, 1, 1, 0,
   "Return the buffer named NAME, or create such a buffer and return it.\n\
 A new buffer is created if there is no live buffer named NAME.\n\
+If NAME starts with a space, the new buffer does not keep undo information.\n\
 If NAME is a buffer instead of a string, then it is the value returned.\n\
 The value is never nil.")  
   (name)
@@ -185,7 +196,7 @@ The value is never nil.")
   register struct buffer *b;
 
   buf = Fget_buffer (name);
-  if (!NULL (buf))
+  if (!NILP (buf))
     return buf;
 
   b = (struct buffer *) malloc (sizeof (struct buffer));
@@ -227,14 +238,14 @@ The value is never nil.")
   b->name = name;
 
   function = buffer_defaults.major_mode;
-  if (NULL (function))
+  if (NILP (function))
     {
       tem = Fget (current_buffer->major_mode, Qmode_class);
       if (EQ (tem, Qnil))
        function = current_buffer->major_mode;
     }
 
-  if (NULL (function) || EQ (function, Qfundamental_mode))
+  if (NILP (function) || EQ (function, Qfundamental_mode))
     return buf;
 
   /* To select a nonfundamental mode,
@@ -258,13 +269,17 @@ reset_buffer (b)
   b->directory = (current_buffer) ? current_buffer->directory : Qnil;
   b->modtime = 0;
   b->save_modified = 1;
-  b->save_length = 0;
+  XFASTINT (b->save_length) = 0;
   b->last_window_start = 1;
   b->backed_up = Qnil;
   b->auto_save_modified = 0;
   b->auto_save_file_name = Qnil;
   b->read_only = Qnil;
   b->fieldlist = Qnil;
+
+  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
+  INITIALIZE_INTERVAL (b, NULL_INTERVAL);
+
   reset_buffer_local_variables(b);
 }
 
@@ -327,7 +342,7 @@ until an unused name is found, and then return that name.")
   CHECK_STRING (name, 0);
 
   tem = Fget_buffer (name);
-  if (NULL (tem))
+  if (NILP (tem))
     return name;
 
   count = 1;
@@ -336,7 +351,7 @@ until an unused name is found, and then return that name.")
       sprintf (number, "<%d>", ++count);
       gentemp = concat2 (name, build_string (number));
       tem = Fget_buffer (gentemp);
-      if (NULL (tem))
+      if (NILP (tem))
        return gentemp;
     }
 }
@@ -348,7 +363,7 @@ With no argument or nil as argument, return the name of the current buffer.")
   (buffer)
      register Lisp_Object buffer;
 {
-  if (NULL (buffer))
+  if (NILP (buffer))
     return current_buffer->name;
   CHECK_BUFFER (buffer, 0);
   return XBUFFER (buffer)->name;
@@ -360,7 +375,7 @@ No argument or nil as argument means use the current buffer.")
   (buffer)
      register Lisp_Object buffer;
 {
-  if (NULL (buffer))
+  if (NILP (buffer))
     return current_buffer->filename;
   CHECK_BUFFER (buffer, 0);
   return XBUFFER (buffer)->filename;
@@ -378,7 +393,7 @@ No argument or nil as argument means use current buffer as BUFFER.")
   register struct buffer *buf;
   register Lisp_Object val;
 
-  if (NULL (buffer))
+  if (NILP (buffer))
     buf = current_buffer;
   else
     {
@@ -433,7 +448,7 @@ No argument or nil as argument means use current buffer as BUFFER.")
      register Lisp_Object buffer;
 {
   register struct buffer *buf;
-  if (NULL (buffer))
+  if (NILP (buffer))
     buf = current_buffer;
   else
     {
@@ -459,17 +474,17 @@ A non-nil FLAG means mark the buffer modified.")
      If buffer becoming unmodified, unlock the file.  */
 
   fn = current_buffer->filename;
-  if (!NULL (fn))
+  if (!NILP (fn))
     {
       already = current_buffer->save_modified < MODIFF;
-      if (!already && !NULL (flag))
+      if (!already && !NILP (flag))
        lock_file (fn);
-      else if (already && NULL (flag))
+      else if (already && NILP (flag))
        unlock_file (fn);
     }
 #endif /* CLASH_DETECTION */
 
-  current_buffer->save_modified = NULL (flag) ? MODIFF : 0;
+  current_buffer->save_modified = NILP (flag) ? MODIFF : 0;
   update_mode_lines++;
   return flag;
 }
@@ -484,7 +499,7 @@ No argument or nil as argument means use current buffer as BUFFER.")
      register Lisp_Object buffer;
 {
   register struct buffer *buf;
-  if (NULL (buffer))
+  if (NILP (buffer))
     buf = current_buffer;
   else
     {
@@ -496,16 +511,17 @@ No argument or nil as argument means use current buffer as BUFFER.")
 }
 \f
 DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
-       "sRename buffer (to new name): ",
+       "sRename buffer (to new name): \nP",
   "Change current buffer's name to NEWNAME (a string).\n\
-If second arg DISTINGUISH is nil or omitted, it is an error if a\n\
+If second arg UNIQUE is nil or omitted, it is an error if a\n\
 buffer named NEWNAME already exists.\n\
-If DISTINGUISH is non-nil, come up with a new name using\n\
+If UNIQUE is non-nil, come up with a new name using\n\
 `generate-new-buffer-name'.\n\
-Return the name we actually gave the buffer.\n\
+Interactively, you can set UNIQUE with a prefix argument.\n\
+We return the name we actually gave the buffer.\n\
 This does not change the name of the visited file (if any).")
-  (name, distinguish)
-     register Lisp_Object name, distinguish;
+  (name, unique)
+     register Lisp_Object name, unique;
 {
   register Lisp_Object tem, buf;
 
@@ -513,47 +529,56 @@ This does not change the name of the visited file (if any).")
   tem = Fget_buffer (name);
   if (XBUFFER (tem) == current_buffer)
     return current_buffer->name;
-  if (!NULL (tem))
+  if (!NILP (tem))
     {
-      if (!NULL (distinguish))
+      if (!NILP (unique))
        name = Fgenerate_new_buffer_name (name);
       else
        error ("Buffer name \"%s\" is in use", XSTRING (name)->data);
     }
 
   current_buffer->name = name;
+
+  /* Catch redisplay's attention.  Unless we do this, the mode lines for
+     any windows displaying current_buffer will stay unchanged.  */
+  update_mode_lines++;
+
   XSET (buf, Lisp_Buffer, current_buffer);
   Fsetcar (Frassq (buf, Vbuffer_alist), name);
-  if (NULL (current_buffer->filename) && !NULL (current_buffer->auto_save_file_name))
+  if (NILP (current_buffer->filename) && !NILP (current_buffer->auto_save_file_name))
     call0 (intern ("rename-auto-save-file"));
   return name;
 }
 
-DEFUN ("other-buffer", Fother_buffer, Sother_buffer, 0, 1, 0,
+DEFUN ("other-buffer", Fother_buffer, Sother_buffer, 0, 2, 0,
   "Return most recently selected buffer other than BUFFER.\n\
-Buffers not visible in windows are preferred to visible buffers.\n\
+Buffers not visible in windows are preferred to visible buffers,\n\
+unless optional second argument VISIBLE-OK is non-nil.\n\
 If no other buffer exists, the buffer `*scratch*' is returned.\n\
 If BUFFER is omitted or nil, some interesting buffer is returned.")
-  (buffer)
-     register Lisp_Object buffer;
+  (buffer, visible_ok)
+     register Lisp_Object buffer, visible_ok;
 {
   register Lisp_Object tail, buf, notsogood, tem;
   notsogood = Qnil;
 
-  for (tail = Vbuffer_alist; !NULL (tail); tail = Fcdr (tail))
+  for (tail = Vbuffer_alist; !NILP (tail); tail = Fcdr (tail))
     {
       buf = Fcdr (Fcar (tail));
       if (EQ (buf, buffer))
        continue;
       if (XSTRING (XBUFFER (buf)->name)->data[0] == ' ')
        continue;
-      tem = Fget_buffer_window (buf, Qnil);
-      if (NULL (tem))
+      if (NILP (visible_ok))
+       tem = Fget_buffer_window (buf, Qnil);
+      else
+       tem = Qnil;
+      if (NILP (tem))
        return buf;
-      if (NULL (notsogood))
+      if (NILP (notsogood))
        notsogood = buf;
     }
-  if (!NULL (notsogood))
+  if (!NILP (notsogood))
     return notsogood;
   return Fget_buffer_create (build_string ("*scratch*"));
 }
@@ -561,11 +586,22 @@ If BUFFER is omitted or nil, some interesting buffer is returned.")
 DEFUN ("buffer-disable-undo", Fbuffer_disable_undo, Sbuffer_disable_undo, 1,1,
 0,
   "Make BUFFER stop keeping undo information.")
-  (buf)
-     register Lisp_Object buf;
+  (buffer)
+     register Lisp_Object buffer;
 {
-  CHECK_BUFFER (buf, 0);
-  XBUFFER (buf)->undo_list = Qt;
+  Lisp_Object real_buffer;
+
+  if (NILP (buffer))
+    XSET (real_buffer, Lisp_Buffer, current_buffer);
+  else
+    {
+      real_buffer = Fget_buffer (buffer);
+      if (NILP (real_buffer))
+       nsberror (buffer);
+    }
+
+  XBUFFER (real_buffer)->undo_list = Qt;
+
   return Qnil;
 }
 
@@ -573,23 +609,22 @@ DEFUN ("buffer-enable-undo", Fbuffer_enable_undo, Sbuffer_enable_undo,
        0, 1, "",
   "Start keeping undo information for buffer BUFFER.\n\
 No argument or nil as argument means do this for the current buffer.")
-  (buf)
-     register Lisp_Object buf;
+  (buffer)
+     register Lisp_Object buffer;
 {
-  register struct buffer *b;
-  register Lisp_Object buf1;
+  Lisp_Object real_buffer;
 
-  if (NULL (buf))
-    b = current_buffer;
+  if (NILP (buffer))
+    XSET (real_buffer, Lisp_Buffer, current_buffer);
   else
     {
-      buf1 = Fget_buffer (buf);
-      if (NULL (buf1)) nsberror (buf);
-      b = XBUFFER (buf1);
+      real_buffer = Fget_buffer (buffer);
+      if (NILP (real_buffer))
+       nsberror (buffer);
     }
 
-  if (EQ (b->undo_list, Qt))
-    b->undo_list = Qnil;
+  if (EQ (XBUFFER (real_buffer)->undo_list, Qt))
+    XBUFFER (real_buffer)->undo_list = Qnil;
 
   return Qnil;
 }
@@ -620,24 +655,24 @@ with `delete-process'.")
   register struct Lisp_Marker *m;
   struct gcpro gcpro1, gcpro2;
 
-  if (NULL (bufname))
+  if (NILP (bufname))
     buf = Fcurrent_buffer ();
   else
     buf = Fget_buffer (bufname);
-  if (NULL (buf))
+  if (NILP (buf))
     nsberror (bufname);
 
   b = XBUFFER (buf);
 
   /* Query if the buffer is still modified.  */
-  if (INTERACTIVE && !NULL (b->filename)
+  if (INTERACTIVE && !NILP (b->filename)
       && BUF_MODIFF (b) > b->save_modified)
     {
       GCPRO2 (buf, bufname);
       tem = do_yes_or_no_p (format1 ("Buffer %s modified; kill anyway? ",
                                     XSTRING (b->name)->data));
       UNGCPRO;
-      if (NULL (tem))
+      if (NILP (tem))
        return Qnil;
     }
 
@@ -660,7 +695,7 @@ with `delete-process'.")
   if (EQ (buf, XWINDOW (minibuf_window)->buffer))
     return Qnil;
 
-  if (NULL (b->name))
+  if (NILP (b->name))
     return Qnil;
 
   /* Make this buffer not be current.
@@ -668,7 +703,7 @@ with `delete-process'.")
      and give up if so.  */
   if (b == current_buffer)
     {
-      tem = Fother_buffer (buf);
+      tem = Fother_buffer (buf, Qnil);
       Fset_buffer (tem);
       if (b == current_buffer)
        return Qnil;
@@ -681,9 +716,7 @@ with `delete-process'.")
   unlock_buffer (b);
 #endif /* CLASH_DETECTION */
 
-#ifdef subprocesses
   kill_buffer_processes (buf);
-#endif /* subprocesses */
 
   tem = Vinhibit_quit;
   Vinhibit_quit = Qt;
@@ -696,7 +729,7 @@ with `delete-process'.")
     {
       Lisp_Object tem;
       tem = Fsymbol_value (intern ("delete-auto-save-files"));
-      if (! NULL (tem))
+      if (! NILP (tem))
        unlink (XSTRING (b->auto_save_file_name)->data);
     }
 
@@ -711,6 +744,10 @@ with `delete-process'.")
     }
   b->markers = Qnil;
 
+  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
+  INITIALIZE_INTERVAL (b, NULL_INTERVAL);
+  /* Perhaps we should explicitly free the interval tree here... */
+
   b->name = Qnil;
   BUFFER_FREE (BUF_BEG_ADDR (b));
   b->undo_list = Qnil;
@@ -718,10 +755,10 @@ with `delete-process'.")
   return Qt;
 }
 \f
-/* Put the element for buffer BUF at the front of buffer-alist.
-   This is done when a buffer is selected "visibly".
-   It keeps buffer-alist in the order of recency of selection
-   so that other_buffer will return something nice.  */
+/* Move the assoc for buffer BUF to the front of buffer-alist.  Since
+   we do this each time BUF is selected visibly, the more recently
+   selected buffers are always closer to the front of the list.  This
+   means that other_buffer is more likely to choose a relevant buffer.  */
 
 record_buffer (buf)
      Lisp_Object buf;
@@ -736,10 +773,10 @@ record_buffer (buf)
       prev = link;
     }
 
-  /* Effectively do Vbuffer_alist = Fdelq (link, Vbuffer_alist)
-     but cannot use Fdelq here it that allows quitting.  */
+  /* Effectively do Vbuffer_alist = Fdelq (link, Vbuffer_alist);
+     we cannot use Fdelq itself here because it allows quitting.  */
 
-  if (NULL (prev))
+  if (NILP (prev))
     Vbuffer_alist = XCONS (Vbuffer_alist)->cdr;
   else
     XCONS (prev)->cdr = XCONS (XCONS (prev)->cdr)->cdr;
@@ -766,19 +803,20 @@ the window-buffer correspondences.")
   if (EQ (minibuf_window, selected_window))
     error ("Cannot switch buffers in minibuffer window");
   tem = Fwindow_dedicated_p (selected_window);
-  if (!NULL (tem))
+  if (!NILP (tem))
     error ("Cannot switch buffers in a dedicated window");
 
-  if (NULL (bufname))
-    buf = Fother_buffer (Fcurrent_buffer ());
+  if (NILP (bufname))
+    buf = Fother_buffer (Fcurrent_buffer (), Qnil);
   else
     buf = Fget_buffer_create (bufname);
   Fset_buffer (buf);
-  if (NULL (norecord))
+  if (NILP (norecord))
     record_buffer (buf);
 
   Fset_window_buffer (EQ (selected_window, minibuf_window)
-                     ? Fnext_window (minibuf_window, Qnil) : selected_window,
+                     ? Fnext_window (minibuf_window, Qnil, Qnil)
+                     : selected_window,
                      buf);
 
   return Qnil;
@@ -794,8 +832,8 @@ window even if BUFFER is already visible in the selected window.")
      Lisp_Object bufname, other;
 {
   register Lisp_Object buf;
-  if (NULL (bufname))
-    buf = Fother_buffer (Fcurrent_buffer ());
+  if (NILP (bufname))
+    buf = Fother_buffer (Fcurrent_buffer (), Qnil);
   else
     buf = Fget_buffer_create (bufname);
   Fset_buffer (buf);
@@ -834,7 +872,7 @@ set_buffer_internal (b)
   /* Look down buffer's list of local Lisp variables
      to find and update any that forward into C variables. */
 
-  for (tail = b->local_var_alist; !NULL (tail); tail = XCONS (tail)->cdr)
+  for (tail = b->local_var_alist; !NILP (tail); tail = XCONS (tail)->cdr)
     {
       valcontents = XSYMBOL (XCONS (XCONS (tail)->car)->car)->value;
       if ((XTYPE (valcontents) == Lisp_Buffer_Local_Value
@@ -850,7 +888,7 @@ set_buffer_internal (b)
   /* Do the same with any others that were local to the previous buffer */
 
   if (old_buf)
-    for (tail = old_buf->local_var_alist; !NULL (tail); tail = XCONS (tail)->cdr)
+    for (tail = old_buf->local_var_alist; !NILP (tail); tail = XCONS (tail)->cdr)
       {
        valcontents = XSYMBOL (XCONS (XCONS (tail)->car)->car)->value;
        if ((XTYPE (valcontents) == Lisp_Buffer_Local_Value
@@ -876,9 +914,9 @@ Use `switch-to-buffer' or `pop-to-buffer' to switch buffers permanently.")
 {
   register Lisp_Object buffer;
   buffer = Fget_buffer (bufname);
-  if (NULL (buffer))
+  if (NILP (buffer))
     nsberror (bufname);
-  if (NULL (XBUFFER (buffer)->name))
+  if (NILP (XBUFFER (buffer)->name))
     error ("Selecting deleted buffer");
   set_buffer_internal (XBUFFER (buffer));
   return buffer;
@@ -889,7 +927,7 @@ DEFUN ("barf-if-buffer-read-only", Fbarf_if_buffer_read_only,
   "Signal a `buffer-read-only' error if the current buffer is read-only.")
   ()
 {
-  while (!NULL (current_buffer->read_only))
+  while (!NILP (current_buffer->read_only))
     Fsignal (Qbuffer_read_only, (Fcons (Fcurrent_buffer (), Qnil)));
   return Qnil;
 }
@@ -897,38 +935,48 @@ DEFUN ("barf-if-buffer-read-only", Fbarf_if_buffer_read_only,
 DEFUN ("bury-buffer", Fbury_buffer, Sbury_buffer, 0, 1, "",
   "Put BUFFER at the end of the list of all buffers.\n\
 There it is the least likely candidate for `other-buffer' to return;\n\
-thus, the least likely buffer for \\[switch-to-buffer] to select by default.")
+thus, the least likely buffer for \\[switch-to-buffer] to select by default.\n\
+If BUFFER is nil or omitted, bury the current buffer.\n\
+Also, if BUFFER is nil or omitted, remove the current buffer from the\n\
+selected window if it is displayed there.")
   (buf)
      register Lisp_Object buf;
 {
-  register Lisp_Object aelt, link;
-
-  if (NULL (buf))
+  /* Figure out what buffer we're going to bury.  */
+  if (NILP (buf))
     {
       XSET (buf, Lisp_Buffer, current_buffer);
-      Fswitch_to_buffer (Fother_buffer (buf), Qnil);
+
+      /* If we're burying the current buffer, unshow it.  */
+      Fswitch_to_buffer (Fother_buffer (buf, Qnil), Qnil);
     }
   else
     {
       Lisp_Object buf1;
       
       buf1 = Fget_buffer (buf);
-      if (NULL (buf1))
+      if (NILP (buf1))
        nsberror (buf);
       buf = buf1;
-    }    
+    }
+
+  /* Move buf to the end of the buffer list.  */
+  {
+    register Lisp_Object aelt, link;
+
+    aelt = Frassq (buf, Vbuffer_alist);
+    link = Fmemq (aelt, Vbuffer_alist);
+    Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
+    XCONS (link)->cdr = Qnil;
+    Vbuffer_alist = nconc2 (Vbuffer_alist, link);
+  }
 
-  aelt = Frassq (buf, Vbuffer_alist);
-  link = Fmemq (aelt, Vbuffer_alist);
-  Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
-  XCONS (link)->cdr = Qnil;
-  Vbuffer_alist = nconc2 (Vbuffer_alist, link);
   return Qnil;
 }
 \f
-DEFUN ("erase-buffer", Ferase_buffer, Serase_buffer, 0, 0, 0,
+DEFUN ("erase-buffer", Ferase_buffer, Serase_buffer, 0, 0, "*",
   "Delete the entire contents of the current buffer.\n\
-Any clipping restriction in effect (see `narrow-to-buffer') is removed,\n\
+Any clipping restriction in effect (see `narrow-to-region') is removed,\n\
 so the buffer is truly empty after this.")
   ()
 {
@@ -983,7 +1031,7 @@ list_buffers_1 (files)
 
   tail = intern ("Buffer-menu-mode");
   if (!EQ (tail, current_buffer->major_mode)
-      && (tem = Ffboundp (tail), !NULL (tem)))
+      && (tem = Ffboundp (tail), !NILP (tem)))
     call0 (tail);
   Fbuffer_disable_undo (Vstandard_output);
   current_buffer->read_only = Qnil;
@@ -992,7 +1040,7 @@ list_buffers_1 (files)
  MR Buffer         Size  Mode           File\n\
  -- ------         ----  ----           ----\n", -1);
 
-  for (tail = Vbuffer_alist; !NULL (tail); tail = Fcdr (tail))
+  for (tail = Vbuffer_alist; !NILP (tail); tail = Fcdr (tail))
     {
       buf = Fcdr (Fcar (tail));
       b = XBUFFER (buf);
@@ -1000,7 +1048,7 @@ list_buffers_1 (files)
       if (XSTRING (b->name)->data[0] == ' ')
        continue;
       /* Optionally don't mention buffers that lack files. */
-      if (!NULL (files) && NULL (b->filename))
+      if (!NILP (files) && NILP (b->filename))
        continue;
       /* Identify the current buffer. */
       if (b == old)
@@ -1008,7 +1056,7 @@ list_buffers_1 (files)
       write_string (b == old ? "." : " ", -1);
       /* Identify modified buffers */
       write_string (BUF_MODIFF (b) > b->save_modified ? "*" : " ", -1);
-      write_string (NULL (b->read_only) ? "  " : "% ", -1);
+      write_string (NILP (b->read_only) ? "  " : "% ", -1);
       Fprinc (b->name, Qnil);
       Findent_to (col1, make_number (2));
       XFASTINT (tem) = BUF_Z (b) - BUF_BEG (b);
@@ -1017,7 +1065,7 @@ list_buffers_1 (files)
       Fprinc (b->mode_name, Qnil);
       Findent_to (col3, minspace);
 
-      if (!NULL (b->filename))
+      if (!NILP (b->filename))
        Fprinc (b->filename, Qnil);
       else
        {
@@ -1025,7 +1073,7 @@ list_buffers_1 (files)
          Lisp_Object tem;
          set_buffer_internal (b);
          tem = Fboundp (other_file_symbol);
-         if (!NULL (tem))
+         if (!NILP (tem))
            {
              tem = Fsymbol_value (other_file_symbol);
              Fset_buffer (Vstandard_output);
@@ -1085,7 +1133,7 @@ a non-nil `permanent-local' property are not eliminated by this function.")
   /* Make sure no local variables remain set up with this buffer
      for their current values.  */
 
-  for (alist = oalist; !NULL (alist); alist = XCONS (alist)->cdr)
+  for (alist = oalist; !NILP (alist); alist = XCONS (alist)->cdr)
     {
       sym = XCONS (XCONS (alist)->car)->car;
 
@@ -1115,11 +1163,11 @@ a non-nil `permanent-local' property are not eliminated by this function.")
   /* Any which are supposed to be permanent,
      make local again, with the same values they had.  */
      
-  for (alist = oalist; !NULL (alist); alist = XCONS (alist)->cdr)
+  for (alist = oalist; !NILP (alist); alist = XCONS (alist)->cdr)
     {
       sym = XCONS (XCONS (alist)->car)->car;
       tem = Fget (sym, Qpermanent_local);
-      if (! NULL (tem))
+      if (! NILP (tem))
        {
          Fmake_local_variable (sym);
          Fset (sym, XCONS (XCONS (alist)->car)->cdr);
@@ -1146,7 +1194,7 @@ if any protected fields overlap this portion.")
   Lisp_Object fieldlist;
   Lisp_Object collector;
 
-  if (NULL (buffer))
+  if (NILP (buffer))
     fieldlist = current_buffer->fieldlist;
   else
     {
@@ -1174,9 +1222,9 @@ if any protected fields overlap this portion.")
       if ((start_loc < field_start && end_loc > field_start)
          || (start_loc >= field_start && start_loc < field_end))
        {
-         if (!NULL (error_check))
+         if (!NILP (error_check))
            {
-             if (!NULL (FIELD_PROTECTED_FLAG (field)))
+             if (!NILP (FIELD_PROTECTED_FLAG (field)))
                {
                  struct gcpro gcpro1;
                  GCPRO1 (fieldlist);
@@ -1194,6 +1242,34 @@ if any protected fields overlap this portion.")
   return collector;
 }
 \f
+/* Somebody has tried to store NEWVAL into the buffer-local slot with
+   offset XUINT (valcontents), and NEWVAL has an unacceptable type.  */
+void
+buffer_slot_type_mismatch (valcontents, newval)
+     Lisp_Object valcontents, newval;
+{
+  unsigned int offset = XUINT (valcontents);
+  unsigned char *symbol_name =
+    (XSYMBOL (*(Lisp_Object *)(offset + (char *)&buffer_local_symbols))
+     ->name->data);
+  char *type_name;
+  
+  switch (XINT (*(Lisp_Object *)(offset + (char *)&buffer_local_types)))
+    {
+    case Lisp_Int:     type_name = "integers";  break;
+    case Lisp_String:  type_name = "strings";   break;
+    case Lisp_Marker:  type_name = "markers";   break;
+    case Lisp_Symbol:  type_name = "symbols";   break;
+    case Lisp_Cons:    type_name = "lists";     break;
+    case Lisp_Vector:  type_name = "vectors";   break;
+    default:
+      abort ();
+    }
+
+  error ("only %s should be stored in the buffer-local variable %s",
+        type_name, symbol_name);
+}
+\f
 init_buffer_once ()
 {
   register Lisp_Object tem;
@@ -1290,18 +1366,27 @@ init_buffer_once ()
   /* super-magic invisible buffer */
   Vbuffer_alist = Qnil;
 
-  tem = Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
-  /* Want no undo records for *scratch*
-     until after Emacs is dumped */
-  Fbuffer_disable_undo (tem);
+  Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
 }
 
 init_buffer ()
 {
   char buf[MAXPATHLEN+1];
+  char *pwd;
+  struct stat dotstat, pwdstat;
 
   Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
-  if (getwd (buf) == 0)
+
+  /* If PWD is accurate, use it instead of calling getwd.  This is faster
+     when PWD is right, and may avoid a fatal error.  */
+  if ((pwd = getenv ("PWD")) != 0 && *pwd == '/'
+      && stat (pwd, &pwdstat) == 0
+      && stat (".", &dotstat) == 0
+      && dotstat.st_ino == pwdstat.st_ino
+      && dotstat.st_dev == pwdstat.st_dev
+      && strlen (pwd) < MAXPATHLEN)
+    strcpy (buf, pwd);
+  else if (getwd (buf) == 0)
     fatal ("`getwd' failed: %s.\n", buf);
 
 #ifndef VMS
@@ -1374,7 +1459,8 @@ This is the same as (default-value 'tab-width).");
     "Default value of `case-fold-search' for buffers that don't override it.\n\
 This is the same as (default-value 'case-fold-search).");
 
-  DEFVAR_PER_BUFFER ("mode-line-format", &current_buffer->mode_line_format, 0);
+  DEFVAR_PER_BUFFER ("mode-line-format", &current_buffer->mode_line_format, 
+                    Qnil, 0);
 
 /* This doc string is too long for cpp; cpp dies if it isn't in a comment.
    But make-docfile finds it!
@@ -1411,53 +1497,61 @@ Decimal digits after the % specify field width to which to pad.");
 nil here means use current buffer's major mode.");
 
   DEFVAR_PER_BUFFER ("major-mode", &current_buffer->major_mode,
+                    make_number (Lisp_Symbol),
     "Symbol for current buffer's major mode.");
 
   DEFVAR_PER_BUFFER ("mode-name", &current_buffer->mode_name,
+                     make_number (Lisp_String),
     "Pretty name of current buffer's major mode (a string).");
 
-  DEFVAR_PER_BUFFER ("abbrev-mode", &current_buffer->abbrev_mode,
+  DEFVAR_PER_BUFFER ("abbrev-mode", &current_buffer->abbrev_mode, Qnil, 
     "Non-nil turns on automatic expansion of abbrevs as they are inserted.\n\
 Automatically becomes buffer-local when set in any fashion.");
 
   DEFVAR_PER_BUFFER ("case-fold-search", &current_buffer->case_fold_search,
+                    Qnil,
     "*Non-nil if searches should ignore case.\n\
 Automatically becomes buffer-local when set in any fashion.");
 
   DEFVAR_PER_BUFFER ("fill-column", &current_buffer->fill_column,
+                    make_number (Lisp_Int),
     "*Column beyond which automatic line-wrapping should happen.\n\
 Automatically becomes buffer-local when set in any fashion.");
 
   DEFVAR_PER_BUFFER ("left-margin", &current_buffer->left_margin,
+                    make_number (Lisp_Int),
     "*Column for the default indent-line-function to indent to.\n\
 Linefeed indents to this column in Fundamental mode.\n\
 Automatically becomes buffer-local when set in any fashion.");
 
   DEFVAR_PER_BUFFER ("tab-width", &current_buffer->tab_width,
+                    make_number (Lisp_Int),
     "*Distance between tab stops (for display of tab characters), in columns.\n\
 Automatically becomes buffer-local when set in any fashion.");
 
-  DEFVAR_PER_BUFFER ("ctl-arrow", &current_buffer->ctl_arrow,
+  DEFVAR_PER_BUFFER ("ctl-arrow", &current_buffer->ctl_arrow, Qnil,
     "*Non-nil means display control chars with uparrow.\n\
 Nil means use backslash and octal digits.\n\
 Automatically becomes buffer-local when set in any fashion.\n\
 This variable does not apply to characters whose display is specified\n\
 in the current display table (if there is one).");
 
-  DEFVAR_PER_BUFFER ("truncate-lines", &current_buffer->truncate_lines,
+  DEFVAR_PER_BUFFER ("truncate-lines", &current_buffer->truncate_lines, Qnil,
     "*Non-nil means do not display continuation lines;\n\
 give each line of text one screen line.\n\
 Automatically becomes buffer-local when set in any fashion.\n\
 \n\
 Note that this is overridden by the variable\n\
 `truncate-partial-width-windows' if that variable is non-nil\n\
-and this buffer is not full-screen width.");
+and this buffer is not full-frame width.");
 
   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.");
 
   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 at a column beyond `fill-column'.\n\
 Each buffer has its own value of this variable.\n\
@@ -1465,30 +1559,34 @@ NOTE: This variable is not an ordinary hook;\n\
 It may not be a list of functions.");
 
   DEFVAR_PER_BUFFER ("buffer-file-name", &current_buffer->filename,
+                    make_number (Lisp_String),
     "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-auto-save-file-name",
-                   &current_buffer->auto_save_file_name,
+                    &current_buffer->auto_save_file_name,
+                    make_number (Lisp_String),
     "Name of file for auto-saving current buffer,\n\
 or nil if buffer should not be auto-saved.\n\
 Each buffer has its own value of this variable.");
 
-  DEFVAR_PER_BUFFER ("buffer-read-only", &current_buffer->read_only,
+  DEFVAR_PER_BUFFER ("buffer-read-only", &current_buffer->read_only, Qnil,
     "Non-nil if this buffer is read-only.\n\
 Each buffer has its own value of this variable.");
 
-  DEFVAR_PER_BUFFER ("buffer-backed-up", &current_buffer->backed_up,
+  DEFVAR_PER_BUFFER ("buffer-backed-up", &current_buffer->backed_up, Qnil,
     "Non-nil if this buffer's file has been backed up.\n\
 Backing up is done before the first time the file is saved.\n\
 Each buffer has its own value of this variable.");
 
   DEFVAR_PER_BUFFER ("buffer-saved-size", &current_buffer->save_length,
+                    make_number (Lisp_Int),
     "Length of current buffer when last read in, saved or auto-saved.\n\
 0 initially.\n\
 Each buffer has its own value of this variable.");
 
   DEFVAR_PER_BUFFER ("selective-display", &current_buffer->selective_display,
+                    Qnil,
     "Non-nil enables selective display:\n\
 Integer N as value means display only lines\n\
  that start with less than n columns of space.\n\
@@ -1499,15 +1597,17 @@ Automatically becomes buffer-local when set in any fashion.");
 #ifndef old
   DEFVAR_PER_BUFFER ("selective-display-ellipses",
                    &current_buffer->selective_display_ellipses,
+                    Qnil,
     "t means display ... on previous line when a line is invisible.\n\
 Automatically becomes buffer-local when set in any fashion.");
 #endif
 
-  DEFVAR_PER_BUFFER ("overwrite-mode", &current_buffer->overwrite_mode,
+  DEFVAR_PER_BUFFER ("overwrite-mode", &current_buffer->overwrite_mode, Qnil,
     "Non-nil if self-insertion should replace existing text.\n\
 Automatically becomes buffer-local when set in any fashion.");
 
   DEFVAR_PER_BUFFER ("buffer-display-table", &current_buffer->display_table,
+                    Qnil,
     "Display table that controls display of the contents of current buffer.\n\
 Automatically becomes buffer-local when set in any fashion.\n\
 The display table is a vector created with `make-display-table'.\n\
@@ -1523,10 +1623,10 @@ The remaining five elements are ropes that control the display of\n\
 If this variable is nil, the value of `standard-display-table' is used.\n\
 Each window can have its own, overriding display table.");
 
-  DEFVAR_PER_BUFFER ("buffer-field-list", &current_buffer->fieldlist,
+  DEFVAR_PER_BUFFER ("buffer-field-list", &current_buffer->fieldlist, Qnil,
     "List of fields in the current buffer.  See `add-field'.");
 
-  DEFVAR_BOOL ("check-protected-fields", check_protected_fields,
+  DEFVAR_BOOL ("check-protected-fields", &check_protected_fields,
     "Non-nil means don't allow modification of a protected field.\n\
 See `add-field'.");
   check_protected_fields = 0;
@@ -1559,12 +1659,14 @@ While executing the `after-change-function', changes to buffers do not\n\
 cause calls to any `before-change-function' or `after-change-function'.");
   Vafter_change_function = Qnil;
 
-  DEFVAR_LISP ("first-change-function", &Vfirst_change_function,
-  "Function to call before changing a buffer which is unmodified.\n\
-The function is called, with no arguments, if it is non-nil.");
-  Vfirst_change_function = Qnil;
+  DEFVAR_LISP ("first-change-hook", &Vfirst_change_hook,
+  "A list of functions to call before changing a buffer which is unmodified.\n\
+The functions are run using the `run-hooks' function.");
+  Vfirst_change_hook = Qnil;
+  Qfirst_change_hook = intern ("first-change-hook");
+  staticpro (&Qfirst_change_hook);
 
-  DEFVAR_PER_BUFFER ("buffer-undo-list", &current_buffer->undo_list,
+  DEFVAR_PER_BUFFER ("buffer-undo-list", &current_buffer->undo_list, Qnil,
     "List of undo entries in current buffer.\n\
 Recent changes come first; older changes follow newer.\n\
 \n\
@@ -1581,6 +1683,10 @@ previously unmodified.  HIGHWORD and LOWWORD are the high and low\n\
 modification count 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\
+\n\
 nil marks undo boundaries.  The undo command treats the changes\n\
 between two undo boundaries as a single step to be undone.\n\
 \n\