(X_IO_BUG): Defined.
[bpt/emacs.git] / src / lread.c
index aa21171..2ee1947 100644 (file)
@@ -1,6 +1,6 @@
 /* Lisp parsing and input streams.
-   Copyright (C) 1985, 1986, 1987, 1988, 1989,
-   1992 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1989, 
+   1993, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -24,13 +24,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <ctype.h>
-#undef NULL
-#include "config.h"
+#include <config.h>
 #include "lisp.h"
 
 #ifndef standalone
 #include "buffer.h"
-#include "paths.h"
+#include <paths.h>
 #include "commands.h"
 #include "keyboard.h"
 #include "termhooks.h"
@@ -48,12 +47,21 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #ifdef STDC_HEADERS
 #include <stdlib.h>
 #endif
+
+#ifdef MSDOS
+#include "msdos.h"
+/* These are redefined (correctly, but differently) in values.h.  */
+#undef INTBITS
+#undef LONGBITS
+#undef SHORTBITS
+#endif
+
 #include <math.h>
 #endif /* LISP_FLOAT_TYPE */
 
-Lisp_Object Qread_char, Qget_file_char, Qstandard_input;
+Lisp_Object Qread_char, Qget_file_char, Qstandard_input, Qcurrent_load_list;
 Lisp_Object Qvariable_documentation, Vvalues, Vstandard_input, Vafter_load_alist;
-Lisp_Object Qascii_character;
+Lisp_Object Qascii_character, Qload;
 
 extern Lisp_Object Qevent_symbol_element_mask;
 
@@ -70,6 +78,9 @@ Lisp_Object Vload_history;
 /* This is useud to build the load history. */
 Lisp_Object Vcurrent_load_list;
 
+/* List of descriptors now open for Fload.  */
+static Lisp_Object load_descriptor_list;
+
 /* File for get_file_char to read from.  Use by load */
 static FILE *instream;
 
