**********************************************************************
	Section	BFC,Code
**********************************************************************

	Include	System.gs
	Include	Macros.i

**********************************************************************

;TaskPriority	Equ	0
NOWBCD
	Include	Start.i

**********************************************************************

	Dc.B	'$VER: Big File Copy (BFC) V1.0 by Shamus Husheer',0
	Even

RESTORE	EQU	0	;(BFC DEV: Filename)
BACKUP	EQU	1	;(BFC Filename DEV:)

NUMCYLS	EQU	80
CYLSIZE	EQU	512*11*2

**********************************************************************
*
* Disk Structure created with BFC: (Not a DOS readable structure)
* Every cyl (11k) has the following structure:
* 11260 bytes of data
* 4 bytes checksum
* On track0 the last 2 bytes of data (before checksum) is the disk number
* On the disk 0, track 0 the last 4 bytes before disknum is filesize.
* All other data is file data.
* Thus each disk holds 900798 bytes of file data at most, with
* disk 1 holding 900798 bytes at most.
*
**********************************************************************

Main:
	Lea.L	VBase,A5
	Clr.B	-1(A0,D0.L)
	Move.L	A0,ArgsPtr-VBase(A5)

	Lea.L	MessagePort-VBase(A5),A0
	Move.B	#4,LN_TYPE(A0)
	Lea.L	MP_MSGLIST+LH_TAIL(A0),A1
	Move.L	A1,-4(A1)
	Subq.L	#4,A1
	Move.L	A1,MP_MSGLIST+LH_TAILPRED(A0)

	Sub.L	A1,A1
	EXEC	FindTask
	Move.L	D0,MP_SIGTASK+MessagePort-VBase(A5)

	Moveq.L	#-1,D0
	EXEC	AllocSignal
	Move.B	D0,MP_SIGBIT+MessagePort-VBase(A5)
	Bmi	.exit

	Lea.L	IORequest-VBase(A5),A1
	Move.B	#5,LN_TYPE(A1)
	Move.L	A0,MN_REPLYPORT(A1)
	Move.W	#IOSTD_SIZE,MN_LENGTH(A1)

	Lea.L	DOSLibName(PC),A1
	Moveq.L	#0,D0
	EXEC	OpenLibrary
	Move.L	D0,_DOSBase
	Beq	.freesig

	DOS	Output
	Move.L	D0,OutputHD-VBase(A5)

	Move.L	D0,D1
	Lea.L	IntroStr(PC),A0
	Move.L	A0,D2
	Move.L	#IntroStrLen,D3
	DOS	Write

	Bsr	ParseArgs
	Tst.L	D0
	Bne	.badargs

	Move.L	DevName-VBase(A5),A0
	Bsr	GetDevName
	Tst.L	D0
	Beq	.nodev

	Move.L	D0,A0
	Move.L	DevUnit-VBase(A5),D0
	Move.L	DevFlags-VBase(A5),D1
	Lea.L	IORequest-VBase(A5),A1
	EXEC	OpenDevice
	Tst.L	D0
	Bne	.nodevopen

	Move.L	#CYLSIZE,D0
	Move.L	#MEMF_CHIP|MEMF_CLEAR,D1
	EXEC	AllocMem
	Move.L	D0,Buffer-VBase(A5)
	Beq	.nomem

	Tst.B	Operation-VBase(A5)
	Beq.S	.restore01
	Move.L	#MODE_OLDFILE,D2
	Bra.S	.openfile
.restore01
	Move.L	#MODE_NEWFILE,D2
.openfile
	Move.L	FileName-VBase(A5),D1
	DOS	Open
	Move.L	D0,FileHD-VBase(A5)
	Beq	.nofile

	Tst.B	Operation-VBase(A5)
	Beq.S	.restore02
	Bsr	DoBackup
	Bra.S	.freeallocs
.restore02
	Bsr	DoRestore
.freeallocs

	Move.L	D0,D7

	Move.L	OutputHD-VBase(A5),D1
	Tst.L	D7
	Beq.S	.noerrors
	Lea.L	ErrorsStr(PC),A0
	Move.L	A0,D2
	Move.L	#ErrorsStrLen,D3
	Bra.S	.dofinal
.noerrors
	Lea.L	NoErrorsStr(PC),A0
	Move.L	A0,D2
	Move.L	#NoErrorsStrLen,D3
.dofinal
	DOS	Write

.closefile
	Move.L	FileHD-VBase(A5),D1
	DOS	Close
.freemem
	Move.L	Buffer-VBase(A5),A1
	Move.L	#CYLSIZE,D0
	EXEC	FreeMem
