/* 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.
whose I/O is done with a special handler. */
Lisp_Object Vfile_name_handler_alist;
+/* Format for auto-save files */
+Lisp_Object Vauto_save_file_format;
+
+/* Lisp functions for translating file formats */
+Lisp_Object Qformat_decode, Qformat_annotate_function;
+
/* Functions to be called to process text properties in inserted file. */
Lisp_Object Vafter_insert_file_functions;
}
\f
Lisp_Object Qexpand_file_name;
+Lisp_Object Qsubstitute_in_file_name;
Lisp_Object Qdirectory_file_name;
Lisp_Object Qfile_name_directory;
Lisp_Object Qfile_name_nondirectory;
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;
#ifdef VMS
&& p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
#endif /* VMS */
-#ifdef MSDOS
- && p[-1] != ':' && p[-1] != '\\'
-#endif
) p--;
if (p == beg)
#ifdef VMS
&& p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
#endif /* VMS */
-#ifdef MSDOS
- && p[-1] != ':'
-#endif
) p--;
return make_string (p, end - p);
}
#else /* not VMS */
/* For Unix syntax, Append a slash if necessary */
-#ifdef MSDOS
- if (out[size] != ':' && out[size] != '/' && out[size] != '\\')
-#else /* not MSDOS */
if (!IS_ANY_SEP (out[size]))
{
out[size + 1] = DIRECTORY_SEP;
out[size + 2] = '\0';
}
-#endif /* not MSDOS */
#endif /* not VMS */
return out;
}
/* 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;
}
defalt = current_buffer->directory;
CHECK_STRING (defalt, 1);
+ if (!NILP (defalt))
+ {
+ handler = Ffind_file_name_handler (defalt, Qexpand_file_name);
+ if (!NILP (handler))
+ return call3 (handler, Qexpand_file_name, name, defalt);
+ }
+
o = XSTRING (defalt)->data;
/* Make sure DEFALT is properly expanded.
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 (
/* 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] == '.'
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++;
/* 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]))
{
*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;
*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;
)
{
target -= 2;
- target[0] = (drive < 0 ? getdisk () : drive) + 'a';
+ target[0] = (drive < 0 ? getdisk () + 'A' : drive);
target[1] = ':';
}
#endif /* DOS_NT */
int total = 0;
int substituted = 0;
unsigned char *xnm;
+ Lisp_Object handler;
CHECK_STRING (string, 0);
+ /* If the file name has special constructs in it,
+ call the corresponding file handler. */
+ handler = Ffind_file_name_handler (string, Qsubstitute_in_file_name);
+ if (!NILP (handler))
+ return call2 (handler, Qsubstitute_in_file_name, string);
+
nm = XSTRING (string)->data;
#ifdef MSDOS
dostounix_filename (nm = strcpy (alloca (strlen (nm) + 1), nm));
return abspath;
}
\f
+/* Signal an error if the file ABSNAME already exists.
+ If INTERACTIVE is nonzero, ask the user whether to proceed,
+ and bypass the error if the user says to go ahead.
+ QUERYSTRING is a name for the action that is being considered
+ to alter the file.
+ *STATPTR is used to store the stat information if the file exists.
+ If the file does not exist, STATPTR->st_mode is set to 0. */
+
void
-barf_or_query_if_file_exists (absname, querystring, interactive)
+barf_or_query_if_file_exists (absname, querystring, interactive, statptr)
Lisp_Object absname;
unsigned char *querystring;
int interactive;
+ struct stat *statptr;
{
register Lisp_Object tem;
struct stat statbuf;
Fsignal (Qfile_already_exists,
Fcons (build_string ("File already exists"),
Fcons (absname, Qnil)));
+ if (statptr)
+ *statptr = statbuf;
+ }
+ else
+ {
+ if (statptr)
+ statptr->st_mode = 0;
}
return;
}
{
int ifd, ofd, n;
char buf[16 * 1024];
- struct stat st;
+ struct stat st, out_st;
Lisp_Object handler;
struct gcpro gcpro1, gcpro2;
int count = specpdl_ptr - specpdl;
if (NILP (ok_if_already_exists)
|| INTEGERP (ok_if_already_exists))
barf_or_query_if_file_exists (newname, "copy to it",
- INTEGERP (ok_if_already_exists));
+ INTEGERP (ok_if_already_exists), &out_st);
+ else if (stat (XSTRING (newname)->data, &out_st) < 0)
+ out_st.st_mode = 0;
ifd = open (XSTRING (filename)->data, O_RDONLY);
if (ifd < 0)
copyable by us. */
input_file_statable_p = (fstat (ifd, &st) >= 0);
+#ifndef DOS_NT
+ if (out_st.st_mode != 0
+ && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
+ {
+ errno = 0;
+ report_file_error ("Input and output files are the same",
+ Fcons (filename, Fcons (newname, Qnil)));
+ }
+#endif
+
#if defined (S_ISREG) && defined (S_ISLNK)
if (input_file_statable_p)
{
/* Get a better looking error message. */
errno = EISDIR;
#endif /* EISDIR */
- report_file_error ("Non-regular file", Fcons (filename, Qnil));
+ report_file_error ("Non-regular file", Fcons (filename, Qnil));
}
}
#endif /* S_ISREG && S_ISLNK */
#endif /* not MSDOS */
#endif /* VMS */
if (ofd < 0)
- report_file_error ("Opening output file", Fcons (newname, Qnil));
+ report_file_error ("Opening output file", Fcons (newname, Qnil));
record_unwind_protect (close_file_unwind, make_number (ofd));
QUIT;
while ((n = read (ifd, buf, sizeof buf)) > 0)
if (write (ofd, buf, n) != n)
- report_file_error ("I/O error", Fcons (newname, Qnil));
+ report_file_error ("I/O error", Fcons (newname, Qnil));
immediate_quit = 0;
/* Closing the output clobbers the file times on some systems. */
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
+#ifndef MSDOS
+ chmod (XSTRING (newname)->data, st.st_mode & 07777);
+#else /* MSDOS */
+#if defined (__DJGPP__) && __DJGPP__ > 1
+ /* In DJGPP v2.0 and later, fstat usually returns true file mode bits,
+ and if it can't, it tells so. Otherwise, under MSDOS we usually
+ get only the READ bit, which will make the copied file read-only,
+ so it's better not to chmod at all. */
+ if ((_djstat_flags & _STFAIL_WRITEBIT) == 0)
chmod (XSTRING (newname)->data, st.st_mode & 07777);
+#endif /* DJGPP version 2 or newer */
+#endif /* MSDOS */
}
close (ifd);
UNGCPRO;
return Qnil;
}
-
+\f
DEFUN ("make-directory-internal", Fmake_directory_internal,
Smake_directory_internal, 1, 1, 0,
"Create a directory. One argument, a file name string.")
return Qnil;
}
+static Lisp_Object
+internal_delete_file_1 (ignore)
+ Lisp_Object ignore;
+{
+ return Qt;
+}
+
+/* Delete file FILENAME, returning 1 if successful and 0 if failed. */
+
+int
+internal_delete_file (filename)
+ Lisp_Object filename;
+{
+ return NILP (internal_condition_case_1 (Fdelete_file, filename,
+ Qt, internal_delete_file_1));
+}
+\f
DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
"fRename file: \nFRename %s to file: \np",
"Rename FILE as NEWNAME. Both args strings.\n\
if (NILP (ok_if_already_exists)
|| INTEGERP (ok_if_already_exists))
barf_or_query_if_file_exists (newname, "rename to it",
- INTEGERP (ok_if_already_exists));
+ INTEGERP (ok_if_already_exists), 0);
#ifndef BSD4_1
if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
#else
RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
newname, ok_if_already_exists));
+ /* If the new name has special constructs in it,
+ call the corresponding file handler. */
+ handler = Ffind_file_name_handler (newname, Qadd_name_to_file);
+ if (!NILP (handler))
+ RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
+ newname, ok_if_already_exists));
+
if (NILP (ok_if_already_exists)
|| INTEGERP (ok_if_already_exists))
barf_or_query_if_file_exists (newname, "make it a new name",
- INTEGERP (ok_if_already_exists));
+ INTEGERP (ok_if_already_exists), 0);
#ifdef WINDOWSNT
/* Windows does not support this operation. */
report_file_error ("Adding new name", Flist (2, &filename));
RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
linkname, ok_if_already_exists));
+ /* If the new link name has special constructs in it,
+ call the corresponding file handler. */
+ handler = Ffind_file_name_handler (linkname, Qmake_symbolic_link);
+ if (!NILP (handler))
+ RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
+ linkname, ok_if_already_exists));
+
if (NILP (ok_if_already_exists)
|| INTEGERP (ok_if_already_exists))
barf_or_query_if_file_exists (linkname, "make it a link",
- INTEGERP (ok_if_already_exists));
+ INTEGERP (ok_if_already_exists), 0);
if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
{
/* If we didn't complain already, silently delete existing file. */
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)
+ || (st.st_mode & S_IFMT) == S_IFDIR);
+#else /* not DOS_NT */
#ifdef HAVE_EACCESS
return (eaccess (filename, 1) >= 0);
#else
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. */
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
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,
/* 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;
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);
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;
}
Lisp_Object handler, val, insval;
Lisp_Object p;
int total;
- int not_regular;
+ int not_regular = 0;
+
+ if (current_buffer->base_buffer && ! NILP (visit))
+ error ("Cannot do file visiting in an indirect buffer");
+
+ if (!NILP (current_buffer->read_only))
+ Fbarf_if_buffer_read_only ();
val = Qnil;
p = Qnil;
GCPRO3 (filename, val, p);
- if (!NILP (current_buffer->read_only))
- Fbarf_if_buffer_read_only();
CHECK_STRING (filename, 0);
filename = Fexpand_file_name (filename, Qnil);
goto notfound;
}
- not_regular = 0;
#ifdef S_IFREG
/* This code will need to be changed in order to work on named
pipes, and it's probably just not worth it. So we should at
Otherwise loop around and scan the preceding bufferfull. */
if (bufpos != 0)
break;
+ /* If display current starts at beginning of line,
+ keep it that way. */
+ if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
+ XWINDOW (selected_window)->start_at_line_beg = Fbolp ();
}
immediate_quit = 0;
current_buffer->filename = filename;
}
- current_buffer->save_modified = MODIFF;
+ SAVE_MODIFF = MODIFF;
current_buffer->auto_save_modified = MODIFF;
XSETFASTINT (current_buffer->save_length, Z - BEG);
#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 */
report_file_error ("Opening input file", Fcons (filename, Qnil));
}
+ /* Decode file format */
+ if (inserted > 0)
+ {
+ insval = call3 (Qformat_decode,
+ Qnil, make_number (inserted), visit);
+ CHECK_NUMBER (insval, 0);
+ inserted = XFASTINT (insval);
+ }
+
if (inserted > 0 && NILP (visit) && total > 0)
signal_after_change (point, 0, inserted);
return Qnil;
}
-DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
+DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 6,
"r\nFWrite region to file: ",
"Write current region into specified file.\n\
When called from a program, takes three arguments:\n\
VISIT is also the file name to lock and unlock for clash detection.\n\
If VISIT is neither t nor nil nor a string,\n\
that means do not print the \"Wrote file\" message.\n\
+The optional sixth arg LOCKNAME, if non-nil, specifies the name to\n\
+ use for locking and unlocking, overriding FILENAME and VISIT.\n\
Kludgy feature: if START is a string, then that string is written\n\
to the file, instead of any buffer contents, and END is ignored.")
- (start, end, filename, append, visit)
- Lisp_Object start, end, filename, append, visit;
+ (start, end, filename, append, visit, lockname)
+ Lisp_Object start, end, filename, append, visit, lockname;
{
register int desc;
int failure;
Lisp_Object visit_file;
Lisp_Object annotations;
int visiting, quietly;
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
struct buffer *given_buffer;
#ifdef DOS_NT
int buffer_file_type
= NILP (current_buffer->buffer_file_type) ? O_TEXT : O_BINARY;
#endif /* DOS_NT */
+ if (current_buffer->base_buffer && ! NILP (visit))
+ error ("Cannot do file visiting in an indirect buffer");
+
if (!NILP (start) && !STRINGP (start))
validate_region (&start, &end);
- GCPRO2 (filename, visit);
+ GCPRO3 (filename, visit, lockname);
filename = Fexpand_file_name (filename, Qnil);
if (STRINGP (visit))
visit_file = Fexpand_file_name (visit, Qnil);
annotations = Qnil;
- GCPRO4 (start, filename, annotations, visit_file);
+ if (NILP (lockname))
+ lockname = visit_file;
+
+ GCPRO5 (start, filename, annotations, visit_file, lockname);
/* If the file name has special constructs in it,
call the corresponding file handler. */
if (visiting)
{
- current_buffer->save_modified = MODIFF;
+ SAVE_MODIFF = MODIFF;
XSETFASTINT (current_buffer->save_length, Z - BEG);
current_buffer->filename = visit_file;
}
#ifdef CLASH_DETECTION
if (!auto_saving)
- lock_file (visit_file);
+ lock_file (lockname);
#endif /* CLASH_DETECTION */
fn = XSTRING (filename)->data;
{
#ifdef CLASH_DETECTION
save_errno = errno;
- if (!auto_saving) unlock_file (visit_file);
+ if (!auto_saving) unlock_file (lockname);
errno = save_errno;
#endif /* CLASH_DETECTION */
report_file_error ("Opening output file", Fcons (filename, Qnil));
if (lseek (desc, 0, 2) < 0)
{
#ifdef CLASH_DETECTION
- if (!auto_saving) unlock_file (visit_file);
+ if (!auto_saving) unlock_file (lockname);
#endif /* CLASH_DETECTION */
report_file_error ("Lseek error", Fcons (filename, Qnil));
}
nwritten += XINT (end) - tem;
save_errno = errno;
}
-
- if (nwritten == 0)
- {
- /* If file was empty, still need to write the annotations */
- failure = 0 > a_write (desc, "", 0, XINT (start), &annotations);
- save_errno = errno;
- }
+ }
+ else
+ {
+ /* If file was empty, still need to write the annotations */
+ failure = 0 > a_write (desc, "", 0, XINT (start), &annotations);
+ save_errno = errno;
}
immediate_quit = 0;
/* 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
#ifdef CLASH_DETECTION
if (!auto_saving)
- unlock_file (visit_file);
+ unlock_file (lockname);
#endif /* CLASH_DETECTION */
/* Do this before reporting IO error
if (visiting)
{
- current_buffer->save_modified = MODIFF;
+ SAVE_MODIFF = MODIFF;
XSETFASTINT (current_buffer->save_length, Z - BEG);
current_buffer->filename = visit_file;
update_mode_lines++;
annotations = merge (annotations, res, Qcar_less_than_car);
p = Fcdr (p);
}
+
+ /* Now do the same for annotation functions implied by the file-format */
+ if (auto_saving && (!EQ (Vauto_save_file_format, Qt)))
+ p = Vauto_save_file_format;
+ else
+ p = current_buffer->file_format;
+ while (!NILP (p))
+ {
+ struct buffer *given_buffer = current_buffer;
+ Vwrite_region_annotations_so_far = annotations;
+ res = call3 (Qformat_annotate_function, Fcar (p), start, end);
+ if (current_buffer != given_buffer)
+ {
+ start = BEGV;
+ end = ZV;
+ annotations = Qnil;
+ }
+ Flength (res);
+ annotations = merge (annotations, res, Qcar_less_than_car);
+ p = Fcdr (p);
+ }
UNGCPRO;
return annotations;
}
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,
return
Fwrite_region (Qnil, Qnil,
current_buffer->auto_save_file_name,
- Qnil, Qlambda);
+ Qnil, Qlambda, Qnil);
}
static Lisp_Object
do_auto_save_unwind (desc) /* used as unwind-protect function */
Lisp_Object desc;
{
+ auto_saving = 0;
close (XINT (desc));
return Qnil;
}
/* 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;
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
autosave perfectly ordinary files because it couldn't handle some
ange-ftp'd file. */
for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
- for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
- tail = XCONS (tail)->cdr)
+ for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
{
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. */
+ 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);
&& b != current_buffer)
continue;
+ /* Don't auto-save indirect buffers.
+ The base buffer takes care of it. */
+ if (b->base_buffer)
+ continue;
+
/* Check for auto save enabled
and file changed since last auto save
and file changed since last real save. */
if (STRINGP (b->auto_save_file_name)
- && b->save_modified < BUF_MODIFF (b)
+ && BUF_SAVE_MODIFF (b) < 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
Vquit_flag = oquit;
- auto_saving = 0;
unbind_to (count, Qnil);
return Qnil;
}
"Return t if buffer has been auto-saved since last read in or saved.")
()
{
- return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
+ return (SAVE_MODIFF < current_buffer->auto_save_modified) ? Qt : Qnil;
}
\f
/* Reading and completing file names */
{
Lisp_Object name, specdir, realdir, val, orig_string;
int changed;
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
realdir = dir;
name = string;
specdir = Qnil;
changed = 0;
/* No need to protect ACTION--we only compare it with t and nil. */
- GCPRO4 (string, realdir, name, specdir);
+ GCPRO5 (string, realdir, name, specdir, orig_string);
if (XSTRING (string)->size == 0)
{
syms_of_fileio ()
{
Qexpand_file_name = intern ("expand-file-name");
+ Qsubstitute_in_file_name = intern ("substitute-in-file-name");
Qdirectory_file_name = intern ("directory-file-name");
Qfile_name_directory = intern ("file-name-directory");
Qfile_name_nondirectory = intern ("file-name-nondirectory");
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");
Qset_visited_file_modtime = intern ("set-visited-file-modtime");
staticpro (&Qexpand_file_name);
+ staticpro (&Qsubstitute_in_file_name);
staticpro (&Qdirectory_file_name);
staticpro (&Qfile_name_directory);
staticpro (&Qfile_name_nondirectory);
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);
staticpro (&Qfind_buffer_file_type);
#endif /* DOS_NT */
+ DEFVAR_LISP ("auto-save-file-format", &Vauto_save_file_format,
+ "*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.");
+ Vauto_save_file_format = Qt;
+
+ Qformat_decode = intern ("format-decode");
+ staticpro (&Qformat_decode);
+ Qformat_annotate_function = intern ("format-annotate-function");
+ staticpro (&Qformat_annotate_function);
+
Qcar_less_than_car = intern ("car-less-than-car");
staticpro (&Qcar_less_than_car);
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.");
+ "File name in which we write a list of all auto save file names.\n\
+This variable is initialized automatically from `auto-save-list-file-prefix'\n\
+shortly after Emacs reads your `.emacs' file, if you have not yet given it\n\
+a non-nil value.");
Vauto_save_list_file_name = Qnil;
defsubr (&Sfind_file_name_handler);