@@ -152,7 +163,11 @@ unreadchar (readcharfun, c)
      Lisp_Object readcharfun;
      int c;
 {
-  if (XTYPE (readcharfun) == Lisp_Buffer)
+  if (c == -1)
+    /* Don't back up the pointer if we're unreading the end-of-input mark,
+       since readchar didn't advance it when we read it.  */
+    ;
+  else if (XTYPE (readcharfun) == Lisp_Buffer)
     {
       if (XBUFFER (readcharfun) == current_buffer)
        SET_PT (point - 1);
@@ -196,13 +211,17 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii)
 #ifdef standalone
   return make_number (getchar ());
 #else
-  register Lisp_Object val;
-  register Lisp_Object delayed_switch_frame = Qnil;
+  register Lisp_Object val, delayed_switch_frame;
+
+  delayed_switch_frame = Qnil;
 
   /* Read until we get an acceptable event.  */
  retry:
   val = read_char (0, 0, 0, Qnil, 0);
 
+  if (XTYPE (val) == Lisp_Buffer)
+    goto retry;
+
   /* switch-frame events are put off until after the next ASCII
      character.  This is better than signalling an error just because
      the last characters were typed to a separate minibuffer frame,
@@ -238,7 +257,7 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii)
        {
          if (error_nonascii)
            {
-             unread_command_events = Fcons (val, Qnil);
+             Vunread_command_events = Fcons (val, Qnil);
              error ("Non-character input-event");
            }
          else
@@ -293,6 +312,7 @@ DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
 \f
 static void readevalloop ();
 static Lisp_Object load_unwind ();
+static Lisp_Object load_descriptor_unwind ();
 
 DEFUN ("load", Fload, Sload, 1, 4, 0,
   "Execute a file of Lisp code named FILE.\n\
@@ -319,16 +339,27 @@ Return t if file exists.")
   Lisp_Object found;
   /* 1 means inhibit the message at the beginning.  */
   int nomessage1 = 0;
+  Lisp_Object handler;
+#ifdef MSDOS
+  char *dosmode = "rt";
+#endif
 
   CHECK_STRING (str, 0);
   str = Fsubstitute_in_file_name (str);
 
+  /* If file name is magic, call the handler.  */
+  handler = Ffind_file_name_handler (str, Qload);
+  if (!NILP (handler))
+    return call5 (handler, Qload, str, noerror, nomessage, nosuffix);
+
   /* Avoid weird lossage with null string as arg,
      since it would try to load a directory as a Lisp file */
   if (XSTRING (str)->size > 0)
     {
+      GCPRO1 (str);
       fd = openp (Vload_path, str, !NILP (nosuffix) ? "" : ".elc:.el:",
                  &found, 0);
+      UNGCPRO;
     }
 
   if (fd < 0)
@@ -347,9 +378,12 @@ Return t if file exists.")
       struct stat s1, s2;
       int result;
 
-      stat (XSTRING (found)->data, &s1);
+#ifdef MSDOS
+      dosmode = "rb";
+#endif
+      stat ((char *)XSTRING (found)->data, &s1);
       XSTRING (found)->data[XSTRING (found)->size - 1] = 0;
-      result = stat (XSTRING (found)->data, &s2);
+      result = stat ((char *)XSTRING (found)->data, &s2);
       if (result >= 0 && (unsigned) s1.st_mtime < (unsigned) s2.st_mtime)
        {
          message ("Source file `%s' newer than byte-compiled file",
@@ -361,7 +395,12 @@ Return t if file exists.")
       XSTRING (found)->data[XSTRING (found)->size - 1] = 'c';
     }
 
+#ifdef MSDOS
+  close (fd);
+  stream = fopen ((char *) XSTRING (found)->data, dosmode);
+#else
   stream = fdopen (fd, "r");
+#endif
   if (stream == 0)
     {
       close (fd);
@@ -379,6 +418,9 @@ Return t if file exists.")
   *ptr = stream;
   XSET (lispstream, Lisp_Internal_Stream, (int) ptr);
   record_unwind_protect (load_unwind, lispstream);
+  record_unwind_protect (load_descriptor_unwind, load_descriptor_list);
+  load_descriptor_list
+    = Fcons (make_number (fileno (stream)), load_descriptor_list);
   load_in_progress++;
   readevalloop (Qget_file_char, stream, str, Feval, 0);
   unbind_to (count, Qnil);
@@ -404,6 +446,23 @@ load_unwind (stream)  /* used as unwind-protect function in load */
   return Qnil;
 }
 
+static Lisp_Object
+load_descriptor_unwind (oldlist)
+     Lisp_Object oldlist;
+{
+  load_descriptor_list = oldlist;
+}
+
+/* Close all descriptors in use for Floads.
+   This is used when starting a subprocess.  */
+
+void
+close_load_descs ()
+{
+  Lisp_Object tail;
+  for (tail = load_descriptor_list; !NILP (tail); tail = XCONS (tail)->cdr)
+    close (XFASTINT (XCONS (tail)->car));
+}
 \f
 static int
 complete_filename_p (pathname)
@@ -417,6 +476,9 @@ complete_filename_p (pathname)
 #ifdef VMS
          || index (s, ':')
 #endif /* VMS */
+#ifdef MSDOS   /* MW, May 1993 */
+         || (s[0] != '\0' && s[1] == ':' && s[2] == '/')
+#endif
          );
 }
 
@@ -448,7 +510,9 @@ openp (path, str, suffix, storeptr, exec_only)
   int want_size;
   register Lisp_Object filename;
   struct stat st;
+  struct gcpro gcpro1;
 
+  GCPRO1 (str);
   if (storeptr)
     *storeptr = Qnil;
 
@@ -506,7 +570,7 @@ openp (path, str, suffix, storeptr, exec_only)
                  /* We succeeded; return this descriptor and filename.  */
                  if (storeptr)
                    *storeptr = build_string (fn);
-                 return fd;
+                 RETURN_UNGCPRO (fd);
                }
            }
 
