changeset 16085:b215fb935fc3

(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.
author Paul Eggert <eggert@twinsun.com>
date Tue, 03 Sep 1996 18:16:06 +0000
parents c477472563dd
children 33519c691e63
files lisp/timer.el
diffstat 1 files changed, 40 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/timer.el	Tue Sep 03 18:16:06 1996 +0000
+++ b/lisp/timer.el	Tue Sep 03 18:16:06 1996 +0000
@@ -70,6 +70,36 @@
   (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 @@
   "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 @@
   (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)