;;; temp-file.lisp --- temporary file creation

;;;  Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 by Walter C. Pelissero
;;;  Copyright (C) 2022 The TVL Authors

;;;  Author: Walter C. Pelissero <walter@pelissero.de>
;;;  Project: mime4cl
;;;
;;;  Code taken from SCLF

#+cmu (ext:file-comment "$Module: temp-file.lisp $")

;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU Lesser General Public License
;;; as published by the Free Software Foundation; either version 2.1
;;; of the License, or (at your option) any later version.
;;; This library is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; Lesser General Public License for more details.
;;; You should have received a copy of the GNU Lesser General Public
;;; License along with this library; if not, write to the Free
;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
;;; 02111-1307 USA

(in-package :mime4cl-tests)

(defvar *tmp-file-defaults* #P"/tmp/")

(defun temp-file-name (&optional (default *tmp-file-defaults*))
  "Create a random pathname based on DEFAULT.  No effort is made
to make sure that the returned pathname doesn't identify an
already existing file.  If missing DEFAULT defaults to
*TMP-FILE-DEFAULTS*."
  (make-pathname :defaults default
                 :name (format nil "~36R" (random #.(expt 36 10)))))

(defun open-temp-file (&optional default-pathname &rest open-args)
  "Open a new temporary file and return a stream to it.  This function
makes sure the pathname of the temporary file is unique.  OPEN-ARGS
are arguments passed verbatim to OPEN.  If OPEN-ARGS specify
the :DIRECTION it should be either :OUTPUT (default) or :IO;
any other value causes an error.  If DEFAULT-PATHNAME is specified and
not NIL it's used as defaults to produce the pathname of the temporary
file, otherwise *TMP-FILE-DEFAULTS* is used."
  (unless default-pathname
    (setf default-pathname *tmp-file-defaults*))
  ;; if :DIRECTION is specified check that it's compatible with the
  ;; purpose of this function, otherwise make it default to :OUTPUT
  (aif (getf open-args :direction)
       (unless (member it '(:output :io))
         (error "Can't create temporary file with open direction ~A." it))
       (setf open-args (append '(:direction :output)
                               open-args)))
  (do* ((name #1=(temp-file-name default-pathname) #1#)
        (stream #2=(apply #'open  name
                          :if-exists nil
                          :if-does-not-exist :create
                          open-args) #2#))
       (stream stream)))

(defmacro with-temp-file ((stream &rest open-temp-args) &body body)
  "Execute BODY within a dynamic extent where STREAM is bound to
a STREAM open on a unique temporary file name.  OPEN-TEMP-ARGS are
passed verbatim to OPEN-TEMP-FILE."
  `(let ((,stream (open-temp-file ,@open-temp-args)))
     (unwind-protect
          (progn ,@body)
       (close ,stream)
       ;; body may decide to rename the file so we must ignore the errors
       (ignore-errors
         (delete-file (pathname ,stream))))))
