(Freplace_match): New arg SUBEXP.
[bpt/emacs.git] / src / fileio.c
index ac10154..3465f8c 100644 (file)
@@ -1,5 +1,5 @@
 /* File IO for GNU Emacs.
-   Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -224,6 +224,7 @@ Lisp_Object Qfile_readable_p;
 Lisp_Object Qfile_symlink_p;
 Lisp_Object Qfile_writable_p;
 Lisp_Object Qfile_directory_p;
+Lisp_Object Qfile_regular_p;
 Lisp_Object Qfile_accessible_directory_p;
 Lisp_Object Qfile_modes;
 Lisp_Object Qset_file_modes;
@@ -649,10 +650,20 @@ directory_file_name (src, dst)
   /* Process as Unix format: just remove any final slash.
      But leave "/" unchanged; do not change it to "".  */
   strcpy (dst, src);
+#ifdef APOLLO
+  /* Handle // as root for apollo's.  */
+  if ((slen > 2 && dst[slen - 1] == '/')
+      || (slen > 1 && dst[0] != '/' && dst[slen - 1] == '/'))
+    dst[slen - 1] = 0;
+#else
   if (slen > 1 
       && IS_DIRECTORY_SEP (dst[slen - 1])
-      && !IS_DEVICE_SEP (dst[slen - 2]))
+#ifdef DOS_NT
+      && !IS_ANY_SEP (dst[slen - 2])
+#endif
+      )
     dst[slen - 1] = 0;
+#endif
   return 1;
 }
 
@@ -813,17 +824,43 @@ See also the function `substitute-in-file-name'.")
        nm++;
       else
        {
-         drive = tolower (colon[-1]) - 'a';
+         drive = colon[-1];
          nm = colon + 1;
          if (!IS_DIRECTORY_SEP (*nm))
            {
              defdir = alloca (MAXPATHLEN + 1);
-             relpath = getdefdir (drive + 1, defdir);
+             relpath = getdefdir (tolower (drive) - 'a' + 1, defdir);
            }
        }       
   }
 #endif /* DOS_NT */
 
+  /* Handle // and /~ in middle of file name
+     by discarding everything through the first / of that sequence.  */
+  p = nm;
+  while (*p)
+    {
+      /* Since we know the path is absolute, we can assume that each
+        element starts with a "/".  */
+
+      /* "//" anywhere isn't necessarily hairy; we just start afresh
+        with the second slash.  */
+      if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
+#if defined (APOLLO) || defined (WINDOWSNT)
+         /* // at start of filename is meaningful on Apollo 
+            and WindowsNT systems */
+         && nm != p
+#endif /* APOLLO || WINDOWSNT */
+         )
+       nm = p + 1;
+
+      /* "~" is hairy as the start of any path element.  */
+      if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~')
+       nm = p + 1;
+
+      p++;
+    }
+
   /* If nm is absolute, flush ...// and detect /./ and /../.
      If no /./ or /../ we can return right away. */
   if (
@@ -847,24 +884,6 @@ See also the function `substitute-in-file-name'.")
          /* Since we know the path is absolute, we can assume that each
             element starts with a "/".  */
 
