(Qforeground_color, Qbackground_color): Declare.
[bpt/emacs.git] / src / fns.c
index b133967..5d5f3fc 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -1,5 +1,5 @@
 /* Random utility Lisp functions.
-   Copyright (C) 1985, 86, 87, 93, 94, 95 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 93, 94, 95, 97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,11 +15,16 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <config.h>
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 /* Note on some machines this defines `vector' as a typedef,
    so make sure we don't use that name in this file.  */
 #undef vector
@@ -27,21 +32,41 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "lisp.h"
 #include "commands.h"
+#include "charset.h"
 
 #include "buffer.h"
 #include "keyboard.h"
 #include "intervals.h"
+#include "frame.h"
+#include "window.h"
+#ifdef HAVE_MENUS
+#include "xterm.h"
+#endif
 
 #ifndef NULL
 #define NULL (void *)0
 #endif
 
-extern Lisp_Object Flookup_key ();
+/* Nonzero enables use of dialog boxes for questions
+   asked by mouse commands.  */
+int use_dialog_box;
+
+extern int minibuffer_auto_raise;
+extern Lisp_Object minibuf_window;
 
 Lisp_Object Qstring_lessp, Qprovide, Qrequire;
 Lisp_Object Qyes_or_no_p_history;
+Lisp_Object Qcursor_in_echo_area;
+Lisp_Object Qwidget_type;
 
 static int internal_equal ();
+
+extern long get_random ();
+extern void seed_random ();
+
+#ifndef HAVE_UNISTD_H
+extern long time ();
+#endif
 \f
 DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
   "Return the argument unchanged.")
@@ -51,38 +76,34 @@ DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
   return arg;
 }
 
-extern long get_random ();
-extern void seed_random ();
-extern long time ();
-
 DEFUN ("random", Frandom, Srandom, 0, 1, 0,
   "Return a pseudo-random number.\n\
 All integers representable in Lisp are equally likely.\n\
   On most systems, this is 28 bits' worth.\n\
 With positive integer argument N, return random number in interval [0,N).\n\
 With argument t, set the random number seed from the current time and pid.")
