(translate_char): Accept list of translation tables.
[bpt/emacs.git] / src / fns.c
index ce8efbf..fa99293 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -1,5 +1,5 @@
 /* Random utility Lisp functions.
 /* Random utility Lisp functions.
-   Copyright (C) 1985, 86, 87, 93, 94, 95, 97, 98, 99, 2000, 2001, 2002
+   Copyright (C) 1985, 86, 87, 93, 94, 95, 97, 98, 99, 2000, 2001, 02, 2003
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -26,15 +26,20 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #include <time.h>
 
 #endif
 #include <time.h>
 
+#ifndef MAC_OSX
+/* On Mac OS X, defining this conflicts with precompiled headers.  */
+
 /* Note on some machines this defines `vector' as a typedef,
    so make sure we don't use that name in this file.  */
 #undef vector
 #define vector *****
 
 /* Note on some machines this defines `vector' as a typedef,
    so make sure we don't use that name in this file.  */
 #undef vector
 #define vector *****
 
+#endif  /* ! MAC_OSX */
+
 #include "lisp.h"
 #include "commands.h"
 #include "lisp.h"
 #include "commands.h"
-#include "charset.h"
-
+#include "character.h"
+#include "coding.h"
 #include "buffer.h"
 #include "keyboard.h"
 #include "keymap.h"
 #include "buffer.h"
 #include "keyboard.h"
 #include "keymap.h"
@@ -47,7 +52,7 @@ Boston, MA 02111-1307, USA.  */
 #endif
 
 #ifndef NULL
 #endif
 
 #ifndef NULL
-#define NULL (void *)0
+#define NULL ((POINTER_TYPE *)0)
 #endif
 
 /* Nonzero enables use of dialog boxes for questions
 #endif
 
 /* Nonzero enables use of dialog boxes for questions
@@ -56,11 +61,13 @@ int use_dialog_box;
 
 extern int minibuffer_auto_raise;
 extern Lisp_Object minibuf_window;
 
 extern int minibuffer_auto_raise;
 extern Lisp_Object minibuf_window;
+extern Lisp_Object Vlocale_coding_system;
 
 Lisp_Object Qstring_lessp, Qprovide, Qrequire;
 Lisp_Object Qyes_or_no_p_history;
 Lisp_Object Qcursor_in_echo_area;
 Lisp_Object Qwidget_type;
 
 Lisp_Object Qstring_lessp, Qprovide, Qrequire;
 Lisp_Object Qyes_or_no_p_history;
 Lisp_Object Qcursor_in_echo_area;
 Lisp_Object Qwidget_type;
+Lisp_Object Qcodeset, Qdays, Qmonths, Qpaper;
 
 extern Lisp_Object Qinput_method_function;
 
 
 extern Lisp_Object Qinput_method_function;
 
@@ -201,7 +208,7 @@ which is at least the number of distinct elements. */)
   return length;
 }
 
   return length;
 }
 
-DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0, 
+DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0,
        doc: /* Return the number of bytes in STRING.
 If STRING is a multibyte string, this is greater than the length of STRING. */)
      (string)
        doc: /* Return the number of bytes in STRING.
 If STRING is a multibyte string, this is greater than the length of STRING. */)
      (string)
@@ -443,27 +450,6 @@ usage: (vconcat &rest SEQUENCES)   */)
   return concat (nargs, args, Lisp_Vectorlike, 0);
 }
 
   return concat (nargs, args, Lisp_Vectorlike, 0);
 }
 
-/* Return 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,
        doc: /* Return a copy of a list, vector, string or char-table.
 
 DEFUN ("copy-sequence", Fcopy_sequence, Scopy_sequence, 1, 1, 0,
        doc: /* Return a copy of a list, vector, string or char-table.
@@ -476,24 +462,7 @@ with the original. */)
 
   if (CHAR_TABLE_P (arg))
     {
 
   if (CHAR_TABLE_P (arg))
     {
-      int i;
-      Lisp_Object copy;
-
-      copy = Fmake_char_table (XCHAR_TABLE (arg)->purpose, Qnil);
-      /* Copy all the slots, including the extra ones.  */
-      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]
-           = copy_sub_char_table (XCHAR_TABLE (copy)->contents[i]);
-
-      return copy;
+      return copy_char_table (arg);
     }
 
   if (BOOL_VECTOR_P (arg))
     }
 
   if (BOOL_VECTOR_P (arg))
@@ -513,6 +482,7 @@ with the original. */)
   return concat (1, &arg, CONSP (arg) ? Lisp_Cons : XTYPE (arg), 0);
 }
 
   return concat (1, &arg, CONSP (arg) ? Lisp_Cons : XTYPE (arg), 0);
 }
 
+#if 0                          /* unused */
 /* In string STR of length LEN, see if bytes before STR[I] combine
    with bytes after STR[I] to form a single character.  If so, return
    the number of bytes after STR[I] which combine in this way.
 /* In string STR of length LEN, see if bytes before STR[I] combine
    with bytes after STR[I] to form a single character.  If so, return
    the number of bytes after STR[I] which combine in this way.
@@ -533,6 +503,7 @@ count_combining (str, len, i)
   PARSE_MULTIBYTE_SEQ (str + j, len - j, bytes);
   return (bytes <= i - j ? 0 : bytes - (i - j));
 }
   PARSE_MULTIBYTE_SEQ (str + j, len - j, bytes);
   return (bytes <= i - j ? 0 : bytes - (i - j));
 }
+#endif
 
 /* This structure holds information of an argument of `concat' that is
    a string and has text properties to be copied.  */
 
 /* This structure holds information of an argument of `concat' that is
    a string and has text properties to be copied.  */
@@ -616,11 +587,11 @@ concat (nargs, args, target_type, last_special)
            for (i = 0; i < len; i++)
              {
                ch = XVECTOR (this)->contents[i];
            for (i = 0; i < len; i++)
              {
                ch = XVECTOR (this)->contents[i];
-               if (! INTEGERP (ch))
-                 wrong_type_argument (Qintegerp, ch);
+               if (! CHARACTERP (ch))
+                 wrong_type_argument (Qcharacterp, ch);
                this_len_byte = CHAR_BYTES (XINT (ch));
                result_len_byte += this_len_byte;
                this_len_byte = CHAR_BYTES (XINT (ch));
                result_len_byte += this_len_byte;
-               if (!SINGLE_BYTE_CHAR_P (XINT (ch)))
+               if (! ASCII_CHAR_P (XINT (ch)) && ! CHAR_BYTE8_P (XINT (ch)))
                  some_multibyte = 1;
              }
          else if (BOOL_VECTOR_P (this) && XBOOL_VECTOR (this)->size > 0)
                  some_multibyte = 1;
              }
          else if (BOOL_VECTOR_P (this) && XBOOL_VECTOR (this)->size > 0)
@@ -629,11 +600,11 @@ concat (nargs, args, target_type, last_special)
            for (; CONSP (this); this = XCDR (this))
              {
                ch = XCAR (this);
            for (; CONSP (this); this = XCDR (this))
              {
                ch = XCAR (this);
-               if (! INTEGERP (ch))
-                 wrong_type_argument (Qintegerp, ch);
+               if (! CHARACTERP (ch))
+                 wrong_type_argument (Qcharacterp, ch);
                this_len_byte = CHAR_BYTES (XINT (ch));
                result_len_byte += this_len_byte;
                this_len_byte = CHAR_BYTES (XINT (ch));
                result_len_byte += this_len_byte;
-               if (!SINGLE_BYTE_CHAR_P (XINT (ch)))
+               if (! ASCII_CHAR_P (XINT (ch)) && ! CHAR_BYTE8_P (XINT (ch)))
                  some_multibyte = 1;
              }
          else if (STRINGP (this))
                  some_multibyte = 1;
              }
          else if (STRINGP (this))
