[__GNUC__] (C_DEBUG_SWITCH): New definition.
[bpt/emacs.git] / src / abbrev.c
index e3f1faf..6d88dad 100644 (file)
@@ -1,11 +1,11 @@
 /* Primitives for word-abbrev mode.
 /* Primitives for word-abbrev mode.
-   Copyright (C) 1985, 1986 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 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
 
 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,
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -15,16 +15,17 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 
 
-#include "config.h"
+#include <config.h>
 #include <stdio.h>
 #include <stdio.h>
-#undef NULL
 #include "lisp.h"
 #include "commands.h"
 #include "buffer.h"
 #include "window.h"
 #include "lisp.h"
 #include "commands.h"
 #include "buffer.h"
 #include "window.h"
+#include "syntax.h"
 
 /* An abbrev table is an obarray.
  Each defined abbrev is represented by a symbol in that obarray
 
 /* An abbrev table is an obarray.
  Each defined abbrev is represented by a symbol in that obarray
@@ -75,6 +76,9 @@ Lisp_Object Vlast_abbrev_text;
 
 int last_abbrev_point;
 
 
 int last_abbrev_point;
 
+/* Hook to run before expanding any abbrev.  */
+
+Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook;
 \f
 DEFUN ("make-abbrev-table", Fmake_abbrev_table, Smake_abbrev_table, 0, 0, 0,
   "Create a new, empty abbrev table object.")
 \f
 DEFUN ("make-abbrev-table", Fmake_abbrev_table, Smake_abbrev_table, 0, 0, 0,
   "Create a new, empty abbrev table object.")
@@ -110,9 +114,9 @@ it is called after EXPANSION is inserted.")
   Lisp_Object sym, oexp, ohook, tem;
   CHECK_VECTOR (table, 0);
   CHECK_STRING (name, 1);
   Lisp_Object sym, oexp, ohook, tem;
   CHECK_VECTOR (table, 0);
   CHECK_STRING (name, 1);
-  if (!NULL (expansion))
+  if (!NILP (expansion))
     CHECK_STRING (expansion, 2);
     CHECK_STRING (expansion, 2);
-  if (NULL (count))
+  if (NILP (count))
     count = make_number (0);
   else
     CHECK_NUMBER (count, 0);
     count = make_number (0);
   else
     CHECK_NUMBER (count, 0);
@@ -122,11 +126,11 @@ it is called after EXPANSION is inserted.")
   oexp = XSYMBOL (sym)->value;
   ohook = XSYMBOL (sym)->function;
   if (!((EQ (oexp, expansion)
   oexp = XSYMBOL (sym)->value;
   ohook = XSYMBOL (sym)->function;
   if (!((EQ (oexp, expansion)
-        || (XTYPE (oexp) == Lisp_String && XTYPE (expansion) == Lisp_String
-            && (tem = Fstring_equal (oexp, expansion), !NULL (tem))))
+        || (STRINGP (oexp) && STRINGP (expansion)
+            && (tem = Fstring_equal (oexp, expansion), !NILP (tem))))
        &&
        (EQ (ohook, hook)
        &&
        (EQ (ohook, hook)
-        || (tem = Fequal (ohook, hook), !NULL (tem)))))
+        || (tem = Fequal (ohook, hook), !NILP (tem)))))
     abbrevs_changed = 1;
 
   Fset (sym, expansion);
     abbrevs_changed = 1;
 
   Fset (sym, expansion);
@@ -139,26 +143,26 @@ it is called after EXPANSION is inserted.")
 DEFUN ("define-global-abbrev", Fdefine_global_abbrev, Sdefine_global_abbrev, 2, 2,
   "sDefine global abbrev: \nsExpansion for %s: ",
   "Define ABBREV as a global abbreviation for EXPANSION.")
 DEFUN ("define-global-abbrev", Fdefine_global_abbrev, Sdefine_global_abbrev, 2, 2,
   "sDefine global abbrev: \nsExpansion for %s: ",
   "Define ABBREV as a global abbreviation for EXPANSION.")
