]> code.delx.au - gnu-emacs/blobdiff - src/lread.c
Fixed a bug in w32-long-file-name.
[gnu-emacs] / src / lread.c
index c4bc6fda8129da7c7ef7b7747d4183b7762c64a4..a64f083a5acbde2cb113f2493e8714757283d5b4 100644 (file)
@@ -1,7 +1,6 @@
 /* Lisp parsing and input streams.
 
-Copyright (C) 1985-1989, 1993-1995, 1997-2013 Free Software Foundation,
-Inc.
+Copyright (C) 1985-1989, 1993-1995, 1997-2013 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -145,7 +144,6 @@ static int read_emacs_mule_char (int, int (*) (int, Lisp_Object),
 static void readevalloop (Lisp_Object, FILE *, Lisp_Object, bool,
                           Lisp_Object, Lisp_Object,
                           Lisp_Object, Lisp_Object);
-static void load_unwind (void *);
 \f
 /* Functions that read one byte from the current source READCHARFUN
    or unreads one byte.  If the integer argument C is -1, it returns
@@ -610,7 +608,7 @@ 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;
+  struct timespec end_time;
 
 #ifdef HAVE_WINDOW_SYSTEM
   if (display_hourglass_p)
@@ -623,8 +621,8 @@ read_filtered_event (bool no_switch_frame, bool ascii_required,
   if (NUMBERP (seconds))
     {
       double duration = extract_float (seconds);
-      EMACS_TIME wait_time = EMACS_TIME_FROM_DOUBLE (duration);
-      end_time = add_emacs_time (current_emacs_time (), wait_time);
+      struct timespec wait_time = dtotimespec (duration);
+      end_time = timespec_add (current_timespec (), wait_time);
     }
 
   /* Read until we get an acceptable event.  */
@@ -1040,10 +1038,12 @@ While the file is in the process of being loaded, the variable
 is bound to the file's name.
 
 Return t if the file exists and loads successfully.  */)
-  (Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage, Lisp_Object nosuffix, Lisp_Object must_suffix)
+  (Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage,
+   Lisp_Object nosuffix, Lisp_Object must_suffix)
 {
-  register FILE *stream;
-  register int fd = -1;
+  FILE *stream;
+  int fd;
+  int fd_index;
   ptrdiff_t count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3;
   Lisp_Object found, efound, hist_file_name;
@@ -1054,7 +1054,6 @@ Return t if the file exists and loads successfully.  */)
   Lisp_Object handler;
   bool safe_p = 1;
   const char *fmode = "r";
-  Lisp_Object tmp[2];
   int version;
 
 #ifdef DOS_NT
@@ -1087,19 +1086,23 @@ Return t if the file exists and loads successfully.  */)
   else
     file = Fsubstitute_in_file_name (file);
 
-
   /* Avoid weird lossage with null string as arg,
      since it would try to load a directory as a Lisp file.  */
-  if (SBYTES (file) > 0)
+  if (SCHARS (file) == 0)
     {
-      ptrdiff_t size = SBYTES (file);
-
+      fd = -1;
+      errno = ENOENT;
+    }
+  else
+    {
+      Lisp_Object suffixes;
       found = Qnil;
       GCPRO2 (file, found);
 
       if (! NILP (must_suffix))
        {
          /* Don't insist on adding a suffix if FILE already ends with one.  */
+         ptrdiff_t size = SBYTES (file);
          if (size > 3
              && !strcmp (SSDATA (file) + size - 3, ".el"))
            must_suffix = Qnil;
@@ -1112,20 +1115,28 @@ Return t if the file exists and loads successfully.  */)
            must_suffix = Qnil;
        }
 
-      fd = openp (Vload_path, file,
-                 (!NILP (nosuffix) ? Qnil
-                  : !NILP (must_suffix) ? Fget_load_suffixes ()
-                  : Fappend (2, (tmp[0] = Fget_load_suffixes (),
-                                 tmp[1] = Vload_file_rep_suffixes,
-                                 tmp))),
-                 &found, Qnil);
+      if (!NILP (nosuffix))
+       suffixes = Qnil;
+      else
+       {
+         suffixes = Fget_load_suffixes ();
+         if (NILP (must_suffix))
+           {
+             Lisp_Object arg[2];
+             arg[0] = suffixes;
+             arg[1] = Vload_file_rep_suffixes;
+             suffixes = Fappend (2, arg);
+           }
+       }
+
+      fd = openp (Vload_path, file, suffixes, &found, Qnil);
       UNGCPRO;
     }
 
   if (fd == -1)
     {
       if (NILP (noerror))
-       xsignal2 (Qfile_error, build_string ("Cannot open load file"), file);
+       report_file_error ("Cannot open load file", file);
       return Qnil;
     }
 
