(Fread_file_name): Check type of DEFAULT_FILENAME.
[bpt/emacs.git] / src / lread.c
index 895fb6c..479281c 100644 (file)
@@ -31,7 +31,7 @@ Boston, MA 02111-1307, USA.  */
 #ifndef standalone
 #include "buffer.h"
 #include "charset.h"
-#include <paths.h>
+#include <epaths.h>
 #include "commands.h"
 #include "keyboard.h"
 #include "termhooks.h"
@@ -48,6 +48,10 @@ Boston, MA 02111-1307, USA.  */
 #include "msdos.h"
 #endif
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #ifndef X_OK
 #define X_OK 01
 #endif
@@ -88,6 +92,9 @@ Lisp_Object Vsource_directory;
 /* Search path for files to be loaded. */
 Lisp_Object Vload_path;
 
+/* File name of user's init file.  */
+Lisp_Object Vuser_init_file;
+
 /* This is the user-visible association list that maps features to
    lists of defs in their load files. */
 Lisp_Object Vload_history;
@@ -138,8 +145,7 @@ static int read_from_string_limit;
    that `readchar' has already advanced over.  */
 static int readchar_backlog;
 
-/* This contains the last string skipped with #@, but only on some systems.
-     On other systems we can't put the string here.  */
+/* This contains the last string skipped with #@.  */
 static char *saved_doc_string;
 /* Length of buffer allocated in saved_doc_string.  */
 static int saved_doc_string_size;
@@ -148,6 +154,17 @@ static int saved_doc_string_length;
 /* This is the file position that string came from.  */
 static int saved_doc_string_position;
 
+/* This contains the previous string skipped with #@.
+   We copy it from saved_doc_string when a new string
+   is put in saved_doc_string.  */
+static char *prev_saved_doc_string;
+/* Length of buffer allocated in prev_saved_doc_string.  */
+static int prev_saved_doc_string_size;
+/* Length of actual data in prev_saved_doc_string.  */
+static int prev_saved_doc_string_length;
+/* This is the file position that string came from.  */
+static int prev_saved_doc_string_position;
+
 /* Nonzero means inside a new-style backquote
    with no surrounding parentheses.
    Fread initializes this to zero, so we need not specbind it
@@ -179,14 +196,46 @@ readchar (readcharfun)
       int pt_byte = BUF_PT_BYTE (inbuffer);
       int orig_pt_byte = pt_byte;
 
+      if (readchar_backlog > 0)
+       /* We get the address of the byte just passed,
+          which is the last byte of the character.
+          The other bytes in this character are consecutive with it,
+          because the gap can't be in the middle of a character.  */
+       return *(BUF_BYTE_ADDRESS (inbuffer, BUF_PT_BYTE (inbuffer) - 1)
+                - --readchar_backlog);
+
       if (pt_byte >= BUF_ZV_BYTE (inbuffer))
        return -1;
 
+      readchar_backlog = -1;
+
       if (! NILP (inbuffer->enable_multibyte_characters))
        {
+         unsigned char workbuf[4];
+         unsigned char *str = workbuf;
+         int length;
+
+         /* Fetch the character code from the buffer.  */
          unsigned char *p = BUF_BYTE_ADDRESS (inbuffer, pt_byte);
          BUF_INC_POS (inbuffer, pt_byte);
          c = STRING_CHAR (p, pt_byte - orig_pt_byte);
+
+         /* Find the byte-sequence representation of that character.  */
+         if (SINGLE_BYTE_CHAR_P (c))
+           length = 1, workbuf[0] = c;
+         else
+           length = non_ascii_char_to_string (c, workbuf, &str);
+
+         /* If the bytes for this character in the buffer
+            are not identical with what the character code implies,
+            read the bytes one by one from the buffer.  */
+         if (length != pt_byte - orig_pt_byte
+             || (length == 1 ? *str != *p : bcmp (str, p, length)))
+           {
+             readchar_backlog = pt_byte - orig_pt_byte;
+             c = BUF_FETCH_BYTE (inbuffer, orig_pt_byte);
+             readchar_backlog--;
+           }
        }
       else
        {
@@ -204,14 +253,46 @@ readchar (readcharfun)
       int bytepos = marker_byte_position (readcharfun);
       int orig_bytepos = bytepos;
 
+      if (readchar_backlog > 0)
+       /* We get the address of the byte just passed,
+          which is the last byte of the character.
+          The other bytes in this character are consecutive with it,
+          because the gap can't be in the middle of a character.  */
+       return *(BUF_BYTE_ADDRESS (inbuffer, XMARKER (readcharfun)->bytepos - 1)
+                - --readchar_backlog);
+
       if (bytepos >= BUF_ZV_BYTE (inbuffer))
        return -1;
 
+      readchar_backlog = -1;
+
       if (! NILP (inbuffer->enable_multibyte_characters))
        {
+         unsigned char workbuf[4];
+         unsigned char *str = workbuf;
+         int length;
+
+         /* Fetch the character code from the buffer.  */
          unsigned char *p = BUF_BYTE_ADDRESS (inbuffer, bytepos);
          BUF_INC_POS (inbuffer, bytepos);
          c = STRING_CHAR (p, bytepos - orig_bytepos);
+
+         /* Find the byte-sequence representation of that character.  */
+         if (SINGLE_BYTE_CHAR_P (c))
+           length = 1, workbuf[0] = c;
+         else
+           length = non_ascii_char_to_string (c, workbuf, &str);
+
+         /* If the bytes for this character in the buffer
+            are not identical with what the character code implies,
+            read the bytes one by one from the buffer.  */
+         if (length != bytepos - orig_bytepos
+             || (length == 1 ? *str != *p : bcmp (str, p, length)))
+           {
+             readchar_backlog = bytepos - orig_bytepos;
+             c = BUF_FETCH_BYTE (inbuffer, orig_bytepos);
+             readchar_backlog--;
+           }
        }
       else
        {
@@ -224,6 +305,10 @@ readchar (readcharfun)
 
       return c;
     }
+
+  if (EQ (readcharfun, Qlambda))
+    return read_bytecode_char (0);
+
   if (EQ (readcharfun, Qget_file_char))
     {
       c = getc (instream);
@@ -276,26 +361,36 @@ unreadchar (readcharfun, c)
       struct buffer *b = XBUFFER (readcharfun);
       int bytepos = BUF_PT_BYTE (b);
 
-      BUF_PT (b)--;
-      if (! NILP (b->enable_multibyte_characters))
-       BUF_DEC_POS (b, bytepos);
+      if (readchar_backlog >= 0)
+       readchar_backlog++;
       else
-       bytepos--;
+       {
+         BUF_PT (b)--;
+         if (! NILP (b->enable_multibyte_characters))
+           BUF_DEC_POS (b, bytepos);
+         else
+           bytepos--;
 
-      BUF_PT_BYTE (b) = bytepos;
+         BUF_PT_BYTE (b) = bytepos;
+       }
     }
   else if (MARKERP (readcharfun))
     {
       struct buffer *b = XMARKER (readcharfun)->buffer;
       int bytepos = XMARKER (readcharfun)->bytepos;
 
-      XMARKER (readcharfun)->charpos--;
-      if (! NILP (b->enable_multibyte_characters))
-       BUF_DEC_POS (b, bytepos);
+      if (readchar_backlog >= 0)
+       readchar_backlog++;
       else
-       bytepos--;
+       {
+         XMARKER (readcharfun)->charpos--;
+         if (! NILP (b->enable_multibyte_characters))
+           BUF_DEC_POS (b, bytepos);
+         else
+           bytepos--;
 
-      XMARKER (readcharfun)->bytepos = bytepos;
+         XMARKER (readcharfun)->bytepos = bytepos;
+       }
     }
   else if (STRINGP (readcharfun))
     {
@@ -303,6 +398,8 @@ unreadchar (readcharfun, c)
       read_from_string_index_byte
        = string_char_to_byte (readcharfun, read_from_string_index);
     }
+  else if (EQ (readcharfun, Qlambda))
+    read_bytecode_char (1);
   else if (EQ (readcharfun, Qget_file_char))
     ungetc (c, instream);
   else
@@ -329,11 +426,15 @@ extern Lisp_Object read_char ();
    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
-   character.  */
+   character.
+
+   If INPUT_METHOD is nonzero, we invoke the current input method
+   if the character warrants that.  */
 
 Lisp_Object
-read_filtered_event (no_switch_frame, ascii_required, error_nonascii)
-     int no_switch_frame, ascii_required, error_nonascii;
+read_filtered_event (no_switch_frame, ascii_required, error_nonascii,
+                    input_method)
+     int no_switch_frame, ascii_required, error_nonascii, input_method;
 {
 #ifdef standalone
   return make_number (getchar ());
@@ -344,7 +445,9 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii)
 
   /* Read until we get an acceptable event.  */
  retry:
-  val = read_char (0, 0, 0, Qnil, 0);
+  val = read_char (0, 0, 0,
+                  (input_method ? Qnil : Qt),
+                  0);
 
   if (BUFFERP (val))
     goto retry;
@@ -399,7 +502,7 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii)
 #endif
 }
 
-DEFUN ("read-char", Fread_char, Sread_char, 0, 0, 0,
+DEFUN ("read-char", Fread_char, Sread_char, 0, 2, 0,
   "Read a character from the command input (keyboard or macro).\n\
 It is returned as a number.\n\
 If the user generates an event which is not a character (i.e. a mouse\n\
@@ -407,25 +510,48 @@ click or function key event), `read-char' signals an error.  As an\n\
 exception, switch-frame events are put off until non-ASCII events can\n\
 be read.\n\
 If you want to read non-character events, or ignore them, call\n\
-`read-event' or `read-char-exclusive' instead.")
-  ()
+`read-event' or `read-char-exclusive' instead.\n\
+\n\
+If the optional argument PROMPT is non-nil, display that as a prompt.\n\
+If the optional argument INHERIT-INPUT-METHOD is non-nil and some\n\
+input method is turned on in the current buffer, that input method\n\
+is used for reading a character.")
+  (prompt, inherit_input_method)
+     Lisp_Object prompt, inherit_input_method;
 {
-  return read_filtered_event (1, 1, 1);
+  if (! NILP (prompt))
+    message_with_string ("%s", prompt, 0);
+  return read_filtered_event (1, 1, 1, ! NILP (inherit_input_method));
 }
 