-  (name, expansion)
-     Lisp_Object name, expansion;
+  (abbrev, expansion)
+     Lisp_Object abbrev, expansion;
 {
 {
-  Fdefine_abbrev (Vglobal_abbrev_table, Fdowncase (name),
+  Fdefine_abbrev (Vglobal_abbrev_table, Fdowncase (abbrev),
                  expansion, Qnil, make_number (0));
                  expansion, Qnil, make_number (0));
-  return name;
+  return abbrev;
 }
 
 DEFUN ("define-mode-abbrev", Fdefine_mode_abbrev, Sdefine_mode_abbrev, 2, 2,
   "sDefine mode abbrev: \nsExpansion for %s: ",
   "Define ABBREV as a mode-specific abbreviation for EXPANSION.")
 }
 
 DEFUN ("define-mode-abbrev", Fdefine_mode_abbrev, Sdefine_mode_abbrev, 2, 2,
   "sDefine mode abbrev: \nsExpansion for %s: ",
   "Define ABBREV as a mode-specific abbreviation for EXPANSION.")
-  (name, expansion)
-     Lisp_Object name, expansion;
+  (abbrev, expansion)
+     Lisp_Object abbrev, expansion;
 {
 {
-  if (NULL (current_buffer->abbrev_table))
+  if (NILP (current_buffer->abbrev_table))
     error ("Major mode has no abbrev table");
 
     error ("Major mode has no abbrev table");
 
-  Fdefine_abbrev (current_buffer->abbrev_table, Fdowncase (name),
+  Fdefine_abbrev (current_buffer->abbrev_table, Fdowncase (abbrev),
                  expansion, Qnil, make_number (0));
                  expansion, Qnil, make_number (0));
-  return name;
+  return abbrev;
 }
 
 DEFUN ("abbrev-symbol", Fabbrev_symbol, Sabbrev_symbol, 1, 2, 0,
 }
 
 DEFUN ("abbrev-symbol", Fabbrev_symbol, Sabbrev_symbol, 1, 2, 0,
@@ -173,19 +177,19 @@ The default is to try buffer's mode-specific abbrev table, then global table.")
 {
   Lisp_Object sym;
   CHECK_STRING (abbrev, 0);
 {
   Lisp_Object sym;
   CHECK_STRING (abbrev, 0);
-  if (!NULL (table))
+  if (!NILP (table))
     sym = Fintern_soft (abbrev, table);
   else
     {
       sym = Qnil;
     sym = Fintern_soft (abbrev, table);
   else
     {
       sym = Qnil;
-      if (!NULL (current_buffer->abbrev_table))
+      if (!NILP (current_buffer->abbrev_table))
        sym = Fintern_soft (abbrev, current_buffer->abbrev_table);
        sym = Fintern_soft (abbrev, current_buffer->abbrev_table);
-      if (NULL (XSYMBOL (sym)->value))
+      if (NILP (XSYMBOL (sym)->value))
        sym = Qnil;
        sym = Qnil;
-      if (NULL (sym))
+      if (NILP (sym))
        sym = Fintern_soft (abbrev, Vglobal_abbrev_table);
     }
        sym = Fintern_soft (abbrev, Vglobal_abbrev_table);
     }
-  if (NULL (XSYMBOL (sym)->value)) return Qnil;
+  if (NILP (XSYMBOL (sym)->value)) return Qnil;
   return sym;
 }
 
   return sym;
 }
 
@@ -198,7 +202,7 @@ then ABBREV is looked up in that table only.")
 {
   Lisp_Object sym;
   sym = Fabbrev_symbol (abbrev, table);
 {
   Lisp_Object sym;
   sym = Fabbrev_symbol (abbrev, table);
-  if (NULL (sym)) return sym;
+  if (NILP (sym)) return sym;
   return Fsymbol_value (sym);
 }
 \f
   return Fsymbol_value (sym);
 }
 \f
@@ -217,37 +221,49 @@ Returns t if expansion took place.")
   int uccount = 0, lccount = 0;
   register Lisp_Object sym;
   Lisp_Object expansion, hook, tem;
   int uccount = 0, lccount = 0;
   register Lisp_Object sym;
   Lisp_Object expansion, hook, tem;
-
-  if (XBUFFER (Vabbrev_start_location_buffer) != current_buffer)
+  int oldmodiff = MODIFF;
+  Lisp_Object value;
+
+  if (!NILP (Vrun_hooks))
+    call1 (Vrun_hooks, Qpre_abbrev_expand_hook);
+  /* If the hook changes the buffer, treat that as having "done an
+     expansion".  */
+  value = (MODIFF != oldmodiff ? Qt : Qnil);
+
+  wordstart = 0;
+  if (!(BUFFERP (Vabbrev_start_location_buffer) &&
+       XBUFFER (Vabbrev_start_location_buffer) == current_buffer))
     Vabbrev_start_location = Qnil;
     Vabbrev_start_location = Qnil;
-  if (!NULL (Vabbrev_start_location))
+  if (!NILP (Vabbrev_start_location))
     {
       tem = Vabbrev_start_location;
       CHECK_NUMBER_COERCE_MARKER (tem, 0);
       wordstart = XINT (tem);
       Vabbrev_start_location = Qnil;
     {
       tem = Vabbrev_start_location;
       CHECK_NUMBER_COERCE_MARKER (tem, 0);
       wordstart = XINT (tem);
       Vabbrev_start_location = Qnil;
-      if (FETCH_CHAR (wordstart) == '-')
+      if (wordstart < BEGV || wordstart > ZV)
+       wordstart = 0;
+      if (wordstart && wordstart != ZV && FETCH_CHAR (wordstart) == '-')
        del_range (wordstart, wordstart + 1);
     }
        del_range (wordstart, wordstart + 1);
     }
-  else
+  if (!wordstart)
     wordstart = scan_words (point, -1);
 
   if (!wordstart)
     wordstart = scan_words (point, -1);
 
   if (!wordstart)
-    return Qnil;
+    return value;
 
   wordend = scan_words (wordstart, 1);
   if (!wordend)
 
   wordend = scan_words (wordstart, 1);
   if (!wordend)
-    return Qnil;
+    return value;
 
   if (wordend > point)
     wordend = point;
   whitecnt = point - wordend;
   if (wordend <= wordstart)
 
   if (wordend > point)
     wordend = point;
   whitecnt = point - wordend;
   if (wordend <= wordstart)
-    return Qnil;
+    return value;
 
   p = buffer = (char *) alloca (wordend - wordstart);
 
 
   p = buffer = (char *) alloca (wordend - wordstart);
 
-  for (idx = wordstart; idx < point; idx++)
+  for (idx = wordstart; idx < wordend; idx++)
     {
       register int c = FETCH_CHAR (idx);
       if (UPPERCASEP (c))
     {
       register int c = FETCH_CHAR (idx);
       if (UPPERCASEP (c))
@@ -257,17 +273,19 @@ Returns t if expansion took place.")
       *p++ = c;
     }
 
       *p++ = c;
     }
 
-  if (XTYPE (current_buffer->abbrev_table) == Lisp_Vector)
+  if (VECTORP (current_buffer->abbrev_table))
     sym = oblookup (current_buffer->abbrev_table, buffer, p - buffer);
   else
     sym = oblookup (current_buffer->abbrev_table, buffer, p - buffer);
   else
-    XFASTINT (sym) = 0;
-  if (XTYPE (sym) == Lisp_Int || NULL (XSYMBOL (sym)->value))
+    XSETFASTINT (sym, 0);
+  if (INTEGERP (sym) || NILP (XSYMBOL (sym)->value))
     sym = oblookup (Vglobal_abbrev_table, buffer, p - buffer);
     sym = oblookup (Vglobal_abbrev_table, buffer, p - buffer);
-  if (XTYPE (sym) == Lisp_Int || NULL (XSYMBOL (sym)->value))
-    return Qnil;
+  if (INTEGERP (sym) || NILP (XSYMBOL (sym)->value))
+    return value;
 
   if (INTERACTIVE && !EQ (minibuf_window, selected_window))
     {
 
   if (INTERACTIVE && !EQ (minibuf_window, selected_window))
     {
+      /* Add an undo boundary, in case we are doing this for
+        a self-inserting command which has avoided making one so far.  */
       SET_PT (wordend);
       Fundo_boundary ();
     }
       SET_PT (wordend);
       Fundo_boundary ();
     }
@@ -280,12 +298,12 @@ Returns t if expansion took place.")
   Vlast_abbrev = sym;
   last_abbrev_point = wordstart;
 
   Vlast_abbrev = sym;
   last_abbrev_point = wordstart;
 
-  if (XTYPE (XSYMBOL (sym)->plist) == Lisp_Int)
+  if (INTEGERP (XSYMBOL (sym)->plist))
     XSETINT (XSYMBOL (sym)->plist,
             XINT (XSYMBOL (sym)->plist) + 1);  /* Increment use count */
 
   expansion = XSYMBOL (sym)->value;
     XSETINT (XSYMBOL (sym)->plist,
             XINT (XSYMBOL (sym)->plist) + 1);  /* Increment use count */
 
   expansion = XSYMBOL (sym)->value;
-  insert_from_string (expansion, 0, XSTRING (expansion)->size);
+  insert_from_string (expansion, 0, XSTRING (expansion)->size, 1);
   SET_PT (point + whitecnt);
 
   if (uccount && !lccount)
   SET_PT (point + whitecnt);
 
   if (uccount && !lccount)
@@ -297,8 +315,8 @@ Returns t if expansion took place.")
       if (!abbrev_all_caps)
        if (scan_words (point, -1) > scan_words (wordstart, 1))
          {
       if (!abbrev_all_caps)
        if (scan_words (point, -1) > scan_words (wordstart, 1))
          {
-           upcase_initials_region (make_number (wordstart),
-                                   make_number (point));
+           Fupcase_initials_region (make_number (wordstart),
+                                    make_number (point));
            goto caped;
          }
       /* If expansion is one word, or if user says so, upcase it all. */
            goto caped;
          }
       /* If expansion is one word, or if user says so, upcase it all. */
@@ -308,20 +326,19 @@ Returns t if expansion took place.")
   else if (uccount)
     {
       /* Abbrev included some caps.  Cap first initial of expansion */
   else if (uccount)
     {
       /* Abbrev included some caps.  Cap first initial of expansion */
-      int old_zv = ZV;
-      int old_pt = point;
+      int pos = wordstart;
 
 
-      /* Don't let Fcapitalize_word operate on text after point.  */
-      ZV = point;
-      SET_PT (wordstart);
-      Fcapitalize_word (make_number (1));
+      /* Find the initial.  */
+      while (pos < point
+            && SYNTAX (*BUF_CHAR_ADDRESS (current_buffer, pos)) != Sword)
+       pos++;
 
 
-      SET_PT (old_pt);
-      ZV = old_zv;
+      /* Change just that.  */
+      Fupcase_initials_region (make_number (pos), make_number (pos + 1));
     }
 
   hook = XSYMBOL (sym)->function;
     }
 
   hook = XSYMBOL (sym)->function;
-  if (!NULL (hook))
+  if (!NILP (hook))
     call0 (hook);
 
   return Qt;
     call0 (hook);
 
   return Qt;
@@ -339,16 +356,19 @@ is not undone.")
       || last_abbrev_point > ZV)
     return Qnil;
   SET_PT (last_abbrev_point);
       || last_abbrev_point > ZV)
     return Qnil;
   SET_PT (last_abbrev_point);