-  (limit)
-     Lisp_Object limit;
+  (n)
+     Lisp_Object n;
 {
   EMACS_INT val;
   Lisp_Object lispy_val;
   unsigned long denominator;
 
-  if (EQ (limit, Qt))
+  if (EQ (n, Qt))
     seed_random (getpid () + time (NULL));
-  if (NATNUMP (limit) && XFASTINT (limit) != 0)
+  if (NATNUMP (n) && XFASTINT (n) != 0)
     {
       /* Try to take our random number from the higher bits of VAL,
         not the lower, since (says Gentzel) the low bits of `random'
         are less random than the higher ones.  We do this by using the
         quotient rather than the remainder.  At the high end of the RNG
-        it's possible to get a quotient larger than limit; discarding
+        it's possible to get a quotient larger than n; discarding
         these values eliminates the bias that would otherwise appear
-        when using a large limit.  */
-      denominator = ((unsigned long)1 << VALBITS) / XFASTINT (limit);
+        when using a large n.  */
+      denominator = ((unsigned long)1 << VALBITS) / XFASTINT (n);
       do
        val = get_random () / denominator;
-      while (val >= XFASTINT (limit));
+      while (val >= XFASTINT (n));
     }
   else
     val = get_random ();
@@ -94,27 +115,32 @@ With argument t, set the random number seed from the current time and pid.")
 
 DEFUN ("length", Flength, Slength, 1, 1, 0,
   "Return the length of vector, list or string SEQUENCE.\n\
-A byte-code function object is also allowed.")
-  (obj)
-     register Lisp_Object obj;
+A byte-code function object is also allowed.\n\
+If the string contains multibyte characters, this is not the necessarily\n\
+the number of bytes in the string; it is the number of characters.\n\
+To get the number of bytes, use `string-bytes'")
+  (sequence)
+     register Lisp_Object sequence;
 {
   register Lisp_Object tail, val;
   register int i;
 
  retry:
-  if (STRINGP (obj))
-    XSETFASTINT (val, XSTRING (obj)->size);
-  else if (VECTORP (obj))
-    XSETFASTINT (val, XVECTOR (obj)->size);
-  else if (CHAR_TABLE_P (obj))
-    XSETFASTINT (val, CHAR_TABLE_ORDINARY_SLOTS);
-  else if (BOOL_VECTOR_P (obj))
-    XSETFASTINT (val, XBOOL_VECTOR (obj)->size);
-  else if (COMPILEDP (obj))
-    XSETFASTINT (val, XVECTOR (obj)->size & PSEUDOVECTOR_SIZE_MASK);
-  else if (CONSP (obj))
-    {
-      for (i = 0, tail = obj; !NILP (tail); i++)
+  if (STRINGP (sequence))
+    XSETFASTINT (val, XSTRING (sequence)->size);
+  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));
+  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++)
        {
          QUIT;
          tail = Fcdr (tail);
@@ -122,11 +148,11 @@ A byte-code function object is also allowed.")
 
       XSETFASTINT (val, i);
     }
-  else if (NILP (obj))
+  else if (NILP (sequence))
     XSETFASTINT (val, 0);
   else
     {
-      obj = wrong_type_argument (Qsequencep, obj);
+      sequence = wrong_type_argument (Qsequencep, sequence);
       goto retry;
     }
   return val;
@@ -140,7 +166,7 @@ DEFUN ("safe-length", Fsafe_length, Ssafe_length, 1, 1, 0,
 This function never gets an error.  If LIST is not really a list,\n\
 it returns 0.  If LIST is circular, it returns a finite value\n\
 which is at least the number of distinct elements.")
- (list)
 (list)
      Lisp_Object list;
 {
   Lisp_Object tail, halftail, length;
@@ -161,8 +187,18 @@ which is at least the number of distinct elements.")
   return length;
 }
 
+DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0,
+  "Return the number of bytes in STRING.\n\
+If STRING is a multibyte string, this is greater than the length of STRING.")
+  (string)
+     Lisp_Object string;
+{
+  CHECK_STRING (string, 1);
+  return make_number (STRING_BYTES (XSTRING (string)));
+}
+
 DEFUN ("string-equal", Fstring_equal, Sstring_equal, 2, 2, 0,
-  "T if two strings have identical contents.\n\
+  "Return t if two strings have identical contents.\n\
 Case is significant, but text properties are ignored.\n\
 Symbols are also allowed; their print names are used instead.")
   (s1, s2)
@@ -175,22 +211,22 @@ Symbols are also allowed; their print names are used instead.")
   CHECK_STRING (s1, 0);
   CHECK_STRING (s2, 1);
 
-  if (XSTRING (s1)->size != XSTRING (s2)->size ||
-      bcmp (XSTRING (s1)->data, XSTRING (s2)->data, XSTRING (s1)->size))
+  if (XSTRING (s1)->size != XSTRING (s2)->size
+      || STRING_BYTES (XSTRING (s1)) != STRING_BYTES (XSTRING (s2))
+      || bcmp (XSTRING (s1)->data, XSTRING (s2)->data, STRING_BYTES (XSTRING (s1))))
     return Qnil;
   return Qt;
 }
 
 DEFUN ("string-lessp", Fstring_lessp, Sstring_lessp, 2, 2, 0,
-  "T if first arg string is less than second in lexicographic order.\n\
+  "Return t if first arg string is less than second in lexicographic order.\n\
 Case is significant.\n\
 Symbols are also allowed; their print names are used instead.")
   (s1, s2)
      register Lisp_Object s1, s2;
 {
-  register int i;
-  register unsigned char *p1, *p2;
   register int end;
+  register int i1, i1_byte, i2, i2_byte;
 
   if (SYMBOLP (s1))
     XSETSTRING (s1, XSYMBOL (s1)->name);
@@ -199,18 +235,32 @@ Symbols are also allowed; their print names are used instead.")
   CHECK_STRING (s1, 0);
   CHECK_STRING (s2, 1);
 
-  p1 = XSTRING (s1)->data;
-  p2 = XSTRING (s2)->data;
+  i1 = i1_byte = i2 = i2_byte = 0;
+
   end = XSTRING (s1)->size;
   if (end > XSTRING (s2)->size)
     end = XSTRING (s2)->size;
 
-  for (i = 0; i < end; i++)
+  while (i1 < end)
     {
-      if (p1[i] != p2[i])
-       return p1[i] < p2[i] ? Qt : Qnil;
+      /* When we find a mismatch, we must compare the
+        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++];
+
+      if (c1 != c2)
+       return c1 < c2 ? Qt : Qnil;
     }
-  return i < XSTRING (s2)->size ? Qt : Qnil;
+  return i1 < XSTRING (s2)->size ? Qt : Qnil;
 }
 \f
 static Lisp_Object concat ();
@@ -285,6 +335,28 @@ Each argument may be a list, vector or string.")
   return concat (nargs, args, Lisp_Vectorlike, 0);
 }
 
+/* Retrun a copy of a sub char table ARG.  The elements except for a
+   nested sub char table are not copied.  */
+static Lisp_Object
+copy_sub_char_table (arg)
+     Lisp_Object arg;
+{
+  Lisp_Object copy = make_sub_char_table (XCHAR_TABLE (arg)->defalt);
+  int i;
+
+  /* Copy all the contents.  */
+  bcopy (XCHAR_TABLE (arg)->contents, XCHAR_TABLE (copy)->contents,
+        SUB_CHAR_TABLE_ORDINARY_SLOTS * sizeof (Lisp_Object));
+  /* Recursively copy any sub char-tables in the ordinary slots.  */
+  for (i = 32; i < SUB_CHAR_TABLE_ORDINARY_SLOTS; i++)
+    if (SUB_CHAR_TABLE_P (XCHAR_TABLE (arg)->contents[i]))
+      XCHAR_TABLE (copy)->contents[i]
+       = copy_sub_char_table (XCHAR_TABLE (copy)->contents[i]);
+
+  return copy;
+}
+
+
 DEFUN ("copy-sequence", Fcopy_sequence, Scopy_sequence, 1, 1, 0,
   "Return a copy of a list, vector or string.\n\
 The elements of a list or vector are not copied; they are shared\n\
@@ -296,21 +368,22 @@ with the original.")
 
   if (CHAR_TABLE_P (arg))
     {
-      int i, size;
+      int i;
       Lisp_Object copy;
 
-      /* Calculate the number of extra slots.  */
-      size = CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (arg));
       copy = Fmake_char_table (XCHAR_TABLE (arg)->purpose, Qnil);
       /* Copy all the slots, including the extra ones.  */
-      bcopy (XCHAR_TABLE (arg)->contents, XCHAR_TABLE (copy)->contents,
-            (XCHAR_TABLE (arg)->size & PSEUDOVECTOR_SIZE_MASK) * sizeof (Lisp_Object));
-
-      /* Recursively copy any char-tables in the ordinary slots.  */
-      for (i = 0; i < CHAR_TABLE_ORDINARY_SLOTS; i++)
-       if (CHAR_TABLE_P (XCHAR_TABLE (arg)->contents[i]))
+      bcopy (XVECTOR (arg)->contents, XVECTOR (copy)->contents,
+            ((XCHAR_TABLE (arg)->size & PSEUDOVECTOR_SIZE_MASK)
+             * sizeof (Lisp_Object)));
+
+      /* Recursively copy any sub char tables in the ordinary slots
+         for multibyte characters.  */
+      for (i = CHAR_TABLE_SINGLE_BYTE_SLOTS;
+          i < CHAR_TABLE_ORDINARY_SLOTS; i++)
+       if (SUB_CHAR_TABLE_P (XCHAR_TABLE (arg)->contents[i]))
          XCHAR_TABLE (copy)->contents[i]
-           = Fcopy_sequence (XCHAR_TABLE (copy)->contents[i]);
+           = copy_sub_char_table (XCHAR_TABLE (copy)->contents[i]);
 
       return copy;
     }
@@ -319,7 +392,7 @@ with the original.")
     {
       Lisp_Object val;
       int size_in_chars
-       = (XBOOL_VECTOR (arg)->size + BITS_PER_CHAR) / BITS_PER_CHAR;
+       = (XBOOL_VECTOR (arg)->size + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
 
       val = Fmake_bool_vector (Flength (arg), Qnil);
       bcopy (XBOOL_VECTOR (arg)->data, XBOOL_VECTOR (val)->data,
@@ -340,14 +413,16 @@ concat (nargs, args, target_type, last_special)
      int last_special;
 {
   Lisp_Object val;
-  Lisp_Object len;
   register Lisp_Object tail;
   register Lisp_Object this;
   int toindex;
-  register int leni;
+  int toindex_byte;
+  register int result_len;
+  register int result_len_byte;
   register int argnum;
   Lisp_Object last_tail;
   Lisp_Object prev;
+  int some_multibyte;
 
   /* In append, the last arg isn't treated like the others */
   if (last_special && nargs > 0)
@@ -358,6 +433,7 @@ concat (nargs, args, target_type, last_special)
   else
     last_tail = Qnil;
 
+  /* Canonicalize each argument.  */
   for (argnum = 0; argnum < nargs; argnum++)
     {
       this = args[argnum];
@@ -371,30 +447,88 @@ concat (nargs, args, target_type, last_special)
        }
     }
 
-  for (argnum = 0, leni = 0; argnum < nargs; argnum++)
+  /* Compute total length in chars of arguments in RESULT_LEN.
+     If desired output is a string, also compute length in bytes
+     in RESULT_LEN_BYTE, and determine in SOME_MULTIBYTE
+     whether the result should be a multibyte string.  */
+  result_len_byte = 0;
+  result_len = 0;
+  some_multibyte = 0;
+  for (argnum = 0; argnum < nargs; argnum++)
     {
+      int len;
       this = args[argnum];
-      len = Flength (this);
-      leni += XFASTINT (len);
+      len = XFASTINT (Flength (this));
+      if (target_type == Lisp_String)
+       {
+         /* We must count the number of bytes needed in the string
+            as well as the number of characters.  */
+         int i;
+         Lisp_Object ch;
+         int this_len_byte;
+
+         if (VECTORP (this))
+           for (i = 0; i < len; i++)
+             {
+               ch = XVECTOR (this)->contents[i];
+               if (! INTEGERP (ch))
+                 wrong_type_argument (Qintegerp, ch);
+               this_len_byte = XFASTINT (Fchar_bytes (ch));
+               result_len_byte += this_len_byte;
+               if (this_len_byte > 1)
+                 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)
+             {
+               ch = XCONS (this)->car;
+               if (! INTEGERP (ch))
+                 wrong_type_argument (Qintegerp, ch);
+               this_len_byte = XFASTINT (Fchar_bytes (ch));
+               result_len_byte += this_len_byte;
+               if (this_len_byte > 1)
+                 some_multibyte = 1;
+             }
+         else if (STRINGP (this))
+           {
+             if (STRING_MULTIBYTE (this))
+               {
+                 some_multibyte = 1;
+                 result_len_byte += STRING_BYTES (XSTRING (this));
+               }
+             else
+               result_len_byte += count_size_as_multibyte (XSTRING (this)->data,
+                                                           XSTRING (this)->size);
+           }
+       }
+
+      result_len += len;
     }
 
-  XSETFASTINT (len, leni);
+  if (! some_multibyte)
+    result_len_byte = result_len;
 
+  /* Create the output object.  */
   if (target_type == Lisp_Cons)
-    val = Fmake_list (len, Qnil);
+    val = Fmake_list (make_number (result_len), Qnil);
   else if (target_type == Lisp_Vectorlike)
-    val = Fmake_vector (len, Qnil);
+    val = Fmake_vector (make_number (result_len), Qnil);
+  else if (some_multibyte)
+    val = make_uninit_multibyte_string (result_len, result_len_byte);
   else
-    val = Fmake_string (len, len);
+    val = make_uninit_string (result_len);
 
-  /* In append, if all but last arg are nil, return last arg */
+  /* In `append', if all but last arg are nil, return last arg.  */
   if (target_type == Lisp_Cons && EQ (val, Qnil))
     return last_tail;
 
+  /* Copy the contents of the args into the result.  */
   if (CONSP (val))
     tail = val, toindex = -1;          /* -1 in toindex is flag we are making a list */
   else
-    toindex = 0;
+    toindex = 0, toindex_byte = 0;
 
   prev = Qnil;
 
@@ -402,7 +536,8 @@ concat (nargs, args, target_type, last_special)
     {
       Lisp_Object thislen;
       int thisleni;
-      register int thisindex = 0;
+      register unsigned int thisindex = 0;
+      register unsigned int thisindex_byte = 0;
 
       this = args[argnum];
       if (!CONSP (this))
@@ -410,71 +545,349 @@ concat (nargs, args, target_type, last_special)
 
       if (STRINGP (this) && STRINGP (val)
          && ! NULL_INTERVAL_P (XSTRING (this)->intervals))
+       copy_text_properties (make_number (0), thislen, this,
+                             make_number (toindex), val, Qnil);
+
+      /* Between strings of the same kind, copy fast.  */
+      if (STRINGP (this) && STRINGP (val)
+         && STRING_MULTIBYTE (this) == some_multibyte)
        {
-         copy_text_properties (make_number (0), thislen, this,
-                               make_number (toindex), val, Qnil);
+         int thislen_byte = STRING_BYTES (XSTRING (this));
+         bcopy (XSTRING (this)->data, XSTRING (val)->data + toindex_byte,
+                STRING_BYTES (XSTRING (this)));
+         toindex_byte += thislen_byte;
+         toindex += thisleni;
        }
-
-      while (1)
+      /* Copy a single-byte string to a multibyte string.  */
+      else if (STRINGP (this) && STRINGP (val))
        {
-         register Lisp_Object elt;
-
-         /* Fetch next element of `this' arg into `elt', or break if
-             `this' is exhausted. */
-         if (NILP (this)) break;
-         if (CONSP (this))
-           elt = Fcar (this), this = Fcdr (this);
-         else
-           {
-             if (thisindex >= thisleni) break;
-             if (STRINGP (this))
-               XSETFASTINT (elt, XSTRING (this)->data[thisindex++]);
-             else if (BOOL_VECTOR_P (this))
-               {
-                 int size_in_chars
-                   = ((XBOOL_VECTOR (this)->size + BITS_PER_CHAR)
-                      / BITS_PER_CHAR);
-                 int byte;
-                 byte = XBOOL_VECTOR (val)->data[thisindex / BITS_PER_CHAR];
-                 if (byte & (1 << thisindex))
-                   elt = Qt;
-                 else
-                   elt = Qnil;
-               }
-             else
-               elt = XVECTOR (this)->contents[thisindex++];
-           }
+         toindex_byte += copy_text (XSTRING (this)->data,
+                                    XSTRING (val)->data + toindex_byte,
+                                    XSTRING (this)->size, 0, 1);
+         toindex += thisleni;
+       }
+      else
+       /* Copy element by element.  */
+       while (1)
+         {
+           register Lisp_Object elt;
+
+           /* Fetch next element of `this' arg into `elt', or break if
+              `this' is exhausted. */
+           if (NILP (this)) break;
+           if (CONSP (this))
+             elt = XCONS (this)->car, this = XCONS (this)->cdr;
+           else if (thisindex >= thisleni)
+             break;
+           else if (STRINGP (this))
+             {
+               int c;
+               if (STRING_MULTIBYTE (this))
+                 {
+                   FETCH_STRING_CHAR_ADVANCE (c, this,
+                                              thisindex,
+                                              thisindex_byte);
+                   XSETFASTINT (elt, c);
+                 }
+               else
+                 {
+                   XSETFASTINT (elt, XSTRING (this)->data[thisindex++]);
+                   if (some_multibyte && XINT (elt) >= 0200
+                       && XINT (elt) < 0400)
+                     {
+                       c = unibyte_char_to_multibyte (XINT (elt));
+                       XSETINT (elt, c);
+                     }
+                 }
+             }
+           else if (BOOL_VECTOR_P (this))
+             {
+               int byte;
+               byte = XBOOL_VECTOR (this)->data[thisindex / BITS_PER_CHAR];
+               if (byte & (1 << (thisindex % BITS_PER_CHAR)))
+                 elt = Qt;
+               else
+                 elt = Qnil;
+               thisindex++;
+             }
+           else
+             elt = XVECTOR (this)->contents[thisindex++];
 
-         /* Store into result */
-         if (toindex < 0)
-           {
-             XCONS (tail)->car = elt;
-             prev = tail;
-             tail = XCONS (tail)->cdr;
-           }
-         else if (VECTORP (val))
-           XVECTOR (val)->contents[toindex++] = elt;
-         else
-           {
-             while (!INTEGERP (elt))
-               elt = wrong_type_argument (Qintegerp, elt);
+           /* Store this element into the result.  */
+           if (toindex < 0)
              {
-#ifdef MASSC_REGISTER_BUG
-               /* Even removing all "register"s doesn't disable this bug!
-                  Nothing simpler than this seems to work. */
-               unsigned char *p = & XSTRING (val)->data[toindex++];
-               *p = XINT (elt);
-#else
-               XSTRING (val)->data[toindex++] = XINT (elt);
-#endif
+               XCONS (tail)->car = elt;
+               prev = tail;
+               tail = XCONS (tail)->cdr;
              }
-           }
-       }
+           else if (VECTORP (val))
+             XVECTOR (val)->contents[toindex++] = elt;
+           else
+             {
+               CHECK_NUMBER (elt, 0);
+               if (SINGLE_BYTE_CHAR_P (XINT (elt)))
+                 {
+                   XSTRING (val)->data[toindex++] = XINT (elt);
+                   toindex_byte++;
+                 }
+               else
+                 /* If we have any multibyte characters,
+                    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++;
+                 }
+             }
+         }
     }
   if (!NILP (prev))
     XCONS (prev)->cdr = last_tail;
 
-  return val;  
+  return val;
+}
+\f
+static Lisp_Object string_char_byte_cache_string;
+static int string_char_byte_cache_charpos;
+static int string_char_byte_cache_bytepos;
+
+/* Return the character index corresponding to CHAR_INDEX in STRING.  */
+
+int
+string_char_to_byte (string, char_index)
+     Lisp_Object string;
+     int char_index;
+{
+  int i, i_byte;
+  int best_below, best_below_byte;
+  int best_above, best_above_byte;
+
+  if (! STRING_MULTIBYTE (string))
+    return char_index;
+
+  best_below = best_below_byte = 0;
+  best_above = XSTRING (string)->size;
+  best_above_byte = STRING_BYTES (XSTRING (string));
+
+  if (EQ (string, string_char_byte_cache_string))
+    {
+      if (string_char_byte_cache_charpos < char_index)
+       {
+         best_below = string_char_byte_cache_charpos;
+         best_below_byte = string_char_byte_cache_bytepos;
+       }
+      else
+       {
+         best_above = string_char_byte_cache_charpos;
+         best_above_byte = string_char_byte_cache_bytepos;
+       }
+    }
+
+  if (char_index - best_below < best_above - char_index)
+    {
+      while (best_below < char_index)
+       {
+         int c;
+         FETCH_STRING_CHAR_ADVANCE (c, string, best_below, best_below_byte);
+       }
+      i = best_below;
+      i_byte = best_below_byte;
+    }
+  else
+    {
+      while (best_above > char_index)
+       {
+         int best_above_byte_saved = --best_above_byte;
+
+         while (best_above_byte > 0
+                && !CHAR_HEAD_P (XSTRING (string)->data[best_above_byte]))
+           best_above_byte--;
+         if (XSTRING (string)->data[best_above_byte] < 0x80)
+           best_above_byte = best_above_byte_saved;
+         best_above--;
+       }
+      i = best_above;
+      i_byte = best_above_byte;
+    }
+
+  string_char_byte_cache_bytepos = i_byte;
+  string_char_byte_cache_charpos = i;
+  string_char_byte_cache_string = string;
+
+  return i_byte;
+}
+\f
+/* Return the character index corresponding to BYTE_INDEX in STRING.  */
+
+int
+string_byte_to_char (string, byte_index)
+     Lisp_Object string;
+     int byte_index;
+{
+  int i, i_byte;
+  int best_below, best_below_byte;
+  int best_above, best_above_byte;
+
+  if (! STRING_MULTIBYTE (string))
+    return byte_index;
+
+  best_below = best_below_byte = 0;
+  best_above = XSTRING (string)->size;
+  best_above_byte = STRING_BYTES (XSTRING (string));
+
+  if (EQ (string, string_char_byte_cache_string))
+    {
+      if (string_char_byte_cache_bytepos < byte_index)
+       {
+         best_below = string_char_byte_cache_charpos;
+         best_below_byte = string_char_byte_cache_bytepos;
+       }
+      else
+       {
+         best_above = string_char_byte_cache_charpos;
+         best_above_byte = string_char_byte_cache_bytepos;
+       }
+    }
+
+  if (byte_index - best_below_byte < best_above_byte - byte_index)
+    {
+      while (best_below_byte < byte_index)
+       {
+         int c;
+         FETCH_STRING_CHAR_ADVANCE (c, string, best_below, best_below_byte);
+       }
+      i = best_below;
+      i_byte = best_below_byte;
+    }
+  else
+    {
+      while (best_above_byte > byte_index)
+       {
+         int best_above_byte_saved = --best_above_byte;
+
+         while (best_above_byte > 0
+                && !CHAR_HEAD_P (XSTRING (string)->data[best_above_byte]))
+           best_above_byte--;
+         if (XSTRING (string)->data[best_above_byte] < 0x80)
+           best_above_byte = best_above_byte_saved;
+         best_above--;
+       }
+      i = best_above;
+      i_byte = best_above_byte;
+    }
+
+  string_char_byte_cache_bytepos = i_byte;
+  string_char_byte_cache_charpos = i;
+  string_char_byte_cache_string = string;
+
+  return i;
+}
+\f
+/* Convert STRING to a multibyte string.
+   Single-byte characters 0240 through 0377 are converted
+   by adding nonascii_insert_offset to each.  */
+
+Lisp_Object
+string_make_multibyte (string)
+     Lisp_Object string;
+{
+  unsigned char *buf;
+  int nbytes;
+
+  if (STRING_MULTIBYTE (string))
+    return string;
+
+  nbytes = count_size_as_multibyte (XSTRING (string)->data,
+                                   XSTRING (string)->size);
+  /* If all the chars are ASCII, they won't need any more bytes
+     once converted.  In that case, we can return STRING itself.  */
+  if (nbytes == STRING_BYTES (XSTRING (string)))
+    return string;
+
+  buf = (unsigned char *) alloca (nbytes);
+  copy_text (XSTRING (string)->data, buf, STRING_BYTES (XSTRING (string)),
+            0, 1);
+
+  return make_multibyte_string (buf, XSTRING (string)->size, nbytes);
+}
+
+/* Convert STRING to a single-byte string.  */
+
+Lisp_Object
+string_make_unibyte (string)
+     Lisp_Object string;
+{
+  unsigned char *buf;
+
+  if (! STRING_MULTIBYTE (string))
+    return string;
+
+  buf = (unsigned char *) alloca (XSTRING (string)->size);
+
+  copy_text (XSTRING (string)->data, buf, STRING_BYTES (XSTRING (string)),
+            1, 0);
+
+  return make_unibyte_string (buf, XSTRING (string)->size);
+}
+
+DEFUN ("string-make-multibyte", Fstring_make_multibyte, Sstring_make_multibyte,
+       1, 1, 0,
+  "Return the multibyte equivalent of STRING.")
+  (string)
+     Lisp_Object string;
+{
+  return string_make_multibyte (string);
+}
+
+DEFUN ("string-make-unibyte", Fstring_make_unibyte, Sstring_make_unibyte,
+       1, 1, 0,
+  "Return the unibyte equivalent of STRING.")
+  (string)
+     Lisp_Object string;
+{
+  return string_make_unibyte (string);
+}
+
+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.")
+  (string)
+     Lisp_Object string;
+{
+  if (STRING_MULTIBYTE (string))
+    {
+      string = Fcopy_sequence (string);
+      XSTRING (string)->size = STRING_BYTES (XSTRING (string));
+      SET_STRING_BYTES (XSTRING (string), -1);
+    }
+  return string;
+}
+
+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.")
+  (string)
+     Lisp_Object string;
+{
+  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;
+    }
+  return string;
 }
 \f
 DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0,
@@ -507,31 +920,112 @@ Elements of ALIST that are not conses are also shared.")
 DEFUN ("substring", Fsubstring, Ssubstring, 2, 3, 0,
   "Return a substring of STRING, starting at index FROM and ending before TO.\n\
 TO may be nil or omitted; then the substring runs to the end of STRING.\n\
-If FROM or TO is negative, it counts from the end.")
+If FROM or TO is negative, it counts from the end.\n\
+\n\
+This function allows vectors as well as strings.")
   (string, from, to)
      Lisp_Object string;
      register Lisp_Object from, to;
 {
   Lisp_Object res;
+  int size;
+  int size_byte;
+  int from_char, to_char;
+  int from_byte, to_byte;
+
+  if (! (STRINGP (string) || VECTORP (string)))
+    wrong_type_argument (Qarrayp, string);
 
-  CHECK_STRING (string, 0);
   CHECK_NUMBER (from, 1);
+
+  if (STRINGP (string))
+    {
+      size = XSTRING (string)->size;
+      size_byte = STRING_BYTES (XSTRING (string));
+    }
+  else
+    size = XVECTOR (string)->size;
+
   if (NILP (to))
-    to = Flength (string);
+    {
+      to_char = size;
+      to_byte = size_byte;
+    }
   else
-    CHECK_NUMBER (to, 2);
-
-  if (XINT (from) < 0)
-    XSETINT (from, XINT (from) + XSTRING (string)->size);
-  if (XINT (to) < 0)
-    XSETINT (to, XINT (to) + XSTRING (string)->size);
-  if (!(0 <= XINT (from) && XINT (from) <= XINT (to)
-        && XINT (to) <= XSTRING (string)->size))
-    args_out_of_range_3 (string, from, to);
-
-  res = make_string (XSTRING (string)->data + XINT (from),
-                    XINT (to) - XINT (from));
-  copy_text_properties (from, to, string, make_number (0), res, Qnil);
+    {
+      CHECK_NUMBER (to, 2);
+
+      to_char = XINT (to);
+      if (to_char < 0)
+       to_char += size;
+
+      if (STRINGP (string))
+       to_byte = string_char_to_byte (string, to_char);
+    }
+
+  from_char = XINT (from);
+  if (from_char < 0)
+    from_char += size;
+  if (STRINGP (string))
+    from_byte = string_char_to_byte (string, from_char);
+
+  if (!(0 <= from_char && from_char <= to_char && to_char <= size))
+    args_out_of_range_3 (string, make_number (from_char),
+                        make_number (to_char));
+
+  if (STRINGP (string))
+    {
+      res = make_specified_string (XSTRING (string)->data + from_byte,
+                                  to_char - from_char, to_byte - from_byte,
+                                  STRING_MULTIBYTE (string));
+      copy_text_properties (make_number (from_char), make_number (to_char),
+                           string, make_number (0), res, Qnil);
+    }
+  else
+    res = Fvector (to_char - from_char,
+                  XVECTOR (string)->contents + from_char);
+
+  return res;
+}
+
+/* Extract a substring of STRING, giving start and end positions
+   both in characters and in bytes.  */
+
+Lisp_Object
+substring_both (string, from, from_byte, to, to_byte)
+     Lisp_Object string;
+     int from, from_byte, to, to_byte;
+{
+  Lisp_Object res;
+  int size;
+  int size_byte;
+
+  if (! (STRINGP (string) || VECTORP (string)))
+    wrong_type_argument (Qarrayp, string);
+
+  if (STRINGP (string))
+    {
+      size = XSTRING (string)->size;
+      size_byte = STRING_BYTES (XSTRING (string));
+    }
+  else
+    size = XVECTOR (string)->size;
+
+  if (!(0 <= from && from <= to && to <= size))
+    args_out_of_range_3 (string, make_number (from), make_number (to));
+
+  if (STRINGP (string))
+    {
+      res = make_specified_string (XSTRING (string)->data + from_byte,
+                                  to - from, to_byte - from_byte,
+                                  STRING_MULTIBYTE (string));
+      copy_text_properties (make_number (from), make_number (to),
+                           string, make_number (0), res, Qnil);
+    }
+  else
+    res = Fvector (to - from,
+                  XVECTOR (string)->contents + from);
+
   return res;
 }
 \f
@@ -563,19 +1057,19 @@ N counts from zero.  If LIST is not that long, nil is returned.")
 
 DEFUN ("elt", Felt, Selt, 2, 2, 0,
   "Return element of SEQUENCE at index N.")
-  (seq, n)
-     register Lisp_Object seq, n;
+  (sequence, n)
+     register Lisp_Object sequence, n;
 {
   CHECK_NUMBER (n, 0);
   while (1)
     {
-      if (CONSP (seq) || NILP (seq))
-       return Fcar (Fnthcdr (n, seq));
-      else if (STRINGP (seq) || VECTORP (seq) || BOOL_VECTOR_P (seq)
-              || CHAR_TABLE_P (seq))
-       return Faref (seq, n);
+      if (CONSP (sequence) || NILP (sequence))
+       return Fcar (Fnthcdr (n, sequence));
+      else if (STRINGP (sequence) || VECTORP (sequence)
+              || BOOL_VECTOR_P (sequence) || CHAR_TABLE_P (sequence))
+       return Faref (sequence, n);
       else
-       seq = wrong_type_argument (Qsequencep, seq);
+       sequence = wrong_type_argument (Qsequencep, sequence);
     }
 }
 
@@ -587,7 +1081,7 @@ 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 = Fcdr (tail))
+  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
     {
       register Lisp_Object tem;
       tem = Fcar (tail);
@@ -606,7 +1100,7 @@ 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 = Fcdr (tail))
+  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
     {
       register Lisp_Object tem;
       tem = Fcar (tail);
@@ -625,12 +1119,12 @@ Elements of LIST that are not conses are ignored.")
      Lisp_Object list;
 {
   register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = Fcdr (tail))
+  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
     {
       register Lisp_Object elt, tem;
       elt = Fcar (tail);
       if (!CONSP (elt)) continue;
-      tem = Fcar (elt);
+      tem = XCONS (elt)->car;
       if (EQ (key, tem)) return elt;
       QUIT;
     }
@@ -646,12 +1140,12 @@ assq_no_quit (key, list)
      Lisp_Object list;
 {
   register Lisp_Object tail;
-  for (tail = list; CONSP (tail); tail = Fcdr (tail))
+  for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
     {
       register Lisp_Object elt, tem;
       elt = Fcar (tail);
       if (!CONSP (elt)) continue;
-      tem = Fcar (elt);
+      tem = XCONS (elt)->car;
       if (EQ (key, tem)) return elt;
     }
   return Qnil;
@@ -665,12 +1159,12 @@ The value is actually the element of LIST whose car equals KEY.")
      Lisp_Object list;
 {
   register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = Fcdr (tail))
+  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
     {
       register Lisp_Object elt, tem;
       elt = Fcar (tail);
       if (!CONSP (elt)) continue;
-      tem = Fequal (Fcar (elt), key);
+      tem = Fequal (XCONS (elt)->car, key);
       if (!NILP (tem)) return elt;
       QUIT;
     }
@@ -685,12 +1179,12 @@ The value is actually the element of LIST whose cdr is ELT.")
      Lisp_Object list;
 {
   register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = Fcdr (tail))
+  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
     {
       register Lisp_Object elt, tem;
       elt = Fcar (tail);
       if (!CONSP (elt)) continue;
-      tem = Fcdr (elt);
+      tem = XCONS (elt)->cdr;
       if (EQ (key, tem)) return elt;
       QUIT;
     }
@@ -705,12 +1199,12 @@ The value is actually the element of LIST whose cdr equals KEY.")
      Lisp_Object list;
 {
   register Lisp_Object tail;
-  for (tail = list; !NILP (tail); tail = Fcdr (tail))
+  for (tail = list; !NILP (tail); tail = XCONS (tail)->cdr)
     {
       register Lisp_Object elt, tem;
       elt = Fcar (tail);
       if (!CONSP (elt)) continue;
-      tem = Fequal (Fcdr (elt), key);
+      tem = Fequal (XCONS (elt)->cdr, key);
       if (!NILP (tem)) return elt;
       QUIT;
     }
@@ -738,13 +1232,13 @@ to be sure of changing the value of `foo'.")
       if (EQ (elt, tem))
        {
          if (NILP (prev))
-           list = Fcdr (tail);
+           list = XCONS (tail)->cdr;
          else
-           Fsetcdr (prev, Fcdr (tail));
+           Fsetcdr (prev, XCONS (tail)->cdr);
        }
       else
        prev = tail;
-      tail = Fcdr (tail);
+      tail = XCONS (tail)->cdr;
       QUIT;
     }
   return list;
@@ -772,13 +1266,13 @@ to be sure of changing the value of `foo'.")
       if (! NILP (Fequal (elt, tem)))
        {
          if (NILP (prev))
-           list = Fcdr (tail);
+           list = XCONS (tail)->cdr;
          else
-           Fsetcdr (prev, Fcdr (tail));
+           Fsetcdr (prev, XCONS (tail)->cdr);
        }
       else
        prev = tail;
-      tail = Fcdr (tail);
+      tail = XCONS (tail)->cdr;
       QUIT;
     }
   return list;
@@ -812,17 +1306,13 @@ See also the function `nreverse', which is used more often.")
   (list)
      Lisp_Object list;
 {
-  Lisp_Object length;
-  register Lisp_Object *vec;
-  register Lisp_Object tail;
-  register int i;
-
-  length = Flength (list);
-  vec = (Lisp_Object *) alloca (XINT (length) * sizeof (Lisp_Object));
-  for (i = XINT (length) - 1, tail = list; i >= 0; i--, tail = Fcdr (tail))
-    vec[i] = Fcar (tail);
+  Lisp_Object new;
 
-  return Flist (XINT (length), vec);
+  for (new = Qnil; CONSP (list); list = XCONS (list)->cdr)
+    new = Fcons (XCONS (list)->car, new);
+  if (!NILP (list))
+    wrong_type_argument (Qconsp, list);
+  return new;
 }
 \f
 Lisp_Object merge ();
@@ -832,8 +1322,8 @@ DEFUN ("sort", Fsort, Ssort, 2, 2, 0,
 Returns the sorted list.  LIST is modified by side effects.\n\
 PREDICATE is called with two elements of LIST, and should return T\n\
 if the first element is \"less\" than the second.")
-  (list, pred)
-     Lisp_Object list, pred;
+  (list, predicate)
+     Lisp_Object list, predicate;
 {
   Lisp_Object front, back;
   register Lisp_Object len, tem;
@@ -852,10 +1342,10 @@ if the first element is \"less\" than the second.")
   Fsetcdr (tem, Qnil);
 
   GCPRO2 (front, back);
-  front = Fsort (front, pred);
-  back = Fsort (back, pred);
+  front = Fsort (front, predicate);
+  back = Fsort (back, predicate);
   UNGCPRO;
-  return merge (front, back, pred);
+  return merge (front, back, predicate);
 }
 
 Lisp_Object
@@ -920,22 +1410,22 @@ merge (org_l1, org_l2, pred)
 \f
 
 DEFUN ("plist-get", Fplist_get, Splist_get, 2, 2, 0,
-       "Extract a value from a property list.\n\
+  "Extract a value from a property list.\n\
 PLIST is a property list, which is a list of the form\n\
 \(PROP1 VALUE1 PROP2 VALUE2...).  This function returns the value\n\
 corresponding to the given PROP, or nil if PROP is not\n\
 one of the properties on the list.")
-  (val, prop)
-     Lisp_Object val;
+  (plist, prop)
+     Lisp_Object plist;
      register Lisp_Object prop;
 {
   register Lisp_Object tail;
-  for (tail = val; !NILP (tail); tail = Fcdr (Fcdr (tail)))
+  for (tail = plist; !NILP (tail); tail = Fcdr (XCONS (tail)->cdr))
     {
       register Lisp_Object tem;
       tem = Fcar (tail);
       if (EQ (prop, tem))
-       return Fcar (Fcdr (tail));
+       return Fcar (XCONS (tail)->cdr);
     }
   return Qnil;
 }
@@ -959,9 +1449,9 @@ otherwise the new PROP VAL pair is added.  The new plist is returned;\n\
 use `(setq x (plist-put x prop val))' to be sure to use the new value.\n\
 The PLIST is modified by side effects.")
   (plist, prop, val)
-    Lisp_Object plist;
-    register Lisp_Object prop;
-    Lisp_Object val;
+     Lisp_Object plist;
+     register Lisp_Object prop;
+     Lisp_Object val;
 {
   register Lisp_Object tail, prev;
   Lisp_Object newcell;
@@ -997,7 +1487,7 @@ It can be retrieved with `(get SYMBOL PROPNAME)'.")
 }
 
 DEFUN ("equal", Fequal, Sequal, 2, 2, 0,
-  "T if two Lisp objects have similar structure and contents.\n\
+  "Return t if two Lisp objects have similar structure and contents.\n\
 They must have the same data type.\n\
 Conses are compared by comparing the cars and the cdrs.\n\
 Vectors and strings are compared element by element.\n\
@@ -1057,7 +1547,7 @@ internal_equal (o1, o2, depth)
        {
          return (XMARKER (o1)->buffer == XMARKER (o2)->buffer
                  && (XMARKER (o1)->buffer == 0
-                     || XMARKER (o1)->bufpos == XMARKER (o2)->bufpos));
+                     || XMARKER (o1)->bytepos == XMARKER (o2)->bytepos));
        }
       break;
 
@@ -1074,7 +1564,7 @@ internal_equal (o1, o2, depth)
        if (BOOL_VECTOR_P (o1))
          {
            int size_in_chars
-             = (XBOOL_VECTOR (o1)->size + BITS_PER_CHAR) / BITS_PER_CHAR;
+             = (XBOOL_VECTOR (o1)->size + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
 
            if (XBOOL_VECTOR (o1)->size != XBOOL_VECTOR (o2)->size)
              return 0;
@@ -1083,6 +1573,8 @@ internal_equal (o1, o2, depth)
              return 0;
            return 1;
          }
+       if (WINDOW_CONFIGURATIONP (o1))
+         return compare_window_configurations (o1, o2, 0);
 
        /* Aside from them, only true vectors, char-tables, and compiled
           functions are sensible to compare, so eliminate the others now.  */
@@ -1107,21 +1599,18 @@ internal_equal (o1, o2, depth)
     case Lisp_String:
       if (XSTRING (o1)->size != XSTRING (o2)->size)
        return 0;
-      if (bcmp (XSTRING (o1)->data, XSTRING (o2)->data,
-               XSTRING (o1)->size))
+      if (STRING_BYTES (XSTRING (o1)) != STRING_BYTES (XSTRING (o2)))
        return 0;
-#ifdef USE_TEXT_PROPERTIES
-      /* If the strings have intervals, verify they match;
-        if not, they are unequal.  */
-      if ((XSTRING (o1)->intervals != 0 || XSTRING (o2)->intervals != 0)
-         && ! compare_string_intervals (o1, o2))
+      if (bcmp (XSTRING (o1)->data, XSTRING (o2)->data,
+               STRING_BYTES (XSTRING (o1))))
        return 0;
-#endif
       return 1;
     }
   return 0;
 }
 \f
+extern Lisp_Object Fmake_char_internal ();
+
 DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
   "Store each element of ARRAY with ITEM.\n\
 ARRAY is a vector, string, char-table, or bool-vector.")
@@ -1158,7 +1647,7 @@ ARRAY is a vector, string, char-table, or bool-vector.")
     {
       register unsigned char *p = XBOOL_VECTOR (array)->data;
       int size_in_chars
-       = (XBOOL_VECTOR (array)->size + BITS_PER_CHAR) / BITS_PER_CHAR;
+       = (XBOOL_VECTOR (array)->size + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
 
       charval = (! NILP (item) ? -1 : 0);
       for (index = 0; index < size_in_chars; index++)
@@ -1171,16 +1660,16 @@ ARRAY is a vector, string, char-table, or bool-vector.")
     }
   return array;
 }
-
+\f
 DEFUN ("char-table-subtype", Fchar_table_subtype, Schar_table_subtype,
        1, 1, 0,
   "Return the subtype of char-table CHAR-TABLE.   The value is a symbol.")
-  (chartable)
-     Lisp_Object chartable;
+  (char_table)
+     Lisp_Object char_table;
 {
-  CHECK_CHAR_TABLE (chartable, 0);  
+  CHECK_CHAR_TABLE (char_table, 0);
 
-  return XCHAR_TABLE (chartable)->purpose;
+  return XCHAR_TABLE (char_table)->purpose;
 }
 
 DEFUN ("char-table-parent", Fchar_table_parent, Schar_table_parent,
@@ -1190,96 +1679,112 @@ The value is either nil or another char-table.\n\
 If CHAR-TABLE holds nil for a given character,\n\
 then the actual applicable value is inherited from the parent char-table\n\
 \(or from its parents, if necessary).")
-  (chartable)
-     Lisp_Object chartable;
+  (char_table)
+     Lisp_Object char_table;
 {
-  CHECK_CHAR_TABLE (chartable, 0);  
+  CHECK_CHAR_TABLE (char_table, 0);
 
-  return XCHAR_TABLE (chartable)->parent;
+  return XCHAR_TABLE (char_table)->parent;
 }
 
 DEFUN ("set-char-table-parent", Fset_char_table_parent, Sset_char_table_parent,
        2, 2, 0,
   "Set the parent char-table of CHAR-TABLE to PARENT.\n\
 PARENT must be either nil or another char-table.")
-  (chartable, parent)
-     Lisp_Object chartable, parent;
+  (char_table, parent)
+     Lisp_Object char_table, parent;
 {
   Lisp_Object temp;
 
-  CHECK_CHAR_TABLE (chartable, 0);  
+  CHECK_CHAR_TABLE (char_table, 0);
 
   if (!NILP (parent))
     {
-      CHECK_CHAR_TABLE (parent, 0);  
+      CHECK_CHAR_TABLE (parent, 0);
 
       for (temp = parent; !NILP (temp); temp = XCHAR_TABLE (temp)->parent)
-       if (EQ (temp, chartable))
+       if (EQ (temp, char_table))
          error ("Attempt to make a chartable be its own parent");
     }
 
-  XCHAR_TABLE (chartable)->parent = parent;
+  XCHAR_TABLE (char_table)->parent = parent;
 
   return parent;
 }
 
 DEFUN ("char-table-extra-slot", Fchar_table_extra_slot, Schar_table_extra_slot,
        2, 2, 0,
-  "Return the value in extra-slot number N of char-table CHAR-TABLE.")
-  (chartable, n)
-     Lisp_Object chartable, n;
+  "Return the value of CHAR-TABLE's extra-slot number N.")
+  (char_table, n)
+     Lisp_Object char_table, n;
 {
-  CHECK_CHAR_TABLE (chartable, 1);
+  CHECK_CHAR_TABLE (char_table, 1);
   CHECK_NUMBER (n, 2);
   if (XINT (n) < 0
-      || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (chartable)))
-    args_out_of_range (chartable, n);
+      || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
+    args_out_of_range (char_table, n);
 
-  return XCHAR_TABLE (chartable)->extras[XINT (n)];
+  return XCHAR_TABLE (char_table)->extras[XINT (n)];
 }
 
 DEFUN ("set-char-table-extra-slot", Fset_char_table_extra_slot,
        Sset_char_table_extra_slot,
        3, 3, 0,
-  "Set extra-slot number N of CHAR-TABLE to VALUE.")
-  (chartable, n, value)
-     Lisp_Object chartable, n, value;
+  "Set CHAR-TABLE's extra-slot number N to VALUE.")
+  (char_table, n, value)
+     Lisp_Object char_table, n, value;
 {
-  CHECK_CHAR_TABLE (chartable, 1);
+  CHECK_CHAR_TABLE (char_table, 1);
   CHECK_NUMBER (n, 2);
   if (XINT (n) < 0
-      || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (chartable)))
-    args_out_of_range (chartable, n);
+      || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
+    args_out_of_range (char_table, n);
 
-  return XCHAR_TABLE (chartable)->extras[XINT (n)] = value;
+  return XCHAR_TABLE (char_table)->extras[XINT (n)] = value;
 }
-
+\f
 DEFUN ("char-table-range", Fchar_table_range, Schar_table_range,
        2, 2, 0,
-  "Return the value in CHARTABLE for a range of characters RANGE.\n\
-RANGE should be t (for all characters), nil (for the default value)\n\
+  "Return the value in CHAR-TABLE for a range of characters RANGE.\n\
+RANGE should be nil (for the default value)\n\
 a vector which identifies a character set or a row of a character set,\n\
-or a character code.")
-  (chartable, range)
-     Lisp_Object chartable, range;
+a character set name, or a character code.")
+  (char_table, range)
+     Lisp_Object char_table, range;
 {
   int i;
 
-  CHECK_CHAR_TABLE (chartable, 0);
-  
+  CHECK_CHAR_TABLE (char_table, 0);
+
   if (EQ (range, Qnil))
-    return XCHAR_TABLE (chartable)->defalt;
+    return XCHAR_TABLE (char_table)->defalt;
   else if (INTEGERP (range))
-    return Faref (chartable, range);
-  else if (VECTORP (range))
+    return Faref (char_table, range);
+  else if (SYMBOLP (range))
     {
-      for (i = 0; i < XVECTOR (range)->size - 1; i++)
-       chartable = Faref (chartable, XVECTOR (range)->contents[i]);
+      Lisp_Object charset_info;
 
-      if (EQ (XVECTOR (range)->contents[i], Qnil))
-       return XCHAR_TABLE (chartable)->defalt;
+      charset_info = Fget (range, Qcharset);
+      CHECK_VECTOR (charset_info, 0);
+
+      return Faref (char_table,
+                   make_number (XINT (XVECTOR (charset_info)->contents[0])
+                                + 128));
+    }
+  else if (VECTORP (range))
+    {
+      if (XVECTOR (range)->size == 1)
+       return Faref (char_table,
+                     make_number (XINT (XVECTOR (range)->contents[0]) + 128));
       else
-       return Faref (chartable, XVECTOR (range)->contents[i]);
+       {
+         int size = XVECTOR (range)->size;
+         Lisp_Object *val = XVECTOR (range)->contents;
+         Lisp_Object ch = Fmake_char_internal (size <= 0 ? Qnil : val[0],
+                                               size <= 1 ? Qnil : val[1],
+                                               size <= 2 ? Qnil : val[2]);
+         return Faref (char_table, ch);
+       }
     }
   else
     error ("Invalid RANGE argument to `char-table-range'");
@@ -1287,93 +1792,206 @@ or a character code.")
 
 DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range,
        3, 3, 0,
-  "Set the value in CHARTABLE for a range of characters RANGE to VALUE.\n\
+  "Set the value in CHAR-TABLE for a range of characters RANGE to VALUE.\n\
 RANGE should be t (for all characters), nil (for the default value)\n\
 a vector which identifies a character set or a row of a character set,\n\
-or a character code.")
-  (chartable, range, value)
-     Lisp_Object chartable, range, value;
+a coding system, or a character code.")
+  (char_table, range, value)
+     Lisp_Object char_table, range, value;
 {
   int i;
 
-  CHECK_CHAR_TABLE (chartable, 0);
-  
+  CHECK_CHAR_TABLE (char_table, 0);
+
   if (EQ (range, Qt))
     for (i = 0; i < CHAR_TABLE_ORDINARY_SLOTS; i++)
-      XCHAR_TABLE (chartable)->contents[i] = value;
+      XCHAR_TABLE (char_table)->contents[i] = value;
   else if (EQ (range, Qnil))
-    XCHAR_TABLE (chartable)->defalt = value;
+    XCHAR_TABLE (char_table)->defalt = value;
+  else if (SYMBOLP (range))
+    {
+      Lisp_Object charset_info;
+
+      charset_info = Fget (range, Qcharset);
+      CHECK_VECTOR (charset_info, 0);
+
+      return Faset (char_table,
+                   make_number (XINT (XVECTOR (charset_info)->contents[0])
+                                + 128),
+                   value);
+    }
   else if (INTEGERP (range))
-    Faset (chartable, range, value);
+    Faset (char_table, range, value);
   else if (VECTORP (range))
     {
-      for (i = 0; i < XVECTOR (range)->size - 1; i++)
-       chartable = Faref (chartable, XVECTOR (range)->contents[i]);
-
-      if (EQ (XVECTOR (range)->contents[i], Qnil))
-       XCHAR_TABLE (chartable)->defalt = value;
+      if (XVECTOR (range)->size == 1)
+       return Faset (char_table,
+                     make_number (XINT (XVECTOR (range)->contents[0]) + 128),
+                     value);
       else
-       Faset (chartable, XVECTOR (range)->contents[i], value);
+       {
+         int size = XVECTOR (range)->size;
+         Lisp_Object *val = XVECTOR (range)->contents;
+         Lisp_Object ch = Fmake_char_internal (size <= 0 ? Qnil : val[0],
+                                               size <= 1 ? Qnil : val[1],
+                                               size <= 2 ? Qnil : val[2]);
+         return Faset (char_table, ch, value);
+       }
     }
   else
     error ("Invalid RANGE argument to `set-char-table-range'");
 
   return value;
 }
+
+DEFUN ("set-char-table-default", Fset_char_table_default,
+       Sset_char_table_default, 3, 3, 0,
+  "Set the default value in CHAR-TABLE for a generic character CHAR to VALUE.\n\
+The generic character specifies the group of characters.\n\
+See also the documentation of make-char.")
+  (char_table, ch, value)
+     Lisp_Object char_table, ch, value;
+{
+  int c, i, charset, code1, code2;
+  Lisp_Object temp;
+
+  CHECK_CHAR_TABLE (char_table, 0);
+  CHECK_NUMBER (ch, 1);
+
+  c = XINT (ch);
+  SPLIT_NON_ASCII_CHAR (c, charset, code1, code2);
+  if (! CHARSET_DEFINED_P (charset))
+    invalid_character (c);
+
+  if (charset == CHARSET_ASCII)
+    return (XCHAR_TABLE (char_table)->defalt = value);
+
+  /* Even if C is not a generic char, we had better behave as if a
+     generic char is specified.  */
+  if (CHARSET_DIMENSION (charset) == 1)
+    code1 = 0;
+  temp = XCHAR_TABLE (char_table)->contents[charset + 128];
+  if (!code1)
+    {
+      if (SUB_CHAR_TABLE_P (temp))
+       XCHAR_TABLE (temp)->defalt = value;
+      else
+       XCHAR_TABLE (char_table)->contents[charset + 128] = value;
+      return value;
+    }
+  char_table = temp;
+  if (! SUB_CHAR_TABLE_P (char_table))
+    char_table = (XCHAR_TABLE (char_table)->contents[charset + 128]
+           = make_sub_char_table (temp));
+  temp = XCHAR_TABLE (char_table)->contents[code1];
+  if (SUB_CHAR_TABLE_P (temp))
+    XCHAR_TABLE (temp)->defalt = value;
+  else
+    XCHAR_TABLE (char_table)->contents[code1] = value;
+  return value;
+}
+
+/* Look up the element in TABLE at index CH,
+   and return it as an integer.
+   If the element is nil, return CH itself.
+   (Actually we do that for any non-integer.)  */
+
+int
+char_table_translate (table, ch)
+     Lisp_Object table;
+     int ch;
+{
+  Lisp_Object value;
+  value = Faref (table, make_number (ch));
+  if (! INTEGERP (value))
+    return ch;
+  return XINT (value);
+}
 \f
-/* Map C_FUNCTION or FUNCTION over CHARTABLE, calling it for each
+/* Map C_FUNCTION or FUNCTION over SUBTABLE, calling it for each
    character or group of characters that share a value.
    DEPTH is the current depth in the originally specified
    chartable, and INDICES contains the vector indices
-   for the levels our callers have descended.  */
+   for the levels our callers have descended.
+
+   ARG is passed to C_FUNCTION when that is called.  */
 
 void
-map_char_table (c_function, function, chartable, depth, indices)
-     Lisp_Object (*c_function) (), function, chartable, depth, *indices;
+map_char_table (c_function, function, subtable, arg, depth, indices)
+     void (*c_function) P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
+     Lisp_Object function, subtable, arg, *indices;
+     int depth;
 {
-  int i;
-  int size = CHAR_TABLE_ORDINARY_SLOTS;
-
-  /* Make INDICES longer if we are about to fill it up.  */
-  if ((depth % 10) == 9)
-    {
-      Lisp_Object *new_indices
-       = (Lisp_Object *) alloca ((depth += 10) * sizeof (Lisp_Object));
-      bcopy (indices, new_indices, depth * sizeof (Lisp_Object));
-      indices = new_indices;
-    }
-
-  for (i = 0; i < size; i++)
-    {
-      Lisp_Object elt;
-      indices[depth] = i;
-      elt = XCHAR_TABLE (chartable)->contents[i];
-      if (CHAR_TABLE_P (elt))
-       map_char_table (chartable, c_function, function, depth + 1, indices);
-      else if (c_function)
-       (*c_function) (depth + 1, indices, elt);
-      /* Here we should handle all cases where the range is a single character
-        by passing that character as a number.  Currently, that is
-        all the time, but with the MULE code this will have to be changed.  */
-      else if (depth == 0)
-       call2 (function, make_number (i), elt);
+  int i, to;
+
+  if (depth == 0)
+    {
+      /* At first, handle ASCII and 8-bit European characters.  */
+      for (i = 0; i < CHAR_TABLE_SINGLE_BYTE_SLOTS; i++)
+       {
+         Lisp_Object elt = XCHAR_TABLE (subtable)->contents[i];
+         if (c_function)
+           (*c_function) (arg, make_number (i), elt);
+         else
+           call2 (function, make_number (i), elt);
+       }
+#if 0 /* If the char table has entries for higher characters,
+        we should report them.  */
+      if (NILP (current_buffer->enable_multibyte_characters))
+       return;
+#endif
+      to = CHAR_TABLE_ORDINARY_SLOTS;
+    }
+  else
+    {
+      i = 32;
+      to = SUB_CHAR_TABLE_ORDINARY_SLOTS;
+    }
+
+  for (; i < to; i++)
+    {
+      Lisp_Object elt = XCHAR_TABLE (subtable)->contents[i];
+
+      XSETFASTINT (indices[depth], i);
+
+      if (SUB_CHAR_TABLE_P (elt))
+       {
+         if (depth >= 3)
+           error ("Too deep char table");
+         map_char_table (c_function, function, elt, arg, depth + 1, indices);
+       }
       else
-       call2 (function, Fvector (depth + 1, indices), elt);
+       {
+         int charset = XFASTINT (indices[0]) - 128, 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);
+           }
+       }
     }
 }
 
 DEFUN ("map-char-table", Fmap_char_table, Smap_char_table,
   2, 2, 0,
-  "Call FUNCTION for each range of like characters in CHARTABLE.\n\
+  "Call FUNCTION for each (normal and generic) characters in CHAR-TABLE.\n\
 FUNCTION is called with two arguments--a key and a value.\n\
-The key is always a possible RANGE argument to `set-char-table-range'.")
-  (function, chartable)
-     Lisp_Object function, chartable;
+The key is always a possible IDX argument to `aref'.")
+  (function, char_table)
+     Lisp_Object function, char_table;
 {
-  Lisp_Object keyvec;
-  Lisp_Object *indices = (Lisp_Object *) alloca (10 * sizeof (Lisp_Object));
+  /* The depth of char table is at most 3. */
+  Lisp_Object indices[3];
 
-  map_char_table (NULL, function, chartable, 0, indices);
+  CHECK_CHAR_TABLE (char_table, 1);
+
+  map_char_table (NULL, function, char_table, char_table, 0, indices);
   return Qnil;
 }
 \f
@@ -1434,9 +2052,9 @@ Only the last argument is not altered, and need not be a list.")
 }
 \f
 /* This is the guts of all mapping functions.
- Apply fn to each element of seq, one by one,
- storing the results into elements of vals, a C vector of Lisp_Objects.
leni is the length of vals, which should also be the length of seq. */
+ Apply FN to each element of SEQ, one by one,
+ storing the results into elements of VALS, a C vector of Lisp_Objects.
LENI is the length of VALS, which should also be the length of SEQ.  */
 
 static void
 mapcar1 (leni, vals, fn, seq)
@@ -1467,21 +2085,52 @@ mapcar1 (leni, vals, fn, seq)
          vals[i] = call1 (fn, dummy);
        }
     }
-  else if (STRINGP (seq))
+  else if (BOOL_VECTOR_P (seq))
+    {
+      for (i = 0; i < leni; i++)
+       {
+         int byte;
+         byte = XBOOL_VECTOR (seq)->data[i / BITS_PER_CHAR];
+         if (byte & (1 << (i % BITS_PER_CHAR)))
+           dummy = Qt;
+         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);
        }
     }
