Fix bug #12587 with slow startup on MS-Windows with Netlogon service.
[bpt/emacs.git] / src / lread.c
index a2a1892..6d4c0d9 100644 (file)
@@ -24,12 +24,12 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <errno.h>
-#include <limits.h>    /* for CHAR_BIT */
-#include <setjmp.h>
+#include <limits.h>    /* For CHAR_BIT.  */
+#include <stat-time.h>
 #include "lisp.h"
 #include "intervals.h"
-#include "buffer.h"
 #include "character.h"
+#include "buffer.h"
 #include "charset.h"
 #include "coding.h"
 #include <epaths.h>
@@ -44,8 +44,11 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "msdos.h"
 #endif
 
+#ifdef HAVE_NS
+#include "nsterm.h"
+#endif
+
 #include <unistd.h>
-#include <math.h>
 
 #ifdef HAVE_SETLOCALE
 #include <locale.h>
@@ -61,7 +64,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define file_tell ftell
 #endif
 
-/* hash table read constants */
+/* Hash table read constants.  */
 static Lisp_Object Qhash_table, Qdata;
 static Lisp_Object Qtest, Qsize;
 static Lisp_Object Qweakness;
@@ -75,7 +78,7 @@ static Lisp_Object Qascii_character, Qload, Qload_file_name;
 Lisp_Object Qbackquote, Qcomma, Qcomma_at, Qcomma_dot, Qfunction;
 static Lisp_Object Qinhibit_file_name_operation;
 static Lisp_Object Qeval_buffer_list;
-static Lisp_Object Qlexical_binding;
+Lisp_Object Qlexical_binding;
 static Lisp_Object Qfile_truename, Qdo_after_load_evaluation; /* ACM 2006/5/16 */
 
 /* Used instead of Qget_file_char while loading *.elc files compiled
@@ -84,8 +87,6 @@ static Lisp_Object Qget_emacs_mule_file_char;
 
 static Lisp_Object Qload_force_doc_strings;
 
-extern Lisp_Object Qinternal_interpreter_environment;
-
 static Lisp_Object Qload_in_progress;
 
 /* The association list of objects read with the #n=object form.
@@ -94,10 +95,10 @@ static Lisp_Object Qload_in_progress;
    It must be set to nil before all top-level calls to read0.  */
 static Lisp_Object read_objects;
 
-/* Nonzero means READCHAR should read bytes one by one (not character)
+/* True 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;
+   This is set by read1 temporarily while handling #@NUMBER.  */
+static bool load_each_byte;
 
 /* List of descriptors now open for Fload.  */
 static Lisp_Object load_descriptor_list;
@@ -105,16 +106,13 @@ static Lisp_Object load_descriptor_list;
 /* File for get_file_char to read from.  Use by load.  */
 static FILE *instream;
 
-/* When nonzero, read conses in pure space */
-static int read_pure;
-
 /* For use within read-from-string (this reader is non-reentrant!!)  */
 static ptrdiff_t read_from_string_index;
 static ptrdiff_t read_from_string_index_byte;
 static ptrdiff_t read_from_string_limit;
 
 /* Number of characters read in the current call to Fread or
-   Fread_from_string. */
+   Fread_from_string.  */
 static EMACS_INT readchar_count;
 
 /* This contains the last string skipped with #@.  */
@@ -137,11 +135,11 @@ static ptrdiff_t prev_saved_doc_string_length;
 /* This is the file position that string came from.  */
 static file_offset prev_saved_doc_string_position;
 
-/* Nonzero means inside a new-style backquote
+/* True means inside a new-style backquote
    with no surrounding parentheses.
-   Fread initializes this to zero, so we need not specbind it
+   Fread initializes this to false, so we need not specbind it
    or worry about what happens to it when there is an error.  */
-static int new_backquote_flag;
+static bool new_backquote_flag;
 static Lisp_Object Qold_style_backquotes;
 
 /* A list of file names for files being loaded in Fload.  Used to
@@ -152,15 +150,11 @@ static Lisp_Object Vloads_in_progress;
 static int read_emacs_mule_char (int, int (*) (int, Lisp_Object),
                                  Lisp_Object);
 
-static void readevalloop (Lisp_Object, FILE*, Lisp_Object, int,
+static void readevalloop (Lisp_Object, FILE *, Lisp_Object, bool,
                           Lisp_Object, Lisp_Object,
                           Lisp_Object, Lisp_Object);
 static Lisp_Object load_unwind (Lisp_Object);
 static Lisp_Object load_descriptor_unwind (Lisp_Object);
-
-static void invalid_syntax (const char *) NO_RETURN;
-static void end_of_file_error (void) 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
@@ -187,18 +181,18 @@ static int readbyte_from_string (int, Lisp_Object);
 /* 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. */
+   means that there's no unread character.  */
 static int unread_char;
 
 static int
