
*	Openers.asm (of PCQ Pascal runtime library)
*	Copyright (c) 1989 Patrick Quaid

*	This file takes care of opening and closing DOS files.  In
*	much the same way as the memory routines, these routines keep a
*	list of the open files around.  Open() puts the files on the list
*	and Close() takes them off.

	SECTION	ONE

	XREF	_p%DOSBase
	XREF	_LVOOpen
	XREF	_p%new
	XREF	_p%dispose
	XREF	_p%wrapitup
	XREF	_LVORead
	XREF	_LVOClose

	XDEF	filekey

*	algorithm for open:
*
*	open the file
*	set the link
*	store the file handle
*	if the record size is not 1, 2, or 4
*	    call _p%new to allocate a buffer
*	    store the address of the buffer
*	if it's an input file
*	    read the first record
*	    set the eof field accordingly

	XDEF	_p%open
_p%open:

	move.l	d2,-(sp)	; save the access mode
	move.l	a0,-(sp)	; save address of file record
	move.l	d0,d1		; get address of file name string
	move.l	_p%DOSBase,a6	; d2 already has mode
	jsr	_LVOOpen(a6)
	tst.l	d0		; opened ok?
	bne.s	1$		; if so, skip this
	add.l	#8,sp		; restore stack
	rts			; and return

1$	move.l	(sp)+,a0	; get address back
	move.l	d0,(a0)		; save file handle in record
	move.l	filekey,14(a0)	; save link
	move.l	a0,filekey	; add to list
	move.l	8(a0),d0	; get size
	cmp.l	#1,d0		; is it 1?
	beq.s	2$		; if so, skip this bit here.
	cmp.l	#2,d0		; ditto if two or four
	beq.s	2$
	cmp.l	#4,d0
	beq.s	2$
	move.l	a0,-(sp)	; save address (again)
	jsr	_p%new		; get block of size in d0, left in d0
	move.l	(sp)+,a0	; get address back again
	move.l	d0,4(a0)	; store the pointer to the new block
	bne.s	2$		; if it's ok, go on.
	jmp	_p%wrapitup	; no memory for file.  Abort!
2$	move.b	#0,12(a0)	; set eof = false
	move.l	(sp)+,d0	; retrieve access mode
	cmp.l	#1005,d0	; is it 1005?
	bne.s	3$		; if so, then it's an input file.

* at this point, a0 has the address of the file block, which
* is set up correctly except for the data direction.  Thus we'll
* set that, then just call the arbitrary read routine on the file.

	move.b	#0,13(a0)	; set inout = input
	jsr	_p%readarbbuf	; read an arbitrary datum into buffer
				; that routine sets the eof flag correctly
3$	move.l	#-1,d0		; regardless of how the read went, the
	rts			; file IS open, so return true.

	XDEF	_p%readarbbuf
_p%readarbbuf

* read 'record length' bytes from 'filehandle' into the record's buffer
* a0 is the file record
* set the eof field accordingly

	move.l	a0,-(sp)
	move.l	(a0),d1		; get file handle
	move.l	8(a0),d3	; get length
	lea	4(a0),a1
	move.l	a1,d2		; get address of buffer.
				; this is correct for size = 1,2 or 3.
				; figure most will be that size, right?
	cmp.l	#1,d3		; is it, in fact, 1?
	beq.s	1$		; if so, then skip correction
	cmp.l	#2,d3		; same with 2
	beq.s	1$
	cmp.l	#4,d3		; and 4
	beq.s	1$
	move.l	4(a0),d2	; load ADDRESS of buffer (correct the assumption)
1$	move.l	_p%DOSBase,a6
	jsr	_LVORead(a6)
	move.l	(sp)+,a0	; retrieve address
	cmp.l	8(a0),d0	; did everything go ok?
	beq.s	2$		; yes, so just leave
	move.b	#-1,12(a0)	; eof = true
2$	rts

	XDEF	_p%close
_p%close:

	move.l	d0,a0		; get address into a0

1$	cmp.l	filekey,a0	; is this first open file?
	bne.s	2$		; if not, go around
	move.l	14(a0),filekey	; bypass record
	bra	5$		; and close file
2$	move.l	filekey,a1
	move.l	14(a1),a2	; a1 is trailer, a2 is node
3$	cmp.l	a2,a0		; is this node the original?
	beq.s	4$		; if so, go
	move.l	a2,a1
	move.l	14(a2),a2	; set up for next
	move.l	a2,d0		; is this zero?
	bne	3$
	rts			; wasn't in list! Abort!
4$	move.l	14(a2),a2	; get next
	move.l	a2,14(a1)	; bypass this node

5$	move.l	(a0),d1
	move.l	a0,-(sp)
	move.l	_p%DOSBase,a6
	jsr	_LVOClose(a6)
	move.l	(sp)+,a0
	move.l	8(a0),d0
	cmp.l	#1,d0		; if size = 1 then no buffer
	beq.s	6$		; so skip
	cmp.l	#2,d0		; same for 2
	beq.s	6$
	cmp.l	#4,d0		; and 4
	beq.s	6$
	move.l	4(a0),d0	; get address of block
	jsr	_p%dispose	; free the buffer
6$	rts

	SECTION	TWO
filekey	dc.l	0
	END