+  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;)
+       {
+         int c;
+         int i_before = i;
+
+         FETCH_STRING_CHAR_ADVANCE (c, seq, i, i_byte);
+         XSETFASTINT (dummy, c);
+         vals[i_before] = call1 (fn, dummy);
+       }
+    }
   else   /* Must be a list, since Flength did not get an error */
     {
       tail = seq;
       for (i = 0; i < leni; i++)
        {
          vals[i] = call1 (fn, Fcar (tail));
-         tail = Fcdr (tail);
+         tail = XCONS (tail)->cdr;
        }
     }
 
@@ -1489,11 +2138,12 @@ mapcar1 (leni, vals, fn, seq)
 }
 
 DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0,
-  "Apply FN to each element of SEQ, and concat the results as strings.\n\
-In between each pair of results, stick in SEP.\n\
-Thus, \" \" as SEP results in spaces between the values returned by FN.")
-  (fn, seq, sep)
-     Lisp_Object fn, seq, sep;
+  "Apply FUNCTION to each element of SEQUENCE, and concat the results as strings.\n\
+In between each pair of results, stick in SEPARATOR.  Thus, \" \" as\n\
+SEPARATOR results in spaces between the values returned by FUNCTION.\n\
+SEQUENCE may be a list, a vector, a bool-vector, or a string.")
+  (function, sequence, separator)
+     Lisp_Object function, sequence, separator;
 {
   Lisp_Object len;
   register int leni;
@@ -1502,22 +2152,22 @@ Thus, \" \" as SEP results in spaces between the values returned by FN.")
   register int i;
   struct gcpro gcpro1;
 