-         /* "//" anywhere isn't necessarily hairy; we just start afresh
-            with the second slash.  */
-         if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
-#ifdef APOLLO
-             /* // at start of filename is meaningful on Apollo system */
-             && nm != p
-#endif /* APOLLO */
-#ifdef WINDOWSNT
-             /* \\ or // at the start of a pathname is meaningful on NT.  */
-             && nm != p
-#endif /* WINDOWSNT */
-             )
-           nm = p + 1;
-
-         /* "~" is hairy as the start of any path element.  */
-         if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~')
-           nm = p + 1, lose = 1;
-
          /* "." and ".." are hairy.  */
          if (IS_DIRECTORY_SEP (p[0])
              && p[1] == '.'
@@ -977,6 +996,10 @@ See also the function `substitute-in-file-name'.")
          if (!(newdir = (unsigned char *) egetenv ("HOME")))
            newdir = (unsigned char *) "";
 #ifdef DOS_NT
+         /* Problem when expanding "~\" if HOME is not on current drive.
+            Ulrich Leodolter, Wed Jan 11 10:20:35 1995 */
+         if (newdir[1] == ':')
+           drive = newdir[0];
          dostounix_filename (newdir);
 #endif
          nm++;
@@ -1039,7 +1062,7 @@ See also the function `substitute-in-file-name'.")
       /* Adding `length > 1 &&' makes ~ expand into / when homedir
         is the root dir.  People disagree about whether that is right.
         Anyway, we can't take the risk of this change now.  */
-#ifdef MSDOS
+#ifdef DOS_NT
       if (newdir[1] != ':' && length > 1)
 #endif
       if (IS_DIRECTORY_SEP (newdir[length - 1]))
@@ -1135,19 +1158,12 @@ See also the function `substitute-in-file-name'.")
        {
          *o++ = *p++;
        }
-#ifdef WINDOWSNT
-      else if (!strncmp (p, "\\\\", 2) || !strncmp (p, "//", 2))
-#else  /* not WINDOWSNT */
-      else if (!strncmp (p, "//", 2)
-#endif /* not WINDOWSNT */
-#ifdef APOLLO
-              /* // at start of filename is meaningful in Apollo system */
+      else if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
+#if defined (APOLLO) || defined (WINDOWSNT)
+              /* // at start of filename is meaningful in Apollo 
+                 and WindowsNT systems */
               && o != target
 #endif /* APOLLO */
-#ifdef WINDOWSNT
-              /* \\ at start of filename is meaningful in Windows-NT */
-              && o != target
-#endif /* WINDOWSNT */
               )
        {
          o = target;
@@ -1164,28 +1180,19 @@ See also the function `substitute-in-file-name'.")
            *o++ = *p;
          p += 2;
        }
