#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
/* Functions to be called to create text property annotations for file. */
Lisp_Object Vwrite_region_annotate_functions;
+/* File name in which we write a list of all our auto save files. */
+Lisp_Object Vauto_save_list_file_name;
+
/* Nonzero means, when reading a filename in the minibuffer,
start out by inserting the default directory into the minibuffer. */
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;
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)
{
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;
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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 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)
report_file_error ("I/O error", Fcons (newname, Qnil));
immediate_quit = 0;
+ /* Closing the output clobbers the file times on some systems. */
+ if (close (ofd) < 0)
+ report_file_error ("I/O error", Fcons (newname, Qnil));
+
if (input_file_statable_p)
{
if (!NILP (keep_date))
chmod (XSTRING (newname)->data, st.st_mode & 07777);
}
+ close (ifd);
+
/* Discard the unwind protects. */
specpdl_ptr = specpdl + count;
- close (ifd);
- if (close (ofd) < 0)
- report_file_error ("I/O error", Fcons (newname, Qnil));
-
UNGCPRO;
return Qnil;
}
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);
}
DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
- "Delete a directory. One argument, a file name string.")
+ "Delete a directory. One argument, a file name or directory name string.")
(dirname)
Lisp_Object dirname;
{
Lisp_Object handler;
CHECK_STRING (dirname, 0);
- dirname = Fexpand_file_name (dirname, Qnil);
+ dirname = Fdirectory_file_name (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);
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);
/* 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 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)
/* 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 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)
/* 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 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)
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
}
/* 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);
/* 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);
/* 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,
with the file contents. Avoid replacing text at the
beginning or end of the buffer that matches the file contents;
that preserves markers pointing to the unchanged parts. */
+#ifdef MSDOS
+ /* On MSDOS, replace mode doesn't really work, except for binary files,
+ and it's not worth supporting just for them. */
if (!NILP (replace))
{
- char buffer[1 << 14];
+ replace = Qnil;
+ XFASTINT (beg) = 0;
+ XFASTINT (end) = st.st_size;
+ del_range_1 (BEGV, ZV, 0);
+ }
+#else /* MSDOS */
+ if (!NILP (replace))
+ {
+ unsigned char buffer[1 << 14];
int same_at_start = BEGV;
int same_at_end = ZV;
int overlap;
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 - BEGV == st.st_size)
{
close (fd);
specpdl_ptr--;
+ /* Truncate the buffer to the size of the file. */
+ del_range_1 (same_at_start, same_at_end, 0);
goto handled;
}
immediate_quit = 1;
/* At what file position are we now scanning? */
curpos = st.st_size - (ZV - same_at_end);
+ /* If the entire file matches the buffer tail, stop the scan. */
+ if (curpos == 0)
+ break;
/* How much can we scan in the next step? */
trial = min (curpos, sizeof buffer);
if (lseek (fd, curpos - trial, 0) < 0)
/* Insert from the file at the proper position. */
SET_PT (same_at_start);
}
+#endif /* MSDOS */
total = XINT (end) - XINT (beg);
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);
/* 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))
{
current_buffer->save_modified = MODIFF;
XFASTINT (current_buffer->save_length) = Z - BEG;
current_buffer->filename = visit_file;
+ update_mode_lines++;
}
else if (quietly)
return Qnil;
/* 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);
/* 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);
Qnil, Qlambda);
}
+static Lisp_Object
+do_auto_save_unwind (desc) /* used as unwind-protect function */
+ Lisp_Object desc;
+{
+ close (XINT (desc));
+ return Qnil;
+}
+
DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
"Auto-save all buffers that need it.\n\
This is all buffers that have auto-saving enabled\n\
extern int minibuf_level;
int do_handled_files;
Lisp_Object oquit;
+ int listdesc;
+ Lisp_Object lispstream;
+ int count = specpdl_ptr - specpdl;
+ int *ptr;
/* Ordinarily don't quit within this function,
but don't make it impossible to quit (in case we get hung in I/O). */
if (!NILP (Vrun_hooks))
call1 (Vrun_hooks, intern ("auto-save-hook"));
+ if (STRINGP (Vauto_save_list_file_name))
+ {
+#ifdef MSDOS
+ listdesc = open (XSTRING (Vauto_save_list_file_name)->data,
+ O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
+ S_IREAD | S_IWRITE);
+#else /* not MSDOS */
+ listdesc = creat (XSTRING (Vauto_save_list_file_name)->data, 0666);
+#endif /* not MSDOS */
+ }
+ else
+ listdesc = -1;
+
+ /* Arrange to close that file whether or not we get an error. */
+ if (listdesc >= 0)
+ record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
+
/* 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
{
buf = XCONS (XCONS (tail)->car)->cdr;
b = XBUFFER (buf);
+
+ /* Record all the buffers that have auto save mode
+ in the special file that lists them. */
+ if (XTYPE (b->auto_save_file_name) == Lisp_String
+ && listdesc >= 0 && do_handled_files == 0)
+ {
+ write (listdesc, XSTRING (b->auto_save_file_name)->data,
+ XSTRING (b->auto_save_file_name)->size);
+ write (listdesc, "\n", 1);
+ }
if (!NILP (current_only)
&& b != current_buffer)
continue;
-
+
/* Check for auto save enabled
and file changed since last auto save
and file changed since last real save. */
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;
/* 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;
}
Vquit_flag = oquit;
auto_saving = 0;
+ unbind_to (count, Qnil);
return Qnil;
}
lists are merged destructively.");
Vwrite_region_annotate_functions = Qnil;
+ DEFVAR_LISP ("inhibit-file-name-handlers", &Vinhibit_file_name_handlers,
+ "A list of file name handlers that temporarily 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;
+
+ DEFVAR_LISP ("auto-save-list-file-name", &Vauto_save_list_file_name,
+ "File name in which we write a list of all auto save file names.");
+ Vauto_save_list_file_name = Qnil;
+
defsubr (&Sfind_file_name_handler);
defsubr (&Sfile_name_directory);
defsubr (&Sfile_name_nondirectory);