@@ -696,25 +667,17 @@ concat (nargs, args, target_type, last_special)
          && STRING_MULTIBYTE (this) == some_multibyte)
        {
          int thislen_byte = SBYTES (this);
          && STRING_MULTIBYTE (this) == some_multibyte)
        {
          int thislen_byte = SBYTES (this);
-         int combined;
 
          bcopy (SDATA (this), SDATA (val) + toindex_byte,
                 SBYTES (this));
 
          bcopy (SDATA (this), SDATA (val) + toindex_byte,
                 SBYTES (this));
-         combined =  (some_multibyte && toindex_byte > 0
-                      ? count_combining (SDATA (val),
-                                         toindex_byte + thislen_byte,
-                                         toindex_byte)
-                      : 0);
          if (! NULL_INTERVAL_P (STRING_INTERVALS (this)))
            {
              textprops[num_textprops].argnum = argnum;
          if (! NULL_INTERVAL_P (STRING_INTERVALS (this)))
            {
              textprops[num_textprops].argnum = argnum;
-             /* We ignore text properties on characters being combined.  */
-             textprops[num_textprops].from = combined;
+             textprops[num_textprops].from = 0;
              textprops[num_textprops++].to = toindex;
            }
          toindex_byte += thislen_byte;
              textprops[num_textprops++].to = toindex;
            }
          toindex_byte += thislen_byte;
-         toindex += thisleni - combined;
-         STRING_SET_CHARS (val, SCHARS (val) - combined);
+         toindex += thisleni;
        }
       /* Copy a single-byte string to a multibyte string.  */
       else if (STRINGP (this) && STRINGP (val))
        }
       /* Copy a single-byte string to a multibyte string.  */
       else if (STRINGP (this) && STRINGP (val))
@@ -757,9 +720,7 @@ concat (nargs, args, target_type, last_special)
                  {
                    XSETFASTINT (elt, SREF (this, thisindex++));
                    if (some_multibyte
                  {
                    XSETFASTINT (elt, SREF (this, thisindex++));
                    if (some_multibyte
-                       && (XINT (elt) >= 0240
-                           || (XINT (elt) >= 0200
-                               && ! NILP (Vnonascii_translation_table)))
+                       && XINT (elt) >= 0200
                        && XINT (elt) < 0400)
                      {
                        c = unibyte_char_to_multibyte (XINT (elt));
                        && XINT (elt) < 0400)
                      {
                        c = unibyte_char_to_multibyte (XINT (elt));
@@ -792,34 +753,12 @@ concat (nargs, args, target_type, last_special)
            else
              {
                CHECK_NUMBER (elt);
            else
              {
                CHECK_NUMBER (elt);
-               if (SINGLE_BYTE_CHAR_P (XINT (elt)))
-                 {
-                   if (some_multibyte)
-                     toindex_byte
-                       += CHAR_STRING (XINT (elt),
-                                       SDATA (val) + toindex_byte);
-                   else
-                     SSET (val, toindex_byte++, XINT (elt));
-                   if (some_multibyte
-                       && toindex_byte > 0
-                       && count_combining (SDATA (val),
-                                           toindex_byte, toindex_byte - 1))
-                     STRING_SET_CHARS (val, SCHARS (val) - 1);
-                   else
-                     toindex++;
-                 }
+               if (some_multibyte)
+                 toindex_byte += CHAR_STRING (XINT (elt),
+                                              SDATA (val) + toindex_byte);
                else
                else
-                 /* If we have any multibyte characters,
-                    we already decided to make a multibyte string.  */
-                 {
-                   int c = XINT (elt);
-                   /* P exists as a variable
-                      to avoid a bug on the Masscomp C compiler.  */
-                   unsigned char *p = SDATA (val) + toindex_byte;
-
-                   toindex_byte += CHAR_STRING (c, p);
-                   toindex++;
-                 }
+                 SSET (val, toindex_byte++, XINT (elt));
+               toindex++;
              }
          }
     }
              }
          }
     }
@@ -867,7 +806,7 @@ string_char_to_byte (string, char_index)
      Lisp_Object string;
      int char_index;
 {
      Lisp_Object string;
      int char_index;
 {
-  int i, i_byte;
+  int i_byte;
   int best_below, best_below_byte;
   int best_above, best_above_byte;
 
   int best_below, best_below_byte;
   int best_above, best_above_byte;
 
@@ -894,40 +833,30 @@ string_char_to_byte (string, char_index)
 
   if (char_index - best_below < best_above - char_index)
     {
 
   if (char_index - best_below < best_above - char_index)
     {
+      unsigned char *p = SDATA (string) + best_below_byte;
+
       while (best_below < char_index)
        {
       while (best_below < char_index)
        {
-         int c;
-         FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string,
-                                             best_below, best_below_byte);
+         p += BYTES_BY_CHAR_HEAD (*p);
+         best_below++;
        }
        }
-      i = best_below;
-      i_byte = best_below_byte;
+      i_byte = p - SDATA (string);
     }
   else
     {
     }
   else
     {
+      unsigned char *p = SDATA (string) + best_above_byte;
+
       while (best_above > char_index)
        {
       while (best_above > char_index)
        {
-         unsigned char *pend = SDATA (string) + best_above_byte;
-         unsigned char *pbeg = pend - best_above_byte;
-         unsigned char *p = pend - 1;
-         int bytes;
-
-         while (p > pbeg  && !CHAR_HEAD_P (*p)) p--;
-         PARSE_MULTIBYTE_SEQ (p, pend - p, bytes);
-         if (bytes == pend - p)
-           best_above_byte -= bytes;
-         else if (bytes > pend - p)
-           best_above_byte -= (pend - p);
-         else
-           best_above_byte--;
+         p--;
+         while (!CHAR_HEAD_P (*p)) p--;
          best_above--;
        }
          best_above--;
        }
-      i = best_above;
-      i_byte = best_above_byte;
+      i_byte = p - SDATA (string);
     }
 
   string_char_byte_cache_bytepos = i_byte;
     }
 
   string_char_byte_cache_bytepos = i_byte;
-  string_char_byte_cache_charpos = i;
+  string_char_byte_cache_charpos = char_index;
   string_char_byte_cache_string = string;
 
   return i_byte;
   string_char_byte_cache_string = string;
 
   return i_byte;
@@ -967,36 +896,30 @@ string_byte_to_char (string, byte_index)
 
   if (byte_index - best_below_byte < best_above_byte - byte_index)
     {
 
   if (byte_index - best_below_byte < best_above_byte - byte_index)
     {
-      while (best_below_byte < byte_index)
+      unsigned char *p = SDATA (string) + best_below_byte;
+      unsigned char *pend = SDATA (string) + byte_index;
+
+      while (p < pend)
        {
        {
-         int c;
-         FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string,
-                                             best_below, best_below_byte);
+         p += BYTES_BY_CHAR_HEAD (*p);
+         best_below++;
        }
       i = best_below;
        }
       i = best_below;
-      i_byte = best_below_byte;
+      i_byte = p - SDATA (string);
     }
   else
     {
     }
   else
     {
-      while (best_above_byte > byte_index)
+      unsigned char *p = SDATA (string) + best_above_byte;
+      unsigned char *pbeg = SDATA (string) + byte_index;
+
+      while (p > pbeg)
        {
        {
-         unsigned char *pend = SDATA (string) + best_above_byte;
-         unsigned char *pbeg = pend - best_above_byte;
-         unsigned char *p = pend - 1;
-         int bytes;
-
-         while (p > pbeg  && !CHAR_HEAD_P (*p)) p--;
-         PARSE_MULTIBYTE_SEQ (p, pend - p, bytes);
-         if (bytes == pend - p)
-           best_above_byte -= bytes;
-         else if (bytes > pend - p)
-           best_above_byte -= (pend - p);
-         else
-           best_above_byte--;
+         p--;
+         while (!CHAR_HEAD_P (*p)) p--;
          best_above--;
        }
       i = best_above;
          best_above--;
        }
       i = best_above;
-      i_byte = best_above_byte;
+      i_byte = p - SDATA (string);
     }
 
   string_char_byte_cache_bytepos = i_byte;
     }
 
   string_char_byte_cache_bytepos = i_byte;