-DEFUN ("read-event", Fread_event, Sread_event, 0, 0, 0,
-  "Read an event object from the input stream.")
-  ()
+DEFUN ("read-event", Fread_event, Sread_event, 0, 2, 0,
+  "Read an event object from the input stream.\n\
+If the optional argument PROMPT is non-nil, display that as a prompt.\n\
+If the optional argument INHERIT-INPUT-METHOD is non-nil and some\n\
+input method is turned on in the current buffer, that input method\n\
+is used for reading a character.")
+  (prompt, inherit_input_method)
+     Lisp_Object prompt, inherit_input_method;
 {
-  return read_filtered_event (0, 0, 0);
+  if (! NILP (prompt))
+    message_with_string ("%s", prompt, 0);
+  return read_filtered_event (0, 0, 0, ! NILP (inherit_input_method));
 }
 
-DEFUN ("read-char-exclusive", Fread_char_exclusive, Sread_char_exclusive, 0, 0, 0,
+DEFUN ("read-char-exclusive", Fread_char_exclusive, Sread_char_exclusive, 0, 2, 0,
   "Read a character from the command input (keyboard or macro).\n\
-It is returned as a number.  Non-character events are ignored.")
-  ()
+It is returned as a number.  Non-character events are ignored.\n\
+\n\
+If the optional argument PROMPT is non-nil, display that as a prompt.\n\
+If the optional argument INHERIT-INPUT-METHOD is non-nil and some\n\
+input method is turned on in the current buffer, that input method\n\
+is used for reading a character.")
+  (prompt, inherit_input_method)
+     Lisp_Object prompt, inherit_input_method;
 {
-  return read_filtered_event (1, 1, 0);
+  if (! NILP (prompt))
+    message_with_string ("%s", prompt, 0);
+  return read_filtered_event (1, 1, 0, ! NILP (inherit_input_method));
 }
 
 DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
@@ -471,8 +597,9 @@ Return t if file exists.")
   /* 1 means we are loading a compiled file.  */
   int compiled = 0;
   Lisp_Object handler;
+  char *fmode = "r";
 #ifdef DOS_NT
-  char *dosmode = "rt";
+  fmode = "rt";
 #endif /* DOS_NT */
 
   CHECK_STRING (file, 0);
@@ -528,15 +655,28 @@ Return t if file exists.")
        return Qnil;
     }
 
