;;; -*- Mode: Lisp; Package: File-System; Base: 8 -*-

;;; This file contains stream definitions for the magtape.

;;; Entrypoints are:
;;; MAKE-MT-STREAM &rest options
;;; MAKE-MT-FILE-STREAM &rest options
;;; MAKE-MAGTAPE-FILE-PROBE-STREAM &rest options

;;; Lossages:
;;; PAGE-SIZE-IN-BITS

;; Get a buffer of the correct byte size
(DEFUN MT-GET-RQB-ARRAY (RQB BYTE-SIZE &AUX TYPE)
  (COND ((= BYTE-SIZE 20) (RQB-BUFFER RQB))
	((= BYTE-SIZE 10) (RQB-8-BIT-BUFFER RQB))
	((SETQ TYPE (CDR (ASSQ BYTE-SIZE '((4 . ART-4B) (2 . ART-2B) (1 . ART-1B)))))
	 (MAKE-ARRAY (FLOOR (* (RQB-NPAGES RQB) (* PAGE-SIZE 32.)) BYTE-SIZE)
		     ':AREA LOCAL-FILE-SYSTEM-AREA
		     ':TYPE TYPE
		     ':DISPLACED-TO RQB
		     ;; This is a system bug.  Don't try to figure it out.
		     ':DISPLACED-INDEX-OFFSET (* (%P-CONTENTS-OFFSET (RQB-BUFFER RQB) 3)
						 (FLOOR 20 BYTE-SIZE))))
	(T (FERROR NIL "~D is an invalid byte size." BYTE-SIZE))))

(DEFFLAVOR MT-MIXIN
	((STATUS ':OPEN)
	 (UNIT 0)
	 (RECORD-SIZE 10000)
	 (DENSITY 0)
	 (IBM-MODE NIL)
	 (BYTE-SIZE 10)
	 (RQB NIL))
	()
  (:INCLUDED-FLAVORS SI:STREAM)
  (:GETTABLE-INSTANCE-VARIABLES BYTE-SIZE UNIT)
  (:INITABLE-INSTANCE-VARIABLES UNIT RECORD-SIZE DENSITY IBM-MODE BYTE-SIZE RQB))

(DEFMETHOD (MT-MIXIN :ADVANCE-FILE) () NIL)

(DEFMETHOD (MT-MIXIN :CLOSE) (&OPTIONAL ABORTP)
  (OR (EQ ABORTP ':RAW) (FUNCALL-SELF ':ADVANCE-FILE))
  (COND ((NEQ STATUS ':CLOSED)
	 (SETQ STATUS ':CLOSED)
	 (AND RQB (RETURN-DISK-RQB RQB))
	 (SETQ RQB NIL)
	 T)))

(DEFMETHOD (MT-MIXIN :RETURN-RQB) ()
  (COND (RQB (RETURN-DISK-RQB RQB)
	     (SETQ RQB NIL))))

(DEFFLAVOR MT-INPUT-MIXIN
	()
	(MT-MIXIN)
  (:INCLUDED-FLAVORS SI:BUFFERED-INPUT-STREAM))

(DEFFLAVOR MT-OUTPUT-MIXIN
	()
	(MT-MIXIN)
  (:INCLUDED-FLAVORS SI:BUFFERED-OUTPUT-STREAM))

(DEFMETHOD (MT-INPUT-MIXIN :NEXT-INPUT-BUFFER)
	   (&OPTIONAL IGNORE &AUX BUFFER BYTES-TRANSFERRED)
  (COND ((EQ STATUS ':CLOSED)
	 (FERROR NIL "Attempt to get input from ~S, which is closed." SELF))
	((EQ STATUS ':EOF) NIL)
	(T (OR RQB
	       (SETQ RQB (GET-DISK-RQB (QUOTIENT-CEILING RECORD-SIZE PAGE-SIZE-IN-BYTES))))
	   (MT-RUN RQB %MT-COMMAND-READ (MINUS RECORD-SIZE) UNIT DENSITY)
	   (COND ((MT-STATUS-EOF)
		  (SETQ STATUS ':EOF)
		  NIL)
		 (T (SETQ BYTES-TRANSFERRED
			  (- (SIGN-EXTEND-16 (AR-1 RQB %MT-BYTE-COUNT-AFTER))
			     (SIGN-EXTEND-16 (AR-1 RQB %MT-BYTE-COUNT))))
		    (SETQ BUFFER (MT-GET-RQB-ARRAY RQB BYTE-SIZE))
		    (COND ((BIT-TEST BYTES-TRANSFERRED 3)
			   (FORMAT T "~%~D BYTES, YOU LOST DUE TO UNIBUS MAP LOSSAGE!"
				   BYTES-TRANSFERRED)
			   (PRINT-MT-RQB RQB)))
		    (SETQ BYTES-TRANSFERRED (LOGAND BYTES-TRANSFERRED (LOGNOT 3)))
		    ;; If this is a CHARACTERS file, trim the nulls from the end.
		    ;; These will only appear in the last record if the record size
		    ;; wasn't a multiple of 4.  This could possibly be fixed...
		    (COND ((FUNCALL-SELF ':CHARACTERS)
			   (DO () ((OR (ZEROP BYTES-TRANSFERRED)
				       (NOT (ZEROP (AR-1 BUFFER (1- BYTES-TRANSFERRED))))))
			     (SETQ BYTES-TRANSFERRED (1- BYTES-TRANSFERRED)))))
		    (VALUES BUFFER 0 (FLOOR (* 8 BYTES-TRANSFERRED) BYTE-SIZE)))))))

(DEFMETHOD (MT-INPUT-MIXIN :DISCARD-INPUT-BUFFER) IGNORE)

(DEFMETHOD (MT-INPUT-MIXIN :NEXT-FILE) ()
  (IF (EQ STATUS ':EOF)
      (SETQ STATUS ':OPEN)
    (MT-SPACE-TO-EOF UNIT)
    (FUNCALL-SELF ':CLEAR-INPUT)))

(DEFMETHOD (MT-INPUT-MIXIN :ADVANCE-FILE) ()
  (COND ((NOT (MEMQ STATUS '(:EOF :CLOSED)))
	 (MT-SPACE-TO-EOF UNIT)
	 (SETQ STATUS ':EOF))))

(DEFMETHOD (MT-OUTPUT-MIXIN :NEW-OUTPUT-BUFFER) ()
  (OR RQB (SETQ RQB (GET-DISK-RQB (QUOTIENT-CEILING RECORD-SIZE PAGE-SIZE-IN-BYTES))))
  (VALUES (MT-GET-RQB-ARRAY RQB BYTE-SIZE) 0 (FLOOR (* RECORD-SIZE 8) BYTE-SIZE)))

(DEFMETHOD (MT-OUTPUT-MIXIN :SEND-OUTPUT-BUFFER) (BUFFER TO-INDEX)
  (OR (AND (ARRAY-INDIRECT-P BUFFER)
	   (EQ (%P-CONTENTS-OFFSET BUFFER
				   (1+ (%P-LDB-OFFSET %%ARRAY-LONG-LENGTH-FLAG BUFFER 0)))
	       RQB))
      (FERROR NIL "Attempt to :SEND-OUTPUT-BUFFER ~S, which is not indirected into ~S"
	      BUFFER RQB))
  (LET ((COUNT (FLOOR (* TO-INDEX BYTE-SIZE) 8)))
    ;; Always write an even number of 16 bit words to
    ;; Avoid unibus map buffer lossage.
    (COND ((BIT-TEST COUNT 1)
	   (AS-1 0 BUFFER TO-INDEX)
	   (INCF COUNT)
	   (INCF TO-INDEX)))
    (COND ((BIT-TEST COUNT 3)
	   (AS-1 0 BUFFER TO-INDEX)
	   (AS-1 0 BUFFER (1+ TO-INDEX))
	   (INCF COUNT 2)))
    (COND ((PLUSP COUNT)
	   (MT-RUN RQB %MT-COMMAND-WRITE (MINUS COUNT) UNIT DENSITY IBM-MODE)))))

(DEFMETHOD (MT-OUTPUT-MIXIN :DISCARD-OUTPUT-BUFFER) IGNORE)

(DEFMETHOD (MT-OUTPUT-MIXIN :ADVANCE-FILE) ()
  (OR (EQ STATUS ':CLOSED)
      (MT-WRITE-EOF UNIT)))

(DEFFLAVOR MT-INPUT-STREAM
	()
	(MT-INPUT-MIXIN SI:BUFFERED-INPUT-STREAM))

(DEFFLAVOR MT-OUTPUT-STREAM
	()
	(MT-OUTPUT-MIXIN SI:BUFFERED-OUTPUT-STREAM))

(DEFFLAVOR MT-CHARACTER-INPUT-STREAM
	()
	(MT-INPUT-MIXIN SI:BUFFERED-LINE-INPUT-STREAM))

(DEFFLAVOR MT-CHARACTER-OUTPUT-STREAM
	()
	(MT-OUTPUT-MIXIN SI:BUFFERED-OUTPUT-CHARACTER-STREAM))

(COMPILE-FLAVOR-METHODS MT-INPUT-STREAM MT-OUTPUT-STREAM
			MT-CHARACTER-INPUT-STREAM MT-CHARACTER-OUTPUT-STREAM)

(DEFVAR *DEFAULT-RECORD-SIZE* 10000 "The number of bytes for a magtape record.")
(DEFVAR *MT-EOT-HANDLER* () "Funcalled on EOT by SOME functions.
In most cases, you should use something like CONDITION-BIND.")

;; This function makes a simple stream to the magtape.
;; It can be used by programs which want to read arbitrarily formated magtapes.
(DEFUN MAKE-MT-STREAM (&OPTIONAL &KEY (DIRECTION ':INPUT) (BYTE-SIZE 8) (CHARACTERS T)
		       (UNIT 0) (RECORD-SIZE *DEFAULT-RECORD-SIZE*) (DENSITY 0) (IBM-MODE NIL)
		       &ALLOW-OTHER-KEYS)
  (CHECK-ARG DIRECTION (MEMQ DIRECTION '(:INPUT :OUTPUT)) ":INPUT or :OUTPUT")
  (CHECK-ARG-TYPE BYTE-SIZE :NUMBER)
  (CHECK-ARG CHARACTERS (MEMQ CHARACTERS '(T NIL)) "T or NIL")
  (MAKE-INSTANCE (IF (EQ DIRECTION ':INPUT)
		     (IF CHARACTERS
			 'MT-CHARACTER-INPUT-STREAM
		       'MT-INPUT-STREAM)
		   (IF CHARACTERS
		       'MT-CHARACTER-OUTPUT-STREAM
		     'MT-OUTPUT-STREAM))
		 ':BYTE-SIZE BYTE-SIZE
		 ':UNIT UNIT
		 ':RECORD-SIZE RECORD-SIZE
		 ':DENSITY DENSITY
		 ':IBM-MODE IBM-MODE))

;;; Magtapes with headers.

;;; The following function reads a block from the magtape and tries to
;;; determine the header plist.  If it reads an EOF, it returns NIL.
;;; The second value returned is the style of header.
;;; Currently known about are :MIT, :MIT, and :MIT.

;;; this code returns a pure PLIST and does not make any assumptions about
;;; name formats or anything.

(DEFUN READ-MAGTAPE-HEADER (STREAM &AUX BUF LOW COUNT PLIST)
  (UNWIND-PROTECT
    (PROGN (MULTIPLE-VALUE (BUF LOW COUNT)
	     (FUNCALL STREAM ':GET-INPUT-BUFFER))
	   (COND ((NULL BUF) NIL)			;EOF
		 ((AND ( COUNT 4)
		       (STRING-EQUAL BUF "LMFL" LOW 0 (+ LOW 4) 4))
		  ;; MIT format.
		  (LOOP REPEAT 4 DO (FUNCALL STREAM ':TYI))
		  (LET ((BASE 10.) (IBASE 10.)
			(PACKAGE FILE-SYSTEM-PACKAGE))  ;for compatibility with old tapes
				;and also so :s come out.
		    (SETQ PLIST (READ STREAM)))
		  (VALUES PLIST ':MIT))
		 (T (FERROR NIL "Unknown tape header format.  Header is:~%~A"
			    (SUBSTRING BUF LOW (+ LOW COUNT))))))
    (FUNCALL STREAM ':DISCARD-CURRENT-INPUT-BUFFER)))
    
    
(DEFCONST TAPE-HEADER-LENGTH 1024. "Maximum and guaranteed block length for the header.")

(DEFUN WRITE-MAGTAPE-HEADER (STREAM PLIST &OPTIONAL (STYLE ':MIT))
  (UNWIND-PROTECT
      (SELECTQ STYLE
	(:MIT
	 (LET* ((*NOPOINT T)
		(BASE 10.)
		(PACKAGE FILE-SYSTEM-PACKAGE)
		(SI:PRINT-READABLY T)
		(READTABLE SI:INITIAL-READTABLE))
	   (SEND STREAM ':STRING-OUT "LMFL")
	   (PRIN1 PLIST STREAM)
	   (FUNCALL STREAM ':PAD-AND-SEND-BUFFER #\SPACE)))
	(OTHERWISE (FERROR NIL "~S is an unknown tape header format." STYLE)))
    (FUNCALL STREAM ':FINISH)))

(DEFFLAVOR HEADER-MIXIN
	(HEADER-FORMAT
	 (SI:PROPERTY-LIST NIL))
	(SI:PROPERTY-LIST-MIXIN)
  (:INCLUDED-FLAVORS MT-MIXIN)
  :INITABLE-INSTANCE-VARIABLES)

(DEFFLAVOR HEADER-INPUT-MIXIN
	()
	(HEADER-MIXIN))

(DEFFLAVOR HEADER-OUTPUT-MIXIN
	()
	(HEADER-MIXIN))

;; Write the header at the last possible minute.
(DEFMETHOD (HEADER-OUTPUT-MIXIN :BEFORE :NEXT-INPUT-BUFFER) ()
  (AND (EQ STATUS ':OPEN)
       (NULL RQB)
       (WRITE-MAGTAPE-HEADER SELF SI:PROPERTY-LIST HEADER-FORMAT)))

;this tries to responds to pathcomponent stream messages, but may not make any
; assumptions about the exact flavor of path involved (which file system, etc).
(DEFFLAVOR MT-FILE-MIXIN
	()
	()
  (:INCLUDED-FLAVORS HEADER-MIXIN MT-MIXIN))

(DEFFLAVOR MT-FILE-INPUT-MIXIN
	()
	(MT-FILE-MIXIN))

(DEFFLAVOR MT-FILE-OUTPUT-MIXIN
	()
	(MT-FILE-MIXIN))

(DEFFLAVOR MT-FILE-INPUT-STREAM
	()
	(MT-FILE-INPUT-MIXIN HEADER-INPUT-MIXIN MT-INPUT-STREAM))

(DEFFLAVOR MT-FILE-CHARACTER-INPUT-STREAM
	()
	(MT-FILE-INPUT-MIXIN HEADER-INPUT-MIXIN MT-CHARACTER-INPUT-STREAM))

(DEFFLAVOR MT-FILE-OUTPUT-STREAM
	()
	(MT-FILE-OUTPUT-MIXIN HEADER-OUTPUT-MIXIN MT-OUTPUT-STREAM))

(DEFFLAVOR MT-FILE-CHARACTER-OUTPUT-STREAM
	()
	(MT-FILE-OUTPUT-MIXIN HEADER-OUTPUT-MIXIN MT-CHARACTER-OUTPUT-STREAM))

(DEFMETHOD (MT-FILE-MIXIN :DEVICE) ()
  NIL)

(DEFMETHOD (MT-FILE-MIXIN :DIRECTORY) ()
  (GET (LOCF SI:PROPERTY-LIST) ':DIRECTORY))

(DEFMETHOD (MT-FILE-MIXIN :NAME) ()
  (GET (LOCF SI:PROPERTY-LIST) ':NAME))

(DEFMETHOD (MT-FILE-MIXIN :TYPE) ()
  (GET (LOCF SI:PROPERTY-LIST) ':TYPE))

(DEFMETHOD (MT-FILE-MIXIN :VERSION) ()
  (GET (LOCF SI:PROPERTY-LIST) ':VERSION))
  
(DEFMETHOD (MT-FILE-MIXIN :CREATION-DATE) ()
  (GET (LOCF SI:PROPERTY-LIST) ':CREATION-DATE))

(DEFMETHOD (MT-FILE-MIXIN :QFASLP) ()
  (GET (LOCF SI:PROPERTY-LIST) ':QFASLP))

(DEFMETHOD (MT-FILE-OUTPUT-MIXIN :CHANGE-PROPERTIES) (IGNORE &REST PROPERTIES)
  (LOOP FOR (IND PROP) IN PROPERTIES BY #'CDDR
	DO (PUTPROP (LOCF SI:PROPERTY-LIST) PROP IND)))

;; This takes keywords compatibly with OPEN
;; Probe openings are not implemented.
;; This function expects the magtape to be at the beginning of a file header.
;; Errors returned unique to magtape are:
;;  PNA F Probe openings not allowed
;;  EOT F End of Tape

(DEFUN MAKE-MT-FILE-STREAM (&OPTIONAL
			     &REST OPTIONS
			     &KEY
			    (DIRECTION ':INPUT)
			    (CHARACTERS ':DEFAULT)
			    (ERROR T)
			    (BYTE-SIZE ':DEFAULT)
			    (UNIT 0)
			    (RECORD-SIZE *DEFAULT-RECORD-SIZE*)
			    (DENSITY 0)
			    (IBM-MODE NIL)
			    (PLIST NIL)
			    (HEADER-STYLE ':MIT)	;Default for write
			    &ALLOW-OTHER-KEYS
			    &AUX STREAM TEM)
  (COND ((EQ DIRECTION ':INPUT)
	 (MULTIPLE-VALUE (PLIST HEADER-STYLE)
	   (READ-MAGTAPE-HEADER
	     (SETQ STREAM (LEXPR-FUNCALL 'MAKE-MT-STREAM
					 ':CHARACTERS T
					 ':BYTE-SIZE 8
					 ':UNIT UNIT
					 ':DENSITY DENSITY
					 OPTIONS))))
	 (FUNCALL STREAM ':CLOSE ':RAW)
	 (IF (NULL PLIST)
	     (MT-OPEN-ERROR (MAKE-CONDITION 'END-OF-TAPE "End of tape on unit ~D." UNIT)
			    ERROR)
	     (AND (EQ CHARACTERS ':DEFAULT)
		  (IF (SETQ TEM (GETL (LOCF PLIST) '(:CHARACTERS)))
		      (SETQ CHARACTERS (CADR TEM))
		      ;; Kludge for old format tapes.
		      (SETQ CHARACTERS (= (GET (LOCF PLIST) ':BYTE-SIZE) 8))))
	     (AND (EQ BYTE-SIZE ':DEFAULT)
		  (SETQ BYTE-SIZE (GET (LOCF PLIST) ':BYTE-SIZE)))
	     (AND (NULL BYTE-SIZE)
		  (SETQ BYTE-SIZE (IF CHARACTERS 8. 16.)))
	     (MAKE-INSTANCE (IF CHARACTERS
				'MT-FILE-CHARACTER-INPUT-STREAM
				'MT-FILE-INPUT-STREAM)
			    ':BYTE-SIZE BYTE-SIZE
			    ':UNIT UNIT
			    ':RECORD-SIZE RECORD-SIZE
			    ':DENSITY DENSITY
			    ':PROPERTY-LIST PLIST
			    ':HEADER-FORMAT HEADER-STYLE
			    ':IBM-MODE IBM-MODE)))
	((EQ DIRECTION ':OUTPUT)
	 (AND (EQ BYTE-SIZE ':DEFAULT)
	      (SETQ BYTE-SIZE (GET (LOCF PLIST) ':BYTE-SIZE)))
	 (AND (NULL BYTE-SIZE)
	      (SETQ BYTE-SIZE (IF CHARACTERS 8. 16.)))
	 (WRITE-MAGTAPE-HEADER
	   (SETQ STREAM (LEXPR-FUNCALL 'MAKE-MT-STREAM
				       ':DIRECTION ':OUTPUT
				       ':CHARACTERS T
				       ':BYTE-SIZE 8
				       ':UNIT UNIT
				       ':DENSITY DENSITY
				       OPTIONS))
	   PLIST
	   HEADER-STYLE)
	 (FUNCALL STREAM ':CLOSE ':RAW)
	 (MAKE-INSTANCE (IF CHARACTERS
			    'MT-FILE-CHARACTER-OUTPUT-STREAM
			    'MT-FILE-OUTPUT-STREAM)
			':BYTE-SIZE BYTE-SIZE
			':UNIT UNIT
			':RECORD-SIZE RECORD-SIZE
			':DENSITY DENSITY
			':PROPERTY-LIST PLIST
			':HEADER-FORMAT HEADER-STYLE
			':IBM-MODE IBM-MODE))
	(T (FERROR NIL "Probe opens not allowed on magtape."))))

(DEFUN MT-OPEN-ERROR (CONDITION ERROR-P)
  (IF ERROR-P
      (SIGNAL-CONDITION CONDITION)
    CONDITION))

(COMPILE-FLAVOR-METHODS MT-FILE-INPUT-STREAM MT-FILE-CHARACTER-INPUT-STREAM
			MT-FILE-OUTPUT-STREAM MT-FILE-CHARACTER-OUTPUT-STREAM)

;;; RESTORE-MAGTAPE

;; This is the driver for RESTORE-MAGTAPE and friends.
;; The first value returned describes what it found on the magtape.
;; Possible values are:
;;  :EOF		An end of file block was found.
;;  :STREAM		A header block was found and sucessfully decoded.
;;			Second value is an input stream, from which can be found
;;			properties, truenames, partition-p, etc.
;;  :TAPE-HEADER	A block was found which was a tape header.
;;			The plist from this header is the second value.
;;  :HEADER		This is some sort of header which is not a tape header.
;;			The plist from this header is the second value.
;;  :ERROR		A tape header couldn't be decoded.
;;			Reason (a string) is the second value.

;This tries to be just enuf to allow opening MT: for input or output.
; It specifially tries to make no assumptions about pathnames.
(DEFFLAVOR MT-HOST
	(DEVICE-NAME)
	(SI:BASIC-HOST)
  (:GETTABLE-INSTANCE-VARIABLES DEVICE-NAME)
  (:INITABLE-INSTANCE-VARIABLES DEVICE-NAME))

(DEFMETHOD (MT-HOST :NAME) NIL DEVICE-NAME)
(DEFMETHOD (MT-HOST :NAME-AS-FILE-COMPUTER) NIL DEVICE-NAME)
(DEFMETHOD (MT-HOST :PATHNAME-HOST-NAMEP) (NAME)
  (STRING-EQUAL NAME DEVICE-NAME))

(DEFMETHOD (MT-HOST :PATHNAME-FLAVOR) ()
  (VALUES 'MT-PATHNAME NIL))

(DEFFLAVOR MT-PATHNAME () (PATHNAME))

(DEFMETHOD (MT-PATHNAME :PARSE-NAMESTRING)
	   (HOST-SPECIFIED STRING &OPTIONAL (START 0) END)
  HOST-SPECIFIED
  (VALUES ':NO-INTERN (MAKE-INSTANCE 'MT-FILEHANDLE
				     ':NAMESTRING (SUBSTRING STRING START END))))

;NAMESTRING is just for pseudo debugging purposes; Magtape files dont really have names.
(DEFFLAVOR MT-FILEHANDLE (NAMESTRING) ()
  (:INITABLE-INSTANCE-VARIABLES NAMESTRING))

(DEFMETHOD (MT-FILEHANDLE :STRING-FOR-PRINTING) () NAMESTRING)
(DEFMETHOD (MT-FILEHANDLE :PRINT-SELF) (STREAM PRINDEPTH SLASHIFY-P) PRINDEPTH
  (COND (SLASHIFY-P
	 (SEND STREAM ':STRING-OUT "#<")
	 (PRIN1 'MT-FILEHANDLE STREAM)
	 (FORMAT STREAM " ~S ~O>" NAMESTRING (%POINTER SELF)))
	(T
	 (SEND STREAM ':STRING-OUT NAMESTRING))))

;This is a kludge to make the copy-patch-files-of-system work.
(DEFMETHOD (MT-FILEHANDLE :PATCH-FILE-PATHNAME) (&REST IGNORE)
  "MT:")

(DEFUN PUTPROP-MAYBE (PLIST VALUE PROP)
  (WHEN (AND VALUE (NULL (GET PLIST PROP)))
    (PUTPROP PLIST VALUE PROP)))

(DEFMETHOD (MT-FILEHANDLE :OPEN) (IGNORE &REST KEYWORD-ARGS
					 &KEY &OPTIONAL
					 (DIRECTION ':INPUT)
					 DEFAULTS-FROM-STREAM 
					 BYTE-SIZE
					 AUTHOR
					 &ALLOW-OTHER-KEYS)
  (COND ((EQ DIRECTION ':INPUT)
	 (LEXPR-FUNCALL 'MAKE-MT-FILE-STREAM KEYWORD-ARGS))
	((EQ DIRECTION ':OUTPUT)
	 (COND (DEFAULTS-FROM-STREAM
		(LET* ((TRUENAME (FUNCALL DEFAULTS-FROM-STREAM ':TRUENAME))
		       (PLIST
			 (FILTER-PLIST (FUNCALL DEFAULTS-FROM-STREAM ':PLIST)
				       (PLIST TRUENAME)))
		       (REAL-PLIST (LOCF PLIST)))
		  (PUTPROP-MAYBE REAL-PLIST BYTE-SIZE ':BYTE-SIZE)
		  (PUTPROP-MAYBE REAL-PLIST AUTHOR ':AUTHOR)
		  (PUTPROP-MAYBE REAL-PLIST (SEND TRUENAME ':DIRECTORY) ':DIRECTORY)
		  (PUTPROP-MAYBE REAL-PLIST (SEND TRUENAME ':NAME) ':NAME)
		  (PUTPROP-MAYBE REAL-PLIST (SEND TRUENAME ':TYPE) ':TYPE)
		  (PUTPROP-MAYBE REAL-PLIST (SEND TRUENAME ':VERSION) ':VERSION)
   ;:UNSPECIFIC would not win when read back in, so guess.
		  (IF (EQ (GET (LOCF PLIST) ':TYPE)
			  ':UNSPECIFIC)
		      (LET ((FPLIST (FILE-READ-ATTRIBUTE-LIST NIL DEFAULTS-FROM-STREAM)))
			(PUT-ON-ALTERNATING-LIST
			  (COND ((EQ (GET (LOCF FPLIST) ':MODE)
				     ':LISP)
				 "LISP")
				((= BYTE-SIZE 10)
				 "TEXT")
				(T "UNKNOWN"))
			  PLIST
			  ':TYPE)))
		  (LEXPR-FUNCALL 'MAKE-MT-FILE-STREAM
				 ':PLIST PLIST
				 KEYWORD-ARGS)))
	       (T (FERROR NIL "MT: wins only for copying with stream default"))))
	(T (FERROR () "~A not a recognised :OPEN direction (and probes are not allowed"
		   DIRECTION))))

;TRY TO GET RID OF ANY UNPRINTABLE THINGS FROM PLIST-TO-FILTER..
(DEFUN FILTER-PLIST (PLIST-TO-FILTER PLIST-SO-FAR)
  (COND ((NULL PLIST-TO-FILTER) PLIST-SO-FAR)
	((OR (NULL (CADR PLIST-TO-FILTER))
	     (NUMBERP (CADR PLIST-TO-FILTER))
	     (STRINGP (CADR PLIST-TO-FILTER))
	     (LISTP (CADR PLIST-TO-FILTER)))
	 (FILTER-PLIST (CDDR PLIST-TO-FILTER)
		       (CONS (CAR PLIST-TO-FILTER)
			     (CONS (CADR PLIST-TO-FILTER)
				   PLIST-SO-FAR))))
	(T (FILTER-PLIST (CDDR PLIST-TO-FILTER) PLIST-SO-FAR))))

(DEFUN ADD-MT-HOST (&OPTIONAL (NAME "MT"))
  (COND ((NULL (GET-PATHNAME-HOST NAME T))
	 (LET ((HOST (MAKE-INSTANCE 'MT-HOST ':DEVICE-NAME NAME)))
	   (PUSH HOST *PATHNAME-HOST-LIST*)))))
(COMPILE-FLAVOR-METHODS MT-HOST MT-PATHNAME MT-FILEHANDLE)

(ADD-MT-HOST)

