Include keymap.h.
[bpt/emacs.git] / src / fns.c
index 7e6995a..162bc16 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -1,5 +1,6 @@
 /* Random utility Lisp functions.
-   Copyright (C) 1985, 86, 87, 93, 94, 95, 97, 98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 93, 94, 95, 97, 98, 99, 2000, 2001
+   Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -37,9 +38,11 @@ Boston, MA 02111-1307, USA.  */
 
 #include "buffer.h"
 #include "keyboard.h"
+#include "keymap.h"
 #include "intervals.h"
 #include "frame.h"
 #include "window.h"
+#include "blockinput.h"
 #if defined (HAVE_MENUS) && defined (HAVE_X_WINDOWS)
 #include "xterm.h"
 #endif
@@ -48,11 +51,6 @@ Boston, MA 02111-1307, USA.  */
 #define NULL (void *)0
 #endif
 
-#ifndef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#define max(a, b) ((a) > (b) ? (a) : (b))
-#endif
-
 /* Nonzero enables use of dialog boxes for questions
    asked by mouse commands.  */
 int use_dialog_box;
@@ -130,7 +128,7 @@ To get the number of bytes, use `string-bytes'")
   (sequence)
      register Lisp_Object sequence;
 {
-  register Lisp_Object tail, val;
+  register Lisp_Object val;
   register int i;
 
  retry:
@@ -139,22 +137,31 @@ To get the number of bytes, use `string-bytes'")
   else if (VECTORP (sequence))
     XSETFASTINT (val, XVECTOR (sequence)->size);
   else if (CHAR_TABLE_P (sequence))
-    XSETFASTINT (val, (MIN_CHAR_COMPOSITION
-                      + (CHAR_FIELD2_MASK | CHAR_FIELD3_MASK)
-                      - 1));
+    XSETFASTINT (val, MAX_CHAR);
   else if (BOOL_VECTOR_P (sequence))
     XSETFASTINT (val, XBOOL_VECTOR (sequence)->size);
   else if (COMPILEDP (sequence))
     XSETFASTINT (val, XVECTOR (sequence)->size & PSEUDOVECTOR_SIZE_MASK);
   else if (CONSP (sequence))
     {
-      for (i = 0, tail = sequence; !NILP (tail); i++)
+      i = 0;
+      while (CONSP (sequence))
        {
+         sequence = XCDR (sequence);
+         ++i;
+
+         if (!CONSP (sequence))
+           break;
+
+         sequence = XCDR (sequence);
+         ++i;
          QUIT;
-         tail = Fcdr (tail);
        }
 
-      XSETFASTINT (val, i);
+      if (!NILP (sequence))
+       wrong_type_argument (Qlistp, sequence);
+
+      val = make_number (i);
     }
   else if (NILP (sequence))
     XSETFASTINT (val, 0);
@@ -182,13 +189,13 @@ which is at least the number of distinct elements.")
 
   /* halftail is used to detect circular lists.  */
   halftail = list;
-  for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
+  for (tail = list; CONSP (tail); tail = XCDR (tail))
     {
       if (EQ (tail, halftail) && len != 0)
        break;
       len++;
       if ((len & 1) == 0)
-       halftail = XCONS (halftail)->cdr;
+       halftail = XCDR (halftail);
     }
 
   XSETINT (length, len);
@@ -281,7 +288,7 @@ If string STR1 is greater, the value is a positive number N;\n\
       int c1, c2;
 
       if (STRING_MULTIBYTE (str1))
-       FETCH_STRING_CHAR_ADVANCE (c1, str1, i1, i1_byte);
+       FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c1, str1, i1, i1_byte);
       else
        {
          c1 = XSTRING (str1)->data[i1++];
@@ -289,7 +296,7 @@ If string STR1 is greater, the value is a positive number N;\n\
        }
 
       if (STRING_MULTIBYTE (str2))
-       FETCH_STRING_CHAR_ADVANCE (c2, str2, i2, i2_byte);
+       FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c2, str2, i2, i2_byte);
       else
        {
          c2 = XSTRING (str2)->data[i2++];
@@ -316,9 +323,9 @@ If string STR1 is greater, the value is a positive number N;\n\
         past the character that we are comparing;
         hence we don't add or subtract 1 here.  */
       if (c1 < c2)
-       return make_number (- i1);
+       return make_number (- i1 + XINT (start1));
       else
-       return make_number (i1);
+       return make_number (i1 - XINT (start1));
     }
 
   if (i1 < end1_char)
@@ -358,15 +365,8 @@ Symbols are also allowed; their print names are used instead.")
         characters, not just the bytes.  */
       int c1, c2;
 
-      if (STRING_MULTIBYTE (s1))
-       FETCH_STRING_CHAR_ADVANCE (c1, s1, i1, i1_byte);
-      else
-       c1 = XSTRING (s1)->data[i1++];
-
-      if (STRING_MULTIBYTE (s2))
-       FETCH_STRING_CHAR_ADVANCE (c2, s2, i2, i2_byte);
-      else
-       c2 = XSTRING (s2)->data[i2++];
+      FETCH_STRING_CHAR_ADVANCE (c1, s1, i1, i1_byte);
+      FETCH_STRING_CHAR_ADVANCE (c2, s2, i2, i2_byte);
 
       if (c1 != c2)
        return c1 < c2 ? Qt : Qnil;
@@ -422,12 +422,7 @@ The last argument is not copied, just used as the tail of the new list.")
 DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0,
   "Concatenate all the arguments and make the result a string.\n\
 The result is a string whose elements are the elements of all the arguments.\n\
-Each argument may be a string or a list or vector of characters (integers).\n\
-\n\
-Do not use individual integers as arguments!\n\
-The behavior of `concat' in that case will be changed later!\n\
-If your program passes an integer as an argument to `concat',\n\
-you should change it right away not to do so.")
+Each argument may be a string or a list or vector of characters (integers).")
   (nargs, args)
      int nargs;
      Lisp_Object *args;
@@ -557,7 +552,7 @@ concat (nargs, args, target_type, last_special)
   register Lisp_Object tail;
   register Lisp_Object this;
   int toindex;
-  int toindex_byte;
+  int toindex_byte = 0;
   register int result_len;
   register int result_len_byte;
   register int argnum;
@@ -569,10 +564,12 @@ concat (nargs, args, target_type, last_special)
      string can't be decided until we finish the whole concatination.
      So, we record strings that have text properties to be copied
      here, and copy the text properties after the concatination.  */
-  struct textprop_rec  *textprops;
+  struct textprop_rec  *textprops = NULL;
   /* Number of elments in textprops.  */
   int num_textprops = 0;
 
+  tail = Qnil;
+
   /* In append, the last arg isn't treated like the others */
   if (last_special && nargs > 0)
     {
@@ -589,9 +586,6 @@ concat (nargs, args, target_type, last_special)
       if (!(CONSP (this) || NILP (this) || VECTORP (this) || STRINGP (this)
            || COMPILEDP (this) || BOOL_VECTOR_P (this)))
        {
-         if (INTEGERP (this))
-            args[argnum] = Fnumber_to_string (this);
-         else
            args[argnum] = wrong_type_argument (Qsequencep, this);
        }
     }
@@ -624,20 +618,20 @@ concat (nargs, args, target_type, last_special)
                  wrong_type_argument (Qintegerp, ch);
                this_len_byte = CHAR_BYTES (XINT (ch));
                result_len_byte += this_len_byte;
-               if (this_len_byte > 1)
+               if (!SINGLE_BYTE_CHAR_P (XINT (ch)))
                  some_multibyte = 1;
              }
          else if (BOOL_VECTOR_P (this) && XBOOL_VECTOR (this)->size > 0)
            wrong_type_argument (Qintegerp, Faref (this, make_number (0)));
          else if (CONSP (this))
-           for (; CONSP (this); this = XCONS (this)->cdr)
+           for (; CONSP (this); this = XCDR (this))
              {
-               ch = XCONS (this)->car;
+               ch = XCAR (this);
                if (! INTEGERP (ch))
                  wrong_type_argument (Qintegerp, ch);
                this_len_byte = CHAR_BYTES (XINT (ch));
                result_len_byte += this_len_byte;
-               if (this_len_byte > 1)
+               if (!SINGLE_BYTE_CHAR_P (XINT (ch)))
                  some_multibyte = 1;
              }
          else if (STRINGP (this))
@@ -687,7 +681,7 @@ concat (nargs, args, target_type, last_special)
   for (argnum = 0; argnum < nargs; argnum++)
     {
       Lisp_Object thislen;
-      int thisleni;
+      int thisleni = 0;
       register unsigned int thisindex = 0;
       register unsigned int thisindex_byte = 0;
 
@@ -744,7 +738,7 @@ concat (nargs, args, target_type, last_special)
               `this' is exhausted. */
            if (NILP (this)) break;
            if (CONSP (this))
-             elt = XCONS (this)->car, this = XCONS (this)->cdr;
+             elt = XCAR (this), this = XCDR (this);
            else if (thisindex >= thisleni)
              break;
            else if (STRINGP (this))
@@ -752,9 +746,9 @@ concat (nargs, args, target_type, last_special)
                int c;
                if (STRING_MULTIBYTE (this))
                  {
-                   FETCH_STRING_CHAR_ADVANCE (c, this,
-                                              thisindex,
-                                              thisindex_byte);
+                   FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, this,
+                                                       thisindex,
+                                                       thisindex_byte);
                    XSETFASTINT (elt, c);
                  }
                else
@@ -787,9 +781,9 @@ concat (nargs, args, target_type, last_special)
            /* Store this element into the result.  */
            if (toindex < 0)
              {
-               XCONS (tail)->car = elt;
+               XCAR (tail) = elt;
                prev = tail;
-               tail = XCONS (tail)->cdr;
+               tail = XCDR (tail);
              }
            else if (VECTORP (val))
              XVECTOR (val)->contents[toindex++] = elt;
@@ -798,7 +792,12 @@ concat (nargs, args, target_type, last_special)
                CHECK_NUMBER (elt, 0);
                if (SINGLE_BYTE_CHAR_P (XINT (elt)))
                  {
-                   XSTRING (val)->data[toindex_byte++] = XINT (elt);
+                   if (some_multibyte)
+                     toindex_byte
+                       += CHAR_STRING (XINT (elt),
+                                       XSTRING (val)->data + toindex_byte);
+                   else
+                     XSTRING (val)->data[toindex_byte++] = XINT (elt);
                    if (some_multibyte
                        && toindex_byte > 0
                        && count_combining (XSTRING (val)->data,
@@ -812,30 +811,38 @@ concat (nargs, args, target_type, last_special)
                     we already decided to make a multibyte string.  */
                  {
                    int c = XINT (elt);
-                   unsigned char work[4], *str;
-                   int i = CHAR_STRING (c, work, str);
-
                    /* P exists as a variable
                       to avoid a bug on the Masscomp C compiler.  */
                    unsigned char *p = & XSTRING (val)->data[toindex_byte];
-                   bcopy (str, p, i);
-                   toindex_byte += i;
+
+                   toindex_byte += CHAR_STRING (c, p);
                    toindex++;
                  }
              }
          }
     }
   if (!NILP (prev))
-    XCONS (prev)->cdr = last_tail;
+    XCDR (prev) = last_tail;
 
   if (num_textprops > 0)
     {
+      Lisp_Object props;
+      int last_to_end = -1;
+
       for (argnum = 0; argnum < num_textprops; argnum++)
        {
          this = args[textprops[argnum].argnum];
-         copy_text_properties (make_number (textprops[argnum].from),
-                               XSTRING (this)->size, this,
-                               make_number (textprops[argnum].to), val, Qnil);
+         props = text_property_list (this,
+                                     make_number (0),
+                                     make_number (XSTRING (this)->size),
+                                     Qnil);
+         /* If successive arguments have properites, be sure that the
+            value of `composition' property be the copy.  */
+         if (last_to_end == textprops[argnum].to)
+           make_composition_value_copy (props);
+         add_text_properties_from_list (val, props,
+                                        make_number (textprops[argnum].to));
+         last_to_end = textprops[argnum].to + XSTRING (this)->size;
        }
     }
   return val;
@@ -888,7 +895,8 @@ string_char_to_byte (string, char_index)
       while (best_below < char_index)
        {
          int c;
-         FETCH_STRING_CHAR_ADVANCE (c, string, best_below, best_below_byte);
+         FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string,
+                                             best_below, best_below_byte);
        }
       i = best_below;
       i_byte = best_below_byte;
@@ -960,7 +968,8 @@ string_byte_to_char (string, byte_index)
       while (best_below_byte < byte_index)
        {
          int c;
-         FETCH_STRING_CHAR_ADVANCE (c, string, best_below, best_below_byte);
+         FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string,
+                                             best_below, best_below_byte);
        }
       i = best_below;
       i_byte = best_below_byte;
