From 155f9a94081f59310d26c20842d107411b9df5c9 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 3 Sep 1996 18:16:06 +0000 Subject: [PATCH] (timer-next-integral-multiple-of-time): New function. (run-at-time): If TIME is t, do the action at the next integral multiple of REPEAT. --- lisp/timer.el | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/lisp/timer.el b/lisp/timer.el index b3f1283d56b..b728aeda287 100644 --- a/lisp/timer.el +++ b/lisp/timer.el @@ -70,6 +70,36 @@ fire each time Emacs is idle for that many seconds." (aset timer 4 repeat) timer) +(defun timer-next-integral-multiple-of-time (time secs) + "Yield the next value after TIME that is an integral number of SECS +since the epoch. SECS may be a fraction." + (let ((time-base (ash 1 16))) + (if (fboundp 'atan) + ;; Use floating point, taking care to not lose precision. + (let* ((float-time-base (float time-base)) + (million 1000000.0) + (time-usec (+ (* million + (+ (* float-time-base (nth 0 time)) + (nth 1 time))) + (nth 2 time))) + (secs-usec (* million secs)) + (mod-usec (mod time-usec secs-usec)) + (next-usec (+ (- time-usec mod-usec) secs-usec)) + (time-base-million (* float-time-base million))) + (list (floor next-usec time-base-million) + (floor (mod next-usec time-base-million) million) + (floor (mod next-usec million)))) + ;; Floating point is not supported. + ;; Use integer arithmetic, avoiding overflow if possible. + (let* ((mod-sec (mod (+ (* (mod time-base secs) + (mod (nth 0 time) secs)) + (nth 1 time)) + secs)) + (next-1-sec (+ (- (nth 1 time) mod-sec) secs))) + (list (+ (nth 0 time) (floor next-1-sec time-base)) + (mod next-1-sec time-base) + 0))))) + (defun timer-relative-time (time secs &optional usecs) "Advance TIME by SECS seconds and optionally USECS microseconds. SECS may be a fraction." @@ -248,17 +278,26 @@ fire repeatedly that many seconds apart." "Perform an action at time TIME. Repeat the action every REPEAT seconds, if REPEAT is non-nil. TIME should be a string like \"11:23pm\", nil meaning now, a number of seconds -from now, or a value from `encode-time'. +from now, a value from `current-time', or t (with non-nil REPEAT) +meaning the next integral multiple of REPEAT. REPEAT may be an integer or floating point number. The action is to call FUNCTION with arguments ARGS. This function returns a timer object which you can use in `cancel-timer'." (interactive "sRun at time: \nNRepeat interval: \naFunction: ") + (or (null repeat) + (and (numberp repeat) (< 0 repeat)) + (error "Invalid repetition interval")) + ;; Special case: nil means "now" and is useful when repeating. (if (null time) (setq time (current-time))) + ;; Special case: t means the next integral multiple of REPEAT. + (if (and (eq time t) repeat) + (setq time (timer-next-integral-multiple-of-time (current-time) repeat))) + ;; Handle numbers as relative times in seconds. (if (numberp time) (setq time (timer-relative-time (current-time) time))) @@ -285,10 +324,6 @@ This function returns a timer object which you can use in `cancel-timer'." (or (consp time) (error "Invalid time format")) - (or (null repeat) - (numberp repeat) - (error "Invalid repetition interval")) - (let ((timer (timer-create))) (timer-set-time timer time repeat) (timer-set-function timer function args) -- 2.39.2