-  /* If FD is 0, that means openp found a remote 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)
     {
-      handler = Ffind_file_name_handler (found, Qload);
-      return call5 (handler, Qload, found, noerror, nomessage, Qt);
+      if (NILP (Fequal (found, file)))
+       /* If FOUND is a different file name from FILE,
+          find its handler even if we have already inhibited
+          the `load' operation on FILE.  */
+       handler = Ffind_file_name_handler (found, Qt);
+      else
+       handler = Ffind_file_name_handler (found, Qload);
+      if (! NILP (handler))
+       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[XSTRING (found)->size - 4]),
-            ".elc", 4))
+            ".elc", 4)
+      && fd != 0)
     {
       struct stat s1, s2;
       int result;
@@ -544,7 +684,7 @@ Return t if file exists.")
       compiled = 1;
 
 #ifdef DOS_NT
-      dosmode = "rb";
+      fmode = "rb";
 #endif /* DOS_NT */
       stat ((char *)XSTRING (found)->data, &s1);
       XSTRING (found)->data[XSTRING (found)->size - 1] = 0;
@@ -566,19 +706,20 @@ Return t if file exists.")
       /* We are loading a source file (*.el).  */
       if (!NILP (Vload_source_file_function))
        {
-         close (fd);
+         if (fd != 0)
+           close (fd);
          return call4 (Vload_source_file_function, found, file,
                        NILP (noerror) ? Qnil : Qt,
                        NILP (nomessage) ? Qnil : Qt);
        }
     }
 
