;;; -*- Mode:LISP; Package:MAC; Base:10; Readtable:ZL -*- ;;; ;;; Making a stream out of a Mac-file ;;; (defconst LOGICAL-EOF-REACHED -39) (declare (special mac-file-streams-list)) ; ; MAC-STREAM-MIXIN ; (defflavor mac-stream-mixin (truename) (si:property-list-mixin si:file-stream-mixin) (:gettable-instance-variables truename) (:init-keywords :file :append :truename :if-exists)) (defmethod (mac-stream-mixin :init) (plist) (let ((file (get plist :file))) (if (not file) (setq truename (get plist :truename)) (setq truename (mac-file-truename file) si:property-list (read-info-blk (file-info-blk file)))))) (defmethod (mac-stream-mixin :qfaslp) () (get (locf si:property-list) :qfaslp)) ;; For probes, assume you really mean :LENGTH-IN-BYTES (defmethod (mac-stream-mixin :length) () (get (locf si:property-list) :length-in-bytes)) (defmethod (mac-stream-mixin :properties) (&optional error-p) error-p ; would be quite hard to get an error here (values (cons truename si:property-list) mac-unsettable-properties)) ; ; MAC-DATA-STREAM-MIXIN ; (defflavor mac-data-stream-mixin (file) (mac-stream-mixin) (:initable-instance-variables file)) (defmethod (mac-data-stream-mixin :init) (ignore) (setq truename (mac-file-truename file) si:property-list (read-info-blk (file-info-blk file))) (without-interrupts (setq mac-file-streams-list (cons self mac-file-streams-list)))) (defmethod (mac-data-stream-mixin :close) (&optional abortp) (mac-close-file file abortp) (without-interrupts (setq mac-file-streams-list (delq self mac-file-streams-list))) (setq file nil)) (defmethod (mac-data-stream-mixin :set-buffer-pointer) (where) (if ( where 0) (ferror "Mac error: You can only set-buffer-pointer to 0.") (send-file-cmd-wait (dev-cmd-blk (file-dev-blk file)) CMD-REWIND 0 0) 0)) (defmethod (mac-data-stream-mixin :geteof) () (get (locf si:property-list) :length-in-bytes)) (defmethod (mac-data-stream-mixin :seteof) (eof-value) (send-file-cmd-wait (dev-cmd-blk (file-dev-blk file)) CMD-SETEOF 1 0 eof-value) (putprop (locf si:property-list) eof-value :length-in-bytes)) (defmethod (mac-data-stream-mixin :delete) (&optional (error-p t)) (fs:identify-file-operation :delete (fs:handling-errors error-p (mac-delete-file file)))) (defmethod (mac-data-stream-mixin :rename) (new-name &optional (error-p t)) (fs:identify-file-operation :rename (fs:handling-errors error-p (mac-rename-file file (pathname-directory new-name) (pathname-name new-name) (pathname-type new-name) (pathname-version new-name))) (setq truename (mac-file-truename file)))) ;; ;; need all properties (defmethod (mac-data-stream-mixin :change-properties) (error-p &rest properties) (fs:identify-file-operation :change-properties (fs:handling-errors error-p (do ((a-property properties (cddr a-property))) ((null a-property)) (putprop (locf si:property-list) (cadr a-property) (car a-property))) (mac-change-file-properties file si:property-list)))) ; ; MAC-INPUT-STREAM-MIXIN ; (defflavor mac-input-stream-mixin () (mac-data-stream-mixin si:input-file-stream-mixin)) ;; For input streams, :LENGTH may be different from :LENGTH-IN-BYTES (defmethod (mac-input-stream-mixin :length) () (get (locf si:property-list) :length-in-bytes)) ; ; MAC-OUTPUT-STREAM-MIXIN ; (defflavor mac-output-stream-mixin () (mac-data-stream-mixin si:output-file-stream-mixin)) ;(defmethod (mac-output-stream-mixin :before :close) (&optional abort-p) ; (unless abort-p ; (send self :finish))) ;; ;; MAC-INPUT-STREAM ;; (defflavor mac-input-stream () (mac-input-stream-mixin) (:included-flavors si:buffered-input-stream)) (defmethod (mac-input-stream :next-input-buffer) (&rest ignore) (let* ((dev-blk (file-dev-blk file)) (current-buffer (dev-current-lisp-buffer dev-blk))) (process-wait "File input" #'(lambda (dev-blk iobuffer) (or (= DST-EOF (dev-status dev-blk)) (memq (buffer-state iobuffer) (list ST-FILLED ST-ERROR)))) dev-blk current-buffer) (if (= DST-EOF (dev-status dev-blk)) nil (select (buffer-state current-buffer) (ST-FILLED (let* ((start (buffer-start current-buffer)) (length (buffer-mac-scan current-buffer)) (array (buffer-to-array start length))) (setf (dev-current-lisp-buffer dev-blk) (buffer-next-buffer current-buffer)) (setf (buffer-state current-buffer) ST-DONE) (values array 0 length))) (ST-ERROR (ferror "Error in next-input-buffer" (buffer-error-byte current-buffer))))))) (defmethod (mac-input-stream :discard-input-buffer) (ignore) nil) ;; ;; MAC-OUTPUT-STREAM ;; ;;; The way this works is specific to the Lambda, where we do not have direct access to the ;;; Nubus buffers. (defflavor mac-output-stream () (mac-output-stream-mixin) (:included-flavors si:buffered-output-stream)) (defmethod (mac-output-stream :new-output-buffer) () (values (make-string *buffer-data-size*) 0 *buffer-data-size*)) (defmethod (mac-output-stream :send-output-buffer) (array ending-index) (let* ((dev-blk (file-dev-blk file)) (current-buffer (dev-current-lisp-buffer dev-blk))) (process-wait "File input" #'(lambda (iobuffer) (memq (buffer-state iobuffer) (list ST-IDLE ST-FILLED ST-ERROR))) current-buffer) (select (buffer-state current-buffer) ((ST-IDLE ST-FILLED) (setf (buffer-state current-buffer) ST-RUN) (setf (buffer-falcon-scan current-buffer) ending-index) (array-to-buffer array (buffer-start current-buffer) ending-index) (setf (buffer-state current-buffer) ST-DONE) (setf (dev-current-lisp-buffer dev-blk) (buffer-next-buffer current-buffer))) (ST-ERROR (ferror "Error in new-output-buffer" (buffer-error-byte current-buffer)))))) (defmethod (mac-output-stream :discard-output-buffer) (ignore) nil) (defmethod (mac-output-stream :force-output) () (let ((buffer (send self :STREAM-outPUT-BUFFER))) (if buffer (send self :send-output-buffer buffer (send self :STREAM-outPUT-INDEX))))) (defmethod (mac-output-stream :finish) () (let* ((dev-blk (file-dev-blk file)) (current-buffer (dev-current-lisp-buffer dev-blk))) (process-wait "force output" #'(lambda (dev-blk buffer) (and (equal buffer (dev-current-mac-buffer dev-blk)) (memq (buffer-state buffer) (list ST-IDLE ST-FILLED ST-ERROR)))) dev-blk current-buffer) (if (eq ST-ERROR (buffer-state current-buffer)) (ferror "Error no: ~a in force-output" (buffer-error-byte current-buffer))))) ;; ;; MAC-IO-STREAM ;; ;(defflavor mac-io-stream () ; (si:io-stream-input-mixin mac-output-stream)) ; ; ; MAC-CHARACTER-INPUT-STREAM ; (defflavor mac-character-input-stream () (si:character-stream mac-input-stream si:buffered-tyi-input-stream)) (defmethod (mac-character-input-stream :around :tyi) (cont mt ignore) (let ((ch (funcall-with-mapping-table cont mt :tyi))) (select ch (8 #\BS) (9 #\TAB) (10 #\LINE) (12 #\FF) (13 #\CR) (127 #\RUBOUT) (t ch)))) (defmethod (mac-character-input-stream :tyi-no-hang) () (send self :tyi)) (defmethod (mac-character-input-stream :tyipeek) () (send self :tyi)) ; ; MAC-CHARACTER-OUTPUT-STREAM ; (defflavor mac-character-output-stream () (si:character-stream mac-output-stream si:buffered-tyo-output-stream)) (defmethod (mac-character-output-stream :around :tyo) (cont mt ignore ch) (funcall-with-mapping-table cont mt :tyo (select ch (#\BS 8) (#\TAB 9) (#\LINE 10) (#\FF 12) (#\CR 13) (#\RUBOUT 127) (t ch)))) ; ; MAC-CHARACTER-IO-STREAM ; ;(defflavor mac-character-io-stream () ; (si:io-stream-input-mixin mac-character-output-stream)) ; ; MAC-PROBE-STREAM ; (defflavor mac-probe-stream () (mac-stream-mixin si:stream) ;; kludge so that open can pass this a :byte-size :default (:init-keywords :byte-size)) (defmethod (mac-probe-stream :status) () :closed) (defmethod (mac-probe-stream :direction) () nil) (defmethod (mac-probe-stream :byte-size) () (getf si:property-list :byte-size)) (COMPILE-FLAVOR-METHODS MAC-CHARACTER-INPUT-STREAM MAC-CHARACTER-OUTPUT-STREAM MAC-PROBE-STREAM) (defun undefflavor-all () (undefflavor 'mac-stream-mixin) (undefflavor 'mac-data-stream-mixin) (undefflavor 'mac-input-stream-mixin) (undefflavor 'mac-output-stream-mixin) (undefflavor 'mac-character-input-stream) (undefflavor 'mac-character-output-stream) (undefflavor 'mac-probe-stream)) ;; change (defun mac-finish-output (file) (send-file-cmd-wait (dev-cmd-blk (file-dev-blk file)) :FINISH-OUTPUT 0 0)) (defun mac-file-truename (file) (make-pathname :host mac-host :device :unspecific :directory (file-directory file) :name (file-name file) :type (file-type file) :version (file-version file))) (defun buffer-to-array (start length) (let ((array (make-string length))) (loop for i from 0 to (1- length) do (aset (read-BC-byte (+ start i)) array i) finally (return array)))) (defun array-to-buffer (array buffer end) (loop for i from 0 to (1- end) do (write-BC-byte (+ buffer i) (aref array i)) finally (return buffer)))