; DISK DIRECTORY AND BACKUP PROGRAM
;COPYRIGHT 1980, G. YOUNG, INC.'
;UPDATED 02/06/83
* THE PRIMARY PURPOSE OF THIS PROGRAM IS TO BACKUP HARD DISKS ON TO
* MULTIPLE FLOPPIES.  FIRST, IT EXTRACTS THE DIRECTORIES FROM ALL OF
* THE HARD DISKS, SORTS BY TYPE AND FILE NAME, AND PRINTS A CONSOLIDATED
* DIRECTORY.  THEN IT DELETES DUPLICATE FILES FROM THE CONSOLIDATED
* DIRECTORY, DELETES UNWANTED TYPES (PRN, BAK, ETC), AND UNWANTED
* FILES TO CREATE A LIST OF FILES TO BACKUP.  THESE ARE COPIED TO
* MULTIPLE FLOPPIES AS NEEDED WHILE PRODUCING AN INDEX OF WHAT FILES ARE
* ON EACH DISKETTE.  RESTART CAPABILITY IS PROVIDED TO BEGIN THE BACKUP
* AT ANY FILE.
* RESTART CAPABILITY ADDED 6/20
* TO RESTART, ENTER A FILE NAME, I.E. A>BACKUP LOAD.COM
* 10/1 ADDED A MORE EFFICIENT SHELL/METZER SORT WHICH DECREASED THE
* SORT TIME FROM 2 MINUTES TO 2 SECONDS
* 10/9/82 ADDED QUESTIONS TO MAKE IT MORE GENERAL PURPOSE

* WRITTEN BY GARY YOUNG, BOX 3218, NO. HOLLYWOOD, CA 91609

	TITLE	'*** HARD DISK BACKUP PROGRAM ***'
	ORG	100H
	JMP	START
	DB	'COPYRIGHT 1980, G. YOUNG, INC.'
TRUE	EQU	0FFH
FALSE	EQU	0
CLOCK	EQU	TRUE
DEBUG	EQU	FALSE
RECSIZE	EQU	12		;RECORD SIZE AS FOLLOWS
				; TYPE   = 3 BYTES
				; FILE	 = 8 BYTES
				; DISKID = 1 BYTES
IDSIZE		EQU	1	;ID NOW MEANS A:, B:, C:, ETC
LINESPAGE	EQU	60	;LINES PER PAGE
RECLINE		EQU	4	;ENTRIES PER LINE
START	LXI	SP,STACK+80
	LXI	H,RAM		;SET UP TABLE ADDRESS
	SHLD	TABADDR
	LXI	H,0000H
	SHLD	TABCNT
	XRA	A		;THE TABLE REFERS TO THE REMAINING AREA
	STA	ABORT		;OF RAM TO HOLD AS MANY DIRECTORY ENTRIES
	STA	EOF		;AS POSSIBLE
	LXI	D,SIGNON	;PRINT SIGNON MESSAGE
	CALL	OUTPUT
	LXI	H,5DH		;SAVE THE FILE NAME FOR RESTARTING
	LXI	D,RESTART
	MVI	B,32
	CALL	MOVE
	IF	CLOCK
	CALL	GETDATE
	LXI	H,DATETIME+1
	ELSE
MSG1	LXI	D,DATEMSG	;GET CURRENT DATE FOR REPORTS
 	CALL	QUESTION	;PRINT MSG AND GET REPLY
 	CPI	8		;8 CHAR MUST HAVE BEEN ENTERED
 	JNZ	MSG1		;REPEAT QUESTION IF NOT
 	LXI	H,INREC		;MOVE DATE FROM INREC
	ENDIF
	MVI	B,8		;MOVE THE DATE TO A HOLD AREA
	LXI	D,DATE		;TO "DATE"
	CALL	MOVE
	LXI	D,DESTMSG	;GET DESTINATION DRIVES
	CALL	QUESTION
	ORA	A
	JZ	LOGICQUS	;DEFAULT
	LDA	INREC
	STA	BACKUPDRV
LOGICQUS LDA	NODRV
	LXI	H,DRIVES	;FORMAT THE QUESTION FOR WHICH DRIVES TO 
SHIFT1	INX	H		;(HARD DISK DRIVES) TO BACKUP
	DCR	A
	JNZ	SHIFT1
	MVI	M,')'
	INX	H
	MVI	M,20H
	INX	H
	MVI	M,'$'
	LXI	D,HD2BU
	CALL	QUESTION
	ORA	A
	JZ	GETTYPEQUS
	STA	NODRV
	MOV	B,A		;NO ERROR CHECKING IS DONE ON THE DATA
	LXI	H,INREC
	LXI	D,DRIVES	;SO IF YOU PUT IN DRIVE Z, IT WILL CRASH
	CALL	MOVE		;BUT YOU WOULD NOT BE THAT STUPID???
GETTYPEQUS LDA	NOSKIP
	MOV	B,A
	ADD	A		;MULTIPLY BY 3
	ADD	B
	LXI	H,SKIPTYPE
SHIFT2	INX	H
	DCR	A
	JNZ	SHIFT2
	MVI	M,')'
	INX	H
	MVI	M,20H		;FORMAT TYPE TO SKIP QUESTION
	INX	H
	MVI	M,'$'
	LXI	D,SKPMSG
	CALL	QUESTION
	ORA	A
	JZ	DEFAULTTYPE
	STA	NOSKIP
	LXI	H,INREC
	LXI	D,SKIPTYPE
	MOV	B,A
	CALL	MOVE
	LDA	NOSKIP
	MVI	B,0
DIVBY3	INR	B
	DCR	A
	JZ	CNTTYPE
	DCR	A
	JZ	CNTTYPE
	DCR	A
	JNZ	DIVBY3		;CONVERT BYTE COUNT TO TYPE COUNT
CNTTYPE	MOV	A,B
	STA	NOSKIP
DEFAULTTYPE
	CALL	EXTRACT		;GET DIRECTORY ENTRIES
	LDA	ABORT		;SEE IF TOO MANY ENTRIES FOR MEMORY SIZE
	ORA	A		;SHOULD BE ZERO TO BE OK
	JZ	NOMORE
	LXI	D,TABFULL	;REPORT WILL NOT BE COMPLETE
	CALL	OUTPUT		;MEMORY FULL ERROR
NOMORE	CALL	SORT		;SORT THE MEMORY TABLE BY TYPE, FILE
				;NAME, THEN DISK ID
	MVI	A,RECSIZE	;SETUP TO REMOVE DUPLICATE ENTRIES
	STA	COMPSIZE	;COMPARE ON ALL CHAR
	CALL	KILLDUPS	;REMOVE DUPLICATE ENTRIES
	LDA	RESTART
	CPI	20H
	CZ  	REPORT		;PRINT ALL ENTRIES
	MVI	A,11		;REMOVE FILES THAT ARE ON MULTIPLE DISKS
	STA	COMPSIZE
	CALL	KILLDUPS
	LDA	RESTART
	CPI	20H
	CNZ	POSITION	;POSITION LIST FOR A RESTART
	CALL	SELECT		;RESTRICT THE FILES TO BACKUP
