(to_multibyte): Fix computation of new read_buffer_size.
[bpt/emacs.git] / src / lread.c
index 7e4f3d2..be0ecb6 100644 (file)
@@ -1,5 +1,5 @@
 /* Lisp parsing and input streams.
-   Copyright (C) 1985, 86, 87, 88, 89, 93, 94, 95, 97, 98, 1999
+   Copyright (C) 1985, 86, 87, 88, 89, 93, 94, 95, 97, 98, 99, 2000, 2001
       Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -21,14 +21,6 @@ Boston, MA 02111-1307, USA.  */
 
 
 #include <config.h>
-/* The following feature selections should be in config.h, but that
-   causes at best a host of warnings on some systems.  */
-#undef _XOPEN_SOURCE           /* Avoid warnings about redefinition
-                                  in some cases.  */
-#define _XOPEN_SOURCE 500      /* for Unix 98 ftello on GNU */
-#undef __EXTENSIONS__
-#define __EXTENSIONS__         /* Keep Solaris 2.6 happy with the
-                                  above, else things we need are hidden.  */
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -72,7 +64,7 @@ Boston, MA 02111-1307, USA.  */
 #define O_RDONLY 0
 #endif
 
-#ifdef HAVE_FTELLO
+#ifdef HAVE_FSEEKO
 #define file_offset off_t
 #define file_tell ftello
 #else
@@ -80,7 +72,9 @@ Boston, MA 02111-1307, USA.  */
 #define file_tell ftell
 #endif
 
+#ifndef USE_CRT_DLL
 extern int errno;
+#endif
 
 Lisp_Object Qread_char, Qget_file_char, Qstandard_input, Qcurrent_load_list;
 Lisp_Object Qvariable_documentation, Vvalues, Vstandard_input, Vafter_load_alist;
@@ -97,8 +91,8 @@ int load_in_progress;
 /* Directory in which the sources were found.  */
 Lisp_Object Vsource_directory;
 
-/* Search path for files to be loaded. */
-Lisp_Object Vload_path;
+/* Search path and suffixes for files to be loaded. */
+Lisp_Object Vload_path, Vload_suffixes, default_suffixes;
 
 /* File name of user's init file.  */
 Lisp_Object Vuser_init_file;
@@ -181,6 +175,31 @@ static file_offset prev_saved_doc_string_position;
    Fread initializes this to zero, so we need not specbind it
    or worry about what happens to it when there is an error.  */
 static int new_backquote_flag;
+
+/* A list of file names for files being loaded in Fload.  Used to
+   check for recursive loads.  */
+
+static Lisp_Object Vloads_in_progress;
+
+/* Limit of the depth of recursive loads.  */
+
+Lisp_Object Vrecursive_load_depth_limit;
+
+/* Non-zero means load dangerous compiled Lisp files.  */
+
+int load_dangerous_libraries;
+
+/* A regular expression used to detect files compiled with Emacs.  */
+
+static Lisp_Object Vbytecomp_version_regexp;
+
+static void to_multibyte P_ ((char **, char **, int *));
+static void readevalloop P_ ((Lisp_Object, FILE*, Lisp_Object, 
+                             Lisp_Object (*) (), int,
+                             Lisp_Object, Lisp_Object));
+static Lisp_Object load_unwind P_ ((Lisp_Object));
+static Lisp_Object load_descriptor_unwind P_ ((Lisp_Object));
+
 \f
 /* Handle unreading and rereading of characters.
    Write READCHAR to read a character,
@@ -296,12 +315,10 @@ readchar (readcharfun)
     {
       if (read_from_string_index >= read_from_string_limit)
        c = -1;
-      else if (STRING_MULTIBYTE (readcharfun))
+      else
        FETCH_STRING_CHAR_ADVANCE (c, readcharfun,
                                   read_from_string_index,
                                   read_from_string_index_byte);
-      else
-       c = XSTRING (readcharfun)->data[read_from_string_index++];
 
       return c;
     }
@@ -410,6 +427,11 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii,
 {
   register Lisp_Object val, delayed_switch_frame;
 
+#ifdef HAVE_WINDOW_SYSTEM
+  if (display_hourglass_p)
+    cancel_hourglass ();
+#endif
+  
   delayed_switch_frame = Qnil;
 
   /* Read until we get an acceptable event.  */
@@ -467,6 +489,10 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii,
   if (! NILP (delayed_switch_frame))
     unread_switch_frame = delayed_switch_frame;
 
+#ifdef HAVE_WINDOW_SYSTEM
+  if (display_hourglass_p)
+    start_hourglass ();
+#endif
   return val;
 }
 
@@ -530,20 +556,9 @@ DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
   XSETINT (val, getc (instream));
   return val;
 }