-  len = Flength (seq);
+  len = Flength (sequence);
   leni = XINT (len);
   nargs = leni + leni - 1;
   if (nargs < 0) return build_string ("");
 
   args = (Lisp_Object *) alloca (nargs * sizeof (Lisp_Object));
 
-  GCPRO1 (sep);
-  mapcar1 (leni, args, fn, seq);
+  GCPRO1 (separator);
+  mapcar1 (leni, args, function, sequence);
   UNGCPRO;
 
   for (i = leni - 1; i >= 0; i--)
     args[i + i] = args[i];
-      
+
   for (i = 1; i < nargs; i += 2)
-    args[i] = sep;
+    args[i] = separator;
 
   return Fconcat (nargs, args);
 }
@@ -1525,19 +2175,19 @@ Thus, \" \" as SEP results in spaces between the values returned by FN.")
 DEFUN ("mapcar", Fmapcar, Smapcar, 2, 2, 0,
   "Apply FUNCTION to each element of SEQUENCE, and make a list of the results.\n\
 The result is a list just as long as SEQUENCE.\n\
-SEQUENCE may be a list, a vector or a string.")
-  (fn, seq)
-     Lisp_Object fn, seq;
+SEQUENCE may be a list, a vector, a bool-vector, or a string.")
+  (function, sequence)
+     Lisp_Object function, sequence;
 {
   register Lisp_Object len;
   register int leni;
   register Lisp_Object *args;
 
-  len = Flength (seq);
+  len = Flength (sequence);
   leni = XFASTINT (len);
   args = (Lisp_Object *) alloca (leni * sizeof (Lisp_Object));
 
-  mapcar1 (leni, args, fn, seq);
+  mapcar1 (leni, args, function, sequence);
 
   return Flist (leni, args);
 }