@@ -1163,6 +1174,17 @@ Return t if the file exists and loads successfully.  */)
 #endif
     }
 
+  if (fd < 0)
+    {
+      /* Pacify older GCC with --enable-gcc-warnings.  */
+      IF_LINT (fd_index = 0);
+    }
+  else
+    {
+      fd_index = SPECPDL_INDEX ();
+      record_unwind_protect_int (close_file_unwind, fd);
+    }
+
   /* Check if we're stuck in a recursive load cycle.
 
      2000-09-21: It's not possible to just check for the file loaded
@@ -1178,11 +1200,7 @@ Return t if the file exists and loads successfully.  */)
     Lisp_Object tem;
     for (tem = Vloads_in_progress; CONSP (tem); tem = XCDR (tem))
       if (!NILP (Fequal (found, XCAR (tem))) && (++load_count > 3))
-       {
-         if (fd >= 0)
-           emacs_close (fd);
-         signal_error ("Recursive load", Fcons (found, Vloads_in_progress));
-       }
+       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);
   }
@@ -1195,9 +1213,8 @@ Return t if the file exists and loads successfully.  */)
 
   /* 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),
-                                   tmp))
+                    ? concat2 (Ffile_name_directory (file),
+                               Ffile_name_nondirectory (found))
                     : found) ;
 
   version = -1;
@@ -1223,12 +1240,7 @@ Return t if the file exists and loads successfully.  */)
            {
              safe_p = 0;
              if (!load_dangerous_libraries)
-               {
-                 if (fd >= 0)
-                   emacs_close (fd);
-                 error ("File `%s' was not compiled in Emacs",
-                        SDATA (found));
-               }
+               error ("File `%s' was not compiled in Emacs", SDATA (found));
              else if (!NILP (nomessage) && !force_load_messages)
                message_with_string ("File `%s' not compiled in Emacs", found, 1);
            }
@@ -1249,7 +1261,7 @@ Return t if the file exists and loads successfully.  */)
            }
 
          if (result == 0
-             && EMACS_TIME_LT (get_stat_mtime (&s1), get_stat_mtime (&s2)))
+             && timespec_cmp (get_stat_mtime (&s1), get_stat_mtime (&s2)) < 0)
            {
              /* Make the progress messages mention that source is newer.  */
              newer = 1;
@@ -1274,7 +1286,10 @@ Return t if the file exists and loads successfully.  */)
          Lisp_Object val;
 
          if (fd >= 0)
-           emacs_close (fd);
+           {
+             emacs_close (fd);
+             clear_unwind_protect (fd_index);
+           }
          val = call4 (Vload_source_file_function, found, hist_file_name,
                       NILP (noerror) ? Qnil : Qt,
                       (NILP (nomessage) || force_load_messages) ? Qnil : Qt);
@@ -1284,26 +1299,28 @@ Return t if the file exists and loads successfully.  */)
 
   GCPRO3 (file, found, hist_file_name);
 
-#ifdef WINDOWSNT
-  efound = ENCODE_FILE (found);
-  /* If we somehow got here with fd == -2, meaning the file is deemed
-     to be remote, don't even try to reopen the file locally; just
-     force a failure instead.  */
-  if (fd >= 0)
+  if (fd < 0)
     {
-      emacs_close (fd);
-      stream = emacs_fopen (SSDATA (efound), fmode);
+      /* We somehow got here with fd == -2, meaning the file is deemed
+        to be remote.  Don't even try to reopen the file locally;
+        just force a failure.  */
+      stream = NULL;
+      errno = EINVAL;
     }
   else
