-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfilesystem.lisp
More file actions
77 lines (65 loc) · 2.63 KB
/
filesystem.lisp
File metadata and controls
77 lines (65 loc) · 2.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
(in-package #:cl-blackjack)
;; cache
(defparameter *cache* (make-hash-table :test #'equal))
(defun cache-cell (id)
(values (gethash id *cache* nil)))
(defun cached-content (id content date)
(setf (gethash id *cache*)
(list date content))
content)
(defmacro with-pathname-cache (pathname &body body)
(with-gensyms (cached-origin)
(once-only (pathname)
`(if (probe-file ,pathname)
(let ((write-date (handler-case (file-write-date ,pathname)
(file-error (condition)
(declare (ignore condition))
0))))
(flet ((,cached-origin ()
(cached-content ,pathname (progn ,@body) write-date)))
(aif (cache-cell pathname)
(destructuring-bind (cache-date cache-content) it
(if (and cache-date (>= cache-date write-date))
(values cache-content t)
(,cached-origin)))
(,cached-origin))))
(error "File not found: ~a" ,pathname)))))
(defun kill-pathname-cache (pathname)
(remhash pathname *cache*))
;; I/O
(defun save-into-file (value pathname)
(ensure-directories-exist pathname)
(kill-pathname-cache pathname)
(with-open-file (file pathname
:direction :output
:if-exists :supersede
:if-does-not-exist :create)
(format file "~s" value))
nil)
(defmacro define-cached-pathname (name (&rest args) &rest content)
(with-gensyms (file-content)
`(defun ,name (pathname &key (cache t) ,@args)
(flet ((,file-content ()
,@content))
(if cache
(with-pathname-cache pathname (,file-content))
(progn (kill-pathname-cache pathname)
(,file-content)))))))
(define-cached-pathname load-from-file ()
(when (probe-file pathname)
(with-open-file (file pathname)
(read file nil))))
(defun pathname-string+bytes (pathname)
"Suck up an entire file from PATH into a freshly-allocated string, returning two values: the string and the number of bytes read."
(with-open-file (s pathname)
(let* ((len (file-length s))
(data (make-string len)))
(values data (read-sequence data s)))))
(define-cached-pathname pathname-content (binary)
(if binary
(let (result)
(with-open-file (file pathname :element-type '(unsigned-byte 8))
(loop for byte = (read-byte file nil)
while byte do (push byte result)))
(reverse result))
(clean-unicode (pathname-string+bytes pathname))))