@@ -515,10 +579,11 @@ openp (path, str, suffix, storeptr, exec_only)
            break;
          nsuffix += lsuffix + 1;
        }
-      if (absolute) return -1;
+      if (absolute)
+       RETURN_UNGCPRO (-1);
     }
 
-  return -1;
+  RETURN_UNGCPRO (-1);
 }
 
 \f
@@ -535,6 +600,10 @@ 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;
@@ -582,12 +651,12 @@ build_load_history (stream, source)
       QUIT;
     }
 
-      /* If we're loading, cons the new assoc onto the front of load-history,
-        the most-recently-loaded position.  Also do this if we didn't find
-        an existing member for the current source.  */
-      if (loading || !foundit)
-         Vload_history = Fcons (Fnreverse(Vcurrent_load_list),
-                                Vload_history);
+  /* If we're loading, cons the new assoc onto the front of load-history,
+     the most-recently-loaded position.  Also do this if we didn't find
+     an existing member for the current source.  */
+  if (loading || !foundit)
+    Vload_history = Fcons (Fnreverse (Vcurrent_load_list),
+                          Vload_history);
 }
 
 Lisp_Object
@@ -607,20 +676,27 @@ readevalloop (readcharfun, stream, sourcename, evalfun, printflag)
 {
   register int c;
   register Lisp_Object val;
-  Lisp_Object oldlist;
   int count = specpdl_ptr - specpdl;
-  struct gcpro gcpro1, gcpro2;
+  struct gcpro gcpro1;
+  struct buffer *b = 0;
+
+  if (BUFFERP (readcharfun))
+    b = XBUFFER (readcharfun);
+  else if (MARKERP (readcharfun))
+    b = XMARKER (readcharfun)->buffer;
 
   specbind (Qstandard_input, readcharfun);
+  specbind (Qcurrent_load_list, Qnil);
 
-  oldlist = Vcurrent_load_list;
-  GCPRO2 (sourcename, oldlist);
+  GCPRO1 (sourcename);
 
-  Vcurrent_load_list = Qnil;
   LOADHIST_ATTACH (sourcename);
 
   while (1)
     {
+      if (b != 0 && NILP (b->name))
+       error ("Reading from killed buffer");
+
       instream = stream;
       c = READCHAR;
       if (c == ';')
@@ -655,8 +731,6 @@ readevalloop (readcharfun, stream, sourcename, evalfun, printflag)
     }
 
   build_load_history (stream, sourcename);
-
-  Vcurrent_load_list = oldlist;
   UNGCPRO;
 
   unbind_to (count, Qnil);
@@ -1139,11 +1213,21 @@ read1 (readcharfun)
                if (p == read_buffer)
                  cancel = 1;
              }
-           else if (c & CHAR_META)
-             /* Move the meta bit to the right place for a string.  */
-             *p++ = (c & ~CHAR_META) | 0x80;
            else
-             *p++ = c;
+             {
+               /* Allow `\C- ' and `\C-?'.  */
+               if (c == (CHAR_CTL | ' '))
+                 c = 0;
+               else if (c == (CHAR_CTL | '?'))
+                 c = 127;
+
+               if (c & CHAR_META)
+                 /* Move the meta bit to the right place for a string.  */
+                 c = (c & ~CHAR_META) | 0x80;
+               if (c & ~0xff)
+                 error ("Invalid modifier in string");
+               *p++ = c;
+             }
          }
        if (c < 0) return Fsignal (Qend_of_file, Qnil);
 
@@ -1184,6 +1268,7 @@ read1 (readcharfun)
       if (c <= 040) goto retry;
       {
        register char *p = read_buffer;
+       int quoted = 0;
 
        {
          register char *end = read_buffer + read_buffer_size;
@@ -1207,7 +1292,10 @@ read1 (readcharfun)
                  end = read_buffer + read_buffer_size;
                }
              if (c == '\\')
-               c = READCHAR;
+               {
+                 c = READCHAR;
+                 quoted = 1;
+               }
              *p++ = c;
              c = READCHAR;
            }
