port.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Robert Ransom
  3. ; Ports and port handlers
  4. ; (discloser <port>) -> (<symbol> <value> ...)
  5. ; (close <port>) -> whatever
  6. ;
  7. ; Input ports
  8. ; (byte <port> <read?>) -> <byte>
  9. ; (char <port> <mode>) -> <char>
  10. ; <mode> says whether we're doing ...
  11. ; - #t: a PEEK
  12. ; - #f: a READ
  13. ; - (): CHAR-READY?
  14. ; (block <port> <buffer> <start> <count>) -> <byte count>
  15. ; (ready? <port>) -> <boolean>
  16. ;
  17. ; Output ports
  18. ; (byte <port> <byte>) -> whatever
  19. ; (char <port> <char>) -> whatever
  20. ; (block <port> <buffer> <start> <count>) -> whatever
  21. ; (ready? <port>) -> <boolean>
  22. ; (force-output <port>) -> whatever
  23. (define-record-type port-handler :port-handler
  24. (make-port-handler discloser close byte char block ready? force)
  25. port-handler?
  26. (discloser port-handler-discloser)
  27. (close port-handler-close)
  28. (byte port-handler-byte)
  29. (char port-handler-char)
  30. (block port-handler-block)
  31. (ready? port-handler-ready?)
  32. (force port-handler-force)) ; only used for output
  33. ;----------------
  34. ; Disclosing ports by calling the disclose handler.
  35. (define (disclose-port port)
  36. ((port-handler-discloser (port-handler port))
  37. port))
  38. (define-method &disclose ((port <input-port>))
  39. (disclose-port port))
  40. (define-method &disclose ((port <output-port>))
  41. (disclose-port port))
  42. ;----------------
  43. ; Set up VM exception handlers for the three unnecessary I/O primitives,
  44. ; READ-BYTE, PEEK-BYTE, and WRITE-BYTE. These do the right thing in
  45. ; the case of unbuffered ports or buffer overflow or underflow.
  46. ;
  47. ; This is abstracted to avoid a circular module dependency.
  48. (define (initialize-i/o-handlers! define-vm-exception-handler signal-exception)
  49. (define-vm-exception-handler (enum op read-byte)
  50. (one-arg-proc->handler (lambda (port)
  51. ((port-handler-byte (port-handler port))
  52. port
  53. #t))))
  54. (define-vm-exception-handler (enum op peek-byte)
  55. (one-arg-proc->handler (lambda (port)
  56. ((port-handler-byte (port-handler port))
  57. port
  58. #f))))
  59. (define-vm-exception-handler (enum op read-char)
  60. (one-arg-proc->handler (lambda (port)
  61. ((port-handler-char (port-handler port))
  62. port
  63. #f))))
  64. (define-vm-exception-handler (enum op peek-char)
  65. (one-arg-proc->handler (lambda (port)
  66. ((port-handler-char (port-handler port))
  67. port
  68. #t))))
  69. (define-vm-exception-handler (enum op write-byte)
  70. (two-arg-proc->handler (lambda (byte port)
  71. ((port-handler-byte (port-handler port))
  72. port
  73. byte))))
  74. (define-vm-exception-handler (enum op write-char)
  75. (two-arg-proc->handler (lambda (ch port)
  76. ((port-handler-char (port-handler port))
  77. port
  78. ch)))))
  79. ; Check the VM exception and then lock the port.
  80. (define (one-arg-proc->handler proc)
  81. (lambda (opcode reason port)
  82. (if (= reason (enum exception buffer-full/empty))
  83. (proc port)
  84. ;; note this must be an assertion violation---these only look at the buffer
  85. (signal-vm-exception opcode reason port))))
  86. ; This could be combined with one-arg-... if the port were the first argument.
  87. (define (two-arg-proc->handler proc)
  88. (lambda (opcode reason arg port)
  89. (if (= reason (enum exception buffer-full/empty))
  90. (proc arg port)
  91. ;; note this must be an assertion violation---these only look at the buffer
  92. (signal-vm-exception opcode reason arg port))))
  93. ;----------------
  94. ; Wrappers for the various port operations. These check types and arguments
  95. ; and then call the appropriate handler procedure.
  96. (define (real-char-ready? port)
  97. (cond
  98. ((open-input-port? port)
  99. ((port-handler-char (port-handler port)) port '()))
  100. (else
  101. (assertion-violation 'char-ready? "invalid argument" port))))
  102. ; See if there is a character available. BYTE-READY? itself is defined
  103. ; in current-port.scm as it needs CURRENT-INPUT-PORT when called with
  104. ; no arguments.
  105. (define (real-byte-ready? port)
  106. (if (open-input-port? port)
  107. ((port-handler-ready? (port-handler port))
  108. port)
  109. (assertion-violation 'real-byte-ready? "invalid argument" port)))
  110. ; Reading in a block of characters at once.
  111. (define (read-block buffer start count port . maybe-wait?)
  112. (if (and (port? port)
  113. (open-input-port? port)
  114. (okay-limits? buffer
  115. start
  116. count))
  117. (if (= count 0)
  118. 0
  119. ((port-handler-block (port-handler port))
  120. port
  121. buffer
  122. start
  123. count
  124. (or (null? maybe-wait?)
  125. (car maybe-wait?))))
  126. (assertion-violation 'read-block "invalid argument" buffer start count port)))
  127. ; Write the COUNT bytes beginning at START from BUFFER to PORT.
  128. (define (write-block buffer start count port)
  129. (if (and (port? port)
  130. (open-output-port? port)
  131. (okay-limits? buffer start count))
  132. (if (< 0 count)
  133. ((port-handler-block (port-handler port))
  134. port
  135. buffer
  136. start
  137. count))
  138. (assertion-violation 'write-block "invalid argument" buffer start count port)))
  139. (define (write-string string port)
  140. (do ((size (string-length string))
  141. (i 0 (+ 1 i)))
  142. ((>= i size) (unspecific))
  143. (write-char (string-ref string i) port)))
  144. ; BYTE-READY? for output ports.
  145. (define (output-port-ready? port)
  146. (if (open-output-port? port)
  147. ((port-handler-ready? (port-handler port))
  148. port)
  149. (assertion-violation 'output-port-ready? "invalid argument" port)))
  150. ; Forcing output.
  151. (define (force-output port)
  152. (if (open-output-port? port)
  153. ((port-handler-force (port-handler port))
  154. port
  155. #t) ; raise error if PORT is not open
  156. (assertion-violation 'force-output "invalid argument" port)))
  157. (define (force-output-if-open port)
  158. (if (open-output-port? port)
  159. ((port-handler-force (port-handler port))
  160. port
  161. #f))) ; do not raise error if PORT is not open
  162. ; Closing input and output ports.
  163. ; RnRS says that CLOSE-{IN|OUT}PUT-PORT is idempotent.
  164. (define (close-input-port port)
  165. (if (input-port? port)
  166. (begin
  167. (if (open-input-port? port)
  168. ((port-handler-close (port-handler port))
  169. port))
  170. (unspecific))
  171. (assertion-violation 'close-input-port "invalid argument" port)))
  172. (define (close-output-port port)
  173. (if (output-port? port)
  174. (begin
  175. (if (open-output-port? port)
  176. ((port-handler-close (port-handler port))
  177. port))
  178. (unspecific))
  179. (assertion-violation 'close-output-port "invalid argument" port)))
  180. ;----------------
  181. (define (port-text-codec p)
  182. (spec->text-codec (port-text-codec-spec p)))
  183. (define (set-port-text-codec! p codec)
  184. (set-port-text-codec-spec! p (text-codec->spec codec)))
  185. ;----------------
  186. ; Check that BUFFER contains COUNT characters starting from START.
  187. (define (okay-limits? buffer start count)
  188. (and (integer? start)
  189. (exact? start)
  190. (<= 0 start)
  191. (integer? count)
  192. (exact? count)
  193. (<= 0 count)
  194. (<= (+ start count)
  195. (cond ((byte-vector? buffer)
  196. (byte-vector-length buffer))
  197. (else
  198. -1)))))
  199. ;----------------
  200. ; Is PORT open?
  201. (define (open-port? port)
  202. (not (= 0 (bitwise-and open-port-mask (provisional-port-status port)))))
  203. (define open-port-mask
  204. (bitwise-ior (arithmetic-shift 1 (enum port-status-options open-for-input))
  205. (arithmetic-shift 1 (enum port-status-options open-for-output))))
  206. ;----------------
  207. ; Input ports
  208. (define input-port-mask
  209. (arithmetic-shift 1
  210. (enum port-status-options input)))
  211. (define open-input-port-mask
  212. (arithmetic-shift 1
  213. (enum port-status-options open-for-input)))
  214. (define open-input-port-status
  215. (bitwise-ior input-port-mask
  216. open-input-port-mask))
  217. (define (open-input-port? port)
  218. (not (= 0 (bitwise-and open-input-port-mask
  219. (provisional-port-status port)))))
  220. (define (make-input-port-closed! port)
  221. (provisional-set-port-status! port
  222. (bitwise-and (provisional-port-status port)
  223. (bitwise-not open-input-port-mask))))
  224. ;----------------
  225. ; Output ports
  226. (define output-port-mask
  227. (arithmetic-shift 1
  228. (enum port-status-options output)))
  229. (define open-output-port-mask
  230. (arithmetic-shift 1
  231. (enum port-status-options open-for-output)))
  232. (define open-output-port-status
  233. (bitwise-ior output-port-mask
  234. open-output-port-mask))
  235. (define (open-output-port? port)
  236. (not (= 0 (bitwise-and open-output-port-mask
  237. (provisional-port-status port)))))
  238. (define (make-output-port-closed! port)
  239. (provisional-set-port-status! port
  240. (bitwise-and (provisional-port-status port)
  241. (bitwise-not open-output-port-mask))))
  242. (define (make-unbuffered-output-port handler data)
  243. (if (port-handler? handler)
  244. (make-port handler
  245. (enum text-encoding-option latin-1)
  246. #f
  247. open-output-port-status
  248. #f ; lock (not used in unbuffered ports)
  249. data
  250. (make-byte-vector 128 0) ; buffer
  251. #f ; index
  252. #f ; limit
  253. #f ; pending-cr?
  254. #f) ; pending-eof?
  255. (assertion-violation 'make-unbuffered-output-port "invalid argument"
  256. handler data)))
  257. (define (make-one-byte-handler write-block)
  258. (lambda (port byte)
  259. (let ((buffer (port-buffer port)))
  260. (byte-vector-set! buffer 0 byte)
  261. (let loop ()
  262. (if (= 0 (write-block port buffer 0 1))
  263. (loop))))))
  264. (define (make-one-char-handler write-block)
  265. (lambda (port ch)
  266. (let ((buffer (port-buffer port))
  267. (encode-char
  268. (text-codec-encode-char-proc (port-text-codec port))))
  269. (let ((encode-count
  270. (if (and (port-crlf? port)
  271. (char=? ch #\newline))
  272. (atomically
  273. (call-with-values
  274. (lambda ()
  275. (encode-char cr
  276. buffer 0 (byte-vector-length buffer)))
  277. (lambda (ok? encode-count-cr)
  278. ;; OK? must be true
  279. (call-with-values
  280. (lambda ()
  281. (encode-char #\newline
  282. buffer
  283. encode-count-cr
  284. (- (byte-vector-length buffer) encode-count-cr)))
  285. (lambda (ok? encode-count-lf)
  286. ;; OK? must be true
  287. (+ encode-count-cr encode-count-lf))))))
  288. (atomically
  289. (call-with-values
  290. (lambda ()
  291. (encode-char ch
  292. buffer 0 (byte-vector-length buffer)))
  293. (lambda (ok? encode-count)
  294. (if ok?
  295. encode-count
  296. ;; hrmpfl ...
  297. (call-with-values
  298. (lambda ()
  299. (encode-char #\?
  300. buffer 0 (byte-vector-length buffer)))
  301. (lambda (ok? encode-count)
  302. encode-count)))))))))
  303. (let loop ((index 0))
  304. (let* ((to-write (- encode-count index))
  305. (written
  306. (write-block port buffer index to-write)))
  307. (if (< written to-write)
  308. (loop (+ index written)))))))))
  309. (define cr (ascii->char 13))
  310. (define (make-write-block-handler write-block)
  311. (lambda (port buffer start count)
  312. (let loop ((sent 0))
  313. (let ((sent (+ sent
  314. (write-block port
  315. buffer
  316. (+ start sent)
  317. (- count sent)))))
  318. (if (< sent count)
  319. (loop sent))))))
  320. (define (make-unbuffered-output-port-handler discloser closer! write-block ready?)
  321. (make-port-handler discloser
  322. closer!
  323. (make-one-byte-handler write-block)
  324. (make-one-char-handler write-block)
  325. (make-write-block-handler write-block)
  326. ready?
  327. (lambda (port error-if-closed?) ; output forcer
  328. (unspecific))))
  329. ;----------------
  330. ; Output ports that just discard any output.
  331. (define null-output-port-handler
  332. (make-port-handler
  333. (lambda (ignore) ; disclose
  334. (list 'null-output-port))
  335. make-output-port-closed! ; close
  336. (lambda (port byte) ; one-byte (we just empty the buffer)
  337. (set-port-index! port 0))
  338. (lambda (port char) ; one-char (we just empty the buffer)
  339. (set-port-index! port 0))
  340. (lambda (port buffer start count) ; write-block
  341. count)
  342. (lambda (port) ; ready?
  343. #t)
  344. (lambda (port error-if-closed?) ; force-output
  345. (unspecific))))
  346. ; They can all share a buffer. The buffer is needed because the WRITE-BYTE
  347. ; byte code actually wants to put characters somewhere.
  348. (define null-output-buffer
  349. (make-byte-vector 1024 0))
  350. (define (make-null-output-port)
  351. (make-port null-output-port-handler
  352. null-text-codec
  353. #f
  354. open-output-port-status
  355. #f ; timestamp
  356. #f ; data
  357. null-output-buffer
  358. 0 ; index
  359. (byte-vector-length null-output-buffer) ; limit
  360. #f ; pending-cr?
  361. #f)) ; pending-eof?