-#ifdef DOS_NT
+#ifdef WINDOWSNT
   close (fd);
-  stream = fopen ((char *) XSTRING (found)->data, dosmode);
-#else  /* not DOS_NT */
-  stream = fdopen (fd, "r");
-#endif /* not DOS_NT */
+  stream = fopen ((char *) XSTRING (found)->data, fmode);
+#else  /* not WINDOWSNT */
+  stream = fdopen (fd, fmode);
+#endif /* not WINDOWSNT */
   if (stream == 0)
     {
       close (fd);
@@ -610,7 +751,7 @@ Return t if file exists.")
   load_descriptor_list
     = Fcons (make_number (fileno (stream)), load_descriptor_list);
   load_in_progress++;
-  readevalloop (Qget_file_char, stream, file, Feval, 0, Qnil);
+  readevalloop (Qget_file_char, stream, file, Feval, 0, Qnil, Qnil);
   unbind_to (count, Qnil);
 
   /* Run any load-hooks for this file.  */
@@ -624,6 +765,11 @@ Return t if file exists.")
   saved_doc_string = 0;
   saved_doc_string_size = 0;
 
+  if (prev_saved_doc_string)
+    free (prev_saved_doc_string);
+  prev_saved_doc_string = 0;
+  prev_saved_doc_string_size = 0;
+
   if (!noninteractive && NILP (nomessage))
     {
       if (!compiled)
@@ -852,10 +998,6 @@ build_load_history (stream, source)
   register Lisp_Object tem, tem2;
   register int foundit, loading;
 
-  /* Don't bother recording anything for preloaded files.  */
-  if (!NILP (Vpurify_flag))
-    return;
-
   loading = stream || !NARROWED;
 
   tail = Vload_history;
@@ -927,16 +1069,17 @@ readevalloop_1 (old)
 }
 
 /* UNIBYTE specifies how to set load_convert_to_unibyte
-   for this invocation.  */
+   for this invocation.
+   READFUN, if non-nil, is used instead of `read'.  */
 
 static void
-readevalloop (readcharfun, stream, sourcename, evalfun, printflag, unibyte)
+readevalloop (readcharfun, stream, sourcename, evalfun, printflag, unibyte, readfun)
      Lisp_Object readcharfun;
      FILE *stream;
      Lisp_Object sourcename;
      Lisp_Object (*evalfun) ();
      int printflag;
-     int unibyte;
+     Lisp_Object unibyte, readfun;
 {
   register int c;
   register Lisp_Object val;
@@ -954,7 +1097,7 @@ readevalloop (readcharfun, stream, sourcename, evalfun, printflag, unibyte)
   record_unwind_protect (readevalloop_1, load_convert_to_unibyte ? Qt : Qnil);
   load_convert_to_unibyte = !NILP (unibyte);
 
-  readchar_backlog = 0;
+  readchar_backlog = -1;
 
   GCPRO1 (sourcename);
 
@@ -989,10 +1132,12 @@ readevalloop (readcharfun, stream, sourcename, evalfun, printflag, unibyte)
        {
          UNREAD (c);
          read_objects = Qnil;
-         if (NILP (Vload_read_function))
-           val = read0 (readcharfun);
-         else
+         if (! NILP (readfun))
+           val = call1 (readfun, readcharfun);
+         else if (! NILP (Vload_read_function))
            val = call1 (Vload_read_function, readcharfun);
+         else
+           val = read0 (readcharfun);
        }
 
       val = (*evalfun) (val);
@@ -1049,7 +1194,7 @@ This function preserves the position of point.")
   specbind (Qstandard_output, tem);
   record_unwind_protect (save_excursion_restore, save_excursion_save ());
   BUF_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf)));
-  readevalloop (buf, 0, filename, Feval, !NILP (printflag), unibyte);
+  readevalloop (buf, 0, filename, Feval, !NILP (printflag), unibyte, Qnil);
   unbind_to (count, Qnil);
 
   return Qnil;
@@ -1079,22 +1224,25 @@ point remains at the end of the last character read from the buffer.")
   record_unwind_protect (save_excursion_restore, save_excursion_save ());
   SET_PT (BEGV);
   readevalloop (cbuf, 0, XBUFFER (cbuf)->filename, Feval,
-               !NILP (printflag), Qnil);
+               !NILP (printflag), Qnil, Qnil);
   return unbind_to (count, Qnil);
 }
 #endif
 
-DEFUN ("eval-region", Feval_region, Seval_region, 2, 3, "r",
+DEFUN ("eval-region", Feval_region, Seval_region, 2, 4, "r",
   "Execute the region as Lisp code.\n\
 When called from programs, expects two arguments,\n\
 giving starting and ending indices in the current buffer\n\
 of the text to be executed.\n\
 Programs can pass third argument PRINTFLAG which controls output:\n\
 nil means discard it; anything else is stream for printing it.\n\
+Also the fourth argument READ-FUNCTION, if non-nil, is used\n\
+instead of `read' to read each expression.  It gets one argument\n\
+which is the input stream for reading characters.\n\
 \n\
 This function does not move point.")
-  (start, end, printflag)
-     Lisp_Object start, end, printflag;
+  (start, end, printflag, read_function)
+     Lisp_Object start, end, printflag, read_function;
 {
   int count = specpdl_ptr - specpdl;
   Lisp_Object tem, cbuf;
@@ -1115,7 +1263,7 @@ This function does not move point.")
   Fgoto_char (start);
   Fnarrow_to_region (make_number (BEGV), end);
   readevalloop (cbuf, 0, XBUFFER (cbuf)->filename, Feval,
-               !NILP (printflag), Qnil);
+               !NILP (printflag), Qnil, read_function);
 
   return unbind_to (count, Qnil);
 }
