Sometimes it's desired to only do a certain cleanup operating in an UNWIND-PROTECT if a true transfer-of-control was issued in the protected-form.
UNWIND-PROTECT-CASE can be used to conveniently control on what circumstances cleanup operations are supposed to be performed.
(I think I've seen UNWIND-PROTECT-CASE on one of the Lisp machines, so it's actually prior art.)
-T.
(defmacro unwind-protect-case ((&optional abort-flag) protected-form &body clauses) "Like CL:UNWIND-PROTECT, but you can specify the circumstances that the cleanup CLAUSES are run.
ABORT-FLAG is the name of a variable that will be bound to T in CLAUSES if the PROTECTED-FORM aborted preemptively, and to NIL otherwise.
Examples:
(unwind-protect-case () (protected-form) (:normal (format t "This is only evaluated if PROTECTED-FORM executed normally.~%")) (:abort (format t "This is only evaluated if PROTECTED-FORM aborted preemptively.~%")) (:always (format t "This is evaluated in either case.~%")))
(unwind-protect-case (aborted-p) (protected-form) (:always (perform-cleanup-if aborted-p))) " (check-type abort-flag (or null symbol)) (let ((gflag (gensym "FLAG+"))) `(let ((,gflag t)) (unwind-protect (multiple-value-prog1 ,protected-form (setf ,gflag nil)) (let ,(and abort-flag `((,abort-flag ,gflag))) ,@(loop for (cleanup-kind . forms) in clauses collect (ecase cleanup-kind (:normal `(when (not ,gflag) ,@forms)) (:abort `(when ,gflag ,@forms)) (:always `(progn ,@forms)))))))))