;;; -*- Mode: Lisp; Package: File-System; Base: 8 -*-
;;; Dump stuff (which will be obsolete as of February 1984) moved to SYS:FILE;ODUMP
;;;
;;; Entry functions which deal only with magtape
;;; MAGTAPE-LIST-FILES -- List files on a magtape.
;;; RESTORE-MAGTAPE -- Restore whatever's on the mounted magtape.
;;; MT-WRITE-FILES -- Write files to magtape.
;;; MT-WRITE-DIRECTORY -- Write an entire directory to magtape.
;;; MT-WRITE-PARTITION -- Write a partition onto a magtape.
;;;
;;; Other functions:
;;; PRINT-MAGTAPE -- Directly print contents of the magtape (for debugging).
;;; 
;;; Moved to SYS:TAPE;PDP10
;;; LOAD-PDP10-DUMP-MAGTAPE -- Load a tape made on DM.
;;; MT-WRITE-PDP10-FILES -- Write files to be read at DM.
;;; VAX functions moved to SYS:TAPE;VAX

;;; If TRANSFORM is supplied, it should be a function of five arguments
;;; (host, directory, name, type, version) that returns a pathname that actually gets the file
;;; or a symbol with a FS:TAPE-RESTORE-TRANSFORM property that is such a function.
;;; The host argument is a host object.
(DEFUN RESTORE-MAGTAPE (&OPTIONAL &KEY (HOST SI:LOCAL-HOST) (QUERY T) DIRECTORIES
			TAPE-OPTIONS COPY-OPTIONS FILES TRANSFORM
			&AUX file last-time-p DIRECTORY NAME TYPE VERSION)
  (SETQ HOST (FS:GET-PATHNAME-HOST HOST))
  (WHEN (AND TRANSFORM (NOT (FUNCTIONP TRANSFORM)))
    (SETQ TRANSFORM (GET TRANSFORM 'TAPE-RESTORE-TRANSFORM))
    (IF (NOT (FUNCTIONP TRANSFORM))
	(FERROR () "The transform supplied is bogus.")))
  (if files (setq files
		  (LOOP FOR file IN files
			AS path = (parse-pathname file)
			COLLECT (string-append
				  (send path ':directory)
				  ";" (send path ':name)))))
  (LOOP AS stream = (LEXPR-FUNCALL #'MAKE-MT-FILE-STREAM ':DIRECTION ':INPUT ':ERROR NIL
				   TAPE-OPTIONS)
	UNTIL (errorp stream) 
	WHEN (send stream ':GET ':PARTITION) ; If this is a partition, allow loading
	DO
	(format T "~%Tape partition ~S, length ~D.  Load ? "
		(send stream ':GET ':COMMENT) (send stream ':GET ':SIZE))
	(cond ((yes-or-no-p)
	       (let ((disk-device
		       (if (yes-or-no-p
			     "Do you want to load the partition onto the local disk ? ")
			   0
			 (format T "~&Enter the machine name (i.e. cadr2): ")
			 (READLINE-TRIM))))
		 (format T "~&Copy into partition: ")
		 (mt-space-rev-to-bof)
		 (si:copy-disk-partition "MT" (send stream ':GET ':NAME)
					 disk-device (readline)))))
	ELSE
	DO (cond (last-time-p (send stream ':CLOSE) (return t))
		 ((and directories
		       (not (member (send stream ':DIRECTORY) directories))))
		 ((and files
		       (cond ((member
				(setq file
				      (string-append
					(send stream ':directory)
					";" (send stream ':name)))
				files)
			      (setq files (delete file files))
			      (if (null files) (setq last-time-p T))
			      NIL)
			     (T T))))
		 ((if (PROGN
			(SETQ DIRECTORY (SEND STREAM :DIRECTORY) NAME (SEND STREAM :NAME)
			      TYPE (SEND STREAM :TYPE) VERSION (SEND STREAM :VERSION))
			QUERY)
		      (PROGN
			(format T "~%~S;~S ~S #~D " DIRECTORY NAME TYPE VERSION)
			(not (y-or-n-p "Restore ? ")))))
		 (T
		  (LEXPR-FUNCALL #'FS-COPY-FILE STREAM
				 (IF TRANSFORM (FUNCALL TRANSFORM
							HOST NAME DIRECTORY TYPE VERSION)
				   HOST)
				 copy-options)))
		 ;No good to do :NEXT-FILE because the :CLOSE operation does an :ADVANCE-FILE 
	DO (send stream ':CLOSE)))

;;; Asssumes standard SYS:FOO; ==> <L.FOO> translations.
(DEFUN (:PROPERTY :STANDARD-SYS TAPE-RESTORE-TRANSFORM) (HOST DIRECTORY NAME TYPE VERSION)
  HOST ; ignored, using standard sys host
  (FS:MAKE-PATHNAME ':HOST (FS:GET-PATHNAME-HOST "SYS") ':DIRECTORY (CDR DIRECTORY)
		    ':NAME NAME ':TYPE TYPE ':VERSION VERSION))

(DEFUN FN-CONCATENATE (LIST)
  (PROG (NAME)
	(SETQ NAME (CAR LIST) LIST (CDR LIST))
     L  (COND ((NULL LIST) (RETURN NAME)))
	(SETQ NAME (STRING-APPEND NAME "-" (CAR LIST))
	      LIST (CDR LIST))
	(GO L)))
	
;; Allow for partitions also.
(DEFUN MAGTAPE-LIST-FILES (&OPTIONAL (OUT-STREAM STANDARD-OUTPUT))
  (DO ((STREAM))
      ((ERRORP (SETQ STREAM (MAKE-MT-FILE-STREAM ':DIRECTION ':INPUT ':ERROR NIL))))
    (IF (SEND STREAM ':GET ':PARTITION)
	(FORMAT OUT-STREAM "~%Partition ~A: ~S, Size ~D"
		(SEND STREAM ':GET ':NAME)
		(SEND STREAM ':GET ':COMMENT)
		(SEND STREAM ':GET ':SIZE))
	(FORMAT OUT-STREAM "~%~A; ~A ~A #~D~35TByte Size ~2D, Created "
		(SEND STREAM ':DIRECTORY)
		(SEND STREAM ':NAME)
		(SEND STREAM ':TYPE)
		(SEND STREAM ':VERSION)
		(SEND STREAM ':BYTE-SIZE))
	(TIME:PRINT-UNIVERSAL-TIME (SEND STREAM ':CREATION-DATE) OUT-STREAM)
;	(FORMAT T "~%PLIST: ~S" (SEND STREAM ':FILE-PLIST))
	)
    (SEND STREAM ':CLOSE)))

;; Tape creation functions which hack EOT.

(DEFUN MT-EOT-HANDLER (&REST IGNORE)
  (*THROW 'EOT NIL))

(DEFUN MT-WRITE-FILES (&REST FILES &AUX (*MT-EOT-HANDLER* 'MT-EOT-HANDLER))
  (LOOP FOR FILE IN FILES DOING
	(LOOP UNTIL (*CATCH 'EOT (COPY-FILE FILE "MT") T)
	      DO (MT-SPACE-REV-TO-BOF)
		 (MT-WRITE-EOF)
		 (MT-REWIND)
		 (BEEP)
		 (FORMAT ERROR-OUTPUT "~&>>> MagTape reached end of tape <<<")
		 (MT-OFFLINE)
		 (LOOP DOING (FORMAT ERROR-OUTPUT "~%Type [Resume] when new tape is mounted:")
		       UNTIL (SEND STANDARD-INPUT ':CLEAR-INPUT)
			     (EQ (SEND STANDARD-INPUT ':TYI) #\RESUME)
		       DOING (BEEP)))
	FINALLY (MT-WRITE-EOF) (MT-SPACE-REV)))

(DEFUN MT-WRITE-DIRECTORIES (&OPTIONAL (HOST SI:LOCAL-HOST) &REST DIRECTORIES)
  (SETQ DIRECTORIES
	(LOOP FOR D IN (OR DIRECTORIES
			   (LOOP FOR D IN (ALL-DIRECTORIES HOST)
				 COLLECTING (SEND (CAR D) ':DIRECTORY)))
	      WHEN D COLLECT (MAKE-PATHNAME ':HOST HOST ':DIRECTORY D ':NAME NIL)))
  (LOOP FOR DIRECTORY IN DIRECTORIES
	DO (FORMAT T "~%Dumping ~A" DIRECTORY)
	   (MT-WRITE-DIRECTORY DIRECTORY)
	   (FORMAT T "~%~%")))
  
(DEFUN MT-WRITE-DIRECTORY (PATH &AUX (*MT-EOT-HANDLER* 'MT-EOT-HANDLER))
  (SETQ PATH (PARSE-PATHNAME PATH))
  (SETQ PATH (SEND PATH ':NEW-PATHNAME
		      ':NAME (OR (PATHNAME-NAME PATH) ':WILD)
		      ':TYPE (OR (PATHNAME-TYPE PATH) ':WILD)
		      ':VERSION (OR (PATHNAME-VERSION PATH) ':WILD)))
  (LOOP AS COUNT = 0 UNTIL
	(*CATCH 'EOT
	  (LOOP FOR (FILE . DIR-LIST)
		IN (DIRECTORY-LIST PATH)
		WHEN (AND FILE (NOT (GET (LOCF DIR-LIST) ':LINK-TO)))
		DO (COPY-FILE FILE "MT" ':DIRECTORY-LIST DIR-LIST)
		   (INCF COUNT)
		FINALLY (RETURN T)))
	DO (LOOP REPEAT COUNT DO (MT-SPACE-REV 0))
	   (MT-SPACE-REV-TO-BOF)
	   (MT-WRITE-EOF)
	   (MT-REWIND)
	   (BEEP)
	   (FORMAT ERROR-OUTPUT "~&>>> MagTape reached end of tape <<<")
	   (MT-OFFLINE)
	   (LOOP DOING (FORMAT ERROR-OUTPUT "~%Type [Resume] when new tape is mounted:")
		 UNTIL (SEND STANDARD-INPUT ':CLEAR-INPUT)
		       (EQ (SEND STANDARD-INPUT ':TYI) #\RESUME)
		 DOING (BEEP))
	FINALLY (MT-WRITE-EOF) (MT-SPACE-REV)))

(DEFUN MT-WRITE-PARTITION (PARTITION &OPTIONAL (UNIT 0))
  (SI:COPY-DISK-PARTITION UNIT PARTITION "MT" PARTITION)
  (MT-WRITE-EOF)
  (MT-SPACE-REV))


;; MagTape Band transfer handler.
(DECLARE (SPECIAL *BAND-WRITE* *BAND-PLIST* *BAND-STREAM*))

(DEFUN MAKE-BAND-MAGTAPE-HANDLER (*BAND-WRITE*)
  (LET ((*BAND-PLIST* `(:PARTITION T :BYTE-SIZE 20 :AUTHOR ,USER-ID))
	(*BAND-STREAM* NIL))
    (COND ((NULL *BAND-WRITE*)
	   (SETQ *BAND-STREAM* (MAKE-MT-FILE-STREAM ':DIRECTION ':INPUT ':CHARACTERS NIL)
		 *BAND-PLIST* (SEND *BAND-STREAM* ':PLIST))))
    (CLOSURE '(*BAND-WRITE* *BAND-PLIST* *BAND-STREAM*)
	     'BAND-MAGTAPE-HANDLER)))

(DEFSELECT (BAND-MAGTAPE-HANDLER IGNORE)
  (:READ (RQB BLOCK)
    BLOCK
    (SEND *BAND-STREAM* ':STRING-IN "unexpected EOF"
	     (RQB-BUFFER RQB) 0 (* (RQB-NPAGES RQB) 1000)))
  (:WRITE (RQB BLOCK &AUX
	   (N-BLOCKS (RQB-NPAGES RQB))
	   (N-HWDS (* N-BLOCKS 1000))
	   (BUF (RQB-BUFFER RQB)))
    BLOCK
    (OR *BAND-STREAM*
	(SETQ *BAND-STREAM*
	      (MAKE-MT-FILE-STREAM ':DIRECTION ':OUTPUT
				   ':PLIST *BAND-PLIST*
				   ':CHARACTERS NIL)))
    (SEND *BAND-STREAM* ':STRING-OUT BUF 0 N-HWDS))
  (:DISPOSE ()
    (COND (*BAND-STREAM*
	   (SEND *BAND-STREAM* ':CLOSE)
	   (SETQ *BAND-STREAM* NIL))))
  (:HANDLES-LABEL () T)
  (:GET (IND) (GET (LOCF *BAND-PLIST*) IND))
  (:PUT (PROP IND) (PUTPROP (LOCF *BAND-PLIST*) PROP IND))
  (:FIND-DISK-PARTITION (NAME &AUX TEM)
    (IF (SETQ TEM (GET-FROM-ALTERNATING-LIST *BAND-PLIST* ':NAME))
	(IF (NOT (EQUALP NAME TEM))
	    (IF (NULL (Y-OR-N-P (FORMAT NIL "~%Tape partition ~s, OK?" *BAND-PLIST*)))
		(BREAK "Now what do you do ?" T))) ; this should be changed...
	(PUTPROP (LOCF *BAND-PLIST*) NAME ':NAME))
    (VALUES  0
	     (OR (GET (LOCF *BAND-PLIST*) ':SIZE) 3777777)
	     NIL))
  (:PARTITION-COMMENT (IGNORE)
    (GET (LOCF *BAND-PLIST*) ':COMMENT)))


;; All stuff hereafter is untested kruft left over from the days of RG;MT.
;; Moved to SYS: TAPE; PDP10

(DEFUN PLIST-VIA-PATHNAME (FILE &AUX ANS)
  (IF (OR (STRINGP FILE)
	  (TYPEP FILE 'PATHNAME))
      (SETQ FILE (OPEN FILE '(:PROBE))))
  (IF (STRINGP FILE)
      (FERROR NIL FILE)
      (LET ((INPATH (SEND FILE ':TRUENAME))
	    (WO  (SEND FILE ':WHICH-OPERATIONS)))
	(LET ((DIRECTORY (SEND INPATH ':DIRECTORY))
	      (NAME (SEND INPATH ':NAME))
	      (TYPE (SEND INPATH ':TYPE))
	      (VERSION (SEND INPATH ':VERSION)))
	  (SETQ ANS `(:DIRECTORY ,DIRECTORY :NAME ,NAME :TYPE ,TYPE :VERSION ,VERSION))
	  (LET ((BYTE-SIZE (COND ((MEMQ ':BYTE-SIZE WO) (SEND FILE ':BYTE-SIZE))
				 ((EQUAL TYPE "QFASL") 16.)
				 (T 8.)))
		(CREATION-DATE (IF (MEMQ ':CREATION-DATE WO)
				   (SEND FILE ':CREATION-DATE)))
		(AUTHOR  (IF (MEMQ ':AUTHOR WO)
			     (SEND FILE ':AUTHOR))))
	    (SETQ ANS (NCONC ANS `(:BYTE-SIZE ,BYTE-SIZE)))
	    (IF CREATION-DATE (SETQ ANS (NCONC ANS `(:CREATION-DATE ,CREATION-DATE))))
	    (IF AUTHOR (SETQ ANS (NCONC ANS `(:AUTHOR ,AUTHOR))))
	    (IF (MEMQ ':PLIST WO)
		(TV:DOPLIST ((SEND FILE ':PLIST) VAL IND)
		  (IF (GET-FROM-ALTERNATING-LIST ANS IND)
		      NIL
		      (SETQ ANS (NCONC ANS (LIST IND VAL))))))
	    ANS)))))

(DEFUN PLIST-FROM-PATHNAME (PATHNAME)
  `(:DIRECTORY ,(SEND PATHNAME ':DIRECTORY)
    :NAME ,(SEND PATHNAME ':NAME)
    :VERSION ,(SEND PATHNAME ':VERSION)
    :TYPE ,(SEND PATHNAME ':TYPE)))

(DEFUN PATHNAME-FROM-PLIST (HOST DIRECTORY PLIST)
  (IF (TYPEP PLIST 'PATHNAME)
      PLIST
      (MAKE-PATHNAME ':HOST HOST
		     ':DIRECTORY (IF DIRECTORY DIRECTORY
				     (GET-FROM-ALTERNATING-LIST PLIST ':DIRECTORY))
		     ':NAME (GET-FROM-ALTERNATING-LIST PLIST ':NAME)
		     ':TYPE (GET-FROM-ALTERNATING-LIST PLIST ':TYPE)
		     ':VERSION (GET-FROM-ALTERNATING-LIST PLIST ':VERSION))))

(DEFUN ASCII-TO-LISPM (CH)
  (COND ((EQ CH 12) NIL)
	((MEMQ CH '(10 11 14 15)) (+ CH 200))
	(T CH)))

(DEFUN LISPM-TO-ASCII (CH)
  (COND ((>= CH 200)
	 (- CH 200))
	(T CH)))

;SPECIAL FUNCTION TO DUMP TAMI'S PICTURE DATA ARRAY IN IBM MODE.
(DEFUN DUMP-2D-BYTE-ARRAY-RAW (ARRAY)
  (LET ((XLIM (ARRAY-DIMENSION ARRAY 1))
	(YLIM (ARRAY-DIMENSION ARRAY 2)))
    (LET ((STREAM (MAKE-MT-STREAM ':DIRECTION ':OUTPUT
				  ':IBM-MODE T ':RECORD-SIZE (+ 100 YLIM))))
      (DOTIMES (Y YLIM)
	(DOTIMES (X XLIM)
	  (SEND STREAM ':TYO (AR-2 ARRAY X Y)))
	(SEND STREAM ':ADVANCE-OUTPUT-BUFFER))
      (SEND STREAM ':CLOSE))))

;; For Debugging.
(DEFUN PRINT-MAGTAPE (&REST OPTIONS)
  (LET ((IS (LEXPR-FUNCALL #'MAKE-MT-STREAM OPTIONS)))
    (UNWIND-PROTECT
      (STREAM-COPY-UNTIL-EOF IS STANDARD-OUTPUT NIL)
      (FUNCALL IS ':CLOSE ':RAW)))		;Avoid searching for EOF
						;This should not normally be done.
  T)


(DEFUN COPY-MAGTAPE-FILE (FN &REST OPTIONS)
  (LET ((IS (LEXPR-FUNCALL #'MAKE-MT-STREAM OPTIONS)))
    (WITH-OPEN-FILE (OS FN ':OUT)
      (UNWIND-PROTECT 
	(STREAM-COPY-UNTIL-EOF IS OS NIL)
	(FUNCALL IS ':CLOSE ':RAW))))		;Avoid searching for EOF
						;This should not normally be done.
  T)

(DEFUN COPY-INSERTING-CR-EVERY-N (N FROM TO)
  (WITH-OPEN-FILE (OS TO ':OUT)
    (WITH-OPEN-FILE (IS FROM ':IN)
      (DO ((CH T))
	  ((NULL CH))
	(DOTIMES (C N)
	  (SETQ CH  (FUNCALL IS ':TYI))
	  (IF CH (FUNCALL OS ':TYO CH)))
	(FUNCALL OS ':TYO #\CR)))))

(DEFUN PRINT-ASCII-MAGTAPE (&REST OPTIONS)
  (LET ((IS (LEXPR-FUNCALL #'MAKE-MT-STREAM OPTIONS)))
    (UNWIND-PROTECT
      (do ((ch (funcall is ':tyi) (funcall is ':tyi)))
	  ((null ch))
	(setq ch (ascii-to-lispm ch))
	(if ch (funcall standard-output ':tyo ch)))
      (FUNCALL IS ':CLOSE ':RAW)))		;Avoid searching for EOF
						;This should not normally be done.
  T)

(DEFUN WRITE-ASCII-MAGTAPE (FN &REST OPTIONS)
  (LET ((IS (OPEN FN))
	(OS (LEXPR-FUNCALL #'MAKE-MT-STREAM ':DIRECTION ':OUTPUT OPTIONS)))
    (DO ((CH (FUNCALL IS ':TYI) (FUNCALL IS ':TYI)))
	((NULL CH)
	 (FUNCALL OS ':CLOSE)
	 (FUNCALL IS ':CLOSE))
      (SETQ CH (LISPM-TO-ASCII CH))
      (FUNCALL OS ':TYO CH))))

(defun read-eof-file (&AUX in-stream)
  (setq in-stream (lexpr-funcall #'MAKE-MT-STREAM ':ERROR NIL))
  (funcall in-stream ':NEXT-FILE)
  (funcall in-stream ':CLOSE ':RAW))
