1 ;;;; os-independent stream functions requiring reader machinery
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB!IMPL")
14 ;;; In the interest of ``once and only once'' this macro contains the
15 ;;; framework necessary to implement a peek-char function, which has
16 ;;; two special-cases (one for gray streams and one for echo streams)
17 ;;; in addition to the normal case.
19 ;;; All arguments are forms which will be used for a specific purpose
20 ;;; PEEK-TYPE - the current peek-type as defined by ANSI CL
21 ;;; EOF-VALUE - the eof-value argument to peek-char
22 ;;; CHAR-VAR - the variable which will be used to store the current character
23 ;;; READ-FORM - the form which will be used to read a character
24 ;;; UNREAD-FORM - ditto for unread-char
25 ;;; SKIPPED-CHAR-FORM - the form to execute when skipping a character
26 ;;; EOF-DETECTED-FORM - the form to execute when EOF has been detected
27 ;;; (this will default to CHAR-VAR)
28 (sb!xc:defmacro generalized-peeking-mechanism
29 (peek-type eof-value char-var read-form unread-form
30 &optional (skipped-char-form nil) (eof-detected-form nil))
31 `(let ((,char-var ,read-form))
32 (cond ((eql ,char-var ,eof-value)
33 ,(if eof-detected-form
36 ((characterp ,peek-type)
37 (do ((,char-var ,char-var ,read-form))
38 ((or (eql ,char-var ,eof-value)
39 (char= ,char-var ,peek-type))
40 (cond ((eql ,char-var ,eof-value)
41 ,(if eof-detected-form
48 (do ((,char-var ,char-var ,read-form))
49 ((or (eql ,char-var ,eof-value)
50 (not (whitespacep ,char-var)))
51 (cond ((eql ,char-var ,eof-value)
52 ,(if eof-detected-form
62 (bug "Impossible case reached in PEEK-CHAR")))))
64 ;;; rudi (2004-08-09): There was an inline declaration for read-char,
65 ;;; unread-char, read-byte, listen here that was removed because these
66 ;;; functions are redefined when simple-streams are loaded.
68 #!-sb-fluid (declaim (inline ansi-stream-peek-char))
69 (defun ansi-stream-peek-char (peek-type stream eof-error-p eof-value
71 (cond ((typep stream 'echo-stream)
75 (list eof-error-p eof-value)))
77 (generalized-peeking-mechanism
78 peek-type eof-value char
79 (ansi-stream-read-char stream eof-error-p eof-value recursive-p)
80 (ansi-stream-unread-char char stream)))))
82 (defun peek-char (&optional (peek-type nil)
83 (stream *standard-input*)
87 (the (or character boolean) peek-type)
88 (let ((stream (in-synonym-of stream)))
89 (if (ansi-stream-p stream)
90 (ansi-stream-peek-char peek-type stream eof-error-p eof-value
92 ;; by elimination, must be Gray streams FUNDAMENTAL-STREAM
93 (generalized-peeking-mechanism
96 (stream-peek-char stream)
97 (stream-read-char stream))
100 (stream-unread-char stream char))
102 (eof-or-lose stream eof-error-p eof-value)))))
104 (defun echo-misc (stream operation &optional arg1 arg2)
105 (let* ((in (two-way-stream-input-stream stream))
106 (out (two-way-stream-output-stream stream)))
109 (or (not (null (echo-stream-unread-stuff stream)))
110 (if (ansi-stream-p in)
111 (or (/= (the fixnum (ansi-stream-in-index in))
112 +ansi-stream-in-buffer-length+)
113 (funcall (ansi-stream-misc in) in :listen))
114 (stream-misc-dispatch in :listen))))
115 (:unread (push arg1 (echo-stream-unread-stuff stream)))
117 (let ((in-type (stream-element-type in))
118 (out-type (stream-element-type out)))
119 (if (equal in-type out-type)
120 in-type `(and ,in-type ,out-type))))
122 (set-closed-flame stream))
124 ;; For the special case of peeking into an echo-stream
125 ;; arg1 is PEEK-TYPE, arg2 is (EOF-ERROR-P EOF-VALUE)
126 ;; returns peeked-char, eof-value, or errors end-of-file
128 ;; Note: This code could be moved into PEEK-CHAR if desired.
129 ;; I am unsure whether this belongs with echo-streams because it is
130 ;; echo-stream specific, or PEEK-CHAR because it is peeking code.
133 ;; UNREAD-CHAR-P indicates whether the current character was one
134 ;; that was previously unread. In that case, we need to ensure that
135 ;; the semantics for UNREAD-CHAR are held; the character should
136 ;; not be echoed again.
137 (let ((unread-char-p nil))
139 (unless unread-char-p
140 (if (ansi-stream-p out)
141 (funcall (ansi-stream-out out) out c)
143 (stream-write-char out c))))
145 ;; Obtain input from unread buffer or input stream,
146 ;; and set the flag appropriately.
147 (cond ((not (null (echo-stream-unread-stuff stream)))
148 (setf unread-char-p t)
149 (pop (echo-stream-unread-stuff stream)))
151 (setf unread-char-p nil)
152 (read-char in (first arg2) (second arg2))))))
153 (generalized-peeking-mechanism
154 arg1 (second arg2) char
156 (unread-char char in)
159 (or (if (ansi-stream-p in)
160 (funcall (ansi-stream-misc in) in operation arg1 arg2)
161 (stream-misc-dispatch in operation arg1 arg2))
162 (if (ansi-stream-p out)
163 (funcall (ansi-stream-misc out) out operation arg1 arg2)
164 (stream-misc-dispatch out operation arg1 arg2)))))))