~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/clos/streams.lsp

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2006-05-17 02:46:26 UTC
  • Revision ID: james.westby@ubuntu.com-20060517024626-lljr08ftv9g9vefl
Tags: upstream-0.9h-20060510
ImportĀ upstreamĀ versionĀ 0.9h-20060510

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;;;;  Copyright (c) 2004, Juan Jose Garcia-Ripoll
 
2
;;;;
 
3
;;;;    This program is free software; you can redistribute it and/or
 
4
;;;;    modify it under the terms of the GNU Library General Public
 
5
;;;;    License as published by the Free Software Foundation; either
 
6
;;;;    version 2 of the License, or (at your option) any later version.
 
7
;;;;
 
8
;;;;    See file '../Copyright' for full details.
 
9
;;;;        The CLOS IO library.
 
10
 
 
11
(in-package "SI")
 
12
 
 
13
;;;
 
14
;;; This is the generic function interface for CLOS streams.
 
15
;;;
 
16
;;; The following is a port of SBCL's implementation of Gray Streams. Minor
 
17
;;; caveats with respect to the proposal are that we rather keep CLOSE,
 
18
;;; STREAM-ELEMENT-TYPE, INPUT-STREAM-P, OUTPUT-STREAM-P and OPEN-STREAM-P
 
19
;;; these as normal functions that call the user extensible EXT:STREAM-{CLOSE,
 
20
;;; ELT-TYPE, INPUT-P, OUTPUT-P, OPEN-P}.
 
21
;;;
 