-\f
-static void readevalloop ();
-static Lisp_Object load_unwind ();
-static Lisp_Object load_descriptor_unwind ();
-
-/* Non-zero means load dangerous compiled Lisp files.  */
-
-int load_dangerous_libraries;
-
-/* A regular expression used to detect files compiled with Emacs.  */
-
-static Lisp_Object Vbytecomp_version_regexp;
 
 
+\f
 /* Value is non-zero if the file asswociated with file descriptor FD
    is a compiled Lisp file that's safe to load.  Only files compiled
    with Emacs are safe to load.  Files compiled with XEmacs can lead
@@ -581,10 +596,22 @@ safe_to_load_p (fd)
 }
 
 
+/* Callback for record_unwind_protect.  Restore the old load list OLD,
+   after loading a file successfully.  */
+
+static Lisp_Object
+record_load_unwind (old)
+     Lisp_Object old;
+{
+  return Vloads_in_progress = old;
+}
+
+
 DEFUN ("load", Fload, Sload, 1, 5, 0,
   "Execute a file of Lisp code named FILE.\n\
 First try FILE with `.elc' appended, then try with `.el',\n\
- then try FILE unmodified.\n\
+ then try FILE unmodified.  Environment variable references in FILE\n\
+ are replaced with their values by calling `substitute-in-file-name'.\n\
 This function searches the directories in `load-path'.\n\
 If optional second arg NOERROR is non-nil,\n\
  report no error if FILE doesn't exist.\n\
@@ -611,22 +638,28 @@ Return t if file exists.")
   /* 1 means we are loading a compiled file.  */
   int compiled = 0;
   Lisp_Object handler;
+  int safe_p = 1;
   char *fmode = "r";
 #ifdef DOS_NT
   fmode = "rt";
 #endif /* DOS_NT */
-  int safe_p = 1;
 
   CHECK_STRING (file, 0);
 
   /* If file name is magic, call the handler.  */
-  handler = Ffind_file_name_handler (file, Qload);
-  if (!NILP (handler))
-    return call5 (handler, Qload, file, noerror, nomessage, nosuffix);
+  /* This shouldn't be necessary any more now that `openp' handles it right.
+    handler = Ffind_file_name_handler (file, Qload);
+    if (!NILP (handler))
+      return call5 (handler, Qload, file, noerror, nomessage, nosuffix); */
 
   /* Do this after the handler to avoid
      the need to gcpro noerror, nomessage and nosuffix.
-     (Below here, we care only whether they are nil or not.)  */
+     (Below here, we care only whether they are nil or not.)
+     The presence of this call is the result of a historical accident:
+     it used to be in every file-operations and when it got removed
+     everywhere, it accidentally stayed here.  Since then, enough people
+     supposedly have things like (load "$PROJECT/foo.el") in their .emacs
+     that it seemed risky to remove.  */
   file = Fsubstitute_in_file_name (file);
 
   /* Avoid weird lossage with null string as arg,
@@ -634,6 +667,7 @@ Return t if file exists.")
   if (XSTRING (file)->size > 0)
     {
       int size = STRING_BYTES (XSTRING (file));
+      Lisp_Object tmp[2];
 
       GCPRO1 (file);
 
@@ -653,14 +687,16 @@ Return t if file exists.")
        }
 
       fd = openp (Vload_path, file,
-                 (!NILP (nosuffix) ? ""
-                  : ! NILP (must_suffix) ? ".elc.gz:.elc:.el.gz:.el"
-                  : ".elc:.elc.gz:.el.gz:.el:"),
+                 (!NILP (nosuffix) ? Qnil
+                  : !NILP (must_suffix) ? Vload_suffixes
+                  : Fappend (2, (tmp[0] = Vload_suffixes,
+                                 tmp[1] = default_suffixes,
+                                 tmp))),
                  &found, 0);
       UNGCPRO;
     }
 
-  if (fd < 0)
+  if (fd == -1)
     {
       if (NILP (noerror))
        while (1)
@@ -670,11 +706,12 @@ Return t if file exists.")
        return Qnil;
     }
 
+  /* Tell startup.el whether or not we found the user's init file.  */
   if (EQ (Qt, Vuser_init_file))
     Vuser_init_file = found;
 