.closedev
	Lea.L	IORequest-VBase(A5),A1
	EXEC	CloseDevice
.closedos
	Move.L	_DOSBase(PC),A1
	EXEC	CloseLibrary
.freesig
	Moveq	#0,D0
	Move.B	MessagePort+MP_SIGBIT-VBase(A5),D0
	EXEC	FreeSignal
.exit
	Moveq.L	#0,D0
	Rts

.badargs
	Move.L	OutputHD-VBase(A5),D1
	Lea.L	ArgStr(PC),A0
	Move.L	A0,D2
	Move.L	#ArgStrLen,D3
	DOS	Write
	Bra.S	.closedos

.nodev
	Move.L	OutputHD-VBase(A5),D1
	Lea.L	NoDevStr(PC),A0
	Move.L	A0,D2
	Move.L	#NoDevStrLen,D3
	DOS	Write
	Bra.S	.closedos

.nodevopen
	Move.L	OutputHD-VBase(A5),D1
	Lea.L	NoDevOpenStr(PC),A0
	Move.L	A0,D2
	Move.L	#NoDevOpenStrLen,D3
	DOS	Write
	Bra.S	.closedos

.nomem
	Move.L	OutputHD-VBase(A5),D1
	Lea.L	NoMemStr(PC),A0
	Move.L	A0,D2
	Move.L	#NoMemStrLen,D3
	DOS	Write
	Bra	.closedev

.nofile
	Move.L	OutputHD-VBase(A5),D1
	Lea.L	NoFileStr(PC),A0
	Move.L	A0,D2
	Move.L	#NoFileStrLen,D3
	DOS	Write
	Bra	.freemem

**********************************************************************

DoBackup:
	Move.B	#-1,Operation-VBase(A5)
	Move.L	#WritingStr,OpType-VBase(A5)
	Clr.W	DiskCounter-VBase(A5)
	Bsr	GetFileSize
	Move.L	D0,FileSize-VBase(A5)
	Beq	.error
	Bsr	DevClear
.diskloop
	Bsr	PromptDisk
	Tst.L	D0
	Beq	.error
	Moveq.L	#1,D0
	Bsr	Motor
	Clr.W	TrackCounter-VBase(A5)
	Move.L	Buffer-VBase(A5),A0
	Lea.L	11258(A0),A0
	Move.W	DiskCounter-VBase(A5),D0
	Move.W	D0,(A0)
	Tst.W	D0
	Bne.S	.datadisk
	Move.L	FileSize-VBase(A5),-4(A0)	;File Size if disk0
	Move.L	#CYLSIZE-10,D7
	Bra.S	.read
.datadisk
	Move.L	#CYLSIZE-6,D7
	Bra.S	.read
.trackloop
	Move.L	#CYLSIZE-4,D7
.read
	Move.L	FileSize-VBase(A5),D0
	Sub.L	FileDone-VBase(A5),D0
	Cmp.L	D0,D7
	Blo.S	.readfile
	Move.L	D0,D7
	Clr.B	Operation-VBase(A5)
.readfile
	Move.L	D7,D0
	Bsr	ReadFileToBuffer
	Cmp.L	D7,D0
	Bne.S	.error
	Bsr	CheckSumData
	Move.L	Buffer-VBase(A5),A0
	Move.L	D0,11260(A0)
	Bsr	PrintProgress
	Move.W	#CMD_WRITE,D0
	Bsr	DoTrack
	Tst.L	D0
	Bne.S	.diskerror
	Add.L	D7,FileDone-VBase(A5)
	Cmp.W	#79,TrackCounter-VBase(A5)
	Bhs.S	.endtrackloop
	Addq.W	#1,TrackCounter-VBase(A5)
	Tst.B	Operation-VBase(A5)
	Bne.S	.trackloop
.endtrackloop
	Bsr	DevUpdate
	Moveq.L	#0,D0
	Bsr	Motor
	Tst.B	Operation-VBase(A5)
	Beq.S	.trackloopend
	Addq.W	#1,DiskCounter-VBase(A5)
	Bra	.diskloop
.trackloopend
	Move.L	FileDone-VBase(A5),D0
	Cmp.L	FileSize-VBase(A5),D0
	Bne.S	.error
.finished
	Moveq.L	#0,D0
	Rts
.error
	Moveq.L	#-1,D0
	Rts
.diskerror
	Bsr	PrintDiskError	;Remove the amount of file done so far
	Bra.S	.endtrackloop