MSG3	LXI	D,BACKQUS	;ASK IF YOU WANT BACKUP FUNCTION
	CALL	QUESTION
	CPI	1
	JNZ	MSG3
	LDA	INREC
	CPI	'N'
	JZ	FINISHED
	CPI	'Y'
	JNZ	MSG3
	CALL	BACKUP		;BACKUP THOSE FILES REPORTED ON
FINISHED	MVI	C,0
	JMP	BDOS		;RESET AND RETURN TO CPM
*
* THE EXTRACT ROUTINE SCANS ALL THE DRIVES IN THE DRIVE TABLE
* WHEN COMPLETE, IT ASKS FOR THE NEXT DRIVE ID
* WHEN THE HARD DISK IS UP, IT WILL NOT ASK FOR THE DRIVE ID BUT
* WILL AUTOMATICALLY SCAN THE THREE HARD DISKS AND FINISH WITHOUT
* EVER ASKING FOR THE DRIVE ID.
*
* THE DUMMYFCB SETS UP A SKELETON TO READ ALL FILES ON THE DIRECTORY
*
DUMMYFCB	DB	0,'????????????',0,0,0,0,0,0,0,0,0
		DB	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
EXTRACT LXI	D,EXTRMSG
	CALL	OUTPUT
       	LXI	H,DRIVES	;GET ADDRESS OF THE DRIVE TABLE
	SHLD	ADDR1		;TO SCAN
	LDA	NODRV    	;SET UP COUNTER FOR THE NUMBER TO SCAN
	INR	A
	STA	MAX1
NEXTDRV	LDA	MAX1		;SEE IF THERE ARE MORE DRIVES TO SCAN
	DCR	A
	STA	MAX1		;RETURN WHEN ALL HAVE BEEN SCANNED
	RZ
	LHLD	ADDR1		;GET ADDRESS OF DRIVE TABLE
	MOV	A,M		;GET DRIVE CHARACTER
	STA	RDISK
	ANI	0FH		;CONVERT A=1...P=15
	STA	DUMMYFCB	;SET IN DR OF DUMMYFCB
	INX	H		;SET FOR NEXT READ OF DRIVE TABLE
	SHLD	ADDR1
	LXI	D,DISKBUF	;SET A DMA ADDRESS FOR DIRECTORY ENTRIES
	MVI	C,1AH
	CALL	BDOS		;SET DMA
	LXI	D,DUMMYFCB	;GET FIRST DIRECTORY ENTRY
	MVI	C,11H
	CALL	BDOS		;GET DIRECTORY
	INR	A
	JZ	NEXTDRV		;NO MORE ENTRIES ON THIS DRIVE
	JMP	GETFCB		;EXTRACT DATA FROM FCB
NEXTFCB	LXI	D,DUMMYFCB	;GET NEXT ENTRY AFTER THE FIRST
	MVI	C,12H
	CALL	BDOS
	INR	A
	JZ	NEXTDRV		;NO MORE DIRECTORIES ON THIS DISK
GETFCB	LXI	D,32		;EACH ENTRY IS 32 BYTES LONG
	LXI	H,DISKBUF	;DIRECTORY RECORD IS IN DISKBUF
	CPI	1		;FIRST ENTRY IN RECORD???
	JZ	FORMREC		;YES
	DAD	D		;ADD 32 TO ADDRESS IN RECORD
	CPI	2		;SECOND ENTRY IN RECORD???
	JZ	FORMREC
	DAD	D		;ADD 64 TO ADDRESS OF RECORD
	CPI	3		;THIRD ENTRY IN RECORD???
	JZ	FORMREC
	DAD	D		;ADD 96 TO ADDRESS OF RECORD
FORMREC	INX	H		;PASS DRIVE BYTE
	LXI	D,RFILE		;MOVE FILE NAME
	MVI	B,8		;MOVE 8 CHARACTERS
	CALL	MOVE
	LXI	D,8		;POSITION PAST NAME TO TYPE
	DAD	D
	LXI	D,RTYPE		;MOVE TYPE
	MVI	B,3		;MOVE 3 CHARACTERS
	CALL	MOVE
	INX	H		;POSITION TO THE EXTENT NUMBER
	INX	H
	INX	H
	MOV	A,M		;GET THE EXTENT
	IF	DEBUG
 	ORI	30H		;DIAGNOSTIC DISPLAY
 	STA	RDISK+1
 	LXI	D,RTYPE
 	CALL	OUTPUT
 	LDA	RDISK+1
 	ANI	0FH
	ENDIF
	LXI	H,RTYPE		;STRIP OFF THE HIGH BIT SET BY
	MVI	B,11		;THE VERSION PROGRAM
STRIP	MOV	A,M
	ANI	07FH
	MOV	M,A
	INX	H
	DCR	B
	JNZ	STRIP
	LXI	H,RTYPE		;SKIP OVER JUNK DISK ENTRIES
	MVI	B,11		;CONTAINING NONPRINTING CHARACTERS
NONPRNT MOV	A,M
	CPI	20H		;ANY CHAR LESS THAN A BLANK
	JC	NEXTFCB		;GO TO NEXT ONE IF SO
	INX	H
	DCR	B
	JNZ	NONPRNT
FIRSTEXT	EQU	$	;GOT THE FIRST EXTENT
	LHLD	TABADDR		;GET MEMORY TABLE ADDRESS
	LXI	D,RTYPE		;GET MEMORY RECORD ADDRESS
	XCHG			;RTYPE (HL) TO TABADDR (DE)
	MVI	B,RECSIZE	;MOVE RECSIZE BYTES
	CALL	MOVE
	LHLD	TABADDR		;INCREMENT FOR NEXT ENTRY
	LXI	D,RECSIZE		;RECSIZE BYTES IN RECORD
	DAD	D
	SHLD	TABADDR		;SAVE NEW ADDRESS
	MVI	M,1AH		;SET AN END-OF-TABLE INDICATOR
	LHLD	TABCNT		;GET RECORD COUNT
	INX	H
	SHLD	TABCNT		;INCREMENT RECORD COUNT
	LHLD	TABADDR		;SEE IF NEW ADDRESS IS GREATER
	XCHG			;THAN THE TOP OF TPA-128
	LHLD	BDOS+1		;HL=TOP...DE=TABLE+RECSIZE
	LXI	B,-128
	DAD	B		;SUBTRACT 128 FROM TOP
	CALL	COMPREG		;COMPARE REGISTER VALUES
	JNC	NEXTFCB		;THERE IS ROOM FOR MORE
	MVI	A,1		;NO MORE ROOM...ABORT NOW
	STA	ABORT
	RET


;THIS ROUTINE IS USED TO POSITION THE LIST OF FILES FOR A RESTART

POSITION LXI	D,POSMSG
	CALL	OUTPUT
        LXI	H,RESTART+8	;CONVERT FILE NAME TO TYP.FILENAME
	LXI	D,REPO
	MVI	B,3
	CALL	MOVE
	LXI	H,RESTART
	LXI	D,REPO+3
	MVI	B,8
	CALL	MOVE
	LXI	H,RAM-RECSIZE	;SETUP FOR COMPARES
	SHLD	ADDR1