@@ -1006,9 +929,7 @@ string_byte_to_char (string, byte_index)
   return i;
 }
 \f
   return i;
 }
 \f
-/* Convert STRING to a multibyte string.
-   Single-byte characters 0240 through 0377 are converted
-   by adding nonascii_insert_offset to each.  */
+/* Convert STRING to a multibyte string.  */
 
 Lisp_Object
 string_make_multibyte (string)
 
 Lisp_Object
 string_make_multibyte (string)
@@ -1034,6 +955,35 @@ string_make_multibyte (string)
   return make_multibyte_string (buf, SCHARS (string), nbytes);
 }
 
   return make_multibyte_string (buf, SCHARS (string), nbytes);
 }
 
+
+/* Convert STRING (if unibyte) to a multibyte string without changing
+   the number of characters.  Characters 0200 trough 0237 are
+   converted to eight-bit characters. */
+
+Lisp_Object
+string_to_multibyte (string)
+     Lisp_Object string;
+{
+  unsigned char *buf;
+  int nbytes;
+
+  if (STRING_MULTIBYTE (string))
+    return string;
+
+  nbytes = parse_str_to_multibyte (SDATA (string), SBYTES (string));
+  /* If all the chars are ASCII, they won't need any more bytes once
+     converted.  */
+  if (nbytes == SBYTES (string))
+    return make_multibyte_string (SDATA (string), nbytes, nbytes);
+
+  buf = (unsigned char *) alloca (nbytes);
+  bcopy (SDATA (string), buf, SBYTES (string));
+  str_to_multibyte (buf, nbytes, SBYTES (string));
+
+  return make_multibyte_string (buf, SCHARS (string), nbytes);
+}
+
+
 /* Convert STRING to a single-byte string.  */
 
 Lisp_Object
 /* Convert STRING to a single-byte string.  */
 
 Lisp_Object
@@ -1112,9 +1062,11 @@ DEFUN ("string-as-multibyte", Fstring_as_multibyte, Sstring_as_multibyte,
        doc: /* Return a multibyte string with the same individual bytes as STRING.
 If STRING is multibyte, the result is STRING itself.
 Otherwise it is a newly created string, with no text properties.
        doc: /* Return a multibyte string with the same individual bytes as STRING.
 If STRING is multibyte, the result is STRING itself.
 Otherwise it is a newly created string, with no text properties.
+
 If STRING is unibyte and contains an individual 8-bit byte (i.e. not
 If STRING is unibyte and contains an individual 8-bit byte (i.e. not
-part of a multibyte form), it is converted to the corresponding
-multibyte character of charset `eight-bit-control' or `eight-bit-graphic'.  */)
+part of a correct utf-8 sequence), it is converted to the corresponding
+multibyte character of charset `eight-bit'.
+See also `string-to-multibyte'.  */)
      (string)
      Lisp_Object string;
 {
      (string)
      Lisp_Object string;
 {
@@ -1139,6 +1091,27 @@ multibyte character of charset `eight-bit-control' or `eight-bit-graphic'.  */)
     }
   return string;
 }
     }
   return string;
 }
+
+DEFUN ("string-to-multibyte", Fstring_to_multibyte, Sstring_to_multibyte,
+       1, 1, 0,
+       doc: /* Return a multibyte string with the same individual chars as STRING.
+If STRING is multibyte, the result is STRING itself.
+Otherwise it is a newly created string, with no text properties.
+
+If STRING is unibyte and contains an 8-bit byte, it is converted to
+the corresponding multibyte character of charset `eight-bit'.
+
+This differs from `string-as-multibyte' by converting each byte of a correct
+utf-8 sequence to an eight-bit character, not just bytes that don't form a
+correct sequence.  */)
+     (string)
+     Lisp_Object string;
+{
+  CHECK_STRING (string);
+
+  return string_to_multibyte (string);
+}
+
 \f
 DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0,
        doc: /* Return a copy of ALIST.
 \f
 DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0,
        doc: /* Return a copy of ALIST.
@@ -1170,7 +1143,7 @@ Elements of ALIST that are not conses are also shared.  */)
 DEFUN ("substring", Fsubstring, Ssubstring, 2, 3, 0,
        doc: /* Return a substring of STRING, starting at index FROM and ending before TO.
 TO may be nil or omitted; then the substring runs to the end of STRING.
 DEFUN ("substring", Fsubstring, Ssubstring, 2, 3, 0,
        doc: /* Return a substring of STRING, starting at index FROM and ending before TO.
 TO may be nil or omitted; then the substring runs to the end of STRING.
-If FROM or TO is negative, it counts from the end.
+FROM and TO start at 0.  If either is negative, it counts from the end.
 
 This function allows vectors as well as strings.  */)
      (string, from, to)
 
 This function allows vectors as well as strings.  */)
      (string, from, to)
