r7rs-file.scm 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. ;;; R7RS (scheme file) library
  2. ;;; Copyright (C) 2024 Igalia, S.L.
  3. ;;; Copyright (C) 2024 David Thompson <dave@spritely.institute>
  4. ;;;
  5. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  6. ;;; you may not use this file except in compliance with the License.
  7. ;;; You may obtain a copy of the License at
  8. ;;;
  9. ;;; http://www.apache.org/licenses/LICENSE-2.0
  10. ;;;
  11. ;;; Unless required by applicable law or agreed to in writing, software
  12. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  13. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ;;; See the License for the specific language governing permissions and
  15. ;;; limitations under the License.
  16. ;;; Commentary:
  17. ;;;
  18. ;;; R7RS (scheme file) implementation
  19. ;;;
  20. ;;; Code:
  21. (library (scheme file)
  22. (export open-binary-input-file
  23. open-binary-output-file
  24. call-with-input-file
  25. call-with-output-file
  26. delete-file
  27. file-exists?
  28. open-input-file
  29. open-output-file
  30. with-input-from-file
  31. with-output-to-file)
  32. (import (scheme base)
  33. (only (hoot primitives) %inline-wasm)
  34. (only (hoot ports) make-port)
  35. (only (hoot errors) assert make-unimplemented-error)
  36. (hoot match))
  37. (define (delete-file filename)
  38. (%inline-wasm
  39. '(func (param $filename (ref string))
  40. (call $delete-file (local.get $filename)))
  41. filename)
  42. (if #f #f))
  43. (define (file-exists? filename)
  44. (%inline-wasm
  45. '(func (param $filename (ref string)) (result (ref eq))
  46. (if (ref eq)
  47. (i32.eqz (call $file-exists? (local.get $filename)))
  48. (then (ref.i31 (i32.const 1)))
  49. (else (ref.i31 (i32.const 17)))))
  50. filename))
  51. (define (%file-random-access? handle)
  52. (%inline-wasm
  53. '(func (param $handle (ref $extern-ref)) (result (ref eq))
  54. (if (ref eq)
  55. (i32.eqz (call $file-random-access?
  56. (ref.as_non_null
  57. (struct.get $extern-ref $val
  58. (local.get $handle)))))
  59. (then (ref.i31 (i32.const 1)))
  60. (else (ref.i31 (i32.const 17)))))
  61. handle))
  62. (define (%file-buffer-size handle)
  63. (%inline-wasm
  64. '(func (param $handle (ref $extern-ref)) (result i64)
  65. (i64.extend_i32_s
  66. (call $file-buffer-size
  67. (ref.as_non_null
  68. (struct.get $extern-ref $val (local.get $handle))))))
  69. handle))
  70. (define (%close-file handle)
  71. (%inline-wasm
  72. '(func (param $handle (ref $extern-ref))
  73. (call $close-file
  74. (ref.as_non_null
  75. (struct.get $extern-ref $val (local.get $handle)))))
  76. handle)
  77. (if #f #f))
  78. (define (%seek-file handle offset whence)
  79. (let* ((whence (match whence ('start 0) ('cur 1) ('end 2)))
  80. (new (%inline-wasm
  81. '(func (param $handle (ref $extern-ref))
  82. (param $offset i64)
  83. (param $whence i64)
  84. (result i64)
  85. (i64.extend_i32_s
  86. (call $seek-file
  87. (ref.as_non_null
  88. (struct.get $extern-ref $val (local.get $handle)))
  89. (i32.wrap_i64 (local.get $offset))
  90. (i32.wrap_i64 (local.get $whence)))))
  91. handle offset whence)))
  92. (assert (>= new 0) 'seek)
  93. new))
  94. (define (open-binary-input-file filename)
  95. (define default-buffer-size 1024)
  96. (define handle
  97. (%inline-wasm
  98. '(func (param $filename (ref string)) (result (ref eq))
  99. (struct.new $extern-ref
  100. (i32.const 0)
  101. (call $open-input-file (local.get $filename))))
  102. filename))
  103. (define (file-buffer-ref i)
  104. (%inline-wasm
  105. '(func (param $handle (ref $extern-ref)) (param $i i64) (result i64)
  106. (i64.extend_i32_s
  107. (call $file-buffer-ref
  108. (ref.as_non_null
  109. (struct.get $extern-ref $val (local.get $handle)))
  110. (i32.wrap_i64 (local.get $i)))))
  111. handle i))
  112. (define (file-read dst start count)
  113. (let ((n (%inline-wasm
  114. '(func (param $handle (ref $extern-ref)) (param $count i64)
  115. (result i64)
  116. (i64.extend_i32_s
  117. (call $read-file
  118. (ref.as_non_null
  119. (struct.get $extern-ref $val (local.get $handle)))
  120. (i32.wrap_i64 (local.get $count)))))
  121. handle count)))
  122. (do ((i 0 (+ i 1)))
  123. ((= i n))
  124. (bytevector-u8-set! dst (+ start i) (file-buffer-ref i)))
  125. n))
  126. (define (file-close) (%close-file handle))
  127. (define (file-seek offset whence)
  128. (%seek-file handle offset whence))
  129. (make-port file-read
  130. #f ; write
  131. #f ; input-waiting?
  132. file-seek
  133. file-close
  134. #f ; truncate
  135. "file" ; repr
  136. filename ; filename
  137. default-buffer-size ; read-buf-size
  138. #f ; write-buf-size
  139. (%file-random-access? handle)
  140. #f ; fold-case?
  141. #f))
  142. (define (open-binary-output-file filename)
  143. (define default-buffer-size 1024)
  144. (define handle
  145. (%inline-wasm
  146. '(func (param $filename (ref string)) (result (ref eq))
  147. (struct.new $extern-ref
  148. (i32.const 0)
  149. (call $open-output-file (local.get $filename))))
  150. filename))
  151. (define handle-buffer-size (%file-buffer-size handle))
  152. (define (file-buffer-set! i x)
  153. (%inline-wasm
  154. '(func (param $handle (ref $extern-ref)) (param $i i64) (param $x i64)
  155. (call $file-buffer-set!
  156. (ref.as_non_null
  157. (struct.get $extern-ref $val (local.get $handle)))
  158. (i32.wrap_i64 (local.get $i))
  159. (i32.wrap_i64 (local.get $x))))
  160. handle i x))
  161. (define (file-write bv start count)
  162. (let ((count (min count handle-buffer-size)))
  163. (do ((i 0 (+ i 1)))
  164. ((= i count))
  165. (file-buffer-set! i (bytevector-u8-ref bv (+ start i))))
  166. (%inline-wasm
  167. '(func (param $handle (ref $extern-ref)) (param $count i64) (result i64)
  168. (i64.extend_i32_s
  169. (call $write-file
  170. (ref.as_non_null
  171. (struct.get $extern-ref $val (local.get $handle)))
  172. (i32.wrap_i64 (local.get $count)))))
  173. handle count)))
  174. (define (file-close) (%close-file handle))
  175. (define (file-seek offset whence)
  176. (%seek-file handle offset whence))
  177. (make-port #f ; read
  178. file-write
  179. #f ; input-waiting?
  180. file-seek
  181. file-close
  182. #f ; truncate
  183. "file" ; repr
  184. filename ; filename
  185. #f ; read-buf-size
  186. default-buffer-size ; write-buf-size
  187. (%file-random-access? handle)
  188. #f ; fold-case?
  189. #f))
  190. (define (open-input-file filename)
  191. (open-binary-input-file filename))
  192. (define (open-output-file filename)
  193. (open-binary-output-file filename))
  194. (define (call-with-input-file filename proc)
  195. (let ((p (open-input-file filename)))
  196. (call-with-values (lambda () (proc p))
  197. (lambda vals
  198. (close-port p)
  199. (apply values vals)))))
  200. (define (call-with-output-file filename proc)
  201. (let ((p (open-output-file filename)))
  202. (call-with-values (lambda () (proc p))
  203. (lambda vals
  204. (close-port p)
  205. (apply values vals)))))
  206. (define (with-input-from-file filename thunk)
  207. (let ((p (open-input-file filename)))
  208. (parameterize ((current-input-port p))
  209. (call-with-values thunk
  210. (lambda vals
  211. (close-port p)
  212. (apply values vals))))))
  213. (define (with-output-to-file filename thunk)
  214. (let ((p (open-output-file filename)))
  215. (parameterize ((current-output-port p))
  216. (call-with-values thunk
  217. (lambda vals
  218. (close-port p)
  219. (apply values vals)))))))