-  if (XTYPE (Vlast_abbrev_text) == Lisp_String)
+  if (STRINGP (Vlast_abbrev_text))
     {
       /* This isn't correct if Vlast_abbrev->function was used
          to do the expansion */
       Lisp_Object val;
     {
       /* This isn't correct if Vlast_abbrev->function was used
          to do the expansion */
       Lisp_Object val;
-      XSET (val, Lisp_String, XSYMBOL (Vlast_abbrev)->value);
+      val = XSYMBOL (Vlast_abbrev)->value;
+      if (!STRINGP (val))
+       error ("value of abbrev-symbol must be a string");
       adjust = XSTRING (val)->size;
       del_range (point, point + adjust);
       adjust = XSTRING (val)->size;
       del_range (point, point + adjust);
+      /* Don't inherit properties here; just copy from old contents.  */
       insert_from_string (Vlast_abbrev_text, 0,
       insert_from_string (Vlast_abbrev_text, 0,
-                         XSTRING (Vlast_abbrev_text)->size);
+                         XSTRING (Vlast_abbrev_text)->size, 0);
       adjust -= XSTRING (Vlast_abbrev_text)->size;
       Vlast_abbrev_text = Qnil;
     }
       adjust -= XSTRING (Vlast_abbrev_text)->size;
       Vlast_abbrev_text = Qnil;
     }