-    stream = NULL;
-#else  /* not WINDOWSNT */
-  stream = fdopen (fd, fmode);
-#endif /* not WINDOWSNT */
-  if (stream == 0)
     {
+#ifdef WINDOWSNT
       emacs_close (fd);
-      error ("Failure to create stdio stream for %s", SDATA (file));
+      clear_unwind_protect (fd_index);
+      efound = ENCODE_FILE (found);
+      stream = emacs_fopen (SSDATA (efound), fmode);
+#else
+      stream = fdopen (fd, fmode);
+#endif
     }
+  if (! stream)
+    report_file_error ("Opening stdio stream", file);
+  set_unwind_protect_ptr (fd_index, fclose_unwind, stream);
 
   if (! NILP (Vpurify_flag))
     Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list);
@@ -1322,7 +1339,6 @@ Return t if the file exists and loads successfully.  */)
        message_with_string ("Loading %s...", file, 1);
     }
 
-  record_unwind_protect_ptr (load_unwind, stream);
   specbind (Qload_file_name, found);
   specbind (Qinhibit_file_name_operation, Qnil);
   specbind (Qload_in_progress, Qt);
@@ -1374,18 +1390,6 @@ Return t if the file exists and loads successfully.  */)
 
   return Qt;
 }
-
-static void
-load_unwind (void *arg)
-{
-  FILE *stream = arg;
-  if (stream != NULL)
-    {
-      block_input ();
-      fclose (stream);
-      unblock_input ();
-    }
-}
 \f
 static bool
 complete_filename_p (Lisp_Object pathname)
@@ -1495,7 +1499,8 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
       for (tail = NILP (suffixes) ? list1 (empty_unibyte_string) : suffixes;
           CONSP (tail); tail = XCDR (tail))
        {
-         ptrdiff_t fnlen, lsuffix = SBYTES (XCAR (tail));
+         Lisp_Object suffix = XCAR (tail);
+         ptrdiff_t fnlen, lsuffix = SBYTES (suffix);
          Lisp_Object handler;
 
          /* Concatenate path element/specified name with the suffix.
@@ -1506,7 +1511,7 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
                           ? 2 : 0);
          fnlen = SBYTES (filename) - prefixlen;
          memcpy (fn, SDATA (filename) + prefixlen, fnlen);
-         memcpy (fn + fnlen, SDATA (XCAR (tail)), lsuffix + 1);
+         memcpy (fn + fnlen, SDATA (suffix), 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:
@@ -1516,12 +1521,22 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
                  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 = make_string (fn, fnlen);
+         /* make_string has its own ideas on when to return a unibyte
+            string and when a multibyte string, but we know better.
+            We must have a unibyte string when dumping, since
+            file-name encoding is shaky at best at that time, and in
+            particular default-file-name-coding-system is reset
+            several times during loadup.  We therefore don't want to
+            encode the file before passing it to file I/O library
+            functions.  */
+         if (!STRING_MULTIBYTE (filename) && !STRING_MULTIBYTE (suffix))
+           string = make_unibyte_string (fn, fnlen);
+         else
+           string = make_string (fn, fnlen);
          handler = Ffind_file_name_handler (string, Qfile_exists_p);
          if ((!NILP (handler) || !NILP (predicate)) && !NATNUMP (predicate))
             {
              bool exists;
-             last_errno = ENOENT;
              if (NILP (predicate))
                exists = !NILP (Ffile_readable_p (string));
              else
@@ -1576,7 +1591,10 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
                {
                  fd = emacs_open (pfn, O_RDONLY, 0);
                  if (fd < 0)
-                   last_errno = errno;
+                   {
+                     if (errno != ENOENT)
+                       last_errno = errno;
+                   }
                  else
                    {
                      struct stat st;
@@ -2558,9 +2576,8 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
          if (c == '"')
            {
              Lisp_Object tmp, val;
-             EMACS_INT size_in_chars
-               = ((XFASTINT (length) + BOOL_VECTOR_BITS_PER_CHAR - 1)
-                  / BOOL_VECTOR_BITS_PER_CHAR);
+             EMACS_INT size_in_chars = bool_vector_bytes (XFASTINT (length));
+             unsigned char *data;
 
              UNREAD (c);
              tmp = read1 (readcharfun, pch, first_in_list);
@@ -2574,11 +2591,12 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
                            == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR)))
                invalid_syntax ("#&...");
 
-             val = Fmake_bool_vector (length, Qnil);
-             memcpy (XBOOL_VECTOR (val)->data, SDATA (tmp), size_in_chars);
+             val = make_uninit_bool_vector (XFASTINT (length));
+             data = bool_vector_uchar_data (val);
+             memcpy (data, SDATA (tmp), size_in_chars);
              /* Clear the extraneous bits in the last byte.  */
              if (XINT (length) != size_in_chars * BOOL_VECTOR_BITS_PER_CHAR)
-               XBOOL_VECTOR (val)->data[size_in_chars - 1]
+               data[size_in_chars - 1]
                  &= (1 << (XINT (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1;
              return val;
            }
@@ -2590,7 +2608,10 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
             build them using function calls.  */
          Lisp_Object tmp;
          tmp = read_vector (readcharfun, 1);
-         make_byte_code (XVECTOR (tmp));
+         struct Lisp_Vector* vec = XVECTOR (tmp);
+         if (vec->header.size==0)
+           invalid_syntax ("Empty byte-code object");
+         make_byte_code (vec);
          return tmp;
        }
       if (c == '(')
@@ -3222,7 +3243,7 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj
        if (BOOL_VECTOR_P (subtree))
          return subtree;               /* No sub-objects anyway.  */
        else if (CHAR_TABLE_P (subtree) || SUB_CHAR_TABLE_P (subtree)
-                || COMPILEDP (subtree))
+                || COMPILEDP (subtree) || HASH_TABLE_P (subtree))
          length = ASIZE (subtree) & PSEUDOVECTOR_SIZE_MASK;
        else if (VECTORP (subtree))
          length = ASIZE (subtree);
@@ -3516,7 +3537,7 @@ read_vector (Lisp_Object readcharfun, bool bytecodeflag)
   return vector;
 }
 
-/* FLAG means check for ] to terminate rather than ) and .  */
+/* FLAG means check for ']' to terminate rather than ')' and '.'.  */
 
 static Lisp_Object
 read_list (bool flag, Lisp_Object readcharfun)
@@ -4084,17 +4105,17 @@ 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.  */
+/* Check that the elements of lpath exist.  */
 
 static void
-load_path_check (void)
+load_path_check (Lisp_Object lpath)
 {
   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))