@@ -1814,7 +1787,10 @@ See also the function `nreverse', which is used more often.  */)
   Lisp_Object new;
 
   for (new = Qnil; CONSP (list); list = XCDR (list))
   Lisp_Object new;
 
   for (new = Qnil; CONSP (list); list = XCDR (list))
-    new = Fcons (XCAR (list), new);
+    {
+      QUIT;
+      new = Fcons (XCAR (list), new);
+    }
   if (!NILP (list))
     wrong_type_argument (Qconsp, list);
   return new;
   if (!NILP (list))
     wrong_type_argument (Qconsp, list);
   return new;
@@ -1925,7 +1901,7 @@ one of the properties on the list.  */)
      Lisp_Object prop;
 {
   Lisp_Object tail;
      Lisp_Object prop;
 {
   Lisp_Object tail;
-  
+
   for (tail = plist;
        CONSP (tail) && CONSP (XCDR (tail));
        tail = XCDR (XCDR (tail)))
   for (tail = plist;
        CONSP (tail) && CONSP (XCDR (tail));
        tail = XCDR (XCDR (tail)))
@@ -1941,7 +1917,7 @@ one of the properties on the list.  */)
 
   if (!NILP (tail))
     wrong_type_argument (Qlistp, prop);
 
   if (!NILP (tail))
     wrong_type_argument (Qlistp, prop);
-  
+
   return Qnil;
 }
 
   return Qnil;
 }
 
@@ -1979,7 +1955,7 @@ The PLIST is modified by side effects.  */)
          Fsetcar (XCDR (tail), val);
          return plist;
        }
          Fsetcar (XCDR (tail), val);
          return plist;
        }
-      
+
       prev = tail;
       QUIT;
     }
       prev = tail;
       QUIT;
     }
@@ -2014,7 +1990,7 @@ one of the properties on the list.  */)
      Lisp_Object prop;
 {
   Lisp_Object tail;
      Lisp_Object prop;
 {
   Lisp_Object tail;
-  
+
   for (tail = plist;
        CONSP (tail) && CONSP (XCDR (tail));
        tail = XCDR (XCDR (tail)))
   for (tail = plist;
        CONSP (tail) && CONSP (XCDR (tail));
        tail = XCDR (XCDR (tail)))
@@ -2027,7 +2003,7 @@ one of the properties on the list.  */)
 
   if (!NILP (tail))
     wrong_type_argument (Qlistp, prop);
 
   if (!NILP (tail))
     wrong_type_argument (Qlistp, prop);
-  
+
   return Qnil;
 }
 
   return Qnil;
 }
 
@@ -2055,7 +2031,7 @@ The PLIST is modified by side effects.  */)
          Fsetcar (XCDR (tail), val);
          return plist;
        }
          Fsetcar (XCDR (tail), val);
          return plist;
        }
-      
+
       prev = tail;
       QUIT;
     }
       prev = tail;
       QUIT;
     }
@@ -2159,7 +2135,8 @@ internal_equal (o1, o2, depth)
           functions are sensible to compare, so eliminate the others now.  */
        if (size & PSEUDOVECTOR_FLAG)
          {
           functions are sensible to compare, so eliminate the others now.  */
        if (size & PSEUDOVECTOR_FLAG)
          {
-           if (!(size & (PVEC_COMPILED | PVEC_CHAR_TABLE)))
+           if (!(size & (PVEC_COMPILED
+                         | PVEC_CHAR_TABLE | PVEC_SUB_CHAR_TABLE)))
              return 0;
            size &= PSEUDOVECTOR_SIZE_MASK;
          }
              return 0;
            size &= PSEUDOVECTOR_SIZE_MASK;
          }
@@ -2190,7 +2167,7 @@ internal_equal (o1, o2, depth)
     case Lisp_Type_Limit:
       break;
     }
     case Lisp_Type_Limit:
       break;
     }
-  
+
   return 0;
 }
 \f
   return 0;
 }
 \f
@@ -2213,11 +2190,11 @@ ARRAY is a vector, string, char-table, or bool-vector.  */)
     }
   else if (CHAR_TABLE_P (array))
     {
     }
   else if (CHAR_TABLE_P (array))
     {
-      register Lisp_Object *p = XCHAR_TABLE (array)->contents;
-      size = CHAR_TABLE_ORDINARY_SLOTS;
-      for (index = 0; index < size; index++)
-       p[index] = item;
-      XCHAR_TABLE (array)->defalt = Qnil;
+      int i;
+
+      for (i = 0; i < (1 << CHARTAB_SIZE_BITS_0); i++)
+       XCHAR_TABLE (array)->contents[i] = item;
+      XCHAR_TABLE (array)->defalt = item;
     }
   else if (STRINGP (array))
     {
     }
   else if (STRINGP (array))
     {
@@ -2265,438 +2242,20 @@ ARRAY is a vector, string, char-table, or bool-vector.  */)
     }
   return array;
 }
     }
   return array;
 }
-\f
-DEFUN ("char-table-subtype", Fchar_table_subtype, Schar_table_subtype,
-       1, 1, 0,
-       doc: /* Return the subtype of char-table CHAR-TABLE.  The value is a symbol.  */)
-     (char_table)
-     Lisp_Object char_table;
-{
-  CHECK_CHAR_TABLE (char_table);
-
-  return XCHAR_TABLE (char_table)->purpose;
-}
 
 
-DEFUN ("char-table-parent", Fchar_table_parent, Schar_table_parent,
+DEFUN ("clear-string", Fclear_string, Sclear_string,
        1, 1, 0,
        1, 1, 0,
-       doc: /* Return the parent char-table of CHAR-TABLE.
-The value is either nil or another char-table.
-If CHAR-TABLE holds nil for a given character,
-then the actual applicable value is inherited from the parent char-table
-\(or from its parents, if necessary).  */)
-     (char_table)
-     Lisp_Object char_table;
-{
-  CHECK_CHAR_TABLE (char_table);
-
-  return XCHAR_TABLE (char_table)->parent;
-}
-
-DEFUN ("set-char-table-parent", Fset_char_table_parent, Sset_char_table_parent,
-       2, 2, 0,
-       doc: /* Set the parent char-table of CHAR-TABLE to PARENT.
-PARENT must be either nil or another char-table.  */)
-     (char_table, parent)
-     Lisp_Object char_table, parent;
-{
-  Lisp_Object temp;
-
-  CHECK_CHAR_TABLE (char_table);
-
-  if (!NILP (parent))
-    {
-      CHECK_CHAR_TABLE (parent);
-
-      for (temp = parent; !NILP (temp); temp = XCHAR_TABLE (temp)->parent)
-       if (EQ (temp, char_table))
-         error ("Attempt to make a chartable be its own 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,
-       doc: /* Return the value of CHAR-TABLE's extra-slot number N.  */)
-     (char_table, n)
-     Lisp_Object char_table, n;
-{
-  CHECK_CHAR_TABLE (char_table);
-  CHECK_NUMBER (n);
-  if (XINT (n) < 0
-      || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
-    args_out_of_range (char_table, 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,
-       doc: /* Set CHAR-TABLE's extra-slot number N to VALUE.  */)
-     (char_table, n, value)
-     Lisp_Object char_table, n, value;
-{
-  CHECK_CHAR_TABLE (char_table);
-  CHECK_NUMBER (n);
-  if (XINT (n) < 0
-      || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
-    args_out_of_range (char_table, n);
-
-  return XCHAR_TABLE (char_table)->extras[XINT (n)] = value;
-}
-\f
-DEFUN ("char-table-range", Fchar_table_range, Schar_table_range,
-       2, 2, 0,
-       doc: /* Return the value in CHAR-TABLE for a range of characters RANGE.
-RANGE should be nil (for the default value)
-a vector which identifies a character set or a row of a character set,
-a character set name, or a character code.  */)
-     (char_table, range)
-     Lisp_Object char_table, range;
-{
-  CHECK_CHAR_TABLE (char_table);
-
-  if (EQ (range, Qnil))
-    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);
-
-      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
-       {
-         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'");
-  return Qt;
-}
-
-DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range,
-       3, 3, 0,
-       doc: /* Set the value in CHAR-TABLE for a range of characters RANGE to VALUE.
-RANGE should be t (for all characters), nil (for the default value)
-a vector which identifies a character set or a row of a character set,
-a coding system, or a character code.  */)
-     (char_table, range, value)
-     Lisp_Object char_table, range, value;
-{
-  int i;
-
-  CHECK_CHAR_TABLE (char_table);
-
-  if (EQ (range, Qt))
-    for (i = 0; i < CHAR_TABLE_ORDINARY_SLOTS; i++)
-      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);
-
-      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,
-                     make_number (XINT (XVECTOR (range)->contents[0]) + 128),
-                     value);
-      else
-       {
-         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,
-       doc: /* Set the default value in CHAR-TABLE for a generic character CHAR to VALUE.
-The generic character specifies the group of characters.
-See also the documentation of make-char.  */)
-     (char_table, ch, value)
-     Lisp_Object char_table, ch, value;
-{
-  int c, charset, code1, code2;
-  Lisp_Object temp;
-
-  CHECK_CHAR_TABLE (char_table);
-  CHECK_NUMBER (ch);
-
-  c = XINT (ch);
-  SPLIT_CHAR (c, charset, code1, code2);
-
-  /* Since we may want to set the default value for a character set
-     not yet defined, we check only if the character set is in the
-     valid range or not, instead of it is already defined or not.  */
-  if (! CHARSET_VALID_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_DEFINED_P (charset) || 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;
-    }
-  if (SUB_CHAR_TABLE_P (temp))
-    char_table = temp;
-  else
-    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);
-}
-
-static void
-optimize_sub_char_table (table, chars)
-     Lisp_Object *table;
-     int chars;
-{
-  Lisp_Object elt;
-  int from, to;
-
-  if (chars == 94)
-    from = 33, to = 127;
-  else
-    from = 32, to = 128;
-
-  if (!SUB_CHAR_TABLE_P (*table))
-    return;
-  elt = XCHAR_TABLE (*table)->contents[from++];
-  for (; from < to; from++)
-    if (NILP (Fequal (elt, XCHAR_TABLE (*table)->contents[from])))
-      return;
-  *table = elt;
-}
-
-DEFUN ("optimize-char-table", Foptimize_char_table, Soptimize_char_table,
-       1, 1, 0, doc: /* Optimize char table TABLE.  */)
-     (table)
-     Lisp_Object table;
-{
-  Lisp_Object elt;
-  int dim;
-  int i, j;
-
-  CHECK_CHAR_TABLE (table);
-
-  for (i = CHAR_TABLE_SINGLE_BYTE_SLOTS; i < CHAR_TABLE_ORDINARY_SLOTS; i++)
-    {
-      elt = XCHAR_TABLE (table)->contents[i];
-      if (!SUB_CHAR_TABLE_P (elt))
-       continue;
-      dim = CHARSET_DIMENSION (i - 128);
-      if (dim == 2)
-       for (j = 32; j < SUB_CHAR_TABLE_ORDINARY_SLOTS; j++)
-         optimize_sub_char_table (XCHAR_TABLE (elt)->contents + j, dim);
-      optimize_sub_char_table (XCHAR_TABLE (table)->contents + i, dim);
-    }
-  return Qnil;
-}
-
-\f
-/* Map C_FUNCTION or FUNCTION over SUBTABLE, calling it for each
-   character or group of characters that share a value.
-   DEPTH is the current depth in the originally specified
-   chartable, and INDICES contains the vector indices
-   for the levels our callers have descended.
-
-   ARG is passed to C_FUNCTION when that is called.  */
-
-void
-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, 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
-    {
-      int charset = XFASTINT (indices[0]) - 128;
-
-      i = 32;
-      to = SUB_CHAR_TABLE_ORDINARY_SLOTS;
-      if (CHARSET_CHARS (charset) == 94)
-       i++, to--;
-    }
-
-  for (; i < to; i++)
-    {
-      Lisp_Object elt;
-      int charset;
-
-      elt = XCHAR_TABLE (subtable)->contents[i];
-      XSETFASTINT (indices[depth], i);
-      charset = XFASTINT (indices[0]) - 128;
-      if (depth == 0
-         && (!CHARSET_DEFINED_P (charset)
-             || charset == CHARSET_8_BIT_CONTROL
-             || charset == CHARSET_8_BIT_GRAPHIC))
-       continue;
-
-      if (SUB_CHAR_TABLE_P (elt))
-       {
-         if (depth >= 3)
-           error ("Too deep char table");
-         map_char_table (c_function, function, elt, arg, depth + 1, indices);
-       }
-      else
-       {
-         int c1, c2, c;
-
-         if (NILP (elt))
-           elt = XCHAR_TABLE (subtable)->defalt;
-         c1 = depth >= 1 ? XFASTINT (indices[1]) : 0;
-         c2 = depth >= 2 ? XFASTINT (indices[2]) : 0;
-         c = MAKE_CHAR (charset, c1, c2);
-         if (c_function)
-           (*c_function) (arg, make_number (c), elt);
-         else
-           call2 (function, make_number (c), elt);
-       }
-    }
-}
-
-DEFUN ("map-char-table", Fmap_char_table, Smap_char_table,
-       2, 2, 0,
-       doc: /* Call FUNCTION for each (normal and generic) characters in CHAR-TABLE.
-FUNCTION is called with two arguments--a key and a value.
-The key is always a possible IDX argument to `aref'.  */)
-     (function, char_table)
-     Lisp_Object function, char_table;
+       doc: /* Clear the contents of STRING.
+This makes STRING unibyte and may change its length.  */)
+     (string)
+     Lisp_Object string;
 {
 {
-  /* The depth of char table is at most 3. */
-  Lisp_Object indices[3];
-
-  CHECK_CHAR_TABLE (char_table);
-
-  map_char_table ((void *) call2, Qnil, char_table, function, 0, indices);
+  int len = SBYTES (string);
+  bzero (SDATA (string), len);
+  STRING_SET_CHARS (string, len);
+  STRING_SET_UNIBYTE (string);
   return Qnil;
 }
   return Qnil;
 }