@@ -1142,7 +1290,7 @@ STREAM or the value of `standard-input' may be:\n\
   if (EQ (stream, Qt))
     stream = Qread_char;
 
-  readchar_backlog = 0;
+  readchar_backlog = -1;
   new_backquote_flag = 0;
   read_objects = Qnil;
 
@@ -1175,6 +1323,7 @@ START and END optionally delimit a substring of STRING from which to read;\n\
   else
     {
       CHECK_NUMBER (end, 2);
+      endval = XINT (end);
       if (endval < 0 || endval > XSTRING (string)->size)
        args_out_of_range (string, end);
     }
@@ -1184,6 +1333,7 @@ START and END optionally delimit a substring of STRING from which to read;\n\
   else
     {
       CHECK_NUMBER (start, 1);
+      startval = XINT (start);
       if (startval < 0 || startval > endval)
        args_out_of_range (string, start);
     }
@@ -1438,7 +1588,7 @@ read1 (readcharfun, pch, first_in_list)
       return read_list (0, readcharfun);
 
     case '[':
-      return read_vector (readcharfun);
+      return read_vector (readcharfun, 0);
 
     case ')':
     case ']':
@@ -1455,7 +1605,7 @@ read1 (readcharfun, pch, first_in_list)
          if (c == '[')
            {
              Lisp_Object tmp;
-             tmp = read_vector (readcharfun);
+             tmp = read_vector (readcharfun, 0);
              if (XVECTOR (tmp)->size < CHAR_TABLE_STANDARD_SLOTS
                  || XVECTOR (tmp)->size > CHAR_TABLE_STANDARD_SLOTS + 10)
                error ("Invalid size char-table");
@@ -1469,7 +1619,7 @@ read1 (readcharfun, pch, first_in_list)
              if (c == '[')
                {
                  Lisp_Object tmp;
-                 tmp = read_vector (readcharfun);
+                 tmp = read_vector (readcharfun, 0);
                  if (XVECTOR (tmp)->size != SUB_CHAR_TABLE_STANDARD_SLOTS)
                    error ("Invalid size char-table");
                  XSETCHAR_TABLE (tmp, XCHAR_TABLE (tmp));
@@ -1506,6 +1656,10 @@ read1 (readcharfun, pch, first_in_list)
              val = Fmake_bool_vector (length, Qnil);
              bcopy (XSTRING (tmp)->data, XBOOL_VECTOR (val)->data,
                     size_in_chars);
+             /* Clear the extraneous bits in the last byte.  */
+             if (XINT (length) != size_in_chars * BITS_PER_CHAR)
+               XBOOL_VECTOR (val)->data[size_in_chars - 1]
+                 &= (1 << (XINT (length) % BITS_PER_CHAR)) - 1;
              return val;
            }
          Fsignal (Qinvalid_read_syntax, Fcons (make_string ("#&...", 5),
@@ -1516,7 +1670,7 @@ read1 (readcharfun, pch, first_in_list)
          /* Accept compiled functions at read-time so that we don't have to
             build them using function calls.  */
          Lisp_Object tmp;
-         tmp = read_vector (readcharfun);
+         tmp = read_vector (readcharfun, 1);
          return Fmake_byte_code (XVECTOR (tmp)->size,
                                  XVECTOR (tmp)->contents);
        }
@@ -1571,12 +1725,31 @@ read1 (readcharfun, pch, first_in_list)
          if (c >= 0)
            UNREAD (c);
          
-#ifndef DOS_NT /* I don't know if filepos works right on MSDOS and Windoze.  */
          if (load_force_doc_strings && EQ (readcharfun, Qget_file_char))
            {
              /* If we are supposed to force doc strings into core right now,
                 record the last string that we skipped,
                 and record where in the file it comes from.  */
+
+             /* But first exchange saved_doc_string
+                with prev_saved_doc_string, so we save two strings.  */
+             {
+               char *temp = saved_doc_string;
+               int temp_size = saved_doc_string_size;
+               int temp_pos = saved_doc_string_position;
+               int temp_len = saved_doc_string_length;
+
+               saved_doc_string = prev_saved_doc_string;
+               saved_doc_string_size = prev_saved_doc_string_size;
+               saved_doc_string_position = prev_saved_doc_string_position;
+               saved_doc_string_length = prev_saved_doc_string_length;
+
+               prev_saved_doc_string = temp;
+               prev_saved_doc_string_size = temp_size;
+               prev_saved_doc_string_position = temp_pos;
+               prev_saved_doc_string_length = temp_len;
+             }
+
              if (saved_doc_string_size == 0)
                {
                  saved_doc_string_size = nskip + 100;
@@ -1598,7 +1771,6 @@ read1 (readcharfun, pch, first_in_list)
              saved_doc_string_length = i;
            }
          else
-#endif /* not DOS_NT */
            {
              /* Skip that many characters.  */
              for (i = 0; i < nskip && c >= 0; i++)
@@ -1715,7 +1887,7 @@ read1 (readcharfun, pch, first_in_list)
        return make_number (c);
       }
 
-    case '\"':
+    case '"':
       {
        register char *p = read_buffer;
        register char *end = read_buffer + read_buffer_size;
@@ -1797,13 +1969,10 @@ read1 (readcharfun, pch, first_in_list)
        if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel)
          return make_number (0);
 
-       if (force_singlebyte && force_multibyte)
-         error ("Multibyte and unibyte characters in one string constant");
-
-       if (force_singlebyte)
-         nchars = p - read_buffer;
-       else if (force_multibyte)
+       if (force_multibyte)
          nchars = multibyte_chars_in_text (read_buffer, p - read_buffer);
+       else if (force_singlebyte)
+         nchars = p - read_buffer;
        else if (load_convert_to_unibyte)
          {
            Lisp_Object string;
@@ -1815,10 +1984,13 @@ read1 (readcharfun, pch, first_in_list)
                return Fstring_make_unibyte (string);
              }
          }
-       else if (EQ (readcharfun, Qget_file_char))
+       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.  */
+            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);
        else
          /* In all other cases, if we read these bytes as
@@ -1950,22 +2122,35 @@ read1 (readcharfun, pch, first_in_list)
 #ifdef LISP_FLOAT_TYPE
            if (isfloat_string (read_buffer))
              {
+               /* Compute NaN and infinities using 0.0 in a variable,
+                  to cope with compilers that think they are smarter
+                  than we are.  */
                double zero = 0.0;
-               double value = atof (read_buffer);
-               if (read_buffer[0] == '-' && value == 0.0)
-                 value *= -1.0;
-               /* The only way this can be true, after isfloat_string
+
+               double value;
+
+               /* Negate the value ourselves.  This treats 0, NaNs,
+                  and infinity properly on IEEE floating point hosts,
+                  and works around a common bug where atof ("-0.0")
+                  drops the sign.  */
+               int negative = read_buffer[0] == '-';
+
+               /* The only way p[-1] can be 'F' or 'N', after isfloat_string
                   returns 1, is if the input ends in e+INF or e+NaN.  */
-               if (p[-1] == 'F' || p[-1] == 'N')
+               switch (p[-1])
                  {
-                   if (p[-1] == 'N')
-                     value = zero / zero;
-                   else if (read_buffer[0] == '-')
-                     value = - 1.0 / zero;
-                   else
-                     value = 1.0 / zero;
+                 case 'F':
+                   value = 1.0 / zero;
+                   break;
+                 case 'N':
+                   value = zero / zero;
+                   break;
+                 default:
+                   value = atof (read_buffer + negative);
+                   break;
                  }
-               return make_float (value);
+
+               return make_float (negative ? - value : value);
              }
 #endif
          }
@@ -1990,8 +2175,10 @@ int
 isfloat_string (cp)
      register char *cp;
 {
-  register state;
+  register int state;
   
+  char *start = cp;
+
   state = 0;
   if (*cp == '+' || *cp == '-')
     cp++;
@@ -2027,6 +2214,8 @@ isfloat_string (cp)
       while (*cp >= '0' && *cp <= '9')
        cp++;
     }
+  else if (cp == start)
+    ;
   else if (cp[-1] == '+' && cp[0] == 'I' && cp[1] == 'N' && cp[2] == 'F')
     {
       state |= EXP_INT;
@@ -2048,13 +2237,14 @@ isfloat_string (cp)
 #endif /* LISP_FLOAT_TYPE */
 \f
 static Lisp_Object
-read_vector (readcharfun)
+read_vector (readcharfun, bytecodeflag)
      Lisp_Object readcharfun;
+     int bytecodeflag;
 {
   register int i;
   register int size;
   register Lisp_Object *ptr;
-  register Lisp_Object tem, vector;
+  register Lisp_Object tem, item, vector;
   register struct Lisp_Cons *otem;
   Lisp_Object len;
 
@@ -2062,12 +2252,55 @@ read_vector (readcharfun)
   len = Flength (tem);
   vector = (read_pure ? make_pure_vector (XINT (len)) : Fmake_vector (len, Qnil));
 
-
   size = XVECTOR (vector)->size;
   ptr = XVECTOR (vector)->contents;
   for (i = 0; i < size; i++)
     {
-      ptr[i] = read_pure ? Fpurecopy (Fcar (tem)) : Fcar (tem);
+      item = Fcar (tem);
+      /* If `load-force-doc-strings' is t when reading a lazily-loaded
+        bytecode object, the docstring containing the bytecode and
+        constants values must be treated as unibyte and passed to
+        Fread, to get the actual bytecode string and constants vector.  */
+      if (bytecodeflag && load_force_doc_strings)
+       {
+         if (i == COMPILED_BYTECODE)
+           {
+             if (!STRINGP (item))
+               error ("invalid byte code");
+
+             /* 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;
+             item = Qnil;
+           }
+         else if (i == COMPILED_CONSTANTS)
+           {
+             Lisp_Object bytestr = ptr[COMPILED_CONSTANTS];
+
+             if (NILP (item))
+               {
+                 /* Coerce string to unibyte (like string-as-unibyte,
+                    but without generating extra garbage and
+                    guaranteeing no change in the contents).  */
+                 XSTRING (bytestr)->size = STRING_BYTES (XSTRING (bytestr));
+                 SET_STRING_BYTES (XSTRING (bytestr), -1);
+
+                 item = Fread (bytestr);
+                 if (!CONSP (item))
+                   error ("invalid byte code");
+
+                 otem = XCONS (item);
+                 bytestr = XCONS (item)->car;
+                 item = XCONS (item)->cdr;
+                 free_cons (otem);
+               }
+
+             /* Now handle the bytecode slot.  */
+             ptr[COMPILED_BYTECODE] = read_pure ? Fpurecopy (bytestr) : bytestr;
+           }
+       }
+      ptr[i] = read_pure ? Fpurecopy (item) : item;
       otem = XCONS (tem);
       tem = Fcdr (tem);
       free_cons (otem);