+  for (path_tail = lpath; !NILP (path_tail); path_tail = XCDR (path_tail))
     {
       Lisp_Object dirfile;
       dirfile = Fcar (path_tail);
@@ -4111,19 +4132,23 @@ load_path_check (void)
    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.
+/* Return the default load-path, to be used if EMACSLOADPATH is unset.
+   This does not include the standard site-lisp directories
+   under the installation prefix (i.e., PATH_SITELOADSEARCH),
+   but it does (unless no_site_lisp is set) include site-lisp
+   directories in the source/build directories if those exist and we
+   are running uninstalled.
+
+   Uses the following logic:
+   If CANNOT_DUMP: Use PATH_LOADSEARCH.
    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.
+   Otherwise use PATH_LOADSEARCH.
 
-   If !initialized, then just set both Vload_path and dump_path.
-   If initialized, then if Vload_path != dump_path, do nothing.
+   If !initialized, then just set dump_path and return PATH_DUMPLOADSEARCH.
+   If initialized, then if Vload_path != dump_path, return just Vload_path.
    (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.)
+   This can only be from a site-load file during dumping.)
    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
@@ -4132,20 +4157,17 @@ static Lisp_Object dump_path;
    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).
-*/
+   check), then repeat the above steps for source-dir/lisp, site-lisp.  */
 
