diff --git a/io.lisp b/io.lisp index 20b89122d763c7cb746093d849e4419473b0e81e..aaac474b1c8936d8204da6e9c2ecfdaa39805ee6 100644 --- a/io.lisp +++ b/io.lisp @@ -3,28 +3,30 @@ (in-package :alexandria) -(eval-when (:compile-toplevel :load-toplevel :execute) - (defun %expand-with-input/output-file (body direction stream-name file-name - &rest args - &key external-format - &allow-other-keys) - (remove-from-plistf args :external-format) - (with-unique-names (body-fn) - (once-only (external-format) - `(flet ((,body-fn (,stream-name) - ,@body)) - ;; this is needed not to screw up the default external-format when not specified - (if ,external-format - (with-open-file (,stream-name ,file-name :direction ,direction - :external-format ,external-format - ,@args) - (,body-fn ,stream-name)) - (with-open-file (,stream-name ,file-name :direction ,direction ,@args) - (,body-fn ,stream-name)))))))) +(defmacro with-open-file* ((stream filespec &key direction element-type + if-exists if-does-not-exist external-format) + &body body) + "Just like WITH-OPEN-FILE, but NIL values in the keyword arguments mean to use +the default value specified for OPEN." + (once-only (direction element-type if-exists if-does-not-exist external-format) + `(with-open-stream + (,stream (apply #'open ,filespec + (append + (when ,direction + (list :direction ,direction)) + (when ,element-type + (list :element-type ,element-type)) + (when ,if-exists + (list :if-exists ,if-exists)) + (when ,if-does-not-exist + (list :if-does-not-exist ,if-does-not-exist)) + (when ,external-format + (list :external-format ,external-format))))) + ,@body))) (defmacro with-input-from-file ((stream-name file-name &rest args &key (direction nil direction-p) - &allow-other-keys) + &allow-other-keys) &body body) "Evaluate BODY with STREAM-NAME to an input stream on the file FILE-NAME. ARGS is sent as is to the call to OPEN except EXTERNAL-FORMAT, @@ -32,11 +34,12 @@ which is only sent to WITH-OPEN-FILE when it's not NIL." (declare (ignore direction)) (when direction-p (error "Can't specifiy :DIRECTION for WITH-INPUT-FROM-FILE.")) - (apply '%expand-with-input/output-file body :input stream-name file-name args)) + `(with-open-file* (,stream-name ,file-name :direction :input ,@args) + ,@body)) (defmacro with-output-to-file ((stream-name file-name &rest args &key (direction nil direction-p) - &allow-other-keys) + &allow-other-keys) &body body) "Evaluate BODY with STREAM-NAME to an output stream on the file FILE-NAME. ARGS is sent as is to the call to OPEN except EXTERNAL-FORMAT, @@ -44,7 +47,8 @@ which is only sent to WITH-OPEN-FILE when it's not NIL." (declare (ignore direction)) (when direction-p (error "Can't specifiy :DIRECTION for WITH-OUTPUT-TO-FILE.")) - (apply '%expand-with-input/output-file body :output stream-name file-name args)) + `(with-open-file* (,stream-name ,file-name :direction :output ,@args) + ,@body)) (defun read-file-into-string (pathname &key (buffer-size 4096) external-format) "Return the contents of the file denoted by PATHNAME as a fresh string. @@ -62,15 +66,15 @@ unless it's NIL, which means the system default." :while (= bytes-read buffer-size))))))) (defun write-string-into-file (string pathname &key (if-exists :error) - (if-does-not-exist :error) + if-does-not-exist external-format) "Write STRING to PATHNAME. The EXTERNAL-FORMAT parameter will be passed directly to WITH-OPEN-FILE unless it's NIL, which means the system default." (with-output-to-file (file-stream pathname :if-exists if-exists - :if-does-not-exist if-does-not-exist - :external-format external-format) + :if-does-not-exist if-does-not-exist + :external-format external-format) (write-sequence string file-stream))) (defun copy-file (from to &key (if-to-exists :supersede)