@@ -361,10 +381,10 @@ write_abbrev (sym, stream)
      Lisp_Object sym, stream;
 {
   Lisp_Object name;
      Lisp_Object sym, stream;
 {
   Lisp_Object name;
-  if (NULL (XSYMBOL (sym)->value))
+  if (NILP (XSYMBOL (sym)->value))
     return;
   insert ("    (", 5);
     return;
   insert ("    (", 5);
-  XSET (name, Lisp_String, XSYMBOL (sym)->name);
+  XSETSTRING (name, XSYMBOL (sym)->name);
   Fprin1 (name, stream);
   insert (" ", 1);
   Fprin1 (XSYMBOL (sym)->value, stream);
   Fprin1 (name, stream);
   insert (" ", 1);
   Fprin1 (XSYMBOL (sym)->value, stream);
@@ -381,7 +401,7 @@ describe_abbrev (sym, stream)
 {
   Lisp_Object one;
 
 {
   Lisp_Object one;
 
-  if (NULL (XSYMBOL (sym)->value))
+  if (NILP (XSYMBOL (sym)->value))
     return;
   one = make_number (1);
   Fprin1 (Fsymbol_name (sym), stream);
     return;
   one = make_number (1);
   Fprin1 (Fsymbol_name (sym), stream);
@@ -389,7 +409,7 @@ describe_abbrev (sym, stream)
   Fprin1 (XSYMBOL (sym)->plist, stream);
   Findent_to (make_number (20), one);
   Fprin1 (XSYMBOL (sym)->value, stream);
   Fprin1 (XSYMBOL (sym)->plist, stream);
   Findent_to (make_number (20), one);
   Fprin1 (XSYMBOL (sym)->value, stream);
-  if (!NULL (XSYMBOL (sym)->function))
+  if (!NILP (XSYMBOL (sym)->function))
     {
       Findent_to (make_number (45), one);
       Fprin1 (XSYMBOL (sym)->function, stream);
     {
       Findent_to (make_number (45), one);
       Fprin1 (XSYMBOL (sym)->function, stream);
@@ -402,8 +422,8 @@ DEFUN ("insert-abbrev-table-description",
   1, 2, 0,
   "Insert before point a full description of abbrev table named NAME.\n\
 NAME is a symbol whose value is an abbrev table.\n\
   1, 2, 0,
   "Insert before point a full description of abbrev table named NAME.\n\
 NAME is a symbol whose value is an abbrev table.\n\
-If optional 2nd arg HUMAN is non-nil, a human-readable description is inserted.\n\
-Otherwise the description is an expression,\n\
+If optional 2nd arg READABLE is non-nil, a human-readable description\n\
+is inserted.  Otherwise the description is an expression,\n\
 a call to `define-abbrev-table', which would\n\
 define the abbrev table NAME exactly as it is currently defined.")
   (name, readable)
 a call to `define-abbrev-table', which would\n\
 define the abbrev table NAME exactly as it is currently defined.")
   (name, readable)
@@ -416,9 +436,9 @@ define the abbrev table NAME exactly as it is currently defined.")
   table = Fsymbol_value (name);
   CHECK_VECTOR (table, 0);
 
   table = Fsymbol_value (name);
   CHECK_VECTOR (table, 0);
 
-  XSET (stream, Lisp_Buffer, current_buffer);
+  XSETBUFFER (stream, current_buffer);
 
 
-  if (!NULL (readable))
+  if (!NILP (readable))
     {
       insert_string ("(");
       Fprin1 (name, stream);
     {
       insert_string ("(");
       Fprin1 (name, stream);
@@ -440,35 +460,31 @@ define the abbrev table NAME exactly as it is currently defined.")
 \f
 DEFUN ("define-abbrev-table", Fdefine_abbrev_table, Sdefine_abbrev_table,
        2, 2, 0,
 \f
 DEFUN ("define-abbrev-table", Fdefine_abbrev_table, Sdefine_abbrev_table,
        2, 2, 0,
-  "Define TABNAME (a symbol) as an abbrev table name.\n\
+  "Define TABLENAME (a symbol) as an abbrev table name.\n\
 Define abbrevs in it according to DEFINITIONS, which is a list of elements\n\
 of the form (ABBREVNAME EXPANSION HOOK USECOUNT).")
 Define abbrevs in it according to DEFINITIONS, which is a list of elements\n\
 of the form (ABBREVNAME EXPANSION HOOK USECOUNT).")
-  (tabname, defns)
-     Lisp_Object tabname, defns;
+  (tablename, definitions)
+     Lisp_Object tablename, definitions;
 {
   Lisp_Object name, exp, hook, count;
   Lisp_Object table, elt;
 
 {
   Lisp_Object name, exp, hook, count;
   Lisp_Object table, elt;
 
-  CHECK_SYMBOL (tabname, 0);
-  table = Fboundp (tabname);
-  if (NULL (table) || (table = Fsymbol_value (tabname), NULL (table)))
+  CHECK_SYMBOL (tablename, 0);
+  table = Fboundp (tablename);
+  if (NILP (table) || (table = Fsymbol_value (tablename), NILP (table)))
     {
       table = Fmake_abbrev_table ();
     {
       table = Fmake_abbrev_table ();
-      Fset (tabname, table);
-      Vabbrev_table_name_list =
-       Fcons (tabname, Vabbrev_table_name_list);
+      Fset (tablename, table);
+      Vabbrev_table_name_list = Fcons (tablename, Vabbrev_table_name_list);
     }
   CHECK_VECTOR (table, 0);
 
     }
   CHECK_VECTOR (table, 0);
 
-  for (;!NULL (defns); defns = Fcdr (defns))
+  for (; !NILP (definitions); definitions = Fcdr (definitions))
     {
     {
-      elt = Fcar (defns);
-      name = Fcar (elt);
-      elt = Fcdr (elt);
-      exp = Fcar (elt);
-      elt = Fcdr (elt);
-      hook = Fcar (elt);
-      elt = Fcdr (elt);
+      elt = Fcar (definitions);
+      name  = Fcar (elt);      elt = Fcdr (elt);
+      exp   = Fcar (elt);      elt = Fcdr (elt);
+      hook  = Fcar (elt);      elt = Fcdr (elt);
       count = Fcar (elt);
       Fdefine_abbrev (table, name, exp, hook, count);
     }
       count = Fcar (elt);
       Fdefine_abbrev (table, name, exp, hook, count);
     }
@@ -520,7 +536,7 @@ Calling `expand-abbrev' sets this to nil.");
 Trying to expand an abbrev in any other buffer clears `abbrev-start-location'.");
   Vabbrev_start_location_buffer = Qnil;
 
 Trying to expand an abbrev in any other buffer clears `abbrev-start-location'.");
   Vabbrev_start_location_buffer = Qnil;
 
-  DEFVAR_PER_BUFFER ("local-abbrev-table", &current_buffer->abbrev_table,
+  DEFVAR_PER_BUFFER ("local-abbrev-table", &current_buffer->abbrev_table, Qnil,
     "Local (mode-specific) abbrev table of current buffer.");
 
   DEFVAR_BOOL ("abbrevs-changed", &abbrevs_changed,
     "Local (mode-specific) abbrev table of current buffer.");
 
   DEFVAR_BOOL ("abbrevs-changed", &abbrevs_changed,
@@ -532,6 +548,14 @@ This causes `save-some-buffers' to offer to save the abbrevs.");
     "*Set non-nil means expand multi-word abbrevs all caps if abbrev was so.");
   abbrev_all_caps = 0;
 
     "*Set non-nil means expand multi-word abbrevs all caps if abbrev was so.");
   abbrev_all_caps = 0;
 
+  DEFVAR_LISP ("pre-abbrev-expand-hook", &Vpre_abbrev_expand_hook,
+    "Function or functions to be called before abbrev expansion is done.\n\
+This is the first thing that `expand-abbrev' does, and so this may change\n\
+the current abbrev table before abbrev lookup happens.");
+  Vpre_abbrev_expand_hook = Qnil;
+  Qpre_abbrev_expand_hook = intern ("pre-abbrev-expand-hook");
+  staticpro (&Qpre_abbrev_expand_hook);
+
   defsubr (&Smake_abbrev_table);
   defsubr (&Sclear_abbrev_table);
   defsubr (&Sdefine_abbrev);
   defsubr (&Smake_abbrev_table);
   defsubr (&Sclear_abbrev_table);
   defsubr (&Sdefine_abbrev);