NE1	LHLD	ADDR1
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR1
CNXT	MOV	A,M
	CPI	1AH		;EOF ON LIST?
	JZ	LBU
	LHLD	ADDR1
	LXI	D,REPO
	MVI	B,11
	CALL	COMPARE
	JZ	LBU
	LHLD	ADDR1
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR2
	CALL	MOVELIST	;TABLE MOVES DOWN SO ADDR1 IS NOT INCREMENTED
	LHLD	ADDR1
	JMP	CNXT
LBU	SHLD	ADDR2
	RET


SORT	LXI	D,SORTMSG	;PUT OUT A MESSAGE SO THE USER DOES
	CALL	OUTPUT		;NOT THINK THIS CRASHED WHILE SORTING
	LHLD	TABCNT
	SHLD	N1
	SHLD	M1
	LXI	H,RECSIZE
	SHLD	K1  
	LXI	H,RAM
	SHLD	J1
	CALL	SHELLM
      	RET			;FINISHED SORTING

;TITLE	'IN MEMORY SHELL-metzner sort'
;sbttl	'from KILOBAUD april 1981 p164'
;
;remark	'For fixed length records stored in memory
;Put no. of records in n1 and m1. The length
;of each record is stored at k1, and the starting
;address at j1. Start sort by calling location
;"entry". To change to descending sort change the
;instruction at neq: to DAH.'
;
n1:	DW   	0	; number of records
m1:	DW   	0	; ..same here
k1:	DW   	0	; length of records
j1:	DW   	0	; starting address of strings
i1:	DW   	0	; ptr
ml1:	DW   	0	; ptr
dj1:	DW   	0	; ptr
di1:	DW   	0	;ptr
;
SHELLM	lhld	j1	; get start address
	push	h	; ..save
	lhld	k1	; get length
	push	h	; ..it too
div:	xra	a	; m1=m1/2
	lhld	m1
	mov	a,h
	rar
	mov	h,a
	mov	a,l
	rar
	mov	l,a
	shld	m1	; save new m1
;
	ora	h	; check if done
	jnz	ndon
	pop	b	; finished
	pop	d	; ..so return
	ret		; ...now
;
;	set k1=n1-m1
;
ndon:	xchg		; m1 to de
	lhld	n1
	mov	a,l
	sub	e
	mov	l,a
	mov	a,h
	sbb	d
	mov	h,a
	shld	k1
	lxi	h,1	; set and save i=j=1
	shld	j1
	shld	i1
;
;	calc & save addr offset = m1*i1
;
	dcr	l
	pop	b	; length of str=i1
	push	b	; ..put it back
lp1:	dad	d
	dcx	b
	mov	a,b
	ora	c
	jnz	lp1
	shld	ml1
;
	xchg		; calc & save d(j), d(i), d(i+m)
	pop	b
	pop	h
	push	h
	push	b
lp2:	shld	dj1
	shld	di1
	xchg
	dad	d
	xchg		; HL has d(i), DE has d(i+m)
;
;	compare strings and switch
;
cp1:	pop	b	; len of string=l1
	push	b
lp3:	ldax	d	; compare each byte
	sub	m
	jnz	neq	; not equal
	inx	h	; if =, then next byte
	inx	d
	dcx	b
	mov	a,b
	ora	c
	jnz	lp3
	jmp	nsw	; if done, don't switch
;
;	change next instruction to jc for descending
;
neq:	jnc	nsw	; if d(i)<d(i+m) don't switch
;
sw:	push	b	; switch bytes not equal
	mov	b,m
	ldax	d
	mov	m,a
	mov	a,b
	stax	d
	inx	h
	inx	d
	pop	b
	dcx	b
	mov	a,b
	ora	c
	jnz	sw
;
;	strings switched, chk if i1-m1 < 1
;
	lhld	m1
	mov	a,h
	cma
	mov	d,a
	mov	a,l
	cma	
	mov	e,a
	lhld	i1
	dad	d	; if i1-m1<1 then jump to same as
			; ..no switch
	jnc	nsw
;
;	calc new d(i), d(i+m)
;
	inx	h	; save	new i1=i1-m
	shld	i1
	lhld	di1	; old d(i)=new d(i+m)
	xchg
	lhld	ml1	; address offset
	mov	a,e	; new d(i)=old d(i)-offset
	sub	l
	mov	l,a
	mov	a,d
	sbb	h
	mov	h,a
	shld	di1	; save new d(i)
	jmp	cp1	; goto compare strings
;
;	check for j>k
;
nsw:	lhld	j1
	inx	h	; save new j=old j+1
	shld	j1
	shld	i1
	xchg
	lhld	k1
	mov	a,l
	sub	e
	mov	a,h
	sbb	d
	jc	div	; if j>k goto beginning and
			; ..divide m1
;
;	calc new d(j), d(i)
;
	lhld	dj1
	pop	d
	push	d
	dad	d	; new d(j)=old d(j+1)
	xchg
	lhld	ml1
	xchg
	jmp	lp2
;
; that all folks
;


* REPORT PRINTS THE SORTED CONSOLIDATED DIRECTORY ENTRIES.  
* LINESPAGE IS THE NUMBER OF LINES PER PAGE AND RECLINE IS THE
* NUMBER OF 20 BYTE ENTRIES PER LINE.  EACH TYPE BEGINS ON A 
* NEW PAGE.

REPORT	LXI	D,RPTMSG
	CALL	OUTPUT
      	LHLD	TABCNT		;SET COUNT OF ENTRIES
	INX	H		;PLUS ONE
	SHLD	LASTTYPE	;INIT LASTTYPE TO INVALID DATA
	SHLD	MAX1		;TO DECREMENT FIRST
	LXI	H,RAM-RECSIZE	;SET STARTING ADDRESS
	SHLD	ADDR1
	CALL	HEADING
NEXTPRT	LHLD	ADDR1
	LXI	D,RECSIZE	;SET TO ADD THE REC LENGTH
	DAD	D
	SHLD	ADDR1
	LHLD	MAX1		;DECREMENT COUNT TO SEE WHEN DONE
	DCX	H
	SHLD	MAX1
	LXI	D,0000		;SEE IF REACHED ZERO YET
	CALL	COMPREG
	JZ	TOPPAGE		;GO TO TOP OF NEXT PAGE
	LHLD	ADDR1		;CURRENT TYPE = LAST TYPE?
	MVI	B,3		;COMPARE 3 CHARACTERS
	LXI	D,LASTTYPE
	CALL	COMPARE
	JNZ	SKIP3		;NEW TYPE ON NEW PAGE
PRNTNOW	LDA	MAX2		;DECREMENT RECORDS PER LINE
	DCR	A
	STA	MAX2
	JZ	NEWLINE		;LINE FULL, GO TO NEW LINE
	CALL	FORMAT
	LXI	D,PRNTREC
	CALL	LIST
	JMP	NEXTPRT
SKIP3	LDA	LINECNT
	DCR	A
	JZ	NEWPAGE
	DCR	A
	JZ	NEWPAGE
	DCR	A
	JZ	NEWPAGE
	STA	LINECNT
	LXI	D,CRLFLFLF
	CALL	LIST
	JMP	CHKTYPE