-#ifdef WINDOWSNT
-      else if (!strncmp (p, "\\..", 3) || !strncmp (p, "/..", 3))
-#else  /* not WINDOWSNT */
-      else if (!strncmp (p, "/..", 3)
-#endif /* not WINDOWSNT */
+      else if (IS_DIRECTORY_SEP (p[0]) && p[1] == '.' && p[2] == '.'
               /* `/../' is the "superroot" on certain file systems.  */
               && o != target
               && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0))
        {
          while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
            ;
-#ifdef APOLLO
-         if (o == target + 1 && o[-1] == '/' && o[0] == '/')
-           ++o;
-         else
-#endif /* APOLLO */
-#ifdef WINDOWSNT
-         if (o == target + 1 && (o[-1] == '/' && o[0] == '/')
-             || (o[-1] == '\\' && o[0] == '\\'))
+#if defined (APOLLO) || defined (WINDOWSNT)
+         if (o == target + 1 
+             && IS_DIRECTORY_SEP (o[-1]) && IS_DIRECTORY_SEP (o[0]))
            ++o;
          else
-#endif /* WINDOWSNT */
+#endif /* APOLLO || WINDOWSNT */
          if (o == target && IS_ANY_SEP (*o))
            ++o;
          p += 3;
@@ -1207,7 +1214,7 @@ See also the function `substitute-in-file-name'.")
       )
     {
       target -= 2;
-      target[0] = (drive < 0 ? getdisk () : drive) + 'a';
+      target[0] = (drive < 0 ? getdisk () + 'A' : drive);
       target[1] = ':';
     }
 #endif /* DOS_NT */
@@ -1914,9 +1921,6 @@ A prefix arg makes KEEP-TIME non-nil.")
          if (set_file_times (XSTRING (newname)->data, atime, mtime))
            report_file_error ("I/O error", Fcons (newname, Qnil));
        }
-#ifdef APOLLO
-      if (!egetenv ("USE_DOMAIN_ACLS"))
-#endif
        chmod (XSTRING (newname)->data, st.st_mode & 07777);
     }
 
@@ -2291,6 +2295,18 @@ static int
 check_executable (filename)
      char *filename;
 {
+#ifdef DOS_NT
+  int len = strlen (filename);
+  char *suffix;
+  struct stat st;
+  if (stat (filename, &st) < 0)
+    return 0;
+  return (S_ISREG (st.st_mode)
+         && len >= 5
+         && (stricmp ((suffix = filename + len-4), ".com") == 0
+             || stricmp (suffix, ".exe") == 0
+             || stricmp (suffix, ".bat") == 0));
+#else /* not DOS_NT */
 #ifdef HAVE_EACCESS
   return (eaccess (filename, 1) >= 0);
 #else
@@ -2299,6 +2315,7 @@ check_executable (filename)
      But Unix doesn't give us a right way to do it.  */
   return (access (filename, 1) >= 0);
 #endif
+#endif /* not DOS_NT */
 }
 
 /* Return nonzero if file FILENAME exists and can be written.  */
@@ -2307,6 +2324,12 @@ static int
 check_writable (filename)
      char *filename;
 {
+#ifdef MSDOS
+  struct stat st;
+  if (stat (filename, &st) < 0)
+    return 0;
+  return (st.st_mode & S_IWRITE || (st.st_mode & S_IFMT) == S_IFDIR);
+#else /* not MSDOS */
 #ifdef HAVE_EACCESS
   return (eaccess (filename, 2) >= 0);
 #else
@@ -2317,6 +2340,7 @@ check_writable (filename)
      but would lose for directories.  */
   return (access (filename, 2) >= 0);
 #endif
+#endif /* not MSDOS */
 }
 
 DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
@@ -2543,9 +2567,9 @@ This is the sort of file that holds an ordinary stream of data bytes.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath, Qfile_directory_p);
+  handler = Ffind_file_name_handler (abspath, Qfile_regular_p);
   if (!NILP (handler))
-    return call2 (handler, Qfile_directory_p, abspath);
+    return call2 (handler, Qfile_regular_p, abspath);
 
   if (stat (XSTRING (abspath)->data, &st) < 0)
     return Qnil;
@@ -2572,16 +2596,8 @@ DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
   if (stat (XSTRING (abspath)->data, &st) < 0)
     return Qnil;
 #ifdef DOS_NT
-  {
-    int len;
-    char *suffix;
-    if (S_ISREG (st.st_mode)
-       && (len = XSTRING (abspath)->size) >= 5
-       && (stricmp ((suffix = XSTRING (abspath)->data + len-4), ".com") == 0
-           || stricmp (suffix, ".exe") == 0
-           || stricmp (suffix, ".bat") == 0))
-      st.st_mode |= S_IEXEC;
-  }
+  if (check_executable (XSTRING (abspath)->data))
+    st.st_mode |= S_IEXEC;
 #endif /* DOS_NT */
 
   return make_number (st.st_mode & 07777);
@@ -2605,36 +2621,8 @@ Only the 12 low bits of MODE are used.")
   if (!NILP (handler))
     return call3 (handler, Qset_file_modes, abspath, mode);
 
-#ifndef APOLLO
   if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
     report_file_error ("Doing chmod", Fcons (abspath, Qnil));
-#else /* APOLLO */
-  if (!egetenv ("USE_DOMAIN_ACLS"))
-    {
-      struct stat st;
-      struct timeval tvp[2];
-
-      /* chmod on apollo also change the file's modtime; need to save the
-        modtime and then restore it. */
-      if (stat (XSTRING (abspath)->data, &st) < 0)
-       {
-         report_file_error ("Doing chmod", Fcons (abspath, Qnil));
-         return (Qnil);
-       }
-      if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
-       report_file_error ("Doing chmod", Fcons (abspath, Qnil));
-      /* reset the old accessed and modified times.  */
-      tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
-      tvp[0].tv_usec = 0;
-      tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
-      tvp[1].tv_usec = 0;
-      if (utimes (XSTRING (abspath)->data, tvp) < 0)
-       report_file_error ("Doing utimes", Fcons (abspath, Qnil));
-    }
-#endif /* APOLLO */
 
   return Qnil;
 }
@@ -3070,8 +3058,8 @@ and (2) it puts less data in the undo list.")
 #ifdef CLASH_DETECTION
       if (NILP (handler))
        {
-         if (!NILP (current_buffer->filename))
-           unlock_file (current_buffer->filename);
+         if (!NILP (current_buffer->file_truename))
+           unlock_file (current_buffer->file_truename);
          unlock_file (filename);
        }
 #endif /* CLASH_DETECTION */
@@ -3405,7 +3393,11 @@ to the file, instead of any buffer contents, and END is ignored.")
   /* mib says that closing the file will try to write as fast as NFS can do
      it, and that means the fsync here is not crucial for autosave files.  */
   if (!auto_saving && fsync (desc) < 0)
-    failure = 1, save_errno = errno;
+    {
+      /* If fsync fails with EINTR, don't treat that as serious.  */
+      if (errno != EINTR)
+       failure = 1, save_errno = errno;
+    }
 #endif
 
   /* Spurious "file has changed on disk" warnings have been 
@@ -3691,7 +3683,7 @@ The value is a list of the form (HIGH . LOW), like the time values\n\
 that `file-attributes' returns.")
   ()
 {
-  return long_to_cons (current_buffer->modtime);
+  return long_to_cons ((unsigned long) current_buffer->modtime);
 }
 
 DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
@@ -3764,6 +3756,7 @@ static Lisp_Object
 do_auto_save_unwind (desc)  /* used as unwind-protect function */
      Lisp_Object desc;
 {
+  auto_saving = 0;
   close (XINT (desc));
   return Qnil;
 }
@@ -3801,7 +3794,6 @@ Non-nil second argument means save only current buffer.")
   /* No GCPRO needed, because (when it matters) all Lisp_Object variables
      point to non-strings reached from Vbuffer_alist.  */
 
-  auto_saving = 1;
   if (minibuf_level)
     no_message = Qt;
 
@@ -3810,21 +3802,26 @@ Non-nil second argument means save only current buffer.")
 
   if (STRINGP (Vauto_save_list_file_name))
     {
+      Lisp_Object listfile;
+      listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
 #ifdef DOS_NT
-      listdesc = open (XSTRING (Vauto_save_list_file_name)->data, 
+      listdesc = open (XSTRING (listfile)->data, 
                       O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
                       S_IREAD | S_IWRITE);
 #else  /* not DOS_NT */
-      listdesc = creat (XSTRING (Vauto_save_list_file_name)->data, 0666);
+      listdesc = creat (XSTRING (listfile)->data, 0666);
 #endif /* not DOS_NT */
     }
   else
     listdesc = -1;
   
-  /* Arrange to close that file whether or not we get an error.  */
+  /* Arrange to close that file whether or not we get an error.
+     Also reset auto_saving to 0.  */
   if (listdesc >= 0)
     record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
 
+  auto_saving = 1;
+
   /* First, save all files which don't have handlers.  If Emacs is
      crashing, the handlers may tweak what is causing Emacs to crash
      in the first place, and it would be a shame if Emacs failed to
@@ -3837,10 +3834,17 @@ Non-nil second argument means save only current buffer.")
        b = XBUFFER (buf);
       
        /* Record all the buffers that have auto save mode
-          in the special file that lists them.  */
+          in the special file that lists them.  For each of these buffers,
+          Record visited name (if any) and auto save name.  */
        if (STRINGP (b->auto_save_file_name)
            && listdesc >= 0 && do_handled_files == 0)
          {
+           if (!NILP (b->filename))
+             {
+               write (listdesc, XSTRING (b->filename)->data,
+                      XSTRING (b->filename)->size);
+             }
+           write (listdesc, "\n", 1);
            write (listdesc, XSTRING (b->auto_save_file_name)->data,
                   XSTRING (b->auto_save_file_name)->size);
            write (listdesc, "\n", 1);
@@ -3925,7 +3929,6 @@ Non-nil second argument means save only current buffer.")
 
   Vquit_flag = oquit;
 
-  auto_saving = 0;
   unbind_to (count, Qnil);
   return Qnil;
 }
@@ -4245,6 +4248,7 @@ syms_of_fileio ()
   Qfile_symlink_p = intern ("file-symlink-p");
   Qfile_writable_p = intern ("file-writable-p");
   Qfile_directory_p = intern ("file-directory-p");
+  Qfile_regular_p = intern ("file-regular-p");
   Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
   Qfile_modes = intern ("file-modes");
   Qset_file_modes = intern ("set-file-modes");
@@ -4274,6 +4278,7 @@ syms_of_fileio ()
   staticpro (&Qfile_symlink_p);
   staticpro (&Qfile_writable_p);
   staticpro (&Qfile_directory_p);
+  staticpro (&Qfile_regular_p);
   staticpro (&Qfile_accessible_directory_p);
   staticpro (&Qfile_modes);
   staticpro (&Qset_file_modes);
@@ -4297,7 +4302,7 @@ syms_of_fileio ()
 #endif /* DOS_NT */
 
   DEFVAR_LISP ("auto-save-file-format", &Vauto_save_file_format,
-    "*Format in which to write auto-save files.
+    "*Format in which to write auto-save files.\n\
 Should be a list of symbols naming formats that are defined in `format-alist'.\n\
 If it is t, which is the default, auto-save files are written in the\n\
 same format as a regular save would use.");