]> code.delx.au - gnu-emacs/blobdiff - src/lread.c
Backport revisions 2011-04-24T05:30:24Z!eggert@cs.ucla.edu..2011-04-25T19:40:22Z...
[gnu-emacs] / src / lread.c
index a7fe30e9f89648147dd2c45c1e5b1335c3c6a559..3d954ac282be72e87d7c1f2b82ed89f8559f22fb 100644 (file)
@@ -1,14 +1,14 @@
 /* Lisp parsing and input streams.
    Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995,
                  1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+                 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,9 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
 #include <config.h>
@@ -31,7 +29,9 @@ Boston, MA 02110-1301, USA.  */
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
+#include "character.h"
 #include "charset.h"
+#include "coding.h"
 #include <epaths.h>
 #include "commands.h"
 #include "keyboard.h"
@@ -40,10 +40,6 @@ Boston, MA 02110-1301, USA.  */
 #include "coding.h"
 #include "blockinput.h"
 
-#ifdef lint
-#include <sys/inode.h>
-#endif /* lint */
-
 #ifdef MSDOS
 #if __DJGPP__ < 2
 #include <unistd.h>    /* to get X_OK */
@@ -84,6 +80,14 @@ Boston, MA 02110-1301, USA.  */
 extern int errno;
 #endif
 
+/* hash table read constants */
+Lisp_Object Qhash_table, Qdata;
+Lisp_Object Qtest, Qsize;
+Lisp_Object Qweakness;
+Lisp_Object Qrehash_size;
+Lisp_Object Qrehash_threshold;
+extern Lisp_Object QCtest, QCsize, QCrehash_size, QCrehash_threshold, QCweakness;
+
 Lisp_Object Qread_char, Qget_file_char, Qstandard_input, Qcurrent_load_list;
 Lisp_Object Qvariable_documentation, Vvalues, Vstandard_input, Vafter_load_alist;
 Lisp_Object Qascii_character, Qload, Qload_file_name;
@@ -92,11 +96,18 @@ Lisp_Object Qinhibit_file_name_operation;
 Lisp_Object Qeval_buffer_list, Veval_buffer_list;
 Lisp_Object Qfile_truename, Qdo_after_load_evaluation; /* ACM 2006/5/16 */
 
+/* Used instead of Qget_file_char while loading *.elc files compiled
+   by Emacs 21 or older.  */
+static Lisp_Object Qget_emacs_mule_file_char;
+
+static Lisp_Object Qload_force_doc_strings;
+
 extern Lisp_Object Qevent_symbol_element_mask;
 extern Lisp_Object Qfile_exists_p;
 
 /* non-zero if inside `load' */
 int load_in_progress;
+static Lisp_Object Qload_in_progress;
 
 /* Directory in which the sources were found.  */
 Lisp_Object Vsource_directory;
@@ -123,6 +134,9 @@ Lisp_Object Vload_file_name;
 /* Function to use for reading, in `load' and friends.  */
 Lisp_Object Vload_read_function;
 
+/* Non-nil means read recursive structures using #n= and #n# syntax.  */
+Lisp_Object Vread_circle;
+
 /* The association list of objects read with the #n=object form.
    Each member of the list has the form (n . object), and is used to
    look up the object for the corresponding #n# construct.
@@ -135,6 +149,11 @@ static int load_force_doc_strings;
 /* Nonzero means read should convert strings to unibyte.  */
 static int load_convert_to_unibyte;
 
+/* Nonzero means READCHAR should read bytes one by one (not character)
+   when READCHARFUN is Qget_file_char or Qget_emacs_mule_file_char.
+   This is set to 1 by read1 temporarily while handling #@NUMBER.  */
+static int load_each_byte;
+
 /* Function to use for loading an Emacs Lisp source file (not
    compiled) instead of readevalloop.  */
 Lisp_Object Vload_source_file_function;
@@ -163,9 +182,6 @@ static int read_from_string_index;
 static int read_from_string_index_byte;
 static int read_from_string_limit;
 
-/* Number of bytes left to read in the buffer character
-   that `readchar' has already advanced over.  */
-static int readchar_backlog;
 /* Number of characters read in the current call to Fread or
    Fread_from_string. */
 static int readchar_count;
@@ -206,11 +222,17 @@ static Lisp_Object Vloads_in_progress;
 
 int load_dangerous_libraries;
 
+/* Non-zero means force printing messages when loading Lisp files.  */
+
+int force_load_messages;
+
 /* A regular expression used to detect files compiled with Emacs.  */
 
 static Lisp_Object Vbytecomp_version_regexp;
 
-static void to_multibyte P_ ((char **, char **, int *));
+static int read_emacs_mule_char P_ ((int, int (*) (int, Lisp_Object),
+                                    Lisp_Object));
+
 static void readevalloop P_ ((Lisp_Object, FILE*, Lisp_Object,
                              Lisp_Object (*) (), int,
                              Lisp_Object, Lisp_Object,
@@ -222,29 +244,48 @@ static void invalid_syntax P_ ((const char *, int)) NO_RETURN;
 static void end_of_file_error P_ (()) NO_RETURN;
 
 \f
+/* Functions that read one byte from the current source READCHARFUN
+   or unreads one byte.  If the integer argument C is -1, it returns
+   one read byte, or -1 when there's no more byte in the source.  If C
+   is 0 or positive, it unreads C, and the return value is not
+   interesting.  */
+
+static int readbyte_for_lambda P_ ((int, Lisp_Object));
+static int readbyte_from_file P_ ((int, Lisp_Object));
+static int readbyte_from_string P_ ((int, Lisp_Object));
+
 /* Handle unreading and rereading of characters.
    Write READCHAR to read a character,
    UNREAD(c) to unread c to be read again.
 
-   The READCHAR and UNREAD macros are meant for reading/unreading a
-   byte code; they do not handle multibyte characters.  The caller
-   should manage them if necessary.
-
-   [ Actually that seems to be a lie; READCHAR will definitely read
-     multibyte characters from buffer sources, at least.  Is the
-     comment just out of date?
-     -- Colin Walters <walters@gnu.org>, 22 May 2002 16:36:50 -0400 ]
- */
+   These macros correctly read/unread multibyte characters.  */
 
-#define READCHAR readchar (readcharfun)
+#define READCHAR readchar (readcharfun, NULL)
 #define UNREAD(c) unreadchar (readcharfun, c)
 
+/* Same as READCHAR but set *MULTIBYTE to the multibyteness of the source.  */
+#define READCHAR_REPORT_MULTIBYTE(multibyte) readchar (readcharfun, multibyte)
+
+/* When READCHARFUN is Qget_file_char, Qget_emacs_mule_file_char,
+   Qlambda, or a cons, we use this to keep an unread character because
+   a file stream can't handle multibyte-char unreading.  The value -1
+   means that there's no unread character. */
+static int unread_char;
+
 static int
-readchar (readcharfun)
+readchar (readcharfun, multibyte)
      Lisp_Object readcharfun;
+     int *multibyte;
 {
   Lisp_Object tem;
   register int c;
+  int (*readbyte) P_ ((int, Lisp_Object));
+  unsigned char buf[MAX_MULTIBYTE_LENGTH];
+  int i, len;
+  int emacs_mule_encoding = 0;
+
+  if (multibyte)
+    *multibyte = 0;
 
   readchar_count++;
 
@@ -253,31 +294,24 @@ readchar (readcharfun)
       register struct buffer *inbuffer = XBUFFER (readcharfun);
 
       int pt_byte = BUF_PT_BYTE (inbuffer);
-      int orig_pt_byte = pt_byte;
-
-      if (readchar_backlog > 0)
-       /* We get the address of the byte just passed,
-          which is the last byte of the character.
-          The other bytes in this character are consecutive with it,
-          because the gap can't be in the middle of a character.  */
-       return *(BUF_BYTE_ADDRESS (inbuffer, BUF_PT_BYTE (inbuffer) - 1)
-                - --readchar_backlog);
 
       if (pt_byte >= BUF_ZV_BYTE (inbuffer))
        return -1;
 
-      readchar_backlog = -1;
-
       if (! NILP (inbuffer->enable_multibyte_characters))
        {
          /* Fetch the character code from the buffer.  */
          unsigned char *p = BUF_BYTE_ADDRESS (inbuffer, pt_byte);
          BUF_INC_POS (inbuffer, pt_byte);
-         c = STRING_CHAR (p, pt_byte - orig_pt_byte);
+         c = STRING_CHAR (p);
+         if (multibyte)
+           *multibyte = 1;
        }
       else
        {
          c = BUF_FETCH_BYTE (inbuffer, pt_byte);
+         if (! ASCII_BYTE_P (c))
+           c = BYTE8_TO_CHAR (c);
          pt_byte++;
        }
       SET_BUF_PT_BOTH (inbuffer, BUF_PT (inbuffer) + 1, pt_byte);
@@ -289,31 +323,24 @@ readchar (readcharfun)
       register struct buffer *inbuffer = XMARKER (readcharfun)->buffer;
 
       int bytepos = marker_byte_position (readcharfun);
-      int orig_bytepos = bytepos;
-
-      if (readchar_backlog > 0)
-       /* We get the address of the byte just passed,
-          which is the last byte of the character.
-          The other bytes in this character are consecutive with it,
-          because the gap can't be in the middle of a character.  */
-       return *(BUF_BYTE_ADDRESS (inbuffer, XMARKER (readcharfun)->bytepos - 1)
-                - --readchar_backlog);
 
       if (bytepos >= BUF_ZV_BYTE (inbuffer))
        return -1;
 
-      readchar_backlog = -1;
-
       if (! NILP (inbuffer->enable_multibyte_characters))
        {
          /* Fetch the character code from the buffer.  */
          unsigned char *p = BUF_BYTE_ADDRESS (inbuffer, bytepos);
          BUF_INC_POS (inbuffer, bytepos);
-         c = STRING_CHAR (p, bytepos - orig_bytepos);
+         c = STRING_CHAR (p);
+         if (multibyte)
+           *multibyte = 1;
        }
       else
        {
          c = BUF_FETCH_BYTE (inbuffer, bytepos);
+         if (! ASCII_BYTE_P (c))
+           c = BYTE8_TO_CHAR (c);
          bytepos++;
        }
 
@@ -324,44 +351,95 @@ readchar (readcharfun)
     }
 
   if (EQ (readcharfun, Qlambda))
-    return read_bytecode_char (0);
+    {
+      readbyte = readbyte_for_lambda;
+      goto read_multibyte;
+    }
 
   if (EQ (readcharfun, Qget_file_char))
     {
-      BLOCK_INPUT;
-      c = getc (instream);
-#ifdef EINTR
-      /* Interrupted reads have been observed while reading over the network */
-      while (c == EOF && ferror (instream) && errno == EINTR)
-       {
-         UNBLOCK_INPUT;
-         QUIT;
-         BLOCK_INPUT;
-         clearerr (instream);
-         c = getc (instream);
-       }
-#endif
-      UNBLOCK_INPUT;
-      return c;
+      readbyte = readbyte_from_file;
+      goto read_multibyte;
     }
 
   if (STRINGP (readcharfun))
     {
       if (read_from_string_index >= read_from_string_limit)
        c = -1;
+      else if (STRING_MULTIBYTE (readcharfun))
+       {
+         if (multibyte)
+           *multibyte = 1;
+         FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, readcharfun,
+                                             read_from_string_index,
+                                             read_from_string_index_byte);
+       }
       else
-       FETCH_STRING_CHAR_ADVANCE (c, readcharfun,
-                                  read_from_string_index,
-                                  read_from_string_index_byte);
-
+       {
+         c = SREF (readcharfun, read_from_string_index_byte);
+         read_from_string_index++;
+         read_from_string_index_byte++;
+       }
       return c;
     }
 
+  if (CONSP (readcharfun))
+    {
+      /* This is the case that read_vector is reading from a unibyte
+        string that contains a byte sequence previously skipped
+        because of #@NUMBER.  The car part of readcharfun is that
+        string, and the cdr part is a value of readcharfun given to
+        read_vector.  */
+      readbyte = readbyte_from_string;
+      if (EQ (XCDR (readcharfun), Qget_emacs_mule_file_char))
+       emacs_mule_encoding = 1;
+      goto read_multibyte;
+    }
+
+  if (EQ (readcharfun, Qget_emacs_mule_file_char))
+    {
+      readbyte = readbyte_from_file;
+      emacs_mule_encoding = 1;
+      goto read_multibyte;
+    }
+
   tem = call0 (readcharfun);
 
   if (NILP (tem))
     return -1;
   return XINT (tem);
+
+ read_multibyte:
+  if (unread_char >= 0)
+    {
+      c = unread_char;
+      unread_char = -1;
+      return c;
+    }
+  c = (*readbyte) (-1, readcharfun);
+  if (c < 0 || load_each_byte)
+    return c;
+  if (multibyte)
+    *multibyte = 1;
+  if (ASCII_BYTE_P (c))
+    return c;
+  if (emacs_mule_encoding)
+    return read_emacs_mule_char (c, readbyte, readcharfun);
+  i = 0;
+  buf[i++] = c;
+  len = BYTES_BY_CHAR_HEAD (c);
+  while (i < len)
+    {
+      c = (*readbyte) (-1, readcharfun);
+      if (c < 0 || ! TRAILING_CODE_P (c))
+       {
+         while (--i > 1)
+           (*readbyte) (buf[i], readcharfun);
+         return BYTE8_TO_CHAR (buf[0]);
+       }
+      buf[i++] = c;
+    }
+  return STRING_CHAR (buf);
 }
 
 /* Unread the character C in the way appropriate for the stream READCHARFUN.
@@ -380,38 +458,28 @@ unreadchar (readcharfun, c)
   else if (BUFFERP (readcharfun))
     {
       struct buffer *b = XBUFFER (readcharfun);
-      int bytepos = BUF_PT_BYTE (b);
+      EMACS_INT charpos = BUF_PT (b);
+      EMACS_INT bytepos = BUF_PT_BYTE (b);
 
-      if (readchar_backlog >= 0)
-       readchar_backlog++;
+      if (! NILP (b->enable_multibyte_characters))
+       BUF_DEC_POS (b, bytepos);
       else
-       {
-         BUF_PT (b)--;
-         if (! NILP (b->enable_multibyte_characters))
-           BUF_DEC_POS (b, bytepos);
-         else
-           bytepos--;
+       bytepos--;
 
-         BUF_PT_BYTE (b) = bytepos;
-       }
+      SET_BUF_PT_BOTH (b, charpos - 1, bytepos);
     }
   else if (MARKERP (readcharfun))
     {
       struct buffer *b = XMARKER (readcharfun)->buffer;
       int bytepos = XMARKER (readcharfun)->bytepos;
 
-      if (readchar_backlog >= 0)
-       readchar_backlog++;
+      XMARKER (readcharfun)->charpos--;
+      if (! NILP (b->enable_multibyte_characters))
+       BUF_DEC_POS (b, bytepos);
       else
-       {
-         XMARKER (readcharfun)->charpos--;
-         if (! NILP (b->enable_multibyte_characters))
-           BUF_DEC_POS (b, bytepos);
-         else
-           bytepos--;
+       bytepos--;
 
-         XMARKER (readcharfun)->bytepos = bytepos;
-       }
+      XMARKER (readcharfun)->bytepos = bytepos;
     }
   else if (STRINGP (readcharfun))
     {
@@ -419,18 +487,165 @@ unreadchar (readcharfun, c)
       read_from_string_index_byte
        = string_char_to_byte (readcharfun, read_from_string_index);
     }
+  else if (CONSP (readcharfun))
+    {
+      unread_char = c;
+    }
   else if (EQ (readcharfun, Qlambda))
-    read_bytecode_char (1);
-  else if (EQ (readcharfun, Qget_file_char))
+    {
+      unread_char = c;
+    }
+  else if (EQ (readcharfun, Qget_file_char)
+          || EQ (readcharfun, Qget_emacs_mule_file_char))
+    {
+      if (load_each_byte)
+       {
+         BLOCK_INPUT;
+         ungetc (c, instream);
+         UNBLOCK_INPUT;
+       }
+      else
+       unread_char = c;
+    }
+  else
+    call1 (readcharfun, make_number (c));
+}
+
+static int
+readbyte_for_lambda (c, readcharfun)
+     int c;
+     Lisp_Object readcharfun;
+{
+  return read_bytecode_char (c >= 0);
+}
+
+
+static int
+readbyte_from_file (c, readcharfun)
+     int c;
+     Lisp_Object readcharfun;
+{
+  if (c >= 0)
     {
       BLOCK_INPUT;
       ungetc (c, instream);
       UNBLOCK_INPUT;
+      return 0;
+    }
+
+  BLOCK_INPUT;
+  c = getc (instream);
+
+#ifdef EINTR
+  /* Interrupted reads have been observed while reading over the network */
+  while (c == EOF && ferror (instream) && errno == EINTR)
+    {
+      UNBLOCK_INPUT;
+      QUIT;
+      BLOCK_INPUT;
+      clearerr (instream);
+      c = getc (instream);
+    }
+#endif
+
+  UNBLOCK_INPUT;
+
+  return (c == EOF ? -1 : c);
+}
+
+static int
+readbyte_from_string (c, readcharfun)
+     int c;
+     Lisp_Object readcharfun;
+{
+  Lisp_Object string = XCAR (readcharfun);
+
+  if (c >= 0)
+    {
+      read_from_string_index--;
+      read_from_string_index_byte
+       = string_char_to_byte (string, read_from_string_index);
     }
+
+  if (read_from_string_index >= read_from_string_limit)
+    c = -1;
   else
-    call1 (readcharfun, make_number (c));
+    FETCH_STRING_CHAR_ADVANCE (c, string,
+                              read_from_string_index,
+                              read_from_string_index_byte);
+  return c;
 }
 