NEWPAGE	CALL	HEADING
CHKTYPE	LXI	D,LASTTYPE	;SET LAST TYPE TO CURRENT TYPE
	LHLD	ADDR1
	MVI	B,3
	CALL	MOVE
SETCNT	MVI	A,RECLINE+1
	STA	MAX2
	JMP	PRNTNOW
NEWLINE	LXI	D,CRLF
	CALL	LIST
	LDA	LINECNT
	DCR	A
	STA	LINECNT
	JZ	NEWPAGE		;PAGE FULL
	JMP	SETCNT
TOPPAGE	RET

 
* THE PURPOSE OF SELECT IS TO CREATE A FINAL LIST OF FILES TO
* BACKUP.  SINCE BACKING UP 26 MEG CAN BE QUITE LONG, THIS REDUCES
* THE LIST TO ONLY NECCESSARY FILES.   IT ALSO ALLOWS A RESTART
* AT ANY FILE.  IT WILL DELETE DUPLICATE FILE NAMES (FILES ON A:
* WILL BE USED SINCE THAT IS ASSUMED TO BE THE LATEST), AND
* WILL DELETE THE FILE TYPES LISTED IN THE SKIP TABLE.  THEN IT
* WILL LIST EACH TYPE AND ASK IF YOU DO WANT TO BACK UP ALL OF
* THIS TYPE (Y), SKIP BACKING UP OF THE ENTIRE TYPE (N), OR
* SELECT CERTAIN FILES (S) TO BACK UP.  IF THE SELECT OPTION IS
* CHOSEN, EACH FILE NAME WILL BE PRINTED AND YOU BE ASKED TO
* BACK UP THE FILE (Y), IGNORE THE FILE DURING THE BACKUP
* (N), OR CONTINUE (C) TO BACKUP ALL OF THE REMAINING FILES
* WITHIN THIS TYPE WITHOUT ASKING ANY FURTHER NAMES (USED FOR 
* RESTART).  AFTER THE LIST HAS BEEN REDUCED, IT WILL BE LISTED
* BEFORE THE BACKUP ACTUALLY BEGINS.
 
KILLDUPS EQU	$	;KILL DUPLICATE ENTRIES FROM MULTIPLE EXTENTS
	LXI	D,KILLMSG
	CALL	OUTPUT
	LXI	H,RAM
	SHLD	ADDR1			;SET THE START OF THE TABLE
NEXTEQUAL	LHLD	ADDR1		;CHECK EACH ENTRY AGAINST THE NEXT
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR2
NEXTCHK	MOV	A,M			;CHECK FOR END OF TABLE
	CPI	1AH
	RZ
	XCHG
	LHLD	ADDR1			;COMPARE ADDR1 WITH ADDR2
	LDA	COMPSIZE
	MOV	B,A
	CALL	COMPARE
	JNZ	SAVELAST
	PUSH	H			;SAVE CURRENT POSITION
	LHLD	ADDR2			;SET UP FOR MOVING LIST
	SHLD	ADDR1			;DOWN ONE ENTRY
	LXI	D,RECSIZE
	DAD	D			;MOVE THIRD ENTRY TO THE SECOND
	SHLD	ADDR2
	CALL	MOVELIST
	LHLD	TABCNT
	DCX	H
	SHLD	TABCNT
	POP	H			;RESTORE CURRENT POSITION
	SHLD	ADDR1			;NOW COMPARE 1ST & 3RD
	JMP	NEXTEQUAL
SAVELAST	LHLD	ADDR2		;MAKE NEW ONE THE CURRENT ONE
	SHLD	ADDR1
	JMP	NEXTEQUAL		;COMPARE

SELECT	EQU	$
NOWSELECT	EQU	$		;LET USER ELIMINATE SOME
	LXI	H,RAM-RECSIZE		;INITIALIZE
	SHLD	ADDR1
	SHLD	LASTTYPE		;MAKE SURE LASTTYPE DOES NOT MATCH
NEXTENTRY	LHLD	ADDR1		;GET NEXT RECORD IN TABLE
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR1			;INCREMENT TABLE ENTRY
CHKNEXT	MOV	A,M			;CHECK FOR THE END OF THE TABLE
	CPI	1AH			;CNTL-Z IS AT END
	JZ	LISTBKUP		;LIST THE FINAL TABLE
	LXI	D,LASTTYPE		;SEE IF THE CURRENT TYPE IS THE
	LHLD	ADDR1			;LAST TYPE
	MVI	B,3
	CALL	COMPARE
	JZ	CHKSELECT		;TYPES MATCH, CHECK FILE SELECT
	CALL	MOVE			;TYPES DON'T MATCH, MAKE THE
					;LAST TYPE = CURRENT TYPE NOW
	LDA	NOSKIP
	INR	A
	MOV	C,A         		;SEE IF THE NEW TYPE IS IN THE
	LXI	D,SKIPTYPE		;LIST OF FILE TYPES TO SKIP
	MVI	B,3
NEXTSKIP	DCR	C		;DECREMENT NO OF FILES TO SKIP
	JZ	FORMQUS			;FILE IS GOOD
	LHLD	ADDR1
	CALL	COMPARE
	JZ	SKIPALLTYPE		;FILE WAS ON THE SKIP LIST
	INX	D			;INCREMENT TO NEXT SKIP FILE
	INX	D
	INX	D
	JMP	NEXTSKIP
FORMQUS	LXI	D,QTYPE			;FORM THE QUESTION ABOUT WHETHER
	LHLD	ADDR1			;TO SKIP THIS FILE TYPE OR NOT
	MVI	B,3			;MOVE THE FILE TYPE TO THE 
	CALL	MOVE			;QUESTION PRINT LINE
	XRA	A
	STA	SELFLAG			;RESET THE SELECT FLAG
REASK1	LXI	D,QUEST1
	CALL	QUESTION		;ASK THE QUESTION ABOUT THE TYPE
	CPI	1			;ONE CHARACTER RESPONSE ALLOWED
	JNZ	REASK1
	LDA	INREC			;GET THE RESPONSE
	CPI	'N'
	JZ	SKIPALLTYPE
	CPI	'Y'
	JZ	SAVEALLTYPE
	CPI	'S'			;S=SELECT CERTAIN FILES FROM THIS
	JNZ	REASK1			;TYPE
	MVI	A,1			;SET THE SELECT FLAG
	STA	SELFLAG			;TO ASK THE NEXT QUESTION
ASKFILE	LHLD	ADDR1			;FORMAT A QUESTION TO ASK IF THIS
	LXI	D,QTYPE2		;PARTICULAR FILE IS TO BE SAVED
	MVI	B,3
	CALL	MOVE
	LXI	D,QFILE2		;MOVE THE FILE NAME TO THE QUESTION
	INX	H
	INX	H			;POSITION PAST THE FILE TYPE
	INX	H			;IN THE TABLE
	MVI	B,8
	CALL	MOVE			;MOVE THE NAME
	LXI	D,8			;POSITION PAST NAME TO THE
	DAD	D			;DISK ID
	LXI	D,QDISK2		;MOVE THE DISK ID
	MVI	B,IDSIZE
	CALL	MOVE	