-void
-init_lread (void)
+static Lisp_Object
+load_path_default (bool changed)
 {
+  Lisp_Object lpath = Qnil;
   const char *normal;
 
 #ifdef CANNOT_DUMP
@@ -4155,63 +4177,48 @@ init_lread (void)
 
   normal = PATH_LOADSEARCH;
 #ifdef HAVE_NS
-  Vload_path = decode_env_path ("EMACSLOADPATH", loadpath ? loadpath : normal);
+  lpath = decode_env_path (0, loadpath ? loadpath : normal, 0);
 #else
-  Vload_path = decode_env_path ("EMACSLOADPATH", normal);
+  lpath = decode_env_path (0, normal, 0);
 #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;
-      /* 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;
+
+  normal = NILP (Vpurify_flag) ? PATH_LOADSEARCH : PATH_DUMPLOADSEARCH;
 
   /* In a dumped Emacs, we normally reset the value of Vload_path using
      PATH_LOADSEARCH, since the value that was dumped uses lisp/ in
      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.  Changes can only be due to EMACSLOADPATH, or
-     site-lisp files that were processed during dumping.  */
+     change it further.  Changes can only be due to site-lisp
+     files that were processed during dumping.  */
+  /* FIXME?  AFAICS, it does not make sense to change load-path in a
+     dumped site-lisp file, so maybe we should just drop this check.
+     E.g., if you add an element to load-path, you are going to be
+     adding it to PATH_DUMPLOADSEARCH, which refers to the source directory.
+     This will make no sense (and may not still exist) in an installed Emacs.
+     And the only change it is sensible to make to load-path is to add
+     something to the front, which you should do with configure's
+     --enable-locallisppath option if you really want to have it dumped.  */
   if (initialized)
     {
-      if (NILP (Fequal (dump_path, Vload_path)))
+      if (changed || 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 ();
+          /* Do not make any changes.  */
+          return Vload_path;
         }
       else
-       {
+        {
 #ifdef HAVE_NS
-         const char *loadpath = ns_load_path ();
-         Vload_path = decode_env_path (0, loadpath ? loadpath : normal);
+          const char *loadpath = ns_load_path ();
+          lpath = decode_env_path (0, loadpath ? loadpath : normal, 0);
 #else
-         Vload_path = decode_env_path (0, normal);
+          lpath = decode_env_path (0, normal, 0);
 #endif
-         if (!NILP (Vinstallation_directory))
-           {
-             Lisp_Object tem, tem1;
+          if (!NILP (Vinstallation_directory))
+            {
+              Lisp_Object tem, tem1;
 
               /* Add to the path the lisp subdir of the installation
                  dir, if it is accessible.  Note: in out-of-tree builds,
@@ -4221,29 +4228,19 @@ init_lread (void)
               tem1 = Ffile_accessible_directory_p (tem);
               if (!NILP (tem1))
                 {
-                  if (NILP (Fmember (tem, Vload_path)))
+                  if (NILP (Fmember (tem, lpath)))
                     {
                       /* 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 = list1 (tem);
+                         points to the eventual installed lisp directories.
+                         We should not use those now, even if they exist,
+                         so start over from a clean slate.  */
+                      lpath = list1 (tem);
                     }
                 }
               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 is accessible. */
-              tem = Fexpand_file_name (build_string ("leim"),
-                                       Vinstallation_directory);
-              tem1 = Ffile_accessible_directory_p (tem);
-              if (!NILP (tem1))
-                {
-                  if (NILP (Fmember (tem, Vload_path)))
-                    Vload_path = Fcons (tem, Vload_path);
-                }
+                lpath = nconc2 (lpath, dump_path);
 
               /* Add site-lisp under the installation dir, if it exists.  */
               if (!no_site_lisp)
@@ -4253,14 +4250,14 @@ init_lread (void)
                   tem1 = Ffile_accessible_directory_p (tem);
                   if (!NILP (tem1))
                     {
-                      if (NILP (Fmember (tem, Vload_path)))
-                        Vload_path = Fcons (tem, Vload_path);
+                      if (NILP (Fmember (tem, lpath)))
+                        lpath = Fcons (tem, lpath);
                     }
                 }
 
               /* 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.  */
+                 the lisp and site-lisp dirs under that directory.  */
 
               if (NILP (Fequal (Vinstallation_directory, Vsource_directory)))
                 {
@@ -4282,14 +4279,8 @@ init_lread (void)
                       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 (NILP (Fmember (tem, lpath)))
+                        lpath = Fcons (tem, lpath);
 
                       if (!no_site_lisp)
                         {
@@ -4298,47 +4289,113 @@ init_lread (void)
                           tem1 = Ffile_accessible_directory_p (tem);
                           if (!NILP (tem1))
                             {
-                              if (NILP (Fmember (tem, Vload_path)))
-                                Vload_path = Fcons (tem, Vload_path);
+                              if (NILP (Fmember (tem, lpath)))
+                                lpath = Fcons (tem, lpath);
                             }
                         }
                     }
                 } /* 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 ();
+            } /* if Vinstallation_directory */
 
-          /* 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 */
+        } /* if dump_path == Vload_path */
     }
   else                          /* !initialized */
     {
       /* 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
+         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.  */
+      lpath = decode_env_path (0, normal, 0);
+      dump_path = lpath;
     }
