123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- (in-package :hurd-streams)
- (defconstant +default-read-ahead+ 512)
- (defclass hurd-input-stream (hurd-stream fundamental-binary-input-stream)
- ((cache :initform (%create-adjustable-array +default-read-ahead+)
- :accessor cache)
- (last-byte :initform nil
- :accessor last-byte)
- (cache-pos :initform 0
- :accessor cache-pos)))
- (defun read-stream-cache (stream)
- (multiple-value-bind (data total)
- (io-read (port stream)
- :offset (offset stream)
- :amount +default-read-ahead+)
- (unless data
- (setf total 0))
- (setf (cache-pos stream) 0)
- (setf (fill-pointer (cache stream)) total)
- (when data
- (replace (cache stream) data))
- t))
- (defmethod initialize-instance :after ((stream hurd-input-stream) &rest initargs)
- (declare (ignore initargs))
- (read-stream-cache stream))
- (defmethod close ((stream hurd-input-stream) &key abort)
- "Closes the stream STREAM."
- (declare (ignore abort))
- (when (open-stream-p stream)
- (setf (cache stream) nil)
- (call-next-method)))
- (defmethod (setf stream-file-position) (position (stream hurd-input-stream))
- "Sets the file offfset."
- (declare (ignore position))
- (with-cleanup (read-stream-cache stream)
- (call-next-method)))
- (defun %hurd-eof-reached-p (cache)
- (not (and cache
- (plusp (length cache)))))
- (defmethod stream-read-byte ((stream hurd-input-stream))
- (with-accessors ((port port) (cache cache)
- (cache-pos cache-pos)
- (offset offset)
- (last-byte last-byte))
- stream
- (unless (< cache-pos (length cache))
- (read-stream-cache stream))
- (when (%hurd-eof-reached-p cache)
- (return-from stream-read-byte :eof))
- (let ((byte (elt cache cache-pos)))
- (incf offset)
- (incf cache-pos)
- (setf last-byte byte)
- byte)))
- (defmethod stream-read-char ((stream hurd-input-stream))
- (let ((byte (stream-read-byte stream)))
- (case byte
- (:eof :eof)
- (otherwise
- (code-char byte)))))
- (defmethod unread-byte (byte (stream hurd-input-stream))
- (with-accessors ((last-byte last-byte) (cache-pos cache-pos))
- stream
- (unless last-byte
- (error "No byte to unread from this stream."))
- (unless (= byte last-byte)
- (error "Last byte read was different from #x~X" byte))
- (setf last-byte nil)
- (decf (offset stream))
- (cond
- ((zerop cache-pos)
- (read-stream-cache stream))
- (t
- (decf cache-pos)))
- nil))
- (defmethod stream-unread-char ((stream hurd-input-stream) char)
- (unread-byte (char-code char) stream))
- (defmethod peek-byte ((stream hurd-input-stream)
- &optional peek-type (eof-error-p t)
- eof-value)
- (loop for octet = (read-byte stream eof-error-p eof-value)
- until (cond ((null peek-type))
- ((eql octet eof-value))
- ((eq peek-type t)
- (plusp octet))
- (t (= octet peek-type)))
- finally (unless (eql octet eof-value)
- (unread-byte octet stream))
- (return octet)))
- (defmethod stream-peek-char ((stream hurd-input-stream))
- (let ((byte (peek-byte stream)))
- (cond
- ((plusp byte)
- (code-char byte))
- (t byte))))
- (defmethod stream-read-sequence ((stream hurd-input-stream)
- sequence start end &key)
- (let ((total (- end start)))
- (with-accessors ((cache cache) (cache-pos cache-pos)
- (offset offset))
- stream
- (when (or (%hurd-eof-reached-p cache)
- (= start end))
- (return-from stream-read-sequence start))
- (let* ((size-cache (length cache))
- (cache-rest (- size-cache cache-pos))
- (this-size (min cache-rest total))
- (new-cache-pos (+ cache-pos this-size)))
- (replace sequence cache
- :start1 start :end1 end
- :start2 cache-pos :end2 new-cache-pos)
- (incf offset this-size)
- (setf cache-pos new-cache-pos)
- (cond
- ((= this-size total) end)
- (t
- (read-stream-cache stream)
- (stream-read-sequence stream sequence
- (+ start this-size)
- end)))))))
-
- (defmethod make-hurd-input-stream ((file string) &optional (flags '(:read)))
- (make-hurd-input-stream
- (file-name-lookup file :flags flags)))
- (defmethod make-hurd-input-stream ((port number) &optional flags)
- (declare (ignore flags))
- (make-instance 'hurd-input-stream :port port))
- (defmacro with-hurd-input-stream ((stream-name file &optional (flags ''(:read))) &body body)
- `(with-stream (,stream-name (make-hurd-input-stream ,file ,flags))
- ,@body))
|