REASK2	LXI	D,QUEST2		;ASK THE FILE QUESTION
	CALL	QUESTION
	CPI	1			;ONLY A 1 CHAR RESPONSE ALLOWED
	LDA	INREC
	JNZ	REASK2
	CPI	'C'			;CONTINUE WITH THE REST OF THE
	JZ	SAVEALLTYPE		;FILES WITHIN THIS TYPE - RESTART
	CPI	'Y'			;SAVE THIS PARTICULAR FILE
	JZ	NEXTENTRY
	CPI	'N'
	JNZ	REASK2
	LHLD	ADDR1			;SHORTEN THE LIST BY ONE ENTRY
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR2			;SKIP THE LAST ONE
	CALL	MOVELIST		;MOVES THE LIST DOWN FROM ADDR1
					;TO ADDR2
	LHLD	ADDR1
	JMP	CHKNEXT			;CHECK NEXT ENTRY
CHKSELECT	LDA	SELFLAG		;CHECK THE SELECT FLAG
	ORA	A			;IF NOT ZERO, ASK THE QUESTION
	JNZ	ASKFILE			;ABOUT EACH FILE
	JMP	NEXTENTRY
SKIPALLTYPE	CALL	FINDTYPE	;FIND THE NEXT TYPE NOT MATCHING
	CALL	MOVELIST		;THIS ONE AND MOVE THE LIST DOWN
	LHLD	ADDR1
	JMP	CHKNEXT			;TO SKIP THIS TYPE
SAVEALLTYPE	CALL	FINDTYPE	;SAVE ALL OF THIS TYPE
	LHLD	ADDR2			;RESET THE ADDRESS TO THE NEXT
	SHLD	ADDR1			;TYPE
	JMP	CHKNEXT
MOVELIST	LHLD	ADDR2		;MOVE THE TABLE FROM ADDR2 DOWN
	XCHG				;TO ADDR1 THEREBY ELIMINATING
	LHLD	ADDR1			;UNWANTED ENTRIES
MOVENEXT	LDAX	D		;AND MAKING MORE ROOM FOR THE
	MOV	M,A
	CPI	1AH
	RZ
	INX	H
	INX	D
	JMP	MOVENEXT
FINDTYPE	LHLD	ADDR1		;FIND THE NEXT ENTRY
	SHLD	ADDR2			;WITH A TYPE DIFFERENT
FINDIT	LHLD	ADDR2			;THAN THE CURRENT TYPE
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR2
	MOV	A,M			;STOP AT END OF THE TABLE
	CPI	1AH
	RZ
	XCHG
	LHLD	ADDR1
	MVI	B,3
	CALL	COMPARE
	RNZ
	JMP	FINDIT			;ADDR2 WILL HAVE THE ADDRESS OF
					;THE NEXT TYPE WHEN FINISHED
LISTBKUP	EQU	$		;LIST THE FILES TO BE BACKED
	SHLD	ADDR2			;SAVE THE END OF THE TABLE FOR LATER
	LXI	H,RAM-RECSIZE
	SHLD	ADDR1
	IF	DEBUG			;PRINT LIST ONLY IF DEBUGGING
	CALL	HEADING2
NEXTONE	LHLD	ADDR1			;PRINT THE NEXT TABLE ENTRY
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR1			;INCREMENT TO THE NEXT ENTRY
	MOV	A,M			;CHECK FOR THE END OF THE
	CPI	1AH			;TABLE
	RZ
	CALL	FORMAT			;FORMAT ENTRY
	LXI	D,PRNTREC
	CALL	LIST			;PRINT IT
	LDA	MAX2			;SEE MORE WILL FIT ON THIS LINE
	DCR	A
	STA	MAX2
	JZ	LINEFULL
	JMP	NEXTONE
LINEFULL	LXI	D,CRLF
	CALL	LIST
	LDA	LINECNT
	DCR	A
	STA	LINECNT
	JZ	PAGEFULL
	JMP	SETLINE
PAGEFULL	CALL	HEADING2
	MVI	A,LINESPAGE
	STA	LINECNT
SETLINE	MVI	A,RECLINE
	STA	MAX2
	JMP	NEXTONE
HEADING2	LXI	D,HEAD2
	CALL	LIST
	LXI	D,CRLF
	CALL	LIST
	MVI	A,LINESPAGE
	STA	LINECNT
	MVI	A,RECLINE
	STA	MAX2
	ENDIF
	RET



* BACKUP IS USED TO BACKUP THE FILES IN THE CREATED LIST.  IT
* WILL NOT BACK UP ANY FILE THAT WILL NOT FIT ON ONE DISK ENTIRELY.
* THE FILES THAT IT BACKS UP WILL COME FROM ANY OF THE HARD DISKS,
* BUT NOT NECCESSARILY IN DISK ORDER, BUT RATHER ALPHABETICAL FILE
* NAME ORDER.  IT WILL PROMPT FOR THE FLOPPY DISK ID AND PRINT A 
* REPORT SHOWING THE FLOPPY ID AND THE FILES COPIED FOR INDEX.
* IF THE FILE WILL NOT FIT ON A DISK, IT WILL BE DELETED FROM THE
* DISK, THAT DISK CLOSED AND REMOVED, AND PROMPTED FOR A NEW DISK
* TO RECEIVE THE FILE.  BLANK 1024 BYTE SECTORED DISKS SHOULD BE
* USED FOR BEST PERFORMANCE.  WHEN ONE DISKETTE IS FULL, IT WILL
* PROMPT FOR A NEW ONE SO MANY DISKETTES CAN BE USED TO BACKUP
* THE HARD DISKS.  IF IT IS NECESSARY TO ABORT DURING THIS PROCESS,
* USE THE RESTART CAPABILITY PROVIDED IN "SELECT".  THE AREA
* FOR THE DISK BUFFER IS ALL OF RAM FROM THE END OF THE TABLE
* TO THE START OF BDOS.

BACKUP	EQU	$
	CALL TOPOFFORM
	LHLD	ADDR2		;GET THE CURRENT END OF TABLE
	INX	H		;PLUS ONE FOR THE START OF THE
	SHLD	ADDR3		;READ/WRITE BUFFER
	LXI	H,RAM		;SET THE ADDRESS OF THE FIRST ENTRY
	SHLD	ADDR1
	LXI	D,RECSIZE	;SET AN ADDRESS FOR THE SECOND ENTRY
	DAD	D		;NEXT ENTRY = CURRENT + RECSIZE
	SHLD	ADDR2		;LATER, USE MOVELIST TO MOVE THE LIST
				;DOWN FROM ADDR2 TO ADDR1 AFTER EACH FILE
				;HAS BEEN COPIED.  THIS IS SO THAT THE
				;RAM BUFFER WILL EXPAND AS THE FILES ARE
				;COPIED SO THAT COPYING WILL BE FASTER.
	CALL	MOUNT
	JMP	PASSMOVE