+
+/* Read one non-ASCII character from INSTREAM.  The character is
+   encoded in `emacs-mule' and the first byte is already read in
+   C.  */
+
+extern char emacs_mule_bytes[256];
+
+static int
+read_emacs_mule_char (c, readbyte, readcharfun)
+     int c;
+     int (*readbyte) P_ ((int, Lisp_Object));
+     Lisp_Object readcharfun;
+{
+  /* Emacs-mule coding uses at most 4-byte for one character.  */
+  unsigned char buf[4];
+  int len = emacs_mule_bytes[c];
+  struct charset *charset;
+  int i;
+  unsigned code;
+
+  if (len == 1)
+    /* C is not a valid leading-code of `emacs-mule'.  */
+    return BYTE8_TO_CHAR (c);
+
+  i = 0;
+  buf[i++] = c;
+  while (i < len)
+    {
+      c = (*readbyte) (-1, readcharfun);
+      if (c < 0xA0)
+       {
+         while (--i > 1)
+           (*readbyte) (buf[i], readcharfun);
+         return BYTE8_TO_CHAR (buf[0]);
+       }
+      buf[i++] = c;
+    }
+
+  if (len == 2)
+    {
+      charset = CHARSET_FROM_ID (emacs_mule_charset[buf[0]]);
+      code = buf[1] & 0x7F;
+    }
+  else if (len == 3)
+    {
+      if (buf[0] == EMACS_MULE_LEADING_CODE_PRIVATE_11
+         || buf[0] == EMACS_MULE_LEADING_CODE_PRIVATE_12)
+       {
+         charset = CHARSET_FROM_ID (emacs_mule_charset[buf[1]]);
+         code = buf[2] & 0x7F;
+       }
+      else
+       {
+         charset = CHARSET_FROM_ID (emacs_mule_charset[buf[0]]);
+         code = ((buf[1] << 8) | buf[2]) & 0x7F7F;
+       }
+    }
+  else
+    {
+      charset = CHARSET_FROM_ID (emacs_mule_charset[buf[1]]);
+      code = ((buf[2] << 8) | buf[3]) & 0x7F7F;
+    }
+  c = DECODE_CHAR (charset, code);
+  if (c < 0)
+    Fsignal (Qinvalid_read_syntax,
+            Fcons (build_string ("invalid multibyte form"), Qnil));
+  return c;
+}
+
+
 static Lisp_Object read_internal_start P_ ((Lisp_Object, Lisp_Object,
                                            Lisp_Object));
 static Lisp_Object read0 P_ ((Lisp_Object));
@@ -438,7 +653,6 @@ static Lisp_Object read1 P_ ((Lisp_Object, int *, int));
 
 static Lisp_Object read_list P_ ((int, Lisp_Object));
 static Lisp_Object read_vector P_ ((Lisp_Object, int));
-static int read_multibyte P_ ((int, Lisp_Object));
 
 static Lisp_Object substitute_object_recurse P_ ((Lisp_Object, Lisp_Object,
                                                  Lisp_Object));
@@ -571,10 +785,13 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii,
 DEFUN ("read-char", Fread_char, Sread_char, 0, 3, 0,
        doc: /* Read a character from the command input (keyboard or macro).
 It is returned as a number.
+If the character has modifiers, they are resolved and reflected to the
+character code if possible (e.g. C-SPC -> 0).
+
 If the user generates an event which is not a character (i.e. a mouse
 click or function key event), `read-char' signals an error.  As an
-exception, switch-frame events are put off until non-ASCII events can
-be read.
+exception, switch-frame events are put off until non-character events
+can be read.
 If you want to read non-character events, or ignore them, call
 `read-event' or `read-char-exclusive' instead.
 
@@ -589,9 +806,14 @@ floating-point value.  */)
      (prompt, inherit_input_method, seconds)
      Lisp_Object prompt, inherit_input_method, seconds;
 {
+  Lisp_Object val;
+
   if (! NILP (prompt))
     message_with_string ("%s", prompt, 0);
-  return read_filtered_event (1, 1, 1, ! NILP (inherit_input_method), seconds);
+  val = read_filtered_event (1, 1, 1, ! NILP (inherit_input_method), seconds);
+
+  return (NILP (val) ? Qnil
+         : make_number (char_resolve_modifier_mask (XINT (val))));
 }
 
 DEFUN ("read-event", Fread_event, Sread_event, 0, 3, 0,
@@ -615,6 +837,8 @@ floating-point value.  */)
 DEFUN ("read-char-exclusive", Fread_char_exclusive, Sread_char_exclusive, 0, 3, 0,
        doc: /* Read a character from the command input (keyboard or macro).
 It is returned as a number.  Non-character events are ignored.
+If the character has modifiers, they are resolved and reflected to the
+character code if possible (e.g. C-SPC -> 0).
 
 If the optional argument PROMPT is non-nil, display that as a prompt.
 If the optional argument INHERIT-INPUT-METHOD is non-nil and some
@@ -627,9 +851,15 @@ floating-point value.  */)
      (prompt, inherit_input_method, seconds)
      Lisp_Object prompt, inherit_input_method, seconds;
 {
+  Lisp_Object val;
+
   if (! NILP (prompt))
     message_with_string ("%s", prompt, 0);
-  return read_filtered_event (1, 1, 0, ! NILP (inherit_input_method), seconds);
+
+  val = read_filtered_event (1, 1, 0, ! NILP (inherit_input_method), seconds);
+
+  return (NILP (val) ? Qnil
+         : make_number (char_resolve_modifier_mask (XINT (val))));
 }
 
 DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
