(x_wm_set_size_hint): Always set PWinGravity.
[bpt/emacs.git] / src / fileio.c
index 3929cbd..36e8ba0 100644 (file)
@@ -22,6 +22,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #if !defined (S_ISLNK) && defined (S_IFLNK)
 #  define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
 #endif
@@ -125,6 +129,16 @@ int insert_default_directory;
    Zero means use var format.  */
 int vms_stmlf_recfm;
 
+/* These variables describe handlers that have "already" had a chance
+   to handle the current operation.
+
+   Vinhibit_file_name_handlers is a list of file name handlers.
+   Vinhibit_file_name_operation is the operation being handled.
+   If we try to handle that operation, we ignore those handlers.  */
+
+static Lisp_Object Vinhibit_file_name_handlers;
+static Lisp_Object Vinhibit_file_name_operation;
+
 Lisp_Object Qfile_error, Qfile_already_exists;
 
 Lisp_Object Qfile_name_history;
@@ -192,19 +206,28 @@ Lisp_Object Qwrite_region;
 Lisp_Object Qverify_visited_file_modtime;
 Lisp_Object Qset_visited_file_modtime;
 
-DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 1, 1, 0,
-  "Return FILENAME's handler function, if its syntax is handled specially.\n\
+DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 2, 2, 0,
+  "Return FILENAME's handler function for OPERATION, if it has one.\n\
 Otherwise, return nil.\n\
 A file name is handled if one of the regular expressions in\n\
-`file-name-handler-alist' matches it.")
-  (filename)
-    Lisp_Object filename;
+`file-name-handler-alist' matches it.\n\n\
+If OPERATION equals `inhibit-file-name-operation', then we ignore\n\
+any handlers that are members of `inhibit-file-name-handlers',\n\
+but we still do run any other handlers.  This lets handlers\n\
+use the standard functions without calling themselves recursively.")
+  (filename, operation)
+    Lisp_Object filename, operation;
 {
   /* This function must not munge the match data.  */
-  Lisp_Object chain;
+  Lisp_Object chain, inhibited_handlers;
 
   CHECK_STRING (filename, 0);
 
+  if (EQ (operation, Vinhibit_file_name_operation))
+    inhibited_handlers = Vinhibit_file_name_handlers;
+  else
+    inhibited_handlers = Qnil;
+
   for (chain = Vfile_name_handler_alist; XTYPE (chain) == Lisp_Cons;
        chain = XCONS (chain)->cdr)
     {
@@ -216,7 +239,14 @@ A file name is handled if one of the regular expressions in\n\
          string = XCONS (elt)->car;
          if (XTYPE (string) == Lisp_String
              && fast_string_match (string, filename) >= 0)
-           return XCONS (elt)->cdr;
+           {
+             Lisp_Object handler, tem;
+
+             handler = XCONS (elt)->cdr;
+             tem = Fmemq (handler, inhibited_handlers);
+             if (NILP (tem))
+               return handler;
+           }
        }
 
       QUIT;
@@ -242,7 +272,7 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (file);
+  handler = Ffind_file_name_handler (file, Qfile_name_directory);
   if (!NILP (handler))
     return call2 (handler, Qfile_name_directory, file);
 
@@ -300,7 +330,7 @@ or the entire name if it contains no slash.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (file);
+  handler = Ffind_file_name_handler (file, Qfile_name_nondirectory);
   if (!NILP (handler))
     return call2 (handler, Qfile_name_nondirectory, file);
 
@@ -334,7 +364,7 @@ get a current directory to run processes in.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qunhandled_file_name_directory);
   if (!NILP (handler))
     return call2 (handler, Qunhandled_file_name_directory, filename);
 
@@ -440,7 +470,7 @@ On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (file);
+  handler = Ffind_file_name_handler (file, Qfile_name_as_directory);
   if (!NILP (handler))
     return call2 (handler, Qfile_name_as_directory, file);
 
@@ -621,7 +651,7 @@ it returns a file name such as \"[X]Y.DIR.1\".")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (directory);
+  handler = Ffind_file_name_handler (directory, Qdirectory_file_name);
   if (!NILP (handler))
     return call2 (handler, Qdirectory_file_name, directory);
 