@@ -1072,7 +1081,10 @@ DEFUN ("string-as-unibyte", Fstring_as_unibyte, Sstring_as_unibyte,
        1, 1, 0,
   "Return a unibyte string with the same individual bytes as STRING.\n\
 If STRING is unibyte, the result is STRING itself.\n\
-Otherwise it is a newly created string, with no text properties.")
+Otherwise it is a newly created string, with no text properties.\n\
+If STRING is multibyte and contains a character of charset\n\
+`eight-bit-control' or `eight-bit-graphic', it is converted to the\n\
+corresponding single byte.")
   (string)
      Lisp_Object string;
 {
@@ -1080,10 +1092,13 @@ Otherwise it is a newly created string, with no text properties.")
 
   if (STRING_MULTIBYTE (string))
     {
-      string = Fcopy_sequence (string);
-      XSTRING (string)->size = STRING_BYTES (XSTRING (string));
-      XSTRING (string)->intervals = NULL_INTERVAL;
-      SET_STRING_BYTES (XSTRING (string), -1);
+      int bytes = STRING_BYTES (XSTRING (string));
+      unsigned char *str = (unsigned char *) xmalloc (bytes);
+
+      bcopy (XSTRING (string)->data, str, bytes);
+      bytes = str_as_unibyte (str, bytes);
+      string = make_unibyte_string (str, bytes);
+      xfree (str);
     }
   return string;
 }
@@ -1092,7 +1107,10 @@ DEFUN ("string-as-multibyte", Fstring_as_multibyte, Sstring_as_multibyte,
        1, 1, 0,
   "Return a multibyte string with the same individual bytes as STRING.\n\
 If STRING is multibyte, the result is STRING itself.\n\
-Otherwise it is a newly created string, with no text properties.")
+Otherwise it is a newly created string, with no text properties.\n\
+If STRING is unibyte and contains an individual 8-bit byte (i.e. not\n\
+part of a multibyte form), it is converted to the corresponding\n\
+multibyte character of charset `eight-bit-control' or `eight-bit-graphic'.")
   (string)
      Lisp_Object string;
 {
@@ -1100,12 +1118,19 @@ Otherwise it is a newly created string, with no text properties.")
 
   if (! STRING_MULTIBYTE (string))
     {
-      int nbytes = STRING_BYTES (XSTRING (string));
-      int newlen = multibyte_chars_in_text (XSTRING (string)->data, nbytes);
-
-      string = Fcopy_sequence (string);
-      XSTRING (string)->size = newlen;
-      XSTRING (string)->size_byte = nbytes;
+      Lisp_Object new_string;
+      int nchars, nbytes;
+
+      parse_str_as_multibyte (XSTRING (string)->data,
+                             STRING_BYTES (XSTRING (string)),
+                             &nchars, &nbytes);
+      new_string = make_uninit_multibyte_string (nchars, nbytes);
+      bcopy (XSTRING (string)->data, XSTRING (new_string)->data,
+            STRING_BYTES (XSTRING (string)));
+      if (nbytes != STRING_BYTES (XSTRING (string)))
+       str_as_multibyte (XSTRING (new_string)->data, nbytes,
+                         STRING_BYTES (XSTRING (string)), NULL);
+      string = new_string;
       XSTRING (string)->intervals = NULL_INTERVAL;
     }
   return string;
@@ -1127,13 +1152,13 @@ Elements of ALIST that are not conses are also shared.")
   if (NILP (alist))
     return alist;
   alist = concat (1, &alist, Lisp_Cons, 0);
-  for (tem = alist; CONSP (tem); tem = XCONS (tem)->cdr)
+  for (tem = alist; CONSP (tem); tem = XCDR (tem))
     {
       register Lisp_Object car;
-      car = XCONS (tem)->car;
+      car = XCAR (tem);
 
       if (CONSP (car))
-       XCONS (tem)->car = Fcons (XCONS (car)->car, XCONS (car)->cdr);
+       XCAR (tem) = Fcons (XCAR (car), XCDR (car));
     }
   return alist;
 }
@@ -1150,9 +1175,9 @@ This function allows vectors as well as strings.")
 {
   Lisp_Object res;
   int size;
-  int size_byte;
+  int size_byte = 0;
   int from_char, to_char;
-  int from_byte, to_byte;
+  int from_byte = 0, to_byte = 0;
 
   if (! (STRINGP (string) || VECTORP (string)))
     wrong_type_argument (Qarrayp, string);
@@ -1262,7 +1287,9 @@ DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0,
   for (i = 0; i < num && !NILP (list); i++)
     {
       QUIT;
-      list = Fcdr (list);
+      if (! CONSP (list))
+       wrong_type_argument (Qlistp, list);
+      list = XCDR (list);
     }
   return list;
 }
@@ -1302,10 +1329,12 @@ The value is actually the tail of LIST whose car is ELT.")
      Lisp_Object list;
 {
   register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
+  for (tail = list; !NILP (tail); tail = XCDR (tail))
     {
       register Lisp_Object tem;
-      tem = Fcar (tail);
+      if (! CONSP (tail))
+       wrong_type_argument (Qlistp, list);
+      tem = XCAR (tail);
       if (! NILP (Fequal (elt, tem)))
        return tail;
       QUIT;
@@ -1314,21 +1343,33 @@ The value is actually the tail of LIST whose car is ELT.")
 }
 
 DEFUN ("memq", Fmemq, Smemq, 2, 2, 0,
-  "Return non-nil if ELT is an element of LIST.  Comparison done with EQ.\n\
-The value is actually the tail of LIST whose car is ELT.")
+  "Return non-nil if ELT is an element of LIST.\n\
+Comparison done with EQ.  The value is actually the tail of LIST\n\
+whose car is ELT.")
   (elt, list)
-     register Lisp_Object elt;
-     Lisp_Object list;
+     Lisp_Object elt, list;
 {
-  register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
+  while (1)
     {
-      register Lisp_Object tem;
-      tem = Fcar (tail);
-      if (EQ (elt, tem)) return tail;
+      if (!CONSP (list) || EQ (XCAR (list), elt))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list) || EQ (XCAR (list), elt))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list) || EQ (XCAR (list), elt))
+       break;
+
+      list = XCDR (list);
       QUIT;
     }
-  return Qnil;
+
+  if (!CONSP (list) && !NILP (list))
+    list = wrong_type_argument (Qlistp, list);
+
+  return list;
 }
 
 DEFUN ("assq", Fassq, Sassq, 2, 2, 0,
@@ -1336,20 +1377,41 @@ DEFUN ("assq", Fassq, Sassq, 2, 2, 0,
 The value is actually the element of LIST whose car is KEY.\n\
 Elements of LIST that are not conses are ignored.")
   (key, list)
-     register Lisp_Object key;
-     Lisp_Object list;
+     Lisp_Object key, list;
 {
-  register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
+  Lisp_Object result;
+
+  while (1)
     {
-      register Lisp_Object elt, tem;
-      elt = Fcar (tail);
-      if (!CONSP (elt)) continue;
-      tem = XCONS (elt)->car;
-      if (EQ (key, tem)) return elt;
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && EQ (XCAR (XCAR (list)), key)))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && EQ (XCAR (XCAR (list)), key)))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && EQ (XCAR (XCAR (list)), key)))
+       break;
+
+      list = XCDR (list);
       QUIT;
     }
-  return Qnil;
+
+  if (CONSP (list))
+    result = XCAR (list);
+  else if (NILP (list))
+    result = Qnil;
+  else
+    result = wrong_type_argument (Qlistp, list);
+
+  return result;
 }
 
 /* Like Fassq but never report an error and do not allow quits.
@@ -1357,79 +1419,144 @@ Elements of LIST that are not conses are ignored.")
 
 Lisp_Object
 assq_no_quit (key, list)
-     register Lisp_Object key;
-     Lisp_Object list;
+     Lisp_Object key, list;
 {
-  register Lisp_Object tail;
-  for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
-    {
-      register Lisp_Object elt, tem;
-      elt = Fcar (tail);
-      if (!CONSP (elt)) continue;
-      tem = XCONS (elt)->car;
-      if (EQ (key, tem)) return elt;
-    }
-  return Qnil;
+  while (CONSP (list)
+        && (!CONSP (XCAR (list))
+            || !EQ (XCAR (XCAR (list)), key)))
+    list = XCDR (list);
+
+  return CONSP (list) ? XCAR (list) : Qnil;
 }
 
 DEFUN ("assoc", Fassoc, Sassoc, 2, 2, 0,
   "Return non-nil if KEY is `equal' to the car of an element of LIST.\n\
 The value is actually the element of LIST whose car equals KEY.")
   (key, list)
-     register Lisp_Object key;
-     Lisp_Object list;
+     Lisp_Object key, list;
 {
-  register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
+  Lisp_Object result, car;
+
+  while (1)
     {
-      register Lisp_Object elt, tem;
-      elt = Fcar (tail);
-      if (!CONSP (elt)) continue;
-      tem = Fequal (XCONS (elt)->car, key);
-      if (!NILP (tem)) return elt;
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && (car = XCAR (XCAR (list)),
+                 EQ (car, key) || !NILP (Fequal (car, key)))))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && (car = XCAR (XCAR (list)),
+                 EQ (car, key) || !NILP (Fequal (car, key)))))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && (car = XCAR (XCAR (list)),
+                 EQ (car, key) || !NILP (Fequal (car, key)))))
+       break;
+
+      list = XCDR (list);
       QUIT;
     }
-  return Qnil;
+
+  if (CONSP (list))
+    result = XCAR (list);
+  else if (NILP (list))
+    result = Qnil;
+  else
+    result = wrong_type_argument (Qlistp, list);
+
+  return result;
 }
 
 DEFUN ("rassq", Frassq, Srassq, 2, 2, 0,
-  "Return non-nil if ELT is `eq' to the cdr of an element of LIST.\n\
-The value is actually the element of LIST whose cdr is ELT.")
+  "Return non-nil if KEY is `eq' to the cdr of an element of LIST.\n\
+The value is actually the element of LIST whose cdr is KEY.")
   (key, list)
      register Lisp_Object key;
      Lisp_Object list;
 {
-  register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
+  Lisp_Object result;
+
+  while (1)
     {
-      register Lisp_Object elt, tem;
-      elt = Fcar (tail);
-      if (!CONSP (elt)) continue;
-      tem = XCONS (elt)->cdr;
-      if (EQ (key, tem)) return elt;
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && EQ (XCDR (XCAR (list)), key)))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && EQ (XCDR (XCAR (list)), key)))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && EQ (XCDR (XCAR (list)), key)))
+       break;
+
+      list = XCDR (list);
       QUIT;
     }
-  return Qnil;
+
+  if (NILP (list))
+    result = Qnil;
+  else if (CONSP (list))
+    result = XCAR (list);
+  else
+    result = wrong_type_argument (Qlistp, list);
+
+  return result;
 }
 
 DEFUN ("rassoc", Frassoc, Srassoc, 2, 2, 0,
   "Return non-nil if KEY is `equal' to the cdr of an element of LIST.\n\
 The value is actually the element of LIST whose cdr equals KEY.")
   (key, list)
-     register Lisp_Object key;
-     Lisp_Object list;
+     Lisp_Object key, list;
 {
-  register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
+  Lisp_Object result, cdr;
+
+  while (1)
     {
-      register Lisp_Object elt, tem;
-      elt = Fcar (tail);
-      if (!CONSP (elt)) continue;
-      tem = Fequal (XCONS (elt)->cdr, key);
-      if (!NILP (tem)) return elt;
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && (cdr = XCDR (XCAR (list)),
+                 EQ (cdr, key) || !NILP (Fequal (cdr, key)))))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && (cdr = XCDR (XCAR (list)),
+                 EQ (cdr, key) || !NILP (Fequal (cdr, key)))))
+       break;
+
+      list = XCDR (list);
+      if (!CONSP (list)
+         || (CONSP (XCAR (list))
+             && (cdr = XCDR (XCAR (list)),
+                 EQ (cdr, key) || !NILP (Fequal (cdr, key)))))
+       break;
+
+      list = XCDR (list);
       QUIT;
     }
-  return Qnil;
+
+  if (CONSP (list))
+    result = XCAR (list);
+  else if (NILP (list))
+    result = Qnil;
+  else
+    result = wrong_type_argument (Qlistp, list);
+
+  return result;
 }
 \f
 DEFUN ("delq", Fdelq, Sdelq, 2, 2, 0,
@@ -1449,54 +1576,146 @@ to be sure of changing the value of `foo'.")
   prev = Qnil;
   while (!NILP (tail))
     {
-      tem = Fcar (tail);
+      if (! CONSP (tail))
+       wrong_type_argument (Qlistp, list);
+      tem = XCAR (tail);
       if (EQ (elt, tem))
        {
          if (NILP (prev))
-           list = XCONS (tail)->cdr;
+           list = XCDR (tail);
          else
-           Fsetcdr (prev, XCONS (tail)->cdr);
+           Fsetcdr (prev, XCDR (tail));
        }
       else
        prev = tail;
-      tail = XCONS (tail)->cdr;
+      tail = XCDR (tail);
       QUIT;
     }
   return list;
 }
 
 DEFUN ("delete", Fdelete, Sdelete, 2, 2, 0,
-  "Delete by side effect any occurrences of ELT as a member of LIST.\n\
-The modified LIST is returned.  Comparison is done with `equal'.\n\
-If the first member of LIST is ELT, deleting it is not a side effect;\n\
-it is simply using a different list.\n\
+  "Delete by side effect any occurrences of ELT as a member of SEQ.\n\
+SEQ must be a list, a vector, or a string.\n\
+The modified SEQ is returned.  Comparison is done with `equal'.\n\
+If SEQ is not a list, or the first member of SEQ is ELT, deleting it\n\
+is not a side effect; it is simply using a different sequence.\n\
 Therefore, write `(setq foo (delete element foo))'\n\
 to be sure of changing the value of `foo'.")
-  (elt, list)
-     register Lisp_Object elt;
-     Lisp_Object list;
+  (elt, seq)
+     Lisp_Object elt, seq;
 {
-  register Lisp_Object tail, prev;
-  register Lisp_Object tem;
+  if (VECTORP (seq))
+    {
+      EMACS_INT i, n;
 
-  tail = list;
-  prev = Qnil;
-  while (!NILP (tail))
+      for (i = n = 0; i < ASIZE (seq); ++i)
+       if (NILP (Fequal (AREF (seq, i), elt)))
+         ++n;
+
+      if (n != ASIZE (seq))
+       {
+         struct Lisp_Vector *p = allocate_vector (n);
+
+         for (i = n = 0; i < ASIZE (seq); ++i)
+           if (NILP (Fequal (AREF (seq, i), elt)))
+             p->contents[n++] = AREF (seq, i);
+
+         XSETVECTOR (seq, p);
+       }
+    }
+  else if (STRINGP (seq))
     {
-      tem = Fcar (tail);
-      if (! NILP (Fequal (elt, tem)))
+      EMACS_INT i, ibyte, nchars, nbytes, cbytes;
+      int c;
+
+      for (i = nchars = nbytes = ibyte = 0;
+          i < XSTRING (seq)->size;
+          ++i, ibyte += cbytes)
        {
-         if (NILP (prev))
-           list = XCONS (tail)->cdr;
+         if (STRING_MULTIBYTE (seq))
+           {
+             c = STRING_CHAR (&XSTRING (seq)->data[ibyte],
+                              STRING_BYTES (XSTRING (seq)) - ibyte);
+             cbytes = CHAR_BYTES (c);
+           }
          else
-           Fsetcdr (prev, XCONS (tail)->cdr);
+           {
+             c = XSTRING (seq)->data[i];
+             cbytes = 1;
+           }
+
+         if (!INTEGERP (elt) || c != XINT (elt))
+           {
+             ++nchars;
+             nbytes += cbytes;
+           }
+       }
+
+      if (nchars != XSTRING (seq)->size)
+       {
+         Lisp_Object tem;
+
+         tem = make_uninit_multibyte_string (nchars, nbytes);
+         if (!STRING_MULTIBYTE (seq))
+           SET_STRING_BYTES (XSTRING (tem), -1);
+
+         for (i = nchars = nbytes = ibyte = 0;
+              i < XSTRING (seq)->size;
+              ++i, ibyte += cbytes)
+           {
+             if (STRING_MULTIBYTE (seq))
+               {
+                 c = STRING_CHAR (&XSTRING (seq)->data[ibyte],
+                                  STRING_BYTES (XSTRING (seq)) - ibyte);
+                 cbytes = CHAR_BYTES (c);
+               }
+             else
+               {
+                 c = XSTRING (seq)->data[i];
+                 cbytes = 1;
+               }
+
+             if (!INTEGERP (elt) || c != XINT (elt))
+               {
+                 unsigned char *from = &XSTRING (seq)->data[ibyte];
+                 unsigned char *to   = &XSTRING (tem)->data[nbytes];
+                 EMACS_INT n;
+
+                 ++nchars;
+                 nbytes += cbytes;
+
+                 for (n = cbytes; n--; )
+                   *to++ = *from++;
+               }
+           }
+
+         seq = tem;
        }
-      else
-       prev = tail;
-      tail = XCONS (tail)->cdr;
-      QUIT;
     }
-  return list;
+  else
+    {
+      Lisp_Object tail, prev;
+
+      for (tail = seq, prev = Qnil; !NILP (tail); tail = XCDR (tail))
+       {
+         if (!CONSP (tail))
+           wrong_type_argument (Qlistp, seq);
+
+         if (!NILP (Fequal (elt, XCAR (tail))))
+           {
+             if (NILP (prev))
+               seq = XCDR (tail);
+             else
+               Fsetcdr (prev, XCDR (tail));
+           }
+         else
+           prev = tail;
+         QUIT;
+       }
+    }
+
+  return seq;
 }
 
 DEFUN ("nreverse", Fnreverse, Snreverse, 1, 1, 0,
@@ -1513,7 +1732,9 @@ Returns the beginning of the reversed list.")
   while (!NILP (tail))
     {
       QUIT;
-      next = Fcdr (tail);
+      if (! CONSP (tail))
+       wrong_type_argument (Qlistp, list);
+      next = XCDR (tail);
       Fsetcdr (tail, prev);
       prev = tail;
       tail = next;
@@ -1529,8 +1750,8 @@ See also the function `nreverse', which is used more often.")
 {
   Lisp_Object new;
 
-  for (new = Qnil; CONSP (list); list = XCONS (list)->cdr)
-    new = Fcons (XCONS (list)->car, new);
+  for (new = Qnil; CONSP (list); list = XCDR (list))
+    new = Fcons (XCAR (list), new);
   if (!NILP (list))
     wrong_type_argument (Qconsp, list);
   return new;
@@ -1628,8 +1849,8 @@ merge (org_l1, org_l2, pred)
       tail = tem;
     }
 }
-\f
 
+\f
 DEFUN ("plist-get", Fplist_get, Splist_get, 2, 2, 0,
   "Extract a value from a property list.\n\
 PLIST is a property list, which is a list of the form\n\
@@ -1638,16 +1859,26 @@ corresponding to the given PROP, or nil if PROP is not\n\
 one of the properties on the list.")
   (plist, prop)
      Lisp_Object plist;
-     register Lisp_Object prop;
+     Lisp_Object prop;
 {
-  register Lisp_Object tail;
-  for (tail = plist; !NILP (tail); tail = Fcdr (XCONS (tail)->cdr))
+  Lisp_Object tail;
+  
+  for (tail = plist;
+       CONSP (tail) && CONSP (XCDR (tail));
+       tail = XCDR (XCDR (tail)))
     {
-      register Lisp_Object tem;
-      tem = Fcar (tail);
-      if (EQ (prop, tem))
-       return Fcar (XCONS (tail)->cdr);
+      if (EQ (prop, XCAR (tail)))
+       return XCAR (XCDR (tail));
+
+      /* This function can be called asynchronously
+        (setup_coding_system).  Don't QUIT in that case.  */
+      if (!interrupt_input_blocked)
+       QUIT;
     }