@@ -645,11 +875,11 @@ DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
 
 
 \f
-/* Value is non-zero if the file associated with file descriptor FD
-   is a compiled Lisp file that's safe to load.  Only files compiled
-   with Emacs are safe to load.  Files compiled with XEmacs can lead
-   to a crash in Fbyte_code because of an incompatible change in the
-   byte compiler.  */
+/* Value is a version number of byte compiled code if the file
+   associated with file descriptor FD is a compiled Lisp file that's
+   safe to load.  Only files compiled with Emacs are safe to load.
+   Files compiled with XEmacs can lead to a crash in Fbyte_code
+   because of an incompatible change in the byte compiler.  */
 
 static int
 safe_to_load_p (fd)
@@ -658,6 +888,7 @@ safe_to_load_p (fd)
   char buf[512];
   int nbytes, i;
   int safe_p = 1;
+  int version = 1;
 
   /* Read the first few bytes from the file, and look for a line
      specifying the byte compiler version used.  */
@@ -667,15 +898,18 @@ safe_to_load_p (fd)
       buf[nbytes] = '\0';
 
       /* Skip to the next newline, skipping over the initial `ELC'
-        with NUL bytes following it.  */
+        with NUL bytes following it, but note the version.  */
       for (i = 0; i < nbytes && buf[i] != '\n'; ++i)
-       ;
+       if (i == 4)
+         version = buf[i];
 
-      if (i < nbytes
-         && fast_c_string_match_ignore_case (Vbytecomp_version_regexp,
+      if (i == nbytes
+         || fast_c_string_match_ignore_case (Vbytecomp_version_regexp,
                                              buf + i) < 0)
        safe_p = 0;
     }
+  if (safe_p)
+    safe_p = version;
 
   lseek (fd, 0, SEEK_SET);
   return safe_p;
@@ -748,7 +982,8 @@ This function searches the directories in `load-path'.
 If optional second arg NOERROR is non-nil,
 report no error if FILE doesn't exist.
 Print messages at start and end of loading unless
-optional third arg NOMESSAGE is non-nil.
+optional third arg NOMESSAGE is non-nil (but `force-load-messages'
+overrides that).
 If optional fourth arg NOSUFFIX is non-nil, don't try adding
 suffixes `.elc' or `.el' to the specified name FILE.
 If optional fifth arg MUST-SUFFIX is non-nil, insist on
@@ -772,6 +1007,10 @@ Loading a file records its definitions, and its `provide' and
 `require' calls, in an element of `load-history' whose
 car is the file name loaded.  See `load-history'.
 
+While the file is in the process of being loaded, the variable
+`load-in-progress' is non-nil and the variable `load-file-name'
+is bound to the file's name.
+
 Return t if the file exists and loads successfully.  */)
      (file, noerror, nomessage, nosuffix, must_suffix)
      Lisp_Object file, noerror, nomessage, nosuffix, must_suffix;
@@ -789,6 +1028,8 @@ Return t if the file exists and loads successfully.  */)
   int safe_p = 1;
   char *fmode = "r";
   Lisp_Object tmp[2];
+  int version;
+
 #ifdef DOS_NT
   fmode = "rt";
 #endif /* DOS_NT */
@@ -884,7 +1125,7 @@ Return t if the file exists and loads successfully.  */)
      2000-09-21: It's not possible to just check for the file loaded
      being a member of Vloads_in_progress.  This fails because of the
      way the byte compiler currently works; `provide's are not
-     evaluted, see font-lock.el/jit-lock.el as an example.  This
+     evaluated, see font-lock.el/jit-lock.el as an example.  This
      leads to a certain amount of ``normal'' recursion.
 
      Also, just loading a file recursively is not always an error in
@@ -893,14 +1134,12 @@ Return t if the file exists and loads successfully.  */)
     int count = 0;
     Lisp_Object tem;
     for (tem = Vloads_in_progress; CONSP (tem); tem = XCDR (tem))
-      if (!NILP (Fequal (found, XCAR (tem))))
-       count++;
-    if (count > 3)
-      {
-       if (fd >= 0)
-         emacs_close (fd);
-       signal_error ("Recursive load", Fcons (found, Vloads_in_progress));
-      }
+      if (!NILP (Fequal (found, XCAR (tem))) && (++count > 3))
+       {
+         if (fd >= 0)
+           emacs_close (fd);
+         signal_error ("Recursive load", Fcons (found, Vloads_in_progress));
+       }
     record_unwind_protect (record_load_unwind, Vloads_in_progress);
     Vloads_in_progress = Fcons (found, Vloads_in_progress);
   }
@@ -912,12 +1151,15 @@ Return t if the file exists and loads successfully.  */)
                                    tmp))
                     : found) ;
 
+  version = -1;
+
   /* Check for the presence of old-style quotes and warn about them.  */
   specbind (Qold_style_backquotes, Qnil);
   record_unwind_protect (load_warn_old_style_backquotes, file);
 
   if (!bcmp (SDATA (found) + SBYTES (found) - 4,
-            ".elc", 4))
+            ".elc", 4)
+      || (fd >= 0 && (version = safe_to_load_p (fd)) > 0))
     /* Load .elc files directly, but not when they are
        remote and have no handler!  */
     {
@@ -928,7 +1170,8 @@ Return t if the file exists and loads successfully.  */)
 
          GCPRO3 (file, found, hist_file_name);
 
-         if (!safe_to_load_p (fd))
+         if (version < 0
+             && ! (version = safe_to_load_p (fd)))
            {
              safe_p = 0;
              if (!load_dangerous_libraries)
@@ -938,7 +1181,7 @@ Return t if the file exists and loads successfully.  */)
                  error ("File `%s' was not compiled in Emacs",
                         SDATA (found));
                }
-             else if (!NILP (nomessage))
+             else if (!NILP (nomessage) && !force_load_messages)
                message_with_string ("File `%s' not compiled in Emacs", found, 1);
            }
 
@@ -960,7 +1203,7 @@ Return t if the file exists and loads successfully.  */)
              newer = 1;
 
              /* If we won't print another message, mention this anyway.  */
-             if (!NILP (nomessage))
+             if (!NILP (nomessage) && !force_load_messages)
                {
                  Lisp_Object msg_file;
                  msg_file = Fsubstring (found, make_number (0), make_number (-1));
@@ -982,7 +1225,7 @@ Return t if the file exists and loads successfully.  */)
            emacs_close (fd);
          val = call4 (Vload_source_file_function, found, hist_file_name,
                       NILP (noerror) ? Qnil : Qt,
-                      NILP (nomessage) ? Qnil : Qt);
+                      (NILP (nomessage) || force_load_messages) ? Qnil : Qt);
          return unbind_to (count, val);
        }
     }
@@ -1003,9 +1246,9 @@ Return t if the file exists and loads successfully.  */)
     }
 
   if (! NILP (Vpurify_flag))
-    Vpreloaded_file_list = Fcons (file, Vpreloaded_file_list);
+    Vpreloaded_file_list = Fcons (Fpurecopy(file), Vpreloaded_file_list);
 
-  if (NILP (nomessage))
+  if (NILP (nomessage) || force_load_messages)
     {
       if (!safe_p)
        message_with_string ("Loading %s (compiled; note unsafe, not compiled in Emacs)...",
@@ -1025,29 +1268,35 @@ Return t if the file exists and loads successfully.  */)
   specbind (Qinhibit_file_name_operation, Qnil);
   load_descriptor_list
     = Fcons (make_number (fileno (stream)), load_descriptor_list);
-  load_in_progress++;
-  readevalloop (Qget_file_char, stream, hist_file_name,
-               Feval, 0, Qnil, Qnil, Qnil, Qnil);
+  specbind (Qload_in_progress, Qt);
+  if (! version || version >= 22)
+    readevalloop (Qget_file_char, stream, hist_file_name,
+                 Feval, 0, Qnil, Qnil, Qnil, Qnil);
+  else
+    {
+      /* We can't handle a file which was compiled with
+        byte-compile-dynamic by older version of Emacs.  */
+      specbind (Qload_force_doc_strings, Qt);
+      readevalloop (Qget_emacs_mule_file_char, stream, hist_file_name, Feval,
+                   0, Qnil, Qnil, Qnil, Qnil);
+    }
   unbind_to (count, Qnil);
 
   /* Run any eval-after-load forms for this file */
-  if (NILP (Vpurify_flag)
-      && (!NILP (Ffboundp (Qdo_after_load_evaluation))))
+  if (!NILP (Ffboundp (Qdo_after_load_evaluation)))
     call1 (Qdo_after_load_evaluation, hist_file_name) ;
 
   UNGCPRO;
 
-  if (saved_doc_string)
-    free (saved_doc_string);
+  xfree (saved_doc_string);
   saved_doc_string = 0;
   saved_doc_string_size = 0;
 
-  if (prev_saved_doc_string)
-    xfree (prev_saved_doc_string);
+  xfree (prev_saved_doc_string);
   prev_saved_doc_string = 0;
   prev_saved_doc_string_size = 0;
 
-  if (!noninteractive && NILP (nomessage))
+  if (!noninteractive && (NILP (nomessage) || force_load_messages))
     {
       if (!safe_p)
        message_with_string ("Loading %s (compiled; note unsafe, not compiled in Emacs)...done",
@@ -1061,11 +1310,6 @@ Return t if the file exists and loads successfully.  */)
        message_with_string ("Loading %s...done", file, 1);
     }
 
-  if (!NILP (Fequal (build_string ("obsolete"),
-                    Ffile_name_nondirectory
-                    (Fdirectory_file_name (Ffile_name_directory (found))))))
-    message_with_string ("Package %s is obsolete", file, 1);
-
   return Qt;
 }
 
@@ -1080,7 +1324,6 @@ load_unwind (arg)  /* used as unwind-protect function in load */
       fclose (stream);
       UNBLOCK_INPUT;
     }
-  if (--load_in_progress < 0) load_in_progress = 0;
   return Qnil;
 }
 