-
-/* Return a value for character C in char-table TABLE.  Store the
-   actual index for that value in *IDX.  Ignore the default value of
-   TABLE.  */
-
-Lisp_Object
-char_table_ref_and_index (table, c, idx)
-     Lisp_Object table;
-     int c, *idx;
-{
-  int charset, c1, c2;
-  Lisp_Object elt;
-
-  if (SINGLE_BYTE_CHAR_P (c))
-    {
-      *idx = c;
-      return XCHAR_TABLE (table)->contents[c];
-    }
-  SPLIT_CHAR (c, charset, c1, c2);
-  elt = XCHAR_TABLE (table)->contents[charset + 128];
-  *idx = MAKE_CHAR (charset, 0, 0);
-  if (!SUB_CHAR_TABLE_P (elt))
-    return elt;
-  if (c1 < 32 || NILP (XCHAR_TABLE (elt)->contents[c1]))
-    return XCHAR_TABLE (elt)->defalt;
-  elt = XCHAR_TABLE (elt)->contents[c1];
-  *idx = MAKE_CHAR (charset, c1, 0);
-  if (!SUB_CHAR_TABLE_P (elt))
-    return elt;
-  if (c2 < 32 || NILP (XCHAR_TABLE (elt)->contents[c2]))
-    return XCHAR_TABLE (elt)->defalt;
-  *idx = c;
-  return XCHAR_TABLE (elt)->contents[c2];
-}
-
 \f
 /* ARGSUSED */
 Lisp_Object
 \f
 /* ARGSUSED */
 Lisp_Object
@@ -2859,6 +2418,8 @@ SEQUENCE may be a list, a vector, a bool-vector, or a string.  */)
   struct gcpro gcpro1;
 
   len = Flength (sequence);
   struct gcpro gcpro1;
 
   len = Flength (sequence);
+  if (CHAR_TABLE_P (sequence))
+    wrong_type_argument (Qlistp, sequence);
   leni = XINT (len);
   nargs = leni + leni - 1;
   if (nargs < 0) return build_string ("");
   leni = XINT (len);
   nargs = leni + leni - 1;
   if (nargs < 0) return build_string ("");
@@ -2890,6 +2451,8 @@ SEQUENCE may be a list, a vector, a bool-vector, or a string.  */)
   register Lisp_Object *args;
 
   len = Flength (sequence);
   register Lisp_Object *args;
 
   len = Flength (sequence);
+  if (CHAR_TABLE_P (sequence))
+    wrong_type_argument (Qlistp, sequence);
   leni = XFASTINT (len);
   args = (Lisp_Object *) alloca (leni * sizeof (Lisp_Object));
 
   leni = XFASTINT (len);
   args = (Lisp_Object *) alloca (leni * sizeof (Lisp_Object));
 
