1 ;;;;------------------------------------------------------------------
3 ;;;; Copyright (C) 2001, 2003-2005,
4 ;;;; Department of Computer Science, University of Tromso, Norway.
6 ;;;; For distribution policy, see the accompanying file COPYING.
8 ;;;; Filename: simple-streams.lisp
10 ;;;; Author: Frode Vatvedt Fjeld <frodef@acm.org>
11 ;;;; Created at: Fri Aug 29 13:39:43 2003
13 ;;;; $Id: simple-streams.lisp,v 1.8 2005/06/10 18:35:44 ffjeld Exp $
15 ;;;;------------------------------------------------------------------
17 (require :muerte
/basic-macros
)
18 (require :muerte
/los-closette
)
19 (provide :muerte
/simple-streams
)
23 (defvar *default-external-format
* :ascii
)
26 (defconstant +flag-bits
+ '(:simple
; instance is valid
27 :input
:output
; direction
28 :dual
:string
; type of stream
30 :dirty
; output buffer needs write
31 :interactive
)) ; interactive stream
34 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
36 (loop for flag in flags
37 as pos
= (position flag
+flag-bits
+)
38 when
(eq flag
:gray
) do
39 (error "Gray streams not supported.")
41 sum
(ash 1 pos
) into bits
43 collect flag into unused
45 (warn "Invalid stream instance flag~P: ~{~S~^, ~}"
46 (length unused
) unused
))
49 (defmacro simple-stream-dispatch
(stream single-clause dual-clause string-clause
)
50 (assert (eq 'single-channel-simple-stream
(car single-clause
)))
51 (assert (eq 'dual-channel-simple-stream
(car dual-clause
)))
52 (assert (eq 'string-simple-stream
(car string-clause
)))
53 (let ((s (gensym "stream-")))
55 (with-stream-class (simple-stream ,s
)
56 (let ((%flags
(sm %flags
,s
)))
57 (cond ((zerop (logand %flags
,(%flags
'(:string
:dual
))))
58 ,@(cdr single-clause
))
59 ((zerop (logand %flags
,(%flags
'(:string
))))
61 (t ,@(cdr string-clause
))))))))
63 (defmacro with-stream-class
((class-name &optional stream
) &body body
)
65 (let ((stream-var (gensym "stream-"))
66 (slots-var (gensym "stream-slots-")))
67 `(let* ((,stream-var
,stream
)
68 (,slots-var
(std-instance-slots ,stream-var
)))
69 (declare (type ,class-name
,stream-var
)
70 (type simple-vector
,slots-var
)
71 (ignorable ,slots-var
))
72 (macrolet ((sm (slot-name stream
)
73 (declare (ignore stream
))
74 `(slot-value ,',stream-var
',slot-name
)
75 #+ignore
`(svref%unsafe
,',slots-var
76 ,(slot-location ,(movitz-find-class class-name
)
78 (add-stream-instance-flags (stream &rest flags
)
79 (declare (ignore stream
))
80 `(setf (sm %flags
,',stream-var
)
81 (logior (sm %flags
,',stream-var
)
83 (remove-stream-instance-flags (stream &rest flags
)
84 (declare (ignore stream
))
85 `(setf (sm %flags
,',stream-var
)
86 (logandc2 (sm %flags
,',stream-var
)
88 (any-stream-instance-flags (stream &rest flags
)
89 (declare (ignore stream
))
90 `(not (zerop (logand (sm %flags
,',stream-var
)
93 `(macrolet ((sm (slot-name stream
)
94 `(svref%unsafe
(std-instance-slots stream
)
95 ,(slot-location ,(movitz-find-class class-name
)
99 (defmacro sm
(slot-name stream
)
100 "Access the named slot in Stream."
101 ;; (warn "Using ~S macro outside ~S." 'sm 'with-stream-class)
102 `(slot-value ,stream
',slot-name
))
104 (defmacro funcall-stm-handler
(slot-name stream
&rest args
)
105 "Call the strategy function named by Slot-Name on Stream."
108 (funcall (sm ,slot-name
,s
) ,s
,@args
))))
110 (defmacro funcall-stm-handler-2
(slot-name arg1 stream
&rest args
)
111 "Call the strategy function named by Slot-Name on Stream."
114 (funcall (sm ,slot-name
,s
) ,arg1
,s
,@args
))))
116 (defmacro add-stream-instance-flags
(stream &rest flags
)
117 "Set the given Flags in Stream."
118 (let ((s (gensym "STREAM")))
120 (with-stream-class (simple-stream ,s
)
121 (add-stream-instance-flags ,s
,@flags
)))))
123 (defmacro remove-stream-instance-flags
(stream &rest flags
)
124 "Clear the given Flags in Stream."
125 (let ((s (gensym "STREAM")))
127 (with-stream-class (simple-stream ,s
)
128 (remove-stream-instance-flags ,s
,@flags
)))))
130 (defmacro any-stream-instance-flags
(stream &rest flags
)
131 "Determine whether any one of the Flags is set in Stream."
132 (let ((s (gensym "STREAM")))
134 (with-stream-class (simple-stream ,s
)
135 (any-stream-instance-flags ,s
,@flags
)))))
138 (defun ill-in-any (stream &rest ignore
)
139 (declare (ignore ignore
))
140 (error 'simple-type-error
142 :expected-type
'(satisfies input-stream-p
)
143 :format-control
"~S is not an input stream."
144 :format-arguments
(list stream
)))
146 (defun ill-out-any (stream &rest ignore
)
147 (declare (ignore ignore
))
148 (error 'simple-type-error
150 :expected-type
'(satisfies output-stream-p
)
151 :format-control
"~S is not an output stream."
152 :format-arguments
(list stream
)))
154 (defclass simple-stream
(stream)
161 :accessor stream-plist
)
164 :initform
'ill-in-any
167 :initform
'ill-in-any
168 :type j-read-char-fn
)
170 :initform
'ill-in-any
171 :type j-read-chars-fn
)
173 :initform
'ill-in-any
174 :type j-unread-char-fn
)
176 :initform
'ill-out-any
177 :type j-write-char-fn
) ;@@
179 :initform
'ill-out-any
180 :type j-write-chars-fn
) ;@@
187 :initform
*default-external-format
*)
191 :initarg
:input-handle
192 :type
(or null fixnum stream
)
194 :accessor stream-input-handle
)
197 :initarg
:output-handle
198 :type
(or null fixnum stream
)
199 :accessor stream-output-handle
)
202 :type
(or null simple-vector
))
205 :type
(or null simple-vector
))
208 :type
(or null simple-stream
))
210 :type
(or null simple-stream
))
212 (encapsulated-char-read-size
220 :type
(or null integer
)
221 :accessor stream-line-column
)
224 :type
(or null fixnum
))
228 :type
(or simple-stream-buffer null
))
244 :type
(or null handler
))))
246 (defclass single-channel-simple-stream
(simple-stream)
251 (defclass dual-channel-simple-stream
(simple-stream)
254 :type
(or simple-stream-buffer null
))
262 (defclass string-simple-stream
(simple-stream) ())
267 ;;;; Generic function definitions
269 (defgeneric device-open
(stream options
)
270 (:documentation
"Write me"))
272 (defgeneric device-close
(stream abort
)
273 (:documentation
"Write me"))
275 (defgeneric device-buffer-length
(stream)
276 (:documentation
"Write me"))
278 (defgeneric device-file-position
(stream)
279 (:documentation
"Write me"))
281 (defgeneric (setf device-file-position
) (value stream
)
282 ;; (:argument-precedence-order stream value)
283 (:documentation
"Write me"))
285 (defgeneric device-file-length
(stream)
286 (:documentation
"Write me"))
288 (defgeneric device-read
(stream buffer start end blocking
)
289 (:documentation
"Write me"))
291 (defgeneric device-clear-input
(stream buffer-only
)
292 (:documentation
"Write me"))
294 (defgeneric device-write
(stream buffer start end blocking
)
295 (:documentation
"Write me"))
297 (defgeneric device-clear-output
(stream)
298 (:documentation
"Write me"))
300 (defgeneric device-finish-record
(stream blocking action
)
301 (:documentation
"Write me"))
303 (defmethod shared-initialize :after
((instance simple-stream
) slot-names
304 &rest initargs
&key
&allow-other-keys
)
305 (declare (ignore slot-names
)
306 (dynamic-extent initargs
))
307 (unless (slot-boundp instance
'melded-stream
)
308 (setf (slot-value instance
'melded-stream
) instance
)
309 (setf (slot-value instance
'melding-base
) instance
))
310 (unless (device-open instance initargs
)
311 (device-close instance t
)))
313 (defmethod print-object ((object simple-stream
) stream
)
314 (print-unreadable-object (object stream
:type nil
:identity nil
)
315 (cond ((not (any-stream-instance-flags object
:simple
))
316 (princ "Invalid " stream
))
317 ((not (any-stream-instance-flags object
:input
:output
))
318 (princ "Closed " stream
)))
319 (format stream
"~:(~A~)" (type-of object
))))
322 (defmethod device-close :around
((stream simple-stream
) abort
)
323 (with-stream-class (simple-stream stream
)
324 (when (any-stream-instance-flags stream
:input
:output
)
325 (when (any-stream-instance-flags stream
:output
)
326 (ignore-errors (if abort
327 (clear-output stream
)
328 (%finish-output stream
))))
330 (setf (sm input-handle stream
) nil
331 (sm output-handle stream
) nil
)
332 (remove-stream-instance-flags stream
:input
:output
)
333 ;; (ext:cancel-finalization stream)
334 (setf (stream-external-format stream
) :void
))))
336 (defmethod device-close ((stream simple-stream
) abort
)
337 (declare (ignore abort
))
340 (defmethod device-buffer-length ((stream simple-stream
))
343 (defmethod device-file-position ((stream simple-stream
))
344 (with-stream-class (simple-stream stream
)
345 (sm buffpos stream
)))
347 (defmethod (setf device-file-position
) (value (stream simple-stream
))
348 (with-stream-class (simple-stream stream
)
349 (setf (sm buffpos stream
) value
)))
351 (defmethod device-file-length ((stream simple-stream
))
354 (defmethod (setf stream-external-format
) (ef (stream simple-stream
))
355 (with-stream-class (simple-stream stream
)
356 (setf (sm external-format stream
) (find-external-format ef
)))
359 (defmethod (setf stream-external-format
) :after
(ef (stream single-channel-simple-stream
))
360 (with-stream-class (single-channel-simple-stream stream
)
361 (compose-encapsulating-streams stream ef
)
362 (install-single-channel-character-strategy (melding-stream stream
)
365 (defmethod (setf stream-external-format
) :after
(ef (stream dual-channel-simple-stream
))
366 (with-stream-class (dual-channel-simple-stream stream
)
367 (compose-encapsulating-streams stream ef
)
368 (install-dual-channel-character-strategy (melding-stream stream
) ef
)))
370 ;;;(defmethod device-read ((stream single-channel-simple-stream) buffer start end blocking)
371 ;;; (read-octets stream buffer start end blocking))
373 ;;;(defmethod device-read ((stream dual-channel-simple-stream) buffer start end blocking)
374 ;;; (read-octets stream buffer start end blocking))
376 (defmethod device-clear-input ((stream simple-stream
) buffer-only
)
377 (declare (ignore buffer-only
))
380 (defmethod device-write ((stream single-channel-simple-stream
) buffer
382 ;; buffer may be :flush to force/finish-output
383 (when (or (and (null buffer
) (not (eql start end
)))
385 (with-stream-class (single-channel-simple-stream stream
)
386 (setf buffer
(sm buffer stream
))
387 (setf end
(sm buffpos stream
))))
388 (write-octets stream buffer start end blocking
))
390 (defmethod device-write ((stream dual-channel-simple-stream
) buffer
392 ;; buffer may be :flush to force/finish-output
393 (when (or (and (null buffer
) (not (eql start end
)))
395 (with-stream-class (dual-channel-simple-stream stream
)
396 (setf buffer
(sm out-buffer stream
))
397 (setf end
(sm outpos stream
))))
398 (write-octets stream buffer start end blocking
))
400 (defmethod device-clear-output ((stream simple-stream
))
403 ;;;; CL layer interface
405 (defun %check
(stream kind
)
406 (declare (type simple-stream stream
)
407 (optimize (speed 3) (space 1) (debug 0) (safety 0)))
408 (with-stream-class (simple-stream stream
)
409 (cond ((not (any-stream-instance-flags stream
:simple
))
410 (error "~S is uninitialized." stream
))
411 ((and (eq kind
:open
)
412 (not (any-stream-instance-flags stream
:input
:output
)))
413 (closed-flame stream
))
414 ((and (or (eq kind
:input
) (eq kind
:io
))
415 (not (any-stream-instance-flags stream
:input
)))
417 ((and (or (eq kind
:output
) (eq kind
:io
))
418 (not (any-stream-instance-flags stream
:output
)))
419 (ill-out-any stream
)))))
421 (defun %write-char
(character stream
)
424 (funcall stream
'stream-write-char character
))
426 (with-stream-class (simple-stream stream
)
427 (%check stream
:output
)
428 (funcall-stm-handler-2 j-write-char character
(sm melded-stream stream
))))
430 (vector-push-extend character stream
))))
432 (defun %read-line
(stream eof-error-p eof-value recursive-p
)
433 (declare (ignore recursive-p
))
436 (funcall stream
'read-line eof-error-p eof-value
))
438 (with-stream-class (simple-stream stream
)
439 (%check stream
:input
)
440 (when (any-stream-instance-flags stream
:eof
)
441 (return-from %read-line
442 (eof-or-lose stream eof-error-p eof-value
)))
443 ;; for interactive streams, finish output first to force prompt
444 (when (and (any-stream-instance-flags stream
:output
)
445 (any-stream-instance-flags stream
:interactive
))
446 (%finish-output stream
))
447 (let* ((encap (sm melded-stream stream
)) ; encapsulating stream
448 (cbuf (make-string 80)) ; current buffer
449 (bufs (list cbuf
)) ; list of buffers
450 (tail bufs
) ; last cons of bufs list
451 (index 0) ; current index in current buffer
452 (total 0)) ; total characters
454 (multiple-value-bind (chars done
)
455 (funcall-stm-handler j-read-chars encap cbuf
456 #\Newline index
(length cbuf
) t
)
459 (when (and (eq done
:eof
) (zerop total
))
461 (error 'end-of-file
:stream stream
)
462 (return (values eof-value t
))))
464 ;; If there's only one buffer in use, return it directly
465 (when (null (cdr bufs
))
466 (return (values (shrink-vector cbuf total
)
468 ;; If total fits in final buffer, use it
469 (when (<= total
(length cbuf
))
470 (replace cbuf cbuf
:start1
(- total index
) :end2 index
)
472 (declare (type index idx
))
473 (do ((list bufs
(cdr list
)))
475 (let ((buf (car list
)))
476 (declare (type simple-base-string buf
))
477 (replace cbuf buf
:start1 idx
)
478 (incf idx
(length buf
)))))
479 (return (values (shrink-vector cbuf total
)
481 ;; Allocate new string of appropriate length
482 (let ((string (make-string total
))
484 (declare (type index index
))
486 (declare (type simple-base-string buf
))
487 (replace string buf
:start1 index
)
488 (incf index
(length buf
)))
489 (return (values string
(eq done
:eof
)))))
490 (when (>= index
(length cbuf
))
491 (setf cbuf
(make-string (the index
(* 2 index
))))
493 (setf (cdr tail
) (cons cbuf nil
))
494 (setf tail
(cdr tail
))))))))))
496 (defun %read-char
(stream eof-error-p eof-value recursive-p blocking-p
)
497 (declare (ignore recursive-p
))
500 (funcall stream
'stream-read-char
))
502 (with-stream-class (simple-stream stream
)
503 (%check stream
:input
)
504 (when (any-stream-instance-flags stream
:eof
)
505 (return-from %read-char
506 (eof-or-lose stream eof-error-p eof-value
)))
507 ;; for interactive streams, finish output first to force prompt
508 (when (and (any-stream-instance-flags stream
:output
)
509 (any-stream-instance-flags stream
:interactive
))
510 (%finish-output stream
))
511 (funcall-stm-handler j-read-char
(sm melded-stream stream
)
512 eof-error-p eof-value blocking-p
)))))
514 (defun %read-key
(stream eof-error-p eof-value recursive-p blocking-p
)
517 (funcall stream
'stream-read-key
))
519 (%read-char stream eof-error-p eof-value recursive-p blocking-p
))))
521 (defun %unread-char
(stream character
)
522 (declare (type simple-stream stream
) (ignore character
))
523 (with-stream-class (simple-stream stream
)
524 (%check stream
:input
)
525 (if (zerop (sm last-char-read-size stream
))
526 (error "Nothing to unread.")
528 (funcall-stm-handler j-unread-char
(sm melded-stream stream
) nil
)
529 (remove-stream-instance-flags stream
:eof
)
530 (setf (sm last-char-read-size stream
) 0)))))
532 (defun %peek-char
(stream peek-type eof-error-p eof-value recursive-p
)
533 (declare (type simple-stream stream
)
534 (ignore recursive-p
))
535 (with-stream-class (simple-stream stream
)
536 (%check stream
:input
)
537 (when (any-stream-instance-flags stream
:eof
)
538 (return-from %peek-char
539 (eof-or-lose stream eof-error-p eof-value
)))
540 (let* ((encap (sm melded-stream stream
))
541 (char (funcall-stm-handler j-read-char encap
542 eof-error-p stream t
)))
543 (cond ((eq char stream
) eof-value
)
544 ((characterp peek-type
)
545 (do ((char char
(funcall-stm-handler j-read-char encap
548 ((or (eq char stream
) (char= char peek-type
))
549 (unless (eq char stream
)
550 (funcall-stm-handler j-unread-char encap t
))
551 (if (eq char stream
) eof-value char
))))
553 (do ((char char
(funcall-stm-handler j-read-char encap
556 ((or (eq char stream
)
557 (not (char-whitespace-p char
)))
558 (unless (eq char stream
)
559 (funcall-stm-handler j-unread-char encap t
))
560 (if (eq char stream
) eof-value char
))))
562 (funcall-stm-handler j-unread-char encap t
)
566 (defun %finish-output
(stream)
567 (declare (type simple-stream stream
))
568 (with-stream-class (simple-stream stream
)
569 (%check stream
:output
)
570 (when (sm handler stream
)
572 ((null (sm pending stream
)))
573 #+ignore
(sys:serve-all-events
)))
574 (device-write stream
:flush
0 nil t
)
575 (simple-stream-dispatch stream
576 (single-channel-simple-stream
577 (setf (sm buffpos stream
) 0))
578 (dual-channel-simple-stream
579 (with-stream-class (dual-channel-simple-stream stream
)
580 (setf (sm outpos stream
) 0)))
581 (string-simple-stream
585 (defun %force-output
(stream)
586 (declare (type simple-stream stream
))
587 (with-stream-class (simple-stream stream
)
588 (%check stream
:output
)
589 (device-write stream
:flush
0 nil nil
)
590 (simple-stream-dispatch stream
591 (single-channel-simple-stream
592 (setf (sm buffpos stream
) 0))
593 (dual-channel-simple-stream
594 (with-stream-class (dual-channel-simple-stream stream
)
595 (setf (sm outpos stream
) 0)))
596 (string-simple-stream)))
599 (defun %clear-output
(stream)
600 (declare (type simple-stream stream
))
601 (with-stream-class (simple-stream stream
)
602 (%check stream
:output
)
603 (when (sm handler stream
)
604 (setf (sm handler stream
) nil
605 (sm pending stream
) nil
))
606 (simple-stream-dispatch stream
607 (single-channel-simple-stream
608 (with-stream-class (single-channel-simple-stream stream
)
609 (case (sm mode stream
)
610 (1 (setf (sm buffpos stream
) 0))
611 (3 (setf (sm mode stream
) 0)))))
612 (dual-channel-simple-stream
613 (with-stream-class (dual-channel-simple-stream stream
)
614 (setf (sm outpos stream
) 0)))
615 (string-simple-stream))
616 (device-clear-output stream
)))
623 (defun null-read-char (stream eof-error-p eof-value blocking
)
624 (declare (ignore blocking
))
625 (eof-or-lose stream eof-error-p eof-value
))
627 (defun null-read-chars (stream string search start end blocking
)
628 (declare (ignore stream string search start end blocking
))
631 (defun null-unread-char (stream relaxed
)
632 (declare (ignore stream relaxed
)))
634 (defun null-write-char (character stream
)
635 (declare (ignore stream
))
638 (defun null-write-chars (string stream start end
)
639 (declare (ignore string stream
))
642 (defun null-listen (stream)
643 (declare (ignore stream
))
646 (defclass null-simple-stream
(single-channel-simple-stream) ())
648 (defmethod device-open ((stream null-simple-stream
) options
)
649 (with-stream-class (null-simple-stream stream
)
650 (add-stream-instance-flags stream
:simple
:input
:output
)
651 (setf (sm j-read-char stream
) 'null-read-char
652 (sm j-read-chars stream
) 'null-read-chars
653 (sm j-unread-char stream
) 'null-unread-char
654 (sm j-write-char stream
) 'null-write-char
655 (sm j-write-chars stream
) 'null-write-chars
656 (sm j-listen stream
) 'null-listen
))
659 (defmethod device-buffer-length ((stream null-simple-stream
))
662 (defmethod device-write ((stream null-simple-stream
) buffer start end blocking
)
663 (declare (ignore buffer blocking
))
666 (defmethod device-read ((stream null-simple-stream
) buffer start end blocking
)
667 (declare (ignore buffer start end blocking
))
672 (defclass string-input-simple-stream
(string-simple-stream) ())
674 (defclass string-output-simple-stream
(string-simple-stream)
677 :type
(or simple-stream-buffer null
))
685 (defclass composing-stream
(string-simple-stream) ())
687 (defun install-string-input-character-strategy (stream)
689 (with-stream-class (simple-stream stream
)
690 (setf (sm j-read-char stream
) #'string-read-char-e-crlf
))
693 (defun install-string-output-character-strategy (stream)
694 (declare (ignore stream
))
697 (defun string-read-char-e-crlf (stream eof-error-p eof-value blocking
)
698 (with-stream-class (composing-stream stream
)
699 (let* ((encap (sm melded-stream stream
))
700 (ctrl (sm control-in stream
))
701 (char (funcall-stm-handler j-read-char encap nil stream blocking
)))
702 ;; if CHAR is STREAM, we hit EOF; if NIL, blocking is NIL and no
703 ;; character was available...
704 (when (eql char
#\Return
)
705 (let ((next (funcall-stm-handler j-read-char encap nil stream blocking
)))
706 ;; if NEXT is STREAM, we hit EOF, so we should just return the
707 ;; #\Return (and mark the stream :EOF? At least unread if we
708 ;; got a soft EOF, from a terminal, etc.
709 ;; if NEXT is NIL, blocking is NIL and there's a CR but no
710 ;; LF available on the stream: have to unread the CR and
711 ;; return NIL, letting the CR be reread later.
713 ;; If we did get a linefeed, adjust the last-char-read-size
714 ;; so that an unread of the resulting newline will unread both
715 ;; the linefeed _and_ the carriage return.
716 (if (eql next
#\Linefeed
)
717 (setq char
#\Newline
)
718 (funcall-stm-handler j-unread-char encap nil
))))
719 (when (characterp char
)
720 (let ((code (char-code char
)))
721 (when (and (< code
32) ctrl
(svref ctrl code
))
722 (setq char
(funcall (the (or symbol function
) (svref ctrl code
))
725 (eof-or-lose stream eof-error-p eof-value
)
728 (defmethod device-open :before
((stream string-input-simple-stream
) options
)
729 ;; Taken with permission from ftp://ftp.franz.com/pub/duane/Simp-stms.ppt
730 (with-stream-class (string-input-simple-stream stream
)
731 (let ((string (getf options
:string
)))
732 (when (and string
(null (sm buffer stream
)))
733 (let ((start (getf options
:start
))
734 (end (or (getf options
:end
) (length string
))))
735 (setf (sm buffer stream
) string
736 (sm buffpos stream
) start
737 (sm buffer-ptr stream
) end
))))
738 (install-string-input-character-strategy stream
)
739 (add-stream-instance-flags stream
:string
:input
:simple
)))
742 (defmethod device-open :before
((stream string-output-simple-stream
) options
)
743 ;; Taken with permission from ftp://ftp.franz.com/pub/duane/Simp-stms.ppt
744 (with-stream-class (string-output-simple-stream stream
)
745 (unless (sm out-buffer stream
)
746 (let ((string (getf options
:string
)))
748 (setf (sm out-buffer stream
) string
749 (sm max-out-pos stream
) (length string
))
750 (let ((buflen (max (device-buffer-length stream
) 16)))
751 (setf (sm out-buffer stream
) (make-string buflen
)
752 (sm max-out-pos stream
) buflen
)))))
753 (unless (sm control-out stream
)
754 (setf (sm control-out stream
) *std-control-out-table
*))
755 (install-string-output-character-strategy stream
)
756 (add-stream-instance-flags stream
:string
:output
:simple
)))
758 (defmethod device-open ((stream string-simple-stream
) options
)
759 (declare (ignore options
))
760 (with-stream-class (string-simple-stream stream
)
761 (if (and (any-stream-instance-flags stream
:simple
)
762 (any-stream-instance-flags stream
:input
:output
))
766 (defmethod device-file-position ((stream string-simple-stream
))
767 (with-stream-class (simple-stream stream
)
768 (sm buffpos stream
)))
770 (defmethod (setf device-file-position
) (value (stream string-simple-stream
))
771 (with-stream-class (simple-stream stream
)
772 (cond ((or (> value
(sm buffer-ptr stream
))
773 (< value
(- -
1 (sm buffer-ptr stream
))))
776 (setf (sm buffpos stream
) value
)
779 (setf (sm buffpos stream
) (+ (sm buffer-ptr stream
) value
1))
782 (defmethod device-file-length ((stream string-simple-stream
))
783 (with-stream-class (simple-stream stream
)
784 (sm buffer-ptr stream
)))