NEXTFILE	EQU	$
	CALL	MOVELIST
	INX	H		;NEW START OF READ/WRITE BUFFER
	SHLD	ADDR3
	XRA	A		;RESET THE FLAG FOR FILES TOO BIG
	STA	TOOBIG		;TO FIT ON ONE FLOPPY
PASSMOVE	LXI	H,RAM	;THE TABLE SHRINKS SO THE CURRENT 
				;ENTRY IS ALWAYS AT "RAM" BUT THE
				;READ/WRITE BUFFER GROWS
	MOV	A,M
	CPI	1AH
	JZ	DISMOUNT	;FINISHED
FORMFCB	LXI	D,HDFCB		;CLEAR THE FCB
	MVI	B,36
	XRA	A
ZEROFCB	STAX	D
	INX	D
	DCR	B
	JNZ	ZEROFCB
	LXI	H,RAM		;GET ADDRESS OF TABLE ENTRY
	LXI	D,HDTYPE	;MOVE IN THE TYPE
	MVI	B,3
	CALL	MOVE
	INX	H
	INX	H		;POSITION TO NAME
	INX	H
	LXI	D,HDFILE	;MOVE THE FILE NAME
	MVI	B,8
	CALL	MOVE
	LXI	D,8
	DAD	D		;POSITION TO DISK ID, A:, B: ETC
	MOV	A,M
	ANI	0FH		;CONVERT A=1...P=15
	STA	HDFCB
	LXI	D,FPFCB		;COPY THE HDFCB TO THE FLOPPY FCB
	LXI	H,HDFCB
	MVI	B,36
	CALL	MOVE
	LDA	BACKUPDRV	;SET THE RECEIVING FLOPPY DRIVE NUMBER
	ANI	0FH		;CONVERT D: TO 4
	STA	FPFCB
	LXI	D,HDFCB		;OPEN THE HD FILE
	MVI	C,0FH
	CALL	BDOS		;OPEN THE INPUT FILE
	INR	A
	JZ	NOTFOUND
	LXI	D,FPFCB		;DELETE THE FILE ON FLOPPY IF IT
	MVI	C,13H		;EXISTS
	CALL	BDOS
	LXI	D,FPFCB		;CREATE THE FILE ON FLOPPY 
	MVI	C,16H
	CALL	BDOS		;MAKE FILE
	INR	A
	JZ	DISKFULL
	LXI	H,RAM
	CALL	FORMAT
	LXI	D,PRNTREC
	CALL	OUTPUT
COPYLOOP	CALL	LOADBUFF	;LOAD MEMORY WITH FILE
	CALL	WRITEBUF		;WRITE MEMORY FILE
	LDA	EOF			;DISPLAY THE STATUS
	ADI	30H
	MOV	E,A			;CONSOLE OUTPUT
	MVI	C,2
	CALL	BDOS
	LDA	EOF
	CPI	1
	JZ	ENDOFFILE
	CPI	2
	JZ	DISKFULL
	JMP	COPYLOOP
ENDOFFILE	LXI	D,FPFCB		;CLOSE FLOPPY FILE
	MVI	C,10H
	CALL	BDOS			;CLOSE
	LXI	H,RAM
	CALL	PRINTFILE	;WRITE FILE NAME ON INDEX LIST
	JMP	NEXTFILE
DISKFULL	LXI	D,FPFCB
	MVI	C,13H		;DELETE FILE ON FLOPPY
	CALL	BDOS
	MVI	C,23H		;GET FILE SIZE
	LXI	D,HDFCB
	CALL	BDOS		;SEE IF IT IS TOO BIG TO FIT ON A FLOPPY
	LDA	HDFCB+34	;GET THE HIGH ORDER BYTE OF THE FILE SIZE
	ANI	0F8H		;SEE IF THE FILE IS > 256K
	JNZ	HUGE		;YEP, TOO BIG FOR SINGLE DENSITY FLOPPY
	CALL	MOUNT		;NO, JUST MOUNT ANOTHER FLOPPY
	JMP	FORMFCB
HUGE	LXI	D,BIGMSG		;YES, SECOND FLOPPY. SEND MESSAGE
	CALL	LIST			;WARNING THAT THIS FILE CANNOT
	LXI	H,RAM
	CALL	FORMAT			;BE BACKED UP WITH THIS PROGRAM
	LXI	D,PRNTREC
	CALL	LIST			;PRINT THE FILE NAME ALSO
	JMP	NEXTFILE
NOTFOUND LXI	H,RAM
	CALL	FORMAT
	LXI	D,NFMSG
	CALL	OUTPUT
	LXI	D,PRNTREC
	CALL	OUTPUT
	RET
DISMOUNT CALL	BELL
	LXI	D,DMNTMSG	;DISMOUNT FLOPPY
	CALL	QUESTION
	CALL	TOPOFFORM
	RET



* ASSORTED ROUTINES

PRINTFILE	CALL	FORMAT
	LXI	D,PRNTREC	;PRINT THE FILE ENTRY
	CALL	LIST
	LDA	MAX2
	DCR	A
	STA	MAX2		;ENTRIES PER LINE COUNTER
	RNZ
	LXI	D,CRLF		;GO TO NEW LINE
	CALL	LIST
	MVI	A,RECLINE
	STA	MAX2
	RET

HEADING3	LXI	D,CRLFLFLF	;INDEX HEADING NOT AT TOP OF FORM
	CALL	LIST
	LXI	D,IDISKNO		;MOVE THE DISK ID NO TO HEADING
	LXI	H,VOLSER
	MVI	B,3
	CALL	MOVE
	LXI	D,IDATE
	LXI	H,DATE
	MVI	B,8
	CALL	MOVE
	LXI	D,INDEX
	CALL	LIST
	LXI	D,CRLF
	CALL	LIST
	MVI	A,RECLINE
	STA	MAX2
	MVI	A,LINESPAGE
	STA	LINECNT
	RET

TOPOFFORM	MVI	E,0CH	;POSITION PRINTER TO TOP OF FORM
	MVI	C,5
	JMP	BDOS

MOUNT	CALL	BELL
	LXI	D,MNTMSG
	CALL	QUESTION
	CPI	3
	JNZ	MOUNT
	LXI	H,INREC
	LXI	D,ENDLIT
	MVI	B,3
	CALL	COMPARE
	JZ	FINISHED
	LXI	D,VOLSER
	LXI	H,INREC
	MVI	B,3
	CALL	MOVE		;MOVE VOLSER ID TO VOLSER
	MVI	C,0DH		;DO A SYSTEM RESET TO  CHANGE DISKS
	CALL	BDOS
ERA	LXI	D,ERASE
	CALL	QUESTION
	CPI	1
	JNZ	ERA
	LDA	INREC
	CPI	'N'
	JZ	NOERA
	CPI	'Y'
	JNZ	ERA
	LDA	BACKUPDRV
	ANI	0FH
	STA	DUMMYFCB
	MVI	C,13H
	LXI	D,DUMMYFCB
	CALL	BDOS		;DELETE ALL FILES ON FLOPPY
NOERA	EQU	$
	CALL	HEADING3
	LXI	D,FPFCB		;CLEAR THE FCB TO CREATE A FILE NAME
	MVI	B,36
	XRA	A