@@ -690,7 +720,7 @@ See also the function `substitute-in-file-name'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (name);
+  handler = Ffind_file_name_handler (name, Qexpand_file_name);
   if (!NILP (handler))
     return call3 (handler, Qexpand_file_name, name, defalt);
 
@@ -1710,13 +1740,13 @@ A prefix arg makes KEEP-TIME non-nil.")
 
   /* If the input file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qcopy_file);
   /* Likewise for output file name.  */
   if (NILP (handler))
-    handler = Ffind_file_name_handler (newname);
+    handler = Ffind_file_name_handler (newname, Qcopy_file);
   if (!NILP (handler))
-    return RETURN_UNGCPRO (call5 (handler, Qcopy_file, filename, newname,
-                                 ok_if_already_exists, keep_date));
+    RETURN_UNGCPRO (call5 (handler, Qcopy_file, filename, newname,
+                          ok_if_already_exists, keep_date));
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -1808,7 +1838,7 @@ DEFUN ("make-directory-internal", Fmake_directory_internal,
   CHECK_STRING (dirname, 0);
   dirname = Fexpand_file_name (dirname, Qnil);
 
-  handler = Ffind_file_name_handler (dirname);
+  handler = Ffind_file_name_handler (dirname, Qmake_directory);
   if (!NILP (handler))
     return call3 (handler, Qmake_directory, dirname, Qnil);
 
@@ -1832,7 +1862,7 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete
   dirname = Fexpand_file_name (dirname, Qnil);
   dir = XSTRING (dirname)->data;
 
-  handler = Ffind_file_name_handler (dirname);
+  handler = Ffind_file_name_handler (dirname, Qdelete_directory);
   if (!NILP (handler))
     return call2 (handler, Qdelete_directory, dirname);
 
@@ -1852,7 +1882,7 @@ If file has multiple names, it continues to exist with the other names.")
   CHECK_STRING (filename, 0);
   filename = Fexpand_file_name (filename, Qnil);
 
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qdelete_file);
   if (!NILP (handler))
     return call2 (handler, Qdelete_file, filename);
 
@@ -1886,12 +1916,12 @@ This is what happens in interactive use with M-x.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qrename_file);
   if (NILP (handler))
-    handler = Ffind_file_name_handler (newname);
+    handler = Ffind_file_name_handler (newname, Qrename_file);
   if (!NILP (handler))
-    return RETURN_UNGCPRO (call4 (handler, Qrename_file,
-                                 filename, newname, ok_if_already_exists));
+    RETURN_UNGCPRO (call4 (handler, Qrename_file,
+                          filename, newname, ok_if_already_exists));
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -1951,10 +1981,10 @@ This is what happens in interactive use with M-x.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qadd_name_to_file);
   if (!NILP (handler))
-    return RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
-                                 newname, ok_if_already_exists));
+    RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
+                          newname, ok_if_already_exists));
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -2005,10 +2035,10 @@ This happens for interactive use with M-x.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qmake_symbolic_link);
   if (!NILP (handler))
-    return RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
-                                 linkname, ok_if_already_exists));
+    RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
+                          linkname, ok_if_already_exists));
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -2126,7 +2156,7 @@ See also `file-readable-p' and `file-attributes'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_exists_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_exists_p, abspath);
 
@@ -2148,7 +2178,7 @@ For a directory, this means you can access files in that directory.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_executable_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_executable_p, abspath);
 
@@ -2169,7 +2199,7 @@ See also `file-exists-p' and `file-attributes'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_readable_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_readable_p, abspath);
 
@@ -2195,7 +2225,7 @@ Otherwise returns nil.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qfile_symlink_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_symlink_p, filename);
 
@@ -2262,7 +2292,7 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_writable_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_writable_p, abspath);
 
@@ -2299,7 +2329,7 @@ if the directory so specified exists and really is a directory.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_directory_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_directory_p, abspath);
 
@@ -2322,7 +2352,7 @@ searchable directory.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_accessible_directory_p, filename);
 
@@ -2346,12 +2376,25 @@ DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_modes);
   if (!NILP (handler))
     return call2 (handler, Qfile_modes, abspath);
 
   if (stat (XSTRING (abspath)->data, &st) < 0)
     return Qnil;
+#ifdef MSDOS
+  {
+    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;
+  }
+#endif /* MSDOS */
+
   return make_number (st.st_mode & 07777);
 }
 
@@ -2369,7 +2412,7 @@ Only the 12 low bits of MODE are used.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qset_file_modes);
   if (!NILP (handler))
     return call3 (handler, Qset_file_modes, abspath, mode);
 
@@ -2472,9 +2515,9 @@ otherwise, if FILE2 does not exist, the answer is t.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath1);
+  handler = Ffind_file_name_handler (abspath1, Qfile_newer_than_file_p);
   if (NILP (handler))
-    handler = Ffind_file_name_handler (abspath2);
+    handler = Ffind_file_name_handler (abspath2, Qfile_newer_than_file_p);
   if (!NILP (handler))
     return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
 
