]> code.delx.au - gnu-emacs/blobdiff - src/fns.c
(Fnext_property_change): Properly offset interval
[gnu-emacs] / src / fns.c
index 69705af4319bde5d19810b429fd4bc973f33dc40..6ca612b2153a4bd3fa7897b64d4b68ffbb4f028d 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, 1997 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.
 
@@ -21,6 +21,11 @@ Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+
 /* Note on some machines this defines `vector' as a typedef,
    so make sure we don't use that name in this file.  */
 #undef vector
@@ -35,6 +40,9 @@ Boston, MA 02111-1307, USA.  */
 #include "intervals.h"
 #include "frame.h"
 #include "window.h"
+#if defined (HAVE_MENUS) && defined (HAVE_X_WINDOWS)
+#include "xterm.h"
+#endif
 
 #ifndef NULL
 #define NULL (void *)0
@@ -44,8 +52,6 @@ Boston, MA 02111-1307, USA.  */
    asked by mouse commands.  */
 int use_dialog_box;
 
-extern Lisp_Object Flookup_key ();
-
 extern int minibuffer_auto_raise;
 extern Lisp_Object minibuf_window;
 
@@ -55,6 +61,13 @@ 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.")
@@ -64,10 +77,6 @@ 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\
@@ -109,8 +118,8 @@ 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.\n\
 If the string contains multibyte characters, this is not the necessarily\n\
-the number of characters in the string; it is the number of bytes.\n\
-To get the number of characters, use `chars-in-string'")
+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;
 {
@@ -123,7 +132,9 @@ To get the number of characters, use `chars-in-string'")
   else if (VECTORP (sequence))
     XSETFASTINT (val, XVECTOR (sequence)->size);
   else if (CHAR_TABLE_P (sequence))
-    XSETFASTINT (val, CHAR_TABLE_ORDINARY_SLOTS);
+    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))
@@ -177,6 +188,16 @@ 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,
   "Return t if two strings have identical contents.\n\
 Case is significant, but text properties are ignored.\n\
@@ -192,12 +213,115 @@ Symbols are also allowed; their print names are used instead.")
   CHECK_STRING (s2, 1);
 
   if (XSTRING (s1)->size != XSTRING (s2)->size
-      || XSTRING (s1)->size_byte != XSTRING (s2)->size_byte
-      || bcmp (XSTRING (s1)->data, XSTRING (s2)->data, XSTRING (s1)->size_byte))
+      || STRING_BYTES (XSTRING (s1)) != STRING_BYTES (XSTRING (s2))
+      || bcmp (XSTRING (s1)->data, XSTRING (s2)->data, STRING_BYTES (XSTRING (s1))))
     return Qnil;
   return Qt;
 }
 