@@ -2908,6 +2471,8 @@ SEQUENCE may be a list, a vector, a bool-vector, or a string.  */)
   register int leni;
 
   leni = XFASTINT (Flength (sequence));
   register int leni;
 
   leni = XFASTINT (Flength (sequence));
+  if (CHAR_TABLE_P (sequence))
+    wrong_type_argument (Qlistp, sequence);
   mapcar1 (leni, 0, function, sequence);
 
   return sequence;
   mapcar1 (leni, 0, function, sequence);
 
   return sequence;
@@ -3133,7 +2698,7 @@ is nil, and `use-dialog-box' is non-nil.  */)
 \f
 DEFUN ("load-average", Fload_average, Sload_average, 0, 1, 0,
        doc: /* Return list of 1 minute, 5 minute and 15 minute load averages.
 \f
 DEFUN ("load-average", Fload_average, Sload_average, 0, 1, 0,
        doc: /* Return list of 1 minute, 5 minute and 15 minute load averages.
-     
+
 Each of the three load averages is multiplied by 100, then converted
 to integer.
 
 Each of the three load averages is multiplied by 100, then converted
 to integer.
 
@@ -3141,7 +2706,12 @@ When USE-FLOATS is non-nil, floats will be used instead of integers.
 These floats are not multiplied by 100.
 
 If the 5-minute or 15-minute load averages are not available, return a
 These floats are not multiplied by 100.
 
 If the 5-minute or 15-minute load averages are not available, return a
-shortened list, containing only those averages which are available.  */)
+shortened list, containing only those averages which are available.
+
+An error is thrown if the load average can't be obtained.  In some
+cases making it work would require Emacs being installed setuid or
+setgid so that it can read kernel information, and that usually isn't
+advisable.  */)
      (use_floats)
      Lisp_Object use_floats;
 {
      (use_floats)
      Lisp_Object use_floats;
 {
@@ -3168,7 +2738,7 @@ extern Lisp_Object Vafter_load_alist;
 
 DEFUN ("featurep", Ffeaturep, Sfeaturep, 1, 2, 0,
        doc: /* Returns t if FEATURE is present in this Emacs.
 
 DEFUN ("featurep", Ffeaturep, Sfeaturep, 1, 2, 0,
        doc: /* Returns t if FEATURE is present in this Emacs.
-     
+
 Use this to conditionalize execution of lisp code based on the
 presence or absence of emacs or environment extensions.
 Use `provide' to declare that a feature is available.  This function
 Use this to conditionalize execution of lisp code based on the
 presence or absence of emacs or environment extensions.
 Use `provide' to declare that a feature is available.  This function
@@ -3245,7 +2815,7 @@ The normal messages at start and end of loading FILENAME are suppressed.  */)
   CHECK_SYMBOL (feature);
 
   tem = Fmemq (feature, Vfeatures);
   CHECK_SYMBOL (feature);
 
   tem = Fmemq (feature, Vfeatures);
-  
+
   if (NILP (tem))
     {
       int count = SPECPDL_INDEX ();
   if (NILP (tem))
     {
       int count = SPECPDL_INDEX ();
@@ -3258,7 +2828,7 @@ The normal messages at start and end of loading FILENAME are suppressed.  */)
       if (! NILP (Vpurify_flag))
        error ("(require %s) while preparing to dump",
               SDATA (SYMBOL_NAME (feature)));
       if (! NILP (Vpurify_flag))
        error ("(require %s) while preparing to dump",
               SDATA (SYMBOL_NAME (feature)));
-      
+
       /* A certain amount of recursive `require' is legitimate,
         but if we require the same feature recursively 3 times,
         signal an error.  */
       /* A certain amount of recursive `require' is legitimate,
         but if we require the same feature recursively 3 times,
         signal an error.  */
@@ -3389,6 +2959,92 @@ usage: (widget-apply WIDGET PROPERTY &rest ARGS)  */)
   UNGCPRO;
   return result;
 }
   UNGCPRO;
   return result;
 }
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+DEFUN ("locale-info", Flocale_info, Slocale_info, 1, 1, 0,
+       doc: /* Access locale data ITEM for the current C locale, if available.
+ITEM should be one of the following:
+
+`codeset', returning the character set as a string (locale item CODESET);
+
+`days', returning a 7-element vector of day names (locale items DAY_n);
+
+`months', returning a 12-element vector of month names (locale items MON_n);
+
+`paper', returning a list (WIDTH HEIGHT) for the default paper size,
+  both measured in milimeters (locale items PAPER_WIDTH, PAPER_HEIGHT).
+
+If the system can't provide such information through a call to
+`nl_langinfo', or if ITEM isn't from the list above, return nil.
+
+See also Info node `(libc)Locales'.
+
+The data read from the system are decoded using `locale-coding-system'.  */)
+     (item)
+     Lisp_Object item;
+{
+  char *str = NULL;
+#ifdef HAVE_LANGINFO_CODESET
+  Lisp_Object val;
+  if (EQ (item, Qcodeset))
+    {
+      str = nl_langinfo (CODESET);
+      return build_string (str);
+    }
+#ifdef DAY_1
+  else if (EQ (item, Qdays))   /* e.g. for calendar-day-name-array */
+    {
+      Lisp_Object v = Fmake_vector (make_number (7), Qnil);
+      int days[7] = {DAY_1, DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7};
+      int i;
+      synchronize_system_time_locale ();
+      for (i = 0; i < 7; i++)
+       {
+         str = nl_langinfo (days[i]);
+         val = make_unibyte_string (str, strlen (str));
+         /* Fixme: Is this coding system necessarily right, even if
+            it is consistent with CODESET?  If not, what to do?  */
+         Faset (v, make_number (i),
+                code_convert_string_norecord (val, Vlocale_coding_system,
+                                              0));
+       }
+      return v;
+    }
+#endif /* DAY_1 */
+#ifdef MON_1
+  else if (EQ (item, Qmonths)) /* e.g. for calendar-month-name-array */
+    {
+      struct Lisp_Vector *p = allocate_vector (12);
+      int months[12] = {MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7,
+                       MON_8, MON_9, MON_10, MON_11, MON_12};
+      int i;
+      synchronize_system_time_locale ();
+      for (i = 0; i < 12; i++)
+       {
+         str = nl_langinfo (months[i]);
+         val = make_unibyte_string (str, strlen (str));
+         p->contents[i] =
+           code_convert_string_norecord (val, Vlocale_coding_system, 0);
+       }
+      XSETVECTOR (val, p);
+      return val;
+    }
+#endif /* MON_1 */
+/* LC_PAPER stuff isn't defined as accessible in glibc as of 2.3.1,
+   but is in the locale files.  This could be used by ps-print.  */
+#ifdef PAPER_WIDTH
+  else if (EQ (item, Qpaper))
+    {
+      return list2 (make_number (nl_langinfo (PAPER_WIDTH)),
+                   make_number (nl_langinfo (PAPER_HEIGHT)));
+    }
+#endif /* PAPER_WIDTH */
+#endif /* HAVE_LANGINFO_CODESET*/
+  return Qnil;
+}
 \f
 /* base64 encode/decode functions (RFC 2045).
    Based on code from GNU recode. */
 \f
 /* base64 encode/decode functions (RFC 2045).
    Based on code from GNU recode. */