-  /* If FD is 0, that means openp found a magic file.  */
-  if (fd == 0)
+  /* If FD is -2, that means openp found a magic file.  */
+  if (fd == -2)
     {
       if (NILP (Fequal (found, file)))
        /* If FOUND is a different file name from FILE,
@@ -687,57 +724,81 @@ Return t if file exists.")
        return call5 (handler, Qload, found, noerror, nomessage, Qt);
     }
 
-  /* Load .elc files directly, but not when they are
-     remote and have no handler!  */
-  if (!bcmp (&(XSTRING (found)->data[STRING_BYTES (XSTRING (found)) - 4]),
-            ".elc", 4)
-      && fd != 0)
+  /* Check if we're stuck in a recursive load cycle.
+
+     2000-09-21: It's not possible to just check for the file loaded
+     being a member of Vloads_in_progress.  This fails because of the
+     way the byte compiler currently works; `provide's are not
+     evaluted, see font-lock.el/jit-lock.el as an example.  This
+     leads to a certain amount of ``normal'' recursion.
+
+     Also, just loading a file recursively is not always an error in
+     the general case; the second load may do something different.  */
+  if (INTEGERP (Vrecursive_load_depth_limit)
+      && XINT (Vrecursive_load_depth_limit) > 0)
     {
-      struct stat s1, s2;
-      int result;
+      Lisp_Object len = Flength (Vloads_in_progress);
+      if (XFASTINT (len) > XFASTINT (Vrecursive_load_depth_limit))
+       Fsignal (Qerror, Fcons (build_string ("Recursive load suspected"),
+                               Fcons (found, Vloads_in_progress)));
+      record_unwind_protect (record_load_unwind, Vloads_in_progress);
+      Vloads_in_progress = Fcons (found, Vloads_in_progress);
+    }
 
-      if (!safe_to_load_p (fd))
+  if (!bcmp (&(XSTRING (found)->data[STRING_BYTES (XSTRING (found)) - 4]),
+            ".elc", 4))
+    /* Load .elc files directly, but not when they are
+       remote and have no handler!  */
+    {
+      if (fd != -2)
        {
-         safe_p = 0;
-         if (!load_dangerous_libraries)
-           error ("File `%s' was not compiled in Emacs",
-                  XSTRING (found)->data);
-         else if (!NILP (nomessage))
-           message_with_string ("File `%s' not compiled in Emacs", found, 1);
-       }
+         struct stat s1, s2;
+         int result;
 
-      compiled = 1;
+         if (!safe_to_load_p (fd))
+           {
+             safe_p = 0;
+             if (!load_dangerous_libraries)
+               error ("File `%s' was not compiled in Emacs",
+                      XSTRING (found)->data);
+             else if (!NILP (nomessage))
+               message_with_string ("File `%s' not compiled in Emacs", found, 1);
+           }
+
+         compiled = 1;
 
 #ifdef DOS_NT
-      fmode = "rb";
+         fmode = "rb";
 #endif /* DOS_NT */
-      stat ((char *)XSTRING (found)->data, &s1);
-      XSTRING (found)->data[STRING_BYTES (XSTRING (found)) - 1] = 0;
-      result = stat ((char *)XSTRING (found)->data, &s2);
-      if (result >= 0 && (unsigned) s1.st_mtime < (unsigned) s2.st_mtime)
-       {
-         /* Make the progress messages mention that source is newer.  */
-         newer = 1;
+         stat ((char *)XSTRING (found)->data, &s1);
+         XSTRING (found)->data[STRING_BYTES (XSTRING (found)) - 1] = 0;
+         result = stat ((char *)XSTRING (found)->data, &s2);
+         if (result >= 0 && (unsigned) s1.st_mtime < (unsigned) s2.st_mtime)
+           {
+             /* Make the progress messages mention that source is newer.  */
+             newer = 1;
 
-         /* If we won't print another message, mention this anyway.  */
-         if (! NILP (nomessage))
-           message_with_string ("Source file `%s' newer than byte-compiled file",
-                                found, 1);
+             /* If we won't print another message, mention this anyway.  */
+             if (! NILP (nomessage))
+               message_with_string ("Source file `%s' newer than byte-compiled file",
+                                    found, 1);
+           }
+         XSTRING (found)->data[STRING_BYTES (XSTRING (found)) - 1] = 'c';
        }
-      XSTRING (found)->data[STRING_BYTES (XSTRING (found)) - 1] = 'c';
     }
   else
     {
-    load_source:
-
       /* We are loading a source file (*.el).  */
       if (!NILP (Vload_source_file_function))
        {
-         if (fd != 0)
+         Lisp_Object val;
+
+         if (fd >= 0)
            emacs_close (fd);
-         return call4 (Vload_source_file_function, found, file,
-                       NILP (noerror) ? Qnil : Qt,
-                       NILP (nomessage) ? Qnil : Qt);
+         val = call4 (Vload_source_file_function, found, file,
+                      NILP (noerror) ? Qnil : Qt,
+                      NILP (nomessage) ? Qnil : Qt);
+         return unbind_to (count, val);
        }
     }
 
@@ -813,6 +874,7 @@ Return t if file exists.")
       else /* The typical case; compiled file newer than source file.  */
        message_with_string ("Loading %s...done", file, 1);
     }
+
   return Qt;
 }
 
@@ -866,9 +928,11 @@ complete_filename_p (pathname)
 
 /* Search for a file whose name is STR, looking in directories
    in the Lisp list PATH, and trying suffixes from SUFFIX.
-   SUFFIX is a string containing possible suffixes separated by colons.
    On success, returns a file descriptor.  On failure, returns -1.
 
+   SUFFIXES is a list of strings containing possible suffixes.
+   The empty suffix is automatically added iff the list is empty.
+
    EXEC_ONLY nonzero means don't open the files,
    just look for one that is executable.  In this case,
    returns 1 on success.
@@ -877,14 +941,14 @@ complete_filename_p (pathname)
    the file actually found should be stored as a Lisp string.
    nil is stored there on failure.
 
-   If the file we find is remote, return 0
+   If the file we find is remote, return -2
    but store the found remote file name in *STOREPTR.
    We do not check for remote files if EXEC_ONLY is nonzero.  */
 
 int
-openp (path, str, suffix, storeptr, exec_only)
+openp (path, str, suffixes, storeptr, exec_only)
      Lisp_Object path, str;