-readchar (Lisp_Object readcharfun, int *multibyte)
+readchar (Lisp_Object readcharfun, bool *multibyte)
 {
   Lisp_Object tem;
   register int c;
   int (*readbyte) (int, Lisp_Object);
   unsigned char buf[MAX_MULTIBYTE_LENGTH];
   int i, len;
-  int emacs_mule_encoding = 0;
+  bool emacs_mule_encoding = 0;
 
   if (multibyte)
     *multibyte = 0;
@@ -414,9 +408,9 @@ unreadchar (Lisp_Object readcharfun, int c)
     {
       if (load_each_byte)
        {
-         BLOCK_INPUT;
+         block_input ();
          ungetc (c, instream);
-         UNBLOCK_INPUT;
+         unblock_input ();
        }
       else
        unread_char = c;
@@ -437,28 +431,28 @@ readbyte_from_file (int c, Lisp_Object readcharfun)
 {
   if (c >= 0)
     {
-      BLOCK_INPUT;
+      block_input ();
       ungetc (c, instream);
-      UNBLOCK_INPUT;
+      unblock_input ();
       return 0;
     }
 
-  BLOCK_INPUT;
+  block_input ();
   c = getc (instream);
 
 #ifdef EINTR
-  /* Interrupted reads have been observed while reading over the network */
+  /* Interrupted reads have been observed while reading over the network */
   while (c == EOF && ferror (instream) && errno == EINTR)
     {
-      UNBLOCK_INPUT;
+      unblock_input ();
       QUIT;
-      BLOCK_INPUT;
+      block_input ();
       clearerr (instream);
       c = getc (instream);
     }
 #endif
 
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   return (c == EOF ? -1 : c);
 }
@@ -552,10 +546,10 @@ read_emacs_mule_char (int c, int (*readbyte) (int, Lisp_Object), Lisp_Object rea
 static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object,
                                         Lisp_Object);
 static Lisp_Object read0 (Lisp_Object);
-static Lisp_Object read1 (Lisp_Object, int *, int);
+static Lisp_Object read1 (Lisp_Object, int *, bool);
 
-static Lisp_Object read_list (int, Lisp_Object);
-static Lisp_Object read_vector (Lisp_Object, int);
+static Lisp_Object read_list (bool, Lisp_Object);
+static Lisp_Object read_vector (Lisp_Object, bool);
 
 static Lisp_Object substitute_object_recurse (Lisp_Object, Lisp_Object,
                                               Lisp_Object);
@@ -568,28 +562,28 @@ static void substitute_in_interval (INTERVAL, Lisp_Object);
 
 /* Read input events until we get one that's acceptable for our purposes.
 
-   If NO_SWITCH_FRAME is non-zero, switch-frame events are stashed
+   If NO_SWITCH_FRAME, switch-frame events are stashed
    until we get a character we like, and then stuffed into
    unread_switch_frame.
 
-   If ASCII_REQUIRED is non-zero, we check function key events to see
+   If ASCII_REQUIRED, check function key events to see
    if the unmodified version of the symbol has a Qascii_character
    property, and use that character, if present.
 
-   If ERROR_NONASCII is non-zero, we signal an error if the input we
-   get isn't an ASCII character with modifiers.  If it's zero but
-   ASCII_REQUIRED is non-zero, we just re-read until we get an ASCII
+   If ERROR_NONASCII, signal an error if the input we
+   get isn't an ASCII character with modifiers.  If it's false but
+   ASCII_REQUIRED is true, just re-read until we get an ASCII
    character.
 
-   If INPUT_METHOD is nonzero, we invoke the current input method
+   If INPUT_METHOD, invoke the current input method
    if the character warrants that.
 
-   If SECONDS is a number, we wait that many seconds for input, and
+   If SECONDS is a number, wait that many seconds for input, and
    return Qnil if no input arrives within that time.  */
 
 static Lisp_Object
-read_filtered_event (int no_switch_frame, int ascii_required,
-                    int error_nonascii, int input_method, Lisp_Object seconds)
+read_filtered_event (bool no_switch_frame, bool ascii_required,
+                    bool error_nonascii, bool input_method, Lisp_Object seconds)
 {
   Lisp_Object val, delayed_switch_frame;
   EMACS_TIME end_time;
@@ -604,18 +598,9 @@ read_filtered_event (int no_switch_frame, int ascii_required,
   /* Compute timeout.  */
   if (NUMBERP (seconds))
     {
-      EMACS_TIME wait_time;
-      int sec, usec;
       double duration = extract_float (seconds);
-
-      if (0 < duration)
-       duration_to_sec_usec (duration, &sec, &usec);
-      else
-       sec = usec = 0;
-
-      EMACS_GET_TIME (end_time);
-      EMACS_SET_SECS_USECS (wait_time, sec, usec);
-      EMACS_ADD_TIME (end_time, end_time, wait_time);
+      EMACS_TIME wait_time = EMACS_TIME_FROM_DOUBLE (duration);
+      end_time = add_emacs_time (current_emacs_time (), wait_time);
     }
 
 /* Read until we get an acceptable event.  */
@@ -768,9 +753,9 @@ DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
   (void)
 {
   register Lisp_Object val;
-  BLOCK_INPUT;
+  block_input ();
   XSETINT (val, getc (instream));
-  UNBLOCK_INPUT;
+  unblock_input ();
   return val;
 }
 
@@ -779,13 +764,30 @@ DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
 
 /* Return true if the lisp code read using READCHARFUN defines a non-nil
    `lexical-binding' file variable.  After returning, the stream is
-   positioned following the first line, if it is a comment, otherwise
-   nothing is read.  */
+   positioned following the first line, if it is a comment or #! line,
+   otherwise nothing is read.  */
 
-static int
+static bool
 lisp_file_lexically_bound_p (Lisp_Object readcharfun)
 {
   int ch = READCHAR;
+
+  if (ch == '#')
+    {
+      ch = READCHAR;
+      if (ch != '!')
+        {
+          UNREAD (ch);
+          UNREAD ('#');
+          return 0;
+        }
+      while (ch != '\n' && ch != EOF)
+        ch = READCHAR;
+      if (ch == '\n') ch = READCHAR;
+      /* It is OK to leave the position after a #! line, since
+         that is what read1 does.  */
+    }
+
   if (ch != ';')
     /* The first line isn't a comment, just give up.  */
     {
@@ -795,11 +797,11 @@ lisp_file_lexically_bound_p (Lisp_Object readcharfun)
   else
     /* Look for an appropriate file-variable in the first line.  */
     {
-      int rv = 0;
+      bool rv = 0;
       enum {
        NOMINAL, AFTER_FIRST_DASH, AFTER_ASTERIX,
       } beg_end_state = NOMINAL;
-      int in_file_vars = 0;
+      bool in_file_vars = 0;
 
 #define UPDATE_BEG_END_STATE(ch)                               \
   if (beg_end_state == NOMINAL)                                        \
@@ -895,20 +897,17 @@ lisp_file_lexically_bound_p (Lisp_Object readcharfun)
    because of an incompatible change in the byte compiler.  */
 
 static int
-safe_to_load_p (int fd)
+safe_to_load_version (int 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.  */
-  nbytes = emacs_read (fd, buf, sizeof buf - 1);
+  nbytes = emacs_read (fd, buf, sizeof buf);
   if (nbytes > 0)
     {
-      buf[nbytes] = '\0';
-
       /* Skip to the next newline, skipping over the initial `ELC'
         with NUL bytes following it, but note the version.  */
       for (i = 0; i < nbytes && buf[i] != '\n'; ++i)
@@ -917,14 +916,12 @@ safe_to_load_p (int fd)
 
       if (i >= nbytes
          || fast_c_string_match_ignore_case (Vbytecomp_version_regexp,
-                                             buf + i) < 0)
-       safe_p = 0;
+                                             buf + i, nbytes - i) < 0)
+       version = 0;
     }
-  if (safe_p)
-    safe_p = version;
 
   lseek (fd, 0, SEEK_SET);
-  return safe_p;
+  return version;
 }
 
 
@@ -1028,12 +1025,12 @@ Return t if the file exists and loads successfully.  */)
   ptrdiff_t count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3;
   Lisp_Object found, efound, hist_file_name;
-  /* 1 means we printed the ".el is newer" message.  */
-  int newer = 0;
-  /* 1 means we are loading a compiled file.  */
-  int compiled = 0;
+  /* True means we printed the ".el is newer" message.  */
+  bool newer = 0;
+  /* True means we are loading a compiled file.  */
+  bool compiled = 0;
   Lisp_Object handler;
-  int safe_p = 1;
+  bool safe_p = 1;
   const char *fmode = "r";
   Lisp_Object tmp[2];
   int version;
@@ -1070,7 +1067,7 @@ Return t if the file exists and loads successfully.  */)
 
 
   /* Avoid weird lossage with null string as arg,
-     since it would try to load a directory as a Lisp file */
+     since it would try to load a directory as a Lisp file */
   if (SBYTES (file) > 0)
     {
       ptrdiff_t size = SBYTES (file);
@@ -1174,7 +1171,7 @@ Return t if the file exists and loads successfully.  */)
      Vload_source_file_function.  */
   specbind (Qlexical_binding, Qnil);
 
-  /* Get the name for load-history. */
+  /* Get the name for load-history.  */
   hist_file_name = (! NILP (Vpurify_flag)
                     ? Fconcat (2, (tmp[0] = Ffile_name_directory (file),
                                    tmp[1] = Ffile_name_nondirectory (found),
@@ -1188,7 +1185,7 @@ Return t if the file exists and loads successfully.  */)
   record_unwind_protect (load_warn_old_style_backquotes, file);
 
   if (!memcmp (SDATA (found) + SBYTES (found) - 4, ".elc", 4)
-      || (fd >= 0 && (version = safe_to_load_p (fd)) > 0))
+      || (fd >= 0 && (version = safe_to_load_version (fd)) > 0))
     /* Load .elc files directly, but not when they are
        remote and have no handler!  */
     {
@@ -1200,7 +1197,7 @@ Return t if the file exists and loads successfully.  */)
          GCPRO3 (file, found, hist_file_name);
 
          if (version < 0
-             && ! (version = safe_to_load_p (fd)))
+             && ! (version = safe_to_load_version (fd)))
            {
              safe_p = 0;
              if (!load_dangerous_libraries)
@@ -1229,7 +1226,8 @@ Return t if the file exists and loads successfully.  */)
              SSET (efound, SBYTES (efound) - 1, 'c');
            }
 
-         if (result == 0 && s1.st_mtime < s2.st_mtime)
+         if (result == 0
+             && EMACS_TIME_LT (get_stat_mtime (&s1), get_stat_mtime (&s2)))
            {
              /* Make the progress messages mention that source is newer.  */
              newer = 1;
@@ -1327,7 +1325,7 @@ Return t if the file exists and loads successfully.  */)
     }
   unbind_to (count, Qnil);
 
-  /* Run any eval-after-load forms for this file */
+  /* Run any eval-after-load forms for this file */
   if (!NILP (Ffboundp (Qdo_after_load_evaluation)))
     call1 (Qdo_after_load_evaluation, hist_file_name) ;
 
@@ -1359,14 +1357,14 @@ Return t if the file exists and loads successfully.  */)
 }
 
 static Lisp_Object
-load_unwind (Lisp_Object arg)  /* used as unwind-protect function in load */
+load_unwind (Lisp_Object arg)  /* Used as unwind-protect function in load.  */
 {
   FILE *stream = (FILE *) XSAVE_VALUE (arg)->pointer;
   if (stream != NULL)
     {
-      BLOCK_INPUT;
+      block_input ();
       fclose (stream);
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
   return Qnil;
 }
@@ -1391,10 +1389,10 @@ close_load_descs (void)
 #endif
 }
 \f