@@ -1112,14 +1355,7 @@ complete_filename_p (pathname)
   register const unsigned char *s = SDATA (pathname);
   return (IS_DIRECTORY_SEP (s[0])
          || (SCHARS (pathname) > 2
-             && IS_DEVICE_SEP (s[1]) && IS_DIRECTORY_SEP (s[2]))
-#ifdef ALTOS
-         || *s == '@'
-#endif
-#ifdef VMS
-         || index (s, ':')
-#endif /* VMS */
-         );
+             && IS_DEVICE_SEP (s[1]) && IS_DIRECTORY_SEP (s[2])));
 }
 
 DEFUN ("locate-file-internal", Flocate_file_internal, Slocate_file_internal, 2, 4, 0,
@@ -1456,8 +1692,6 @@ readevalloop (readcharfun, stream, sourcename, evalfun,
   record_unwind_protect (readevalloop_1, load_convert_to_unibyte ? Qt : Qnil);
   load_convert_to_unibyte = !NILP (unibyte);
 
-  readchar_backlog = -1;
-
   GCPRO4 (sourcename, readfun, start, end);
 
   /* Try to ensure sourcename is a truename, except whilst preloading. */
@@ -1583,18 +1817,16 @@ readevalloop (readcharfun, stream, sourcename, evalfun,
 
 DEFUN ("eval-buffer", Feval_buffer, Seval_buffer, 0, 5, "",
        doc: /* Execute the current buffer as Lisp code.
-Programs can pass two arguments, BUFFER and PRINTFLAG.
+When called from a Lisp program (i.e., not interactively), this
+function accepts up to five optional arguments:
 BUFFER is the buffer to evaluate (nil means use current buffer).
 PRINTFLAG controls printing of output:
-A value of nil means discard it; anything else is stream for print.
-
-If the optional third argument FILENAME is non-nil,
-it specifies the file name to use for `load-history'.
-The optional fourth argument UNIBYTE specifies `load-convert-to-unibyte'
-for this invocation.
-
-The optional fifth argument DO-ALLOW-PRINT, if non-nil, specifies that
-`print' and related functions should work normally even if PRINTFLAG is nil.
+ A value of nil means discard it; anything else is stream for print.
+FILENAME specifies the file name to use for `load-history'.
+UNIBYTE, if non-nil, specifies `load-convert-to-unibyte' for this
+ invocation.
+DO-ALLOW-PRINT, if non-nil, specifies that `print' and related
+ functions should work normally even if PRINTFLAG is nil.
 
 This function preserves the position of point.  */)
      (buffer, printflag, filename, unibyte, do_allow_print)
@@ -1621,7 +1853,7 @@ This function preserves the position of point.  */)
   specbind (Qeval_buffer_list, Fcons (buf, Veval_buffer_list));
   specbind (Qstandard_output, tem);
   record_unwind_protect (save_excursion_restore, save_excursion_save ());
-  BUF_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf)));
+  BUF_TEMP_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf)));
   readevalloop (buf, 0, filename, Feval,
                !NILP (printflag), unibyte, Qnil, Qnil, Qnil);
   unbind_to (count, Qnil);
@@ -1714,7 +1946,6 @@ read_internal_start (stream, start, end)
 {
   Lisp_Object retval;
 
-  readchar_backlog = -1;
   readchar_count = 0;
   new_backquote_flag = 0;
   read_objects = Qnil;
@@ -1722,17 +1953,25 @@ read_internal_start (stream, start, end)
       || EQ (Vread_with_symbol_positions, stream))
     Vread_symbol_positions_list = Qnil;
 
-  if (STRINGP (stream))
+  if (STRINGP (stream)
+      || ((CONSP (stream) && STRINGP (XCAR (stream)))))
     {
       int startval, endval;
+      Lisp_Object string;
+
+      if (STRINGP (stream))
+       string = stream;
+      else
+       string = XCAR (stream);
+
       if (NILP (end))
-       endval = SCHARS (stream);
+       endval = SCHARS (string);
       else
        {
          CHECK_NUMBER (end);
          endval = XINT (end);
-         if (endval < 0 || endval > SCHARS (stream))
-           args_out_of_range (stream, end);
+         if (endval < 0 || endval > SCHARS (string))
+           args_out_of_range (string, end);
        }
 
       if (NILP (start))
@@ -1742,10 +1981,10 @@ read_internal_start (stream, start, end)
          CHECK_NUMBER (start);
          startval = XINT (start);
          if (startval < 0 || startval > endval)
-           args_out_of_range (stream, start);
+           args_out_of_range (string, start);
        }
       read_from_string_index = startval;
-      read_from_string_index_byte = string_char_to_byte (stream, startval);
+      read_from_string_index_byte = string_char_to_byte (string, startval);
       read_from_string_limit = endval;
     }
 
@@ -1792,59 +2031,19 @@ read0 (readcharfun)
 static int read_buffer_size;
 static char *read_buffer;
 
-/* Read multibyte form and return it as a character.  C is a first
-   byte of multibyte form, and rest of them are read from
-   READCHARFUN.  */
-
-static int
-read_multibyte (c, readcharfun)
-     register int c;
-     Lisp_Object readcharfun;
-{
-  /* We need the actual character code of this multibyte
-     characters.  */
-  unsigned char str[MAX_MULTIBYTE_LENGTH];
-  int len = 0;
-  int bytes;
-
-  if (c < 0)
-    return c;
-
-  str[len++] = c;
-  while ((c = READCHAR) >= 0xA0
-        && len < MAX_MULTIBYTE_LENGTH)
-    {
-      str[len++] = c;
-      readchar_count--;
-    }
-  UNREAD (c);
-  if (UNIBYTE_STR_AS_MULTIBYTE_P (str, len, bytes))
-    return STRING_CHAR (str, len);
-  /* The byte sequence is not valid as multibyte.  Unread all bytes
-     but the first one, and return the first byte.  */
-  while (--len > 0)
-    UNREAD (str[len]);
-  return str[0];
-}
-
 /* Read a \-escape sequence, assuming we already read the `\'.
-   If the escape sequence forces unibyte, store 1 into *BYTEREP.
-   If the escape sequence forces multibyte, store 2 into *BYTEREP.
-   Otherwise store 0 into *BYTEREP.  */
+   If the escape sequence forces unibyte, return eight-bit char.  */
 
 static int
-read_escape (readcharfun, stringp, byterep)
+read_escape (readcharfun, stringp)
      Lisp_Object readcharfun;
      int stringp;
-     int *byterep;
 {
   register int c = READCHAR;
-  /* \u allows up to four hex digits, \U up to eight. Default to the
-     behaviour for \u, and change this value in the case that \U is seen. */
+  /* \u allows up to four hex digits, \U up to eight.  Default to the
+     behavior for \u, and change this value in the case that \U is seen. */
   int unicode_hex_count = 4;
 
-  *byterep = 0;
-
   switch (c)
     {
     case -1:
@@ -1881,7 +2080,7 @@ read_escape (readcharfun, stringp, byterep)
        error ("Invalid escape character syntax");
       c = READCHAR;
       if (c == '\\')
-       c = read_escape (readcharfun, 0, byterep);
+       c = read_escape (readcharfun, 0);
       return c | meta_modifier;
 
     case 'S':
@@ -1890,7 +2089,7 @@ read_escape (readcharfun, stringp, byterep)
        error ("Invalid escape character syntax");
       c = READCHAR;
       if (c == '\\')
-       c = read_escape (readcharfun, 0, byterep);
+       c = read_escape (readcharfun, 0);
       return c | shift_modifier;
 
     case 'H':
@@ -1899,7 +2098,7 @@ read_escape (readcharfun, stringp, byterep)
        error ("Invalid escape character syntax");
       c = READCHAR;
       if (c == '\\')
-       c = read_escape (readcharfun, 0, byterep);
+       c = read_escape (readcharfun, 0);
       return c | hyper_modifier;
 
     case 'A':
@@ -1908,7 +2107,7 @@ read_escape (readcharfun, stringp, byterep)
        error ("Invalid escape character syntax");
       c = READCHAR;
       if (c == '\\')
-       c = read_escape (readcharfun, 0, byterep);
+       c = read_escape (readcharfun, 0);
       return c | alt_modifier;
 
     case 's':
@@ -1920,7 +2119,7 @@ read_escape (readcharfun, stringp, byterep)
        }
       c = READCHAR;
       if (c == '\\')
-       c = read_escape (readcharfun, 0, byterep);
+       c = read_escape (readcharfun, 0);
       return c | super_modifier;
 
     case 'C':
@@ -1930,7 +2129,7 @@ read_escape (readcharfun, stringp, byterep)
     case '^':
       c = READCHAR;
       if (c == '\\')
-       c = read_escape (readcharfun, 0, byterep);
+       c = read_escape (readcharfun, 0);
       if ((c & ~CHAR_MODIFIER_MASK) == '?')
        return 0177 | (c & CHAR_MODIFIER_MASK);
       else if (! SINGLE_BYTE_CHAR_P ((c & ~CHAR_MODIFIER_MASK)))
@@ -1970,7 +2169,8 @@ read_escape (readcharfun, stringp, byterep)
              }
          }
 
-       *byterep = 1;
+       if (i >= 0x80 && i < 0x100)
+         i = BYTE8_TO_CHAR (i);
        return i;
       }
 
@@ -1978,6 +2178,7 @@ read_escape (readcharfun, stringp, byterep)
       /* A hex escape, as in ANSI C.  */
       {
        int i = 0;
+       int count = 0;
        while (1)
          {
            c = READCHAR;
@@ -2000,9 +2201,11 @@ read_escape (readcharfun, stringp, byterep)
                UNREAD (c);
                break;
              }
+           count++;
          }
 
-       *byterep = 2;
+       if (count < 3 && i >= 0x80)
+         return BYTE8_TO_CHAR (i);
        return i;
       }
 
@@ -2011,13 +2214,11 @@ read_escape (readcharfun, stringp, byterep)
       unicode_hex_count = 8;
     case 'u':
 
-      /* A Unicode escape. We only permit them in strings and characters,
+      /* A Unicode escape.  We only permit them in strings and characters,
         not arbitrarily in the source code, as in some other languages.  */
       {
-       int i = 0;
+       unsigned int i = 0;
        int count = 0;
-       Lisp_Object lisp_char;
-       struct gcpro gcpro1;
 
        while (++count <= unicode_hex_count)
          {
@@ -2033,23 +2234,12 @@ read_escape (readcharfun, stringp, byterep)
                break;
              }
          }
-
-       GCPRO1 (readcharfun);
-       lisp_char = call2 (intern ("decode-char"), intern ("ucs"),
-                         make_number (i));
-       UNGCPRO;
-
-       if (NILP (lisp_char))
-         {
-           error ("Unsupported Unicode code point: U+%x", (unsigned)i);
-         }
-
-       return XFASTINT (lisp_char);
+       if (i > 0x10FFFF)
+         error ("Non-Unicode character: 0x%x", i);
+       return i;
       }
 
     default:
-      if (BASE_LEADING_CODE_P (c))
-       c = read_multibyte (c, readcharfun);
       return c;
     }
 }
@@ -2066,7 +2256,8 @@ read_integer (readcharfun, radix)
      int radix;
 {
   int ndigits = 0, invalid_p, c, sign = 0;
-  EMACS_INT number = 0;
+  /* We use a floating point number because  */
+  double number = 0;
 
   if (radix < 2 || radix > 36)
     invalid_p = 1;
@@ -2116,44 +2307,7 @@ read_integer (readcharfun, radix)
       invalid_syntax (buf, 0);
     }
 
-  return make_number (sign * number);
-}
-
-
-/* Convert unibyte text in read_buffer to multibyte.
-
-   Initially, *P is a pointer after the end of the unibyte text, and
-   the pointer *END points after the end of read_buffer.
-
-   If read_buffer doesn't have enough room to hold the result
-   of the conversion, reallocate it and adjust *P and *END.
-
-   At the end, make *P point after the result of the conversion, and
-   return in *NCHARS the number of characters in the converted
-   text.  */
-
-static void
-to_multibyte (p, end, nchars)
-     char **p, **end;
-     int *nchars;
-{
-  int nbytes;
-
-  parse_str_as_multibyte (read_buffer, *p - read_buffer, &nbytes, nchars);
-  if (read_buffer_size < 2 * nbytes)
-    {
-      int offset = *p - read_buffer;
-      read_buffer_size = 2 * max (read_buffer_size, nbytes);
-      read_buffer = (char *) xrealloc (read_buffer, read_buffer_size);
-      *p = read_buffer + offset;
-      *end = read_buffer + read_buffer_size;
-    }
-
-  if (nbytes != *nchars)
-    nbytes = str_as_multibyte (read_buffer, read_buffer_size,
-                              *p - read_buffer, nchars);
-
-  *p = read_buffer + nbytes;
+  return make_fixnum_or_float (sign * number);
 }
 
 