DoRestore:
	Move.B	#-1,Operation-VBase(A5)
	Move.L	#ReadingStr,OpType-VBase(A5)
	Clr.W	DiskCounter-VBase(A5)
	Bsr	DevClear
.diskloop
	Bsr	PromptDisk
	Tst.L	D0
	Beq	.error
	Moveq.L	#1,D0
	Bsr	Motor
	Clr.W	TrackCounter-VBase(A5)
.trackloop
	Bsr	PrintProgress
	Move.W	#CMD_READ,D0
	Bsr	DoTrack
	Tst.L	D0
	Bne	.diskerror
	Bsr	CheckSumData
	Move.L	Buffer-VBase(A5),A0
	Lea.L	11260(A0),A0
	Cmp.L	(A0),D0
	Bne	.diskerror
	Tst.W	TrackCounter-VBase(A5)
	Bne.S	.datatrack
	Move.W	DiskCounter-VBase(A5),D0
	Cmp.W	-2(A0),D0
	Bne.S	.diskloop			;Disks out of order
	Tst.W	-2(A0)
	Bne.S	.datadisk
	Move.L	-6(A0),FileSize-VBase(A5)
	Move.L	#CYLSIZE-10,D7
	Bra.S	.write
.datadisk
	Move.L	#CYLSIZE-6,D7
	Bra.S	.write
.datatrack
	Move.L	#CYLSIZE-4,D7
.write
	Move.L	FileSize-VBase(A5),D0
	Sub.L	FileDone-VBase(A5),D0
	Cmp.L	D0,D7
	Blo.S	.writefile
	Move.L	D0,D7
	Clr.B	Operation-VBase(A5)
.writefile
	Move.L	D7,D0
	Bsr	WriteBufferToFile
	Cmp.L	D7,D0
	Bne.S	.error
	Add.L	D7,FileDone-VBase(A5)
	Cmp.W	#79,TrackCounter-VBase(A5)
	Bhs.S	.endtrackloop
	Addq.W	#1,TrackCounter-VBase(A5)
	Tst.B	Operation-VBase(A5)
	Bne	.trackloop
.endtrackloop
	Moveq.L	#0,D0
	Bsr	Motor
	Tst.B	Operation-VBase(A5)
	Beq.S	.trackloopend
	Addq.W	#1,DiskCounter-VBase(A5)
	Bra	.diskloop
.trackloopend
	Move.L	FileDone-VBase(A5),D0
	Cmp.L	FileSize-VBase(A5),D0
	Bne.S	.error
.finished
	Moveq.L	#0,D0
	Rts
.error
	Moveq.L	#-1,D0
	Rts
.diskerror
	Bsr	PrintDiskError	;Remove the amount of file done so far
	Bra.S	.endtrackloop

**********************************************************************

CheckSumData:
	Move.L	Buffer-VBase(A5),A0
	Moveq.L	#0,D0
	Move.L	#2816,D1
.loop
	Subq.L	#1,D1
	Beq.S	.fin
	Add.L	(A0)+,D0
	Bcc.S	.loop
	Addq.L	#1,D0
	Bra.S	.loop
.fin
	Rts

DoTrack:
	Move.W	D0,IO_COMMAND+IORequest-VBase(A5)
	Move.W	TrackCounter-VBase(A5),D0
	Mulu	#44,D0
	Lsl.L	#8,D0
	Move.L	D0,IO_OFFSET+IORequest-VBase(A5)
	Move.L	#CYLSIZE,IO_LENGTH+IORequest-VBase(A5)
	Move.L	Buffer-VBase(A5),IO_DATA+IORequest-VBase(A5)
	Lea.L	IORequest-VBase(A5),A1
	EXEC	DoIO
	Moveq.L	#0,D0
	Move.B	IO_ERROR+IORequest-VBase(A5),D0
	Rts

ReadFileToBuffer:
	Move.L	FileHD-VBase(A5),D1
	Move.L	Buffer-VBase(A5),D2
	Move.L	D0,D3
	DOS	Read
	Rts

WriteBufferToFile:
	Move.L	FileHD-VBase(A5),D1
	Move.L	Buffer-VBase(A5),D2
	Move.L	D0,D3
	DOS	Write
	Rts

Motor:
	Move.W	#TD_MOTOR,IO_COMMAND+IORequest-VBase(A5)
	Move.L	D0,IO_LENGTH+IORequest-VBase(A5)
	Lea.L	IORequest-VBase(A5),A1
	EXEC	DoIO
	Rts

DevClear:
	Move.W	#CMD_CLEAR,IO_COMMAND+IORequest-VBase(A5)
	Lea.L	IORequest-VBase(A5),A1
	EXEC	DoIO
	Rts