+DEFUN ("compare-strings", Fcompare_strings,
+       Scompare_strings, 6, 7, 0,
+  "Compare the contents of two strings, converting to multibyte if needed.\n\
+In string STR1, skip the first START1 characters and stop at END1.\n\
+In string STR2, skip the first START2 characters and stop at END2.\n\
+END1 and END2 default to the full lengths of the respective strings.\n\
+\n\
+Case is significant in this comparison if IGNORE-CASE is nil.\n\
+Unibyte strings are converted to multibyte for comparison.\n\
+\n\
+The value is t if the strings (or specified portions) match.\n\
+If string STR1 is less, the value is a negative number N;\n\
+  - 1 - N is the number of characters that match at the beginning.\n\
+If string STR1 is greater, the value is a positive number N;\n\
+  N - 1 is the number of characters that match at the beginning.")
+  (str1, start1, end1, str2, start2, end2, ignore_case)
+     Lisp_Object str1, start1, end1, start2, str2, end2, ignore_case;
+{
+  register int end1_char, end2_char;
+  register int i1, i1_byte, i2, i2_byte;
+
+  CHECK_STRING (str1, 0);
+  CHECK_STRING (str2, 1);
+  if (NILP (start1))
+    start1 = make_number (0);
+  if (NILP (start2))
+    start2 = make_number (0);
+  CHECK_NATNUM (start1, 2);
+  CHECK_NATNUM (start2, 3);
+  if (! NILP (end1))
+    CHECK_NATNUM (end1, 4);
+  if (! NILP (end2))
+    CHECK_NATNUM (end2, 4);
+
+  i1 = XINT (start1);
+  i2 = XINT (start2);
+
+  i1_byte = string_char_to_byte (str1, i1);
+  i2_byte = string_char_to_byte (str2, i2);
+
+  end1_char = XSTRING (str1)->size;
+  if (! NILP (end1) && end1_char > XINT (end1))
+    end1_char = XINT (end1);
+
+  end2_char = XSTRING (str2)->size;
+  if (! NILP (end2) && end2_char > XINT (end2))
+    end2_char = XINT (end2);
+
+  while (i1 < end1_char && i2 < end2_char)
+    {
+      /* When we find a mismatch, we must compare the
+        characters, not just the bytes.  */
+      int c1, c2;
+
+      if (STRING_MULTIBYTE (str1))
+       FETCH_STRING_CHAR_ADVANCE (c1, str1, i1, i1_byte);
+      else
+       {
+         c1 = XSTRING (str1)->data[i1++];
+         c1 = unibyte_char_to_multibyte (c1);
+       }
+
+      if (STRING_MULTIBYTE (str2))
+       FETCH_STRING_CHAR_ADVANCE (c2, str2, i2, i2_byte);
+      else
+       {
+         c2 = XSTRING (str2)->data[i2++];
+         c2 = unibyte_char_to_multibyte (c2);
+       }
+
+      if (c1 == c2)
+       continue;
+
+      if (! NILP (ignore_case))
+       {
+         Lisp_Object tem;
+
+         tem = Fupcase (make_number (c1));
+         c1 = XINT (tem);
+         tem = Fupcase (make_number (c2));
+         c2 = XINT (tem);
+       }
+
+      if (c1 == c2)
+       continue;
+
+      /* Note that I1 has already been incremented
+        past the character that we are comparing;
+        hence we don't add or subtract 1 here.  */
+      if (c1 < c2)
+       return make_number (- i1);
+      else
+       return make_number (i1);
+    }
+
+  if (i1 < end1_char)
+    return make_number (i1 - XINT (start1) + 1);
+  if (i2 < end2_char)
+    return make_number (- i1 + XINT (start1) - 1);
+
+  return Qt;
+}
+
 DEFUN ("string-lessp", Fstring_lessp, Sstring_lessp, 2, 2, 0,
   "Return t if first arg string is less than second in lexicographic order.\n\
 Case is significant.\n\
@@ -205,9 +329,8 @@ 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);
@@ -216,18 +339,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;
-  end = XSTRING (s1)->size_byte;
-  if (end > XSTRING (s2)->size_byte)
-    end = XSTRING (s2)->size_byte;
+  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_byte ? Qt : Qnil;
+  return i1 < XSTRING (s2)->size ? Qt : Qnil;
 }
 \f
 static Lisp_Object concat ();