@@ -2165,6 +2398,8 @@ read_list (flag, readcharfun)
                      /* Get a doc string from the file we are loading.
                         If it's in saved_doc_string, get it from there.  */
                      int pos = XINT (XCONS (val)->cdr);
+                     /* Position is negative for user variables.  */
+                     if (pos < 0) pos = -pos;
                      if (pos >= saved_doc_string_position
                          && pos < (saved_doc_string_position
                                    + saved_doc_string_length))
@@ -2196,8 +2431,40 @@ read_list (flag, readcharfun)
                          return make_string (saved_doc_string + start,
                                              to - start);
                        }
+                     /* Look in prev_saved_doc_string the same way.  */
+                     else if (pos >= prev_saved_doc_string_position
+                              && pos < (prev_saved_doc_string_position
+                                        + prev_saved_doc_string_length))
+                       {
+                         int start = pos - prev_saved_doc_string_position;
+                         int from, to;
+
+                         /* Process quoting with ^A,
+                            and find the end of the string,
+                            which is marked with ^_ (037).  */
+                         for (from = start, to = start;
+                              prev_saved_doc_string[from] != 037;)
+                           {
+                             int c = prev_saved_doc_string[from++];
+                             if (c == 1)
+                               {
+                                 c = prev_saved_doc_string[from++];
+                                 if (c == 1)
+                                   prev_saved_doc_string[to++] = c;
+                                 else if (c == '0')
+                                   prev_saved_doc_string[to++] = 0;
+                                 else if (c == '_')
+                                   prev_saved_doc_string[to++] = 037;
+                               }
+                             else
+                               prev_saved_doc_string[to++] = c;
+                           }
+
+                         return make_string (prev_saved_doc_string + start,
+                                             to - start);
+                       }
                      else
