1 ;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
3 ;;; --- Implementation using Gray streams.
6 (in-package :iolib.streams
)
8 ;;;-------------------------------------------------------------------------
9 ;;; Instance Initialization
10 ;;;-------------------------------------------------------------------------
12 (defun free-stream-buffers (ibuf obuf
)
13 (when ibuf
(free-iobuf ibuf
))
14 (when obuf
(free-iobuf obuf
)))
16 ;;; TODO: use the buffer pool
17 ;;; TODO: handle instance reinitialization
18 (defmethod shared-initialize :after
((stream dual-channel-gray-stream
) slot-names
19 &key external-format input-buffer-size output-buffer-size
)
20 (declare (ignore slot-names
))
21 (let ((external-format (or external-format
:default
))
22 (input-buffer-size (or input-buffer-size
+bytes-per-iobuf
+))
23 (output-buffer-size (or output-buffer-size
+bytes-per-iobuf
+)))
24 (check-type input-buffer-size buffer-index
)
25 (check-type output-buffer-size buffer-index
)
26 (with-accessors ((ibuf input-buffer-of
)
27 (obuf output-buffer-of
)
28 (ef external-format-of
))
30 (setf ibuf
(allocate-iobuf input-buffer-size
)
31 obuf
(allocate-iobuf output-buffer-size
)
33 (trivial-garbage:finalize stream
(lambda () (free-stream-buffers ibuf obuf
))))))
36 ;;;-------------------------------------------------------------------------
38 ;;;-------------------------------------------------------------------------
40 (defmethod print-object ((o dual-channel-gray-stream
) s
)
41 (with-slots (fd (ef external-format
) (ib input-buffer
) (ob output-buffer
))
43 (print-unreadable-object (o s
:type nil
:identity t
)
45 (format s
"~A ~S ~S ~S ~S/~S ~S ~S/~S ~S (~S ~S ~S)"
47 :ibuf
(iobuf-length ib
) (iobuf-size ib
)
48 :obuf
(iobuf-length ob
) (iobuf-size ob
)
49 :ef
(babel-encodings:enc-name
(babel:external-format-encoding ef
))
50 :eol-style
(babel:external-format-eol-style ef
))
51 (format s
"~A ~A ~S (~S ~S ~S)"
53 :ef
(babel-encodings:enc-name
(babel:external-format-encoding ef
))
54 :eol-style
(babel:external-format-eol-style ef
))))))
57 ;;;-------------------------------------------------------------------------
59 ;;;-------------------------------------------------------------------------
61 (defmethod stream-element-type ((stream dual-channel-gray-stream
))
64 ;; TODO: use the buffer pool
65 (defmethod close :around
((stream dual-channel-gray-stream
) &key abort
)
66 (with-accessors ((ibuf input-buffer-of
)
67 (obuf output-buffer-of
))
69 (trivial-garbage:cancel-finalization stream
)
70 (unless (or abort
(null ibuf
)) (finish-output stream
))
71 (free-stream-buffers ibuf obuf
)
72 (setf ibuf nil obuf nil
))
75 (defmethod (setf external-format-of
)
76 (external-format (stream dual-channel-gray-stream
))
77 (let ((canonical-ef (babel:ensure-external-format external-format
)))
78 (setf (slot-value stream
'external-format
) canonical-ef
)
79 (setf (slot-value stream
'eol-writer
)
80 (case (babel:external-format-eol-style canonical-ef
)
81 (:lf
#'stream-write-lf
)
82 (:crlf
#'stream-write-crlf
)
83 (:cr
#'stream-write-cr
)))
84 (setf (values (slot-value stream
'eol-finder
)
85 (slot-value stream
'eol-finder
/no-hang
))
86 (case (babel:external-format-eol-style canonical-ef
)
87 (:lf
(values #'stream-find-lf
#'stream-find-lf
/no-hang
))
88 (:crlf
(values #'stream-find-crlf
#'stream-find-crlf
/no-hang
))
89 (:cr
(values #'stream-find-cr
#'stream-find-cr
/no-hang
))))))
92 ;;;-------------------------------------------------------------------------
94 ;;;-------------------------------------------------------------------------
96 (defmethod stream-clear-input ((stream dual-channel-gray-stream
))
97 (iobuf-reset (input-buffer-of stream
)))
99 (declaim (inline %read-sequence
))
100 (defun %read-sequence
(stream seq start end
)
101 (check-bounds seq start end
)
104 (ub8-sarray (%read-into-simple-array-ub8 stream seq start end
))
105 (string (%read-into-string stream seq start end
))
106 (ub8-vector (%read-into-vector stream seq start end
)))
109 (declaim (inline read-sequence
*))
110 (defun read-sequence* (stream sequence
&key
(start 0) end
)
111 (%read-sequence stream sequence start end
))
113 (defmethod stream-read-sequence
114 ((stream dual-channel-gray-stream
) sequence start end
&key
)
115 (%read-sequence stream sequence start end
))
117 (defmethod drain-input-buffer
118 ((stream dual-channel-gray-stream
) sequence
&key
(start 0) end
)
119 (check-bounds sequence start end
)
120 (with-accessors ((ib input-buffer-of
))
122 (let ((nbytes (min (- end start
)
125 (iobuf-copy-into-lisp-array ib
(iobuf-start ib
)
128 (incf (iobuf-start ib
) nbytes
)
129 (let ((len (iobuf-length ib
)))
130 (values (+ start nbytes
)
131 (and (plusp len
) len
)))))))
134 ;;;-------------------------------------------------------------------------
136 ;;;-------------------------------------------------------------------------
138 (defmethod stream-clear-output ((stream dual-channel-gray-stream
))
139 (iobuf-reset (output-buffer-of stream
))
140 (setf (dirtyp stream
) nil
))
142 (defmethod stream-finish-output ((stream dual-channel-gray-stream
))
143 (with-accessors ((fd fd-of
)
144 (write-fn write-fn-of
)
145 (ob output-buffer-of
)
148 (with-hangup-guard stream
149 (%write-octets-from-iobuf write-fn fd ob
))
152 (defmethod stream-force-output ((stream dual-channel-gray-stream
))
153 (with-accessors ((fd fd-of
)
154 (write-fn write-fn-of
)
155 (ob output-buffer-of
)
158 (with-hangup-guard stream
159 (%write-octets-from-iobuf write-fn fd ob t
))
160 (unless (iobuf-empty-p ob
)
163 (declaim (inline %write-sequence
))
164 (defun %write-sequence
(stream seq start end
)
165 (check-bounds seq start end
)
168 (ub8-sarray (%write-simple-array-ub8 stream seq start end
))
169 (string (stream-write-string stream seq start end
))
170 (ub8-vector (%write-vector-ub8 stream seq start end
))
171 (vector (%write-vector stream seq start end
)))))
173 (declaim (inline write-sequence
*))
174 (defun write-sequence* (stream sequence
&key
(start 0) end
)
175 (%write-sequence stream sequence start end
))
177 (defmethod stream-write-sequence ((stream dual-channel-gray-stream
)
178 sequence start end
&key
)
179 (%write-sequence stream sequence start end
))
182 ;;;-------------------------------------------------------------------------
184 ;;;-------------------------------------------------------------------------
186 (defun %stream-rewind-iobuf
(stream iobuf encoding
)
187 (maybe-rewind-iobuf iobuf encoding
)
188 (setf (unread-index-of stream
) (iobuf-start iobuf
)))
190 (defmethod stream-read-char ((stream dual-channel-gray-stream
))
191 (with-accessors ((fd fd-of
)
194 (unread-index unread-index-of
)
195 (ef external-format-of
))
197 (let ((encoding (babel:external-format-encoding ef
)))
198 (%stream-rewind-iobuf stream ib encoding
)
200 ((and (iobuf-empty-p ib
)
201 (eql :eof
(%fill-ibuf ib fd read-fn
)))
204 ;; At this point, there's at least one octet in the buffer
205 (debug-only (assert (not (iobuf-empty-p ib
))))
206 (let ((line-end (funcall (eol-finder-of stream
) ib fd read-fn
)))
207 (if (eql #\Newline line-end
)
209 (decode-one-char fd read-fn ib encoding
))))))))
211 (defmethod stream-read-char-no-hang ((stream dual-channel-gray-stream
))
212 (with-accessors ((fd fd-of
)
215 (ef external-format-of
))
217 (let ((encoding (babel:external-format-encoding ef
)))
218 (%stream-rewind-iobuf stream ib encoding
)
219 (when (iobuf-empty-p ib
)
220 (let ((nbytes (%fill-ibuf
/no-hang ib fd read-fn
)))
222 ((eql :eof nbytes
) (return* :eof
))
223 ((zerop nbytes
) (return* nil
)))))
224 ;; At this point, there's at least one octet in the buffer
225 (debug-only (assert (not (iobuf-empty-p ib
))))
226 (let ((line-end (funcall (eol-finder/no-hang-of stream
) ib fd read-fn
)))
228 ((nil) (decode-one-char/no-hang ib encoding
))
229 (#\Newline
#\Newline
)
230 ;; There's a CR but it's not EOF so we could still receive a LF
231 (:incomplete nil
))))))
233 (defun %stream-unread-char
(stream)
234 (declare (type dual-channel-gray-stream stream
))
235 (with-accessors ((ib input-buffer-of
)
236 (unread-index unread-index-of
))
238 (symbol-macrolet ((start (iobuf-start ib
)))
240 ((> start unread-index
)
241 (setf start unread-index
))
242 ((= start unread-index
)
243 (error 'no-characters-to-unread
:stream stream
))
244 (t (bug "On stream ~S the buffer start(~A) is less than the unread index(~A)."
245 stream start unread-index
)))))
248 (defmethod stream-unread-char ((stream dual-channel-gray-stream
) character
)
249 (declare (ignore character
))
250 (%stream-unread-char stream
))
252 (defmethod stream-peek-char ((stream dual-channel-gray-stream
))
253 (let ((char (stream-read-char stream
)))
254 (cond ((eql :eof char
)
257 (%stream-unread-char stream
)
260 ;; (defmethod stream-read-line ((stream dual-channel-gray-stream))
263 (defmethod stream-listen ((stream dual-channel-gray-stream
))
264 (let ((char (stream-read-char-no-hang stream
)))
265 (cond ((characterp char
) (stream-unread-char stream char
) t
)
266 ((eql :eof char
) nil
)
270 ;;;-------------------------------------------------------------------------
272 ;;;-------------------------------------------------------------------------
274 (defmethod stream-write-char ((stream dual-channel-gray-stream
)
275 (character character
))
276 (%flush-obuf-if-needed stream
)
277 (if (char= character
#\Newline
)
278 (funcall (eol-writer-of stream
) stream
)
279 (let ((string (make-string 1 :initial-element character
)))
280 (declare (dynamic-extent string
))
281 (stream-write-string stream string
))))
283 (defmethod stream-line-column ((stream dual-channel-gray-stream
))
286 (defmethod stream-start-line-p ((stream dual-channel-gray-stream
))
289 (defmethod stream-terpri ((stream dual-channel-gray-stream
))
290 (write-char #\Newline stream
) nil
)
292 (defmethod stream-fresh-line ((stream dual-channel-gray-stream
))
293 (write-char #\Newline stream
) t
)
295 (defmethod stream-write-string ((stream dual-channel-gray-stream
)
296 (string string
) &optional
(start 0) end
)
297 (check-bounds string start end
)
298 (do* ((ef (external-format-of stream
))
299 (encoding (babel:external-format-encoding ef
)))
301 (case (char string start
)
303 (funcall (eol-writer-of stream
) stream
)
306 (setf start
(%write-string-chunk stream string start end encoding
)))))
310 ;;;-------------------------------------------------------------------------
312 ;;;-------------------------------------------------------------------------
314 (defmethod stream-read-byte ((stream dual-channel-gray-stream
))
315 (with-accessors ((fd fd-of
)
317 (ib input-buffer-of
))
319 (flet ((fill-buf-or-eof ()
321 (when (eql :eof
(%fill-ibuf ib fd read-fn
))
323 (when (zerop (iobuf-length ib
))
325 (iobuf-pop-octet ib
))))
328 ;;;-------------------------------------------------------------------------
330 ;;;-------------------------------------------------------------------------
332 (defmethod stream-write-byte ((stream dual-channel-gray-stream
) integer
)
333 (check-type integer ub8
"an unsigned 8-bit value")
334 (with-accessors ((ob output-buffer-of
))
336 (with-hangup-guard stream
337 (%flush-obuf-if-needed stream
))
338 (iobuf-push-octet ob integer
)))
341 ;;;-------------------------------------------------------------------------
342 ;;; Buffer-related functions
343 ;;;-------------------------------------------------------------------------
345 (defmethod input-buffer-size ((stream dual-channel-gray-stream
))
346 (iobuf-length (input-buffer-of stream
)))
348 (defmethod input-buffer-empty-p ((stream dual-channel-gray-stream
))
349 (iobuf-empty-p (input-buffer-of stream
)))
351 (defmethod output-buffer-size ((stream dual-channel-gray-stream
))
352 (iobuf-length (output-buffer-of stream
)))
354 (defmethod output-buffer-empty-p ((stream dual-channel-gray-stream
))
355 (iobuf-empty-p (output-buffer-of stream
)))