Commit 954b166e authored by Paul Eggert's avatar Paul Eggert

Timestamp fixes for undo.

* doc/lispref/text.texi (Undo):
Document (t . 0) and (t . -1) in buffer-undo-list.
* etc/NEWS: Changes to visited-file-modtime, set-visited-file-modtime.
* lisp/files.el (clear-visited-file-modtime): Move here from fileio.c.
* src/atimer.c (schedule_atimer):
* src/fileio.c (Ffile_newer_than_file_p):
Minor cleanup: use EMACS_TIME_LT so that we can remove EMACS_TIME_GT.
* src/buffer.c (buffer-undo-list): Document (t . 0) and (t . -1).
* src/fileio.c (Fclear_visited_file_modtime): Move to lisp/files.el.
(syms_of_fileio): Remove Sclear_visited_file_name.
(Fvisited_file_modtime): Return -1, not (-1 ...), when the visited
file doesn't exist; this avoids an ambiguity with negative timestamps.
(Fset_visited_file_modtime): Accept -1 and 0 as time-list arg.
* src/systime.h (make_emacs_time, invalid_emacs_time):
Don't assume struct timespec layout; POSIX doesn't guarantee it.
(EMACS_TIME_NE, EMACS_TIME_GT, EMACS_TIME_GE): Remove.
* src/undo.c (record_first_change): Push (visited-file-modtime) onto
undo list rather than reimplementing it by hand, incorrectly.