@@ -3607,7 +3263,9 @@ base64_encode_1 (from, to, length, line_break, multibyte)
       if (multibyte)
        {
          c = STRING_CHAR_AND_LENGTH (from + i, length - i, bytes);
       if (multibyte)
        {
          c = STRING_CHAR_AND_LENGTH (from + i, length - i, bytes);
-         if (c >= 256)
+         if (CHAR_BYTE8_P (c))
+           c = CHAR_TO_BYTE8 (c);
+         else if (c >= 256)
            return -1;
          i += bytes;
        }
            return -1;
          i += bytes;
        }
@@ -3645,7 +3303,9 @@ base64_encode_1 (from, to, length, line_break, multibyte)
       if (multibyte)
        {
          c = STRING_CHAR_AND_LENGTH (from + i, length - i, bytes);
       if (multibyte)
        {
          c = STRING_CHAR_AND_LENGTH (from + i, length - i, bytes);
-         if (c >= 256)
+         if (CHAR_BYTE8_P (c))
+           c = CHAR_TO_BYTE8 (c);
+         else if (c >= 256)
            return -1;
          i += bytes;
        }
            return -1;
          i += bytes;
        }
@@ -3667,7 +3327,9 @@ base64_encode_1 (from, to, length, line_break, multibyte)
       if (multibyte)
        {
          c = STRING_CHAR_AND_LENGTH (from + i, length - i, bytes);
       if (multibyte)
        {
          c = STRING_CHAR_AND_LENGTH (from + i, length - i, bytes);
-         if (c >= 256)
+         if (CHAR_BYTE8_P (c))
+           c = CHAR_TO_BYTE8 (c);
+         else if (c >= 256)
            return -1;
          i += bytes;
        }
            return -1;
          i += bytes;
        }
@@ -3823,8 +3485,8 @@ base64_decode_1 (from, to, length, multibyte, nchars_return)
       value |= base64_char_to_value[c] << 12;
 
       c = (unsigned char) (value >> 16);
       value |= base64_char_to_value[c] << 12;
 
       c = (unsigned char) (value >> 16);
-      if (multibyte)
-       e += CHAR_STRING (c, e);
+      if (multibyte && c >= 128)
+       e += BYTE8_STRING (c, e);
       else
        *e++ = c;
       nchars++;
       else
        *e++ = c;
       nchars++;
@@ -3847,8 +3509,8 @@ base64_decode_1 (from, to, length, multibyte, nchars_return)
       value |= base64_char_to_value[c] << 6;
 
       c = (unsigned char) (0xff & value >> 8);
       value |= base64_char_to_value[c] << 6;
 
       c = (unsigned char) (0xff & value >> 8);
-      if (multibyte)
-       e += CHAR_STRING (c, e);
+      if (multibyte && c >= 128)
+       e += BYTE8_STRING (c, e);
       else
        *e++ = c;
       nchars++;
       else
        *e++ = c;
       nchars++;
@@ -3865,8 +3527,8 @@ base64_decode_1 (from, to, length, multibyte, nchars_return)
       value |= base64_char_to_value[c];
 
       c = (unsigned char) (0xff & value);
       value |= base64_char_to_value[c];
 
       c = (unsigned char) (0xff & value);
-      if (multibyte)
-       e += CHAR_STRING (c, e);
+      if (multibyte && c >= 128)
+       e += BYTE8_STRING (c, e);
       else
        *e++ = c;
       nchars++;
       else
        *e++ = c;
       nchars++;
@@ -4575,13 +4237,13 @@ sweep_weak_table (h, remove_entries_p)
                  /* Make sure key and value survive.  */
                  if (!key_known_to_survive_p)
                    {
                  /* Make sure key and value survive.  */
                  if (!key_known_to_survive_p)
                    {
-                     mark_object (&HASH_KEY (h, i));
+                     mark_object (HASH_KEY (h, i));
                      marked = 1;
                    }
 
                  if (!value_known_to_survive_p)
                    {
                      marked = 1;
                    }
 
                  if (!value_known_to_survive_p)
                    {
-                     mark_object (&HASH_VALUE (h, i));
+                     mark_object (HASH_VALUE (h, i));
                      marked = 1;
                    }
                }
                      marked = 1;
                    }
                }
@@ -4626,7 +4288,7 @@ sweep_weak_hash_tables ()
     {
       h = XHASH_TABLE (table);
       next = h->next_weak;
     {
       h = XHASH_TABLE (table);
       next = h->next_weak;
-      
+
       if (h->size & ARRAY_MARK_FLAG)
        {
          /* TABLE is marked as used.  Sweep its contents.  */
       if (h->size & ARRAY_MARK_FLAG)
        {
          /* TABLE is marked as used.  Sweep its contents.  */
@@ -4839,7 +4501,7 @@ DEFUN ("sxhash", Fsxhash, Ssxhash, 1, 1, 0,
 
 DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
        doc: /* Create and return a new hash table.
 
 DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
        doc: /* Create and return a new hash table.
-         
+
 Arguments are specified as keyword/argument pairs.  The following
 arguments are defined:
 
 Arguments are specified as keyword/argument pairs.  The following
 arguments are defined:
 
@@ -5114,7 +4776,7 @@ FUNCTION is called with 2 arguments KEY and VALUE.  */)
 DEFUN ("define-hash-table-test", Fdefine_hash_table_test,
        Sdefine_hash_table_test, 3, 3, 0,
        doc: /* Define a new hash table test with name NAME, a symbol.
 DEFUN ("define-hash-table-test", Fdefine_hash_table_test,
        Sdefine_hash_table_test, 3, 3, 0,
        doc: /* Define a new hash table test with name NAME, a symbol.
-         
+
 In hash tables created with NAME specified as test, use TEST to
 compare keys, and HASH for computing hash codes of keys.
 
 In hash tables created with NAME specified as test, use TEST to
 compare keys, and HASH for computing hash codes of keys.
 
@@ -5136,11 +4798,10 @@ including negative integers.  */)
  ************************************************************************/
 
 #include "md5.h"
  ************************************************************************/
 
 #include "md5.h"
-#include "coding.h"
 
 DEFUN ("md5", Fmd5, Smd5, 1, 5, 0,
        doc: /* Return MD5 message digest of OBJECT, a buffer or string.
 
 DEFUN ("md5", Fmd5, Smd5, 1, 5, 0,
        doc: /* Return MD5 message digest of OBJECT, a buffer or string.
-         
+
 A message digest is a cryptographic checksum of a document, and the
 algorithm to calculate it is defined in RFC 1321.
 
 A message digest is a cryptographic checksum of a document, and the
 algorithm to calculate it is defined in RFC 1321.
 
@@ -5187,15 +4848,15 @@ guesswork fails.  Normally, an error is signaled in such case.  */)
 
          if (STRING_MULTIBYTE (object))
            /* use default, we can't guess correct value */
 
          if (STRING_MULTIBYTE (object))
            /* use default, we can't guess correct value */
-           coding_system = SYMBOL_VALUE (XCAR (Vcoding_category_list));
-         else 
+           coding_system = preferred_coding_system ();
+         else
            coding_system = Qraw_text;
        }
            coding_system = Qraw_text;
        }
-      
+
       if (NILP (Fcoding_system_p (coding_system)))
        {
          /* Invalid coding system.  */
       if (NILP (Fcoding_system_p (coding_system)))
        {
          /* Invalid coding system.  */
-         
+
          if (!NILP (noerror))
            coding_system = Qraw_text;
          else
          if (!NILP (noerror))
            coding_system = Qraw_text;
          else
@@ -5204,7 +4865,7 @@ guesswork fails.  Normally, an error is signaled in such case.  */)
        }
 
       if (STRING_MULTIBYTE (object))
        }
 
       if (STRING_MULTIBYTE (object))
-       object = code_convert_string1 (object, coding_system, Qnil, 1);
+       object = code_convert_string (object, coding_system, Qnil, 1, 0, 1);
 
       size = SCHARS (object);
       size_byte = SBYTES (object);
 
       size = SCHARS (object);
       size_byte = SBYTES (object);
@@ -5229,15 +4890,15 @@ guesswork fails.  Normally, an error is signaled in such case.  */)
       else
        {
          CHECK_NUMBER (end);
       else
        {
          CHECK_NUMBER (end);
-         
+
          end_char = XINT (end);
 
          if (end_char < 0)
            end_char += size;
          end_char = XINT (end);
 
          if (end_char < 0)
            end_char += size;
-         
+
          end_byte = string_char_to_byte (object, end_char);
        }
          end_byte = string_char_to_byte (object, end_char);
        }