DevUpdate:
	Move.W	#CMD_UPDATE,IO_COMMAND+IORequest-VBase(A5)
	Lea.L	IORequest-VBase(A5),A1
	EXEC	DoIO
	Rts

ParseArgs:
	Move.L	ArgsPtr-VBase(A5),A0
.find1starg
	Move.B	(A0)+,D0
	Tst.B	D0
	Beq.S	.badargs
	Cmp.B	#' ',D0
	Bne.S	.find1starg
	Lea.L	-2(A0),A1
	Cmp.B	#':',(A1)
	Bne.S	.write
	Clr.W	(A1)+
	Move.L	ArgsPtr-VBase(A5),DevName-VBase(A5)
	Move.L	A1,FileName-VBase(A5)
	Move.B	#RESTORE,Operation-VBase(A5)
	Bra.S	.doneargs
.write
	Clr.B	1(A1)
	Move.L	ArgsPtr-VBase(A5),FileName-VBase(A5)
	Move.L	A0,DevName-VBase(A5)
	Move.B	#BACKUP,Operation-VBase(A5)
.find2ndarg
	Cmp.B	#':',(A0)
	Beq.S	.found
	Tst.B	(A0)+
	Bne.S	.find2ndarg
	Bra.S	.badargs
.found
	Clr.W	(A0)
.doneargs
	Moveq.L	#0,D0
	Rts
.badargs
	Moveq.L	#-1,D0
	Rts


GetDevName:		;In:  A0 - Dev Name (eg FF0) Out: D0 = aptr Device
	Move.L	A0,A2
	Moveq.L	#-1,D1
.lenloop
	Cmp.B	#'a',(A0)
	Blo.S	.noand
	Cmp.B	#'z',(A0)
	Bhi.S	.noand
	And.B	#$DF,(A0)
.noand
	Tst.B	(A0)+
	DBeq	D1,.lenloop
	Neg.L	D1
	Subq.L	#1,D1
	Beq.S	.notfound
	Move.L	_DOSBase(PC),A0
	EXEC	Forbid
	Move.L	34(A0),A0
	Move.L	24(A0),D0
	Lsl.L	#2,D0
	Move.L	D0,A0
	Addq.L	#4,A0
.loop
	Move.L	(A0),D0
	Beq.S	.notfound
	Lsl.L	#2,D0
	Move.L	D0,A0
	Tst.L	dol_Type(A0)
	Bne.S	.loop
	Move.L	dol_Name(A0),D0
	Lsl.L	#2,D0
	Move.L	D0,A1
	Cmp.B	(A1)+,D1
	Bne.S	.loop
	Move.L	D1,D0
	Subq.L	#1,D0
	Move.L	A2,A3
.cmploop
	Cmp.B	(A1)+,(A3)+
	Bne.S	.loop
	DBra	D0,.cmploop
	Move.L	dol_Startup(A0),D0
	Beq.S	.loop
	Lsl.L	#2,D0
	Move.L	D0,A1
	Move.L	4(A1),D0
	Beq.S	.loop
	Move.L	(A1),DevUnit-VBase(A5)
	Move.L	12(A1),DevFlags-VBase(A5)
	Lsl.L	#2,D0
	Addq.L	#1,D0
	Move.L	D0,DeviceName-VBase(A5)
	Bra.S	.permit
.notfound
	Moveq.L	#0,D0
.permit
	EXEC	Permit
	Rts

PrintDiskError:
	Lea.L	DiskErrorStr(PC),A0
	Lea.L	OpType-VBase(A5),A1
	Bsr.S	PrintF
	Move.W	DiskCounter-VBase(A5),D0
	Move.W	D0,D1
	Mulu	#55,D0
	Lsl.L	#7,D0
	Lsl.L	#7,D0				;Number of bytes assuming full disk
	Mulu	#328,D1				;Number of non-data bytes per disk
	Sub.L	D1,D0
	Move.L	D0,FileDone-VBase(A5)
	Move.L	FileHD-VBase(A5),D1
	Moveq.L	#OFFSET_BEGINNING,D2
	Move.L	D0,D3
	DOS	Seek
	Subq.W	#1,DiskCounter-VBase(A5)
	Moveq.L	#0,D0
	Bsr	Motor
	Rts

