3 ;;; **********************************************************************
4 ;;; This code was written by Paul Foley and has been placed in the public
8 ;;; Sbcl port by Rudi Schlatte.
10 (in-package "SB-SIMPLE-STREAMS")
13 ;;; **********************************************************************
15 ;;; Base class and generic function definitions for simple-streams
18 ;;; 12.2 Strategy descriptions necessary for encapsulation
19 ;;; in the Franz documentation for a description of the j-xxx-fn slots.
21 ;;;; Types for buffer and strategy functions
23 (deftype simple-stream-buffer
()
24 '(or sb-sys
:system-area-pointer
(sb-kernel:simple-unboxed-array
(*))))
29 (deftype j-listen-fn
()
30 '(function (simple-stream) boolean
))
32 (deftype j-read-char-fn
()
33 '(function (simple-stream boolean t boolean
) t
)) ; may return EOF-VALUE
35 (deftype j-read-chars-fn
()
36 '(function (simple-stream string
(or character null
) fixnum fixnum blocking
)
37 (values fixnum
&optional
(member nil t
:eof
))))
39 (deftype j-write-char-fn
()
40 '(function ((or character null
) simple-stream
) (or character null
)))
42 (deftype j-write-chars-fn
()
43 '(function (string simple-stream fixnum fixnum
) t
)) ; return chars-written?
45 (deftype j-unread-char-fn
()
46 '(function (simple-stream t
) t
)) ; "relaxed" arg is boolean? what return?
48 ;;;; Base simple-stream classes
50 (def-stream-class simple-stream
(standard-object stream
)
51 (;; instance flags (not a normal slot in Allegro CL)
52 (%flags
:initform
0 :type fixnum
)
53 (plist :initform nil
:type list
:accessor stream-plist
)
55 ;; Strategy slots. See section 12.2 of streams.htm for function
56 ;; signatures and possible side-effects.
58 ;; A function that determines if one character can be successfully
60 (j-listen :initform
#'sb-kernel
:ill-in
:type j-listen-fn
)
61 ;; A function that reads one character.
62 (j-read-char :initform
#'sb-kernel
:ill-in
:type j-read-char-fn
)
63 ;; A function that reads characters into a string.
64 (j-read-chars :initform
#'sb-kernel
:ill-in
:type j-read-chars-fn
)
65 ;; A function that writes one character.
66 (j-write-char :initform
#'sb-kernel
:ill-out
:type j-write-char-fn
)
67 ;; A function that writes characters from a string into the stream.
68 (j-write-chars :initform
#'sb-kernel
:ill-out
:type j-write-chars-fn
)
69 ;; A function that unreads the last character read.
70 (j-unread-char :initform
#'sb-kernel
:ill-in
:type j-unread-char-fn
)
74 ;; TODO: find out what this one does
75 (oc-state :initform nil
)
76 ;; TODO: find out what this one does
77 (co-state :initform nil
)
78 (external-format :initform
(find-external-format :default
))
80 ;; A fixnum (denoting a valid file descriptor), a stream, or nil if
81 ;; the stream is not open for input.
82 (input-handle :initform nil
:initarg
:input-handle
83 :type
(or null fixnum stream
)
84 :accessor stream-input-handle
)
85 ;; A fixnum (denoting a valid file descriptor), a stream, or nil if
86 ;; the stream is not open for output.
87 (output-handle :initform nil
:initarg
:output-handle
88 :type
(or null fixnum stream
)
89 :accessor stream-output-handle
)
90 (control-in :initform nil
:type
(or null simple-vector
))
91 (control-out :initform nil
:type
(or null simple-vector
))
93 ;; a stream, allowing for composing external formats (see
94 ;; streams.htm, section 12.5) TODO: document this better
95 (melded-stream :type
(or null simple-stream
))
96 ;; a stream, allowing for composing external formats (see
97 ;; streams.htm, section 12.5) TODO: document this better
98 (melding-base :type
(or null simple-stream
))
100 ;; Number of octets the last read-char operation consumed TODO:
101 ;; document this better; what is the difference to
102 ;; last-char-read-size ?
103 (encapsulated-char-read-size :initform
0 :type fixnum
)
104 ;; Number of octets the last read-char operation consumed
105 (last-char-read-size :initform
0 :type fixnum
)
106 (charpos :initform
0 :type
(or null integer
)
107 :accessor stream-line-column
)
108 (record-end :initform nil
:type
(or null fixnum
))
110 ;; Input/output buffer.
111 (buffer :initform nil
:type
(or simple-stream-buffer null
))
112 ;; Current position in buffer.
113 (buffpos :initform
0 :type fixnum
)
114 ;; Maximum valid position in buffer, or -1 on eof.
115 (buffer-ptr :initform
0 :type fixnum
)
116 (buf-len :initform
0 :type fixnum
)
118 (pending :initform nil
:type list
)
119 (handler :initform nil
:type
(or null sb-impl
::handler
))))
121 (def-stream-class single-channel-simple-stream
(simple-stream)
122 (;; the "dirty" flag -- if this is > 0, write out buffer contents
123 ;; before changing position; see flush-buffer
124 (mode :initform
0 :type fixnum
)))
126 (def-stream-class dual-channel-simple-stream
(simple-stream)
128 (out-buffer :initform nil
:type
(or simple-stream-buffer null
))
129 ;; Current position in output buffer.
130 (outpos :initform
0 :type fixnum
)
131 ;; Buffer length (one greater than maximum output buffer index)
132 (max-out-pos :initform
0 :type fixnum
)))
134 ;;; A stream with a string as buffer.
135 (def-stream-class string-simple-stream
(simple-stream string-stream
)
139 ;;; ======================================================
143 ;;; DEVICE-LEVEL FUNCTIONS
146 (defgeneric device-open
(stream options
))
148 (defgeneric device-close
(stream abort
))
150 (defgeneric device-buffer-length
(stream))
152 (defgeneric device-file-position
(stream))
154 (defgeneric (setf device-file-position
) (value stream
))
156 (defgeneric device-file-length
(stream))
158 (defgeneric device-read
(stream buffer start end blocking
))
160 (defgeneric device-clear-input
(stream buffer-only
))
162 (defgeneric device-write
(stream buffer start end blocking
))
164 (defgeneric device-clear-output
(stream))
166 (defgeneric device-finish-record
(stream blocking action
))
169 (defmethod shared-initialize :after
((instance simple-stream
) slot-names
170 &rest initargs
&key
&allow-other-keys
)
171 (declare (ignore slot-names
))
172 (unless (slot-boundp instance
'melded-stream
)
173 (setf (slot-value instance
'melded-stream
) instance
)
174 (setf (slot-value instance
'melding-base
) instance
))
175 (unless (device-open instance initargs
)
176 (device-close instance t
)))
179 (defmethod print-object ((object simple-stream
) stream
)
180 (print-unreadable-object (object stream
:type nil
:identity nil
)
181 (cond ((not (any-stream-instance-flags object
:simple
))
182 (princ "Invalid " stream
))
183 ((not (any-stream-instance-flags object
:input
:output
))
184 (princ "Closed " stream
)))
185 (format stream
"~:(~A~)" (type-of object
))))
187 ;;; This takes care of the things all device-close methods have to do,
188 ;;; regardless of the type of simple-stream
189 (defmethod device-close :around
((stream simple-stream
) abort
)
190 (with-stream-class (simple-stream stream
)
191 (when (any-stream-instance-flags stream
:input
:output
)
192 (when (any-stream-instance-flags stream
:output
)
193 (ignore-errors (if abort
194 (clear-output stream
)
195 (finish-output stream
))))
197 (setf (sm input-handle stream
) nil
198 (sm output-handle stream
) nil
)
199 (remove-stream-instance-flags stream
:input
:output
)
200 (sb-ext:cancel-finalization stream
)
201 ;; This sets all readers and writers to error-raising functions
202 (setf (stream-external-format stream
) :void
))))
204 (defmethod device-close ((stream simple-stream
) abort
)
205 (declare (ignore abort
))
208 (defmethod device-buffer-length ((stream simple-stream
))
211 (defmethod device-file-position ((stream simple-stream
))
212 (with-stream-class (simple-stream stream
)
213 (sm buffpos stream
)))
215 (defmethod (setf device-file-position
) (value (stream simple-stream
))
216 (with-stream-class (simple-stream stream
)
217 (setf (sm buffpos stream
) value
)))
219 (defmethod device-file-length ((stream simple-stream
))
222 (defgeneric (setf stream-external-format
) (value stream
))
224 (defmethod (setf stream-external-format
) :before
(value (stream simple-stream
))
225 ;; (unless (eq value (sm external-format stream))
226 ;; flush out the existing external-format
229 (defmethod (setf stream-external-format
) :after
230 (ef (stream single-channel-simple-stream
))
231 (compose-encapsulating-streams stream ef
)
232 (install-single-channel-character-strategy (melding-stream stream
) ef nil
))
234 (defmethod (setf stream-external-format
) :after
235 (ef (stream dual-channel-simple-stream
))
236 (compose-encapsulating-streams stream ef
)
237 (install-dual-channel-character-strategy (melding-stream stream
) ef
))
240 (defmethod device-read ((stream single-channel-simple-stream
) buffer
242 (read-octets stream buffer start end blocking
))
244 (defmethod device-read ((stream dual-channel-simple-stream
) buffer
246 (read-octets stream buffer start end blocking
))
248 (defmethod device-clear-input ((stream simple-stream
) buffer-only
)
249 (declare (ignore buffer-only
))
252 (defmethod device-write ((stream single-channel-simple-stream
) buffer
254 ;; buffer may be :flush to force/finish-output
255 (when (or (and (null buffer
) (not (eql start end
)))
257 (with-stream-class (single-channel-simple-stream stream
)
258 (setf buffer
(sm buffer stream
))
259 (setf end
(sm buffpos stream
))))
260 (write-octets stream buffer start end blocking
))
262 (defmethod device-write ((stream dual-channel-simple-stream
) buffer
264 ;; buffer may be :flush to force/finish-output
265 (when (or (and (null buffer
) (not (eql start end
)))
267 (with-stream-class (dual-channel-simple-stream stream
)
268 (setf buffer
(sm out-buffer stream
))
269 (setf end
(sm outpos stream
))))
270 (write-octets stream buffer start end blocking
))
272 (defmethod device-clear-output ((stream simple-stream
))