+
+  if (!NILP (tail))
+    wrong_type_argument (Qlistp, prop);
+  
   return Qnil;
 }
 
@@ -1677,21 +1908,23 @@ The PLIST is modified by side effects.")
   register Lisp_Object tail, prev;
   Lisp_Object newcell;
   prev = Qnil;
-  for (tail = plist; CONSP (tail) && CONSP (XCONS (tail)->cdr);
-       tail = XCONS (XCONS (tail)->cdr)->cdr)
+  for (tail = plist; CONSP (tail) && CONSP (XCDR (tail));
+       tail = XCDR (XCDR (tail)))
     {
-      if (EQ (prop, XCONS (tail)->car))
+      if (EQ (prop, XCAR (tail)))
        {
-         Fsetcar (XCONS (tail)->cdr, val);
+         Fsetcar (XCDR (tail), val);
          return plist;
        }
+      
       prev = tail;
+      QUIT;
     }
   newcell = Fcons (prop, Fcons (val, Qnil));
   if (NILP (prev))
     return newcell;
   else
-    Fsetcdr (XCONS (prev)->cdr, newcell);
+    Fsetcdr (XCDR (prev), newcell);
   return plist;
 }
 
@@ -1738,16 +1971,14 @@ internal_equal (o1, o2, depth)
 
   switch (XTYPE (o1))
     {
-#ifdef LISP_FLOAT_TYPE
     case Lisp_Float:
       return (extract_float (o1) == extract_float (o2));
-#endif
 
     case Lisp_Cons:
-      if (!internal_equal (XCONS (o1)->car, XCONS (o2)->car, depth + 1))
+      if (!internal_equal (XCAR (o1), XCAR (o2), depth + 1))
        return 0;
-      o1 = XCONS (o1)->cdr;
-      o2 = XCONS (o2)->cdr;
+      o1 = XCDR (o1);
+      o2 = XCDR (o2);
       goto tail_recurse;
 
     case Lisp_Misc:
@@ -1826,7 +2057,13 @@ internal_equal (o1, o2, depth)
                STRING_BYTES (XSTRING (o1))))
        return 0;
       return 1;
+
+    case Lisp_Int:
+    case Lisp_Symbol:
+    case Lisp_Type_Limit:
+      break;
     }
+  
   return 0;
 }
 \f
@@ -1863,8 +2100,8 @@ ARRAY is a vector, string, char-table, or bool-vector.")
       size = XSTRING (array)->size;
       if (STRING_MULTIBYTE (array))
        {
-         unsigned char workbuf[4], *str;
-         int len = CHAR_STRING (charval, workbuf, str);
+         unsigned char str[MAX_MULTIBYTE_LENGTH];
+         int len = CHAR_STRING (charval, str);
          int size_byte = STRING_BYTES (XSTRING (array));
          unsigned char *p1 = p, *endp = p + size_byte;
          int i;
@@ -1993,8 +2230,6 @@ a character set name, or a character code.")
   (char_table, range)
      Lisp_Object char_table, range;
 {
-  int i;
-
   CHECK_CHAR_TABLE (char_table, 0);
 
   if (EQ (range, Qnil))
@@ -2029,6 +2264,7 @@ a character set name, or a character code.")
     }
   else
     error ("Invalid RANGE argument to `char-table-range'");
+  return Qt;
 }
 
 DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range,
@@ -2093,7 +2329,7 @@ See also the documentation of make-char.")
   (char_table, ch, value)
      Lisp_Object char_table, ch, value;
 {
-  int c, i, charset, code1, code2;
+  int c, charset, code1, code2;
   Lisp_Object temp;
 
   CHECK_CHAR_TABLE (char_table, 0);
@@ -2113,7 +2349,7 @@ See also the documentation of make-char.")
 
   /* Even if C is not a generic char, we had better behave as if a
      generic char is specified.  */
-  if (charset == CHARSET_COMPOSITION || CHARSET_DIMENSION (charset) == 1)
+  if (!CHARSET_DEFINED_P (charset) || CHARSET_DIMENSION (charset) == 1)
     code1 = 0;
   temp = XCHAR_TABLE (char_table)->contents[charset + 128];
   if (!code1)
@@ -2124,10 +2360,11 @@ See also the documentation of make-char.")
        XCHAR_TABLE (char_table)->contents[charset + 128] = value;
       return value;
     }
-  char_table = temp;
-  if (! SUB_CHAR_TABLE_P (char_table))
+  if (SUB_CHAR_TABLE_P (temp))
+    char_table = temp;
+  else
     char_table = (XCHAR_TABLE (char_table)->contents[charset + 128]
-           = make_sub_char_table (temp));
+                 = make_sub_char_table (temp));
   temp = XCHAR_TABLE (char_table)->contents[code1];
   if (SUB_CHAR_TABLE_P (temp))
     XCHAR_TABLE (temp)->defalt = value;
@@ -2152,6 +2389,55 @@ char_table_translate (table, ch)
     return ch;
   return XINT (value);
 }