Fixes: debbugs:14824
parent 56973319
2013-07-10 Paul Eggert <eggert@cs.ucla.edu>
Timestamp fixes for undo (Bug#14824).
* text.texi (Undo): Document (t . 0) and (t . -1) in buffer-undo-list.
2013-07-06 Eli Zaretskii <eliz@gnu.org> 2013-07-06 Eli Zaretskii <eliz@gnu.org>
* nonascii.texi (Text Representations): Document that * nonascii.texi (Text Representations): Document that
......
...@@ -1250,14 +1250,18 @@ reinsert it is @code{(abs @var{position})}. If @var{position} is ...@@ -1250,14 +1250,18 @@ reinsert it is @code{(abs @var{position})}. If @var{position} is
positive, point was at the beginning of the deleted text, otherwise it positive, point was at the beginning of the deleted text, otherwise it
was at the end. was at the end.
@item (t @var{sec-high} @var{sec-low} @var{microsec} @var{picosec}) @item (t . @var{time-flag})
This kind of element indicates that an unmodified buffer became This kind of element indicates that an unmodified buffer became
modified. The list @code{(@var{sec-high} @var{sec-low} @var{microsec} modified. A @var{time-flag} of the form
@code{(@var{sec-high} @var{sec-low} @var{microsec}
@var{picosec})} represents the visited file's modification time as of @var{picosec})} represents the visited file's modification time as of
when it was previously visited or saved, using the same format as when it was previously visited or saved, using the same format as
@code{current-time}; see @ref{Time of Day}. @code{primitive-undo} uses those @code{current-time}; see @ref{Time of Day}.
A @var{time-flag} of 0 means the buffer does not correspond to any file;
@minus{}1 means the visited file previously did not exist.
@code{primitive-undo} uses these
values to determine whether to mark the buffer as unmodified once again; values to determine whether to mark the buffer as unmodified once again;
it does so only if the file's modification time matches those numbers. it does so only if the file's status matches that of @var{time-flag}.
@item (nil @var{property} @var{value} @var{beg} . @var{end}) @item (nil @var{property} @var{value} @var{beg} . @var{end})
This kind of element records a change in a text property. This kind of element records a change in a text property.
......
2013-07-10 Paul Eggert <eggert@cs.ucla.edu>
Timestamp fixes for undo (Bug#14824).
* NEWS: Changes to visited-file-modtime, set-visited-file-modtime.
2013-07-08 Jan Djärv <jan.h.d@swipnet.se> 2013-07-08 Jan Djärv <jan.h.d@swipnet.se>
* NEWS: NS can be build with ImageMagick. * NEWS: NS can be build with ImageMagick.
......
...@@ -537,6 +537,9 @@ alist of extended attributes as returned by the new function ...@@ -537,6 +537,9 @@ alist of extended attributes as returned by the new function
`file-extended-attributes'. The attributes can be applied to another `file-extended-attributes'. The attributes can be applied to another
file using `set-file-extended-attributes'. file using `set-file-extended-attributes'.
** `visited-file-modtime' now returns -1 for nonexistent files.
Formerly it returned a list (-1 LOW USEC PSEC), but this was ambiguous
in the presence of files with negative time stamps.
* Lisp Changes in Emacs 24.4 * Lisp Changes in Emacs 24.4
...@@ -613,6 +616,9 @@ Emacs uses `image-default-frame-delay'. ...@@ -613,6 +616,9 @@ Emacs uses `image-default-frame-delay'.
*** New functions `image-current-frame' and `image-show-frame' for getting *** New functions `image-current-frame' and `image-show-frame' for getting
and setting the current frame of a multi-frame image. and setting the current frame of a multi-frame image.
** The function `set-visited-file-modtime' now accepts a 0 or -1 argument
with the same interpretation as the returned value of `visited-file-modtime'.
** time-to-seconds is not obsolete any more. ** time-to-seconds is not obsolete any more.
** New function special-form-p. ** New function special-form-p.
** Docstrings can be made dynamic by adding a `dynamic-docstring-function' ** Docstrings can be made dynamic by adding a `dynamic-docstring-function'
......
2013-07-10 Paul Eggert <eggert@cs.ucla.edu>
Timestamp fixes for undo (Bug#14824).
* files.el (clear-visited-file-modtime): Move here from fileio.c.
2013-07-10 Leo Liu <sdl.web@gmail.com> 2013-07-10 Leo Liu <sdl.web@gmail.com>
* files.el (require-final-newline): Allow safe local value. * files.el (require-final-newline): Allow safe local value.
......
...@@ -4918,6 +4918,11 @@ change the additional actions you can take on files." ...@@ -4918,6 +4918,11 @@ change the additional actions you can take on files."
(length autosaved-buffers) (length autosaved-buffers)
(mapconcat 'identity autosaved-buffers ", ")))))))) (mapconcat 'identity autosaved-buffers ", "))))))))
(defun clear-visited-file-modtime ()
"Clear out records of last mod time of visited file.
Next attempt to save will certainly not complain of a discrepancy."
(set-visited-file-modtime 0))
(defun not-modified (&optional arg) (defun not-modified (&optional arg)
"Mark current buffer as unmodified, not needing to be saved. "Mark current buffer as unmodified, not needing to be saved.
With prefix ARG, mark buffer as modified, so \\[save-buffer] will save. With prefix ARG, mark buffer as modified, so \\[save-buffer] will save.
......
2013-07-10 Paul Eggert <eggert@cs.ucla.edu>
Timestamp fixes for undo (Bug#14824).
* atimer.c (schedule_atimer):
* fileio.c (Ffile_newer_than_file_p):
Minor cleanup: use EMACS_TIME_LT so that we can remove EMACS_TIME_GT.
* buffer.c (buffer-undo-list): Document (t . 0) and (t . -1).
* fileio.c (Fclear_visited_file_modtime): Move to lisp/files.el.
(syms_of_fileio): Remove Sclear_visited_file_name.
(Fvisited_file_modtime): Return -1, not (-1 ...), when the visited
file doesn't exist; this avoids an ambiguity with negative timestamps.
(Fset_visited_file_modtime): Accept -1 and 0 as time-list arg.
* systime.h (make_emacs_time, invalid_emacs_time):
Don't assume struct timespec layout; POSIX doesn't guarantee it.
(EMACS_TIME_NE, EMACS_TIME_GT, EMACS_TIME_GE): Remove.
* undo.c (record_first_change): Push (visited-file-modtime) onto
undo list rather than reimplementing it by hand, incorrectly.
2013-07-09 Ken Brown <kbrown@cornell.edu> 2013-07-09 Ken Brown <kbrown@cornell.edu>
* sheap.c (STATIC_HEAP_SIZE) [__x86_64__]: Increase to 18MB. * sheap.c (STATIC_HEAP_SIZE) [__x86_64__]: Increase to 18MB.
......
...@@ -336,7 +336,7 @@ schedule_atimer (struct atimer *t) ...@@ -336,7 +336,7 @@ schedule_atimer (struct atimer *t)
struct atimer *a = atimers, *prev = NULL; struct atimer *a = atimers, *prev = NULL;
/* Look for the first atimer that is ripe after T. */ /* Look for the first atimer that is ripe after T. */
while (a && EMACS_TIME_GT (t->expiration, a->expiration)) while (a && EMACS_TIME_LT (a->expiration, t->expiration))
prev = a, a = a->next; prev = a, a = a->next;
/* Insert T in front of the atimer found, if any. */ /* Insert T in front of the atimer found, if any. */
......
...@@ -6095,6 +6095,11 @@ and is the visited file's modification time, as of that time. If the ...@@ -6095,6 +6095,11 @@ and is the visited file's modification time, as of that time. If the
modification time of the most recent save is different, this entry is modification time of the most recent save is different, this entry is
obsolete. obsolete.
An entry (t . 0) means means the buffer was previously unmodified but
its time stamp was unknown because it was not associated with a file.
An entry (t . -1) is similar, except that it means the buffer's visited
file did not exist.
An entry (nil PROPERTY VALUE BEG . END) indicates that a text property An entry (nil PROPERTY VALUE BEG . END) indicates that a text property
was modified between BEG and END. PROPERTY is the property name, was modified between BEG and END. PROPERTY is the property name,
and VALUE is the old value. and VALUE is the old value.
......
...@@ -3345,7 +3345,7 @@ otherwise, if FILE2 does not exist, the answer is t. */) ...@@ -3345,7 +3345,7 @@ otherwise, if FILE2 does not exist, the answer is t. */)
if (stat (SSDATA (absname2), &st2) < 0) if (stat (SSDATA (absname2), &st2) < 0)
return Qt; return Qt;
return (EMACS_TIME_GT (get_stat_mtime (&st1), get_stat_mtime (&st2)) return (EMACS_TIME_LT (get_stat_mtime (&st2), get_stat_mtime (&st1))
? Qt : Qnil); ? Qt : Qnil);
} }
...@@ -5375,36 +5375,19 @@ See Info node `(elisp)Modification Time' for more details. */) ...@@ -5375,36 +5375,19 @@ See Info node `(elisp)Modification Time' for more details. */)
return Qnil; return Qnil;
} }
DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
Sclear_visited_file_modtime, 0, 0, 0,
doc: /* Clear out records of last mod time of visited file.
Next attempt to save will certainly not complain of a discrepancy. */)
(void)
{
current_buffer->modtime = make_emacs_time (0, UNKNOWN_MODTIME_NSECS);
current_buffer->modtime_size = -1;
return Qnil;
}
DEFUN ("visited-file-modtime", Fvisited_file_modtime, DEFUN ("visited-file-modtime", Fvisited_file_modtime,
Svisited_file_modtime, 0, 0, 0, Svisited_file_modtime, 0, 0, 0,
doc: /* Return the current buffer's recorded visited file modification time. doc: /* Return the current buffer's recorded visited file modification time.
The value is a list of the form (HIGH LOW USEC PSEC), like the time values that The value is a list of the form (HIGH LOW USEC PSEC), like the time values that
`file-attributes' returns. If the current buffer has no recorded file `file-attributes' returns. If the current buffer has no recorded file
modification time, this function returns 0. If the visited file modification time, this function returns 0. If the visited file
doesn't exist, HIGH will be -1. doesn't exist, return -1.
See Info node `(elisp)Modification Time' for more details. */) See Info node `(elisp)Modification Time' for more details. */)
(void) (void)
{ {
if (EMACS_NSECS (current_buffer->modtime) < 0) int ns = EMACS_NSECS (current_buffer->modtime);
{ if (ns < 0)
if (EMACS_NSECS (current_buffer->modtime) == NONEXISTENT_MODTIME_NSECS) return make_number (UNKNOWN_MODTIME_NSECS - ns);
{
/* make_lisp_time won't work here if time_t is unsigned. */
return list4i (-1, 65535, 0, 0);
}
return make_number (0);
}
return make_lisp_time (current_buffer->modtime); return make_lisp_time (current_buffer->modtime);
} }
...@@ -5415,12 +5398,22 @@ Useful if the buffer was not read from the file normally ...@@ -5415,12 +5398,22 @@ Useful if the buffer was not read from the file normally
or if the file itself has been changed for some known benign reason. or if the file itself has been changed for some known benign reason.
An argument specifies the modification time value to use An argument specifies the modification time value to use
\(instead of that of the visited file), in the form of a list \(instead of that of the visited file), in the form of a list
\(HIGH LOW USEC PSEC) as returned by `current-time'. */) \(HIGH LOW USEC PSEC) or an integer flag as returned by
(Lisp_Object time_list) `visited-file-modtime'. */)
(Lisp_Object time_flag)
{ {
if (!NILP (time_list)) if (!NILP (time_flag))
{ {
current_buffer->modtime = lisp_time_argument (time_list); EMACS_TIME mtime;
if (INTEGERP (time_flag))
{
CHECK_RANGED_INTEGER (time_flag, -1, 0);
mtime = make_emacs_time (0, UNKNOWN_MODTIME_NSECS - XINT (time_flag));
}
else
mtime = lisp_time_argument (time_flag);
current_buffer->modtime = mtime;
current_buffer->modtime_size = -1; current_buffer->modtime_size = -1;
} }
else else
...@@ -6121,7 +6114,6 @@ This includes interactive calls to `delete-file' and ...@@ -6121,7 +6114,6 @@ This includes interactive calls to `delete-file' and
defsubr (&Swrite_region); defsubr (&Swrite_region);
defsubr (&Scar_less_than_car); defsubr (&Scar_less_than_car);
defsubr (&Sverify_visited_file_modtime); defsubr (&Sverify_visited_file_modtime);
defsubr (&Sclear_visited_file_modtime);
defsubr (&Svisited_file_modtime); defsubr (&Svisited_file_modtime);
defsubr (&Sset_visited_file_modtime); defsubr (&Sset_visited_file_modtime);
defsubr (&Sdo_auto_save); defsubr (&Sdo_auto_save);
......
...@@ -67,7 +67,9 @@ SYSTIME_INLINE time_t *emacs_secs_addr (EMACS_TIME *t) { return &t->tv_sec; } ...@@ -67,7 +67,9 @@ SYSTIME_INLINE time_t *emacs_secs_addr (EMACS_TIME *t) { return &t->tv_sec; }
SYSTIME_INLINE EMACS_TIME SYSTIME_INLINE EMACS_TIME
make_emacs_time (time_t s, int ns) make_emacs_time (time_t s, int ns)
{ {
EMACS_TIME r = { s, ns }; EMACS_TIME r;
r.tv_sec = s;
r.tv_nsec = ns;
return r; return r;
} }
...@@ -75,7 +77,9 @@ make_emacs_time (time_t s, int ns) ...@@ -75,7 +77,9 @@ make_emacs_time (time_t s, int ns)
SYSTIME_INLINE EMACS_TIME SYSTIME_INLINE EMACS_TIME
invalid_emacs_time (void) invalid_emacs_time (void)
{ {
EMACS_TIME r = { 0, -1 }; EMACS_TIME r;
r.tv_sec = 0;
r.tv_nsec = -1;
return r; return r;
} }
...@@ -166,21 +170,6 @@ EMACS_TIME_EQ (EMACS_TIME t1, EMACS_TIME t2) ...@@ -166,21 +170,6 @@ EMACS_TIME_EQ (EMACS_TIME t1, EMACS_TIME t2)
return timespec_cmp (t1, t2) == 0; return timespec_cmp (t1, t2) == 0;
} }
SYSTIME_INLINE int SYSTIME_INLINE int
EMACS_TIME_NE (EMACS_TIME t1, EMACS_TIME t2)
{
return timespec_cmp (t1, t2) != 0;
}
SYSTIME_INLINE int
EMACS_TIME_GT (EMACS_TIME t1, EMACS_TIME t2)
{
return timespec_cmp (t1, t2) > 0;
}
SYSTIME_INLINE int
EMACS_TIME_GE (EMACS_TIME t1, EMACS_TIME t2)
{
return timespec_cmp (t1, t2) >= 0;
}
SYSTIME_INLINE int
EMACS_TIME_LT (EMACS_TIME t1, EMACS_TIME t2) EMACS_TIME_LT (EMACS_TIME t1, EMACS_TIME t2)
{ {
return timespec_cmp (t1, t2) < 0; return timespec_cmp (t1, t2) < 0;
......
...@@ -229,10 +229,9 @@ record_first_change (void) ...@@ -229,10 +229,9 @@ record_first_change (void)
if (base_buffer->base_buffer) if (base_buffer->base_buffer)
base_buffer = base_buffer->base_buffer; base_buffer = base_buffer->base_buffer;
bset_undo_list bset_undo_list (current_buffer,
(current_buffer, Fcons (Fcons (Qt, Fvisited_file_modtime ()),
Fcons (Fcons (Qt, make_lisp_time (base_buffer->modtime)), BVAR (current_buffer, undo_list)));
BVAR (current_buffer, undo_list)));
} }
/* Record a change in property PROP (whose old value was VAL) /* Record a change in property PROP (whose old value was VAL)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment