input.lisp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. (in-package :hurd-streams)
  2. (defconstant +default-read-ahead+ 512)
  3. (defclass hurd-input-stream (hurd-stream fundamental-binary-input-stream)
  4. ((cache :initform (%create-adjustable-array +default-read-ahead+)
  5. :accessor cache)
  6. (last-byte :initform nil
  7. :accessor last-byte)
  8. (cache-pos :initform 0
  9. :accessor cache-pos)))
  10. (defun read-stream-cache (stream)
  11. (multiple-value-bind (data total)
  12. (io-read (port stream)
  13. :offset (offset stream)
  14. :amount +default-read-ahead+)
  15. (unless data
  16. (setf total 0))
  17. (setf (cache-pos stream) 0)
  18. (setf (fill-pointer (cache stream)) total)
  19. (when data
  20. (replace (cache stream) data))
  21. t))
  22. (defmethod initialize-instance :after ((stream hurd-input-stream) &rest initargs)
  23. (declare (ignore initargs))
  24. (read-stream-cache stream))
  25. (defmethod close ((stream hurd-input-stream) &key abort)
  26. "Closes the stream STREAM."
  27. (declare (ignore abort))
  28. (when (open-stream-p stream)
  29. (setf (cache stream) nil)
  30. (call-next-method)))
  31. (defmethod (setf stream-file-position) (position (stream hurd-input-stream))
  32. "Sets the file offfset."
  33. (declare (ignore position))
  34. (with-cleanup (read-stream-cache stream)
  35. (call-next-method)))
  36. (defun %hurd-eof-reached-p (cache)
  37. (not (and cache
  38. (plusp (length cache)))))
  39. (defmethod stream-read-byte ((stream hurd-input-stream))
  40. (with-accessors ((port port) (cache cache)
  41. (cache-pos cache-pos)
  42. (offset offset)
  43. (last-byte last-byte))
  44. stream
  45. (unless (< cache-pos (length cache))
  46. (read-stream-cache stream))
  47. (when (%hurd-eof-reached-p cache)
  48. (return-from stream-read-byte :eof))
  49. (let ((byte (elt cache cache-pos)))
  50. (incf offset)
  51. (incf cache-pos)
  52. (setf last-byte byte)
  53. byte)))
  54. (defmethod stream-read-char ((stream hurd-input-stream))
  55. (let ((byte (stream-read-byte stream)))
  56. (case byte
  57. (:eof :eof)
  58. (otherwise
  59. (code-char byte)))))
  60. (defmethod unread-byte (byte (stream hurd-input-stream))
  61. (with-accessors ((last-byte last-byte) (cache-pos cache-pos))
  62. stream
  63. (unless last-byte
  64. (error "No byte to unread from this stream."))
  65. (unless (= byte last-byte)
  66. (error "Last byte read was different from #x~X" byte))
  67. (setf last-byte nil)
  68. (decf (offset stream))
  69. (cond
  70. ((zerop cache-pos)
  71. (read-stream-cache stream))
  72. (t
  73. (decf cache-pos)))
  74. nil))
  75. (defmethod stream-unread-char ((stream hurd-input-stream) char)
  76. (unread-byte (char-code char) stream))
  77. (defmethod peek-byte ((stream hurd-input-stream)
  78. &optional peek-type (eof-error-p t)
  79. eof-value)
  80. (loop for octet = (read-byte stream eof-error-p eof-value)
  81. until (cond ((null peek-type))
  82. ((eql octet eof-value))
  83. ((eq peek-type t)
  84. (plusp octet))
  85. (t (= octet peek-type)))
  86. finally (unless (eql octet eof-value)
  87. (unread-byte octet stream))
  88. (return octet)))
  89. (defmethod stream-peek-char ((stream hurd-input-stream))
  90. (let ((byte (peek-byte stream)))
  91. (cond
  92. ((plusp byte)
  93. (code-char byte))
  94. (t byte))))
  95. (defmethod stream-read-sequence ((stream hurd-input-stream)
  96. sequence start end &key)
  97. (let ((total (- end start)))
  98. (with-accessors ((cache cache) (cache-pos cache-pos)
  99. (offset offset))
  100. stream
  101. (when (or (%hurd-eof-reached-p cache)
  102. (= start end))
  103. (return-from stream-read-sequence start))
  104. (let* ((size-cache (length cache))
  105. (cache-rest (- size-cache cache-pos))
  106. (this-size (min cache-rest total))
  107. (new-cache-pos (+ cache-pos this-size)))
  108. (replace sequence cache
  109. :start1 start :end1 end
  110. :start2 cache-pos :end2 new-cache-pos)
  111. (incf offset this-size)
  112. (setf cache-pos new-cache-pos)
  113. (cond
  114. ((= this-size total) end)
  115. (t
  116. (read-stream-cache stream)
  117. (stream-read-sequence stream sequence
  118. (+ start this-size)
  119. end)))))))
  120. (defmethod make-hurd-input-stream ((file string) &optional (flags '(:read)))
  121. (make-hurd-input-stream
  122. (file-name-lookup file :flags flags)))
  123. (defmethod make-hurd-input-stream ((port number) &optional flags)
  124. (declare (ignore flags))
  125. (make-instance 'hurd-input-stream :port port))
  126. (defmacro with-hurd-input-stream ((stream-name file &optional (flags ''(:read))) &body body)
  127. `(with-stream (,stream-name (make-hurd-input-stream ,file ,flags))
  128. ,@body))