+
+static void
+optimize_sub_char_table (table, chars)
+     Lisp_Object *table;
+     int chars;
+{
+  Lisp_Object elt;
+  int from, to;
+
+  if (chars == 94)
+    from = 33, to = 127;
+  else
+    from = 32, to = 128;
+
+  if (!SUB_CHAR_TABLE_P (*table))
+    return;
+  elt = XCHAR_TABLE (*table)->contents[from++];
+  for (; from < to; from++)
+    if (NILP (Fequal (elt, XCHAR_TABLE (*table)->contents[from])))
+      return;
+  *table = elt;
+}
+
+DEFUN ("optimize-char-table", Foptimize_char_table, Soptimize_char_table,
+       1, 1, 0,
+  "Optimize char table TABLE.")
+  (table)
+     Lisp_Object table;
+{
+  Lisp_Object elt;
+  int dim;
+  int i, j;
+
+  CHECK_CHAR_TABLE (table, 0);
+
+  for (i = CHAR_TABLE_SINGLE_BYTE_SLOTS; i < CHAR_TABLE_ORDINARY_SLOTS; i++)
+    {
+      elt = XCHAR_TABLE (table)->contents[i];
+      if (!SUB_CHAR_TABLE_P (elt))
+       continue;
+      dim = CHARSET_DIMENSION (i - 128);
+      if (dim == 2)
+       for (j = 32; j < SUB_CHAR_TABLE_ORDINARY_SLOTS; j++)
+         optimize_sub_char_table (XCHAR_TABLE (elt)->contents + j, dim);
+      optimize_sub_char_table (XCHAR_TABLE (table)->contents + i, dim);
+    }
+  return Qnil;
+}
+
 \f
 /* Map C_FUNCTION or FUNCTION over SUBTABLE, calling it for each
    character or group of characters that share a value.
@@ -2189,15 +2475,27 @@ map_char_table (c_function, function, subtable, arg, depth, indices)
     }
   else
     {
+      int charset = XFASTINT (indices[0]) - 128;
+
       i = 32;
       to = SUB_CHAR_TABLE_ORDINARY_SLOTS;
+      if (CHARSET_CHARS (charset) == 94)
+       i++, to--;
     }
 
   for (; i < to; i++)
     {
-      Lisp_Object elt = XCHAR_TABLE (subtable)->contents[i];
+      Lisp_Object elt;
+      int charset;
 
+      elt = XCHAR_TABLE (subtable)->contents[i];
       XSETFASTINT (indices[depth], i);
+      charset = XFASTINT (indices[0]) - 128;
+      if (depth == 0
+         && (!CHARSET_DEFINED_P (charset)
+             || charset == CHARSET_8_BIT_CONTROL
+             || charset == CHARSET_8_BIT_GRAPHIC))
+       continue;
 
       if (SUB_CHAR_TABLE_P (elt))
        {
@@ -2207,18 +2505,17 @@ map_char_table (c_function, function, subtable, arg, depth, indices)
        }
       else
        {
-         int charset = XFASTINT (indices[0]) - 128, c1, c2, c;
+         int c1, c2, c;
 
-         if (CHARSET_DEFINED_P (charset))
-           {
-             c1 = depth >= 1 ? XFASTINT (indices[1]) : 0;
-             c2 = depth >= 2 ? XFASTINT (indices[2]) : 0;
-             c = MAKE_NON_ASCII_CHAR (charset, c1, c2);
-             if (c_function)
-               (*c_function) (arg, make_number (c), elt);
-             else
-               call2 (function, make_number (c), elt);
-           }
+         if (NILP (elt))
+           elt = XCHAR_TABLE (subtable)->defalt;
+         c1 = depth >= 1 ? XFASTINT (indices[1]) : 0;
+         c2 = depth >= 2 ? XFASTINT (indices[2]) : 0;
+         c = MAKE_CHAR (charset, c1, c2);
+         if (c_function)
+           (*c_function) (arg, make_number (c), elt);
+         else
+           call2 (function, make_number (c), elt);
        }
     }
 }
@@ -2239,6 +2536,41 @@ The key is always a possible IDX argument to `aref'.")
   map_char_table (NULL, function, char_table, char_table, 0, indices);
   return Qnil;
 }
+
+/* Return a value for character C in char-table TABLE.  Store the
+   actual index for that value in *IDX.  Ignore the default value of
+   TABLE.  */
+
+Lisp_Object
+char_table_ref_and_index (table, c, idx)
+     Lisp_Object table;
+     int c, *idx;
+{
+  int charset, c1, c2;
+  Lisp_Object elt;
+
+  if (SINGLE_BYTE_CHAR_P (c))
+    {
+      *idx = c;
+      return XCHAR_TABLE (table)->contents[c];
+    }
+  SPLIT_CHAR (c, charset, c1, c2);
+  elt = XCHAR_TABLE (table)->contents[charset + 128];
+  *idx = MAKE_CHAR (charset, 0, 0);
+  if (!SUB_CHAR_TABLE_P (elt))
+    return elt;
+  if (c1 < 32 || NILP (XCHAR_TABLE (elt)->contents[c1]))
+    return XCHAR_TABLE (elt)->defalt;
+  elt = XCHAR_TABLE (elt)->contents[c1];
+  *idx = MAKE_CHAR (charset, c1, 0);
+  if (!SUB_CHAR_TABLE_P (elt))
+    return elt;
+  if (c2 < 32 || NILP (XCHAR_TABLE (elt)->contents[c2]))
+    return XCHAR_TABLE (elt)->defalt;
+  *idx = c;
+  return XCHAR_TABLE (elt)->contents[c2];
+}
+
 \f
 /* ARGSUSED */
 Lisp_Object
@@ -2265,7 +2597,7 @@ Only the last argument is not altered, and need not be a list.")
   register int argnum;
   register Lisp_Object tail, tem, val;
 
-  val = Qnil;
+  val = tail = Qnil;
 
   for (argnum = 0; argnum < nargs; argnum++)
     {
@@ -2312,13 +2644,18 @@ mapcar1 (leni, vals, fn, seq)
   register int i;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
-  /* Don't let vals contain any garbage when GC happens.  */
-  for (i = 0; i < leni; i++)
-    vals[i] = Qnil;
+  if (vals)
+    {
+      /* Don't let vals contain any garbage when GC happens.  */
+      for (i = 0; i < leni; i++)
+       vals[i] = Qnil;
 
-  GCPRO3 (dummy, fn, seq);
-  gcpro1.var = vals;
-  gcpro1.nvars = leni;
+      GCPRO3 (dummy, fn, seq);
+      gcpro1.var = vals;
+      gcpro1.nvars = leni;
+    }
+  else
+    GCPRO2 (fn, seq);
   /* We need not explicitly protect `tail' because it is used only on lists, and
     1) lists are not relocated and 2) the list is marked via `seq' so will not be freed */
 
@@ -2327,7 +2664,9 @@ mapcar1 (leni, vals, fn, seq)
       for (i = 0; i < leni; i++)
        {
          dummy = XVECTOR (seq)->contents[i];
-         vals[i] = call1 (fn, dummy);
+         dummy = call1 (fn, dummy);
+         if (vals)
+           vals[i] = dummy;
        }
     }
   else if (BOOL_VECTOR_P (seq))
@@ -2341,22 +2680,13 @@ mapcar1 (leni, vals, fn, seq)
          else
            dummy = Qnil;
 
-         vals[i] = call1 (fn, dummy);
-       }
-    }
-  else if (STRINGP (seq) && ! STRING_MULTIBYTE (seq))
-    {
-      /* Single-byte string.  */
-      for (i = 0; i < leni; i++)
-       {
-         XSETFASTINT (dummy, XSTRING (seq)->data[i]);
-         vals[i] = call1 (fn, dummy);
+         dummy = call1 (fn, dummy);
+         if (vals)
+           vals[i] = dummy;
        }
     }
   else if (STRINGP (seq))
     {
-      /* Multi-byte string.  */
-      int len_byte = STRING_BYTES (XSTRING (seq));
       int i_byte;
 
       for (i = 0, i_byte = 0; i < leni;)
@@ -2366,7 +2696,9 @@ mapcar1 (leni, vals, fn, seq)
 
          FETCH_STRING_CHAR_ADVANCE (c, seq, i, i_byte);
          XSETFASTINT (dummy, c);
-         vals[i_before] = call1 (fn, dummy);
+         dummy = call1 (fn, dummy);
+         if (vals)
+           vals[i_before] = dummy;
        }
     }
   else   /* Must be a list, since Flength did not get an error */
@@ -2374,8 +2706,10 @@ mapcar1 (leni, vals, fn, seq)
       tail = seq;
       for (i = 0; i < leni; i++)
        {
-         vals[i] = call1 (fn, Fcar (tail));
-         tail = XCONS (tail)->cdr;
+         dummy = call1 (fn, Fcar (tail));
+         if (vals)
+           vals[i] = dummy;
+         tail = XCDR (tail);
        }
     }
 
@@ -2436,6 +2770,21 @@ SEQUENCE may be a list, a vector, a bool-vector, or a string.")
 
   return Flist (leni, args);
 }
+
+DEFUN ("mapc", Fmapc, Smapc, 2, 2, 0,
+  "Apply FUNCTION to each element of SEQUENCE for side effects only.\n\
+Unlike `mapcar', don't accumulate the results.  Return SEQUENCE.\n\
+SEQUENCE may be a list, a vector, a bool-vector, or a string.")
+  (function, sequence)
+     Lisp_Object function, sequence;
+{
+  register int leni;
+
+  leni = XFASTINT (Flength (sequence));
+  mapcar1 (leni, 0, function, sequence);
+
+  return sequence;
+}
 \f
 /* Anything that calls this function must protect from GC!  */
 