@@ -2171,12 +2325,14 @@ read1 (readcharfun, pch, first_in_list)
 {
   register int c;
   int uninterned_symbol = 0;
+  int multibyte;
 
   *pch = 0;
+  load_each_byte = 0;
 
  retry:
 
-  c = READCHAR;
+  c = READCHAR_REPORT_MULTIBYTE (&multibyte);
   if (c < 0)
     end_of_file_error ();
 
@@ -2197,6 +2353,79 @@ read1 (readcharfun, pch, first_in_list)
 
     case '#':
       c = READCHAR;
+      if (c == 's')
+       {
+         c = READCHAR;
+         if (c == '(')
+           {
+             /* Accept extended format for hashtables (extensible to
+                other types), e.g.
+                #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
+             Lisp_Object tmp = read_list (0, readcharfun);
+             Lisp_Object head = CAR_SAFE (tmp);
+             Lisp_Object data = Qnil;
+             Lisp_Object val = Qnil;
+             /* The size is 2 * number of allowed keywords to
+                make-hash-table. */
+             Lisp_Object params[10];
+             Lisp_Object ht;
+             Lisp_Object key = Qnil;
+             int param_count = 0;
+
+             if (!EQ (head, Qhash_table))
+               error ("Invalid extended read marker at head of #s list "
+                      "(only hash-table allowed)");
+
+             tmp = CDR_SAFE (tmp);
+
+             /* This is repetitive but fast and simple. */
+             params[param_count] = QCsize;
+             params[param_count+1] = Fplist_get (tmp, Qsize);
+             if (!NILP (params[param_count + 1]))
+               param_count += 2;
+
+             params[param_count] = QCtest;
+             params[param_count+1] = Fplist_get (tmp, Qtest);
+             if (!NILP (params[param_count + 1]))
+               param_count += 2;
+
+             params[param_count] = QCweakness;
+             params[param_count+1] = Fplist_get (tmp, Qweakness);
+             if (!NILP (params[param_count + 1]))
+               param_count += 2;
+
+             params[param_count] = QCrehash_size;
+             params[param_count+1] = Fplist_get (tmp, Qrehash_size);
+             if (!NILP (params[param_count + 1]))
+               param_count += 2;
+
+             params[param_count] = QCrehash_threshold;
+             params[param_count+1] = Fplist_get (tmp, Qrehash_threshold);
+             if (!NILP (params[param_count + 1]))
+               param_count += 2;
+
+             /* This is the hashtable data. */
+             data = Fplist_get (tmp, Qdata);
+
+             /* Now use params to make a new hashtable and fill it. */
+             ht = Fmake_hash_table (param_count, params);
+
+             while (CONSP (data))
+               {
+                 key = XCAR (data);
+                 data = XCDR (data);
+                 if (!CONSP (data))
+                   error ("Odd number of elements in hashtable data");
+                 val = XCAR (data);
+                 data = XCDR (data);
+                 Fputhash (key, val, ht);
+               }
+
+             return ht;
+           }
+         UNREAD (c);
+         invalid_syntax ("#", 1);
+       }
       if (c == '^')
        {
          c = READCHAR;
@@ -2204,11 +2433,9 @@ read1 (readcharfun, pch, first_in_list)
            {
              Lisp_Object tmp;
              tmp = read_vector (readcharfun, 0);
-             if (XVECTOR (tmp)->size < CHAR_TABLE_STANDARD_SLOTS
-                 || XVECTOR (tmp)->size > CHAR_TABLE_STANDARD_SLOTS + 10)
+             if (XVECTOR_SIZE (tmp) < CHAR_TABLE_STANDARD_SLOTS)
                error ("Invalid size char-table");
              XSETPVECTYPE (XVECTOR (tmp), PVEC_CHAR_TABLE);
-             XCHAR_TABLE (tmp)->top = Qt;
              return tmp;
            }
          else if (c == '^')
@@ -2217,11 +2444,18 @@ read1 (readcharfun, pch, first_in_list)
              if (c == '[')
                {
                  Lisp_Object tmp;
+                 int depth, size;
+
                  tmp = read_vector (readcharfun, 0);
-                 if (XVECTOR (tmp)->size != SUB_CHAR_TABLE_STANDARD_SLOTS)
+                 if (!INTEGERP (AREF (tmp, 0)))
+                   error ("Invalid depth in char-table");
+                 depth = XINT (AREF (tmp, 0));
+                 if (depth < 1 || depth > 3)
+                   error ("Invalid depth in char-table");
+                 size = XVECTOR_SIZE (tmp) - 2;
+                 if (chartab_size [depth] != size)
                    error ("Invalid size char-table");
-                 XSETPVECTYPE (XVECTOR (tmp), PVEC_CHAR_TABLE);
-                 XCHAR_TABLE (tmp)->top = Qnil;
+                 XSETPVECTYPE (XVECTOR (tmp), PVEC_SUB_CHAR_TABLE);
                  return tmp;
                }
              invalid_syntax ("#^^", 3);
@@ -2242,12 +2476,14 @@ read1 (readcharfun, pch, first_in_list)
 
              UNREAD (c);
              tmp = read1 (readcharfun, pch, first_in_list);
-             if (size_in_chars != SCHARS (tmp)
-                 /* We used to print 1 char too many
-                    when the number of bits was a multiple of 8.
-                    Accept such input in case it came from an old version.  */
-                 && ! (XFASTINT (length)
-                       == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR))
+             if (STRING_MULTIBYTE (tmp)
+                 || (size_in_chars != SCHARS (tmp)
+                     /* We used to print 1 char too many
+                        when the number of bits was a multiple of 8.
+                        Accept such input in case it came from an old
+                        version.  */
+                     && ! (XFASTINT (length)
+                           == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR)))
                invalid_syntax ("#&...", 5);
 
              val = Fmake_bool_vector (length, Qnil);
@@ -2267,7 +2503,7 @@ read1 (readcharfun, pch, first_in_list)
             build them using function calls.  */
          Lisp_Object tmp;
          tmp = read_vector (readcharfun, 1);
-         return Fmake_byte_code (XVECTOR (tmp)->size,
+         return Fmake_byte_code (XVECTOR_SIZE (tmp),
                                  XVECTOR (tmp)->contents);
        }
       if (c == '(')
@@ -2309,6 +2545,7 @@ read1 (readcharfun, pch, first_in_list)
        {
          int i, nskip = 0;
 
+         load_each_byte = 1;
          /* Read a decimal integer.  */
          while ((c = READCHAR) >= 0
                 && c >= '0' && c <= '9')
@@ -2319,7 +2556,9 @@ read1 (readcharfun, pch, first_in_list)
          if (c >= 0)
            UNREAD (c);
 
-         if (load_force_doc_strings && EQ (readcharfun, Qget_file_char))
+         if (load_force_doc_strings
+             && (EQ (readcharfun, Qget_file_char)
+                 || EQ (readcharfun, Qget_emacs_mule_file_char)))
            {
              /* If we are supposed to force doc strings into core right now,
                 record the last string that we skipped,
@@ -2371,6 +2610,7 @@ read1 (readcharfun, pch, first_in_list)
                c = READCHAR;
            }
 
+         load_each_byte = 0;
          goto retry;
        }
       if (c == '!')
@@ -2406,13 +2646,13 @@ read1 (readcharfun, pch, first_in_list)
              c = READCHAR;
            }
          /* #n=object returns object, but associates it with n for #n#.  */
-         if (c == '=')
+         if (c == '=' && !NILP (Vread_circle))
            {
              /* Make a placeholder for #n# to use temporarily */
              Lisp_Object placeholder;
              Lisp_Object cell;
 
-             placeholder = Fcons(Qnil, Qnil);
+             placeholder = Fcons (Qnil, Qnil);
              cell = Fcons (make_number (n), placeholder);
              read_objects = Fcons (cell, read_objects);
 
@@ -2428,7 +2668,7 @@ read1 (readcharfun, pch, first_in_list)
              return tem;
            }
          /* #n# returns a previously read object.  */
-         if (c == '#')
+         if (c == '#' && !NILP (Vread_circle))
            {
              tem = Fassq (make_number (n), read_objects);
              if (CONSP (tem))
@@ -2506,7 +2746,7 @@ read1 (readcharfun, pch, first_in_list)
 
     case '?':
       {
-       int discard;
+       int modifiers;
        int next_char;
        int ok;
 
@@ -2522,9 +2762,12 @@ read1 (readcharfun, pch, first_in_list)
          return make_number (c);
 
        if (c == '\\')
-         c = read_escape (readcharfun, 0, &discard);
-       else if (BASE_LEADING_CODE_P (c))
-         c = read_multibyte (c, readcharfun);
+         c = read_escape (readcharfun, 0);
+       modifiers = c & CHAR_MODIFIER_MASK;
+       c &= ~CHAR_MODIFIER_MASK;
+       if (CHAR_BYTE8_P (c))
+         c = CHAR_TO_BYTE8 (c);
+       c |= modifiers;
 
        next_char = READCHAR;
        if (next_char == '.')
@@ -2559,14 +2802,12 @@ read1 (readcharfun, pch, first_in_list)
        char *p = read_buffer;
        char *end = read_buffer + read_buffer_size;
        register int c;
-       /* 1 if we saw an escape sequence specifying
-          a multibyte character, or a multibyte character.  */
+       /* Nonzero if we saw an escape sequence specifying
+          a multibyte character.  */
        int force_multibyte = 0;
-       /* 1 if we saw an escape sequence specifying
+       /* Nonzero if we saw an escape sequence specifying
           a single-byte character.  */
        int force_singlebyte = 0;
-       /* 1 if read_buffer contains multibyte text now.  */
-       int is_multibyte = 0;
        int cancel = 0;
        int nchars = 0;
 
@@ -2584,9 +2825,9 @@ read1 (readcharfun, pch, first_in_list)
 
            if (c == '\\')
              {
-               int byterep;
+               int modifiers;
 
-               c = read_escape (readcharfun, 1, &byterep);
+               c = read_escape (readcharfun, 1);
 
                /* C is -1 if \ newline has just been seen */
                if (c == -1)
@@ -2596,50 +2837,55 @@ read1 (readcharfun, pch, first_in_list)
                    continue;
                  }
 
-               if (byterep == 1)
+               modifiers = c & CHAR_MODIFIER_MASK;
+               c = c & ~CHAR_MODIFIER_MASK;
+
+               if (CHAR_BYTE8_P (c))
                  force_singlebyte = 1;
-               else if (byterep == 2)
+               else if (! ASCII_CHAR_P (c))
                  force_multibyte = 1;
-             }
-
-           /* A character that must be multibyte forces multibyte.  */
-           if (! SINGLE_BYTE_CHAR_P (c & ~CHAR_MODIFIER_MASK))
-             force_multibyte = 1;
+               else            /* i.e. ASCII_CHAR_P (c) */
+                 {
+                   /* Allow `\C- ' and `\C-?'.  */
+                   if (modifiers == CHAR_CTL)
+                     {
+                       if (c == ' ')
+                         c = 0, modifiers = 0;
+                       else if (c == '?')
+                         c = 127, modifiers = 0;
+                     }
+                   if (modifiers & CHAR_SHIFT)
+                     {
+                       /* Shift modifier is valid only with [A-Za-z].  */
+                       if (c >= 'A' && c <= 'Z')
+                         modifiers &= ~CHAR_SHIFT;
+                       else if (c >= 'a' && c <= 'z')
+                         c -= ('a' - 'A'), modifiers &= ~CHAR_SHIFT;
+                     }
+
+                   if (modifiers & CHAR_META)
+                     {
+                       /* Move the meta bit to the right place for a
+                          string.  */
+                       modifiers &= ~CHAR_META;
+                       c = BYTE8_TO_CHAR (c | 0x80);
+                       force_singlebyte = 1;
+                     }
+                 }
 
-           /* If we just discovered the need to be multibyte,
-              convert the text accumulated thus far.  */
-           if (force_multibyte && ! is_multibyte)
-             {
-               is_multibyte = 1;
-               to_multibyte (&p, &end, &nchars);
+               /* Any modifiers remaining are invalid.  */
+               if (modifiers)
+                 error ("Invalid modifier in string");
+               p += CHAR_STRING (c, (unsigned char *) p);
              }
-
-           /* Allow `\C- ' and `\C-?'.  */
-           if (c == (CHAR_CTL | ' '))
-             c = 0;
-           else if (c == (CHAR_CTL | '?'))
-             c = 127;
-
-           if (c & CHAR_SHIFT)
+           else
              {
-               /* Shift modifier is valid only with [A-Za-z].  */
-               if ((c & 0377) >= 'A' && (c & 0377) <= 'Z')
-                 c &= ~CHAR_SHIFT;
-               else if ((c & 0377) >= 'a' && (c & 0377) <= 'z')
-                 c = (c & ~CHAR_SHIFT) - ('a' - 'A');
+               p += CHAR_STRING (c, (unsigned char *) p);
+               if (CHAR_BYTE8_P (c))
+                 force_singlebyte = 1;
+               else if (! ASCII_CHAR_P (c))
+                 force_multibyte = 1;
              }
-
-           if (c & CHAR_META)
-             /* Move the meta bit to the right place for a string.  */
-             c = (c & ~CHAR_META) | 0x80;
-           if (c & CHAR_MODIFIER_MASK)
-             error ("Invalid modifier in string");
-
-           if (is_multibyte)
-             p += CHAR_STRING (c, p);
-           else
-             *p++ = c;
-
            nchars++;
          }
 
@@ -2652,37 +2898,16 @@ read1 (readcharfun, pch, first_in_list)
        if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel)
          return make_number (0);
 
-       if (is_multibyte || force_singlebyte)
+       if (force_multibyte)
+         /* READ_BUFFER already contains valid multibyte forms.  */
          ;
-       else if (load_convert_to_unibyte)
+       else if (force_singlebyte)
          {
-           Lisp_Object string;
-           to_multibyte (&p, &end, &nchars);
-           if (p - read_buffer != nchars)
-             {
-               string = make_multibyte_string (read_buffer, nchars,
-                                               p - read_buffer);
-               return Fstring_make_unibyte (string);
-             }
-           /* We can make a unibyte string directly.  */
-           is_multibyte = 0;
-         }
-       else if (EQ (readcharfun, Qget_file_char)
-                || EQ (readcharfun, Qlambda))
-         {
-           /* Nowadays, reading directly from a file is used only for
-              compiled Emacs Lisp files, and those always use the
-              Emacs internal encoding.  Meanwhile, Qlambda is used
-              for reading dynamic byte code (compiled with
-              byte-compile-dynamic = t).  So make the string multibyte
-              if the string contains any multibyte sequences.
-              (to_multibyte is a no-op if not.)  */
-           to_multibyte (&p, &end, &nchars);
-           is_multibyte = (p - read_buffer) != nchars;
+           nchars = str_as_unibyte (read_buffer, p - read_buffer);
+           p = read_buffer + nchars;
          }
        else
-         /* In all other cases, if we read these bytes as
-            separate characters, treat them as separate characters now.  */
+         /* Otherwise, READ_BUFFER contains only ASCII.  */
          ;
 
        /* We want readchar_count to be the number of characters, not
@@ -2692,9 +2917,11 @@ read1 (readcharfun, pch, first_in_list)
        /* readchar_count -= (p - read_buffer) - nchars; */
        if (read_pure)
          return make_pure_string (read_buffer, nchars, p - read_buffer,
-                                  is_multibyte);
+                                  (force_multibyte
+                                   || (p - read_buffer != nchars)));
        return make_specified_string (read_buffer, nchars, p - read_buffer,
-                                     is_multibyte);
+                                     (force_multibyte
+                                      || (p - read_buffer != nchars)));
       }
 
     case '.':