PromptDisk:
	Lea.L	PromptDiskStr(PC),A0
	Lea.L	DiskCounter-VBase(A5),A1
	Bsr.S	PrintF
	Move.L	OutputHD-VBase(A5),D1
	Lea.L	TextBuffer-VBase(A5),A0
	Move.L	A0,D2
	Moveq.L	#1,D3
	DOS	Read
	Cmp.B	#'!',TextBuffer-VBase(A5)
	Beq.S	.ctlc
	Moveq.L	#-1,D0
	Rts
.ctlc
	Moveq.L	#0,D0
	Rts

PrintProgress:
	Lea.L	ProgressStr(PC),A0
	Lea.L	OpType-VBase(A5),A1
	Bsr.S	PrintF
	Rts

PrintF:					;A0/A1 as rawdofmt
	Lea.L	.stuffchar(PC),A2
	Lea.L	TextBuffer-VBase(A5),A3
	EXEC	RawDoFmt

	Move.L	OutputHD-VBase(A5),D1
	Lea.L	TextBuffer-VBase(A5),A0
	Move.L	A0,D2
	Moveq.L	#-1,D3
.lenloop
	Tst.B	(A3)+
	DBeq	D3,.lenloop
	Not.L	D3
	DOS	Write
	Rts

.stuffchar
	Move.B	D0,(A3)+
	Rts

GetFileSize:
	Move.L	FileName-VBase(A5),D1
	Moveq.L	#ACCESS_READ,D2
	DOS	Lock
	Move.L	D0,D1
	Beq.S	.error
	Move.L	D0,D7
	Lea.L	FileInfo-VBase(A5),A0
	Move.L	A0,D2
	DOS	Examine
	Move.L	D7,D1
	Move.L	D0,D7
	DOS	UnLock
	Move.L	D7,D0
	Beq.S	.error
	Move.L	fib_Size+FileInfo-VBase(A5),D0
.error
	Rts

**********************************************************************

IntroStr:
	Dc.B	'Big File Copy V1.0 by Shamus Husheer',10
IntroStrLen	Equ	*-IntroStr

ArgStr:
	Dc.B	'Command Line Parameters INCORRECT.  Try:',10
	Dc.B	'BFC <source> <dest>',10
	Dc.B	'Where, for backing up, <source> is a file and <dest> is a device, eg DF0,',10
	Dc.B	'or for restoring <source> is a device, and <dest> is a file.',10
ArgStrLen	Equ	*-ArgStr

NoDevStr:
	Dc.B	'Unable to locate the device you have requested.',10
NoDevStrLen	Equ	*-NoDevStr

NoDevOpenStr:
	Dc.B	'The device you have requested failed allocation.',10
NoDevOpenStrLen	Equ	*-NoDevOpenStr

NoMemStr:
	Dc.B	'Unable to allocate 11KB of memory for track buffer.',10
NoMemStrLen	Equ	*-NoMemStr

NoFileStr:
	Dc.B	'Unable to open your requested file.',10
NoFileStrLen	Equ	*-NoFileStr

ErrorsStr:
	Dc.B	13,'There were errors in the operation.',10
ErrorsStrLen	Equ	*-ErrorsStr

NoErrorsStr:
	Dc.B	13,'No errors were encountered.',10
NoErrorsStrLen	Equ	*-NoErrorsStr

ProgressStr:
	Dc.B	13,'%s disk %d, cyl %d',0

DiskErrorStr:
	Dc.B	13,'Error %s disk %d, cyl %d',10,0

ReadingStr:
	Dc.B	'Reading',0
WritingStr:
	Dc.B	'Writing',0

PromptDiskStr:
	Dc.B	13,'Please Insert disk %d in drive and press return. ! = Abort',0

DOSLibName:
	DOSNAME

	EVEN

_DOSBase
	Dc.L	0		;Frequently used, so PC relative.

*******

	Section	Variables,BSS

VBase:

ArgsPtr:
	Ds.L	1

OutputHD:
	Ds.L	1

DevName:
	Ds.L	1
DeviceName:
	Ds.L	1
DevUnit:
	Ds.L	1
DevFlags:
	Ds.L	1

Buffer:
	Ds.L	1

FileName:
	Ds.L	1
FileHD:
	Ds.L	1
FileSize:
	Ds.L	1
FileDone:
	Ds.L	1

OpType:			;Do not separate
	Ds.L	1
DiskCounter:		;Do not separate
	Ds.W	1
TrackCounter:		;Do not separate
	Ds.W	1

TextBuffer:
	Ds.B	40

	Ds.L	0	;Long Align
FileInfo:
	Ds.B	fib_SIZEOF

MessagePort:
	Ds.B	MP_SIZE

IORequest:
	Ds.B	IOSTD_SIZE

Operation:
	Ds.B	1