-     char *suffix;
+     Lisp_Object suffixes;
      Lisp_Object *storeptr;
      int exec_only;
 {
@@ -896,20 +960,29 @@ openp (path, str, suffix, storeptr, exec_only)
   int want_size;
   Lisp_Object filename;
   struct stat st;
-  struct gcpro gcpro1;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+  Lisp_Object string, tail;
+  int max_suffix_len = 0;
 
-  GCPRO1 (str);
+  for (tail = suffixes; CONSP (tail); tail = XCDR (tail))
+    {
+      CHECK_STRING (XCAR (tail), 0);
+      max_suffix_len = max (max_suffix_len,
+                           STRING_BYTES (XSTRING (XCAR (tail))));
+    }
+
+  string = filename = Qnil;
+  GCPRO5 (str, string, filename, path, suffixes);
+  
   if (storeptr)
     *storeptr = Qnil;
 
   if (complete_filename_p (str))
     absolute = 1;
 
-  for (; !NILP (path); path = Fcdr (path))
+  for (; CONSP (path); path = XCDR (path))
     {
-      char *nsuffix;
-
-      filename = Fexpand_file_name (str, Fcar (path));
+      filename = Fexpand_file_name (str, XCAR (path));
       if (!complete_filename_p (filename))
        /* If there are non-absolute elts in PATH (eg ".") */
        /* Of course, this could conceivably lose if luser sets
@@ -923,17 +996,15 @@ openp (path, str, suffix, storeptr, exec_only)
 
       /* Calculate maximum size of any filename made from
         this path element/specified file name and any possible suffix.  */
-      want_size = strlen (suffix) + STRING_BYTES (XSTRING (filename)) + 1;
+      want_size = max_suffix_len + STRING_BYTES (XSTRING (filename)) + 1;
       if (fn_size < want_size)
        fn = (char *) alloca (fn_size = 100 + want_size);
 
-      nsuffix = suffix;
-
       /* Loop over suffixes.  */
-      while (1)
+      for (tail = NILP (suffixes) ? default_suffixes : suffixes;
+          CONSP (tail); tail = XCDR (tail))
        {
-         char *esuffix = (char *) index (nsuffix, ':');
-         int lsuffix = esuffix ? esuffix - nsuffix : strlen (nsuffix);
+         int lsuffix = STRING_BYTES (XSTRING (XCAR (tail)));
          Lisp_Object handler;
 
          /* Concatenate path element/specified name with the suffix.
@@ -954,23 +1025,24 @@ openp (path, str, suffix, storeptr, exec_only)
            }
 
          if (lsuffix != 0)  /* Bug happens on CCI if lsuffix is 0.  */
-           strncat (fn, nsuffix, lsuffix);
-
+           strncat (fn, XSTRING (XCAR (tail))->data, lsuffix);
+         
          /* Check that the file exists and is not a directory.  */
-         if (absolute)
-           handler = Qnil;
-         else
-           handler = Ffind_file_name_handler (filename, Qfile_exists_p);
-         if (! NILP (handler) && ! exec_only)
+         /* We used to only check for handlers on non-absolute file names:
+               if (absolute)
+                 handler = Qnil;
+               else
+                 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".  */
+         handler = Ffind_file_name_handler (filename, Qfile_exists_p);
+         if (!NILP (handler) && !exec_only)
            {
-             Lisp_Object string;
              int exists;
 
              string = build_string (fn);
-             exists = ! NILP (exec_only ? Ffile_executable_p (string)
-                              : Ffile_readable_p (string));
-             if (exists
-                 && ! NILP (Ffile_directory_p (build_string (fn))))
+             exists = !NILP (Ffile_readable_p (string));
+             if (exists && !NILP (Ffile_directory_p (build_string (fn))))
                exists = 0;
 
              if (exists)
@@ -979,7 +1051,7 @@ openp (path, str, suffix, storeptr, exec_only)
                  if (storeptr)
                    *storeptr = build_string (fn);
                  UNGCPRO;
-                 return 0;
+                 return -2;
                }
            }
          else
@@ -1004,11 +1076,6 @@ openp (path, str, suffix, storeptr, exec_only)
                    }
                }
            }
-
-         /* Advance to next suffix.  */
-         if (esuffix == 0)
-           break;
-         nsuffix += lsuffix + 1;
        }
       if (absolute)
        break;
@@ -1088,7 +1155,8 @@ build_load_history (stream, source)
 }
 
 Lisp_Object
-unreadpure ()  /* Used as unwind-protect function in readevalloop */
+unreadpure (junk) /* Used as unwind-protect function in readevalloop */
+     Lisp_Object junk;
 {
   read_pure = 0;
   return Qnil;
@@ -1102,6 +1170,22 @@ readevalloop_1 (old)
   return Qnil;
 }
 
+/* Signal an `end-of-file' error, if possible with file name
+   information.  */
+
+static void
+end_of_file_error ()
+{
+  Lisp_Object data;
+
+  if (STRINGP (Vload_file_name))
+    data = Fcons (Vload_file_name, Qnil);
+  else
+    data = Qnil;
+
+  Fsignal (Qend_of_file, data);
+}
+
 /* UNIBYTE specifies how to set load_convert_to_unibyte
    for this invocation.
    READFUN, if non-nil, is used instead of `read'.  */