CLRFCB	STAX	D
	INX	D
	DCR	B
	JNZ	CLRFCB
	LDA	BACKUPDRV	;SET UP THE DRIVE AS THE BACKUP
	ANI	0FH		;CONVERT D: TO 4
	STA	FPFCB
	LXI	H,DATE		;CREATE A NULL FILE WITH THE DATE AS
	LXI	D,FPFCB+1	;THE FILE NAME AND THE 3 DIGIT
	MVI	B,8
	CALL	MOVE
	LXI	H,VOLSER		;3 DIGIT VOLSER AS THE FILE TYPE
	LXI	D,FPFCB+9
	MVI	B,3		;THIS FILE WILL BE USED TO IDENTIFY
	CALL	MOVE		; THE DISK AND MARK THE DATE
	LXI	D,FPFCB
	MVI	C,16H		;CREATE THE FILE
	CALL	BDOS
	INR	A
	JZ	MOUNT		;DISK FULL?
	LXI	D,FPFCB
	MVI	C,10H		;CLOSE THE FILE
	CALL	BDOS
	RET

LOADBUFF	EQU	$	;THIS ROUTINE LOADS AS MUCH OF
	LXI	H,0000		;MEMORY WITH THE FILE AS POSSIBLE
	SHLD	MAX1
	LHLD	ADDR3		;NEW TOP OF TABLE +2
	SHLD	TEMP
	XRA	A
	STA	EOF		;CLEAR EOF FLAG
LOADNEXT	LHLD	TEMP
	XCHG			;SET DMA ADDRESS
	MVI	C,1AH
	CALL	BDOS
	LXI	D,HDFCB		;READ HARD DISK
	MVI	C,14H
	CALL	BDOS
	ORA	A
	JNZ	HDEOF		;EOF?
	LHLD	MAX1
	INX	H		;INCREMENT RECORD COUNT
	SHLD	MAX1
	LHLD	TEMP		;SEE IF NEXT RECORD WOULD EXCEED THE
	LXI	D,128		;TPA AREA
	DAD	D
	SHLD	TEMP
	DAD	D		;WILL THE NEXT RECORD OVERWRITE BDOS?
	XCHG
	LHLD	BDOS+1		;FIND THE TOP OF MEMORY
	CALL	COMPREG		;COMPARE REGISTERS
	RC			;RETURN IF MEMORY ALREADY FULL
	JMP	LOADNEXT	;GET ANOTHER RECORD
HDEOF	MVI	A,1		;SET FILE EOF
	STA	EOF
	RET

BELL	EQU	$
	MVI	C,9
	LXI	D,MSG
	CALL	BDOS
BEEP
	MVI	C,2		;07H ON CRT
	MVI	E,07H
	CALL	BDOS
	MVI	C,0BH
	CALL	BDOS		;GET CONSOLE STATUS
	ORA	A
	JZ	BEEP
	MVI	C,01
	CALL	BDOS		;GET THE DUMMY CHAR
	RET
MSG	DB	0DH,0AH,0AH,'PRESS ANY KEY TO CONTINUE'
	DB	0DH,0AH,0AH,'$'

WRITEBUF	EQU	$	;WRITE FROM THE MEMORY BUFFER
	LHLD	ADDR3
	SHLD	TEMP
	LHLD	MAX1		;ALLOW FOR FILES THAT HAVE NO 
	LXI	D,0000		;RECORDS SUCH AS RESTART
	CALL	COMPREG
	RZ
WRITENEXT	LHLD	TEMP
	XCHG			;SET DMA ADDRESS
	MVI	C,1AH
	CALL	BDOS
	LXI	D,FPFCB
	MVI	C,15H		;WRITE SEQUENTIAL
	CALL	BDOS
	ORA	A
	JNZ	FPFULL		;FLOPPY DISK FULL
	LHLD	MAX1		;DECREASE RECORD COUNT
	DCX	H
	SHLD	MAX1
	LXI	D,0000		;CHECK FOR NO MORE TO WRITE
	CALL	COMPREG
	RZ
	LHLD	TEMP
	LXI	D,128		;INCREMENT WRITE ADDRESS
	DAD	D
	SHLD	TEMP
	JMP	WRITENEXT
FPFULL	MVI	A,2		;FULL DISKETTE
	STA	EOF
	RET

FORMAT	LXI	D,PRNTYPE	;FORMAT THE ENTRY FROM THE TABLE
	MVI	B,3		;FORMAT TO THE PRINT FORMAT
	CALL	MOVE		;THE TABLE ADDRESS IS ASSUMMED TO BE
	LXI	D,3		;IN HL. FIRST MOVE THE TYPE
	DAD	D		;NOW POSITION TO THE FILE NAME
	LXI	D,PRNFILE	;MOVE THE FILE NAME
	MVI	B,8
	CALL	MOVE
	LXI	D,8		;POSITION TO THE DISK ID
	DAD	D
	LXI	D,PRNTREC	;MOVE THE DISK ID TO THE LINE
	MVI	B,IDSIZE
	CALL	MOVE
	RET

COMPREG	MOV	A,H		;COMPARE HL TO DE
	CMP	D
	RNZ
	MOV	A,L
	CMP	E
	RET

OUTPUT	PUSH	D		;PUT OUT A CRLF
	LXI	D,CRLF
	MVI	C,09
	CALL	BDOS
	POP	D		;NOW PUT OUT THE MESSAGE
OUT1	MVI	C,09
	JMP	BDOS

HEADING	LXI	D,HEAD1
	CALL	LIST
	LXI	D,DATE
	CALL	LIST
	LXI	D,TABFULL
	LDA	ABORT
	ORA	A
	CNZ	LIST
	MVI	A,LINESPAGE
	STA	LINECNT
	LXI	D,CRLF
	CALL	LIST
	LXI	D,CRLF
	JMP	LIST

LIST	PUSH	H		;THIS DIFFERS FROM OUTPUT
	PUSH	B		; IN THAT LIST GOES TO THE
	PUSH	D		;LIST DEVICE AND OUTPUT GOES
LIST1	LDAX	D		;TO THE CONSOLE DEVICE
	CPI	'$'
	JZ	LIST2
	INX	D
	PUSH	D
	MOV	E,A
	MVI	C,5
	CALL	BDOS
	POP	D
	JMP	LIST1
LIST2	POP	D
	POP	B
	POP	H
	RET


QUESTION	CALL	OUTPUT	;PUT OUT THE QUESTION
	LXI	D,INBUF
	MVI	C,0AH		;INPUT THE REPLY
	CALL	BDOS
	LDA	INCNT		;SEE IF ANYTHING WAS ENTERED
	RET
 
MOVE	PUSH	H		;MOVE DATA POINTED TO IN HL
	PUSH	D		;TO THE AREA POINTED TO IN DE
	PUSH	B		;BY THE BYTE COUNT IN B
MOVE1	MOV	A,M
	ANI	7FH		;RESET THE HIGH ORDER BIT BECAUSE IT
				;MAY HAVE BEEN TURNED ON FOR THE TYPE
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MOVE1
	POP	B		;RESTORE THE TOTAL ENVIRONMENT
	POP	D
	POP	H
	RET