-static int
+static bool
 complete_filename_p (Lisp_Object pathname)
 {
-  register const unsigned char *s = SDATA (pathname);
+  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])));
@@ -1444,14 +1442,13 @@ static Lisp_Object Qdir_ok;
 int
 openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *storeptr, Lisp_Object predicate)
 {
-  register int fd;
+  int fd;
   ptrdiff_t fn_size = 100;
   char buf[100];
-  register char *fn = buf;
-  int absolute = 0;
+  char *fn = buf;
+  bool absolute = 0;
   ptrdiff_t want_length;
   Lisp_Object filename;
-  struct stat st;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
   Lisp_Object string, tail, encoded_fn;
   ptrdiff_t max_suffix_len = 0;
@@ -1478,13 +1475,13 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto
     {
       filename = Fexpand_file_name (str, XCAR (path));
       if (!complete_filename_p (filename))
-       /* If there are non-absolute elts in PATH (eg ".") */
+       /* If there are non-absolute elts in PATH (eg ".") */
        /* Of course, this could conceivably lose if luser sets
-          default-directory to be something non-absolute... */
+          default-directory to be something non-absolute...  */
        {
          filename = Fexpand_file_name (filename, BVAR (current_buffer, directory));
          if (!complete_filename_p (filename))
-           /* Give up on this path element! */
+           /* Give up on this path element!  */
            continue;
        }
 
@@ -1492,36 +1489,26 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto
         this path element/specified file name and any possible suffix.  */
       want_length = max_suffix_len + SBYTES (filename);
       if (fn_size <= want_length)
-       fn = (char *) alloca (fn_size = 100 + want_length);
+       fn = alloca (fn_size = 100 + want_length);
 
       /* Loop over suffixes.  */
       for (tail = NILP (suffixes) ? Fcons (empty_unibyte_string, Qnil) : suffixes;
           CONSP (tail); tail = XCDR (tail))
        {
-         ptrdiff_t lsuffix = SBYTES (XCAR (tail));
+         ptrdiff_t fnlen, lsuffix = SBYTES (XCAR (tail));
          Lisp_Object handler;
-         int exists;
+         bool exists;
 
          /* Concatenate path element/specified name with the suffix.
             If the directory starts with /:, remove that.  */
-         if (SCHARS (filename) > 2
-             && SREF (filename, 0) == '/'
-             && SREF (filename, 1) == ':')
-           {
-             strncpy (fn, SSDATA (filename) + 2,
-                      SBYTES (filename) - 2);
-             fn[SBYTES (filename) - 2] = 0;
-           }
-         else
-           {
-             strncpy (fn, SSDATA (filename),
-                      SBYTES (filename));
-             fn[SBYTES (filename)] = 0;
-           }
-
-         if (lsuffix != 0)  /* Bug happens on CCI if lsuffix is 0.  */
-           strncat (fn, SSDATA (XCAR (tail)), lsuffix);
-
+         int prefixlen = ((SCHARS (filename) > 2
+                           && SREF (filename, 0) == '/'
+                           && SREF (filename, 1) == ':')
+                          ? 2 : 0);
+         fnlen = SBYTES (filename) - prefixlen;
+         memcpy (fn, SDATA (filename) + prefixlen, fnlen);
+         memcpy (fn + fnlen, SDATA (XCAR (tail)), lsuffix + 1);
+         fnlen += lsuffix;
          /* Check that the file exists and is not a directory.  */
          /* We used to only check for handlers on non-absolute file names:
                if (absolute)
@@ -1530,7 +1517,7 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto
                  handler = Ffind_file_name_handler (filename, Qfile_exists_p);
             It's not clear why that was the case and it breaks things like
             (load "/bar.el") where the file is actually "/bar.el.gz".  */
-         string = build_string (fn);
+         string = make_string (fn, fnlen);
          handler = Ffind_file_name_handler (string, Qfile_exists_p);
          if ((!NILP (handler) || !NILP (predicate)) && !NATNUMP (predicate))
             {
@@ -1555,11 +1542,18 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto
            }
          else
            {
+#ifndef WINDOWSNT
+             struct stat st;
+#endif
              const char *pfn;
 
              encoded_fn = ENCODE_FILE (string);
              pfn = SSDATA (encoded_fn);
+#ifdef WINDOWSNT
+             exists = access (pfn, F_OK) == 0 && access (pfn, D_OK) < 0;
+#else
              exists = (stat (pfn, &st) == 0 && ! S_ISDIR (st.st_mode));
+#endif
              if (exists)
                {
                  /* Check that we can access or open it.  */
@@ -1595,14 +1589,16 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto
    the source has an associated file name or not.
 
    FILENAME is the file name that we are loading from.
-   ENTIRE is 1 if loading that entire file, 0 if evaluating part of it.  */
+
+   ENTIRE is true if loading that entire file, false if evaluating
+   part of it.  */
 
 static void
-build_load_history (Lisp_Object filename, int entire)
+build_load_history (Lisp_Object filename, bool entire)
 {
-  register Lisp_Object tail, prev, newelt;
-  register Lisp_Object tem, tem2;
-  register int foundit = 0;
+  Lisp_Object tail, prev, newelt;
+  Lisp_Object tem, tem2;
+  bool foundit = 0;
 
   tail = Vload_history;
   prev = Qnil;
@@ -1611,12 +1607,12 @@ build_load_history (Lisp_Object filename, int entire)
     {
       tem = XCAR (tail);
 
-      /* Find the feature's previous assoc list... */
+      /* Find the feature's previous assoc list...  */
       if (!NILP (Fequal (filename, Fcar (tem))))
        {
          foundit = 1;
 
-         /*  If we're loading the entire file, remove old data. */
+         /*  If we're loading the entire file, remove old data.  */
          if (entire)
            {
              if (NILP (prev))
@@ -1657,13 +1653,6 @@ build_load_history (Lisp_Object filename, int entire)
                           Vload_history);
 }
 
-static Lisp_Object
-unreadpure (Lisp_Object junk) /* Used as unwind-protect function in readevalloop */
-{
-  read_pure = 0;
-  return Qnil;
-}
-
 static Lisp_Object
 readevalloop_1 (Lisp_Object old)
 {
@@ -1674,7 +1663,7 @@ readevalloop_1 (Lisp_Object old)
 /* Signal an `end-of-file' error, if possible with file name
    information.  */
 
-static void
+static _Noreturn void
 end_of_file_error (void)
 {
   if (STRINGP (Vload_file_name))
@@ -1694,7 +1683,7 @@ static void
 readevalloop (Lisp_Object readcharfun,
              FILE *stream,
              Lisp_Object sourcename,
-             int printflag,
+             bool printflag,
              Lisp_Object unibyte, Lisp_Object readfun,
              Lisp_Object start, Lisp_Object end)
 {
@@ -1703,12 +1692,23 @@ readevalloop (Lisp_Object readcharfun,
   ptrdiff_t count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   struct buffer *b = 0;
-  int continue_reading_p;
+  bool continue_reading_p;
   Lisp_Object lex_bound;
-  /* Nonzero if reading an entire buffer.  */
-  int whole_buffer = 0;
-  /* 1 on the first time around.  */
-  int first_sexp = 1;
+  /* True if reading an entire buffer.  */
+  bool whole_buffer = 0;
+  /* True on the first time around.  */
+  bool first_sexp = 1;
+  Lisp_Object macroexpand = intern ("internal-macroexpand-for-load");
+
+  if (NILP (Ffboundp (macroexpand))
+      /* Don't macroexpand in .elc files, since it should have been done
+        already.  We actually don't know whether we're in a .elc file or not,
+        so we use circumstantial evidence: .el files normally go through
+        Vload_source_file_function -> load-with-code-conversion
+        -> eval-buffer.  */
+      || EQ (readcharfun, Qget_file_char)
+      || EQ (readcharfun, Qget_emacs_mule_file_char))
+    macroexpand = Qnil;
 
   if (MARKERP (readcharfun))
     {
@@ -1723,7 +1723,7 @@ readevalloop (Lisp_Object readcharfun,
 
   /* We assume START is nil when input is not from a buffer.  */
   if (! NILP (start) && !b)
-    abort ();
+    emacs_abort ();
 
   specbind (Qstandard_input, readcharfun); /* GCPROs readcharfun.  */
   specbind (Qcurrent_load_list, Qnil);
@@ -1740,7 +1740,7 @@ readevalloop (Lisp_Object readcharfun,
 
   GCPRO4 (sourcename, readfun, start, end);
 
-  /* Try to ensure sourcename is a truename, except whilst preloading. */
+  /* Try to ensure sourcename is a truename, except whilst preloading.  */
   if (NILP (Vpurify_flag)
       && !NILP (sourcename) && !NILP (Ffile_name_absolute_p (sourcename))
       && !NILP (Ffboundp (Qfile_truename)))
@@ -1753,7 +1753,7 @@ readevalloop (Lisp_Object readcharfun,
     {
       ptrdiff_t count1 = SPECPDL_INDEX ();
 
-      if (b != 0 && NILP (BVAR (b, name)))
+      if (b != 0 && !BUFFER_LIVE_P (b))
        error ("Reading from killed buffer");
 
       if (!NILP (start))
@@ -1805,8 +1805,7 @@ readevalloop (Lisp_Object readcharfun,
 
       if (!NILP (Vpurify_flag) && c == '(')
        {
-         record_unwind_protect (unreadpure, Qnil);
-         val = read_list (-1, readcharfun);
+         val = read_list (0, readcharfun);
        }
       else
        {
@@ -1839,6 +1838,8 @@ readevalloop (Lisp_Object readcharfun,
       unbind_to (count1, Qnil);
 
       /* Now eval what we just read.  */
+      if (!NILP (macroexpand))
+       val = call1 (macroexpand, val);
       val = eval_sub (val);
 
       if (printflag)
@@ -1934,7 +1935,7 @@ This function does not move point.  */)
   specbind (Qstandard_output, tem);
   specbind (Qeval_buffer_list, Fcons (cbuf, Veval_buffer_list));
 
-  /* readevalloop calls functions which check the type of start and end.  */
+  /* `readevalloop' calls functions which check the type of start and end.  */
   readevalloop (cbuf, 0, BVAR (XBUFFER (cbuf), filename),
                !NILP (printflag), Qnil, read_function,
                start, end);
@@ -1977,16 +1978,16 @@ START and END optionally delimit a substring of STRING from which to read;
 {
   Lisp_Object ret;
   CHECK_STRING (string);
-  /* read_internal_start sets read_from_string_index. */
+  /* `read_internal_start' sets `read_from_string_index'.  */
   ret = read_internal_start (string, start, end);
   return Fcons (ret, make_number (read_from_string_index));
 }
 
 /* Function to set up the global context we need in toplevel read
-   calls. */
+   calls.  */
 static Lisp_Object
 read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
-/* start, end only used when stream is a string. */
+/* `start', `end' only used when stream is a string.  */
 {
   Lisp_Object retval;
 
@@ -2043,7 +2044,7 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
 /* Signal Qinvalid_read_syntax error.
    S is error string of length N (if > 0)  */
 
-static void
+static _Noreturn void
 invalid_syntax (const char *s)
 {
   xsignal1 (Qinvalid_read_syntax, build_string (s));
@@ -2051,7 +2052,7 @@ invalid_syntax (const char *s)
 
 
 /* Use this for recursive reads, in contexts where internal tokens
-   are not allowed. */
+   are not allowed.  */
 
 static Lisp_Object
 read0 (Lisp_Object readcharfun)
@@ -2074,11 +2075,11 @@ static char *read_buffer;
    If the escape sequence forces unibyte, return eight-bit char.  */
 
 static int
-read_escape (Lisp_Object readcharfun, int stringp)
+read_escape (Lisp_Object readcharfun, bool stringp)
 {
-  register int c = READCHAR;
+  int c = READCHAR;
   /* \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. */
+     behavior for \u, and change this value in the case that \U is seen.  */
   int unicode_hex_count = 4;
 
   switch (c)
@@ -2264,8 +2265,8 @@ read_escape (Lisp_Object readcharfun, int stringp)
        while (++count <= unicode_hex_count)
          {
            c = READCHAR;
-           /* isdigit and isalpha may be locale-specific, which we don't
-              want. */
+           /* `isdigit' and `isalpha' may be locale-specific, which we don't
+              want.  */
            if      (c >= '0' && c <= '9')  i = (i << 4) + (c - '0');
            else if (c >= 'a' && c <= 'f')  i = (i << 4) + (c - 'a') + 10;
             else if (c >= 'A' && c <= 'F')  i = (i << 4) + (c - 'A') + 10;
@@ -2285,7 +2286,7 @@ read_escape (Lisp_Object readcharfun, int stringp)
 /* Return the digit that CHARACTER stands for in the given BASE.
    Return -1 if CHARACTER is out of range for BASE,
    and -2 if CHARACTER is not valid for any supported BASE.  */
-static inline int
+static int
 digit_to_number (int character, int base)
 {
   int digit;
@@ -2377,14 +2378,14 @@ read_integer (Lisp_Object readcharfun, EMACS_INT radix)
    in *PCH and the return value is not interesting.  Else, we store
    zero in *PCH and we read and return one lisp object.
 
-   FIRST_IN_LIST is nonzero if this is the first element of a list.  */
+   FIRST_IN_LIST is true if this is the first element of a list.  */
 
 static Lisp_Object
-read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
+read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 {
-  register int c;
-  unsigned uninterned_symbol = 0;
-  int multibyte;
+  int c;
+  bool uninterned_symbol = 0;
+  bool multibyte;
 
   *pch = 0;
   load_each_byte = 0;
@@ -2419,13 +2420,13 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
            {
              /* Accept extended format for hashtables (extensible to
                 other types), e.g.
-                #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
+                #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. */
+                make-hash-table.  */
              Lisp_Object params[10];
              Lisp_Object ht;
              Lisp_Object key = Qnil;
@@ -2437,36 +2438,36 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
 
              tmp = CDR_SAFE (tmp);
 
-             /* This is repetitive but fast and simple. */
+             /* This is repetitive but fast and simple.  */
              params[param_count] = QCsize;
-             params[param_count+1] = Fplist_get (tmp, Qsize);
+             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);
+             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);
+             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);
+             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);
+             params[param_count + 1] = Fplist_get (tmp, Qrehash_threshold);
              if (!NILP (params[param_count + 1]))
                param_count += 2;
 
-             /* This is the hashtable data. */
+             /* This is the hashtable data.  */
              data = Fplist_get (tmp, Qdata);
 
-             /* Now use params to make a new hashtable and fill it. */
+             /* Now use params to make a new hashtable and fill it.  */
              ht = Fmake_hash_table (param_count, params);
 
              while (CONSP (data))
@@ -2562,8 +2563,8 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
             build them using function calls.  */
          Lisp_Object tmp;
          tmp = read_vector (readcharfun, 1);
-         return Fmake_byte_code (ASIZE (tmp),
-                                 XVECTOR (tmp)->contents);
+         make_byte_code (XVECTOR (tmp));
+         return tmp;
        }
       if (c == '(')
        {
@@ -2646,13 +2647,12 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
 
              if (saved_doc_string_size == 0)
                {
-                 saved_doc_string = (char *) xmalloc (nskip + extra);
+                 saved_doc_string = xmalloc (nskip + extra);
                  saved_doc_string_size = nskip + extra;
                }
              if (nskip > saved_doc_string_size)
                {
-                 saved_doc_string = (char *) xrealloc (saved_doc_string,
-                                                       nskip + extra);
+                 saved_doc_string = xrealloc (saved_doc_string, nskip + extra);
                  saved_doc_string_size = nskip + extra;
                }
 
@@ -2699,13 +2699,13 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
              /* No symbol character follows, this is the empty
                 symbol.  */
              UNREAD (c);
-             return Fmake_symbol (build_string (""));
+             return Fmake_symbol (empty_unibyte_string);
            }
          goto read_symbol;
        }
       /* ## is the empty symbol.  */
       if (c == '#')
-       return Fintern (build_string (""), Qnil);
+       return Fintern (empty_unibyte_string, Qnil);
       /* Reader forms that can reuse previously read objects.  */
       if (c >= '0' && c <= '9')
        {
@@ -2734,7 +2734,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                       n for #n#.  */
                  if (c == '=')
                    {
-                     /* Make a placeholder for #n# to use temporarily */
+                     /* Make a placeholder for #n# to use temporarily */
                      Lisp_Object placeholder;
                      Lisp_Object cell;
 
@@ -2742,10 +2742,10 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                      cell = Fcons (make_number (n), placeholder);
                      read_objects = Fcons (cell, read_objects);
 
-                     /* Read the object itself. */
+                     /* Read the object itself.  */
                      tem = read0 (readcharfun);
 
-                     /* Now put it everywhere the placeholder was... */
+                     /* Now put it everywhere the placeholder was...  */
                      substitute_object_in_subtree (tem, placeholder);
 
                      /* ...and #n# will use the real value from now on.  */
@@ -2806,10 +2806,11 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
        else
          {
            Lisp_Object value;
+           bool saved_new_backquote_flag = new_backquote_flag;
 
-           new_backquote_flag++;
+           new_backquote_flag = 1;
            value = read0 (readcharfun);
-           new_backquote_flag--;
+           new_backquote_flag = saved_new_backquote_flag;
 
            return Fcons (Qbackquote, Fcons (value, Qnil));
          }
@@ -2861,7 +2862,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
       {
        int modifiers;
        int next_char;
-       int ok;
+       bool ok;
 
        c = READCHAR;
        if (c < 0)
@@ -2897,14 +2898,14 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
       {
        char *p = read_buffer;
        char *end = read_buffer + read_buffer_size;
-       register int ch;
-       /* Nonzero if we saw an escape sequence specifying
+       int ch;
+       /* True if we saw an escape sequence specifying
           a multibyte character.  */
-       int force_multibyte = 0;
-       /* Nonzero if we saw an escape sequence specifying
+       bool force_multibyte = 0;
+       /* True if we saw an escape sequence specifying
           a single-byte character.  */
-       int force_singlebyte = 0;
-       int cancel = 0;
+       bool force_singlebyte = 0;
+       bool cancel = 0;
        ptrdiff_t nchars = 0;
 
        while ((ch = READCHAR) >= 0
@@ -2915,8 +2916,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                ptrdiff_t offset = p - read_buffer;
                if (min (PTRDIFF_MAX, SIZE_MAX) / 2 < read_buffer_size)
                  memory_full (SIZE_MAX);
-               read_buffer = (char *) xrealloc (read_buffer,
-                                                read_buffer_size * 2);
+               read_buffer = xrealloc (read_buffer, read_buffer_size * 2);
                read_buffer_size *= 2;
                p = read_buffer + offset;
                end = read_buffer + read_buffer_size;
@@ -2928,7 +2928,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
 
                ch = read_escape (readcharfun, 1);
 
-               /* CH is -1 if \ newline has just been seen */
+               /* CH is -1 if \ newline has just been seen */
                if (ch == -1)
                  {
                    if (p == read_buffer)
@@ -2943,7 +2943,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                  force_singlebyte = 1;
                else if (! ASCII_CHAR_P (ch))
                  force_multibyte = 1;
-               else            /* i.e. ASCII_CHAR_P (ch) */
+               else            /* I.e. ASCII_CHAR_P (ch).  */
                  {
                    /* Allow `\C- ' and `\C-?'.  */
                    if (modifiers == CHAR_CTL)
@@ -2993,28 +2993,19 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
 
        /* If purifying, and string starts with \ newline,
           return zero instead.  This is for doc strings
-          that we are really going to find in etc/DOC.nn.nn  */
+          that we are really going to find in etc/DOC.nn.nn.  */
        if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel)
          return make_number (0);
 
-       if (force_multibyte)
-         /* READ_BUFFER already contains valid multibyte forms.  */
-         ;
-       else if (force_singlebyte)
+       if (! force_multibyte && force_singlebyte)
          {
+           /* READ_BUFFER contains raw 8-bit bytes and no multibyte
+              forms.  Convert it to unibyte.  */
            nchars = str_as_unibyte ((unsigned char *) read_buffer,
                                     p - read_buffer);
            p = read_buffer + nchars;
          }
-       else
-         {
-           /* Otherwise, READ_BUFFER contains only ASCII.  */
-         }
 
-       if (read_pure)
-         return make_pure_string (read_buffer, nchars, p - read_buffer,
-                                  (force_multibyte
-                                   || (p - read_buffer != nchars)));
        return make_specified_string (read_buffer, nchars, p - read_buffer,
                                      (force_multibyte
                                       || (p - read_buffer != nchars)));
@@ -3046,7 +3037,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
     read_symbol:
       {
        char *p = read_buffer;
-       int quoted = 0;
+       bool quoted = 0;
        EMACS_INT start_position = readchar_count - 1;
 
        {
@@ -3059,8 +3050,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                  ptrdiff_t offset = p - read_buffer;
                  if (min (PTRDIFF_MAX, SIZE_MAX) / 2 < read_buffer_size)
                    memory_full (SIZE_MAX);
-                 read_buffer = (char *) xrealloc (read_buffer,
-                                                  read_buffer_size * 2);
+                 read_buffer = xrealloc (read_buffer, read_buffer_size * 2);
                  read_buffer_size *= 2;
                  p = read_buffer + offset;
                  end = read_buffer + read_buffer_size;
@@ -3090,8 +3080,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
              ptrdiff_t offset = p - read_buffer;
              if (min (PTRDIFF_MAX, SIZE_MAX) / 2 < read_buffer_size)
                memory_full (SIZE_MAX);
-             read_buffer = (char *) xrealloc (read_buffer,
-                                              read_buffer_size * 2);
+             read_buffer = xrealloc (read_buffer, read_buffer_size * 2);
              read_buffer_size *= 2;
              p = read_buffer + offset;
              end = read_buffer + read_buffer_size;
@@ -3115,18 +3104,17 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                                          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);
+         name = ((uninterned_symbol && ! NILP (Vpurify_flag)
+                  ? make_pure_string : 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 =
-             Fcons (Fcons (result, make_number (start_position)),
-                    Vread_symbol_positions_list);
+           Vread_symbol_positions_list
+             Fcons (Fcons (result, make_number (start_position)),
+                      Vread_symbol_positions_list);
          return result;
        }
       }
@@ -3134,7 +3122,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
 }
 \f
 
-/* List of nodes we've seen during substitute_object_in_subtree. */
+/* List of nodes we've seen during substitute_object_in_subtree.  */
 static Lisp_Object seen_list;
 
 static void
@@ -3142,23 +3130,23 @@ substitute_object_in_subtree (Lisp_Object object, Lisp_Object placeholder)
 {
   Lisp_Object check_object;
 
-  /* We haven't seen any objects when we start. */
+  /* We haven't seen any objects when we start.  */
   seen_list = Qnil;
 
-  /* Make all the substitutions. */
+  /* Make all the substitutions.  */
   check_object
     = substitute_object_recurse (object, placeholder, object);
 
-  /* Clear seen_list because we're done with it. */
+  /* Clear seen_list because we're done with it.  */
   seen_list = Qnil;
 
   /* The returned object here is expected to always eq the
-     original. */
+     original.  */
   if (!EQ (check_object, object))
     error ("Unexpected mutation error in reader");
 }
 
-/*  Feval doesn't get called from here, so no gc protection is needed. */
+/*  Feval doesn't get called from here, so no gc protection is needed.  */
 #define SUBSTITUTE(get_val, set_val)                   \
   do {                                                 \
     Lisp_Object old_value = get_val;                   \
@@ -3175,11 +3163,11 @@ substitute_object_in_subtree (Lisp_Object object, Lisp_Object placeholder)
 static Lisp_Object
 substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Object subtree)
 {
-  /* If we find the placeholder, return the target object. */
+  /* If we find the placeholder, return the target object.  */
   if (EQ (placeholder, subtree))
     return object;
 
-  /* If we've been to this node before, don't explore it again. */
+  /* If we've been to this node before, don't explore it again.  */
   if (!EQ (Qnil, Fmemq (subtree, seen_list)))
     return subtree;
 
@@ -3229,10 +3217,10 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj
     case Lisp_String:
       {
        /* Check for text properties in each interval.
-          substitute_in_interval contains part of the logic. */
+          substitute_in_interval contains part of the logic.  */
 
-       INTERVAL    root_interval = STRING_INTERVALS (subtree);
-       Lisp_Object arg           = Fcons (object, placeholder);
+       INTERVAL root_interval = string_intervals (subtree);
+       Lisp_Object arg = Fcons (object, placeholder);
 
        traverse_intervals_noorder (root_interval,
                                    &substitute_in_interval, arg);
@@ -3240,7 +3228,7 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj
        return subtree;
       }
 
-      /* Other types don't recurse any further. */
+      /* Other types don't recurse any further.  */
     default:
       return subtree;
     }
@@ -3253,7 +3241,7 @@ substitute_in_interval (INTERVAL interval, Lisp_Object arg)
   Lisp_Object object      = Fcar (arg);
   Lisp_Object placeholder = Fcdr (arg);
 
-  SUBSTITUTE (interval->plist, interval->plist = true_value);
+  SUBSTITUTE (interval->plist, set_interval_plist (interval, true_value));
 }
 
 \f
@@ -3266,17 +3254,17 @@ substitute_in_interval (INTERVAL interval, Lisp_Object arg)
 /* Convert STRING to a number, assuming base BASE.  Return a fixnum if CP has
    integer syntax and fits in a fixnum, else return the nearest float if CP has
    either floating point or integer syntax and BASE is 10, else return nil.  If
-   IGNORE_TRAILING is nonzero, consider just the longest prefix of CP that has
+   IGNORE_TRAILING, consider just the longest prefix of CP that has
    valid floating point syntax.  Signal an overflow if BASE is not 10 and the
    number has integer syntax but does not fit.  */
 
 Lisp_Object
-string_to_number (char const *string, int base, int ignore_trailing)
+string_to_number (char const *string, int base, bool ignore_trailing)
 {
   int state;
   char const *cp = string;
   int leading_digit;
-  int float_syntax = 0;
+  bool float_syntax = 0;
   double value = 0;
 
   /* Compute NaN and infinities using a variable, to cope with compilers that
@@ -3286,9 +3274,9 @@ string_to_number (char const *string, int base, int ignore_trailing)
   /* Negate the value ourselves.  This treats 0, NaNs, and infinity properly on
      IEEE floating point hosts, and works around a formerly-common bug where
      atof ("-0.0") drops the sign.  */
-  int negative = *cp == '-';
+  bool negative = *cp == '-';
 
-  int signedp = negative || *cp == '+';
+  bool signedp = negative || *cp == '+';
   cp += signedp;
 
   state = 0;
@@ -3381,7 +3369,7 @@ string_to_number (char const *string, int base, int ignore_trailing)
       uintmax_t n;
 
       /* Fast special case for single-digit integers.  This also avoids a
-        glitch when BASE is 16 and IGNORE_TRAILING is nonzero, because in that
+        glitch when BASE is 16 and IGNORE_TRAILING, because in that
         case some versions of strtoumax accept numbers like "0x1" that Emacs
         does not allow.  */
       if (digit_to_number (string[signedp + 1], base) < 0)
@@ -3417,17 +3405,17 @@ string_to_number (char const *string, int base, int ignore_trailing)
 
 \f
 static Lisp_Object
-read_vector (Lisp_Object readcharfun, int bytecodeflag)
+read_vector (Lisp_Object readcharfun, bool bytecodeflag)
 {
   ptrdiff_t i, size;
-  register Lisp_Object *ptr;
-  register Lisp_Object tem, item, vector;
-  register struct Lisp_Cons *otem;
+  Lisp_Object *ptr;
+  Lisp_Object tem, item, vector;
+  struct Lisp_Cons *otem;
   Lisp_Object len;
 
   tem = read_list (1, readcharfun);
   len = Flength (tem);
-  vector = (read_pure ? make_pure_vector (XINT (len)) : Fmake_vector (len, Qnil));
+  vector = Fmake_vector (len, Qnil);
 
   size = ASIZE (vector);
   ptr = XVECTOR (vector)->contents;
@@ -3448,7 +3436,7 @@ read_vector (Lisp_Object readcharfun, int bytecodeflag)
              /* Delay handling the bytecode slot until we know whether
                 it is lazily-loaded (we can tell by whether the
                 constants slot is nil).  */
-             ptr[COMPILED_CONSTANTS] = item;
+             ASET (vector, COMPILED_CONSTANTS, item);
              item = Qnil;
            }
          else if (i == COMPILED_CONSTANTS)
@@ -3474,7 +3462,7 @@ read_vector (Lisp_Object readcharfun, int bytecodeflag)
                }
 
              /* Now handle the bytecode slot.  */
-             ptr[COMPILED_BYTECODE] = read_pure ? Fpurecopy (bytestr) : bytestr;
+             ASET (vector, COMPILED_BYTECODE, bytestr);
            }
          else if (i == COMPILED_DOC_STRING
                   && STRINGP (item)
@@ -3486,7 +3474,7 @@ read_vector (Lisp_Object readcharfun, int bytecodeflag)
                item = Fstring_as_multibyte (item);
            }
        }
-      ptr[i] = read_pure ? Fpurecopy (item) : item;
+      ASET (vector, i, item);
       otem = XCONS (tem);
       tem = Fcdr (tem);
       free_cons (otem);
@@ -3494,19 +3482,13 @@ read_vector (Lisp_Object readcharfun, int bytecodeflag)
   return vector;
 }
 
-/* FLAG = 1 means check for ] to terminate rather than ) and .
-   FLAG = -1 means check for starting with defun
-    and make structure pure.  */
+/* FLAG means check for ] to terminate rather than ) and .  */
 
 static Lisp_Object
-read_list (int flag, register Lisp_Object readcharfun)
+read_list (bool flag, Lisp_Object readcharfun)
 {
-  /* -1 means check next element for defun,
-     0 means don't check,
-     1 means already checked and found defun. */
-  int defunflag = flag < 0 ? -1 : 0;
   Lisp_Object val, tail;
-  register Lisp_Object elt, tem;
+  Lisp_Object elt, tem;
   struct gcpro gcpro1, gcpro2;
   /* 0 is the normal case.
      1 means this list is a doc reference; replace it with the number 0.
@@ -3514,7 +3496,7 @@ read_list (int flag, register Lisp_Object readcharfun)
   int doc_reference = 0;
 
   /* Initialize this to 1 if we are reading a list.  */
-  int first_in_list = flag <= 0;
+  bool first_in_list = flag <= 0;
 
   val = Qnil;
   tail = Qnil;
@@ -3546,7 +3528,7 @@ read_list (int flag, register Lisp_Object readcharfun)
               We don't use Fexpand_file_name because that would make
               the directory absolute now.  */
            elt = concat2 (build_string ("../lisp/"),
-                          Ffile_name_nondirectory (elt));
+                        Ffile_name_nondirectory (elt));
        }
       else if (EQ (elt, Vload_file_name)
               && ! NILP (elt)
@@ -3666,24 +3648,18 @@ read_list (int flag, register Lisp_Object readcharfun)
            }
          invalid_syntax ("] in a list");
        }
-      tem = (read_pure && flag <= 0
-            ? pure_cons (elt, Qnil)
-            : Fcons (elt, Qnil));
+      tem = Fcons (elt, Qnil);
       if (!NILP (tail))
        XSETCDR (tail, tem);
       else
        val = tem;
       tail = tem;
-      if (defunflag < 0)
-       defunflag = EQ (elt, Qdefun);
-      else if (defunflag > 0)
-       read_pure = 1;
     }
 }
 \f
 static Lisp_Object initial_obarray;
 
-/* oblookup stores the bucket number here, for the sake of Funintern.  */
+/* `oblookup' stores the bucket number here, for the sake of Funintern.  */
 
 static size_t oblookup_last_bucket_number;
 
@@ -3706,32 +3682,20 @@ check_obarray (Lisp_Object obarray)
    interned in the current obarray.  */
 
 Lisp_Object
-intern (const char *str)
+intern_1 (const char *str, ptrdiff_t len)
 {
-  Lisp_Object tem;
-  ptrdiff_t len = strlen (str);
-  Lisp_Object obarray;
+  Lisp_Object obarray = check_obarray (Vobarray);
+  Lisp_Object tem = oblookup (obarray, str, len, len);
 
-  obarray = Vobarray;
-  if (!VECTORP (obarray) || ASIZE (obarray) == 0)
-    obarray = check_obarray (obarray);
-  tem = oblookup (obarray, str, len, len);
-  if (SYMBOLP (tem))
-    return tem;
-  return Fintern (make_string (str, len), obarray);
+  return SYMBOLP (tem) ? tem : Fintern (make_string (str, len), obarray);
 }
 
 Lisp_Object
-intern_c_string (const char *str)
+intern_c_string_1 (const char *str, ptrdiff_t len)
 {
-  Lisp_Object tem;
-  ptrdiff_t len = strlen (str);
-  Lisp_Object obarray;
+  Lisp_Object obarray = check_obarray (Vobarray);
+  Lisp_Object tem = oblookup (obarray, str, len, len);
 
-  obarray = Vobarray;
-  if (!VECTORP (obarray) || ASIZE (obarray) == 0)
-    obarray = check_obarray (obarray);
-  tem = oblookup (obarray, str, len, len);
   if (SYMBOLP (tem))
     return tem;
 
@@ -3739,9 +3703,9 @@ intern_c_string (const char *str)
     /* 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 ();
+    emacs_abort ();
 
-  return Fintern (make_pure_c_string (str), obarray);
+  return Fintern (make_pure_c_string (str, len), obarray);
 }
 \f
 DEFUN ("intern", Fintern, Sintern, 1, 2, 0,
@@ -3781,11 +3745,11 @@ it defaults to the value of `obarray'.  */)
       SET_SYMBOL_VAL (XSYMBOL (sym), sym);
     }
 
-  ptr = &XVECTOR (obarray)->contents[XINT (tem)];
+  ptr = aref_addr (obarray, XINT(tem));
   if (SYMBOLP (*ptr))
-    XSYMBOL (sym)->next = XSYMBOL (*ptr);
+    set_symbol_next (sym, XSYMBOL (*ptr));
   else
-    XSYMBOL (sym)->next = 0;
+    set_symbol_next (sym, NULL);
   *ptr = sym;
   return sym;
 }
@@ -3860,25 +3824,29 @@ OBARRAY defaults to the value of the variable `obarray'.  */)
 
   hash = oblookup_last_bucket_number;
 
-  if (EQ (XVECTOR (obarray)->contents[hash], tem))
+  if (EQ (AREF (obarray, hash), tem))
     {
       if (XSYMBOL (tem)->next)
-       XSETSYMBOL (XVECTOR (obarray)->contents[hash], XSYMBOL (tem)->next);
+       {
+         Lisp_Object sym;
+         XSETSYMBOL (sym, XSYMBOL (tem)->next);
+         ASET (obarray, hash, sym);
+       }
       else
-       XSETINT (XVECTOR (obarray)->contents[hash], 0);
+       ASET (obarray, hash, make_number (0));
     }
   else
     {
       Lisp_Object tail, following;
 
-      for (tail = XVECTOR (obarray)->contents[hash];
+      for (tail = AREF (obarray, hash);
           XSYMBOL (tail)->next;
           tail = following)
        {
          XSETSYMBOL (following, XSYMBOL (tail)->next);
          if (EQ (following, tem))
            {
-             XSYMBOL (tail)->next = XSYMBOL (following)->next;
+             set_symbol_next (tail, XSYMBOL (following)->next);
              break;
            }
        }
@@ -3901,21 +3869,18 @@ oblookup (Lisp_Object obarray, register const char *ptr, ptrdiff_t size, ptrdiff
   register Lisp_Object tail;
   Lisp_Object bucket, tem;
 
-  if (!VECTORP (obarray)
-      || (obsize = ASIZE (obarray)) == 0)
-    {
-      obarray = check_obarray (obarray);
-      obsize = ASIZE (obarray);
-    }
+  obarray = check_obarray (obarray);
+  obsize = ASIZE (obarray);
+
   /* This is sometimes needed in the middle of GC.  */
   obsize &= ~ARRAY_MARK_FLAG;
   hash = hash_string (ptr, size_byte) % obsize;
-  bucket = XVECTOR (obarray)->contents[hash];
+  bucket = AREF (obarray, hash);
   oblookup_last_bucket_number = hash;
   if (EQ (bucket, make_number (0)))
     ;
   else if (!SYMBOLP (bucket))
-    error ("Bad data in guts of obarray"); /* Like CADR error message */
+    error ("Bad data in guts of obarray"); /* Like CADR error message */
   else
     for (tail = bucket; ; XSETSYMBOL (tail, XSYMBOL (tail)->next))
       {
@@ -3938,7 +3903,7 @@ map_obarray (Lisp_Object obarray, void (*fn) (Lisp_Object, Lisp_Object), Lisp_Ob
   CHECK_VECTOR (obarray);
   for (i = ASIZE (obarray) - 1; i >= 0; i--)
     {
-      tail = XVECTOR (obarray)->contents[i];
+      tail = AREF (obarray, i);
       if (SYMBOLP (tail))
        while (1)
          {
@@ -3982,7 +3947,7 @@ init_obarray (void)
   initial_obarray = Vobarray;
   staticpro (&initial_obarray);
 
-  Qunbound = Fmake_symbol (make_pure_c_string ("unbound"));
+  Qunbound = Fmake_symbol (build_pure_c_string ("unbound"));
   /* Set temporary dummy values to Qnil and Vpurify_flag to satisfy the
      NILP (Vpurify_flag) check in intern_c_string.  */
   Qnil = make_number (-1); Vpurify_flag = make_number (1);
@@ -3991,15 +3956,16 @@ init_obarray (void)
   /* Fmake_symbol inits fields of new symbols with Qunbound and Qnil,
      so those two need to be fixed manually.  */
   SET_SYMBOL_VAL (XSYMBOL (Qunbound), Qunbound);
-  XSYMBOL (Qunbound)->function = Qunbound;
-  XSYMBOL (Qunbound)->plist = Qnil;
-  /* XSYMBOL (Qnil)->function = Qunbound; */
+  set_symbol_function (Qunbound, Qunbound);
+  set_symbol_plist (Qunbound, Qnil);
   SET_SYMBOL_VAL (XSYMBOL (Qnil), Qnil);
   XSYMBOL (Qnil)->constant = 1;
-  XSYMBOL (Qnil)->plist = Qnil;
+  XSYMBOL (Qnil)->declared_special = 1;
+  set_symbol_plist (Qnil, Qnil);
 
   Qt = intern_c_string ("t");
   SET_SYMBOL_VAL (XSYMBOL (Qt), Qt);
+  XSYMBOL (Qnil)->declared_special = 1;
   XSYMBOL (Qt)->constant = 1;
 
   /* Qt is correct even if CANNOT_DUMP.  loadup.el will set to nil at end.  */
@@ -4007,20 +3973,21 @@ init_obarray (void)
 
   DEFSYM (Qvariable_documentation, "variable-documentation");
 
-  read_buffer = (char *) xmalloc (size);
+  read_buffer = xmalloc (size);
   read_buffer_size = size;
 }
 \f
 void
 defsubr (struct Lisp_Subr *sname)
 {
-  Lisp_Object sym;
+  Lisp_Object sym, tem;
   sym = intern_c_string (sname->symbol_name);
   XSETTYPED_PVECTYPE (sname, size, PVEC_SUBR);
-  XSETSUBR (XSYMBOL (sym)->function, sname);
+  XSETSUBR (tem, sname);
+  set_symbol_function (sym, tem);
 }
 
-#ifdef NOTDEF /* use fset in subr.el now */
+#ifdef NOTDEF /* Use fset in subr.el now!  */
 void
 defalias (struct Lisp_Subr *sname, char *string)
 {
@@ -4050,7 +4017,7 @@ defvar_int (struct Lisp_Intfwd *i_fwd,
    nil if address contains 0.  */
 void
 defvar_bool (struct Lisp_Boolfwd *b_fwd,
-            const char *namestring, int *address)
+            const char *namestring, bool *address)
 {
   Lisp_Object sym;
   sym = intern_c_string (namestring);
@@ -4104,62 +4071,105 @@ defvar_kboard (struct Lisp_Kboard_Objfwd *ko_fwd,
   SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)ko_fwd);
 }
 \f
+/* Check that the elements of Vload_path exist.  */
+
+static void
+load_path_check (void)
+{
+  Lisp_Object path_tail;
+
+  /* The only elements that might not exist are those from
+     PATH_LOADSEARCH, EMACSLOADPATH.  Anything else is only added if
+     it exists.  */
+  for (path_tail = Vload_path; !NILP (path_tail); path_tail = XCDR (path_tail))
+    {
+      Lisp_Object dirfile;
+      dirfile = Fcar (path_tail);
+      if (STRINGP (dirfile))
+        {
+          dirfile = Fdirectory_file_name (dirfile);
+          if (access (SSDATA (dirfile), 0) < 0)
+            dir_warning ("Warning: Lisp directory `%s' does not exist.\n",
+                         XCAR (path_tail));
+        }
+    }
+}
+
 /* Record the value of load-path used at the start of dumping
    so we can see if the site changed it later during dumping.  */
 static Lisp_Object dump_path;
 
+/* Compute the default Vload_path, with the following logic:
+   If CANNOT_DUMP:
+   use EMACSLOADPATH env-var if set; otherwise use PATH_LOADSEARCH,
+   prepending PATH_SITELOADSEARCH unless --no-site-lisp.
+   The remainder is what happens when dumping works:
+   If purify-flag (ie dumping) just use PATH_DUMPLOADSEARCH.
+   Otherwise use EMACSLOADPATH if set, else PATH_LOADSEARCH.
+
+   If !initialized, then just set both Vload_path and dump_path.
+   If initialized, then if Vload_path != dump_path, do nothing.
+   (Presumably the load-path has already been changed by something.
+   This can only be from a site-load file during dumping,
+   or because EMACSLOADPATH is set.)
+   If Vinstallation_directory is not nil (ie, running uninstalled):
+   If installation-dir/lisp exists and not already a member,
+   we must be running uninstalled.  Reset the load-path
+   to just installation-dir/lisp.  (The default PATH_LOADSEARCH
+   refers to the eventual installation directories.  Since we
+   are not yet installed, we should not use them, even if they exist.)
+   If installation-dir/lisp does not exist, just add dump_path at the
+   end instead.
+   Add installation-dir/leim (if exists and not already a member) at the front.
+   Add installation-dir/site-lisp (if !no_site_lisp, and exists
+   and not already a member) at the front.
+   If installation-dir != source-dir (ie running an uninstalled,
+   out-of-tree build) AND install-dir/src/Makefile exists BUT
+   install-dir/src/Makefile.in does NOT exist (this is a sanity
+   check), then repeat the above steps for source-dir/lisp,
+   leim and site-lisp.
+   Finally, add the site-lisp directories at the front (if !no_site_lisp).
+*/
+
 void
 init_lread (void)
 {
   const char *normal;
-  int turn_off_warning = 0;
-
-  /* Compute the default Vload-path, with the following logic:
-     If CANNOT_DUMP just use PATH_LOADSEARCH.
-     Else if purify-flag (ie dumping) start from PATH_DUMPLOADSEARCH;
-     otherwise start from PATH_LOADSEARCH.
-     If !initialized, then just set both Vload_path and dump_path.
-     If initialized, then if Vload_path != dump_path, do nothing.
-     (Presumably the load-path has already been changed by something.)
-     Also do nothing if Vinstallation_directory is nil.
-     Otherwise:
-       Remove site-lisp directories from the front of load-path.
-       Add installation-dir/lisp (if exists and not already a member),
-         at the front, and turn off warnings about missing directories
-         (because we are presumably running uninstalled).
-         If it does not exist, add dump_path at the end instead.
-       Add installation-dir/leim (if exists and not already a member)
-         at the front.
-       Add installation-dir/site-lisp (if !no_site_lisp, and exists
-         and not already a member) at the front.
-       If installation-dir != source-dir (ie running an uninstalled,
-         out-of-tree build) AND install-dir/src/Makefile exists BUT
-         install-dir/src/Makefile.in does NOT exist (this is a sanity
-         check), then repeat the above steps for source-dir/lisp,
-         leim and site-lisp.
-       Finally, add the previously removed site-lisp directories back
-       at the front (if !no_site_lisp).
-
-     We then warn about any of the load-path elements that do not
-     exist.  The only ones that might not exist are those from
-     PATH_LOADSEARCH, and perhaps dump_path.
-
-     Having done all this, we then throw it all away if purify-flag is
-     nil (ie, not dumping) and EMACSLOADPATH is set, and just
-     unconditionally use the latter value instead.
-     So AFAICS the only net results of all the previous steps will be
-     possibly to issue some irrelevant warnings.
-
-     FIXME? There's a case for saying that if we are running
-     uninstalled, the eventual installation directories should not yet
-     be included in load-path.
-  */
+
 #ifdef CANNOT_DUMP
+#ifdef HAVE_NS
+  const char *loadpath = ns_load_path ();
+#endif
+
   normal = PATH_LOADSEARCH;
-  Vload_path = decode_env_path (0, normal);
+#ifdef HAVE_NS
+  Vload_path = decode_env_path ("EMACSLOADPATH", loadpath ? loadpath : normal);
 #else
+  Vload_path = decode_env_path ("EMACSLOADPATH", normal);
+#endif
+
+  load_path_check ();
+
+  /* FIXME CANNOT_DUMP platforms should get source-dir/lisp etc added
+   to their load-path too, AFAICS.  I don't think we can tell the
+   difference between initialized and !initialized in this case,
+   so we'll have to do it unconditionally when Vinstallation_directory
+   is non-nil.  */
+  if (!no_site_lisp && !egetenv ("EMACSLOADPATH"))
+    {
+      Lisp_Object sitelisp;
+      sitelisp = decode_env_path (0, PATH_SITELOADSEARCH);
+      if (! NILP (sitelisp)) Vload_path = nconc2 (sitelisp, Vload_path);
+    }
+#else  /* !CANNOT_DUMP */
   if (NILP (Vpurify_flag))
-    normal = PATH_LOADSEARCH;
+    {
+      normal = PATH_LOADSEARCH;
+      /* If the EMACSLOADPATH environment variable is set, use its value.
+         This doesn't apply if we're dumping.  */
+      if (egetenv ("EMACSLOADPATH"))
+        Vload_path = decode_env_path ("EMACSLOADPATH", normal);
+    }
   else
     normal = PATH_DUMPLOADSEARCH;
 
@@ -4168,183 +4178,155 @@ init_lread (void)
      the source directory, instead of the path of the installed elisp
      libraries.  However, if it appears that Vload_path has already been
      changed from the default that was saved before dumping, don't
-     change it further.  */
+     change it further.  Changes can only be due to EMACSLOADPATH, or
+     site-lisp files that were processed during dumping.  */
   if (initialized)
     {
-      if (! NILP (Fequal (dump_path, Vload_path)))
+      if (NILP (Fequal (dump_path, Vload_path)))
+        {
+          /* Do not make any changes, just check the elements exist.  */
+          /* Note: --no-site-lisp is ignored.
+             I don't know what to do about this.  */
+          load_path_check ();
+        }
+      else
        {
+#ifdef HAVE_NS
+         const char *loadpath = ns_load_path ();
+         Vload_path = decode_env_path (0, loadpath ? loadpath : normal);
+#else
          Vload_path = decode_env_path (0, normal);
-         if (no_site_lisp || !NILP (Vinstallation_directory))
+#endif
+         if (!NILP (Vinstallation_directory))
            {
-             Lisp_Object tem, tem1, sitelisp;
-
-             /* Remove "site-lisp" dirs from front of path temporarily
-                and store them in sitelisp, then conc them on at the
-                end so they're always first in path.
-                Note that this won't work if you used a
-                --enable-locallisppath element that does not happen
-                to contain "site-lisp" in its name.
-             */
-             sitelisp = Qnil;
-             while (1)
-               {
-                 tem = Fcar (Vload_path);
-                 tem1 = Fstring_match (build_string ("site-lisp"),
-                                       tem, Qnil);
-                 if (!NILP (tem1))
-                   {
-                     Vload_path = Fcdr (Vload_path);
-                     sitelisp = Fcons (tem, sitelisp);
-                   }
-                 else
-                   break;
-               }
-
-             if (!NILP (Vinstallation_directory))
-               {
-                 /* Add to the path the lisp subdir of the
-                    installation dir, if it exists.  */
-                 tem = Fexpand_file_name (build_string ("lisp"),
-                                          Vinstallation_directory);
-                 tem1 = Ffile_exists_p (tem);
-                 if (!NILP (tem1))
-                   {
-                     if (NILP (Fmember (tem, Vload_path)))
-                       {
-                         turn_off_warning = 1;
-                         Vload_path = Fcons (tem, Vload_path);
-                       }
-                   }
-                 else
-                   /* That dir doesn't exist, so add the build-time
-                      Lisp dirs instead.  */
-                   Vload_path = nconc2 (Vload_path, dump_path);
-
-                 /* Add leim under the installation dir, if it exists.  */
-                 tem = Fexpand_file_name (build_string ("leim"),
-                                          Vinstallation_directory);
-                 tem1 = Ffile_exists_p (tem);
-                 if (!NILP (tem1))
-                   {
-                     if (NILP (Fmember (tem, Vload_path)))
-                       Vload_path = Fcons (tem, Vload_path);
-                   }
-
-                 /* Add site-lisp under the installation dir, if it exists.  */
-                 if (!no_site_lisp)
-                   {
-                     tem = Fexpand_file_name (build_string ("site-lisp"),
-                                              Vinstallation_directory);
-                     tem1 = Ffile_exists_p (tem);
-                     if (!NILP (tem1))
-                       {
-                         if (NILP (Fmember (tem, Vload_path)))
-                           Vload_path = Fcons (tem, Vload_path);
-                       }
-                   }
-
-                 /* If Emacs was not built in the source directory,
-                    and it is run from where it was built, add to load-path
-                    the lisp, leim and site-lisp dirs under that directory.  */
-
-                 if (NILP (Fequal (Vinstallation_directory, Vsource_directory)))
-                   {
-                     Lisp_Object tem2;
-
-                     tem = Fexpand_file_name (build_string ("src/Makefile"),
-                                              Vinstallation_directory);
-                     tem1 = Ffile_exists_p (tem);
-
-                     /* Don't be fooled if they moved the entire source tree
-                        AFTER dumping Emacs.  If the build directory is indeed
-                        different from the source dir, src/Makefile.in and
-                        src/Makefile will not be found together.  */
-                     tem = Fexpand_file_name (build_string ("src/Makefile.in"),
-                                              Vinstallation_directory);
-                     tem2 = Ffile_exists_p (tem);
-                     if (!NILP (tem1) && NILP (tem2))
-                       {
-                         tem = Fexpand_file_name (build_string ("lisp"),
-                                                  Vsource_directory);
-
-                         if (NILP (Fmember (tem, Vload_path)))
-                           Vload_path = Fcons (tem, Vload_path);
-
-                         tem = Fexpand_file_name (build_string ("leim"),
-                                                  Vsource_directory);
-
-                         if (NILP (Fmember (tem, Vload_path)))
-                           Vload_path = Fcons (tem, Vload_path);
-
-                         if (!no_site_lisp)
-                           {
-                             tem = Fexpand_file_name (build_string ("site-lisp"),
-                                                      Vsource_directory);
-
-                             if (NILP (Fmember (tem, Vload_path)))
-                               Vload_path = Fcons (tem, Vload_path);
-                           }
-                       }
-                   } /* Vinstallation_directory != Vsource_directory */
-               }     /* if Vinstallation_directory */
-             if (!NILP (sitelisp) && !no_site_lisp)
-               Vload_path = nconc2 (Fnreverse (sitelisp), Vload_path);
-           } /* if Vinstallation_directory || no_site_lisp */
-       }     /* if dump_path == Vload_path */
+             Lisp_Object tem, tem1;
+
+              /* Add to the path the lisp subdir of the installation
+                 dir, if it exists.  Note: in out-of-tree builds,
+                 this directory is empty save for Makefile.  */
+              tem = Fexpand_file_name (build_string ("lisp"),
+                                       Vinstallation_directory);
+              tem1 = Ffile_exists_p (tem);
+              if (!NILP (tem1))
+                {
+                  if (NILP (Fmember (tem, Vload_path)))
+                    {
+                      /* We are running uninstalled.  The default load-path
+                         points to the eventual installed lisp, leim
+                         directories.  We should not use those now, even
+                         if they exist, so start over from a clean slate.  */
+                      Vload_path = Fcons (tem, Qnil);
+                    }
+                }
+              else
+                /* That dir doesn't exist, so add the build-time
+                   Lisp dirs instead.  */
+                Vload_path = nconc2 (Vload_path, dump_path);
+
+              /* Add leim under the installation dir, if it exists. */
+              tem = Fexpand_file_name (build_string ("leim"),
+                                       Vinstallation_directory);
+              tem1 = Ffile_exists_p (tem);
+              if (!NILP (tem1))
+                {
+                  if (NILP (Fmember (tem, Vload_path)))
+                    Vload_path = Fcons (tem, Vload_path);
+                }
+
+              /* Add site-lisp under the installation dir, if it exists.  */
+              if (!no_site_lisp)
+                {
+                  tem = Fexpand_file_name (build_string ("site-lisp"),
+                                           Vinstallation_directory);
+                  tem1 = Ffile_exists_p (tem);
+                  if (!NILP (tem1))
+                    {
+                      if (NILP (Fmember (tem, Vload_path)))
+                        Vload_path = Fcons (tem, Vload_path);
+                    }
+                }
+
+              /* If Emacs was not built in the source directory,
+                 and it is run from where it was built, add to load-path
+                 the lisp, leim and site-lisp dirs under that directory.  */
+
+              if (NILP (Fequal (Vinstallation_directory, Vsource_directory)))
+                {
+                  Lisp_Object tem2;
+
+                  tem = Fexpand_file_name (build_string ("src/Makefile"),
+                                           Vinstallation_directory);
+                  tem1 = Ffile_exists_p (tem);
+
+                  /* Don't be fooled if they moved the entire source tree
+                     AFTER dumping Emacs.  If the build directory is indeed
+                     different from the source dir, src/Makefile.in and
+                     src/Makefile will not be found together.  */
+                  tem = Fexpand_file_name (build_string ("src/Makefile.in"),
+                                           Vinstallation_directory);
+                  tem2 = Ffile_exists_p (tem);
+                  if (!NILP (tem1) && NILP (tem2))
+                    {
+                      tem = Fexpand_file_name (build_string ("lisp"),
+                                               Vsource_directory);
+
+                      if (NILP (Fmember (tem, Vload_path)))
+                        Vload_path = Fcons (tem, Vload_path);
+
+                      tem = Fexpand_file_name (build_string ("leim"),
+                                               Vsource_directory);
+
+                      if (NILP (Fmember (tem, Vload_path)))
+                        Vload_path = Fcons (tem, Vload_path);
+
+                      if (!no_site_lisp)
+                        {
+                          tem = Fexpand_file_name (build_string ("site-lisp"),
+                                                   Vsource_directory);
+                          tem1 = Ffile_exists_p (tem);
+                          if (!NILP (tem1))
+                            {
+                              if (NILP (Fmember (tem, Vload_path)))
+                                Vload_path = Fcons (tem, Vload_path);
+                            }
+                        }
+                    }
+                } /* Vinstallation_directory != Vsource_directory */
+
+           } /* if Vinstallation_directory */
+
+          /* Check before adding the site-lisp directories.
+             The install should have created them, but they are not
+             required, so no need to warn if they are absent.
+             Or we might be running before installation.  */
+          load_path_check ();
+
+          /* Add the site-lisp directories at the front.  */
+          if (!no_site_lisp)
+            {
+              Lisp_Object sitelisp;
+              sitelisp = decode_env_path (0, PATH_SITELOADSEARCH);
+              if (! NILP (sitelisp)) Vload_path = nconc2 (sitelisp, Vload_path);
+            }
+       } /* if dump_path == Vload_path */
     }
   else                          /* !initialized */
     {
-      /* NORMAL refers to the lisp dir in the source directory.  */
-      /* We used to add ../lisp at the front here, but
-        that caused trouble because it was copied from dump_path
-        into Vload_path, above, when Vinstallation_directory was non-nil.
-        It should be unnecessary.  */
+      /* NORMAL refers to PATH_DUMPLOADSEARCH, ie the lisp dir in the
+         source directory.  We used to add ../lisp (ie the lisp dir in
+         the build directory) at the front here, but that caused trouble
+        because it was copied from dump_path into Vload_path, above,
+        when Vinstallation_directory was non-nil.  It should not be
+         necessary, since in out of tree builds lisp/ is empty, save
+         for Makefile.  */
       Vload_path = decode_env_path (0, normal);
       dump_path = Vload_path;
+      /* No point calling load_path_check; load-path only contains essential
+         elements from the source directory at this point.  They cannot
+         be missing unless something went extremely (and improbably)
+         wrong, in which case the build will fail in obvious ways.  */
     }
-#endif  /* CANNOT_DUMP */
-
-#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.  */
-
-  /* HAVE_NS also uses EMACSLOADPATH.  */
-
-  /* Warn if dirs in the *standard* path don't exist.  */
-  if (!turn_off_warning)
-    {
-      Lisp_Object path_tail;
-
-      for (path_tail = Vload_path;
-          !NILP (path_tail);
-          path_tail = XCDR (path_tail))
-       {
-         Lisp_Object dirfile;
-         dirfile = Fcar (path_tail);
-         if (STRINGP (dirfile))
-           {
-             dirfile = Fdirectory_file_name (dirfile);
-              /* Do we really need to warn about missing site-lisp dirs?
-                 It's true that the installation should have created
-                 them and added subdirs.el, but it's harmless if they
-                 are not there.  */
-             if (access (SSDATA (dirfile), 0) < 0)
-               dir_warning ("Warning: Lisp directory `%s' does not exist.\n",
-                            XCAR (path_tail));
-           }
-       }
-    }
-#endif /* !(WINDOWSNT || HAVE_NS) */
-
-  /* If the EMACSLOADPATH environment variable is set, use its value.
-     This doesn't apply if we're dumping.  */
-#ifndef CANNOT_DUMP
-  if (NILP (Vpurify_flag)
-      && egetenv ("EMACSLOADPATH"))
-#endif
-    Vload_path = decode_env_path ("EMACSLOADPATH", normal);
+#endif  /* !CANNOT_DUMP */
 
   Vvalues = Qnil;
 
@@ -4365,15 +4347,13 @@ dir_warning (const char *format, Lisp_Object dirname)
 {
   fprintf (stderr, format, SDATA (dirname));
 
-  /* Don't log the warning before we've initialized!! */
+  /* Don't log the warning before we've initialized!!  */
   if (initialized)
     {
-      char *buffer;
-      ptrdiff_t message_len;
       USE_SAFE_ALLOCA;
-      SAFE_ALLOCA (buffer, char *,
-                  SBYTES (dirname) + strlen (format) - (sizeof "%s" - 1) + 1);
-      message_len = esprintf (buffer, format, SDATA (dirname));
+      char *buffer = SAFE_ALLOCA (SBYTES (dirname)
+                                 + strlen (format) - (sizeof "%s" - 1) + 1);
+      ptrdiff_t message_len = esprintf (buffer, format, SDATA (dirname));
       message_dolog (buffer, message_len, 0, STRING_MULTIBYTE (dirname));
       SAFE_FREE ();
     }
@@ -4406,7 +4386,8 @@ to find all the symbols in an obarray, use `mapatoms'.  */);
 
   DEFVAR_LISP ("values", Vvalues,
               doc: /* List of values of all expressions which were read, evaluated and printed.
-Order is reverse chronological.  */);
+                      Order is reverse chronological.  */);
+  XSYMBOL (intern ("values"))->declared_special = 0;
 
   DEFVAR_LISP ("standard-input", Vstandard_input,
               doc: /* Stream for read to get input from.
@@ -4424,7 +4405,7 @@ defined, although they may be in the future.
 
 The positions are relative to the last call to `read' or
 `read-from-string'.  It is probably a bad idea to set this variable at
-the toplevel; bind it instead. */);
+the toplevel; bind it instead.  */);
   Vread_with_symbol_positions = Qnil;
 
   DEFVAR_LISP ("read-symbol-positions-list", Vread_symbol_positions_list,
@@ -4439,7 +4420,7 @@ symbol from the position where `read' or `read-from-string' started.
 
 Note that a symbol will appear multiple times in this list, if it was
 read multiple times.  The list is in the same order as the symbols
-were read in. */);
+were read in.  */);
   Vread_symbol_positions_list = Qnil;
 
   DEFVAR_LISP ("read-circle", Vread_circle,
@@ -4457,8 +4438,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 (make_pure_c_string (".elc"),
-                         Fcons (make_pure_c_string (".el"), Qnil));
+  Vload_suffixes = Fcons (build_pure_c_string (".elc"),
+                         Fcons (build_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.
@@ -4591,10 +4572,9 @@ 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
-    = make_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
+    = build_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
 
-  Qlexical_binding = intern ("lexical-binding");
-  staticpro (&Qlexical_binding);
+  DEFSYM (Qlexical_binding, "lexical-binding");
   DEFVAR_LISP ("lexical-binding", Vlexical_binding,
               doc: /* Whether to use lexical binding when evaluating code.
 Non-nil means that the code in the current buffer should be evaluated
@@ -4602,6 +4582,7 @@ with lexical binding.
 This variable is automatically set from the file variables of an
 interpreted Lisp file read using `load'.  Unlike other file local
 variables, this must be set in the first line of a file.  */);
+  Vlexical_binding = Qnil;
   Fmake_variable_buffer_local (Qlexical_binding);
 
   DEFVAR_LISP ("eval-buffer-list", Veval_buffer_list,