22
 
 
23
(defgeneric stream-advance-to-column (stream column)
 
24
  (:documentation
 
25
   "Write enough blank space so that the next character will be
 
26
  written at the specified column. Returns true if the operation is
 
27
  successful, or NIL if it is not supported for this stream. This is
 
28
  intended for use by by PPRINT and FORMAT ~T. The default method uses
 
29
  STREAM-LINE-COLUMN and repeated calls to STREAM-WRITE-CHAR with a
 
30
  #\SPACE character; it returns NIL if STREAM-LINE-COLUMN returns NIL."))
 
31
 
 
32
(defgeneric stream-clear-input (stream)
 
33
  (:documentation
 
34
   "This is like CL:CLEAR-INPUT, but for Gray streams, returning NIL.
 
35
  The default method does nothing."))
 
36
 
 
37
(defgeneric stream-clear-output (stream)
 
38
  (:documentation
 
39
   "This is like CL:CLEAR-OUTPUT, but for Gray streams: clear the given
 
40
  output STREAM. The default method does nothing."))
 
41
 
 
42
(defgeneric stream-close (stream &key abort)
 
43
  (:documentation
 
44
   "Close the given STREAM. No more I/O may be performed, but
 
45
  inquiries may still be made. If :ABORT is true, an attempt is made
 
46
  to clean up the side effects of having created the stream."))
 
47
 
 
48
(defgeneric stream-elt-type (stream)
 
49
  (:documentation
 
50
   "Return a type specifier for the kind of object returned by the
 
51
  STREAM. The class FUNDAMENTAL-CHARACTER-STREAM provides a default method
 
52
  which returns CHARACTER."))
 
53
 
 
54
(defgeneric stream-finish-output (stream)
 
55
  (:documentation
 
56
   "Attempts to ensure that all output sent to the Stream has reached
 
57
  its destination, and only then returns false. Implements
 
58
  FINISH-OUTPUT. The default method does nothing."))
 
59
 
 
60
(defgeneric stream-force-output (stream)
 
61
  (:documentation
 
62
   "Attempts to force any buffered output to be sent. Implements
 
63
  FORCE-OUTPUT. The default method does nothing."))
 
64
 
 
65
(defgeneric stream-fresh-line (stream)
 
66
  (:documentation
 
67
   "Outputs a new line to the Stream if it is not positioned at the
 
68
  begining of a line. Returns T if it output a new line, nil
 
69
  otherwise. Used by FRESH-LINE. The default method uses
 
70
  STREAM-START-LINE-P and STREAM-TERPRI."))
 
71
 
 
72
(defgeneric stream-input-p (stream)
 
73
  (:documentation "Can STREAM perform input operations?"))
 
74
 
 
75
(defgeneric stream-interactive-p (stream)
 
76
  (:documentation "Is stream interactive (For instance, a tty)?"))
 
77
 
 
78
(defgeneric stream-line-column (stream)
 
79
  (:documentation
 
80
   "Return the column number where the next character
 
81
  will be written, or NIL if that is not meaningful for this stream.
 
82
  The first column on a line is numbered 0. This function is used in
 
83
  the implementation of PPRINT and the FORMAT ~T directive. For every
 
84
  character output stream class that is defined, a method must be
 
85
  defined for this function, although it is permissible for it to
 
86
  always return NIL."))
 
87
 
 
88
(defgeneric stream-listen (stream)
 
89
  #+sb-doc
 
90
  (:documentation
 
91
   "This is used by LISTEN. It returns true or false. The default method uses
 
92
  STREAM-READ-CHAR-NO-HANG and STREAM-UNREAD-CHAR. Most streams should
 
93
  define their own method since it will usually be trivial and will
 
94
  always be more efficient than the default method."))
 
95
 
 
96
(defgeneric stream-open-p (stream)
 
97
  (:documentation
 
98
   "Return true if STREAM is not closed. A default method is provided
 
99
  by class FUNDAMENTAL-STREAM which returns true if CLOSE has not been
 
100
  called on the stream."))
 
101
 
 
102
(defgeneric stream-output-p (stream)
 
103
  (:documentation "Can STREAM perform output operations?"))
 
104
 
 
105
(defgeneric stream-peek-char (stream)
 
106
  (:documentation
 
107
   "This is used to implement PEEK-CHAR; this corresponds to PEEK-TYPE of NIL.
 
108
  It returns either a character or :EOF. The default method calls
 
109
  STREAM-READ-CHAR and STREAM-UNREAD-CHAR."))
 
110
 
 
111
(defgeneric stream-read-byte (stream)
 
112
  (:documentation
 
113
   "Used by READ-BYTE; returns either an integer, or the symbol :EOF
 
114
  if the stream is at end-of-file."))
 
115
 
 
116
(defgeneric stream-read-char (stream)
 
117
  (:documentation
 
118
   "Read one character from the stream. Return either a
 
119
  character object, or the symbol :EOF if the stream is at end-of-file.
 
120
  Every subclass of FUNDAMENTAL-CHARACTER-INPUT-STREAM must define a
 
121
  method for this function."))
 
122
 
 
123
(defgeneric stream-read-char-no-hang (stream)
 
124
  (:documentation
 
125
   "This is used to implement READ-CHAR-NO-HANG. It returns either a
 
126
  character, or NIL if no input is currently available, or :EOF if
 
127
  end-of-file is reached. The default method provided by
 
128
  FUNDAMENTAL-CHARACTER-INPUT-STREAM simply calls STREAM-READ-CHAR; this
 
129
  is sufficient for file streams, but interactive streams should define
 
130
  their own method."))
 
131
 
 
132
(defgeneric stream-read-line (stream)
 
133
  (:documentation
 
134
   "This is used by READ-LINE. A string is returned as the first value. The
 
135
  second value is true if the string was terminated by end-of-file
 
136
  instead of the end of a line. The default method uses repeated
 
137
  calls to STREAM-READ-CHAR."))
 
138
 
 
139
(defgeneric stream-read-sequence (stream seq &optional start end)
 
140
  (:documentation
 
141
   "This is like CL:READ-SEQUENCE, but for Gray streams."))
 
142
 
 
143
(defgeneric stream-start-line-p (stream)
 
144
  (:documentation
 
145
   "Is STREAM known to be positioned at the beginning of a line?
 
146
  It is permissible for an implementation to always return
 
147
  NIL. This is used in the implementation of FRESH-LINE. Note that
 
148
  while a value of 0 from STREAM-LINE-COLUMN also indicates the
 
149
  beginning of a line, there are cases where STREAM-START-LINE-P can be
 
150
  meaningfully implemented although STREAM-LINE-COLUMN can't be. For
 
151
  example, for a window using variable-width characters, the column
 
152
  number isn't very meaningful, but the beginning of the line does have
 
153
  a clear meaning. The default method for STREAM-START-LINE-P on class
 
154
  FUNDAMENTAL-CHARACTER-OUTPUT-STREAM uses STREAM-LINE-COLUMN, so if
 
155
  that is defined to return NIL, then a method should be provided for
 
156
  either STREAM-START-LINE-P or STREAM-FRESH-LINE."))
 
157
 
 
158
(defgeneric stream-terpri (stream)
 
159
  (:documentation
 
160
   "Writes an end of line, as for TERPRI. Returns NIL. The default
 
161
  method does (STREAM-WRITE-CHAR stream #\NEWLINE)."))
 
162
 
 
163
(defgeneric stream-unread-char (stream character)
 
164
  (:documentation
 
165
   "Un-do the last call to STREAM-READ-CHAR, as in UNREAD-CHAR.
 
166
  Return NIL. Every subclass of FUNDAMENTAL-CHARACTER-INPUT-STREAM
 
167
  must define a method for this function."))
 
168
 
 
169
(defgeneric stream-write-byte (stream integer)
 
170
  (:documentation
 
171
   "Implements WRITE-BYTE; writes the integer to the stream and
 
172
  returns the integer as the result."))
 
173
 
 
174
(defgeneric stream-write-char (stream character)
 
175
  (:documentation
 
176
   "Write CHARACTER to STREAM and return CHARACTER. Every
 
177
  subclass of FUNDAMENTAL-CHARACTER-OUTPUT-STREAM must have a method
 
178
  defined for this function."))
 
179
 
 
180
(defgeneric stream-write-string (stream string &optional start end)
 
181
  (:documentation
 
182
   "This is used by WRITE-STRING. It writes the string to the stream,
 
183
  optionally delimited by start and end, which default to 0 and NIL.
 
184
  The string argument is returned. The default method provided by
 
185
  FUNDAMENTAL-CHARACTER-OUTPUT-STREAM uses repeated calls to
 
186
  STREAM-WRITE-CHAR."))
 
187
 
 
188
(defgeneric stream-write-sequence (stream seq &optional start end)
 
189
  (:documentation
 
190
   "This is like CL:WRITE-SEQUENCE, but for Gray streams."))
 
191
 
 
192
 
 
193
;;;
 
194
;;; Our class hierarchy looks like the one from Gray streams
 
195
;;;
 
196
;;; character output streams
 
197
;;;
 
198
;;; A character output stream can be created by defining a class that
 
199
;;; includes FUNDAMENTAL-CHARACTER-OUTPUT-STREAM and defining methods
 
200
;;; for the generic functions below.
 
201
;;;
 
202
;;; binary streams
 
203
;;;
 
204
;;; Binary streams can be created by defining a class that includes
 
205
;;; either FUNDAMENTAL-BINARY-INPUT-STREAM or
 
206
;;; FUNDAMENTAL-BINARY-OUTPUT-STREAM (or both) and defining a method
 
207
;;; for STREAM-ELEMENT-TYPE and for one or both of the following
 
208
;;; generic functions.
 
209
;;;
 
210
 
 
211
(defclass fundamental-stream (standard-object stream)
 
212
  ((open-p :initform t :accessor stream-open-p))
 
213
  (:documentation "the base class for all CLOS streams"))
 
214
 
 
215
(defclass fundamental-input-stream (fundamental-stream) nil)
 
216
 
 
217
(defclass fundamental-output-stream (fundamental-stream) nil)
 
218
 
 
219
(defclass fundamental-character-stream (fundamental-stream) nil)
 
220
 
 
221
(defclass fundamental-binary-stream (fundamental-stream) nil)
 
222
 
 
223
(defclass fundamental-character-input-stream
 
224
    (fundamental-input-stream fundamental-character-stream) nil)
 
225
 
 
226
(defclass fundamental-character-output-stream
 
227
    (fundamental-output-stream fundamental-character-stream) nil)
 
228
 
 
229
(defclass fundamental-binary-input-stream
 
230
    (fundamental-input-stream fundamental-binary-stream) nil)
 
231
 
 
232
(defclass fundamental-binary-output-stream
 
233
    (fundamental-output-stream fundamental-binary-stream) nil)
 
234
 
 
235
 
 
236
;;;
 
237
;;; The following methods constitute default implementations.
 
238
;;;
 
239
 
 
240
(defun bug-or-error (stream fun)
 
241
  (declare (ext::c-local))
 
242
  (error "The stream ~S has no suitable method for ~S." stream fun))
 
243
 
 
244
;; STREAM-ADVANCE-TO-COLUMN
 
245
 
 
246
(defmethod stream-advance-to-column ((stream fundamental-character-output-stream)
 
247
                                     column)
 
248
  (let ((current-column (stream-line-column stream)))
 
249
    (when current-column
 
250
      (let ((fill (- column current-column)))
 
251
        (dotimes (i fill)
 
252
          (stream-write-char stream #\Space)))
 
253
      T)))
 
254
 
 
255
 
 
256
;; CLEAR-INPUT
 
257
 
 
258
(defmethod stream-clear-input ((stream fundamental-character-input-stream))
 
259
  nil)
 
260
(defmethod stream-clear-input ((stream stream))
 
261
  (bug-or-error stream 'stream-clear-input))
 
262
(defmethod stream-clear-input ((non-stream t))
 
263
  (error 'type-error :datum non-stream :expected-type 'stream))
 
264
 
 
265
 
 
266
;; CLEAR-OUTPUT
 
267
 
 
268
(defmethod stream-clear-output ((stream fundamental-output-stream))
 
269
  nil)
 
270
(defmethod stream-clear-output ((stream stream))
 
271
  (bug-or-error stream 'stream-clear-output))
 
272
(defmethod stream-clear-output ((non-stream t))
 
273
  (error 'type-error :datum non-stream :expected-type 'stream))
 
274
 
 
275
 
 
276
;; CLOSE
 
277
 
 
278
(defmethod stream-close ((stream fundamental-stream) &key abort)
 
279
  (declare (ignore abort))
 
280
  (setf (stream-open-p stream) nil)
 
281
  t)
 
282
 
 
283
 
 
284
;; STREAM-ELEMENT-TYPE
 
285
 
 
286
(defmethod stream-elt-type ((stream fundamental-character-stream))
 
287
  'character)
 
288
 
 
289
(defmethod stream-elt-type ((stream stream))
 
290
  (bug-or-error stream 'stream-elt-type))
 
291
 
 
292
(defmethod stream-elt-type ((non-stream t))
 
293
  (error 'type-error :datum non-stream :expected-type 'stream))
 
294
 
 
295
 
 
296
;; FINISH-OUTPUT
 
297
 
 
298
(defmethod stream-finish-output ((stream fundamental-output-stream))
 
299
  nil)
 
300
(defmethod stream-finish-output ((stream stream))
 
301
  (bug-or-error stream 'stream-finish-output))
 
302
(defmethod stream-finish-output ((non-stream t))
 
303
  (error 'type-error :datum non-stream :expected-type 'stream))
 
304
 
 
305
 
 
306
;; FORCE-OUTPUT
 
307
 
 
308
(defmethod stream-force-output ((stream fundamental-output-stream))
 
309
  nil)
 
310
(defmethod stream-force-output ((stream stream))
 
311
  (bug-or-error stream 'stream-force-output))
 
312
(defmethod stream-force-output ((non-stream t))
 
313
  (error 'type-error :datum non-stream :expected-type 'stream))
 
314
 
 
315
 
 
316
;; FRESH-LINE
 
317
 
 
318
(defmethod stream-fresh-line ((stream fundamental-character-output-stream))
 
319
  (unless (stream-start-line-p stream)
 
320
    (stream-terpri stream)
 
321
    t))
 
322
 
 
323
 
 
324
;; INPUT-STREAM-P
 
325
 
 
326
(defmethod stream-input-p ((stream fundamental-stream))
 
327
  nil)
 
328
 
 
329
(defmethod stream-input-p ((stream fundamental-input-stream))
 
330
  t)
 
331
 
 
332
(defmethod stream-input-p ((stream stream))
 
333
  (bug-or-error stream 'stream-input-p))
 
334
 
 
335
(defmethod stream-input-p ((non-stream t))
 
336
  (error 'type-error :datum non-stream :expected-type 'stream))
 
337
 
 
338
 
 
339
;; INTERACTIVE-STREAM-P
 
340
 
 
341
(defmethod stream-interactive-p ((stream stream))
 
342
  (bug-or-error stream 'stream-interactive-p))
 
343
 
 
344
(defmethod stream-interactive-p ((non-stream t))
 
345
  (error 'type-error :datum non-stream :expected-type 'stream))
 
346
 
 
347
;; LINE-COLUMN
 
348
 
 
349
(defmethod stream-line-column ((stream fundamental-character-output-stream))
 
350
   nil)
 
351
 
 
352
 
 
353
;; LISTEN
 
354
 
 
355
(defmethod stream-listen ((stream fundamental-character-input-stream))
 
356
  (let ((char (stream-read-char-no-hang stream)))
 
357
    (when (characterp char)
 
358
      (stream-unread-char stream char)
 
359
      t)))
 
360
 
 
361
 
 
362
;; OPEN-STREAM-P
 
363
 
 
364
(defmethod stream-open-p ((stream fundamental-stream))
 
365
  (stream-open-p stream))
 
366
 
 
367
(defmethod stream-open-p ((stream stream))
 
368
  (bug-or-error stream 'open-stream-p))
 
369
 
 
370
(defmethod stream-open-p ((non-stream t))
 
371
  (error 'type-error :datum non-stream :expected-type 'stream))
 
372
 
 
373
 
 
374
;; OUTPUT-STREAM-P
 
375
 
 
376
(defmethod stream-output-p ((stream fundamental-stream))
 
377
  nil)
 
378
 
 
379
(defmethod stream-output-p ((stream fundamental-output-stream))
 
380
  t)
 
381
 
 
382
(defmethod stream-output-p ((stream stream))
 
383
  (bug-or-error stream 'stream-output-p))
 
384
 
 
385
(defmethod stream-output-p ((non-stream t))
 
386
  (error 'type-error :datum non-stream :expected-type 'stream))
 
387
 
 
388
 
 
389
;; PEEK-CHAR
 
390
 
 
391
(defmethod stream-peek-char ((stream fundamental-character-input-stream))
 
392
  (let ((char (stream-read-char stream)))
 
393
    (unless (eq char :eof)
 
394
      (stream-unread-char stream char))
 
395
    char))
 
396
 
 
397
 
 
398
;; READ-BYTE
 
399
 
 
400
(defmethod stream-read-byte ((stream stream))
 
401
  (bug-or-error stream 'stream-read-byte))
 
402
(defmethod stream-read-byte ((non-stream t))
 
403
  (error 'type-error :datum non-stream :expected-type 'stream))
 
404
 
 
405
 
 
406
;; READ-CHAR-NO-HANG
 
407
 
 
408
(defmethod stream-read-char-no-hang ((stream fundamental-character-input-stream))
 
409
  (stream-read-char stream))
 
410
 
 
411
 
 
412
;; READ-LINE
 
413
 
 
414
(defmethod stream-read-line ((stream fundamental-character-input-stream))
 
415
  (let ((res (make-string 80))
 
416
        (len 80)
 
417
        (index 0))
 
418
    (loop
 
419
     (let ((ch (stream-read-char stream)))
 
420
       (cond ((eq ch :eof)
 
421
              (return (values (shrink-vector res index) t)))
 
422
             (t
 
423
              (when (char= ch #\newline)
 
424
                (return (values (shrink-vector res index) nil)))
 
425
              (when (= index len)
 
426
                (setq len (* len 2))
 
427
                (let ((new (make-string len)))
 
428
                  (replace new res)
 
429
                  (setq res new)))
 
430
              (setf (schar res index) ch)
 
431
              (incf index)))))))
 
432
 
 
433
 
 
434
;; READ-SEQUENCE
 
435
 
 
436
(defmethod stream-read-sequence ((stream fundamental-character-input-stream)
 
437
                                 (seq sequence)
 
438
                                 &optional (start 0) (end nil))
 
439
  (si::do-read-sequence seq stream start end))
 
440
 
 
441
(defmethod stream-read-sequence ((stream fundamental-binary-input-stream)
 
442
                                 (seq sequence)
 
443
                                 &optional (start 0) (end nil))
 
444
  (si::do-read-sequence seq stream start end))
 
445
 
 
446
 
 
447
;; START-LINE-P
 
448
 
 
449
(defmethod stream-start-line-p ((stream fundamental-character-output-stream))
 
450
  (eql (stream-line-column stream) 0))
 
451
 
 
452
 
 
453
;; WRITE-BYTE
 
454
 
 
455
(defmethod stream-write-byte ((stream stream) integer)
 
456
  (bug-or-error stream 'stream-write-byte))
 
457
(defmethod stream-write-byte ((non-stream t) integer)
 
458
  (error 'type-error :datum non-stream :expected-type 'stream))
 
459
 
 
460
 
 
461
;; WRITE-SEQUENCE
 
462
 
 
463
(defmethod stream-write-sequence ((stream fundamental-character-output-stream)
 
464
                                  (seq sequence)
 
465
                                  &optional (start 0) (end nil))
 
466
  (si::do-write-sequence seq stream start end))
 
467
 
 
468
(defmethod stream-write-sequence ((stream fundamental-binary-output-stream)
 
469
                                  (seq sequence)
 
470
                                  &optional (start 0) (end nil))
 
471
  (si::do-write-sequence seq stream start end))
 
472
 
 
473
;; WRITE-STRING
 
474
 
 
475
(defmethod stream-write-string ((stream fundamental-character-output-stream)
 
476
                                string &optional (start 0) end)
 
477
  (declare (string string)
 
478
           (fixnum start))
 
479
  (let ((end (or end (length string))))
 
480
    (declare (fixnum end))
 
481
    (do ((pos start (1+ pos)))
 
482
        ((>= pos end))
 
483
      (declare (type index pos))
 
484
      (stream-write-char stream (aref string pos))))
 
485
  string)
 
486
 
 
487
 
 
488
;; TERPRI
 
489
 
 
490
(defmethod stream-terpri ((stream fundamental-character-output-stream))
 
491
  (stream-write-char stream #\Newline))
 
492