@@ -1224,35 +1312,36 @@ read1 (readcharfun)
            UNREAD (c);
        }
 
-       /* Is it an integer? */
-       {
-         register char *p1;
-         register Lisp_Object val;
-         p1 = read_buffer;
-         if (*p1 == '+' || *p1 == '-') p1++;
-         if (p1 != p)
-           {
-             while (p1 != p && (c = *p1) >= '0' && c <= '9') p1++;
+       if (!quoted)
+         {
+           register char *p1;
+           register Lisp_Object val;
+           p1 = read_buffer;
+           if (*p1 == '+' || *p1 == '-') p1++;
+           /* Is it an integer? */
+           if (p1 != p)
+             {
+               while (p1 != p && (c = *p1) >= '0' && c <= '9') p1++;
 #ifdef LISP_FLOAT_TYPE
-             /* Integers can have trailing decimal points.  */
-             if (p1 > read_buffer && p1 < p && *p1 == '.') p1++;
+               /* Integers can have trailing decimal points.  */
+               if (p1 > read_buffer && p1 < p && *p1 == '.') p1++;
 #endif
-             if (p1 == p)
-               /* It is an integer. */
-               {
+               if (p1 == p)
+                 /* It is an integer. */
+                 {
 #ifdef LISP_FLOAT_TYPE
-                 if (p1[-1] == '.')
-                   p1[-1] = '\0';
+                   if (p1[-1] == '.')
+                     p1[-1] = '\0';
 #endif
-                 XSET (val, Lisp_Int, atoi (read_buffer));
-                 return val;
-               }
-           }
+                   XSET (val, Lisp_Int, atoi (read_buffer));
+                   return val;
+                 }
+             }
 #ifdef LISP_FLOAT_TYPE
-         if (isfloat_string (read_buffer))
-           return make_float (atof (read_buffer));
+           if (isfloat_string (read_buffer))
+             return make_float (atof (read_buffer));
 #endif
-       }
+         }
 
        return intern (read_buffer);
       }
