diff --git a/docs/manual.scr b/docs/manual.scr index 7a5d16c..b2a2aae 100644 --- a/docs/manual.scr +++ b/docs/manual.scr @@ -220,6 +220,20 @@ some code should be executed based on the results of those bindings. @end(def) +@term(File macros) +@begin(def) + +These macros abstract common operations on files. + +@cl:with-package[name="kutils"]( +@cl:doc(macro read-file-string) +@cl:doc(macro with-string-output-to-file) +@cl:doc(macro with-read-from-file) +@cl:doc(macro with-write-to-file) +) + +@end(def) + @end(deflist) @end(section) @@ -251,10 +265,10 @@ described in "Miscellaneous utilities" under "General".) "On Lisp utilities".) @item(@c(condlet) is a macro defined in @c(macros.lisp), described in -"Macros".) +"Macros" under "Let macros".) @item(@c(condlet*) is a macro defined in @c(macros.lisp), described in -"Macros".) +"Macros" under "Let macros".) @item(@c(copy-hash-table) is a function defined in @c(kutils-hash-tables.lisp), described in "Hash-table related @@ -294,10 +308,10 @@ utilities".) utilities".) @item(@c(iflet) is a macro defined in @c(macros.lisp), described in -"Macros".) +"Macros" under "Let macros".) @item(@c(iflet*) is a macro defined in @c(macros.lisp), described in -"Macros".) +"Macros" under "Let macros".) @item(@c(interpose) is a function defined in @c(kutils.lisp), described in "Miscellaneous utilities" under "Clojure-inspired @@ -328,6 +342,9 @@ described in "Miscellaneous utilities" under "Vector-related".) @item(@c(partial) is a function defined in @c(kutils.lisp), described in "Miscellaneous utilities" under "Clojure-inspired functions".) +@item(@c(read-file-string) is a macro defined in @c(macros.lisp), +described in "Macros" under "File macros".) + @item(@c(sethash) is a macro defined in @c(kutils-hash-tables.lisp), described in "Hash-table related utilities".) @@ -338,21 +355,30 @@ Lisp utilities".) "Miscellaneous utilities" under "Clojure-inspired functions".) @item(@c(unlesslet) is a macro defined in @c(macros.lisp), described in -"Macros".) +"Macros" under "Let macros".) @item(@c(unlesslet*) is a macro defined in @c(macros.lisp), described in -"Macros".) +"Macros" under "Let macros".) @item(@c(whenlet) is a macro defined in @c(macros.lisp), described in -"Macros".) +"Macros" under "Let macros".) @item(@c(whenlet*) is a macro defined in @c(macros.lisp), described in -"Macros".) +"Macros" under "Let macros".) @item(@c(with-new-hash-table) is a macro defined in @c(kutils-hash-tables.lisp), described in "Hash-table related utilities".) +@item(@c(with-read-from-file) is a macro defined in @c(macros.lisp), +described in "Macros" under "File macros".) + +@item(@c(with-string-output-to-file) is a macro defined in @c(macros.lisp), +described in "Macros" under "File macros".) + +@item(@c(with-write-to-file) is a macro defined in @c(macros.lisp), +described in "Macros" under "File macros".) + @item(@c(zip) is a function defined in @c(kutils.lisp), described in "Miscellaneous utilities" under "General".) @@ -396,6 +422,7 @@ Alphabetical documentation for all exported symbols. @cl:doc(function new-hash-table) @cl:doc(function new-vector) @cl:doc(function partial) +@cl:doc(macro read-file-string) @cl:doc(macro sethash) @cl:doc(function symb) @cl:doc(function take) @@ -404,6 +431,9 @@ Alphabetical documentation for all exported symbols. @cl:doc(macro whenlet) @cl:doc(macro whenlet*) @cl:doc(macro with-new-hash-table) +@cl:doc(macro with-read-from-file) +@cl:doc(macro with-string-output-to-file) +@cl:doc(macro with-write-to-file) @cl:doc(function zip)) @end(section) diff --git a/kutils.lisp b/kutils.lisp index 9ea4857..46a18de 100644 --- a/kutils.lisp +++ b/kutils.lisp @@ -83,14 +83,6 @@ additional args provided to the lambda." (cons (mapcar #'car lsts) (zip-acc (mapcar #'cdr lsts)))))) (zip-acc lsts))) - -(defun read-file-string (path) - "Read the contents of the file at path as a string." - (with-open-file (s path) - (let ((data (make-string (file-length s)))) - (read-sequence data s) - data))) - (defun new-vector () "Create a new, empty, adjustable vector with fill pointer." (make-array 0 :adjustable t :fill-pointer t)) @@ -150,3 +142,5 @@ effectful code, such as logging." (lambda (&rest args) (dolist (fn fns) (apply fn args)))) + + diff --git a/macros.lisp b/macros.lisp index f6bcd3b..2e9f526 100644 --- a/macros.lisp +++ b/macros.lisp @@ -68,3 +68,50 @@ a @c(cond)." `(let (,@bindings) (cond ,@forms)))) +(defmacro! read-file-as-string (path &rest args &key (direction nil directionp) + &allow-other-keys) + "Read the contents of the file at @c(path) as a string. Any +remaining arguments are sent to @c(with-open-file)." + (when directionp + (error "Specifying :direction is not allowed with READ-FILE-STRING.")) + `(with-open-file (g!s ,path ,@args) + (let ((g!data (make-string (file-length g!s)))) + (read-sequence g!data g!s) + g!data))) + +(defmacro! with-string-output-to-file ((path &rest args &key (direction :output directionp) + &allow-other-keys) + &body body) + "Evaluate @c(body), and call @c(mkstr) on the result. Write the +resulting string to @c(path). Any remaining arguments are sent to +@c(with-open-file)." + (when directionp + (error "Specifying :direction is not allowed with WRITE-FILE-STRING.")) + `(with-open-file (g!s ,path :direction ,direction ,@args) + (with-standard-io-syntax + (let ((o!out (mkstr ,@body))) + (princ o!out g!s))))) + +(defmacro with-read-from-file (path &rest args &key (direction nil directionp) + &allow-other-keys) + "Read the form contained in @c(path), with any remaining arguments +passed to @c(with-open-file)." + (let ((s (gensym))) + (declare (ignore direction)) + (when directionp + (error "Specifying :direction is not allowed with READ-FILE.")) + `(with-open-file (,s ,path ,@args) + (with-standard-io-syntax + (read ,s))))) + +(defmacro with-write-to-file ((stream path &rest args + &key (direction :output directionp) + &allow-other-keys) + &body body) + "Evaluate @c(body) with the file at @c(path) opened and bound to the + value of @c(stream). Any remaining keyword arguments are passed to + @c(with-open-file)." + (when directionp + (error "Specifying :direction is not allowed with WRITE-FILE.")) + `(with-open-file (,stream ,path :direction ,direction ,@args) + ,@body)) diff --git a/package.lisp b/package.lisp index 8042db2..472fc22 100644 --- a/package.lisp +++ b/package.lisp @@ -50,4 +50,8 @@ #:iflet* #:condlet #:condlet* + #:read-file-string + #:with-string-output-to-file + #:with-read-from-file + #:with-write-to-file ))