@@ -1120,6 +1204,7 @@ readevalloop (readcharfun, stream, sourcename, evalfun, printflag, unibyte, read
   int count = specpdl_ptr - specpdl;
   struct gcpro gcpro1;
   struct buffer *b = 0;
+  int continue_reading_p;
 
   if (BUFFERP (readcharfun))
     b = XBUFFER (readcharfun);
@@ -1137,7 +1222,8 @@ readevalloop (readcharfun, stream, sourcename, evalfun, printflag, unibyte, read
 
   LOADHIST_ATTACH (sourcename);
 
-  while (1)
+  continue_reading_p = 1;
+  while (continue_reading_p)
     {
       if (b != 0 && NILP (b->name))
        error ("Reading from killed buffer");
@@ -1166,8 +1252,20 @@ readevalloop (readcharfun, stream, sourcename, evalfun, printflag, unibyte, read
        {
          UNREAD (c);
          read_objects = Qnil;
-         if (! NILP (readfun))
-           val = call1 (readfun, readcharfun);
+         if (!NILP (readfun))
+           {
+             val = call1 (readfun, readcharfun);
+
+             /* If READCHARFUN has set point to ZV, we should
+                stop reading, even if the form read sets point
+                to a different value when evaluated.  */
+             if (BUFFERP (readcharfun))
+               {
+                 struct buffer *b = XBUFFER (readcharfun);
+                 if (BUF_PT (b) == BUF_ZV (b))
+                   continue_reading_p = 0;
+               }
+           }
          else if (! NILP (Vload_read_function))
            val = call1 (Vload_read_function, readcharfun);
          else
@@ -1175,6 +1273,7 @@ readevalloop (readcharfun, stream, sourcename, evalfun, printflag, unibyte, read
        }
 
       val = (*evalfun) (val);
+
       if (printflag)
        {
          Vvalues = Fcons (val, Vvalues);
@@ -1315,7 +1414,8 @@ STREAM or the value of `standard-input' may be:\n\
  a function (call it with no arguments for each character,\n\
      call it with a char as argument to push a char back)\n\
  a string (takes text from string, starting at the beginning)\n\
- t (read text line using minibuffer and use it).")
+ t (read text line using minibuffer and use it, or read from\n\
+    standard input in batch mode).")
   (stream)
      Lisp_Object stream;
 {
@@ -1418,13 +1518,20 @@ read_multibyte (c, readcharfun)
      characters.  */
   unsigned char str[MAX_MULTIBYTE_LENGTH];
   int len = 0;
+  int bytes;
 
   str[len++] = c;
   while ((c = READCHAR) >= 0xA0
         && len < MAX_MULTIBYTE_LENGTH)
     str[len++] = c;
   UNREAD (c);
-  return STRING_CHAR (str, len);
+  if (UNIBYTE_STR_AS_MULTIBYTE_P (str, len, bytes))
+    return STRING_CHAR (str, len);
+  /* The byte sequence is not valid as multibyte.  Unread all bytes
+     but the first one, and return the first byte.  */
+  while (--len > 0)
+    UNREAD (str[len]);
+  return str[0];
 }
 
 /* Read a \-escape sequence, assuming we already read the `\'.  */
@@ -1608,7 +1715,8 @@ read_integer (readcharfun, radix)
      Lisp_Object readcharfun;
      int radix;
 {
-  int number, ndigits, invalid_p, c, sign;
+  int ndigits = 0, invalid_p, c, sign = 0;
+  EMACS_INT number = 0;
 
   if (radix < 2 || radix > 36)
     invalid_p = 1;
@@ -1662,6 +1770,43 @@ read_integer (readcharfun, radix)
 }
 
 
+/* Convert unibyte text in read_buffer to multibyte.
+
+   Initially, *P is a pointer after the end of the unibyte text, and
+   the pointer *END points after the end of read_buffer.
+
+   If read_buffer doesn't have enough room to hold the result
+   of the conversion, reallocate it and adjust *P and *END.
+
+   At the end, make *P point after the result of the conversion, and
+   return in *NCHARS the number of characters in the converted
+   text.  */
+
+static void
+to_multibyte (p, end, nchars)
+     char **p, **end;
+     int *nchars;
+{
+  int nbytes;
+
+  parse_str_as_multibyte (read_buffer, *p - read_buffer, &nbytes, nchars);
+  if (read_buffer_size < 2 * nbytes)
+    {
+      int offset = *p - read_buffer;
+      read_buffer_size = 2 * max (read_buffer_size, nbytes);
+      read_buffer = (char *) xrealloc (read_buffer, read_buffer_size);
+      *p = read_buffer + offset;
+      *end = read_buffer + read_buffer_size;
+    }
+
+  if (nbytes != *nchars)
+    nbytes = str_as_multibyte (read_buffer, read_buffer_size,
+                              *p - read_buffer, nchars);
+  
+  *p = read_buffer + nbytes;
+}
+
+
 /* If the next token is ')' or ']' or '.', we store that character
    in *PCH and the return value is not interesting.  Else, we store
    zero in *PCH and we read and return one lisp object.
@@ -1682,7 +1827,8 @@ read1 (readcharfun, pch, first_in_list)
  retry:
 
   c = READCHAR;
-  if (c < 0) return Fsignal (Qend_of_file, Qnil);
+  if (c < 0)
+    end_of_file_error ();
 
   switch (c)
     {
@@ -1793,6 +1939,7 @@ read1 (readcharfun, pch, first_in_list)
              Lisp_Object beg, end, plist;
 
              beg = read1 (readcharfun, &ch, 0);
+             end = plist = Qnil;
              if (ch == ')')
                break;
              if (ch == 0)
@@ -2000,7 +2147,8 @@ read1 (readcharfun, pch, first_in_list)
     case '?':
       {
        c = READCHAR;
-       if (c < 0) return Fsignal (Qend_of_file, Qnil);
+       if (c < 0)
+         end_of_file_error ();
 
        if (c == '\\')
          c = read_escape (readcharfun, 0);
@@ -2012,8 +2160,8 @@ read1 (readcharfun, pch, first_in_list)
 
     case '"':
       {
-       register char *p = read_buffer;
-       register char *end = read_buffer + read_buffer_size;
+       char *p = read_buffer;
+       char *end = read_buffer + read_buffer_size;
        register int c;
        /* Nonzero if we saw an escape sequence specifying
           a multibyte character.  */
@@ -2029,9 +2177,10 @@ read1 (readcharfun, pch, first_in_list)
          {
            if (end - p < MAX_MULTIBYTE_LENGTH)
              {
-               char *new = (char *) xrealloc (read_buffer, read_buffer_size *= 2);
-               p += new - read_buffer;
-               read_buffer += new - read_buffer;
+               int offset = p - read_buffer;
+               read_buffer = (char *) xrealloc (read_buffer,
+                                                read_buffer_size *= 2);
+               p = read_buffer + offset;
                end = read_buffer + read_buffer_size;
              }
 
@@ -2088,7 +2237,7 @@ read1 (readcharfun, pch, first_in_list)
              }
          }
        if (c < 0)
-         return Fsignal (Qend_of_file, Qnil);
+         end_of_file_error ();
 
        /* If purifying, and string starts with \ newline,
           return zero instead.  This is for doc strings
@@ -2097,13 +2246,13 @@ read1 (readcharfun, pch, first_in_list)
          return make_number (0);
 
        if (force_multibyte)
-         nchars = multibyte_chars_in_text (read_buffer, p - read_buffer);
+         to_multibyte (&p, &end, &nchars);
        else if (force_singlebyte)
          nchars = p - read_buffer;
        else if (load_convert_to_unibyte)
          {
            Lisp_Object string;
-           nchars = multibyte_chars_in_text (read_buffer, p - read_buffer);
+           to_multibyte (&p, &end, &nchars);
            if (p - read_buffer != nchars)
              {
                string = make_multibyte_string (read_buffer, nchars,
@@ -2113,12 +2262,14 @@ read1 (readcharfun, pch, first_in_list)
          }
        else if (EQ (readcharfun, Qget_file_char)
                 || EQ (readcharfun, Qlambda))
-         /* Nowadays, reading directly from a file
-            is used only for compiled Emacs Lisp files,
-            and those always use the Emacs internal encoding.
-            Meanwhile, Qlambda is used for reading dynamic byte code
-            (compiled with byte-compile-dynamic = t).  */
-         nchars = multibyte_chars_in_text (read_buffer, p - read_buffer);
+         {
+           /* Nowadays, reading directly from a file is used only for
+              compiled Emacs Lisp files, and those always use the
+              Emacs internal encoding.  Meanwhile, Qlambda is used
+              for reading dynamic byte code (compiled with
+              byte-compile-dynamic = t).  */
+           to_multibyte (&p, &end, &nchars);
+         }
        else
          /* In all other cases, if we read these bytes as
             separate characters, treat them as separate characters now.  */
@@ -2135,13 +2286,11 @@ read1 (readcharfun, pch, first_in_list)
 
     case '.':
       {
-       /* If a period is followed by a number, then we should read it
-          as a floating point number.  Otherwise, it denotes a dotted
-          pair.  */
        int next_char = READCHAR;
        UNREAD (next_char);
 
-       if (! (next_char >= '0' && next_char <= '9'))
+       if (next_char <= 040
+           || index ("\"'`,(", next_char))
          {
            *pch = c;
            return Qnil;
@@ -2155,28 +2304,31 @@ read1 (readcharfun, pch, first_in_list)
     default_label:
       if (c <= 040) goto retry;
       {
-       register char *p = read_buffer;
+       char *p = read_buffer;
        int quoted = 0;
 
        {
-         register char *end = read_buffer + read_buffer_size;
+         char *end = read_buffer + read_buffer_size;
 
          while (c > 040
-                && !(c == '\"' || c == '\'' || c == ';' || c == '?'
+                && !(c == '\"' || c == '\'' || c == ';'
                      || c == '(' || c == ')'
-                     || c == '[' || c == ']' || c == '#'
-                     ))
+                     || c == '[' || c == ']' || c == '#'))
            {
              if (end - p < MAX_MULTIBYTE_LENGTH)
                {
-                 register char *new = (char *) xrealloc (read_buffer, read_buffer_size *= 2);
-                 p += new - read_buffer;
-                 read_buffer += new - read_buffer;
+                 int offset = p - read_buffer;
+                 read_buffer = (char *) xrealloc (read_buffer,
+                                                  read_buffer_size *= 2);
+                 p = read_buffer + offset;
                  end = read_buffer + read_buffer_size;
                }
+             
              if (c == '\\')
                {
                  c = READCHAR;
+                 if (c == -1)
+                   end_of_file_error ();
                  quoted = 1;
                }
 
@@ -2190,10 +2342,11 @@ read1 (readcharfun, pch, first_in_list)
 
          if (p == end)
            {
-             char *new = (char *) xrealloc (read_buffer, read_buffer_size *= 2);
-             p += new - read_buffer;
-             read_buffer += new - read_buffer;
-/*           end = read_buffer + read_buffer_size;  */
+             int offset = p - read_buffer;
+             read_buffer = (char *) xrealloc (read_buffer,
+                                              read_buffer_size *= 2);
+             p = read_buffer + offset;
+             end = read_buffer + read_buffer_size;
            }
          *p = 0;
          if (c >= 0)
@@ -2337,7 +2490,7 @@ substitute_object_recurse (object, placeholder, subtree)
     case Lisp_Vectorlike:
       {
        int i;
-       int length = Flength(subtree);
+       int length = XINT (Flength(subtree));
        for (i = 0; i < length; i++)
          {
            Lisp_Object idx = make_number (i);
@@ -2350,22 +2503,22 @@ substitute_object_recurse (object, placeholder, subtree)
     case Lisp_Cons:
       {
        SUBSTITUTE (Fcar_safe (subtree),
-                   Fsetcar (subtree, true_value)); 
+                   Fsetcar (subtree, true_value));
        SUBSTITUTE (Fcdr_safe (subtree),
-                   Fsetcdr (subtree, true_value)); 
+                   Fsetcdr (subtree, true_value));
        return subtree;
       }
 
     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 = XSTRING (subtree)->intervals;
        Lisp_Object arg           = Fcons (object, placeholder);
           
-       traverse_intervals (root_interval, 1, 0,
-                           &substitute_in_interval, arg); 
+       traverse_intervals_noorder (root_interval,
+                                   &substitute_in_interval, arg);
 
        return subtree;
       }
@@ -2796,11 +2949,18 @@ it defaults to the value of `obarray'.")
   if (!NILP (Vpurify_flag))
     string = Fpurecopy (string);
   sym = Fmake_symbol (string);
-  XSYMBOL (sym)->obarray = obarray;
+
+  if (EQ (obarray, initial_obarray))
+    XSYMBOL (sym)->interned = SYMBOL_INTERNED_IN_INITIAL_OBARRAY;
+  else
+    XSYMBOL (sym)->interned = SYMBOL_INTERNED;
 
   if ((XSTRING (string)->data[0] == ':')
       && EQ (obarray, initial_obarray))
-    XSYMBOL (sym)->value = sym;
+    {
+      XSYMBOL (sym)->constant = 1;
+      XSYMBOL (sym)->value = sym;
+    }
 
   ptr = &XVECTOR (obarray)->contents[XINT (tem)];
   if (SYMBOLP (*ptr))
@@ -2873,7 +3033,9 @@ OBARRAY defaults to the value of the variable `obarray'.")
   if (SYMBOLP (name) && !EQ (name, tem))
     return Qnil;
 
-  XSYMBOL (tem)->obarray = Qnil;
+  XSYMBOL (tem)->interned = SYMBOL_UNINTERNED;
+  XSYMBOL (tem)->constant = 0;
+  XSYMBOL (tem)->indirect_variable = 0;
 
   hash = oblookup_last_bucket_number;
 
@@ -3030,7 +3192,9 @@ init_obarray ()
   initial_obarray = Vobarray;
   staticpro (&initial_obarray);
   /* Intern nil in the obarray */
-  XSYMBOL (Qnil)->obarray = Vobarray;
+  XSYMBOL (Qnil)->interned = SYMBOL_INTERNED_IN_INITIAL_OBARRAY;
+  XSYMBOL (Qnil)->constant = 1;
+  
   /* These locals are to kludge around a pyramid compiler bug. */
   hash = hash_string ("nil", 3);
   /* Separate statement here to avoid VAXC bug. */
@@ -3047,6 +3211,7 @@ init_obarray ()
   XSYMBOL (Qnil)->value = Qnil;
   XSYMBOL (Qnil)->plist = Qnil;
   XSYMBOL (Qt)->value = Qt;
+  XSYMBOL (Qt)->constant = 1;
 
   /* Qt is correct even if CANNOT_DUMP.  loadup.el will set to nil at end.  */
   Vpurify_flag = Qt;
@@ -3092,7 +3257,7 @@ defvar_int (namestring, address)
   val = allocate_misc ();
   XMISCTYPE (val) = Lisp_Misc_Intfwd;
   XINTFWD (val)->intvar = address;
-  XSYMBOL (sym)->value = val;
+  SET_SYMBOL_VALUE (sym, val);
 }
 
 /* Similar but define a variable whose value is T if address contains 1,
@@ -3107,7 +3272,7 @@ defvar_bool (namestring, address)
   val = allocate_misc ();
   XMISCTYPE (val) = Lisp_Misc_Boolfwd;
   XBOOLFWD (val)->boolvar = address;
-  XSYMBOL (sym)->value = val;
+  SET_SYMBOL_VALUE (sym, val);
   Vbyte_boolean_vars = Fcons (sym, Vbyte_boolean_vars);
 }
 
@@ -3126,7 +3291,7 @@ defvar_lisp_nopro (namestring, address)
   val = allocate_misc ();
   XMISCTYPE (val) = Lisp_Misc_Objfwd;
   XOBJFWD (val)->objvar = address;
-  XSYMBOL (sym)->value = val;
+  SET_SYMBOL_VALUE (sym, val);
 }
 
 void
@@ -3159,10 +3324,11 @@ defvar_per_buffer (namestring, address, type, doc)
 
   XMISCTYPE (val) = Lisp_Misc_Buffer_Objfwd;
   XBUFFER_OBJFWD (val)->offset = offset;
-  XSYMBOL (sym)->value = val;
-  *(Lisp_Object *)(offset + (char *)&buffer_local_symbols) = sym;
-  *(Lisp_Object *)(offset + (char *)&buffer_local_types) = type;
-  if (XINT (*(Lisp_Object *)(offset + (char *)&buffer_local_flags)) == 0)
+  SET_SYMBOL_VALUE (sym, val);
+  PER_BUFFER_SYMBOL (offset) = sym;
+  PER_BUFFER_TYPE (offset) = type;
+  
+  if (PER_BUFFER_IDX (offset) == 0)
     /* Did a DEFVAR_PER_BUFFER without initializing the corresponding
        slot of buffer_local_flags */
     abort ();
@@ -3182,7 +3348,7 @@ defvar_kboard (namestring, offset)
   val = allocate_misc ();
   XMISCTYPE (val) = Lisp_Misc_Kboard_Objfwd;
   XKBOARD_OBJFWD (val)->offset = offset;
-  XSYMBOL (sym)->value = val;
+  SET_SYMBOL_VALUE (sym, val);
 }
 \f
 /* Record the value of load-path used at the start of dumping
@@ -3355,6 +3521,7 @@ init_lread ()
   load_descriptor_list = Qnil;
 
   Vstandard_input = Qt;
+  Vloads_in_progress = Qnil;
 }
 
 /* Print a warning, using format string FORMAT, that directory DIRNAME
@@ -3413,6 +3580,15 @@ Each element is a string (directory name) or nil (try default directory).\n\
 Initialized based on EMACSLOADPATH environment variable, if any,\n\
 otherwise to default specified by file `epaths.h' when Emacs was built.");
 
+  DEFVAR_LISP ("load-suffixes", &Vload_suffixes,
+    "*List of suffixes to try for files to load.\n\
+This list should not include the empty string.");
+  Vload_suffixes = Fcons (build_string (".elc"),
+                         Fcons (build_string (".el"), Qnil));
+  /* We don't use empty_string because it's not initialized yet.  */
+  default_suffixes = Fcons (build_string (""), Qnil);
+  staticpro (&default_suffixes);
+
   DEFVAR_BOOL ("load-in-progress", &load_in_progress,
     "Non-nil iff inside of `load'.");
 
@@ -3424,7 +3600,9 @@ the FORMS in the corresponding element are executed at the end of loading.\n\n\
 FILENAME must match exactly!  Normally FILENAME is the name of a library,\n\
 with no directory specified, since that is how `load' is normally called.\n\
 An error in FORMS does not undo the load,\n\
-but does prevent execution of the rest of the FORMS.");
+but does prevent execution of the rest of the FORMS.\n\
+FILENAME can also be a symbol (a feature) and FORMS are then executed\n\
+when the corresponding call to `provide' is made.");
   Vafter_load_alist = Qnil;
 
   DEFVAR_LISP ("load-history", &Vload_history,
@@ -3433,7 +3611,8 @@ Each alist element is a list that starts with a file name,\n\
 except for one element (optional) that starts with nil and describes\n\
 definitions evaluated from buffers not visiting files.\n\
 The remaining elements of each list are symbols defined as functions\n\
-or variables, and cons cells `(provide . FEATURE)' and `(require . FEATURE)'.");
+or variables, and cons cells `(provide . FEATURE)', `(require . FEATURE)',\n\
+and `(autoload . SYMBOL)'.");
   Vload_history = Qnil;
 
   DEFVAR_LISP ("load-file-name", &Vload_file_name,
@@ -3471,9 +3650,9 @@ This is useful when the file being loaded is a temporary copy.");
   load_force_doc_strings = 0;
 
   DEFVAR_BOOL ("load-convert-to-unibyte", &load_convert_to_unibyte,
-     "Non-nil means `load' converts strings to unibyte whenever possible.\n\
-This is normally used in `load-with-code-conversion'\n\
-for loading non-compiled files.");
+     "Non-nil means `read' converts strings to unibyte whenever possible.\n\
+This is normally bound by `load' and `eval-buffer' to control `read',\n\
+and is not meant for users to change.");
   load_convert_to_unibyte = 0;
 
   DEFVAR_LISP ("source-directory", &Vsource_directory,
@@ -3498,8 +3677,20 @@ incompatible byte codes can make Emacs crash when it tries to execute\n\
 them.");
   load_dangerous_libraries = 0;
 
-  Vbytecomp_version_regexp = build_string ("^;;;.in Emacs version");
-  staticpro (&Vbytecomp_version_regexp);
+  DEFVAR_LISP ("bytecomp-version-regexp", &Vbytecomp_version_regexp,
+     "Regular expression matching safe to load compiled Lisp files.\n\
+When Emacs loads a compiled Lisp file, it reads the first 512 bytes\n\
+from the file, and matches them against this regular expression.\n\
+When the regular expression matches, the file is considered to be safe\n\
+to load.  See also `load-dangerous-libraries'.");
+  Vbytecomp_version_regexp
+    = build_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
+
+  DEFVAR_LISP ("recursive-load-depth-limit", &Vrecursive_load_depth_limit,
+    "Limit for depth of recursive loads.\n\
+Value should be either an integer > 0 specifying the limit, or nil for\n\
+no limit.");
+  Vrecursive_load_depth_limit = make_number (50);
 
   /* Vsource_directory was initialized in init_lread.  */
 
@@ -3548,4 +3739,6 @@ them.");
   read_objects = Qnil;
   staticpro (&seen_list);
   
+  Vloads_in_progress = Qnil;
+  staticpro (&Vloads_in_progress);
 }