@@ -1436,8 +1525,9 @@ intern (str)
 {
   Lisp_Object tem;
   int len = strlen (str);
-  Lisp_Object obarray = Vobarray;
+  Lisp_Object obarray;
 
+  obarray = Vobarray;
   if (XTYPE (obarray) != Lisp_Vector || XVECTOR (obarray)->size == 0)
     obarray = check_obarray (obarray);
   tem = oblookup (obarray, str, len);
@@ -1511,8 +1601,8 @@ oblookup (obarray, ptr, size)
   register Lisp_Object tail;
   Lisp_Object bucket, tem;
 
-  if (XTYPE (obarray) != Lisp_Vector ||
-      (obsize = XVECTOR (obarray)->size) == 0)
+  if (XTYPE (obarray) != Lisp_Vector
+      || (obsize = XVECTOR (obarray)->size) == 0)
     {
       obarray = check_obarray (obarray);
       obsize = XVECTOR (obarray)->size;
@@ -1600,7 +1690,7 @@ OBARRAY defaults to the value of `obarray'.")
   return Qnil;
 }
 
-#define OBARRAY_SIZE 509
+#define OBARRAY_SIZE 1511
 
 void
 init_obarray ()
@@ -1663,17 +1753,14 @@ defalias (sname, string)
 }
 #endif /* NOTDEF */
 
-/* New replacement for DefIntVar; it ignores the doc string argument
-   on the assumption that make-docfile will handle that.  */
 /* Define an "integer variable"; a symbol whose value is forwarded
  to a C variable of type int.  Sample call: */
   /* DEFVARINT ("indent-tabs-mode", &indent_tabs_mode, "Documentation");  */
 
 void
-defvar_int (namestring, address, doc)
+defvar_int (namestring, address)
      char *namestring;
      int *address;
-     char *doc;
 {
   Lisp_Object sym;
   sym = intern (namestring);
@@ -1684,10 +1771,9 @@ defvar_int (namestring, address, doc)
  NIL if address contains 0 */
 
 void
-defvar_bool (namestring, address, doc)
+defvar_bool (namestring, address)
      char *namestring;
      int *address;
-     char *doc;
 {
   Lisp_Object sym;
   sym = intern (namestring);
@@ -1697,10 +1783,9 @@ defvar_bool (namestring, address, doc)
 /* Similar but define a variable whose value is the Lisp Object stored at address. */
 
 void
-defvar_lisp (namestring, address, doc)
+defvar_lisp (namestring, address)
      char *namestring;
      Lisp_Object *address;
-     char *doc;
 {
   Lisp_Object sym;
   sym = intern (namestring);
@@ -1713,10 +1798,9 @@ defvar_lisp (namestring, address, doc)
    since marking the same slot twice can cause trouble with strings.  */
 
 void
-defvar_lisp_nopro (namestring, address, doc)
+defvar_lisp_nopro (namestring, address)
      char *namestring;
      Lisp_Object *address;
-     char *doc;
 {
   Lisp_Object sym;
   sym = intern (namestring);
@@ -1779,7 +1863,27 @@ init_lread ()
 
       dump_path = decode_env_path (0, PATH_DUMPLOADSEARCH);
       if (! NILP (Fequal (dump_path, Vload_path)))
-       Vload_path = decode_env_path (0, normal);
+       {
+         Vload_path = decode_env_path (0, normal);
+         if (!NILP (Vinstallation_directory))
+           {
+             /* Add to the path the lisp subdir of the
+                installation dir, if it exists.  */
+             Lisp_Object tem, tem1;
+             tem = Fexpand_file_name (build_string ("lisp"),
+                                      Vinstallation_directory);
+             tem1 = Ffile_exists_p (tem);
+             if (!NILP (tem1))
+               {
+                 if (NILP (Fmember (tem, Vload_path)))
+                   Vload_path = nconc2 (Vload_path, Fcons (tem, Qnil));
+               }
+             else
+               /* That dir doesn't exist, so add the build-time
+                  Lisp dirs instead.  */
+               Vload_path = nconc2 (Vload_path, dump_path);
+           }
+       }
     }
   else
     Vload_path = decode_env_path (0, normal);
@@ -1799,8 +1903,9 @@ init_lread ()
          {
            dirfile = Fdirectory_file_name (dirfile);
            if (access (XSTRING (dirfile)->data, 0) < 0)
-             printf ("Warning: lisp library (%s) does not exist.\n",
-                     XSTRING (Fcar (path_tail))->data);
+             fprintf (stderr,
+                      "Warning: Lisp directory `%s' does not exist.\n",
+                      XSTRING (Fcar (path_tail))->data);
          }
       }
   }
@@ -1814,6 +1919,8 @@ init_lread ()
   Vvalues = Qnil;
 
   load_in_progress = 0;
+
+  load_descriptor_list = Qnil;
 }
 
 void
@@ -1876,9 +1983,16 @@ The remaining elements of each list are symbols defined as functions\n\
 or variables, and cons cells `(provide . FEATURE)' and `(require . FEATURE)'.");
   Vload_history = Qnil;
 
-  staticpro (&Vcurrent_load_list);
+  DEFVAR_LISP ("current-load-list", &Vcurrent_load_list,
+    "Used for internal purposes by `load'.");
   Vcurrent_load_list = Qnil;
 
+  load_descriptor_list = Qnil;
+  staticpro (&load_descriptor_list);
+
+  Qcurrent_load_list = intern ("current-load-list");
+  staticpro (&Qcurrent_load_list);
+
   Qstandard_input = intern ("standard-input");
   staticpro (&Qstandard_input);
 
@@ -1890,4 +2004,7 @@ or variables, and cons cells `(provide . FEATURE)' and `(require . FEATURE)'.");
 
   Qascii_character = intern ("ascii-character");
   staticpro (&Qascii_character);
+
+  Qload = intern ("load");
+  staticpro (&Qload);
 }