@@ -2534,7 +2577,7 @@ and (2) it puts less data in the undo list.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qinsert_file_contents);
   if (!NILP (handler))
     {
       val = call6 (handler, Qinsert_file_contents, filename,
@@ -2635,7 +2678,7 @@ and (2) it puts less data in the undo list.")
       immediate_quit = 0;
       /* If the file matches the buffer completely,
         there's no need to replace anything.  */
-      if (same_at_start == ZV)
+      if (same_at_start == st.st_size)
        {
          close (fd);
          specpdl_ptr--;
@@ -2750,13 +2793,13 @@ and (2) it puts less data in the undo list.")
      is deemed to be a text file.  */
   {
     struct gcpro gcpro1;
-    Lisp_Object code = Qnil;
+    Lisp_Object code;
+    code = Qnil;
     GCPRO1 (filename);
-    code = call1 (Qfind_buffer_file_type, filename);
+    current_buffer->buffer_file_type
+      = call1 (Qfind_buffer_file_type, filename);
     UNGCPRO;
-    if (XTYPE (code) == Lisp_Int) 
-      XFASTINT (current_buffer->buffer_file_type) = XFASTINT (code);
-    if (XFASTINT (current_buffer->buffer_file_type) == 0)
+    if (NILP (current_buffer->buffer_file_type))
       {
        int reduced_size
          = inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
@@ -2907,10 +2950,10 @@ to the file, instead of any buffer contents, and END is ignored.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qwrite_region);
   /* If FILENAME has no handler, see if VISIT has one.  */
   if (NILP (handler) && XTYPE (visit) == Lisp_String)
-    handler = Ffind_file_name_handler (visit);    
+    handler = Ffind_file_name_handler (visit, Qwrite_region);    
 
   if (!NILP (handler))
     {
@@ -3303,7 +3346,8 @@ This means that the file has not been changed since it was visited or saved.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (b->filename);
+  handler = Ffind_file_name_handler (b->filename,
+                                    Qverify_visited_file_modtime);
   if (!NILP (handler))
     return call2 (handler, Qverify_visited_file_modtime, buf);
 
@@ -3368,7 +3412,7 @@ An argument specifies the modification time value to use\n\
 
       /* If the file name has special constructs in it,
         call the corresponding file handler.  */
-      handler = Ffind_file_name_handler (filename);
+      handler = Ffind_file_name_handler (filename, Qset_visited_file_modtime);
       if (!NILP (handler))
        /* The handler can find the file name the same way we did.  */
        return call2 (handler, Qset_visited_file_modtime, Qnil);
@@ -3472,8 +3516,11 @@ Non-nil second argument means save only current buffer.")
        if (XTYPE (b->auto_save_file_name) == Lisp_String
            && b->save_modified < BUF_MODIFF (b)
            && b->auto_save_modified < BUF_MODIFF (b)
+           /* -1 means we've turned off autosaving for a while--see below.  */
+           && XINT (b->save_length) >= 0
            && (do_handled_files
-               || NILP (Ffind_file_name_handler (b->auto_save_file_name))))
+               || NILP (Ffind_file_name_handler (b->auto_save_file_name,
+                                                 Qwrite_region))))
          {
            EMACS_TIME before_time, after_time;
 
@@ -3496,10 +3543,9 @@ Non-nil second argument means save only current buffer.")
                /* It has shrunk too much; turn off auto-saving here.  */
                message ("Buffer %s has shrunk a lot; auto save turned off there",
                         XSTRING (b->name)->data);
-               /* User can reenable saving with M-x auto-save.  */
-               b->auto_save_file_name = Qnil;
-               /* Prevent warning from repeating if user does so.  */
-               XFASTINT (b->save_length) = 0;
+               /* Turn off auto-saving until there's a real save,
+                  and prevent any more warnings.  */
+               XSET (b->save_length, Lisp_Int, -1);
                Fsleep_for (make_number (1), Qnil);
                continue;
              }
@@ -3952,6 +3998,15 @@ increasing order.  If there are several functions in the list, the several\n\
 lists are merged destructively.");
   Vwrite_region_annotate_functions = Qnil;
 
+  DEFVAR_LISP ("inhibit-file-name-handlers", &Vinhibit_file_name_handlers,
+    "A list of file names for which handlers should not be used.\n\
+This applies only to the operation `inhibit-file-name-operation'.");
+  Vinhibit_file_name_handlers = Qnil;
+
+  DEFVAR_LISP ("inhibit-file-name-operation", &Vinhibit_file_name_operation,
+    "The operation for which `inhibit-file-name-handlers' is applicable.");
+  Vinhibit_file_name_operation = Qnil;
+
   defsubr (&Sfind_file_name_handler);
   defsubr (&Sfile_name_directory);
   defsubr (&Sfile_name_nondirectory);