-      
+
       if (!(0 <= start_char && start_char <= end_char && end_char <= size))
        args_out_of_range_3 (object, make_number (start_char),
                             make_number (end_char));
       if (!(0 <= start_char && start_char <= end_char && end_char <= size))
        args_out_of_range_3 (object, make_number (start_char),
                             make_number (end_char));
@@ -5247,7 +4908,7 @@ guesswork fails.  Normally, an error is signaled in such case.  */)
       CHECK_BUFFER (object);
 
       bp = XBUFFER (object);
       CHECK_BUFFER (object);
 
       bp = XBUFFER (object);
-         
+
       if (NILP (start))
        b = BUF_BEGV (bp);
       else
       if (NILP (start))
        b = BUF_BEGV (bp);
       else
@@ -5263,16 +4924,16 @@ guesswork fails.  Normally, an error is signaled in such case.  */)
          CHECK_NUMBER_COERCE_MARKER (end);
          e = XINT (end);
        }
          CHECK_NUMBER_COERCE_MARKER (end);
          e = XINT (end);
        }
-      
+
       if (b > e)
        temp = b, b = e, e = temp;
       if (b > e)
        temp = b, b = e, e = temp;
-      
+
       if (!(BUF_BEGV (bp) <= b && e <= BUF_ZV (bp)))
        args_out_of_range (start, end);
       if (!(BUF_BEGV (bp) <= b && e <= BUF_ZV (bp)))
        args_out_of_range (start, end);
-      
+
       if (NILP (coding_system))
        {
       if (NILP (coding_system))
        {
-         /* Decide the coding-system to encode the data with. 
+         /* Decide the coding-system to encode the data with.
             See fileio.c:Fwrite-region */
 
          if (!NILP (Vcoding_system_for_write))
             See fileio.c:Fwrite-region */
 
          if (!NILP (Vcoding_system_for_write))
@@ -5294,7 +4955,7 @@ guesswork fails.  Normally, an error is signaled in such case.  */)
                {
                  /* Check file-coding-system-alist.  */
                  Lisp_Object args[4], val;
                {
                  /* Check file-coding-system-alist.  */
                  Lisp_Object args[4], val;
-                 
+
                  args[0] = Qwrite_region; args[1] = start; args[2] = end;
                  args[3] = Fbuffer_file_name(object);
                  val = Ffind_operation_coding_system (4, args);
                  args[0] = Qwrite_region; args[1] = start; args[2] = end;
                  args[3] = Fbuffer_file_name(object);
                  val = Ffind_operation_coding_system (4, args);
@@ -5336,11 +4997,11 @@ guesswork fails.  Normally, an error is signaled in such case.  */)
       object = make_buffer_string (b, e, 0);
 
       if (STRING_MULTIBYTE (object))
       object = make_buffer_string (b, e, 0);
 
       if (STRING_MULTIBYTE (object))
-       object = code_convert_string1 (object, coding_system, Qnil, 1);
+       object = code_convert_string (object, coding_system, Qnil, 1, 0, 0);
     }
 
     }
 
-  md5_buffer (SDATA (object) + start_byte, 
-             SBYTES (object) - (size_byte - end_byte), 
+  md5_buffer (SDATA (object) + start_byte,
+             SBYTES (object) - (size_byte - end_byte),
              digest);
 
   for (i = 0; i < 16; i++)
              digest);
 
   for (i = 0; i < 16; i++)
@@ -5429,6 +5090,17 @@ Used by `featurep' and `require', and altered by `provide'.  */);
   Qsubfeatures = intern ("subfeatures");
   staticpro (&Qsubfeatures);
 
   Qsubfeatures = intern ("subfeatures");
   staticpro (&Qsubfeatures);
 
+#ifdef HAVE_LANGINFO_CODESET
+  Qcodeset = intern ("codeset");
+  staticpro (&Qcodeset);
+  Qdays = intern ("days");
+  staticpro (&Qdays);
+  Qmonths = intern ("months");
+  staticpro (&Qmonths);
+  Qpaper = intern ("paper");
+  staticpro (&Qpaper);
+#endif /* HAVE_LANGINFO_CODESET */
+
   DEFVAR_BOOL ("use-dialog-box", &use_dialog_box,
     doc: /* *Non-nil means mouse commands use dialog boxes to ask questions.
 This applies to `y-or-n-p' and `yes-or-no-p' questions asked by commands
   DEFVAR_BOOL ("use-dialog-box", &use_dialog_box,
     doc: /* *Non-nil means mouse commands use dialog boxes to ask questions.
 This applies to `y-or-n-p' and `yes-or-no-p' questions asked by commands
@@ -5451,6 +5123,7 @@ invoked by mouse clicks and mouse menu items.  */);
   defsubr (&Sstring_make_unibyte);
   defsubr (&Sstring_as_multibyte);
   defsubr (&Sstring_as_unibyte);
   defsubr (&Sstring_make_unibyte);
   defsubr (&Sstring_as_multibyte);
   defsubr (&Sstring_as_unibyte);
+  defsubr (&Sstring_to_multibyte);
   defsubr (&Scopy_alist);
   defsubr (&Ssubstring);
   defsubr (&Ssubstring_no_properties);
   defsubr (&Scopy_alist);
   defsubr (&Ssubstring);
   defsubr (&Ssubstring_no_properties);
@@ -5476,16 +5149,7 @@ invoked by mouse clicks and mouse menu items.  */);
   defsubr (&Slax_plist_put);
   defsubr (&Sequal);
   defsubr (&Sfillarray);
   defsubr (&Slax_plist_put);
   defsubr (&Sequal);
   defsubr (&Sfillarray);
-  defsubr (&Schar_table_subtype);
-  defsubr (&Schar_table_parent);
-  defsubr (&Sset_char_table_parent);
-  defsubr (&Schar_table_extra_slot);
-  defsubr (&Sset_char_table_extra_slot);
-  defsubr (&Schar_table_range);
-  defsubr (&Sset_char_table_range);
-  defsubr (&Sset_char_table_default);
-  defsubr (&Soptimize_char_table);
-  defsubr (&Smap_char_table);
+  defsubr (&Sclear_string);
   defsubr (&Snconc);
   defsubr (&Smapcar);
   defsubr (&Smapc);
   defsubr (&Snconc);
   defsubr (&Smapcar);
   defsubr (&Smapc);
@@ -5505,6 +5169,7 @@ invoked by mouse clicks and mouse menu items.  */);
   defsubr (&Sbase64_encode_string);
   defsubr (&Sbase64_decode_string);
   defsubr (&Smd5);
   defsubr (&Sbase64_encode_string);
   defsubr (&Sbase64_decode_string);
   defsubr (&Smd5);
+  defsubr (&Slocale_info);
 }
 
 
 }