From 954b166e9037de5fdd43b4fbe7b8c73a36ac402e Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 9 Jul 2013 23:26:23 -0700 Subject: [PATCH] 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 --- doc/lispref/ChangeLog | 5 +++++ doc/lispref/text.texi | 12 +++++++---- etc/ChangeLog | 5 +++++ etc/NEWS | 6 ++++++ lisp/ChangeLog | 5 +++++ lisp/files.el | 5 +++++ src/ChangeLog | 18 +++++++++++++++++ src/atimer.c | 2 +- src/buffer.c | 5 +++++ src/fileio.c | 46 ++++++++++++++++++------------------------- src/systime.h | 23 ++++++---------------- src/undo.c | 7 +++---- 12 files changed, 86 insertions(+), 53 deletions(-) diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index e4bc6eb5bc..f8b7406c42 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,8 @@ +2013-07-10 Paul Eggert + + Timestamp fixes for undo (Bug#14824). + * text.texi (Undo): Document (t . 0) and (t . -1) in buffer-undo-list. + 2013-07-06 Eli Zaretskii * nonascii.texi (Text Representations): Document that diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index c10458b39a..7cace70ad0 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -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 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 -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 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; -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}) This kind of element records a change in a text property. diff --git a/etc/ChangeLog b/etc/ChangeLog index 843f176a6a..9ed1b6e0df 100644 --- a/etc/ChangeLog +++ b/etc/ChangeLog @@ -1,3 +1,8 @@ +2013-07-10 Paul Eggert + + Timestamp fixes for undo (Bug#14824). + * NEWS: Changes to visited-file-modtime, set-visited-file-modtime. + 2013-07-08 Jan Djärv * NEWS: NS can be build with ImageMagick. diff --git a/etc/NEWS b/etc/NEWS index 1c81c8329a..6dd89fcd4d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -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 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 @@ -613,6 +616,9 @@ Emacs uses `image-default-frame-delay'. *** New functions `image-current-frame' and `image-show-frame' for getting 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. ** New function special-form-p. ** Docstrings can be made dynamic by adding a `dynamic-docstring-function' diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 3b7d95837b..91ce836617 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2013-07-10 Paul Eggert + + Timestamp fixes for undo (Bug#14824). + * files.el (clear-visited-file-modtime): Move here from fileio.c. + 2013-07-10 Leo Liu * files.el (require-final-newline): Allow safe local value. diff --git a/lisp/files.el b/lisp/files.el index a8ccf81fa1..26f229ec98 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -4918,6 +4918,11 @@ change the additional actions you can take on files." (length 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) "Mark current buffer as unmodified, not needing to be saved. With prefix ARG, mark buffer as modified, so \\[save-buffer] will save. diff --git a/src/ChangeLog b/src/ChangeLog index a96f1153ef..049c917edd 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,21 @@ +2013-07-10 Paul Eggert + + 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 * sheap.c (STATIC_HEAP_SIZE) [__x86_64__]: Increase to 18MB. diff --git a/src/atimer.c b/src/atimer.c index 73c7aa5686..bb5294670d 100644 --- a/src/atimer.c +++ b/src/atimer.c @@ -336,7 +336,7 @@ schedule_atimer (struct atimer *t) struct atimer *a = atimers, *prev = NULL; /* 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; /* Insert T in front of the atimer found, if any. */ diff --git a/src/buffer.c b/src/buffer.c index 94104ef535..81768849a4 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -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 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 was modified between BEG and END. PROPERTY is the property name, and VALUE is the old value. diff --git a/src/fileio.c b/src/fileio.c index d030c78c42..cb863410cc 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3345,7 +3345,7 @@ otherwise, if FILE2 does not exist, the answer is t. */) if (stat (SSDATA (absname2), &st2) < 0) 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); } @@ -5375,36 +5375,19 @@ See Info node `(elisp)Modification Time' for more details. */) 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, Svisited_file_modtime, 0, 0, 0, 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 `file-attributes' returns. If the current buffer has no recorded 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. */) (void) { - if (EMACS_NSECS (current_buffer->modtime) < 0) - { - if (EMACS_NSECS (current_buffer->modtime) == NONEXISTENT_MODTIME_NSECS) - { - /* make_lisp_time won't work here if time_t is unsigned. */ - return list4i (-1, 65535, 0, 0); - } - return make_number (0); - } + int ns = EMACS_NSECS (current_buffer->modtime); + if (ns < 0) + return make_number (UNKNOWN_MODTIME_NSECS - ns); return make_lisp_time (current_buffer->modtime); } @@ -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. An argument specifies the modification time value to use \(instead of that of the visited file), in the form of a list -\(HIGH LOW USEC PSEC) as returned by `current-time'. */) - (Lisp_Object time_list) +\(HIGH LOW USEC PSEC) or an integer flag as returned by +`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; } else @@ -6121,7 +6114,6 @@ This includes interactive calls to `delete-file' and defsubr (&Swrite_region); defsubr (&Scar_less_than_car); defsubr (&Sverify_visited_file_modtime); - defsubr (&Sclear_visited_file_modtime); defsubr (&Svisited_file_modtime); defsubr (&Sset_visited_file_modtime); defsubr (&Sdo_auto_save); diff --git a/src/systime.h b/src/systime.h index c3bc00c147..df733b290c 100644 --- a/src/systime.h +++ b/src/systime.h @@ -67,7 +67,9 @@ SYSTIME_INLINE time_t *emacs_secs_addr (EMACS_TIME *t) { return &t->tv_sec; } SYSTIME_INLINE EMACS_TIME 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; } @@ -75,7 +77,9 @@ make_emacs_time (time_t s, int ns) SYSTIME_INLINE EMACS_TIME invalid_emacs_time (void) { - EMACS_TIME r = { 0, -1 }; + EMACS_TIME r; + r.tv_sec = 0; + r.tv_nsec = -1; return r; } @@ -166,21 +170,6 @@ EMACS_TIME_EQ (EMACS_TIME t1, EMACS_TIME t2) return timespec_cmp (t1, t2) == 0; } 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) { return timespec_cmp (t1, t2) < 0; diff --git a/src/undo.c b/src/undo.c index d8711882fb..234b8510f0 100644 --- a/src/undo.c +++ b/src/undo.c @@ -229,10 +229,9 @@ record_first_change (void) if (base_buffer->base_buffer) base_buffer = base_buffer->base_buffer; - bset_undo_list - (current_buffer, - Fcons (Fcons (Qt, make_lisp_time (base_buffer->modtime)), - BVAR (current_buffer, undo_list))); + bset_undo_list (current_buffer, + Fcons (Fcons (Qt, Fvisited_file_modtime ()), + BVAR (current_buffer, undo_list))); } /* Record a change in property PROP (whose old value was VAL) -- 2.20.1