-#endif  /* !CANNOT_DUMP */
+#endif /* !CANNOT_DUMP */
+
+  return lpath;
+}
+
+void
+init_lread (void)
+{
+  /* First, set Vload_path.  */
+
+  /* NB: Do not change Vload_path before calling load_path_default,
+     since it may check it against dump_path.
+     (This behavior could be changed.)  */
+
+  /* We explicitly ignore EMACSLOADPATH when dumping.  */
+  if (NILP (Vpurify_flag) && egetenv ("EMACSLOADPATH"))
+    {
+      Lisp_Object elpath = decode_env_path ("EMACSLOADPATH", 0, 1);
+
+      /* Check (non-nil) user-supplied elements.  */
+      load_path_check (elpath);
+
+      /* If no nils in the environment variable, use as-is.
+         Otherwise, replace any nils with the default.  */
+      if (NILP (Fmemq (Qnil, elpath)))
+        {
+          Vload_path = elpath;
+        }
+      else
+        {
+          Lisp_Object elem, default_lpath = load_path_default (0);
+
+          /* Check defaults, before adding site-lisp.  */
+          load_path_check (default_lpath);
+
+          /* Add the site-lisp directories to the front of the default.  */
+          if (!no_site_lisp)
+            {
+              Lisp_Object sitelisp;
+              sitelisp = decode_env_path (0, PATH_SITELOADSEARCH, 0);
+              if (! NILP (sitelisp))
+                default_lpath = nconc2 (sitelisp, default_lpath);
+            }
+
+          Vload_path = Qnil;
+
+          /* Replace nils from EMACSLOADPATH by default.  */
+          while (CONSP (elpath))
+            {
+              Lisp_Object arg[2];
+              elem = XCAR (elpath);
+              elpath = XCDR (elpath);
+              arg[0] = Vload_path;
+              arg[1] = NILP (elem) ? default_lpath : Fcons (elem, Qnil);
+              Vload_path = Fappend (2, arg);
+            }
+        }                       /* Fmemq (Qnil, Vload_path) */
+    }
+  else                          /* Vpurify_flag || !EMACSLOADPATH */
+    {
+#ifdef CANNOT_DUMP
+      bool changed = 0;
+#else
+      bool changed = initialized && NILP (Fequal (dump_path, Vload_path));
+#endif
+
+      Vload_path = load_path_default (changed);
+
+      /* Check before adding 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 (Vload_path);
+
+      /* Add the site-lisp directories at the front, unless the
+         load-path has already been changed.
+         FIXME?  Should we ignore changed here?  */
+      if (initialized && !no_site_lisp && !changed)
+        {
+          Lisp_Object sitelisp;
+          sitelisp = decode_env_path (0, PATH_SITELOADSEARCH, 0);
+          if (! NILP (sitelisp)) Vload_path = nconc2 (sitelisp, Vload_path);
+        }
+    }                           /* !Vpurify_flag && EMACSLOADPATH */
 
   Vvalues = Qnil;
 
@@ -4445,9 +4502,8 @@ were read in.  */);
 
   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).
-Initialized based on EMACSLOADPATH environment variable, if any,
-otherwise to default specified by file `epaths.h' when Emacs was built.  */);
+Each element is a string (directory name) or nil (meaning `default-directory').
+Initialized during startup as described in Info node `(elisp)Library Search'.  */);
 
   DEFVAR_LISP ("load-suffixes", Vload_suffixes,
               doc: /* List of suffixes for (compiled or source) Emacs Lisp files.
@@ -4563,7 +4619,7 @@ and is not meant for users to change.  */);
 You cannot count on them to still be there!  */);
   Vsource_directory
     = Fexpand_file_name (build_string ("../"),
-                        Fcar (decode_env_path (0, PATH_DUMPLOADSEARCH)));
+                        Fcar (decode_env_path (0, PATH_DUMPLOADSEARCH, 0)));
 
   DEFVAR_LISP ("preloaded-file-list", Vpreloaded_file_list,
               doc: /* List of files that were preloaded (when dumping Emacs).  */);