[Ecls-list] CLOS streams
Juan Jose Garcia-Ripoll
worm at arrakis.es
Fri Jun 27 01:59:07 UTC 2003
On Friday 27 June 2003 00:44, Julian St. wrote:
> Hello,
>
> having the ability to create own streams proves to be really useful for
> using ECL as a plugin. But I wonder what the right way to this it
> (especially what methods I have to provide, currently I just grep'ed
> thorugh the ECL sources to see where ECL_CLOS_STREAMS takes effect). I
> tried it the following way ( %print is the only function that gets called.
> It emits a single line and changes to the next ).
>
> The implementation as it is seen below works despite of two issues:
> 1) I get the following warnings:
>
> ;;; Warning: STREAM-CLOSE is being redefined.
> ;;; Warning: STREAM-INPUT-P is being redefined.
> ;;; Warning: STREAM-OUTPUT-P is being redefined.
> ;;; Warning: STREAM-WRITE-CHAR is being redefined.
> ;;; Warning: STREAM-FORCE-OUTPUT is being redefined.
> ;;; Warning: STREAM-CLEAR-OUTPUT is being redefined.
No problem. It just complains because, when you are defining these functions,
the Common-Lisp package is locked. If you do (SI:PACKAGE-LOCK "CL" NIL)
and (SI:PACKAGE-LOCK "CL" T) before and after your code, everything should
become quieter.
> 2) I think there too many empty lines written. Looks strange sometimes:
a) Some characters have special meaning in the output. In particular, your
%print function has to interpret #\Newline not only as a flush character, but
also as a new line command. See the code I have attached: my implementation
of %PRINT issues a FRESH-LINE whenever it finds #\Newline, and otherwise
outputs the character directly to the terminal. Depending on the device which
you use for output, you may need or not care about this.
b) STREAM-FORCE-OUTPUT may be called any number of times by the lisp
environement, to ensure that buffers are being flushed, but it does not imply
that a new line has to be written. Therefore, your STREAM-FLUSH-BUFFER should
do nothing when the buffer is empty.
c) You do not need to detect #\Newline characters in the STREAM-WRITE-CHAR
routine. This can be done in the %PRINT-ROUTINE. This way, since your routine
will operate on strings, the check may be compiled faster. Or, if you use C
routines to output data, you do not even need to care about the #\Newline.
d) The number of empty lines may differ between a normal stream and a CLOS
stream, because the FILE-COLUMN functionality has not been implemented for
the latter, and sometimes the printer has no clue about whether it should
break a line or not.
BTW, I am going to build an "examples" directory for ECL. Could I include a
modified version of the file you have posted to the list?
Regards,
Juanjo
-------------- next part --------------
;; Getting *standard-output* redirected to X-Chat.
;; Complicated version, which shows what your plugin should do
;; when you handle low-level output (for instance X-windows)
(defun %print (s)
(dotimes (i (length s))
(let ((c (char s i)))
(if (char= c #\Newline)
(fresh-line *terminal-io*)
(write-char c *terminal-io*)))))
;; Easy version, which relies on the Unix terminal to interpret
;; the #\Newline character.
(defun %print (s)
(si::write-bytes *terminal-io* s 0 (fill-pointer s)))
(defclass xchat-stream
()
((lbuffer :accessor xchat-stream-buffer
:initform (make-array 128 :adjustable t :fill-pointer 0
:element-type 'character)))
(:documentation "A stream directed to X-Chat"))
(defmethod stream-close ((stream xchat-stream))
(error "Cannot close ~S." stream))
(defmethod stream-input-p ((stream xchat-stream))
nil)
(defmethod stream-output-p ((stream xchat-stream))
t)
(defmethod stream-flush-buffer ((stream xchat-stream))
(let ((buffer (xchat-stream-buffer stream)))
(unless (zerop (length buffer))
(%print buffer)
(stream-clear-output stream))))
(defmethod stream-write-char ((stream xchat-stream) char)
(let ((buffer (xchat-stream-buffer stream)))
(unless (vector-push char buffer)
;; When VECTOR-PUSH fails, the buffer is full
(stream-flush-buffer stream)
(vector-push char buffer))))
(defmethod stream-force-output ((stream xchat-stream))
(stream-flush-buffer stream))
(defmethod stream-clear-output ((stream xchat-stream))
(setf (fill-pointer (xchat-stream-buffer stream)) 0))
(setq *new-standard-output* (make-instance 'xchat-stream))
(fresh-line)
(let ((*standard-output* *new-standard-output*))
(describe 'CONS)
(stream-force-output *standard-output*))
More information about the ecl-devel
mailing list