@@ -428,8 +565,8 @@ concat (nargs, args, target_type, last_special)
       len = XFASTINT (Flength (this));
       if (target_type == Lisp_String)
        {
-         /* We must pay attention to a multibyte character which
-            takes more than one byte in 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;
@@ -445,6 +582,8 @@ concat (nargs, args, target_type, last_special)
                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)
              {
@@ -458,27 +597,36 @@ concat (nargs, args, target_type, last_special)
              }
          else if (STRINGP (this))
            {
-             result_len_byte += XSTRING (this)->size_byte;
              if (STRING_MULTIBYTE (this))
-               some_multibyte = 1;
+               {
+                 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;
     }
 
-  /* In `append', if all but last arg are nil, return last arg.  */
-  if (target_type == Lisp_Cons && EQ (val, Qnil))
-    return last_tail;
+  if (! some_multibyte)
+    result_len_byte = result_len;
 
   /* Create the output object.  */
   if (target_type == Lisp_Cons)
     val = Fmake_list (make_number (result_len), Qnil);
   else if (target_type == Lisp_Vectorlike)
     val = Fmake_vector (make_number (result_len), Qnil);
-  else
+  else if (some_multibyte)
     val = make_uninit_multibyte_string (result_len, result_len_byte);
+  else
+    val = make_uninit_string (result_len);
 
+  /* 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))
@@ -508,12 +656,20 @@ concat (nargs, args, target_type, last_special)
       if (STRINGP (this) && STRINGP (val)
          && STRING_MULTIBYTE (this) == some_multibyte)
        {
-         int thislen_byte = XSTRING (this)->size_byte;
+         int thislen_byte = STRING_BYTES (XSTRING (this));
          bcopy (XSTRING (this)->data, XSTRING (val)->data + toindex_byte,
-                XSTRING (this)->size_byte);
+                STRING_BYTES (XSTRING (this)));
          toindex_byte += thislen_byte;
          toindex += thisleni;
        }
+      /* Copy a single-byte string to a multibyte string.  */
+      else if (STRINGP (this) && STRINGP (val))
+       {
+         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)
@@ -525,47 +681,41 @@ concat (nargs, args, target_type, last_special)
            if (NILP (this)) break;
            if (CONSP (this))
              elt = XCONS (this)->car, this = XCONS (this)->cdr;
-           else
+           else if (thisindex >= thisleni)
+             break;
+           else if (STRINGP (this))
              {
-               if (thisindex >= thisleni) break;
-               if (STRINGP (this))
+               int c;
+               if (STRING_MULTIBYTE (this))
                  {
-                   if (STRING_MULTIBYTE (this))
-                     {
-                       int c;
-                       FETCH_STRING_CHAR_ADVANCE (c, this,
-                                                  thisindex,
-                                                  thisindex_byte);
-                       XSETFASTINT (elt, c);
-                     }
-                   else
-                     {
-                       unsigned char c;
-                       XSETFASTINT (elt, XSTRING (this)->data[thisindex++]);
-                       if (some_multibyte && XINT (elt) >= 0200
-                           && XINT (elt) < 0400)
-                         {
-                           c = XINT (elt);
-                           copy_text (&c, &c, 1, 0, 1);
-                           XSETINT (elt, c);
-                         }
-                     }
+                   FETCH_STRING_CHAR_ADVANCE (c, this,
+                                              thisindex,
+                                              thisindex_byte);
+                   XSETFASTINT (elt, c);
                  }
-               else if (BOOL_VECTOR_P (this))
+               else
                  {
-                   int size_in_chars
-                     = ((XBOOL_VECTOR (this)->size + BITS_PER_CHAR - 1)
-                        / BITS_PER_CHAR);
-                   int byte;
-                   byte = XBOOL_VECTOR (val)->data[thisindex / BITS_PER_CHAR];
-                   if (byte & (1 << (thisindex % BITS_PER_CHAR)))
-                     elt = Qt;
-                   else
-                     elt = Qnil;
+                   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 = XVECTOR (this)->contents[thisindex++];
+                 elt = Qnil;
+               thisindex++;
              }
+           else
+             elt = XVECTOR (this)->contents[thisindex++];
 
            /* Store this element into the result.  */
            if (toindex < 0)
@@ -581,8 +731,8 @@ concat (nargs, args, target_type, last_special)
                CHECK_NUMBER (elt, 0);
                if (SINGLE_BYTE_CHAR_P (XINT (elt)))
                  {
-                   XSTRING (val)->data[toindex++] = XINT (elt);
-                   toindex_byte++;
+                   XSTRING (val)->data[toindex_byte++] = XINT (elt);
+                   toindex++;
                  }
                else
                  /* If we have any multibyte characters,
@@ -608,6 +758,10 @@ concat (nargs, args, target_type, last_special)
   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
@@ -615,20 +769,65 @@ string_char_to_byte (string, char_index)
      Lisp_Object string;
      int char_index;
 {
-  int i = 0, i_byte = 0;
+  int i, i_byte;
+  int best_below, best_below_byte;
+  int best_above, best_above_byte;
 
   if (! STRING_MULTIBYTE (string))
     return char_index;
 
-  while (i < 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
     {
-      int c;
-      FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte);
+      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
@@ -636,22 +835,67 @@ string_byte_to_char (string, byte_index)
      Lisp_Object string;
      int byte_index;
 {
-  int i = 0, i_byte = 0;
+  int i, i_byte;
+  int best_below, best_below_byte;
+  int best_above, best_above_byte;
 
   if (! STRING_MULTIBYTE (string))
     return byte_index;
 
-  while (i_byte < 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))
     {
-      int c;
-      FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte);
+      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 0200 through 0377 are converted
+   Single-byte characters 0240 through 0377 are converted
    by adding nonascii_insert_offset to each.  */
 
 Lisp_Object
@@ -666,8 +910,13 @@ string_make_multibyte (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, XSTRING (string)->size_byte,
+  copy_text (XSTRING (string)->data, buf, STRING_BYTES (XSTRING (string)),
             0, 1);
 
   return make_multibyte_string (buf, XSTRING (string)->size, nbytes);
@@ -686,11 +935,76 @@ string_make_unibyte (string)
 
   buf = (unsigned char *) alloca (XSTRING (string)->size);
 
-  copy_text (XSTRING (string)->data, buf, XSTRING (string)->size_byte,
+  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.\n\
+The function `unibyte-char-to-multibyte' is used to convert\n\
+each unibyte character to a multibyte character.")
+  (string)
+     Lisp_Object string;
+{
+  CHECK_STRING (string, 0);
+
+  return string_make_multibyte (string);
+}
+
+DEFUN ("string-make-unibyte", Fstring_make_unibyte, Sstring_make_unibyte,
+       1, 1, 0,
+  "Return the unibyte equivalent of STRING.\n\
+Multibyte character codes are converted to unibyte\n\
+by using just the low 8 bits.")
+  (string)
+     Lisp_Object string;
+{
+  CHECK_STRING (string, 0);
+
+  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;
+{
+  CHECK_STRING (string, 0);
+
+  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;
+{
+  CHECK_STRING (string, 0);
+
+  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,
   "Return a copy of ALIST.\n\
@@ -743,7 +1057,7 @@ This function allows vectors as well as strings.")
   if (STRINGP (string))
     {
       size = XSTRING (string)->size;
-      size_byte = XSTRING (string)->size_byte;
+      size_byte = STRING_BYTES (XSTRING (string));
     }
   else
     size = XVECTOR (string)->size;
@@ -777,10 +1091,11 @@ This function allows vectors as well as strings.")
 
   if (STRINGP (string))
     {
-      res = make_multibyte_string (XSTRING (string)->data + from_byte,
-                                  to_char - from_char, to_byte - from_byte);
-      copy_text_properties (from_char, to_char, string,
-                           make_number (0), res, Qnil);
+      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,
@@ -807,7 +1122,7 @@ substring_both (string, from, from_byte, to, to_byte)
   if (STRINGP (string))
     {
       size = XSTRING (string)->size;
-      size_byte = XSTRING (string)->size_byte;
+      size_byte = STRING_BYTES (XSTRING (string));
     }
   else
     size = XVECTOR (string)->size;
@@ -817,9 +1132,11 @@ substring_both (string, from, from_byte, to, to_byte)
 
   if (STRINGP (string))
     {
-      res = make_multibyte_string (XSTRING (string)->data + from_byte,
-                                  to - from, to_byte - from_byte);
-      copy_text_properties (from, to, string, make_number (0), res, Qnil);
+      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,
@@ -1372,6 +1689,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.  */
@@ -1396,10 +1715,10 @@ internal_equal (o1, o2, depth)
     case Lisp_String:
       if (XSTRING (o1)->size != XSTRING (o2)->size)
        return 0;
-      if (XSTRING (o1)->size_byte != XSTRING (o2)->size_byte)
+      if (STRING_BYTES (XSTRING (o1)) != STRING_BYTES (XSTRING (o2)))
        return 0;
       if (bcmp (XSTRING (o1)->data, XSTRING (o2)->data,
-               XSTRING (o1)->size_byte))
+               STRING_BYTES (XSTRING (o1))))
        return 0;
       return 1;
     }
@@ -1543,9 +1862,9 @@ DEFUN ("set-char-table-extra-slot", Fset_char_table_extra_slot,
 DEFUN ("char-table-range", Fchar_table_range, Schar_table_range,
        2, 2, 0,
   "Return the value in CHAR-TABLE for a range of characters RANGE.\n\
-RANGE should be t (for all characters), nil (for the default value)\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.")
+a character set name, or a character code.")
   (char_table, range)
      Lisp_Object char_table, range;
 {
@@ -1557,10 +1876,22 @@ or a character code.")
     return XCHAR_TABLE (char_table)->defalt;
   else if (INTEGERP (range))
     return Faref (char_table, range);
+  else if (SYMBOLP (range))
+    {
+      Lisp_Object charset_info;
+
+      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, XVECTOR (range)->contents[0]);
+       return Faref (char_table,
+                     make_number (XINT (XVECTOR (range)->contents[0]) + 128));
       else
        {
          int size = XVECTOR (range)->size;
@@ -1580,7 +1911,7 @@ DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range,
   "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.")
+a coding system, or a character code.")
   (char_table, range, value)
      Lisp_Object char_table, range, value;
 {
@@ -1593,12 +1924,26 @@ or a character code.")
       XCHAR_TABLE (char_table)->contents[i] = value;
   else if (EQ (range, Qnil))
     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 (char_table, range, value);
   else if (VECTORP (range))
     {
       if (XVECTOR (range)->size == 1)
-       return Faset (char_table, XVECTOR (range)->contents[0], value);
+       return Faset (char_table,
+                     make_number (XINT (XVECTOR (range)->contents[0]) + 128),
+                     value);
       else
        {
          int size = XVECTOR (range)->size;
@@ -1632,7 +1977,7 @@ See also the documentation of make-char.")
   c = XINT (ch);
   SPLIT_NON_ASCII_CHAR (c, charset, code1, code2);
   if (! CHARSET_DEFINED_P (charset))
-    error ("Invalid character: %d", c);
+    invalid_character (c);
 
   if (charset == CHARSET_ASCII)
     return (XCHAR_TABLE (char_table)->defalt = value);
@@ -1661,6 +2006,23 @@ See also the documentation of make-char.")
     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 SUBTABLE, calling it for each
    character or group of characters that share a value.
@@ -1839,6 +2201,20 @@ mapcar1 (leni, vals, fn, seq)
          vals[i] = call1 (fn, dummy);
        }
     }
+  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.  */
@@ -1851,15 +2227,17 @@ mapcar1 (leni, vals, fn, seq)
   else if (STRINGP (seq))
     {
       /* Multi-byte string.  */
-      int len_byte = XSTRING (seq)->size_byte;
+      int len_byte = STRING_BYTES (XSTRING (seq));
       int i_byte;
 
       for (i = 0, i_byte = 0; i < leni;)
        {
          int c;
-         FETCH_STRING_CHAR_ADVANCE (c, seq, i, i_byte)
+         int i_before = i;
+
+         FETCH_STRING_CHAR_ADVANCE (c, seq, i, i_byte);
          XSETFASTINT (dummy, c);
-         vals[i] = call1 (fn, dummy);
+         vals[i_before] = call1 (fn, dummy);
        }
     }
   else   /* Must be a list, since Flength did not get an error */
@@ -1878,7 +2256,8 @@ mapcar1 (leni, vals, fn, seq)
 DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0,
   "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.")
+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;
 {
@@ -1912,7 +2291,7 @@ SEPARATOR results in spaces between the values returned by FUNCTION.")
 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.")
+SEQUENCE may be a list, a vector, a bool-vector, or a string.")
   (function, sequence)
      Lisp_Object function, sequence;
 {
@@ -2124,24 +2503,31 @@ and can edit it until it has been confirmed.")
     }
 }
 \f
-DEFUN ("load-average", Fload_average, Sload_average, 0, 0, 0,
+DEFUN ("load-average", Fload_average, Sload_average, 0, 1, 0,
   "Return list of 1 minute, 5 minute and 15 minute load averages.\n\
 Each of the three load averages is multiplied by 100,\n\
 then converted to integer.\n\
+When USE-FLOATS is non-nil, floats will be used instead of integers.\n\
+These floats are not multiplied by 100.\n\n\
 If the 5-minute or 15-minute load averages are not available, return a\n\
 shortened list, containing only those averages which are available.")
-  ()
+  (use_floats)
+     Lisp_Object use_floats;
 {
   double load_ave[3];
   int loads = getloadavg (load_ave, 3);
-  Lisp_Object ret;
+  Lisp_Object ret = Qnil;
 
   if (loads < 0)
     error ("load-average not implemented for this operating system");
 
-  ret = Qnil;
-  while (loads > 0)
-    ret = Fcons (make_number ((int) (load_ave[--loads] * 100.0)), ret);
+  while (loads-- > 0)
+    {
+      Lisp_Object load = (NILP (use_floats) ?
+                         make_number ((int) (100.0 * load_ave[loads]))
+                         : make_float (load_ave[loads]));
+      ret = Fcons (load, ret);
+    }
 
   return ret;
 }
@@ -2183,7 +2569,8 @@ 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.")
+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;
 {
@@ -2298,6 +2685,7 @@ ARGS are passed as extra arguments to the function.")
   return result;
 }
 \f
+void
 syms_of_fns ()
 {
   Qstring_lessp = intern ("string-lessp");
@@ -2313,6 +2701,9 @@ syms_of_fns ()
   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,
@@ -2330,12 +2721,18 @@ invoked by mouse clicks and mouse menu items.");
   defsubr (&Srandom);
   defsubr (&Slength);
   defsubr (&Ssafe_length);
+  defsubr (&Sstring_bytes);
   defsubr (&Sstring_equal);
+  defsubr (&Scompare_strings);
   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);