(defmacro with-staging-pathname ((pathname-var &optional (pathname-value pathname-var)) &body body)
`(call-with-staging-pathname ,pathname-value #'(lambda (,pathname-var) ,@body)))
+
+(defun* stamp< (x y)
+ (etypecase x
+ (null (and y t))
+ ((eql t) nil)
+ (real (etypecase y
+ (null nil)
+ ((eql t) t)
+ (real (< x y))))))
+;;(defun* stamps< (list) (loop :for y :in list :for x = nil :then y :always (stamp< x y)))
+;;(defun* stamp*< (&rest list) (stamps< list))
+(defun* stamp<= (x y) (not (stamp< y x)))
+(defun* earlier-stamp (x y) (if (stamp< x y) x y))
+(defun* stamps-earliest (list) (reduce 'earlier-stamp list :initial-value t))
+(defun* earliest-stamp (&rest list) (stamps-earliest list))
+(defun* later-stamp (x y) (if (stamp< x y) y x))
+(defun* stamps-latest (list) (reduce 'later-stamp list :initial-value nil))
+(defun* latest-stamp (&rest list) (stamps-latest list))
+(define-modify-macro latest-stamp-f (&rest stamps) latest-stamp)
+
+(defun* safe-file-write-date (pathname)
+ ;; If FILE-WRITE-DATE returns NIL, it's possible that
+ ;; the user or some other agent has deleted an input file.
+ ;; Also, generated files will not exist at the time planning is done
+ ;; and calls compute-action-stamp which calls safe-file-write-date.
+ ;; So it is very possible that we can't get a valid file-write-date,
+ ;; and we can survive and we will continue the planning
+ ;; as if the file were very old.
+ ;; (or should we treat the case in a different, special way?)
+ (and pathname (probe-file* pathname) (ignore-errors (file-write-date pathname))))