@@ -2752,11 +2979,10 @@ read1 (readcharfun, pch, first_in_list)
                  quoted = 1;
                }
 
-             if (! SINGLE_BYTE_CHAR_P (c))
+             if (multibyte)
                p += CHAR_STRING (c, p);
              else
                *p++ = c;
-
              c = READCHAR;
            }
 
@@ -2776,7 +3002,6 @@ read1 (readcharfun, pch, first_in_list)
        if (!quoted && !uninterned_symbol)
          {
            register char *p1;
-           register Lisp_Object val;
            p1 = read_buffer;
            if (*p1 == '+' || *p1 == '-') p1++;
            /* Is it an integer? */
@@ -2790,16 +3015,24 @@ read1 (readcharfun, pch, first_in_list)
                  {
                    if (p1[-1] == '.')
                      p1[-1] = '\0';
-                   if (sizeof (int) == sizeof (EMACS_INT))
-                     XSETINT (val, atoi (read_buffer));
-                   else if (sizeof (long) == sizeof (EMACS_INT))
-                     XSETINT (val, atol (read_buffer));
-                   else
-                     abort ();
-                   return val;
+                   {
+                     /* EMACS_INT n = atol (read_buffer); */
+                     char *endptr = NULL;
+                     EMACS_INT n = (errno = 0,
+                                    strtol (read_buffer, &endptr, 10));
+                     if (errno == ERANGE && endptr)
+                       {
+                         Lisp_Object args
+                           = Fcons (make_string (read_buffer,
+                                                 endptr - read_buffer),
+                                    Qnil);
+                         xsignal (Qoverflow_error, args);
+                       }
+                     return make_fixnum_or_float (n);
+                   }
                  }
              }
-           if (isfloat_string (read_buffer))
+           if (isfloat_string (read_buffer, 0))
              {
                /* Compute NaN and infinities using 0.0 in a variable,
                   to cope with compilers that think they are smarter
@@ -2850,8 +3083,19 @@ read1 (readcharfun, pch, first_in_list)
              }
          }
        {
-         Lisp_Object result = uninterned_symbol ? make_symbol (read_buffer)
-           : intern (read_buffer);
+         Lisp_Object name, result;
+         EMACS_INT nbytes = p - read_buffer;
+         EMACS_INT nchars
+           = (multibyte ? multibyte_chars_in_text (read_buffer, nbytes)
+              : nbytes);
+
+         if (uninterned_symbol && ! NILP (Vpurify_flag))
+           name = make_pure_string (read_buffer, nchars, nbytes, multibyte);
+         else
+           name = make_specified_string (read_buffer, nchars, nbytes,multibyte);
+         result = (uninterned_symbol ? Fmake_symbol (name)
+                   : Fintern (name, Qnil));
+
          if (EQ (Vread_with_symbol_positions, Qt)
              || EQ (Vread_with_symbol_positions, readcharfun))
            Vread_symbol_positions_list =
@@ -2896,18 +3140,18 @@ substitute_object_in_subtree (object, placeholder)
 }
 
 /*  Feval doesn't get called from here, so no gc protection is needed. */
-#define SUBSTITUTE(get_val, set_val)                 \
-{                                                    \
-  Lisp_Object old_value = get_val;                   \
-  Lisp_Object true_value                             \
-    = substitute_object_recurse (object, placeholder,\
-                              old_value);           \
-                                                     \
-  if (!EQ (old_value, true_value))                   \
-    {                                                \
-       set_val;                                      \
-    }                                                \
-}
+#define SUBSTITUTE(get_val, set_val)                   \
+  do {                                                 \
+    Lisp_Object old_value = get_val;                   \
+    Lisp_Object true_value                             \
+      = substitute_object_recurse (object, placeholder,        \
+                                  old_value);          \
+                                                       \
+    if (!EQ (old_value, true_value))                   \
+      {                                                        \
+       set_val;                                        \
+      }                                                        \
+  } while (0)
 
 static Lisp_Object
 substitute_object_recurse (object, placeholder, subtree)
@@ -2936,23 +3180,33 @@ substitute_object_recurse (object, placeholder, subtree)
     {
     case Lisp_Vectorlike:
       {
-       int i;
-       int length = XINT (Flength(subtree));
+       int i, length = 0;
+       if (BOOL_VECTOR_P (subtree))
+         return subtree;               /* No sub-objects anyway.  */
+       else if (CHAR_TABLE_P (subtree) || SUB_CHAR_TABLE_P (subtree)
+                || COMPILEDP (subtree))
+         length = ASIZE (subtree) & PSEUDOVECTOR_SIZE_MASK;
+       else if (VECTORP (subtree))
+         length = ASIZE (subtree);
+       else
+         /* An unknown pseudovector may contain non-Lisp fields, so we
+            can't just blindly traverse all its fields.  We used to call
+            `Flength' which signaled `sequencep', so I just preserved this
+            behavior.  */
+         wrong_type_argument (Qsequencep, subtree);
+
        for (i = 0; i < length; i++)
-         {
-           Lisp_Object idx = make_number (i);
-           SUBSTITUTE (Faref (subtree, idx),
-                       Faset (subtree, idx, true_value));
-         }
+         SUBSTITUTE (AREF (subtree, i),
+                     ASET (subtree, i, true_value));
        return subtree;
       }
 
     case Lisp_Cons:
       {
-       SUBSTITUTE (Fcar_safe (subtree),
-                   Fsetcar (subtree, true_value));
-       SUBSTITUTE (Fcdr_safe (subtree),
-                   Fsetcdr (subtree, true_value));
+       SUBSTITUTE (XCAR (subtree),
+                   XSETCAR (subtree, true_value));
+       SUBSTITUTE (XCDR (subtree),
+                   XSETCDR (subtree, true_value));
        return subtree;
       }
 
@@ -2985,7 +3239,7 @@ substitute_in_interval (interval, arg)
   Lisp_Object object      = Fcar (arg);
   Lisp_Object placeholder = Fcdr (arg);
 
-  SUBSTITUTE(interval->plist, interval->plist = true_value);
+  SUBSTITUTE (interval->plist, interval->plist = true_value);
 }
 
 \f
@@ -2996,8 +3250,9 @@ substitute_in_interval (interval, arg)
 #define EXP_INT 16
 
 int
-isfloat_string (cp)
+isfloat_string (cp, ignore_trailing)
      register char *cp;
+     int ignore_trailing;
 {
   register int state;
 
@@ -3051,7 +3306,8 @@ isfloat_string (cp)
       cp += 3;
     }
 
-  return (((*cp == 0) || (*cp == ' ') || (*cp == '\t') || (*cp == '\n') || (*cp == '\r') || (*cp == '\f'))
+  return ((ignore_trailing
+           || (*cp == 0) || (*cp == ' ') || (*cp == '\t') || (*cp == '\n') || (*cp == '\r') || (*cp == '\f'))
          && (state == (LEAD_INT|DOT_CHAR|TRAIL_INT)
              || state == (DOT_CHAR|TRAIL_INT)
              || state == (LEAD_INT|E_CHAR|EXP_INT)
@@ -3076,7 +3332,7 @@ read_vector (readcharfun, bytecodeflag)
   len = Flength (tem);
   vector = (read_pure ? make_pure_vector (XINT (len)) : Fmake_vector (len, Qnil));
 
-  size = XVECTOR (vector)->size;
+  size = XVECTOR_SIZE (vector);
   ptr = XVECTOR (vector)->contents;
   for (i = 0; i < size; i++)
     {
@@ -3110,7 +3366,7 @@ read_vector (readcharfun, bytecodeflag)
                  STRING_SET_CHARS (bytestr, SBYTES (bytestr));
                  STRING_SET_UNIBYTE (bytestr);
 
-                 item = Fread (bytestr);
+                 item = Fread (Fcons (bytestr, readcharfun));
                  if (!CONSP (item))
                    error ("Invalid byte code");
 
@@ -3123,6 +3379,15 @@ read_vector (readcharfun, bytecodeflag)
              /* Now handle the bytecode slot.  */
              ptr[COMPILED_BYTECODE] = read_pure ? Fpurecopy (bytestr) : bytestr;
            }
+         else if (i == COMPILED_DOC_STRING
+                  && STRINGP (item)
+                  && ! STRING_MULTIBYTE (item))
+           {
+             if (EQ (readcharfun, Qget_emacs_mule_file_char))
+               item = Fdecode_coding_string (item, Qemacs_mule, Qnil, Qnil);
+             else
+               item = Fstring_as_multibyte (item);
+           }
        }
       ptr[i] = read_pure ? Fpurecopy (item) : item;
       otem = XCONS (tem);
@@ -3219,7 +3484,15 @@ read_list (flag, readcharfun)
                  if (doc_reference == 2)
                    {
                      /* Get a doc string from the file we are loading.
-                        If it's in saved_doc_string, get it from there.  */
+                        If it's in saved_doc_string, get it from there.
+
+                        Here, we don't know if the string is a
+                        bytecode string or a doc string.  As a
+                        bytecode string must be unibyte, we always
+                        return a unibyte string.  If it is actually a
+                        doc string, caller must make it
+                        multibyte.  */
+
                      int pos = XINT (XCDR (val));
                      /* Position is negative for user variables.  */
                      if (pos < 0) pos = -pos;
@@ -3251,8 +3524,8 @@ read_list (flag, readcharfun)
                                saved_doc_string[to++] = c;
                            }
 
-                         return make_string (saved_doc_string + start,
-                                             to - start);
+                         return make_unibyte_string (saved_doc_string + start,
+                                                     to - start);
                        }
                      /* Look in prev_saved_doc_string the same way.  */
                      else if (pos >= prev_saved_doc_string_position
@@ -3283,11 +3556,12 @@ read_list (flag, readcharfun)
                                prev_saved_doc_string[to++] = c;
                            }
 
-                         return make_string (prev_saved_doc_string + start,
-                                             to - start);
+                         return make_unibyte_string (prev_saved_doc_string
+                                                     + start,
+                                                     to - start);
                        }
                      else
-                       return get_doc_string (val, 0, 0);
+                       return get_doc_string (val, 1, 0);
                    }
 
                  return val;