COMPARE	PUSH	H		;COMPARE THE STRINGS POINTED TO IN HL
	PUSH	D		;TO THE STRING POINTED TO IN DE
	PUSH	B		;FOR A LENGTH OF B CHARACTERS
COMP1	LDAX	D		; JC IF HL > DE
	CMP	M		; JZ IF HL = DE
	JNZ	COMP2		;JNC IF HL < DE
	INX	H
	INX	D
	DCR	B
	JNZ	COMP1
COMP2	POP	B
	POP	D
	POP	H
	RET

	IF	CLOCK
; THIS ROUTINE READS THE COMPUTIME CLOCK AND FORMATS THE TIME AND DATE
GETDATE	EQU	$
	MVI	A,16		;RAISE THE HOLD SIGNAL
	OUT	C2
	MVI	A,50		;DELAY AT LEAST 50 MILLISECONDS
WAIT50 DCR	A
	JNZ	WAIT50
	LXI	H,DATETIME	;SET MESSAGE START.  NOTE 1ST CHAR IS SPACE
	MVI	A,42		;GET MONTH TENS CHAR
	CALL	GETTIME
	MVI	A,41		;GET MONTH UNITS CHAR
	CALL	GETTIME
	INX	H		;SKIP SLASH
	MVI	A,40		;GET DAY TENS CHAR
	CALL	GETTIME
	ANI	0F3H		;DROP LEAP YEAR INDICATOR
	MOV	M,A
	MVI	A,39		;GET DAY UNITS CHAR
	CALL	GETTIME		
	INX	H		;SKIP SLASH
	MVI	A,44		;GET YEAR TENS CHAR
	CALL	GETTIME
	MVI	A,43		;GET YEAR UNITS CHAR
	CALL	GETTIME
	INX	H		;SKIP BLANK
	MVI	A,37		;GET HOUR TENS CHAR
	CALL	GETTIME
	ANI	0F3H		;DROP AM/PM AND 24HR INDICATORS
	MOV	M,A
	MVI	A,36		;GET HOUR UNITS CHAR
	CALL	GETTIME
	INX	H		;SKIP COLON
	MVI	A,35		;GET MINUTES TENS CHAR
	CALL	GETTIME
	MVI	A,34		;GET MINUTES UNITS CHAR
	CALL	GETTIME
	INX	H		;SKIP COLON
	MVI	A,33		;GET SECONDS TENS CHAR
	CALL	GETTIME
	MVI	A,32		;GET SECONDS UNITS CHAR
	CALL	GETTIME
	XRA	A
	OUT	C2		;LOWER HOLD SIGNAL
	RET
C1	EQU	254		;CLOCK ADDRESS PORT
C2	EQU	253		;CLOCK DATA OUTPUT PORT
GETTIME	INX	H		;ADVANCE TO NEXT PRINT POSITION
	OUT	C1
	MVI	A,6		;DELAY AT LEAST 6 MILLISECONDS
WAIT6	DCR	A
	JNZ	WAIT6
	IN	C1
	ORI	30H		;CONVERT TO ASCII
	MOV	M,A
	RET
DATETIME DB	' 00/00/00 HH:MM:SS$'
	ENDIF

SIGNON	DB	'HARD DISK CATALOG AND BACKUP '
	DB	'10/09/82A$'
RESTART DS	32
REPO	DS	12
DATEMSG	DB	'ENTER 8 CHAR DATE FOR REPORTS MM/DD/YY: $'
ERASE	DB	'ERASE FLOPPY DISK FIRST (Y/N)? $'
TABFULL	DB	'MEMORY FULL...REPORT NOT COMPLETE$'
BACKQUS	DB	'BEGIN BACKUP PROCEDURE (Y/N)? $'
SORTMSG	DB	'SORTING...$'
RPTMSG  DB	'PRINTING REPORTS...$'
EXTRMSG DB	'EXTRACTING DIRECTORY...$'
POSMSG	DB	'POSITION FOR RESTART...$'
KILLMSG	DB	'REMOVING DUPLICATES...$'
NFMSG	DB	'FILE NOT FOUND...ABORTING$'
DMNTMSG	DB	'DISMOUNT BACKUP DISK AND ENTER RETURN$'
MNTMSG	DB	'MOUNT DISKETTE FOR BACKUP AND ENTER '
	DB	'3 CHAR DISK ID OR "END": $'
ENDLIT	DB	'END'
VOLSER	DS	3
QUEST1	DB	'BACKUP ALL FILES OF TYPE '
QTYPE	DS	3
	DB	', (Y/N/S)? $'
QUEST2	DB	'BACKUP FILE NAMED '
QDISK2	DS	1
	DB	':'
QFILE2	DS	8
	DB	'.'
QTYPE2	DS	3
	DB	', (Y/N/C)? $'
HEAD2	DB	0CH,'THE FOLLOWING FILES WILL BE COPIED TO DISKETTES$'
PRNTREC	DS	1
	DB	':'
PRNFILE	DS	8
	DB	'.'
PRNTYPE	DS	3
	DB	'    $'
CRLFLFLF	DB	0DH,0AH,0AH,0AH,'$'
INDEX	DB	'THE FOLLOWING FILES ARE ON DISKETTE NO. '
IDISKNO	DS	3
	DB	' AS OF '
IDATE	DS	8
	DB	'$'
CRLF	DB	0DH,0AH,'$'
HEAD1	DB	0CH,'CONSOLIDATED INDEX BY FILE TYPE AS OF $'
DATE	DS	8
	DB	'   $'
BIGMSG	DB	0DH,0AH,'FILE TOO LARGE TO FIT ON ONE DISKETTE '
	DB	'SO NOT BACKED UP **** $'
DESTMSG	DB	'DESTINATION FLOPPY (DEFAULT='
BACKUPDRV DB	'D) $'
HD2BU	DB	'LOGICAL HARD DISK DRIVES TO BACKUP (DEFAULT='
DRIVES	DB	'ABCDEFGHIJKLMNOP'
NODRV	DB	3
SKPMSG	DB	'FILE TYPES TO SKIP (DEFAULT='
SKIPTYPE DB	'PRNHEXSYMBAKTMP'
	DS	45
NOSKIP	DB	5
HDFCB	DS	1
HDFILE	DS	8
HDTYPE	DS	3
	DS	24
FPFCB	DS	36
TOP	DB	0CH,'$'
INBUF	DB	60
INCNT	DS	1
INREC	DS	60
STACK	DS	80
EOF	DS	1
ABORT	DS	1
LINECNT	DS	1
LASTTYPE DS     3
LASTFILE DS	8
TABADDR	DS	2
TABCNT	DS	2
SELFLAG	DS	1
TOOBIG	DS	1
ADDR1	DS	2
ADDR2	DS	2
ADDR3	DS	2
MAX1	DS	2
MAX2	DS	2
RTYPE	DS	3
RFILE	DS	8
RDISK	DS	3
	DB	'$'
TEMP	DS	RECSIZE
DISKBUF	DS	128
COMPSIZE DS	1
RAM	EQU	$
BDOS	EQU	05H
	END	100H