@@ -2445,12 +2794,12 @@ Takes one argument, which is the string to display to ask the question.\n\
 It should end in a space; `y-or-n-p' adds `(y or n) ' to it.\n\
 No confirmation of the answer is requested; a single character is enough.\n\
 Also accepts Space to mean yes, or Delete to mean no.  \(Actually, it uses\n\
-the bindings in query-replace-map; see the documentation of that variable\n\
+the bindings in `query-replace-map'; see the documentation of that variable\n\
 for more information.  In this case, the useful bindings are `act', `skip',\n\
 `recenter', and `quit'.\)\n\
 \n\
 Under a windowing system a dialog box will be used if `last-nonmenu-event'\n\
-is nil.")
+is nil and `use-dialog-box' is non-nil.")
   (prompt)
      Lisp_Object prompt;
 {
@@ -2469,6 +2818,11 @@ is nil.")
   xprompt = prompt;
   GCPRO2 (prompt, xprompt);
 
+#ifdef HAVE_X_WINDOWS
+  if (display_hourglass_p)
+    cancel_hourglass ();
+#endif
+
   while (1)
     {
 
@@ -2478,7 +2832,7 @@ is nil.")
          && have_menus_p ())
        {
          Lisp_Object pane, menu;
-         redisplay_preserve_echo_area ();
+         redisplay_preserve_echo_area (3);
          pane = Fcons (Fcons (build_string ("Yes"), Qt),
                        Fcons (Fcons (build_string ("No"), Qnil),
                               Qnil));
@@ -2582,14 +2936,13 @@ The user must confirm the answer with RET,\n\
 and can edit it until it has been confirmed.\n\
 \n\
 Under a windowing system a dialog box will be used if `last-nonmenu-event'\n\
-is nil.")
+is nil, and `use-dialog-box' is non-nil.")
   (prompt)
      Lisp_Object prompt;
 {
   register Lisp_Object ans;
   Lisp_Object args[2];
   struct gcpro gcpro1;
-  Lisp_Object menu;
 
   CHECK_STRING (prompt, 0);
 
@@ -2599,7 +2952,7 @@ is nil.")
       && have_menus_p ())
     {
       Lisp_Object pane, menu, obj;
-      redisplay_preserve_echo_area ();
+      redisplay_preserve_echo_area (4);
       pane = Fcons (Fcons (build_string ("Yes"), Qt),
                    Fcons (Fcons (build_string ("No"), Qnil),
                           Qnil));
@@ -2707,17 +3060,21 @@ DEFUN ("require", Frequire, Srequire, 1, 3, 0,
 If FEATURE is not a member of the list `features', then the feature\n\
 is not loaded; so load the file FILENAME.\n\
 If FILENAME is omitted, the printname of FEATURE is used as the file name,\n\
-but in this case `load' insists on adding the suffix `.el' or `.elc'.\n\
+and `load' will try to load this name appended with the suffix `.elc',\n\
+`.el' or the unmodified name, in that order.\n\
 If the optional third argument NOERROR is non-nil,\n\
-then return nil if the file is not found.\n\
-Normally the return value is FEATURE.")
-  (feature, file_name, noerror)
-     Lisp_Object feature, file_name, noerror;
+then return nil if the file is not found instead of signaling an error.\n\
+Normally the return value is FEATURE.\n\
+The normal messages at start and end of loading FILENAME are suppressed.")
+  (feature, filename, noerror)
+     Lisp_Object feature, filename, noerror;
 {
   register Lisp_Object tem;
   CHECK_SYMBOL (feature, 0);
   tem = Fmemq (feature, Vfeatures);
+
   LOADHIST_ATTACH (Fcons (Qrequire, feature));
+  
   if (NILP (tem))
     {
       int count = specpdl_ptr - specpdl;
@@ -2726,8 +3083,8 @@ Normally the return value is FEATURE.")
       record_unwind_protect (un_autoload, Vautoload_queue);
       Vautoload_queue = Qt;
 
-      tem = Fload (NILP (file_name) ? Fsymbol_name (feature) : file_name,
-                    noerror, Qt, Qnil, (NILP (file_name) ? Qt : Qnil));
+      tem = Fload (NILP (filename) ? Fsymbol_name (feature) : filename,
+                  noerror, Qt, Qnil, (NILP (filename) ? Qt : Qnil));
       /* If load failed entirely, return nil.  */
       if (NILP (tem))
        return unbind_to (count, Qnil);
@@ -2751,7 +3108,7 @@ Normally the return value is FEATURE.")
    bottleneck of Widget operation.  Here is their translation to C,
    for the sole reason of efficiency.  */
 
-DEFUN ("widget-plist-member", Fwidget_plist_member, Swidget_plist_member, 2, 2, 0,
+DEFUN ("plist-member", Fplist_member, Splist_member, 2, 2, 0,
   "Return non-nil if PLIST has the property PROP.\n\
 PLIST is a property list, which is a list of the form\n\
 \(PROP1 VALUE1 PROP2 VALUE2 ...\).  PROP is a symbol.\n\
@@ -2795,7 +3152,7 @@ later with `widget-put'.")
       if (NILP (widget))
        return Qnil;
       CHECK_CONS (widget, 1);
-      tmp = Fwidget_plist_member (XCDR (widget), property);
+      tmp = Fplist_member (XCDR (widget), property);
       if (CONSP (tmp))
        {
          tmp = XCDR (tmp);
@@ -2829,7 +3186,7 @@ ARGS are passed as extra arguments to the function.")
   return result;
 }
 \f
-/* base64 encode/decode functions.
+/* base64 encode/decode functions (RFC 2045).
    Based on code from GNU recode. */
 
 #define MIME_LINE_LENGTH 76
@@ -2845,13 +3202,17 @@ ARGS are passed as extra arguments to the function.")
 /* Used by base64_decode_1 to retrieve a non-base64-ignorable
    character or return retval if there are no characters left to
    process. */
-#define READ_QUADRUPLET_BYTE(retval) \
-  do \
-    { \
-      if (i == length) \
-        return (retval); \
-      c = from[i++]; \
-    } \
+#define READ_QUADRUPLET_BYTE(retval)   \
+  do                                   \
+    {                                  \
+      if (i == length)                 \
+       {                               \
+         if (nchars_return)            \
+           *nchars_return = nchars;    \
+         return (retval);              \
+       }                               \
+      c = from[i++];                   \
+    }                                  \
   while (IS_BASE64_IGNORABLE (c))
 
 /* Don't use alloca for regions larger than this, lest we overflow
@@ -2907,8 +3268,8 @@ static short base64_char_to_value[128] =
    base64 characters.  */
 
 
-static int base64_encode_1 P_ ((const char *, char *, int, int));
-static int base64_decode_1 P_ ((const char *, char *, int));
+static int base64_encode_1 P_ ((const char *, char *, int, int, int));
+static int base64_decode_1 P_ ((const char *, char *, int, int, int *));
 
 DEFUN ("base64-encode-region", Fbase64_encode_region, Sbase64_encode_region,
        2, 3, "r",
@@ -2942,10 +3303,19 @@ into shorter lines.")
   else
     encoded = (char *) xmalloc (allength);
   encoded_length = base64_encode_1 (BYTE_POS_ADDR (ibeg), encoded, length,
-                                   NILP (no_line_break));
+                                   NILP (no_line_break),
+                                   !NILP (current_buffer->enable_multibyte_characters));
   if (encoded_length > allength)
     abort ();
 
+  if (encoded_length < 0)
+    {
+      /* The encoding wasn't possible. */
+      if (length > MAX_ALLOCA)
+       xfree (encoded);
+      error ("Multibyte character in data for base64 encoding");
+    }
+
   /* Now we have encoded the region, so we insert the new contents
      and delete the old.  (Insert first in order to preserve markers.)  */
   SET_PT_BOTH (XFASTINT (beg), ibeg);
@@ -2994,10 +3364,19 @@ into shorter lines.")
     encoded = (char *) xmalloc (allength);
 
   encoded_length = base64_encode_1 (XSTRING (string)->data,
-                                   encoded, length, NILP (no_line_break));
+                                   encoded, length, NILP (no_line_break),
+                                   STRING_MULTIBYTE (string));
   if (encoded_length > allength)
     abort ();
 
+  if (encoded_length < 0)
+    {
+      /* The encoding wasn't possible. */
+      if (length > MAX_ALLOCA)
+       xfree (encoded);
+      error ("Multibyte character in data for base64 encoding");
+    }
+
   encoded_string = make_unibyte_string (encoded, encoded_length);
   if (allength > MAX_ALLOCA)
     xfree (encoded);
@@ -3006,20 +3385,30 @@ into shorter lines.")
 }
 
 static int
-base64_encode_1 (from, to, length, line_break)
+base64_encode_1 (from, to, length, line_break, multibyte)
      const char *from;
      char *to;
      int length;
      int line_break;
+     int multibyte;
 {
   int counter = 0, i = 0;
   char *e = to;
-  unsigned char c;
+  int c;
   unsigned int value;
+  int bytes;
 
   while (i < length)
     {
-      c = from[i++];
+      if (multibyte)
+       {
+         c = STRING_CHAR_AND_LENGTH (from + i, length - i, bytes);
+         if (c >= 256)
+           return -1;
+         i += bytes;
+       }
+      else
+       c = from[i++];
 
       /* Wrap line every 76 characters.  */
 
@@ -3049,7 +3438,15 @@ base64_encode_1 (from, to, length, line_break)
          break;
        }
 
-      c = from[i++];
+      if (multibyte)
+       {
+         c = STRING_CHAR_AND_LENGTH (from + i, length - i, bytes);
+         if (c >= 256)
+           return -1;
+         i += bytes;
+       }
+      else
+       c = from[i++];
 
       *e++ = base64_value_to_char[value | (0x0f & c >> 4)];
       value = (0x0f & c) << 2;
@@ -3063,7 +3460,15 @@ base64_encode_1 (from, to, length, line_break)
          break;
        }
 
-      c = from[i++];
+      if (multibyte)
+       {
+         c = STRING_CHAR_AND_LENGTH (from + i, length - i, bytes);
+         if (c >= 256)
+           return -1;
+         i += bytes;
+       }
+      else
+       c = from[i++];
 
       *e++ = base64_value_to_char[value | (0x03 & c >> 6)];
       *e++ = base64_value_to_char[0x3f & c];
@@ -3077,15 +3482,16 @@ DEFUN ("base64-decode-region", Fbase64_decode_region, Sbase64_decode_region,
   2, 2, "r",
   "Base64-decode the region between BEG and END.\n\
 Return the length of the decoded text.\n\
-If the region can't be decoded, return nil and don't modify the buffer.")
+If the region can't be decoded, signal an error and don't modify the buffer.")
      (beg, end)
      Lisp_Object beg, end;
 {
-  int ibeg, iend, length;
+  int ibeg, iend, length, allength;
   char *decoded;
   int old_pos = PT;
   int decoded_length;
   int inserted_chars;
+  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
 
   validate_region (&beg, &end);
 
@@ -3093,46 +3499,39 @@ If the region can't be decoded, return nil and don't modify the buffer.")
   iend = CHAR_TO_BYTE (XFASTINT (end));
 
   length = iend - ibeg;
-  /* We need to allocate enough room for decoding the text. */
-  if (length <= MAX_ALLOCA)
-    decoded = (char *) alloca (length);
+
+  /* We need to allocate enough room for decoding the text.  If we are
+     working on a multibyte buffer, each decoded code may occupy at
+     most two bytes.  */
+  allength = multibyte ? length * 2 : length;
+  if (allength <= MAX_ALLOCA)
+    decoded = (char *) alloca (allength);
   else
-    decoded = (char *) xmalloc (length);
+    decoded = (char *) xmalloc (allength);
 
   move_gap_both (XFASTINT (beg), ibeg);
-  decoded_length = base64_decode_1 (BYTE_POS_ADDR (ibeg), decoded, length);
-  if (decoded_length > length)
+  decoded_length = base64_decode_1 (BYTE_POS_ADDR (ibeg), decoded, length,
+                                   multibyte, &inserted_chars);
+  if (decoded_length > allength)
     abort ();
 
   if (decoded_length < 0)
     {
       /* The decoding wasn't possible. */
-      if (length > MAX_ALLOCA)
+      if (allength > MAX_ALLOCA)
        xfree (decoded);
-      return Qnil;
+      error ("Invalid base64 data");
     }
 
   /* Now we have decoded the region, so we insert the new contents
      and delete the old.  (Insert first in order to preserve markers.)  */
-  /* We insert two spaces, then insert the decoded text in between
-     them, at last, delete those extra two spaces.  This is to avoid
-     byte combining while inserting.  */
   TEMP_SET_PT_BOTH (XFASTINT (beg), ibeg);
-  insert_1_both ("  ", 2, 2, 0, 1, 0);
-  TEMP_SET_PT_BOTH (XFASTINT (beg) + 1, ibeg + 1);  
-  insert (decoded, decoded_length);
-  inserted_chars = PT - (XFASTINT (beg) + 1);
-  if (length > MAX_ALLOCA)
+  insert_1_both (decoded, inserted_chars, decoded_length, 0, 1, 0);
+  if (allength > MAX_ALLOCA)
     xfree (decoded);
-  /* At first delete the original text.  This never cause byte
-     combining.  */
-  del_range_both (PT + 1, PT_BYTE + 1, XFASTINT (end) + inserted_chars + 2,
-                 iend + decoded_length + 2, 1);
-  /* Next delete the extra spaces.  This will cause byte combining
-     error.  */
-  del_range_both (PT, PT_BYTE, PT + 1, PT_BYTE + 1, 0);
-  del_range_both (XFASTINT (beg), ibeg, XFASTINT (beg) + 1, ibeg + 1, 0);
-  inserted_chars = PT - XFASTINT (beg);
+  /* Delete the original text.  */
+  del_range_both (PT, PT_BYTE, XFASTINT (end) + inserted_chars,
+                 iend + decoded_length, 1);
 
   /* If point was outside of the region, restore it exactly; else just
      move to the beginning of the region.  */
@@ -3147,8 +3546,8 @@ If the region can't be decoded, return nil and don't modify the buffer.")
 
 DEFUN ("base64-decode-string", Fbase64_decode_string, Sbase64_decode_string,
        1, 1, 0,
-       "Base64-decode STRING and return the result.")
-     (string)
+  "Base64-decode STRING and return the result.")
+  (string)
      Lisp_Object string;
 {
   char *decoded;
@@ -3164,32 +3563,42 @@ DEFUN ("base64-decode-string", Fbase64_decode_string, Sbase64_decode_string,
   else
     decoded = (char *) xmalloc (length);
 
-  decoded_length = base64_decode_1 (XSTRING (string)->data, decoded, length);
+  /* The decoded result should be unibyte. */
+  decoded_length = base64_decode_1 (XSTRING (string)->data, decoded, length,
+                                   0, NULL);
   if (decoded_length > length)
     abort ();
-
-  if (decoded_length < 0)
-    /* The decoding wasn't possible. */
-    decoded_string = Qnil;
+  else if (decoded_length >= 0)
+    decoded_string = make_unibyte_string (decoded, decoded_length);
   else
-    decoded_string = make_string (decoded, decoded_length);
+    decoded_string = Qnil;
 
   if (length > MAX_ALLOCA)
     xfree (decoded);
+  if (!STRINGP (decoded_string))
+    error ("Invalid base64 data");
 
   return decoded_string;
 }
 
+/* Base64-decode the data at FROM of LENGHT bytes into TO.  If
+   MULTIBYTE is nonzero, the decoded result should be in multibyte
+   form.  If NCHARS_RETRUN is not NULL, store the number of produced
+   characters in *NCHARS_RETURN.  */
+
 static int
-base64_decode_1 (from, to, length)
+base64_decode_1 (from, to, length, multibyte, nchars_return)
      const char *from;
      char *to;
      int length;
+     int multibyte;
+     int *nchars_return;
 {
   int i = 0;
   char *e = to;
   unsigned char c;
   unsigned long value;
+  int nchars = 0;
 
   while (1)
     {
@@ -3209,16 +3618,21 @@ base64_decode_1 (from, to, length)
        return -1;
       value |= base64_char_to_value[c] << 12;
 
-      *e++ = (unsigned char) (value >> 16);
+      c = (unsigned char) (value >> 16);
+      if (multibyte)
+       e += CHAR_STRING (c, e);
+      else
+       *e++ = c;
+      nchars++;
 
       /* Process third byte of a quadruplet.  */
-      
+
       READ_QUADRUPLET_BYTE (-1);
 
       if (c == '=')
        {
          READ_QUADRUPLET_BYTE (-1);
-         
+
          if (c != '=')
            return -1;
          continue;
@@ -3228,7 +3642,12 @@ base64_decode_1 (from, to, length)
        return -1;
       value |= base64_char_to_value[c] << 6;
 
-      *e++ = (unsigned char) (0xff & value >> 8);
+      c = (unsigned char) (0xff & value >> 8);
+      if (multibyte)
+       e += CHAR_STRING (c, e);
+      else
+       *e++ = c;
+      nchars++;
 
       /* Process fourth byte of a quadruplet.  */
 
@@ -3241,7 +3660,12 @@ base64_decode_1 (from, to, length)
        return -1;
       value |= base64_char_to_value[c];
 
-      *e++ = (unsigned char) (0xff & value);
+      c = (unsigned char) (0xff & value);
+      if (multibyte)
+       e += CHAR_STRING (c, e);
+      else
+       *e++ = c;
+      nchars++;
     }
 }
 
@@ -3268,10 +3692,6 @@ base64_decode_1 (from, to, length)
    if a `:linear-search t' argument is given to make-hash-table.  */
 
 
-/* Return the contents of vector V at index IDX.  */
-
-#define AREF(V, IDX)       XVECTOR (V)->contents[IDX]
-
 /* Value is the key part of entry IDX in hash table H.  */
 
 #define HASH_KEY(H, IDX)   AREF ((H)->key_and_value, 2 * (IDX))
@@ -3306,14 +3726,12 @@ Lisp_Object Vweak_hash_tables;
 
 Lisp_Object Qhash_table_p, Qeq, Qeql, Qequal, Qkey, Qvalue;
 Lisp_Object QCtest, QCsize, QCrehash_size, QCrehash_threshold, QCweakness;
-Lisp_Object Qhash_table_test;
+Lisp_Object Qhash_table_test, Qkey_or_value, Qkey_and_value;
 
 /* Function prototypes.  */
 
 static struct Lisp_Hash_Table *check_hash_table P_ ((Lisp_Object));
-static int next_almost_prime P_ ((int));
 static int get_key_arg P_ ((Lisp_Object, int, Lisp_Object *, char *));
-static Lisp_Object larger_vector P_ ((Lisp_Object, int, Lisp_Object));
 static void maybe_resize_hash_table P_ ((struct Lisp_Hash_Table *));
 static int cmpfn_eql P_ ((struct Lisp_Hash_Table *, Lisp_Object, unsigned,
                          Lisp_Object, unsigned));
@@ -3330,6 +3748,7 @@ static unsigned sxhash_string P_ ((unsigned char *, int));
 static unsigned sxhash_list P_ ((Lisp_Object, int));
 static unsigned sxhash_vector P_ ((Lisp_Object, int));
 static unsigned sxhash_bool_vector P_ ((Lisp_Object));
+static int sweep_weak_table P_ ((struct Lisp_Hash_Table *, int));
 
 
 \f
@@ -3352,7 +3771,7 @@ check_hash_table (obj)
 /* Value is the next integer I >= N, N >= 0 which is "almost" a prime
    number.  */
 
-static int
+int
 next_almost_prime (n)
      int n;
 {
@@ -3380,11 +3799,11 @@ get_key_arg (key, nargs, args, used)
      char *used;
 {
   int i;
-  
+
   for (i = 0; i < nargs - 1; ++i)
     if (!used[i] && EQ (args[i], key))
       break;
-  
+
   if (i >= nargs - 1)
     i = -1;
   else
@@ -3392,7 +3811,7 @@ get_key_arg (key, nargs, args, used)
       used[i++] = 1;
       used[i] = 1;
     }
-  
+
   return i;
 }
 
@@ -3401,7 +3820,7 @@ get_key_arg (key, nargs, args, used)
    size NEW_SIZE, NEW_SIZE >= VEC->size.  Entries in the resulting
    vector that are not copied from VEC are set to INIT.  */
 
-static Lisp_Object
+Lisp_Object
 larger_vector (vec, new_size, init)
      Lisp_Object vec;
      int new_size;
@@ -3414,8 +3833,7 @@ larger_vector (vec, new_size, init)
   old_size = XVECTOR (vec)->size;
   xassert (new_size >= old_size);
 
-  v = allocate_vectorlike (new_size);
-  v->size = new_size;
+  v = allocate_vector (new_size);
   bcopy (XVECTOR (vec)->contents, v->contents,
         old_size * sizeof *v->contents);
   for (i = old_size; i < new_size; ++i)
@@ -3458,7 +3876,7 @@ cmpfn_equal (h, key1, hash1, key2, hash2)
   return hash1 == hash2 && !NILP (Fequal (key1, key2));
 }
 
-  
+
 /* Compare KEY1 which has hash code HASH1, and KEY2 with hash code
    HASH2 in hash table H using H->user_cmp_function.  Value is non-zero
    if KEY1 and KEY2 are the same.  */
@@ -3472,7 +3890,7 @@ cmpfn_user_defined (h, key1, hash1, key2, hash2)
   if (hash1 == hash2)
     {
       Lisp_Object args[3];
-  
+
       args[0] = h->user_cmp_function;
       args[1] = key1;
       args[2] = key2;
@@ -3492,12 +3910,9 @@ hashfn_eq (h, key)
      struct Lisp_Hash_Table *h;
      Lisp_Object key;
 {
-  /* Lisp strings can change their address.  Don't try to compute a
-     hash code for a string from its address.  */
-  if (STRINGP (key))
-    return sxhash_string (XSTRING (key)->data, XSTRING (key)->size);
-  else
-    return XUINT (key) ^ XGCTYPE (key);
+  unsigned hash = XUINT (key) ^ XGCTYPE (key);
+  xassert ((hash & ~VALMASK) == 0);
+  return hash;
 }
 
 
@@ -3510,14 +3925,13 @@ hashfn_eql (h, key)
      struct Lisp_Hash_Table *h;
      Lisp_Object key;
 {
-  /* Lisp strings can change their address.  Don't try to compute a
-     hash code for a string from its address.  */
-  if (STRINGP (key))
-    return sxhash_string (XSTRING (key)->data, XSTRING (key)->size);
-  else if (FLOATP (key))
-    return sxhash (key, 0);
+  unsigned hash;
+  if (FLOATP (key))
+    hash = sxhash (key, 0);
   else
-    return XUINT (key) ^ XGCTYPE (key);
+    hash = XUINT (key) ^ XGCTYPE (key);
+  xassert ((hash & ~VALMASK) == 0);
+  return hash;
 }
 
 
@@ -3530,7 +3944,9 @@ hashfn_equal (h, key)
      struct Lisp_Hash_Table *h;
      Lisp_Object key;
 {
-  return sxhash (key, 0);
+  unsigned hash = sxhash (key, 0);
+  xassert ((hash & ~VALMASK) == 0);
+  return hash;
 }
 
 
@@ -3544,13 +3960,13 @@ hashfn_user_defined (h, key)
      Lisp_Object key;
 {
   Lisp_Object args[2], hash;
-  
+
   args[0] = h->user_hash_function;
   args[1] = key;
   hash = Ffuncall (2, args);
   if (!INTEGERP (hash))
     Fsignal (Qerror,
-            list2 (build_string ("Illegal hash code returned from \
+            list2 (build_string ("Invalid hash code returned from \
 user-supplied hash function"),
                    hash));
   return XUINT (hash);
@@ -3563,8 +3979,8 @@ user-supplied hash function"),
    It must be either one of the predefined tests `eq', `eql' or
    `equal' or a symbol denoting a user-defined test named TEST with
    test and hash functions USER_TEST and USER_HASH.
-   
-   Give the table initial capacity SIZE, SIZE > 0, an integer.
+
+   Give the table initial capacity SIZE, SIZE >= 0, an integer.
 
    If REHASH_SIZE is an integer, it must be > 0, and this hash table's
    new size when it becomes full is computed by adding REHASH_SIZE to
@@ -3577,7 +3993,7 @@ user-supplied hash function"),
    (table size) is >= REHASH_THRESHOLD.
 
    WEAK specifies the weakness of the table.  If non-nil, it must be
-   one of the symbols `key', `value' or t.  */
+   one of the symbols `key', `value', `key-or-value', or `key-and-value'.  */
 
 Lisp_Object
 make_hash_table (test, size, rehash_size, rehash_threshold, weak,
@@ -3586,30 +4002,27 @@ make_hash_table (test, size, rehash_size, rehash_threshold, weak,
      Lisp_Object user_test, user_hash;
 {
   struct Lisp_Hash_Table *h;
-  struct Lisp_Vector *v;
   Lisp_Object table;
-  int index_size, i, len, sz;
+  int index_size, i, sz;
 
   /* Preconditions.  */
   xassert (SYMBOLP (test));
-  xassert (INTEGERP (size) && XINT (size) > 0);
+  xassert (INTEGERP (size) && XINT (size) >= 0);
   xassert ((INTEGERP (rehash_size) && XINT (rehash_size) > 0)
           || (FLOATP (rehash_size) && XFLOATINT (rehash_size) > 1.0));
   xassert (FLOATP (rehash_threshold)
           && XFLOATINT (rehash_threshold) > 0
           && XFLOATINT (rehash_threshold) <= 1.0);
 
-  /* Allocate a vector, and initialize it.  */
-  len = VECSIZE (struct Lisp_Hash_Table);
-  v = allocate_vectorlike (len);
-  v->size = len;
-  for (i = 0; i < len; ++i)
-    v->contents[i] = Qnil;
+  if (XFASTINT (size) == 0)
+    size = make_number (1);
+
+  /* Allocate a table and initialize it.  */
+  h = allocate_hash_table ();
 
   /* Initialize hash table slots.  */
   sz = XFASTINT (size);
-  h = (struct Lisp_Hash_Table *) v;
-  
+
   h->test = test;
   if (EQ (test, Qeql))
     {
@@ -3633,7 +4046,7 @@ make_hash_table (test, size, rehash_size, rehash_threshold, weak,
       h->cmpfn = cmpfn_user_defined;
       h->hashfn = hashfn_user_defined;
     }
-  
+
   h->weak = weak;
   h->rehash_threshold = rehash_threshold;
   h->rehash_size = rehash_size;
@@ -3641,7 +4054,8 @@ make_hash_table (test, size, rehash_size, rehash_threshold, weak,
   h->key_and_value = Fmake_vector (make_number (2 * sz), Qnil);
   h->hash = Fmake_vector (size, Qnil);
   h->next = Fmake_vector (size, Qnil);
-  index_size = next_almost_prime (sz / XFLOATINT (rehash_threshold));
+  /* Cast to int here avoids losing with gcc 2.95 on Tru64/Alpha...  */
+  index_size = next_almost_prime ((int) (sz / XFLOATINT (rehash_threshold)));
   h->index = Fmake_vector (make_number (index_size), Qnil);
 
   /* Set up the free list.  */
@@ -3676,11 +4090,8 @@ copy_hash_table (h1)
   Lisp_Object table;
   struct Lisp_Hash_Table *h2;
   struct Lisp_Vector *v, *next;
-  int len;
-  
-  len = VECSIZE (struct Lisp_Hash_Table);
-  v = allocate_vectorlike (len);
-  h2 = (struct Lisp_Hash_Table *) v;
+
+  h2 = allocate_hash_table ();
   next = h2->vec_next;
   bcopy (h1, h2, sizeof *h2);
   h2->vec_next = next;
@@ -3712,13 +4123,15 @@ maybe_resize_hash_table (h)
     {
       int old_size = HASH_TABLE_SIZE (h);
       int i, new_size, index_size;
+
       if (INTEGERP (h->rehash_size))
        new_size = old_size + XFASTINT (h->rehash_size);
       else
        new_size = old_size * XFLOATINT (h->rehash_size);
-      index_size = next_almost_prime (new_size
-                                     / XFLOATINT (h->rehash_threshold));
+      new_size = max (old_size + 1, new_size);
+      index_size = next_almost_prime ((int)
+                                     (new_size
+                                      / XFLOATINT (h->rehash_threshold)));
       if (max (index_size, 2 * new_size) & ~VALMASK)
        error ("Hash table too large to resize");
 
@@ -3732,16 +4145,16 @@ maybe_resize_hash_table (h)
          maphash faster.  */
       for (i = old_size; i < new_size - 1; ++i)
        HASH_NEXT (h, i) = make_number (i + 1);
-      
+
       if (!NILP (h->next_free))
        {
          Lisp_Object last, next;
-         
+
          last = h->next_free;
          while (next = HASH_NEXT (h, XFASTINT (last)),
                 !NILP (next))
            last = next;
-         
+
          HASH_NEXT (h, XFASTINT (last)) = make_number (old_size);
        }
       else
@@ -3756,7 +4169,7 @@ maybe_resize_hash_table (h)
            HASH_NEXT (h, i) = HASH_INDEX (h, start_of_bucket);
            HASH_INDEX (h, start_of_bucket) = make_number (i);
          }
-    }  
+    }
 }
 
 
@@ -3777,17 +4190,18 @@ hash_lookup (h, key, hash)
   hash_code = h->hashfn (h, key);
   if (hash)
     *hash = hash_code;
-  
+
   start_of_bucket = hash_code % XVECTOR (h->index)->size;
   idx = HASH_INDEX (h, start_of_bucket);
 
+  /* We need not gcpro idx since it's either an integer or nil.  */
   while (!NILP (idx))
     {
       int i = XFASTINT (idx);
       if (EQ (key, HASH_KEY (h, i))
          || (h->cmpfn
              && h->cmpfn (h, key, hash_code,
-                          HASH_KEY (h, i), HASH_HASH (h, i))))
+                          HASH_KEY (h, i), XUINT (HASH_HASH (h, i)))))
        break;
       idx = HASH_NEXT (h, i);
     }
@@ -3797,9 +4211,10 @@ hash_lookup (h, key, hash)
 
 
 /* Put an entry into hash table H that associates KEY with VALUE.
-   HASH is a previously computed hash code of KEY.  */
+   HASH is a previously computed hash code of KEY.
+   Value is the index of the entry in H matching KEY.  */
 
-void
+int
 hash_put (h, key, value, hash)
      struct Lisp_Hash_Table *h;
      Lisp_Object key, value;
@@ -3812,7 +4227,7 @@ hash_put (h, key, value, hash)
   /* Increment count after resizing because resizing may fail.  */
   maybe_resize_hash_table (h);
   h->count = make_number (XFASTINT (h->count) + 1);
-  
+
   /* Store key/value in the key_and_value vector.  */
   i = XFASTINT (h->next_free);
   h->next_free = HASH_NEXT (h, i);
@@ -3826,6 +4241,7 @@ hash_put (h, key, value, hash)
   start_of_bucket = hash % XVECTOR (h->index)->size;
   HASH_NEXT (h, i) = HASH_INDEX (h, start_of_bucket);
   HASH_INDEX (h, start_of_bucket) = make_number (i);
+  return i;
 }
 
 
@@ -3845,6 +4261,7 @@ hash_remove (h, key)
   idx = HASH_INDEX (h, start_of_bucket);
   prev = Qnil;
 
+  /* We need not gcpro idx, prev since they're either integers or nil.  */
   while (!NILP (idx))
     {
       int i = XFASTINT (idx);
@@ -3852,7 +4269,7 @@ hash_remove (h, key)
       if (EQ (key, HASH_KEY (h, i))
          || (h->cmpfn
              && h->cmpfn (h, key, hash_code,
-                          HASH_KEY (h, i), HASH_HASH (h, i))))
+                          HASH_KEY (h, i), XUINT (HASH_HASH (h, i)))))
        {
          /* Take entry out of collision chain.  */
          if (NILP (prev))
@@ -3910,93 +4327,141 @@ hash_clear (h)
                           Weak Hash Tables
  ************************************************************************/
 
-/* Remove elements from weak hash tables that don't survive the
-   current garbage collection.  Remove weak tables that don't survive
-   from Vweak_hash_tables.  Called from gc_sweep.  */
+/* Sweep weak hash table H.  REMOVE_ENTRIES_P non-zero means remove
+   entries from the table that don't survive the current GC.
+   REMOVE_ENTRIES_P zero means mark entries that are in use.  Value is
+   non-zero if anything was marked.  */
 
-void
-sweep_weak_hash_tables ()
+static int
+sweep_weak_table (h, remove_entries_p)
+     struct Lisp_Hash_Table *h;
+     int remove_entries_p;
 {
-  Lisp_Object table;
-  struct Lisp_Hash_Table *h = 0, *prev;
+  int bucket, n, marked;
+
+  n = XVECTOR (h->index)->size & ~ARRAY_MARK_FLAG;
+  marked = 0;
 
-  for (table = Vweak_hash_tables; !GC_NILP (table); table = h->next_weak)
+  for (bucket = 0; bucket < n; ++bucket)
     {
-      prev = h;
-      h = XHASH_TABLE (table);
-       
-      if (h->size & ARRAY_MARK_FLAG)
+      Lisp_Object idx, next, prev;
+
+      /* Follow collision chain, removing entries that
+        don't survive this garbage collection.  */
+      prev = Qnil;
+      for (idx = HASH_INDEX (h, bucket); !GC_NILP (idx); idx = next)
        {
-         if (XFASTINT (h->count) > 0)
+         int i = XFASTINT (idx);
+         int key_known_to_survive_p = survives_gc_p (HASH_KEY (h, i));
+         int value_known_to_survive_p = survives_gc_p (HASH_VALUE (h, i));
+         int remove_p;
+
+         if (EQ (h->weak, Qkey))
+           remove_p = !key_known_to_survive_p;
+         else if (EQ (h->weak, Qvalue))
+           remove_p = !value_known_to_survive_p;
+         else if (EQ (h->weak, Qkey_or_value))
+           remove_p = !(key_known_to_survive_p || value_known_to_survive_p);
+         else if (EQ (h->weak, Qkey_and_value))
+           remove_p = !(key_known_to_survive_p && value_known_to_survive_p);
+         else
+           abort ();
+
+         next = HASH_NEXT (h, i);
+
+         if (remove_entries_p)
            {
-             int bucket, n;
+             if (remove_p)
+               {
+                 /* Take out of collision chain.  */
+                 if (GC_NILP (prev))
+                   HASH_INDEX (h, bucket) = next;
+                 else
+                   HASH_NEXT (h, XFASTINT (prev)) = next;
 
-             n = XVECTOR (h->index)->size & ~ARRAY_MARK_FLAG;
-             for (bucket = 0; bucket < n; ++bucket)
+                 /* Add to free list.  */
+                 HASH_NEXT (h, i) = h->next_free;
+                 h->next_free = idx;
+
+                 /* Clear key, value, and hash.  */
+                 HASH_KEY (h, i) = HASH_VALUE (h, i) = Qnil;
+                 HASH_HASH (h, i) = Qnil;
+
+                 h->count = make_number (XFASTINT (h->count) - 1);
+               }
+           }
+         else
+           {
+             if (!remove_p)
                {
-                 Lisp_Object idx, key, value, prev, next;
+                 /* Make sure key and value survive.  */
+                 if (!key_known_to_survive_p)
+                   {
+                     mark_object (&HASH_KEY (h, i));
+                     marked = 1;
+                   }
 
-                 /* Follow collision chain, removing entries that
-                    don't survive this garbage collection.  */
-                 idx = HASH_INDEX (h, bucket);
-                 prev = Qnil;
-                 while (!GC_NILP (idx))
+                 if (!value_known_to_survive_p)
                    {
-                     int remove_p;
-                     int i = XFASTINT (idx);
-                     Lisp_Object next;
-
-                     if (EQ (h->weak, Qkey))
-                       remove_p = !survives_gc_p (HASH_KEY (h, i));
-                     else if (EQ (h->weak, Qvalue))
-                       remove_p = !survives_gc_p (HASH_VALUE (h, i));
-                     else if (EQ (h->weak, Qt))
-                       remove_p = (!survives_gc_p (HASH_KEY (h, i))
-                                   || !survives_gc_p (HASH_VALUE (h, i)));
-                     else
-                       abort ();
-                     
-                     next = HASH_NEXT (h, i);
-                     if (remove_p)
-                       {
-                         /* Take out of collision chain.  */
-                         if (GC_NILP (prev))
-                           HASH_INDEX (h, i) = next;
-                         else
-                           HASH_NEXT (h, XFASTINT (prev)) = next;
-
-                         /* Add to free list.  */
-                         HASH_NEXT (h, i) = h->next_free;
-                         h->next_free = idx;
-
-                         /* Clear key, value, and hash.  */
-                         HASH_KEY (h, i) = HASH_VALUE (h, i) = Qnil;
-                         HASH_HASH (h, i) = Qnil;
-
-                         h->count = make_number (XFASTINT (h->count) - 1);
-                       }
-                     else
-                       {
-                         /* Make sure key and value survive.  */
-                         mark_object (&HASH_KEY (h, i));
-                         mark_object (&HASH_VALUE (h, i));
-                       }
-
-                     idx = next;
+                     mark_object (&HASH_VALUE (h, i));
+                     marked = 1;
                    }
                }
            }
        }
-      else
+    }
+
+  return marked;
+}
+
+/* Remove elements from weak hash tables that don't survive the
+   current garbage collection.  Remove weak tables that don't survive
+   from Vweak_hash_tables.  Called from gc_sweep.  */
+
+void
+sweep_weak_hash_tables ()
+{
+  Lisp_Object table, used, next;
+  struct Lisp_Hash_Table *h;
+  int marked;
+
+  /* Mark all keys and values that are in use.  Keep on marking until
+     there is no more change.  This is necessary for cases like
+     value-weak table A containing an entry X -> Y, where Y is used in a
+     key-weak table B, Z -> Y.  If B comes after A in the list of weak
+     tables, X -> Y might be removed from A, although when looking at B
+     one finds that it shouldn't.  */
+  do
+    {
+      marked = 0;
+      for (table = Vweak_hash_tables; !GC_NILP (table); table = h->next_weak)
        {
-         /* Table is not marked, and will thus be freed.
-            Take it out of the list of weak hash tables.  */
-         if (prev)
-           prev->next_weak = h->next_weak;
-         else
-           Vweak_hash_tables = h->next_weak;
+         h = XHASH_TABLE (table);
+         if (h->size & ARRAY_MARK_FLAG)
+           marked |= sweep_weak_table (h, 0);
        }
     }
+  while (marked);
+
+  /* Remove tables and entries that aren't used.  */
+  for (table = Vweak_hash_tables, used = Qnil; !GC_NILP (table); table = next)
+    {
+      h = XHASH_TABLE (table);
+      next = h->next_weak;
+      
+      if (h->size & ARRAY_MARK_FLAG)
+       {
+         /* TABLE is marked as used.  Sweep its contents.  */
+         if (XFASTINT (h->count) > 0)
+           sweep_weak_table (h, 1);
+
+         /* Add table to the list of used weak hash tables.  */
+         h->next_weak = used;
+         used = table;
+       }
+    }
+
+  Vweak_hash_tables = used;
 }
 
 
@@ -4017,11 +4482,12 @@ sweep_weak_hash_tables ()
 /* Combine two integers X and Y for hashing.  */
 
 #define SXHASH_COMBINE(X, Y)                                           \
-     ((((unsigned)(X) << 4) + ((unsigned)(X) >> 24) & 0x0fffffff)      \
+     ((((unsigned)(X) << 4) + (((unsigned)(X) >> 24) & 0x0fffffff))    \
       + (unsigned)(Y))
 
 
-/* Return a hash for string PTR which has length LEN.  */
+/* Return a hash for string PTR which has length LEN.  The hash
+   code returned is guaranteed to fit in a Lisp integer.  */
 
 static unsigned
 sxhash_string (ptr, len)
@@ -4040,8 +4506,8 @@ sxhash_string (ptr, len)
        c -= 40;
       hash = ((hash << 3) + (hash >> 28) + c);
     }
-  
-  return hash & 07777777777;
+
+  return hash & VALMASK;
 }
 
 
@@ -4055,7 +4521,7 @@ sxhash_list (list, depth)
 {
   unsigned hash = 0;
   int i;
-  
+
   if (depth < SXHASH_MAX_DEPTH)
     for (i = 0;
         CONSP (list) && i < SXHASH_MAX_LEN;
@@ -4120,7 +4586,7 @@ sxhash (obj, depth)
 
   if (depth > SXHASH_MAX_DEPTH)
     return 0;
-  
+
   switch (XTYPE (obj))
     {
     case Lisp_Int:
@@ -4198,27 +4664,29 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
 Arguments are specified as keyword/argument pairs.  The following\n\
 arguments are defined:\n\
 \n\
-:TEST TEST -- TEST must be a symbol that specifies how to compare keys.
+:test TEST -- TEST must be a symbol that specifies how to compare keys.\n\
 Default is `eql'.  Predefined are the tests `eq', `eql', and `equal'.\n\
 User-supplied test and hash functions can be specified via\n\
 `define-hash-table-test'.\n\
 \n\
-:SIZE SIZE -- A hint as to how many elements will be put in the table.
+:size SIZE -- A hint as to how many elements will be put in the table.\n\
 Default is 65.\n\
 \n\
-:REHASH-SIZE REHASH-SIZE - Indicates how to expand the table when\n\
+:rehash-size REHASH-SIZE - Indicates how to expand the table when\n\
 it fills up.  If REHASH-SIZE is an integer, add that many space.\n\
 If it is a float, it must be > 1.0, and the new size is computed by\n\
 multiplying the old size with that factor.  Default is 1.5.\n\
 \n\
-:REHASH-THRESHOLD THRESHOLD -- THRESHOLD must a float > 0, and <= 1.0.\n\
+:rehash-threshold THRESHOLD -- THRESHOLD must a float > 0, and <= 1.0.\n\
 Resize the hash table when ratio of the number of entries in the table.\n\
 Default is 0.8.\n\
 \n\
-:WEAKNESS WEAK -- WEAK must be one of nil, t, `key', or `value'.\n\
-If WEAK is not nil, the table returned is a weak table.  Key/value\n\
-pairs are removed from a weak hash table when their key, value or both\n\
-(WEAK t) are otherwise unreferenced.  Default is nil.")
+:weakness WEAK -- WEAK must be one of nil, t, `key', `value',\n\
+`key-or-value', or `key-and-value'.  If WEAK is not nil, the table returned\n\
+is a weak table.  Key/value pairs are removed from a weak hash table when\n\
+there are no non-weak references pointing to their key, value, one of key\n\
+or value, or both key and value, depending on WEAK.  WEAK t is equivalent\n\
+to `key-and-value'.  Default value of WEAK is nil.")
   (nargs, args)
      int nargs;
      Lisp_Object *args;
@@ -4240,10 +4708,10 @@ pairs are removed from a weak hash table when their key, value or both\n\
     {
       /* See if it is a user-defined test.  */
       Lisp_Object prop;
-      
+
       prop = Fget (test, Qhash_table_test);
       if (!CONSP (prop) || XFASTINT (Flength (prop)) < 2)
-       Fsignal (Qerror, list2 (build_string ("Illegal hash table test"),
+       Fsignal (Qerror, list2 (build_string ("Invalid hash table test"),
                                test));
       user_test = Fnth (make_number (0), prop);
       user_hash = Fnth (make_number (1), prop);
@@ -4254,9 +4722,9 @@ pairs are removed from a weak hash table when their key, value or both\n\
   /* See if there's a `:size SIZE' argument.  */
   i = get_key_arg (QCsize, nargs, args, used);
   size = i < 0 ? make_number (DEFAULT_HASH_SIZE) : args[i];
-  if (!INTEGERP (size) || XINT (size) <= 0)
+  if (!INTEGERP (size) || XINT (size) < 0)
     Fsignal (Qerror,
-            list2 (build_string ("Illegal hash table size"),
+            list2 (build_string ("Invalid hash table size"),
                    size));
 
   /* Look for `:rehash-size SIZE'.  */
@@ -4266,9 +4734,9 @@ pairs are removed from a weak hash table when their key, value or both\n\
       || (INTEGERP (rehash_size) && XINT (rehash_size) <= 0)
       || XFLOATINT (rehash_size) <= 1.0)
     Fsignal (Qerror,
-            list2 (build_string ("Illegal hash table rehash size"),
+            list2 (build_string ("Invalid hash table rehash size"),
                    rehash_size));
-  
+
   /* Look for `:rehash-threshold THRESHOLD'.  */
   i = get_key_arg (QCrehash_threshold, nargs, args, used);
   rehash_threshold = i < 0 ? make_float (DEFAULT_REHASH_THRESHOLD) : args[i];
@@ -4276,19 +4744,22 @@ pairs are removed from a weak hash table when their key, value or both\n\
       || XFLOATINT (rehash_threshold) <= 0.0
       || XFLOATINT (rehash_threshold) > 1.0)
     Fsignal (Qerror,
-            list2 (build_string ("Illegal hash table rehash threshold"),
+            list2 (build_string ("Invalid hash table rehash threshold"),
                    rehash_threshold));
-  
+
   /* Look for `:weakness WEAK'.  */
   i = get_key_arg (QCweakness, nargs, args, used);
   weak = i < 0 ? Qnil : args[i];
+  if (EQ (weak, Qt))
+    weak = Qkey_and_value;
   if (!NILP (weak)
-      && !EQ (weak, Qt)
       && !EQ (weak, Qkey)
-      && !EQ (weak, Qvalue))
-    Fsignal (Qerror, list2 (build_string ("Illegal hash table weakness"), 
+      && !EQ (weak, Qvalue)
+      && !EQ (weak, Qkey_or_value)
+      && !EQ (weak, Qkey_and_value))
+    Fsignal (Qerror, list2 (build_string ("Invalid hash table weakness"),
                            weak));
-  
+
   /* Now, all args should have been used up, or there's a problem.  */
   for (i = 0; i < nargs; ++i)
     if (!used[i])
@@ -4319,7 +4790,7 @@ is `eql'.  New tests can be defined with `define-hash-table-test'.")
 {
   Lisp_Object args[2];
   args[0] = QCtest;
-  args[1] = test;
+  args[1] = NILP (test) ? Qeql : test;
   return Fmake_hash_table (2, args);
 }
 
@@ -4332,7 +4803,7 @@ DEFUN ("hash-table-count", Fhash_table_count, Shash_table_count, 1, 1, 0,
   return check_hash_table (table)->count;
 }
 
-  
+
 DEFUN ("hash-table-rehash-size", Fhash_table_rehash_size,
        Shash_table_rehash_size, 1, 1, 0,
   "Return the current rehash size of TABLE.")
@@ -4341,7 +4812,7 @@ DEFUN ("hash-table-rehash-size", Fhash_table_rehash_size,
 {
   return check_hash_table (table)->rehash_size;
 }
-  
+
 
 DEFUN ("hash-table-rehash-threshold", Fhash_table_rehash_threshold,
        Shash_table_rehash_threshold, 1, 1, 0,
@@ -4351,7 +4822,7 @@ DEFUN ("hash-table-rehash-threshold", Fhash_table_rehash_threshold,
 {
   return check_hash_table (table)->rehash_threshold;
 }
-  
+
 
 DEFUN ("hash-table-size", Fhash_table_size, Shash_table_size, 1, 1, 0,
   "Return the size of TABLE.\n\
@@ -4364,7 +4835,7 @@ without need for resizing.")
   struct Lisp_Hash_Table *h = check_hash_table (table);
   return make_number (HASH_TABLE_SIZE (h));
 }
-  
+
 
 DEFUN ("hash-table-test", Fhash_table_test, Shash_table_test, 1, 1, 0,
   "Return the test TABLE uses.")
@@ -4374,7 +4845,7 @@ DEFUN ("hash-table-test", Fhash_table_test, Shash_table_test, 1, 1, 0,
   return check_hash_table (table)->test;
 }
 
-  
+
 DEFUN ("hash-table-weakness", Fhash_table_weakness, Shash_table_weakness,
        1, 1, 0,
   "Return the weakness of TABLE.")
@@ -4384,7 +4855,7 @@ DEFUN ("hash-table-weakness", Fhash_table_weakness, Shash_table_weakness,
   return check_hash_table (table)->weak;
 }
 
-  
+
 DEFUN ("hash-table-p", Fhash_table_p, Shash_table_p, 1, 1, 0,
   "Return t if OBJ is a Lisp hash table object.")
   (obj)
@@ -4408,7 +4879,7 @@ DEFUN ("gethash", Fgethash, Sgethash, 2, 3, 0,
   "Look up KEY in TABLE and return its associated value.\n\
 If KEY is not found, return DFLT which defaults to nil.")
   (key, table, dflt)
-     Lisp_Object key, table;
+     Lisp_Object key, table, dflt;
 {
   struct Lisp_Hash_Table *h = check_hash_table (table);
   int i = hash_lookup (h, key, NULL);
@@ -4417,7 +4888,7 @@ If KEY is not found, return DFLT which defaults to nil.")
 
 
 DEFUN ("puthash", Fputhash, Sputhash, 3, 3, 0,
-  "Associate KEY with VALUE is hash table TABLE.\n\
+  "Associate KEY with VALUE in hash table TABLE.\n\
 If KEY is already present in table, replace its current value with\n\
 VALUE.")
   (key, value, table)
@@ -4432,8 +4903,8 @@ VALUE.")
     HASH_VALUE (h, i) = value;
   else
     hash_put (h, key, value, hash);
-  
-  return Qnil;
+
+  return value;
 }
 
 
@@ -4466,7 +4937,7 @@ FUNCTION is called with 2 arguments KEY and VALUE.")
        args[2] = HASH_VALUE (h, i);
        Ffuncall (3, args);
       }
-  
+
   return Qnil;
 }
 
@@ -4489,6 +4960,224 @@ integers, including negative integers.")
 }
 
 
+\f
+/************************************************************************
+                                MD5
+ ************************************************************************/
+
+#include "md5.h"
+#include "coding.h"
+
+DEFUN ("md5", Fmd5, Smd5, 1, 5, 0,
+  "Return MD5 message digest of OBJECT, a buffer or string.\n\
+A message digest is a cryptographic checksum of a document,\n\
+and the algorithm to calculate it is defined in RFC 1321.\n\
+\n\
+The two optional arguments START and END are character positions\n\
+specifying for which part of OBJECT the message digest should be computed.\n\
+If nil or omitted, the digest is computed for the whole OBJECT.\n\
+\n\
+The MD5 message digest is computed from the result of encoding the\n\
+text in a coding system, not directly from the internal Emacs form\n\
+of the text.  The optional fourth argument CODING-SYSTEM specifies\n\
+which coding system to encode the text with.  It should be the same\n\
+coding system that you used or will use when actually writing the text\n\
+into a file.\n\
+\n\
+If CODING-SYSTEM is nil or omitted, the default depends on OBJECT.\n\
+If OBJECT is a buffer, the default for CODING-SYSTEM is whatever\n\
+coding system would be chosen by default for writing this text\n\
+into a file.\n\
+\n\
+If OBJECT is a string, the most preferred coding system (see the\n\
+command `prefer-coding-system') is used.\n\
+\n\
+If NOERROR is non-nil, silently assume the `raw-text' coding if the\n\
+guesswork fails.  Normally, an error is signaled in such case.")
+  (object, start, end, coding_system, noerror)
+     Lisp_Object object, start, end, coding_system, noerror;
+{
+  unsigned char digest[16];
+  unsigned char value[33];
+  int i;
+  int size;
+  int size_byte = 0;
+  int start_char = 0, end_char = 0;
+  int start_byte = 0, end_byte = 0;
+  register int b, e;
+  register struct buffer *bp;
+  int temp;
+
+  if (STRINGP (object))
+    {
+      if (NILP (coding_system))
+       {
+         /* Decide the coding-system to encode the data with.  */
+
+         if (STRING_MULTIBYTE (object))
+           /* use default, we can't guess correct value */
+           coding_system = SYMBOL_VALUE (XCAR (Vcoding_category_list));
+         else 
+           coding_system = Qraw_text;
+       }
+      
+      if (NILP (Fcoding_system_p (coding_system)))
+       {
+         /* Invalid coding system.  */
+         
+         if (!NILP (noerror))
+           coding_system = Qraw_text;
+         else
+           while (1)
+             Fsignal (Qcoding_system_error, Fcons (coding_system, Qnil));
+       }
+
+      if (STRING_MULTIBYTE (object))
+       object = code_convert_string1 (object, coding_system, Qnil, 1);
+
+      size = XSTRING (object)->size;
+      size_byte = STRING_BYTES (XSTRING (object));
+
+      if (!NILP (start))
+       {
+         CHECK_NUMBER (start, 1);
+
+         start_char = XINT (start);
+
+         if (start_char < 0)
+           start_char += size;
+
+         start_byte = string_char_to_byte (object, start_char);
+       }
+
+      if (NILP (end))
+       {
+         end_char = size;
+         end_byte = size_byte;
+       }
+      else
+       {
+         CHECK_NUMBER (end, 2);
+         
+         end_char = XINT (end);
+
+         if (end_char < 0)
+           end_char += size;
+         
+         end_byte = string_char_to_byte (object, end_char);
+       }
+      
+      if (!(0 <= start_char && start_char <= end_char && end_char <= size))
+       args_out_of_range_3 (object, make_number (start_char),
+                            make_number (end_char));
+    }
+  else
+    {
+      CHECK_BUFFER (object, 0);
+
+      bp = XBUFFER (object);
+         
+      if (NILP (start))
+       b = BUF_BEGV (bp);
+      else
+       {
+         CHECK_NUMBER_COERCE_MARKER (start, 0);
+         b = XINT (start);
+       }
+
+      if (NILP (end))
+       e = BUF_ZV (bp);
+      else
+       {
+         CHECK_NUMBER_COERCE_MARKER (end, 1);
+         e = XINT (end);
+       }
+      
+      if (b > e)
+       temp = b, b = e, e = temp;
+      
+      if (!(BUF_BEGV (bp) <= b && e <= BUF_ZV (bp)))
+       args_out_of_range (start, end);
+      
+      if (NILP (coding_system))
+       {
+         /* Decide the coding-system to encode the data with. 
+            See fileio.c:Fwrite-region */
+
+         if (!NILP (Vcoding_system_for_write))
+           coding_system = Vcoding_system_for_write;
+         else
+           {
+             int force_raw_text = 0;
+
+             coding_system = XBUFFER (object)->buffer_file_coding_system;
+             if (NILP (coding_system)
+                 || NILP (Flocal_variable_p (Qbuffer_file_coding_system, Qnil)))
+               {
+                 coding_system = Qnil;
+                 if (NILP (current_buffer->enable_multibyte_characters))
+                   force_raw_text = 1;
+               }
+
+             if (NILP (coding_system) && !NILP (Fbuffer_file_name(object)))
+               {
+                 /* Check file-coding-system-alist.  */
+                 Lisp_Object args[4], val;
+                 
+                 args[0] = Qwrite_region; args[1] = start; args[2] = end;
+                 args[3] = Fbuffer_file_name(object);
+                 val = Ffind_operation_coding_system (4, args);
+                 if (CONSP (val) && !NILP (XCDR (val)))
+                   coding_system = XCDR (val);
+               }
+
+             if (NILP (coding_system)
+                 && !NILP (XBUFFER (object)->buffer_file_coding_system))
+               {
+                 /* If we still have not decided a coding system, use the
+                    default value of buffer-file-coding-system.  */
+                 coding_system = XBUFFER (object)->buffer_file_coding_system;
+               }
+
+             if (!force_raw_text
+                 && !NILP (Ffboundp (Vselect_safe_coding_system_function)))
+               /* Confirm that VAL can surely encode the current region.  */
+               coding_system = call3 (Vselect_safe_coding_system_function,
+                                      make_number (b), make_number (e),
+                                      coding_system);
+
+             if (force_raw_text)
+               coding_system = Qraw_text;
+           }
+
+         if (NILP (Fcoding_system_p (coding_system)))
+           {
+             /* Invalid coding system.  */
+
+             if (!NILP (noerror))
+               coding_system = Qraw_text;
+             else
+               while (1)
+                 Fsignal (Qcoding_system_error, Fcons (coding_system, Qnil));
+           }
+       }
+
+      object = make_buffer_string (b, e, 0);
+
+      if (STRING_MULTIBYTE (object))
+       object = code_convert_string1 (object, coding_system, Qnil, 1);
+    }
+
+  md5_buffer (XSTRING (object)->data + start_byte, 
+             STRING_BYTES(XSTRING (object)) - (size_byte - end_byte), 
+             digest);
+
+  for (i = 0; i < 16; i++)
+    sprintf (&value[2 * i], "%02x", digest[i]);
+  value[32] = '\0';
+
+  return make_string (value, 32);
+}
 
 \f
 void
@@ -4519,6 +5208,10 @@ syms_of_fns ()
   staticpro (&Qvalue);
   Qhash_table_test = intern ("hash-table-test");
   staticpro (&Qhash_table_test);
+  Qkey_or_value = intern ("key-or-value");
+  staticpro (&Qkey_or_value);
+  Qkey_and_value = intern ("key-and-value");
+  staticpro (&Qkey_and_value);
 
   defsubr (&Ssxhash);
   defsubr (&Smake_hash_table);
@@ -4537,7 +5230,7 @@ syms_of_fns ()
   defsubr (&Sremhash);
   defsubr (&Smaphash);
   defsubr (&Sdefine_hash_table_test);
-  
+
   Qstring_lessp = intern ("string-lessp");
   staticpro (&Qstring_lessp);
   Qprovide = intern ("provide");
@@ -4613,9 +5306,11 @@ invoked by mouse clicks and mouse menu items.");
   defsubr (&Schar_table_range);
   defsubr (&Sset_char_table_range);
   defsubr (&Sset_char_table_default);
+  defsubr (&Soptimize_char_table);
   defsubr (&Smap_char_table);
   defsubr (&Snconc);
   defsubr (&Smapcar);
+  defsubr (&Smapc);
   defsubr (&Smapconcat);
   defsubr (&Sy_or_n_p);
   defsubr (&Syes_or_no_p);
@@ -4623,7 +5318,7 @@ invoked by mouse clicks and mouse menu items.");
   defsubr (&Sfeaturep);
   defsubr (&Srequire);
   defsubr (&Sprovide);
-  defsubr (&Swidget_plist_member);
+  defsubr (&Splist_member);
   defsubr (&Swidget_put);
   defsubr (&Swidget_get);
   defsubr (&Swidget_apply);
@@ -4631,6 +5326,7 @@ invoked by mouse clicks and mouse menu items.");
   defsubr (&Sbase64_decode_region);
   defsubr (&Sbase64_encode_string);
   defsubr (&Sbase64_decode_string);
+  defsubr (&Smd5);
 }