@@ -3327,7 +3601,7 @@ Lisp_Object
 check_obarray (obarray)
      Lisp_Object obarray;
 {
-  if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
+  if (!VECTORP (obarray) || XVECTOR_SIZE (obarray) == 0)
     {
       /* If Vobarray is now invalid, force it to be valid.  */
       if (EQ (Vobarray, obarray)) Vobarray = initial_obarray;
@@ -3348,7 +3622,7 @@ intern (str)
   Lisp_Object obarray;
 
   obarray = Vobarray;
-  if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
+  if (!VECTORP (obarray) || XVECTOR_SIZE (obarray) == 0)
     obarray = check_obarray (obarray);
   tem = oblookup (obarray, str, len, len);
   if (SYMBOLP (tem))
@@ -3356,6 +3630,29 @@ intern (str)
   return Fintern (make_string (str, len), obarray);
 }
 
+Lisp_Object
+intern_c_string (const char *str)
+{
+  Lisp_Object tem;
+  int len = strlen (str);
+  Lisp_Object obarray;
+
+  obarray = Vobarray;
+  if (!VECTORP (obarray) || XVECTOR_SIZE (obarray) == 0)
+    obarray = check_obarray (obarray);
+  tem = oblookup (obarray, str, len, len);
+  if (SYMBOLP (tem))
+    return tem;
+
+  if (NILP (Vpurify_flag))
+    /* Creating a non-pure string from a string literal not
+       implemented yet.  We could just use make_string here and live
+       with the extra copy.  */
+    abort ();
+
+  return Fintern (make_pure_c_string (str), obarray);
+}
+
 /* Create an uninterned symbol with name STR.  */
 
 Lisp_Object
@@ -3476,6 +3773,13 @@ OBARRAY defaults to the value of the variable `obarray'.  */)
   if (SYMBOLP (name) && !EQ (name, tem))
     return Qnil;
 
+  /* There are plenty of other symbols which will screw up the Emacs
+     session if we unintern them, as well as even more ways to use
+     `setq' or `fset' or whatnot to make the Emacs session
+     unusable.  Let's not go down this silly road.  --Stef  */
+  /* if (EQ (tem, Qnil) || EQ (tem, Qt))
+       error ("Attempt to unintern t or nil"); */
+
   XSYMBOL (tem)->interned = SYMBOL_UNINTERNED;
   XSYMBOL (tem)->constant = 0;
   XSYMBOL (tem)->indirect_variable = 0;
@@ -3527,16 +3831,14 @@ oblookup (obarray, ptr, size, size_byte)
   Lisp_Object bucket, tem;
 
   if (!VECTORP (obarray)
-      || (obsize = XVECTOR (obarray)->size) == 0)
+      || (obsize = XVECTOR_SIZE (obarray)) == 0)
     {
       obarray = check_obarray (obarray);
-      obsize = XVECTOR (obarray)->size;
+      obsize = XVECTOR_SIZE (obarray);
     }
   /* This is sometimes needed in the middle of GC.  */
   obsize &= ~ARRAY_MARK_FLAG;
-  /* Combining next two lines breaks VMS C 2.3.  */
-  hash = hash_string (ptr, size_byte);
-  hash %= obsize;
+  hash = hash_string (ptr, size_byte) % obsize;
   bucket = XVECTOR (obarray)->contents[hash];
   oblookup_last_bucket_number = hash;
   if (EQ (bucket, make_number (0)))
@@ -3585,7 +3887,7 @@ map_obarray (obarray, fn, arg)
   register int i;
   register Lisp_Object tail;
   CHECK_VECTOR (obarray);
-  for (i = XVECTOR (obarray)->size - 1; i >= 0; i--)
+  for (i = XVECTOR_SIZE (obarray) - 1; i >= 0; i--)
     {
       tail = XVECTOR (obarray)->contents[i];
       if (SYMBOLP (tail))
@@ -3630,7 +3932,7 @@ init_obarray ()
 
   XSETFASTINT (oblength, OBARRAY_SIZE);
 
-  Qnil = Fmake_symbol (make_pure_string ("nil", 3, 3, 0));
+  Qnil = Fmake_symbol (make_pure_c_string ("nil"));
   Vobarray = Fmake_vector (oblength, make_number (0));
   initial_obarray = Vobarray;
   staticpro (&initial_obarray);
@@ -3645,12 +3947,12 @@ init_obarray ()
   tem = &XVECTOR (Vobarray)->contents[hash];
   *tem = Qnil;
 
-  Qunbound = Fmake_symbol (make_pure_string ("unbound", 7, 7, 0));
+  Qunbound = Fmake_symbol (make_pure_c_string ("unbound"));
   XSYMBOL (Qnil)->function = Qunbound;
   XSYMBOL (Qunbound)->value = Qunbound;
   XSYMBOL (Qunbound)->function = Qunbound;
 
-  Qt = intern ("t");
+  Qt = intern_c_string ("t");
   XSYMBOL (Qnil)->value = Qnil;
   XSYMBOL (Qnil)->plist = Qnil;
   XSYMBOL (Qt)->value = Qt;
@@ -3659,7 +3961,7 @@ init_obarray ()
   /* Qt is correct even if CANNOT_DUMP.  loadup.el will set to nil at end.  */
   Vpurify_flag = Qt;
 
-  Qvariable_documentation = intern ("variable-documentation");
+  Qvariable_documentation = intern_c_string ("variable-documentation");
   staticpro (&Qvariable_documentation);
 
   read_buffer_size = 100 + MAX_MULTIBYTE_LENGTH;
@@ -3671,8 +3973,8 @@ defsubr (sname)
      struct Lisp_Subr *sname;
 {
   Lisp_Object sym;
-  sym = intern (sname->symbol_name);
-  XSETPVECTYPE (sname, PVEC_SUBR);
+  sym = intern_c_string (sname->symbol_name);
+  XSETTYPED_PVECTYPE (sname, size, PVEC_SUBR);
   XSETSUBR (XSYMBOL (sym)->function, sname);
 }
 
@@ -3692,12 +3994,10 @@ defalias (sname, string)
    to a C variable of type int.  Sample call:
    DEFVAR_INT ("emacs-priority", &emacs_priority, "Documentation");  */
 void
-defvar_int (namestring, address)
-     char *namestring;
-     EMACS_INT *address;
+defvar_int (const char *namestring, EMACS_INT *address)
 {
   Lisp_Object sym, val;
-  sym = intern (namestring);
+  sym = intern_c_string (namestring);
   val = allocate_misc ();
   XMISCTYPE (val) = Lisp_Misc_Intfwd;
   XINTFWD (val)->intvar = address;
@@ -3707,12 +4007,10 @@ defvar_int (namestring, address)
 /* Similar but define a variable whose value is t if address contains 1,
    nil if address contains 0.  */
 void
-defvar_bool (namestring, address)
-     char *namestring;
-     int *address;
+defvar_bool (const char *namestring, int *address)
 {
   Lisp_Object sym, val;
-  sym = intern (namestring);
+  sym = intern_c_string (namestring);
   val = allocate_misc ();
   XMISCTYPE (val) = Lisp_Misc_Boolfwd;
   XBOOLFWD (val)->boolvar = address;
@@ -3726,12 +4024,10 @@ defvar_bool (namestring, address)
    gc-marked for some other reason, since marking the same slot twice
    can cause trouble with strings.  */
 void
-defvar_lisp_nopro (namestring, address)
-     char *namestring;
-     Lisp_Object *address;
+defvar_lisp_nopro (const char *namestring, Lisp_Object *address)
 {
   Lisp_Object sym, val;
-  sym = intern (namestring);
+  sym = intern_c_string (namestring);
   val = allocate_misc ();
   XMISCTYPE (val) = Lisp_Misc_Objfwd;
   XOBJFWD (val)->objvar = address;
@@ -3739,9 +4035,7 @@ defvar_lisp_nopro (namestring, address)
 }
 
 void
-defvar_lisp (namestring, address)
-     char *namestring;
-     Lisp_Object *address;
+defvar_lisp (const char *namestring, Lisp_Object *address)
 {
   defvar_lisp_nopro (namestring, address);
   staticpro (address);
@@ -3751,12 +4045,10 @@ defvar_lisp (namestring, address)
    at a particular offset in the current kboard object.  */
 
 void
-defvar_kboard (namestring, offset)
-     char *namestring;
-     int offset;
+defvar_kboard (const char *namestring, int offset)
 {
   Lisp_Object sym, val;
-  sym = intern (namestring);
+  sym = intern_c_string (namestring);
   val = allocate_misc ();
   XMISCTYPE (val) = Lisp_Misc_Kboard_Objfwd;
   XKBOARD_OBJFWD (val)->offset = offset;
@@ -3910,15 +4202,11 @@ init_lread ()
     }
 #endif
 
-#if (!(defined(WINDOWSNT) || (defined(HAVE_CARBON))))
+#if (!(defined (WINDOWSNT) || (defined (HAVE_NS))))
   /* When Emacs is invoked over network shares on NT, PATH_LOADSEARCH is
      almost never correct, thereby causing a warning to be printed out that
      confuses users.  Since PATH_LOADSEARCH is always overridden by the
-     EMACSLOADPATH environment variable below, disable the warning on NT.
-     Also, when using the "self-contained" option for Carbon Emacs for MacOSX,
-     the "standard" paths may not exist and would be overridden by
-     EMACSLOADPATH as on NT.  Since this depends on how the executable
-     was build and packaged, turn off the warnings in general */
+     EMACSLOADPATH environment variable below, disable the warning on NT.  */
 
   /* Warn if dirs in the *standard* path don't exist.  */
   if (!turn_off_warning)
@@ -3940,7 +4228,7 @@ init_lread ()
            }
        }
     }
-#endif /* !(WINDOWSNT || HAVE_CARBON) */
+#endif /* !(WINDOWSNT || HAVE_NS) */
 
   /* If the EMACSLOADPATH environment variable is set, use its value.
      This doesn't apply if we're dumping.  */
@@ -4042,6 +4330,10 @@ read multiple times.  The list is in the same order as the symbols
 were read in. */);
   Vread_symbol_positions_list = Qnil;
 
