suspendable-ports.scm 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. ;;; Ports, implemented in Scheme
  2. ;;; Copyright (C) 2016, 2019 Free Software Foundation, Inc.
  3. ;;;
  4. ;;; This library is free software: you can redistribute it and/or modify
  5. ;;; it under the terms of the GNU Lesser General Public License as
  6. ;;; published by the Free Software Foundation, either version 3 of the
  7. ;;; License, or (at your option) any later version.
  8. ;;;
  9. ;;; This library is distributed in the hope that it will be useful, but
  10. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; Lesser General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU Lesser General Public
  15. ;;; License along with this program. If not, see
  16. ;;; <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;;;
  19. ;;; We would like to be able to implement green threads using delimited
  20. ;;; continuations. When a green thread would block on I/O, it should
  21. ;;; suspend and arrange to be resumed when it can make progress.
  22. ;;;
  23. ;;; The problem is that the ports code is written in C. A delimited
  24. ;;; continuation that captures a C activation can't be resumed, because
  25. ;;; Guile doesn't know about the internal structure of the C activation
  26. ;;; (stack frame) and so can't compose it with the current continuation.
  27. ;;; For that reason, to implement this desired future, we have to
  28. ;;; implement ports in Scheme.
  29. ;;;
  30. ;;; If Scheme were fast enough, we would just implement ports in Scheme
  31. ;;; early in Guile's boot, and that would be that. However currently
  32. ;;; that's not the case: character-by-character I/O is about three or
  33. ;;; four times slower in Scheme than in C. This is mostly bytecode
  34. ;;; overhead, though there are some ways that compiler improvements
  35. ;;; could help us too.
  36. ;;;
  37. ;;; Note that the difference between Scheme and C is much less for
  38. ;;; batched operations, like read-bytes or read-line.
  39. ;;;
  40. ;;; So the upshot is that we need to keep the C I/O routines around for
  41. ;;; performance reasons. We can still have our Scheme routines
  42. ;;; available as a module, though, for use by people working with green
  43. ;;; threads. That's this module. People that want green threads can
  44. ;;; even replace the core bindings, which enables green threading over
  45. ;;; other generic routines like the HTTP server.
  46. ;;;
  47. ;;; Code:
  48. (define-module (ice-9 suspendable-ports)
  49. #:use-module (rnrs bytevectors)
  50. #:use-module (ice-9 ports internal)
  51. #:use-module (ice-9 match)
  52. #:export (current-read-waiter
  53. current-write-waiter
  54. install-suspendable-ports!
  55. uninstall-suspendable-ports!))
  56. (define (default-read-waiter port) (port-poll port "r"))
  57. (define (default-write-waiter port) (port-poll port "w"))
  58. (define current-read-waiter (make-parameter default-read-waiter))
  59. (define current-write-waiter (make-parameter default-write-waiter))
  60. (define (wait-for-readable port) ((current-read-waiter) port))
  61. (define (wait-for-writable port) ((current-write-waiter) port))
  62. (define (read-bytes port dst start count)
  63. (cond
  64. (((port-read port) port dst start count)
  65. => (lambda (read)
  66. (unless (<= 0 read count)
  67. (error "bad return from port read function" read))
  68. read))
  69. (else
  70. (wait-for-readable port)
  71. (read-bytes port dst start count))))
  72. (define (write-bytes port src start count)
  73. (cond
  74. (((port-write port) port src start count)
  75. => (lambda (written)
  76. (unless (<= 0 written count)
  77. (error "bad return from port write function" written))
  78. (when (< written count)
  79. (write-bytes port src (+ start written) (- count written)))))
  80. (else
  81. (wait-for-writable port)
  82. (write-bytes port src start count))))
  83. (define (flush-input port)
  84. (let* ((buf (port-read-buffer port))
  85. (cur (port-buffer-cur buf))
  86. (end (port-buffer-end buf)))
  87. (when (< cur end)
  88. (set-port-buffer-cur! buf 0)
  89. (set-port-buffer-end! buf 0)
  90. (seek port (- cur end) SEEK_CUR))))
  91. (define (flush-output port)
  92. (let* ((buf (port-write-buffer port))
  93. (cur (port-buffer-cur buf))
  94. (end (port-buffer-end buf)))
  95. (when (< cur end)
  96. ;; Update cursors before attempting to write, assuming that I/O
  97. ;; errors are sticky. That way if the write throws an error,
  98. ;; causing the computation to abort, and possibly causing the port
  99. ;; to be collected by GC when it's open, any subsequent close-port
  100. ;; or force-output won't signal *another* error.
  101. (set-port-buffer-cur! buf 0)
  102. (set-port-buffer-end! buf 0)
  103. (write-bytes port (port-buffer-bytevector buf) cur (- end cur)))))
  104. (define utf8-bom #vu8(#xEF #xBB #xBF))
  105. (define utf16be-bom #vu8(#xFE #xFF))
  106. (define utf16le-bom #vu8(#xFF #xFE))
  107. (define utf32be-bom #vu8(#x00 #x00 #xFE #xFF))
  108. (define utf32le-bom #vu8(#xFF #xFE #x00 #x00))
  109. (define (clear-stream-start-for-bom-read port io-mode)
  110. (define (maybe-consume-bom bom)
  111. (and (eq? (peek-byte port) (bytevector-u8-ref bom 0))
  112. (call-with-values (lambda ()
  113. (fill-input port (bytevector-length bom)))
  114. (lambda (buf cur buffered)
  115. (and (<= (bytevector-length bom) buffered)
  116. (let ((bv (port-buffer-bytevector buf)))
  117. (let lp ((i 1))
  118. (if (= i (bytevector-length bom))
  119. (begin
  120. (set-port-buffer-cur! buf (+ cur i))
  121. #t)
  122. (and (eq? (bytevector-u8-ref bv (+ cur i))
  123. (bytevector-u8-ref bom i))
  124. (lp (1+ i)))))))))))
  125. (when (and (port-clear-stream-start-for-bom-read port)
  126. (eq? io-mode 'text))
  127. (case (%port-encoding port)
  128. ((UTF-8)
  129. (maybe-consume-bom utf8-bom))
  130. ((UTF-16)
  131. (cond
  132. ((maybe-consume-bom utf16le-bom)
  133. (specialize-port-encoding! port 'UTF-16LE))
  134. (else
  135. (maybe-consume-bom utf16be-bom)
  136. (specialize-port-encoding! port 'UTF-16BE))))
  137. ((UTF-32)
  138. (cond
  139. ((maybe-consume-bom utf32le-bom)
  140. (specialize-port-encoding! port 'UTF-32LE))
  141. (else
  142. (maybe-consume-bom utf32be-bom)
  143. (specialize-port-encoding! port 'UTF-32BE)))))))
  144. (define* (fill-input port #:optional (minimum-buffering 1) (io-mode 'text))
  145. (clear-stream-start-for-bom-read port io-mode)
  146. (let* ((buf (port-read-buffer port))
  147. (cur (port-buffer-cur buf))
  148. (buffered (max (- (port-buffer-end buf) cur) 0)))
  149. (cond
  150. ((or (<= minimum-buffering buffered) (port-buffer-has-eof? buf))
  151. (values buf cur buffered))
  152. (else
  153. (unless (input-port? port)
  154. (error "not an input port" port))
  155. (when (port-random-access? port)
  156. (flush-output port))
  157. (let ((bv (port-buffer-bytevector buf)))
  158. (cond
  159. ((< (bytevector-length bv) minimum-buffering)
  160. (expand-port-read-buffer! port minimum-buffering)
  161. (fill-input port minimum-buffering))
  162. (else
  163. (when (< 0 cur)
  164. (bytevector-copy! bv cur bv 0 buffered)
  165. (set-port-buffer-cur! buf 0)
  166. (set-port-buffer-end! buf buffered))
  167. (let ((buffering (max (port-read-buffering port) minimum-buffering)))
  168. (let lp ((buffered buffered))
  169. (let* ((count (- buffering buffered))
  170. (read (read-bytes port bv buffered count)))
  171. (cond
  172. ((zero? read)
  173. (set-port-buffer-has-eof?! buf #t)
  174. (values buf 0 buffered))
  175. (else
  176. (let ((buffered (+ buffered read)))
  177. (set-port-buffer-end! buf buffered)
  178. (if (< buffered minimum-buffering)
  179. (lp buffered)
  180. (values buf 0 buffered)))))))))))))))
  181. (define* (force-output #:optional (port (current-output-port)))
  182. (unless (and (output-port? port) (not (port-closed? port)))
  183. (error "not an open output port" port))
  184. (flush-output port))
  185. (define close-port
  186. (let ((%close-port (@ (guile) close-port)))
  187. (lambda (port)
  188. (cond
  189. ((port-closed? port) #f)
  190. (else
  191. (when (output-port? port) (flush-output port))
  192. (%close-port port))))))
  193. (define-inlinable (peek-bytes port count kfast kslow)
  194. (let* ((buf (port-read-buffer port))
  195. (cur (port-buffer-cur buf))
  196. (buffered (- (port-buffer-end buf) cur)))
  197. (if (<= count buffered)
  198. (kfast buf (port-buffer-bytevector buf) cur buffered)
  199. (call-with-values (lambda () (fill-input port count))
  200. (lambda (buf cur buffered)
  201. (kslow buf (port-buffer-bytevector buf) cur buffered))))))
  202. (define (peek-byte port)
  203. (peek-bytes port 1
  204. (lambda (buf bv cur buffered)
  205. (bytevector-u8-ref bv cur))
  206. (lambda (buf bv cur buffered)
  207. (and (> buffered 0)
  208. (bytevector-u8-ref bv cur)))))
  209. (define* (lookahead-u8 port)
  210. (define (fast-path buf bv cur buffered)
  211. (bytevector-u8-ref bv cur))
  212. (define (slow-path buf bv cur buffered)
  213. (if (zero? buffered)
  214. the-eof-object
  215. (fast-path buf bv cur buffered)))
  216. (peek-bytes port 1 fast-path slow-path))
  217. (define* (get-u8 port)
  218. (define (fast-path buf bv cur buffered)
  219. (set-port-buffer-cur! buf (1+ cur))
  220. (bytevector-u8-ref bv cur))
  221. (define (slow-path buf bv cur buffered)
  222. (if (zero? buffered)
  223. (begin
  224. (set-port-buffer-has-eof?! buf #f)
  225. the-eof-object)
  226. (fast-path buf bv cur buffered)))
  227. (peek-bytes port 1 fast-path slow-path))
  228. (define (get-bytevector-n! port bv start count)
  229. (define (port-buffer-take! pos buf cur to-copy)
  230. (bytevector-copy! (port-buffer-bytevector buf) cur
  231. bv pos to-copy)
  232. (set-port-buffer-cur! buf (+ cur to-copy))
  233. (+ pos to-copy))
  234. (define (take-already-buffered)
  235. (let* ((buf (port-read-buffer port))
  236. (cur (port-buffer-cur buf))
  237. (buffered (max (- (port-buffer-end buf) cur) 0)))
  238. (port-buffer-take! start buf cur (min count buffered))))
  239. (define (buffer-and-fill pos)
  240. (call-with-values (lambda () (fill-input port 1 'binary))
  241. (lambda (buf cur buffered)
  242. (if (zero? buffered)
  243. ;; We found EOF, which is marked in the port read buffer.
  244. ;; If we haven't read any bytes yet, clear the EOF from the
  245. ;; buffer and return it. Otherwise return the number of
  246. ;; bytes that we have read.
  247. (if (= pos start)
  248. (begin
  249. (set-port-buffer-has-eof?! buf #f)
  250. the-eof-object)
  251. (- pos start))
  252. (let ((pos (port-buffer-take! pos buf cur
  253. (min (- (+ start count) pos)
  254. buffered))))
  255. (if (= pos (+ start count))
  256. count
  257. (buffer-and-fill pos)))))))
  258. (define (fill-directly pos)
  259. (when (port-random-access? port)
  260. (flush-output port))
  261. (port-clear-stream-start-for-bom-read port)
  262. (let lp ((pos pos))
  263. (let ((read (read-bytes port bv pos (- (+ start count) pos))))
  264. (cond
  265. ((= (+ pos read) (+ start count))
  266. count)
  267. ((zero? read)
  268. ;; We found EOF. If we haven't read any bytes yet, return
  269. ;; EOF. Otherwise save the EOF in the port read buffer.
  270. (if (= pos start)
  271. the-eof-object
  272. (begin
  273. (set-port-buffer-has-eof?! (port-read-buffer port) #t)
  274. (- pos start))))
  275. (else (lp (+ pos read)))))))
  276. (let ((pos (take-already-buffered)))
  277. (cond
  278. ((= pos (+ start count))
  279. count)
  280. ((< (- (+ start count) pos) (port-read-buffering port))
  281. (buffer-and-fill pos))
  282. (else (fill-directly pos)))))
  283. (define (get-bytevector-n port count)
  284. (let* ((bv (make-bytevector count))
  285. (result (get-bytevector-n! port bv 0 count)))
  286. (cond ((eof-object? result)
  287. result)
  288. ((= result count)
  289. bv)
  290. (else
  291. (let ((bv* (make-bytevector result)))
  292. (bytevector-copy! bv 0 bv* 0 result)
  293. bv*)))))
  294. (define (get-bytevector-some port)
  295. (call-with-values (lambda () (fill-input port 1 'binary))
  296. (lambda (buf cur buffered)
  297. (if (zero? buffered)
  298. (begin
  299. (set-port-buffer-has-eof?! buf #f)
  300. the-eof-object)
  301. (let ((result (make-bytevector buffered)))
  302. (bytevector-copy! (port-buffer-bytevector buf) cur
  303. result 0 buffered)
  304. (set-port-buffer-cur! buf (+ cur buffered))
  305. result)))))
  306. (define (get-bytevector-some! port bv start count)
  307. (if (zero? count)
  308. 0
  309. (call-with-values (lambda () (fill-input port 1 'binary))
  310. (lambda (buf cur buffered)
  311. (if (zero? buffered)
  312. (begin
  313. (set-port-buffer-has-eof?! buf #f)
  314. the-eof-object)
  315. (let ((transfer-size (min count buffered)))
  316. (bytevector-copy! (port-buffer-bytevector buf) cur
  317. bv start transfer-size)
  318. (set-port-buffer-cur! buf (+ cur transfer-size))
  319. transfer-size))))))
  320. (define (put-u8 port byte)
  321. (let* ((buf (port-write-buffer port))
  322. (bv (port-buffer-bytevector buf))
  323. (end (port-buffer-end buf)))
  324. (unless (<= 0 end (bytevector-length bv))
  325. (error "not an output port" port))
  326. (when (and (eq? (port-buffer-cur buf) end) (port-random-access? port))
  327. (flush-input port))
  328. (cond
  329. ((= end (bytevector-length bv))
  330. ;; Multiple threads racing; race to flush, then retry.
  331. (flush-output port)
  332. (put-u8 port byte))
  333. (else
  334. (bytevector-u8-set! bv end byte)
  335. (set-port-buffer-end! buf (1+ end))
  336. (when (= (1+ end) (bytevector-length bv)) (flush-output port))))))
  337. (define* (put-bytevector port src #:optional (start 0)
  338. (count (- (bytevector-length src) start)))
  339. (unless (<= 0 start (+ start count) (bytevector-length src))
  340. (error "invalid start/count" start count))
  341. (let* ((buf (port-write-buffer port))
  342. (bv (port-buffer-bytevector buf))
  343. (size (bytevector-length bv))
  344. (cur (port-buffer-cur buf))
  345. (end (port-buffer-end buf))
  346. (buffered (max (- end cur) 0)))
  347. (when (and (eq? cur end) (port-random-access? port))
  348. (flush-input port))
  349. (cond
  350. ((<= size count)
  351. ;; The write won't fit in the buffer at all; write directly.
  352. ;; Write directly. Flush write buffer first if needed.
  353. (when (< cur end) (flush-output port))
  354. (write-bytes port src start count))
  355. ((< (- size buffered) count)
  356. ;; The write won't fit into the buffer along with what's already
  357. ;; buffered. Flush and fill.
  358. (flush-output port)
  359. (set-port-buffer-end! buf count)
  360. (bytevector-copy! src start bv 0 count))
  361. (else
  362. ;; The write will fit in the buffer, but we need to shuffle the
  363. ;; already-buffered bytes (if any) down.
  364. (set-port-buffer-cur! buf 0)
  365. (set-port-buffer-end! buf (+ buffered count))
  366. (bytevector-copy! bv cur bv 0 buffered)
  367. (bytevector-copy! src start bv buffered count)
  368. ;; If the buffer completely fills, we flush.
  369. (when (= (+ buffered count) size)
  370. (flush-output port))))))
  371. (define (decoding-error subr port)
  372. ;; GNU definition; fixme?
  373. (define EILSEQ 84)
  374. (throw 'decoding-error subr "input decoding error" EILSEQ port))
  375. (define-inlinable (decode-utf8 bv start avail u8_0 kt kf)
  376. (cond
  377. ((< u8_0 #x80)
  378. (kt (integer->char u8_0) 1))
  379. ((and (<= #xc2 u8_0 #xdf) (<= 2 avail))
  380. (let ((u8_1 (bytevector-u8-ref bv (1+ start))))
  381. (if (= (logand u8_1 #xc0) #x80)
  382. (kt (integer->char
  383. (logior (ash (logand u8_0 #x1f) 6)
  384. (logand u8_1 #x3f)))
  385. 2)
  386. (kf))))
  387. ((and (= (logand u8_0 #xf0) #xe0) (<= 3 avail))
  388. (let ((u8_1 (bytevector-u8-ref bv (+ start 1)))
  389. (u8_2 (bytevector-u8-ref bv (+ start 2))))
  390. (if (and (= (logand u8_1 #xc0) #x80)
  391. (= (logand u8_2 #xc0) #x80)
  392. (case u8_0
  393. ((#xe0) (>= u8_1 #xa0))
  394. ((#xed) (>= u8_1 #x9f))
  395. (else #t)))
  396. (kt (integer->char
  397. (logior (ash (logand u8_0 #x0f) 12)
  398. (ash (logand u8_1 #x3f) 6)
  399. (logand u8_2 #x3f)))
  400. 3)
  401. (kf))))
  402. ((and (<= #xf0 u8_0 #xf4) (<= 4 avail))
  403. (let ((u8_1 (bytevector-u8-ref bv (+ start 1)))
  404. (u8_2 (bytevector-u8-ref bv (+ start 2)))
  405. (u8_3 (bytevector-u8-ref bv (+ start 3))))
  406. (if (and (= (logand u8_1 #xc0) #x80)
  407. (= (logand u8_2 #xc0) #x80)
  408. (= (logand u8_3 #xc0) #x80)
  409. (case u8_0
  410. ((#xf0) (>= u8_1 #x90))
  411. ((#xf4) (>= u8_1 #x8f))
  412. (else #t)))
  413. (kt (integer->char
  414. (logior (ash (logand u8_0 #x07) 18)
  415. (ash (logand u8_1 #x3f) 12)
  416. (ash (logand u8_2 #x3f) 6)
  417. (logand u8_3 #x3f)))
  418. 4)
  419. (kf))))
  420. (else (kf))))
  421. (define (bad-utf8-len bv cur buffering first-byte)
  422. (define (ref n)
  423. (bytevector-u8-ref bv (+ cur n)))
  424. (cond
  425. ((< first-byte #x80) 0)
  426. ((<= #xc2 first-byte #xdf)
  427. (cond
  428. ((< buffering 2) 1)
  429. ((not (= (logand (ref 1) #xc0) #x80)) 1)
  430. (else 0)))
  431. ((= (logand first-byte #xf0) #xe0)
  432. (cond
  433. ((< buffering 2) 1)
  434. ((not (= (logand (ref 1) #xc0) #x80)) 1)
  435. ((and (eq? first-byte #xe0) (< (ref 1) #xa0)) 1)
  436. ((and (eq? first-byte #xed) (< (ref 1) #x9f)) 1)
  437. ((< buffering 3) 2)
  438. ((not (= (logand (ref 2) #xc0) #x80)) 2)
  439. (else 0)))
  440. ((<= #xf0 first-byte #xf4)
  441. (cond
  442. ((< buffering 2) 1)
  443. ((not (= (logand (ref 1) #xc0) #x80)) 1)
  444. ((and (eq? first-byte #xf0) (< (ref 1) #x90)) 1)
  445. ((and (eq? first-byte #xf4) (< (ref 1) #x8f)) 1)
  446. ((< buffering 3) 2)
  447. ((not (= (logand (ref 2) #xc0) #x80)) 2)
  448. ((< buffering 4) 3)
  449. ((not (= (logand (ref 3) #xc0) #x80)) 3)
  450. (else 0)))
  451. (else 1)))
  452. (define (peek-char-and-next-cur/utf8 port buf cur first-byte)
  453. (if (< first-byte #x80)
  454. (values (integer->char first-byte) buf (+ cur 1))
  455. (call-with-values (lambda ()
  456. (fill-input port
  457. (cond
  458. ((<= #xc2 first-byte #xdf) 2)
  459. ((= (logand first-byte #xf0) #xe0) 3)
  460. (else 4))))
  461. (lambda (buf cur buffering)
  462. (let ((bv (port-buffer-bytevector buf)))
  463. (define (bad-utf8)
  464. (let ((len (bad-utf8-len bv cur buffering first-byte)))
  465. (when (zero? len) (error "internal error"))
  466. (if (eq? (port-conversion-strategy port) 'substitute)
  467. (values #\xFFFD buf (+ cur len))
  468. (decoding-error "peek-char" port))))
  469. (decode-utf8 bv cur buffering first-byte
  470. (lambda (char len)
  471. (values char buf (+ cur len)))
  472. bad-utf8))))))
  473. (define (peek-char-and-next-cur/iso-8859-1 port buf cur first-byte)
  474. (values (integer->char first-byte) buf (+ cur 1)))
  475. (define (peek-char-and-next-cur/iconv port)
  476. (let lp ((prev-input-size 0))
  477. (let ((input-size (1+ prev-input-size)))
  478. (call-with-values (lambda () (fill-input port input-size))
  479. (lambda (buf cur buffered)
  480. (cond
  481. ((< buffered input-size)
  482. ;; Buffer failed to fill; EOF, possibly premature.
  483. (cond
  484. ((zero? prev-input-size)
  485. (values the-eof-object buf cur))
  486. ((eq? (port-conversion-strategy port) 'substitute)
  487. (values #\xFFFD buf (+ cur prev-input-size)))
  488. (else
  489. (decoding-error "peek-char" port))))
  490. ((port-decode-char port (port-buffer-bytevector buf)
  491. cur input-size)
  492. => (lambda (char)
  493. (values char buf (+ cur input-size))))
  494. (else
  495. (lp input-size))))))))
  496. (define (peek-char-and-next-cur port)
  497. (define (have-byte buf bv cur buffered)
  498. (let ((first-byte (bytevector-u8-ref bv cur)))
  499. (case (%port-encoding port)
  500. ((UTF-8)
  501. (peek-char-and-next-cur/utf8 port buf cur first-byte))
  502. ((ISO-8859-1)
  503. (peek-char-and-next-cur/iso-8859-1 port buf cur first-byte))
  504. (else
  505. (peek-char-and-next-cur/iconv port)))))
  506. (peek-bytes port 1 have-byte
  507. (lambda (buf bv cur buffered)
  508. (if (< 0 buffered)
  509. (have-byte buf bv cur buffered)
  510. (values the-eof-object buf cur)))))
  511. (define* (peek-char #:optional (port (current-input-port)))
  512. (define (slow-path)
  513. (call-with-values (lambda () (peek-char-and-next-cur port))
  514. (lambda (char buf cur)
  515. char)))
  516. (define (fast-path buf bv cur buffered)
  517. (let ((u8 (bytevector-u8-ref bv cur))
  518. (enc (%port-encoding port)))
  519. (case enc
  520. ((UTF-8) (decode-utf8 bv cur buffered u8 (lambda (char len) char)
  521. slow-path))
  522. ((ISO-8859-1) (integer->char u8))
  523. (else (slow-path)))))
  524. (peek-bytes port 1 fast-path
  525. (lambda (buf bv cur buffered) (slow-path))))
  526. (define-inlinable (advance-port-position! pos char)
  527. ;; FIXME: this cond is a speed hack; really we should just compile
  528. ;; `case' better.
  529. (cond
  530. ;; FIXME: char>? et al should compile well.
  531. ((<= (char->integer #\space) (char->integer char))
  532. (set-port-position-column! pos (1+ (port-position-column pos))))
  533. (else
  534. (case char
  535. ((#\alarm) #t) ; No change.
  536. ((#\backspace)
  537. (let ((col (port-position-column pos)))
  538. (when (> col 0)
  539. (set-port-position-column! pos (1- col)))))
  540. ((#\newline)
  541. (set-port-position-line! pos (1+ (port-position-line pos)))
  542. (set-port-position-column! pos 0))
  543. ((#\return)
  544. (set-port-position-column! pos 0))
  545. ((#\tab)
  546. (let ((col (port-position-column pos)))
  547. (set-port-position-column! pos (- (+ col 8) (remainder col 8)))))
  548. (else
  549. (set-port-position-column! pos (1+ (port-position-column pos))))))))
  550. (define* (read-char #:optional (port (current-input-port)))
  551. (define (finish buf char)
  552. (advance-port-position! (port-buffer-position buf) char)
  553. char)
  554. (define (slow-path)
  555. (call-with-values (lambda () (peek-char-and-next-cur port))
  556. (lambda (char buf cur)
  557. (set-port-buffer-cur! buf cur)
  558. (if (eq? char the-eof-object)
  559. (begin
  560. (set-port-buffer-has-eof?! buf #f)
  561. char)
  562. (finish buf char)))))
  563. (define (fast-path buf bv cur buffered)
  564. (let ((u8 (bytevector-u8-ref bv cur))
  565. (enc (%port-encoding port)))
  566. (case enc
  567. ((UTF-8)
  568. (decode-utf8 bv cur buffered u8
  569. (lambda (char len)
  570. (set-port-buffer-cur! buf (+ cur len))
  571. (finish buf char))
  572. slow-path))
  573. ((ISO-8859-1)
  574. (set-port-buffer-cur! buf (+ cur 1))
  575. (finish buf (integer->char u8)))
  576. (else (slow-path)))))
  577. (peek-bytes port 1 fast-path
  578. (lambda (buf bv cur buffered) (slow-path))))
  579. (define-inlinable (port-fold-chars/iso-8859-1 port proc seed)
  580. (let* ((buf (port-read-buffer port))
  581. (cur (port-buffer-cur buf)))
  582. (let fold-buffer ((buf buf) (cur cur) (seed seed))
  583. (let ((bv (port-buffer-bytevector buf))
  584. (end (port-buffer-end buf)))
  585. (let fold-chars ((cur cur) (seed seed))
  586. (cond
  587. ((= end cur)
  588. (call-with-values (lambda () (fill-input port))
  589. (lambda (buf cur buffered)
  590. (if (zero? buffered)
  591. (call-with-values (lambda () (proc the-eof-object seed))
  592. (lambda (seed done?)
  593. (if done? seed (fold-buffer buf cur seed))))
  594. (fold-buffer buf cur seed)))))
  595. (else
  596. (let ((ch (integer->char (bytevector-u8-ref bv cur)))
  597. (cur (1+ cur)))
  598. (set-port-buffer-cur! buf cur)
  599. (advance-port-position! (port-buffer-position buf) ch)
  600. (call-with-values (lambda () (proc ch seed))
  601. (lambda (seed done?)
  602. (if done? seed (fold-chars cur seed))))))))))))
  603. (define-inlinable (port-fold-chars port proc seed)
  604. (case (%port-encoding port)
  605. ((ISO-8859-1) (port-fold-chars/iso-8859-1 port proc seed))
  606. (else
  607. (let lp ((seed seed))
  608. (let ((ch (read-char port)))
  609. (call-with-values (lambda () (proc ch seed))
  610. (lambda (seed done?)
  611. (if done? seed (lp seed)))))))))
  612. (define* (read-delimited delims #:optional (port (current-input-port))
  613. (handle-delim 'trim))
  614. ;; Currently this function conses characters into a list, then uses
  615. ;; reverse-list->string. It wastes 2 words per character but it still
  616. ;; seems to be the fastest thing at the moment.
  617. (define (finish delim chars)
  618. (define (->string chars)
  619. (if (and (null? chars) (not (char? delim)))
  620. the-eof-object
  621. (reverse-list->string chars)))
  622. (case handle-delim
  623. ((trim) (->string chars))
  624. ((split) (cons (->string chars) delim))
  625. ((concat)
  626. (->string (if (char? delim) (cons delim chars) chars)))
  627. ((peek)
  628. (when (char? delim) (unread-char delim port))
  629. (->string chars))
  630. (else
  631. (error "unexpected handle-delim value: " handle-delim))))
  632. (define-syntax-rule (make-folder delimiter?)
  633. (lambda (char chars)
  634. (if (or (not (char? char)) (delimiter? char))
  635. (values (finish char chars) #t)
  636. (values (cons char chars) #f))))
  637. (define-syntax-rule (specialized-fold delimiter?)
  638. (port-fold-chars port (make-folder delimiter?) '()))
  639. (case (string-length delims)
  640. ((0) (specialized-fold (lambda (char) #f)))
  641. ((1) (let ((delim (string-ref delims 0)))
  642. (specialized-fold (lambda (char) (eqv? char delim)))))
  643. (else => (lambda (ndelims)
  644. (specialized-fold
  645. (lambda (char)
  646. (let lp ((i 0))
  647. (and (< i ndelims)
  648. (or (eqv? char (string-ref delims i))
  649. (lp (1+ i)))))))))))
  650. (define* (read-line #:optional (port (current-input-port))
  651. (handle-delim 'trim))
  652. (read-delimited "\n" port handle-delim))
  653. (define* (%read-line port)
  654. (read-line port 'split))
  655. (define* (put-string port str #:optional (start 0)
  656. (count (- (string-length str) start)))
  657. (let* ((aux (port-auxiliary-write-buffer port))
  658. (pos (port-buffer-position aux))
  659. (line (port-position-line pos)))
  660. (set-port-buffer-cur! aux 0)
  661. (port-clear-stream-start-for-bom-write port aux)
  662. (let lp ((encoded 0))
  663. (when (< encoded count)
  664. (let ((encoded (+ encoded
  665. (port-encode-chars port aux str
  666. (+ start encoded)
  667. (- count encoded)))))
  668. (let ((end (port-buffer-end aux)))
  669. (set-port-buffer-end! aux 0)
  670. (put-bytevector port (port-buffer-bytevector aux) 0 end)
  671. (lp encoded)))))
  672. (when (and (not (eqv? line (port-position-line pos)))
  673. (port-line-buffered? port))
  674. (flush-output port))))
  675. (define* (put-char port char)
  676. (let ((aux (port-auxiliary-write-buffer port)))
  677. (set-port-buffer-cur! aux 0)
  678. (port-clear-stream-start-for-bom-write port aux)
  679. (port-encode-char port aux char)
  680. (let ((end (port-buffer-end aux)))
  681. (set-port-buffer-end! aux 0)
  682. (put-bytevector port (port-buffer-bytevector aux) 0 end))
  683. (when (and (eqv? char #\newline) (port-line-buffered? port))
  684. (flush-output port))))
  685. (define accept
  686. (let ((%accept (@ (guile) accept)))
  687. (lambda* (port #:optional (flags 0))
  688. (let lp ()
  689. (or (%accept port flags)
  690. (begin
  691. (wait-for-readable port)
  692. (lp)))))))
  693. (define connect
  694. (let ((%connect (@ (guile) connect)))
  695. (lambda (port sockaddr . args)
  696. (unless (apply %connect port sockaddr args)
  697. ;; Clownshoes semantics; see connect(2).
  698. (wait-for-writable port)
  699. (let ((err (getsockopt port SOL_SOCKET SO_ERROR)))
  700. (unless (zero? err)
  701. (scm-error 'system-error "connect" "~A"
  702. (list (strerror err)) #f)))))))
  703. (define saved-port-bindings #f)
  704. (define port-bindings
  705. '(((guile)
  706. read-char peek-char force-output close-port
  707. accept connect)
  708. ((ice-9 binary-ports)
  709. get-u8 lookahead-u8 get-bytevector-n get-bytevector-n!
  710. get-bytevector-some get-bytevector-some!
  711. put-u8 put-bytevector)
  712. ((ice-9 textual-ports)
  713. put-char put-string)
  714. ((ice-9 rdelim) %read-line read-line read-delimited)))
  715. (define (install-suspendable-ports!)
  716. (unless saved-port-bindings
  717. (set! saved-port-bindings (make-hash-table))
  718. (let ((suspendable-ports (resolve-module '(ice-9 suspendable-ports))))
  719. (for-each
  720. (match-lambda
  721. ((mod . syms)
  722. (let ((mod (resolve-module mod)))
  723. (for-each (lambda (sym)
  724. (hashq-set! saved-port-bindings sym
  725. (module-ref mod sym))
  726. (module-set! mod sym
  727. (module-ref suspendable-ports sym)))
  728. syms))))
  729. port-bindings))))
  730. (define (uninstall-suspendable-ports!)
  731. (when saved-port-bindings
  732. (for-each
  733. (match-lambda
  734. ((mod . syms)
  735. (let ((mod (resolve-module mod)))
  736. (for-each (lambda (sym)
  737. (let ((saved (hashq-ref saved-port-bindings sym)))
  738. (module-set! mod sym saved)))
  739. syms))))
  740. port-bindings)
  741. (set! saved-port-bindings #f)))