-                       return read_doc_string (val);
+                       return get_doc_string (val, 0, 0);
                    }
 
                  return val;
@@ -2307,7 +2574,8 @@ it defaults to the value of `obarray'.")
   sym = Fmake_symbol (string);
   XSYMBOL (sym)->obarray = obarray;
 
-  if (XSTRING (string)->data[0] == ':')
+  if ((XSTRING (string)->data[0] == ':')
+      && EQ (obarray, initial_obarray))
     XSYMBOL (sym)->value = sym;
 
   ptr = &XVECTOR (obarray)->contents[XINT (tem)];
@@ -2879,7 +3147,9 @@ dir_warning (format, dirname)
 
   fprintf (stderr, format, XSTRING (dirname)->data);
   sprintf (buffer, format, XSTRING (dirname)->data);
-  message_dolog (buffer, strlen (buffer), 0, STRING_MULTIBYTE (dirname));
+  /* Don't log the warning before we've initialized!! */
+  if (initialized)
+    message_dolog (buffer, strlen (buffer), 0, STRING_MULTIBYTE (dirname));
 }
 
 void
@@ -2918,7 +3188,7 @@ See documentation of `read' for possible values.");
     "*List of directories to search for files to load.\n\
 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 `paths.h' when Emacs was built.");
+otherwise to default specified by file `epaths.h' when Emacs was built.");
 
   DEFVAR_BOOL ("load-in-progress", &load_in_progress,
     "Non-nil iff inside of `load'.");
@@ -2947,6 +3217,10 @@ or variables, and cons cells `(provide . FEATURE)' and `(require . FEATURE)'.");
     "Full name of file being loaded by `load'.");
   Vload_file_name = Qnil;
 
+  DEFVAR_LISP ("user-init-file", &Vuser_init_file,
+    "File name, including directory, of user's initialization file.");
+  Vuser_init_file = Qnil;
+
   DEFVAR_LISP ("current-load-list", &Vcurrent_load_list,
     "Used for internal purposes by `load'.");
   Vcurrent_load_list = Qnil;