@@ -1557,8 +2207,10 @@ Also accepts Space to mean yes, or Delete to mean no.")
   register int answer;
   Lisp_Object xprompt;
   Lisp_Object args[2];
-  int ocech = cursor_in_echo_area;
   struct gcpro gcpro1, gcpro2;
+  int count = specpdl_ptr - specpdl;
+
+  specbind (Qcursor_in_echo_area, Qt);
 
   map = Fsymbol_value (intern ("query-replace-map"));
 
@@ -1568,8 +2220,10 @@ Also accepts Space to mean yes, or Delete to mean no.")
 
   while (1)
     {
+
 #ifdef HAVE_MENUS
       if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
+         && use_dialog_box
          && have_menus_p ())
        {
          Lisp_Object pane, menu;
@@ -1584,7 +2238,17 @@ Also accepts Space to mean yes, or Delete to mean no.")
        }
 #endif /* HAVE_MENUS */
       cursor_in_echo_area = 1;
-      message_nolog ("%s(y or n) ", XSTRING (xprompt)->data);
+      choose_minibuf_frame ();
+      message_with_string ("%s(y or n) ", xprompt, 0);
+
+      if (minibuffer_auto_raise)
+       {
+         Lisp_Object mini_frame;
+
+         mini_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
+
+         Fraise_frame (mini_frame);
+       }
 
       obj = read_filtered_event (1, 0, 0);
       cursor_in_echo_area = 0;
