; Tee, split stdinput to stdoutput and multiple file streams.

	INCLUDE	"/include/init.i"

; Local Equs

BufSize		EQU	512
Handles		EQU	BufSize

; Variable storage

	STRUCT	ArgArray,(2+1)*4		; +1 'cause I'm parnoid
	SIZE

; Regs

AppendBool	EQUR	D4
StdInput	EQUR	D5
AllocStruct	EQUR	D6
ActualLength	EQUR	D7

FileNamePtrPtr	EQUR	A2
HandlePtr	EQUR	A3
ErrorStrPtr	EQUR	A4

; Start

	STACK	4000
	INIT

; Let ARP interpret the commandline

	MOVE.L	ComLineBase(GP),A0
	MOVE.L	ComLineSize(GP),D0
	LEA	HelpMsg(PC),A1
	LEA	ArgArray(GP),A2
	LEA	Template(PC),A3
	MOVE.L	A1,(A2)
	CALL	GADS
	TST.L	D0
	BEQ.S	UnusableArgs
	BPL.S	ArgsMightBeOK
UnusableArgs:
	MOVE.L	(A2),ErrorStrPtr
	BRA	ErrorExit
ArgsMightBeOK:

; Fetch the -a switch and check if at least one file present.

	MOVE.L	4(A2),AppendBool
	BEQ.S	ArgsOK
	LEA	HelpMsg(PC),ErrorStrPtr
	MOVEQ	#1,D1
	CMP.L	D0,D1
	BEQ	ErrorExit
ArgsOK:

; Alloc tracked mem for the read write buf and the handles.

	LEA	OutOfMem(PC),ErrorStrPtr
	ADDQ.L	#1+1,D0			; Make space for StdOut + null termination
	LSL.L	#2,D0			; in the file handles longword array.
	ADD.L	#BufSize,D0		; Buffer and Handles use same mem allocation
	MOVEQ	#0,D1
	CALL	ArpAllocMem
	MOVE.L	D0,AllocStruct		; Data reg, so Z gets set
	BEQ	ErrorExit

; Initialize the handle and filename longword array pointers

	MOVE.L	ArgArray(GP),FileNamePtrPtr
	MOVE.L	AllocStruct,A0
	LEA	Handles(A0),HandlePtr

; Open the standard input and output

	CALL	Input
	MOVE.L	D0,StdInput
	CALL	Output
	MOVE.L	D0,(HandlePtr)+


;-----	The open the files, and seek to end loop

	LEA	OpenError(PC),ErrorStrPtr
OpenNextFile:
	TST.L	(FileNamePtrPtr)
	BEQ.S	AllFilesOpened

; If Appending, try to open (tracked) the file as an old file

	TST.L	AppendBool
	BEQ.S	NoAppendingRequested
	MOVE.L	(FileNamePtrPtr),D1
	MOVE.L	#MODE_OLDFILE,D2
	CALL	ArpOpen
	MOVE.L	D0,(HandlePtr)
	BEQ.S	TryToOpenNewFile

; Seek to the end

	MOVE.L	D0,D1
	MOVEQ	#0,D2
	MOVE.L	#OFFSET_END,D3
	CALL	Seek
	ADDQ.L	#1,D0
	BEQ	ErrorExit
	BRA.S	IncrementAndLoop
NoAppendingRequested:

; Open files (tracked) as new

TryToOpenNewFile:
	MOVE.L	(FileNamePtrPtr),D1
	MOVE.L	#MODE_NEWFILE,D2
	CALL	ArpOpen
	MOVE.L	D0,(HandlePtr)
	BEQ	ErrorExit

; Update pointers and loop back

IncrementAndLoop:
	ADDQ.L	#4,FileNamePtrPtr
	ADDQ.L	#4,HandlePtr
	BRA	OpenNextFile
AllFilesOpened:
	CLR.L	(HandlePtr)				; Null termination


;-----	The single input multi output copy loop, check for ^C & initize

DoNextRdWrChunk:
	SUB.L	A1,A1
	CALL	CheckAbort
	MOVE.L	A1,ErrorStrPtr
	TST.L	D0
	BNE.S	ErrorExit

	LEA	WriteError(PC),ErrorStrPtr
	MOVE.L	AllocStruct,A0
	LEA	Handles(A0),HandlePtr			; Reset to start of array

; Read from the standard input until EOF or error

	MOVE.L	StdInput,D1
	MOVE.L	AllocStruct,D2
	MOVE.L	#BufSize,D3
	CALL	Read
	MOVE.L	D0,ActualLength
	BEQ.S	Exit
	BMI.S	ErrorExit

; Do the multiwrite, and loop back

DoNextWrite:
	MOVE.L	(HandlePtr)+,D1
	BEQ	DoNextRdWrChunk
	MOVE.L	AllocStruct,D2
	MOVE.L	ActualLength,D3
	CALL	Write
	CMP.L	D0,D3
	BNE.S	ErrorExit
	BRA	DoNextWrite


; Done, cleanup

Exit:
	CLR.W	ReturnCode(GP)
	SUB.L	ErrorStrPtr,ErrorStrPtr
ErrorExit:

; Display error string, if any, and exit

	MOVE.L	ErrorStrPtr,D0
	BEQ.S	NoErrorMsg
	MOVE.L	D0,A1
	CALL	Puts
NoErrorMsg:
	RTS

; The string section

Template:
	DC.B	'Files/...,-a=APPEND/s',0
HelpMsg:
	DC.B	'Tee - pipe fitting.',10
	DC.B	'Usage: Tee [-a] <File> [...]',0
OutOfMem:
	DC.B	'Out of memory!',0
OpenError:
	DC.B	'Tee-file could not be opened',10
WriteError:
	DC.B	'Error while writing to tee-file',0
	CNOP	0,2

	END