+  DEFVAR_LISP ("read-circle", &Vread_circle,
+              doc: /* Non-nil means read recursive structures using #N= and #N# syntax.  */);
+  Vread_circle = Qt;
+
   DEFVAR_LISP ("load-path", &Vload_path,
               doc: /* *List of directories to search for files to load.
 Each element is a string (directory name) or nil (try default directory).
@@ -4053,8 +4345,8 @@ otherwise to default specified by file `epaths.h' when Emacs was built.  */);
 This list should not include the empty string.
 `load' and related functions try to append these suffixes, in order,
 to the specified file name if a Lisp suffix is allowed or required.  */);
-  Vload_suffixes = Fcons (build_string (".elc"),
-                         Fcons (build_string (".el"), Qnil));
+  Vload_suffixes = Fcons (make_pure_c_string (".elc"),
+                         Fcons (make_pure_c_string (".el"), Qnil));
   DEFVAR_LISP ("load-file-rep-suffixes", &Vload_file_rep_suffixes,
               doc: /* List of suffixes that indicate representations of \
 the same file.
@@ -4072,6 +4364,8 @@ customize `jka-compr-load-suffixes' rather than the present variable.  */);
 
   DEFVAR_BOOL ("load-in-progress", &load_in_progress,
               doc: /* Non-nil if inside of `load'.  */);
+  Qload_in_progress = intern_c_string ("load-in-progress");
+  staticpro (&Qload_in_progress);
 
   DEFVAR_LISP ("after-load-alist", &Vafter_load_alist,
               doc: /* An alist of expressions to be evalled when particular files are loaded.
@@ -4089,20 +4383,20 @@ the rest of the FORMS.  */);
   Vafter_load_alist = Qnil;
 
   DEFVAR_LISP ("load-history", &Vload_history,
-              doc: /* Alist mapping file names to symbols and features.
-Each alist element is a list that starts with a file name,
-except for one element (optional) that starts with nil and describes
-definitions evaluated from buffers not visiting files.
-
-The file name is absolute and is the true file name (i.e. it doesn't
-contain symbolic links) of the loaded file.
-
-The remaining elements of each list are symbols defined as variables
-and cons cells of the form `(provide . FEATURE)', `(require . FEATURE)',
-`(defun . FUNCTION)', `(autoload . SYMBOL)', `(defface . SYMBOL)'
-and `(t . SYMBOL)'.  An element `(t . SYMBOL)' precedes an entry
-`(defun . FUNCTION)', and means that SYMBOL was an autoload before
-this file redefined it as a function.
+              doc: /* Alist mapping loaded file names to symbols and features.
+Each alist element should be a list (FILE-NAME ENTRIES...), where
+FILE-NAME is the name of a file that has been loaded into Emacs.
+The file name is absolute and true (i.e. it doesn't contain symlinks).
+As an exception, one of the alist elements may have FILE-NAME nil,
+for symbols and features not associated with any file.
+
+The remaining ENTRIES in the alist element describe the functions and
+variables defined in that file, the features provided, and the
+features required.  Each entry has the form `(provide . FEATURE)',
+`(require . FEATURE)', `(defun . FUNCTION)', `(autoload . SYMBOL)',
+`(defface . SYMBOL)', or `(t . SYMBOL)'.  In addition, an entry `(t
+. SYMBOL)' may precede an entry `(defun . FUNCTION)', and means that
+SYMBOL was an autoload before this file redefined it as a function.
 
 During preloading, the file name recorded is relative to the main Lisp
 directory.  These file names are converted to absolute at startup.  */);
@@ -4172,6 +4466,11 @@ incompatible byte codes can make Emacs crash when it tries to execute
 them.  */);
   load_dangerous_libraries = 0;
 
+  DEFVAR_BOOL ("force-load-messages", &force_load_messages,
+              doc: /* Non-nil means force printing messages when loading Lisp files.
+This overrides the value of the NOMESSAGE argument to `load'.  */);
+  force_load_messages = 0;
+
   DEFVAR_LISP ("bytecomp-version-regexp", &Vbytecomp_version_regexp,
               doc: /* Regular expression matching safe to load compiled Lisp files.
 When Emacs loads a compiled Lisp file, it reads the first 512 bytes
@@ -4179,7 +4478,7 @@ from the file, and matches them against this regular expression.
 When the regular expression matches, the file is considered to be safe
 to load.  See also `load-dangerous-libraries'.  */);
   Vbytecomp_version_regexp
-    = build_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
+    = make_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
 
   DEFVAR_LISP ("eval-buffer-list", &Veval_buffer_list,
               doc: /* List of buffers being read from by calls to `eval-buffer' and `eval-region'.  */);
@@ -4188,7 +4487,7 @@ to load.  See also `load-dangerous-libraries'.  */);
   DEFVAR_LISP ("old-style-backquotes", &Vold_style_backquotes,
               doc: /* Set to non-nil when `read' encounters an old-style backquote.  */);
   Vold_style_backquotes = Qnil;
-  Qold_style_backquotes = intern ("old-style-backquotes");
+  Qold_style_backquotes = intern_c_string ("old-style-backquotes");
   staticpro (&Qold_style_backquotes);
 
   /* Vsource_directory was initialized in init_lread.  */
@@ -4196,49 +4495,55 @@ to load.  See also `load-dangerous-libraries'.  */);
   load_descriptor_list = Qnil;
   staticpro (&load_descriptor_list);
 
-  Qcurrent_load_list = intern ("current-load-list");
+  Qcurrent_load_list = intern_c_string ("current-load-list");
   staticpro (&Qcurrent_load_list);
 
-  Qstandard_input = intern ("standard-input");
+  Qstandard_input = intern_c_string ("standard-input");
   staticpro (&Qstandard_input);
 
-  Qread_char = intern ("read-char");
+  Qread_char = intern_c_string ("read-char");
   staticpro (&Qread_char);
 
-  Qget_file_char = intern ("get-file-char");
+  Qget_file_char = intern_c_string ("get-file-char");
   staticpro (&Qget_file_char);
 
-  Qbackquote = intern ("`");
+  Qget_emacs_mule_file_char = intern_c_string ("get-emacs-mule-file-char");
+  staticpro (&Qget_emacs_mule_file_char);
+
+  Qload_force_doc_strings = intern_c_string ("load-force-doc-strings");
+  staticpro (&Qload_force_doc_strings);
+
+  Qbackquote = intern_c_string ("`");
   staticpro (&Qbackquote);
-  Qcomma = intern (",");
+  Qcomma = intern_c_string (",");
   staticpro (&Qcomma);
-  Qcomma_at = intern (",@");
+  Qcomma_at = intern_c_string (",@");
   staticpro (&Qcomma_at);
-  Qcomma_dot = intern (",.");
+  Qcomma_dot = intern_c_string (",.");
   staticpro (&Qcomma_dot);
 
-  Qinhibit_file_name_operation = intern ("inhibit-file-name-operation");
+  Qinhibit_file_name_operation = intern_c_string ("inhibit-file-name-operation");
   staticpro (&Qinhibit_file_name_operation);
 
-  Qascii_character = intern ("ascii-character");
+  Qascii_character = intern_c_string ("ascii-character");
   staticpro (&Qascii_character);
 
-  Qfunction = intern ("function");
+  Qfunction = intern_c_string ("function");
   staticpro (&Qfunction);
 
-  Qload = intern ("load");
+  Qload = intern_c_string ("load");
   staticpro (&Qload);
 
-  Qload_file_name = intern ("load-file-name");
+  Qload_file_name = intern_c_string ("load-file-name");
   staticpro (&Qload_file_name);
 
-  Qeval_buffer_list = intern ("eval-buffer-list");
+  Qeval_buffer_list = intern_c_string ("eval-buffer-list");
   staticpro (&Qeval_buffer_list);
 
-  Qfile_truename = intern ("file-truename");
+  Qfile_truename = intern_c_string ("file-truename");
   staticpro (&Qfile_truename) ;
 
-  Qdo_after_load_evaluation = intern ("do-after-load-evaluation");
+  Qdo_after_load_evaluation = intern_c_string ("do-after-load-evaluation");
   staticpro (&Qdo_after_load_evaluation) ;
 
   staticpro (&dump_path);
@@ -4250,6 +4555,21 @@ to load.  See also `load-dangerous-libraries'.  */);
 
   Vloads_in_progress = Qnil;
   staticpro (&Vloads_in_progress);
+
+  Qhash_table = intern_c_string ("hash-table");
+  staticpro (&Qhash_table);
+  Qdata = intern_c_string ("data");
+  staticpro (&Qdata);
+  Qtest = intern_c_string ("test");
+  staticpro (&Qtest);
+  Qsize = intern_c_string ("size");
+  staticpro (&Qsize);
+  Qweakness = intern_c_string ("weakness");
+  staticpro (&Qweakness);
+  Qrehash_size = intern_c_string ("rehash-size");
+  staticpro (&Qrehash_size);
+  Qrehash_threshold = intern_c_string ("rehash-threshold");
+  staticpro (&Qrehash_threshold);
 }
 
 /* arch-tag: a0d02733-0f96-4844-a659-9fd53c4f414d