@@ -1592,7 +2256,7 @@ Also accepts Space to mean yes, or Delete to mean no.")
       QUIT;
 
       key = Fmake_vector (make_number (1), obj);
-      def = Flookup_key (map, key);
+      def = Flookup_key (map, key, Qt);
       answer_string = Fsingle_key_description (obj);
 
       if (EQ (def, intern ("skip")))
@@ -1638,11 +2302,11 @@ Also accepts Space to mean yes, or Delete to mean no.")
   if (! noninteractive)
     {
       cursor_in_echo_area = -1;
-      message_nolog ("%s(y or n) %c",
-                    XSTRING (xprompt)->data, answer ? 'y' : 'n');
-      cursor_in_echo_area = ocech;
+      message_with_string (answer ? "%s(y or n) y" : "%s(y or n) n",
+                          xprompt, 0);
     }
 
+  unbind_to (count, Qnil);
   return answer ? Qt : Qnil;
 }
 \f
@@ -1677,7 +2341,8 @@ and can edit it until it has been confirmed.")
   CHECK_STRING (prompt, 0);
 
 #ifdef HAVE_MENUS
-  if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event)) 
+  if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
+      && use_dialog_box
       && have_menus_p ())
     {
       Lisp_Object pane, menu, obj;
@@ -1702,7 +2367,8 @@ and can edit it until it has been confirmed.")
   while (1)
     {
       ans = Fdowncase (Fread_from_minibuffer (prompt, Qnil, Qnil, Qnil,
-                                             Qyes_or_no_p_history));
+                                             Qyes_or_no_p_history, Qnil,
+                                             Qnil));
       if (XSTRING (ans)->size == 3 && !strcmp (XSTRING (ans)->data, "yes"))
        {
          UNGCPRO;
@@ -1751,7 +2417,7 @@ Use this to conditionalize execution of lisp code based on the presence or\n\
 absence of emacs or environment extensions.\n\
 Use `provide' to declare that a feature is available.\n\
 This function looks at the value of the variable `features'.")
-     (feature)
+  (feature)
      Lisp_Object feature;
 {
   register Lisp_Object tem;
@@ -1762,7 +2428,7 @@ This function looks at the value of the variable `features'.")
 
 DEFUN ("provide", Fprovide, Sprovide, 1, 1, 0,
   "Announce that FEATURE is a feature of the current Emacs.")
-     (feature)
+  (feature)
      Lisp_Object feature;
 {
   register Lisp_Object tem;
@@ -1780,8 +2446,9 @@ DEFUN ("require", Frequire, Srequire, 1, 2, 0,
   "If feature FEATURE is not loaded, load it from FILENAME.\n\
 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.")
-     (feature, file_name)
+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'.")
+  (feature, file_name)
      Lisp_Object feature, file_name;
 {
   register Lisp_Object tem;
@@ -1797,12 +2464,12 @@ If FILENAME is omitted, the printname of FEATURE is used as the file name.")
       Vautoload_queue = Qt;
 
       Fload (NILP (file_name) ? Fsymbol_name (feature) : file_name,
-            Qnil, Qt, Qnil);
+            Qnil, Qt, Qnil, (NILP (file_name) ? Qt : Qnil));
 
       tem = Fmemq (feature, Vfeatures);
       if (NILP (tem))
        error ("Required feature %s was not provided",
-              XSYMBOL (feature)->name->data );
+              XSYMBOL (feature)->name->data);
 
       /* Once loading finishes, don't undo it.  */
       Vautoload_queue = Qt;
@@ -1811,6 +2478,91 @@ If FILENAME is omitted, the printname of FEATURE is used as the file name.")
   return feature;
 }
 \f
+/* Primitives for work of the "widget" library.
+   In an ideal world, this section would not have been necessary.
+   However, lisp function calls being as slow as they are, it turns
+   out that some functions in the widget library (wid-edit.el) are the
+   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,
+  "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\
+Unlike `plist-get', this allows you to distinguish between a missing\n\
+property and a property with the value nil.\n\
+The value is actually the tail of PLIST whose car is PROP.")
+  (plist, prop)
+     Lisp_Object plist, prop;
+{
+  while (CONSP (plist) && !EQ (XCAR (plist), prop))
+    {
+      QUIT;
+      plist = XCDR (plist);
+      plist = CDR (plist);
+    }
+  return plist;
+}
+
+DEFUN ("widget-put", Fwidget_put, Swidget_put, 3, 3, 0,
+  "In WIDGET, set PROPERTY to VALUE.\n\
+The value can later be retrieved with `widget-get'.")
+  (widget, property, value)
+     Lisp_Object widget, property, value;
+{
+  CHECK_CONS (widget, 1);
+  XCDR (widget) = Fplist_put (XCDR (widget), property, value);
+}
+
+DEFUN ("widget-get", Fwidget_get, Swidget_get, 2, 2, 0,
+  "In WIDGET, get the value of PROPERTY.\n\
+The value could either be specified when the widget was created, or\n\
+later with `widget-put'.")
+  (widget, property)
+     Lisp_Object widget, property;
+{
+  Lisp_Object tmp;
+
+  while (1)
+    {
+      if (NILP (widget))
+       return Qnil;
+      CHECK_CONS (widget, 1);
+      tmp = Fwidget_plist_member (XCDR (widget), property);
+      if (CONSP (tmp))
+       {
+         tmp = XCDR (tmp);
+         return CAR (tmp);
+       }
+      tmp = XCAR (widget);
+      if (NILP (tmp))
+       return Qnil;
+      widget = Fget (tmp, Qwidget_type);
+    }
+}
+
+DEFUN ("widget-apply", Fwidget_apply, Swidget_apply, 2, MANY, 0,
+  "Apply the value of WIDGET's PROPERTY to the widget itself.\n\
+ARGS are passed as extra arguments to the function.")
+  (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  /* This function can GC. */
+  Lisp_Object newargs[3];
+  struct gcpro gcpro1, gcpro2;
+  Lisp_Object result;
+
+  newargs[0] = Fwidget_get (args[0], args[1]);
+  newargs[1] = args[0];
+  newargs[2] = Flist (nargs - 2, args + 2);
+  GCPRO2 (newargs[0], newargs[2]);
+  result = Fapply (3, newargs);
+  UNGCPRO;
+  return result;
+}
+\f
+void
 syms_of_fns ()
 {
   Qstring_lessp = intern ("string-lessp");
@@ -1821,22 +2573,42 @@ syms_of_fns ()
   staticpro (&Qrequire);
   Qyes_or_no_p_history = intern ("yes-or-no-p-history");
   staticpro (&Qyes_or_no_p_history);
+  Qcursor_in_echo_area = intern ("cursor-in-echo-area");
+  staticpro (&Qcursor_in_echo_area);
+  Qwidget_type = intern ("widget-type");
+  staticpro (&Qwidget_type);
+
+  staticpro (&string_char_byte_cache_string);
+  string_char_byte_cache_string = Qnil;
+
+  Fset (Qyes_or_no_p_history, Qnil);
 
   DEFVAR_LISP ("features", &Vfeatures,
     "A list of symbols which are the features of the executing emacs.\n\
 Used by `featurep' and `require', and altered by `provide'.");
   Vfeatures = Qnil;
 
+  DEFVAR_BOOL ("use-dialog-box", &use_dialog_box,
+    "*Non-nil means mouse commands use dialog boxes to ask questions.\n\
+This applies to y-or-n and yes-or-no questions asked by commands\n\
+invoked by mouse clicks and mouse menu items.");
+  use_dialog_box = 1;
+
   defsubr (&Sidentity);
   defsubr (&Srandom);
   defsubr (&Slength);
   defsubr (&Ssafe_length);
+  defsubr (&Sstring_bytes);
   defsubr (&Sstring_equal);
   defsubr (&Sstring_lessp);
   defsubr (&Sappend);
   defsubr (&Sconcat);
   defsubr (&Svconcat);
   defsubr (&Scopy_sequence);
+  defsubr (&Sstring_make_multibyte);
+  defsubr (&Sstring_make_unibyte);
+  defsubr (&Sstring_as_multibyte);
+  defsubr (&Sstring_as_unibyte);
   defsubr (&Scopy_alist);
   defsubr (&Ssubstring);
   defsubr (&Snthcdr);
@@ -1866,6 +2638,7 @@ Used by `featurep' and `require', and altered by `provide'.");
   defsubr (&Sset_char_table_extra_slot);
   defsubr (&Schar_table_range);
   defsubr (&Sset_char_table_range);
+  defsubr (&Sset_char_table_default);
   defsubr (&Smap_char_table);
   defsubr (&Snconc);
   defsubr (&Smapcar);
@@ -1876,4 +2649,8 @@ Used by `featurep' and `require', and altered by `provide'.");
   defsubr (&Sfeaturep);
   defsubr (&Srequire);
   defsubr (&Sprovide);
+  defsubr (&Swidget_plist_member);
+  defsubr (&Swidget_put);
+  defsubr (&Swidget_get);
+  defsubr (&Swidget_apply);
 }