0.9.12.30:
[sbcl.git] / contrib / sb-simple-streams / iodefs.lisp
1 ;;; -*- lisp -*-
2 ;;;
3 ;;; **********************************************************************
4 ;;; This code was written by Paul Foley and has been placed in the public
5 ;;; domain.
6 ;;;
7
8 ;;; Sbcl port by Rudi Schlatte.
9
10 ;;;
11 ;;; **********************************************************************
12 ;;;
13 ;;; Macros needed by the simple-streams implementation
14
15 (in-package "SB-SIMPLE-STREAMS")
16
17 (defmacro def-stream-class (name superclasses slots &rest options)
18   `(defclass ,name ,superclasses ,slots ,@options))
19
20
21 ;; All known stream flags.  Note that the position in the constant
22 ;; list is significant (cf. %flags below).
23 (sb-int:defconstant-eqx +flag-bits+
24                         '(:simple       ; instance is valid
25                           :input :output ; direction
26                           :dual :string ; type of stream
27                           :eof          ; latched EOF
28                           :dirty        ; output buffer needs write
29                           :interactive) ; interactive stream
30                         #'equal)
31
32 (eval-when (:compile-toplevel :load-toplevel :execute)
33   (defun %flags (flags)
34     (loop for flag in flags
35           as pos = (position flag +flag-bits+)
36         when (eq flag :gray) do
37           (error "Gray streams not supported.")
38         if pos
39           sum (ash 1 pos) into bits
40         else
41           collect flag into unused
42       finally (when unused
43                 (warn "Invalid stream instance flag~P: ~{~S~^, ~}"
44                       (length unused) unused))
45               (return bits))))
46
47 ;;; Setup an environment where sm, funcall-stm-handler and
48 ;;; funcall-stm-handler-2 are valid and efficient for a stream of type
49 ;;; class-name or for the stream argument (in which case the
50 ;;; class-name argument is ignored).  In nested with-stream-class
51 ;;; forms, the inner with-stream-class form must specify a stream
52 ;;; argument if the outer one specifies one, or the wrong object will
53 ;;; be accessed.
54
55 (defmacro with-stream-class ((class-name &optional stream) &body body)
56   (if stream
57     (let ((stm (gensym "STREAM"))
58           (slt (gensym "SV")))
59       `(let* ((,stm ,stream)
60               (,slt (sb-kernel:%instance-ref ,stm 1)))
61          (declare (type ,class-name ,stm)
62                   (type simple-vector ,slt)
63                   (ignorable ,slt))
64          (macrolet ((sm (slot-name stream)
65                       (declare (ignore stream))
66                       #-count-sm
67                       `(slot-value ,',stm ',slot-name)
68                       #+count-sm
69                       `(%sm ',slot-name ,',stm))
70                     (add-stream-instance-flags (stream &rest flags)
71                       (declare (ignore stream))
72                       `(setf (sm %flags ,',stm) (logior (the fixnum (sm %flags ,',stm))
73                                                         ,(%flags flags))))
74                     (remove-stream-instance-flags (stream &rest flags)
75                       (declare (ignore stream))
76                       `(setf (sm %flags ,',stm) (logandc2 (the fixnum (sm %flags ,',stm))
77                                                           ,(%flags flags))))
78                     (any-stream-instance-flags (stream &rest flags)
79                       (declare (ignore stream))
80                       `(not (zerop (logand (the fixnum (sm %flags ,',stm))
81                                            ,(%flags flags))))))
82            ,@body)))
83     `(macrolet ((sm (slot-name stream)
84                   #-count-sm
85                   `(slot-value ,stream ',slot-name)
86                   #+count-sm
87                   `(%sm ',slot-name ,stream)))
88        ,@body)))
89
90 (defmacro sm (slot-name stream)
91   "Access the named slot in Stream."
92   (warn "Using ~S macro outside ~S." 'sm 'with-stream-class)
93   `(slot-value ,stream ',slot-name))
94
95 (defmacro funcall-stm-handler (slot-name stream &rest args)
96   "Call the strategy function named by Slot-Name on Stream."
97   (let ((s (gensym)))
98     `(let ((,s ,stream))
99        (funcall (sm ,slot-name ,s) ,s ,@args))))
100
101 (defmacro funcall-stm-handler-2 (slot-name arg1 stream &rest args)
102   "Call the strategy function named by Slot-Name on Stream."
103   (let ((s (gensym)))
104     `(let ((,s ,stream))
105        (funcall (sm ,slot-name ,s) ,arg1 ,s ,@args))))
106
107 (defmacro add-stream-instance-flags (stream &rest flags)
108   "Set the given Flags in Stream."
109   (let ((s (gensym "STREAM")))
110     `(let ((,s ,stream))
111        (with-stream-class (simple-stream ,s)
112          (add-stream-instance-flags ,s ,@flags)))))
113
114 (defmacro remove-stream-instance-flags (stream &rest flags)
115   "Clear the given Flags in Stream."
116   (let ((s (gensym "STREAM")))
117     `(let ((,s ,stream))
118        (with-stream-class (simple-stream ,s)
119          (remove-stream-instance-flags ,s ,@flags)))))
120
121 (defmacro any-stream-instance-flags (stream &rest flags)
122   "Determine whether any one of the Flags is set in Stream."
123   (let ((s (gensym "STREAM")))
124     `(let ((,s ,stream))
125        (with-stream-class (simple-stream ,s)
126          (any-stream-instance-flags ,s ,@flags)))))
127
128 (defmacro simple-stream-dispatch (stream single dual string)
129   (let ((s (gensym "STREAM")))
130     `(let ((,s ,stream))
131        (with-stream-class (simple-stream ,s)
132          (let ((%flags (sm %flags ,s)))
133            (cond ((zerop (logand %flags ,(%flags '(:string :dual))))
134                   ,single)
135                  ((zerop (logand %flags ,(%flags '(:string))))
136                   ,dual)
137                  (t
138                   ,string)))))))
139
140 (defmacro simple-stream-dispatch-2 (stream non-string string)
141   (let ((s (gensym "STREAM")))
142     `(let ((,s ,stream))
143        (with-stream-class (simple-stream ,s)
144          (let ((%flags (sm %flags ,s)))
145            (cond ((zerop (logand %flags ,(%flags '(:string))))
146                   ,non-string)
147                  (t
148                   ,string)))))))
149
150
151 ;;;; The following two forms are for Franz source-compatibility,
152 ;;;; disabled at the moment.
153
154 #+nil
155 (defpackage "EXCL"
156   (:use "SB-SIMPLE-STREAMS")
157   (:import-from "SB-SIMPLE-STREAMS"
158         "BUFFER" "BUFFPOS" "BUFFER-PTR"
159         "OUT-BUFFER" "MAX-OUT-POS"
160         "INPUT-HANDLE" "OUTPUT-HANDLE"
161         "MELDED-STREAM"
162         "J-READ-CHARS"))
163
164 #+nil
165 (provide :iodefs)
166