	.title	bio - basic unix style i/o routines

	.psect	.prog.
	.even

; creat(fname,mode)
;
;	fname		file name
;	mode		(unused)
creat::
	jsr	r5,csv$			; Save the registers
	mov	#wmode,-(sp)		; Open file in write mode
	br	opncre			; Join common code

; open(fname,mode)
;
;	fname		file name
;	mode		(unused)
open::
	jsr	r5,csv$			; Save the registers
	mov	#rmode,-(sp)		; Open file in read mode
opncre:
	mov	c$pmtr(r5),-(sp)	; Pass filename to fopen
	jsr	pc,fopen		; Open the file
	mov	(sp)+,(sp)+		; Clean the stack
	tst	r0			; Check the value returned
	bne	10$			; Branch if fopen succeeded
	mov	#-1,r0			; Return -1 on failures
	jmp	cret$			; Back we go

10$:	bic	#vf$bzy,v$flag(r0)	; Clear the buzy flag
	mov	#-1,v$bnbr(r0)		; Set block to -1
	clr	v$bcnt(r0)		; Clear the count remaining
	jmp	cret$			; Back we go

; close(fd)
;
;	fd		file descriptor
close::
	jsr	r5,csv$			; Save the registers
	mov	c$pmtr(r5),r4		; Get the IOV pointer
	bit	#vf$bzy,v$flag(r4)	; Is the buffer buzy?
	beq	10$			; No...
	jsr	pc,bwrite		; Write out the current buffer
10$:	mov	r4,-(sp)		; Pass file descriptor to fclose
	jsr	pc,fclose		; Close the file
	tst	(sp)+			; Clean the stack
	jmp	cret$			; Back we go

	.psect	.strn.
rmode:	.asciz	\r\			; read mode
wmode:	.asciz	\w\			; write mode
ioerr:	.byte	e$$eof,e$$err,e$$fat
	.psect	.prog.
; lseek(fd,offset,start)
;
;	fd		file descriptor
;	offset		byte offset (long)
;	start		(unused)
lseek::
	jsr	r5,csv$			; Save the registers
	mov	c$pmtr(r5),r4		; Get IOV pointer
	mov	c$pmtr+2(r5),r1		; Get high-order byte offset
	mov	c$pmtr+4(r5),r2		; Get  low-order byte offset
	mov	r2,r3			; Get offset into block
	bic	#^C777,r3
	mov	#9.,r0			; Shift right 9 places
10$:	asr	r1			; Shift the high 16 bits
	ror	r2			; Shift the  low 16 bits
	dec	r0			; Done?
	bne	10$			; Not yet...continue
	cmp	r2,v$bnbr(r4)		; Same as current block?
	beq	20$			; Yes...
	bit	#vf$bzy,v$flag(r4)	; Current block buzy?
	beq	15$			; No...don't write in back
	jsr	pc,bwrite		; Write back the current block
15$:	mov	r2,v$bnbr(r4)		; Store the new block number
	jsr	pc,bread		; Read it
20$:	mov	r4,v$bptr(r4)		; Create a pointer to the byte
	add	#v$buff,v$bptr(r4)
	add	r3,v$bptr(r4)
	mov	#512.,v$bcnt(r4)	; Compute the count remaining
	sub	r3,v$bcnt(r4)
	jmp	cret$			; Back we go
; acnt = read(fd,buf,buflen)
;
;	fd		file descriptor
;	buf		address of buffer
;	buflen		buffer length in bytes
;
;	acnt		the number of bytes actually transfered
read::
	jsr	r5,csv$			; Save the registers
	mov	c$pmtr(r5),r4		; Get IOV pointer
	mov	c$pmtr+4(r5),r0		; Get length in bytes
	mov	c$pmtr+2(r5),r1		; Get address of user buffer
10$:	mov	v$bcnt(r4),r2		; Get count remaining in block buffer
	mov	v$bptr(r4),r3		; Get address of block buffer
15$:	dec	r0			; Need more bytes?
	blt	99$			; No...done
	dec	r2			; Are there more bytes?
	blt	20$			; No...try next block
	movb	(r3)+,(r1)+		; Copy a byte into user buffer
	br	15$
20$:	inc	r0			; Backup the byte count
	bit	#vf$bzy,v$flag(r4)	; Current buffer need writing?
	beq	25$			; No...
	jsr	pc,bwrite		; Write current block
	bcs	rwerr			; Branch if write failed
25$:	inc	v$bnbr(r4)		; Bump the block number
	jsr	pc,bread		; Read next block
	bcs	rwerr			; Branch if the read failed
	br	10$			; Continue
99$:	mov	r2,v$bcnt(r4)		; Save remaining byte count
	mov	r3,v$bptr(r4)		; Save remaining byte pointer
	mov	c$pmtr+4(r5),r0		; Success, return full count
	jmp	cret$			; Back we go
; acnt = write(fd,buf,buflen)
;
;	fd		file descriptor
;	buf		address of buffer
;	buflen		buffer length in bytes
;
;	acnt		the number of bytes actually transfered
write::
	jsr	r5,csv$			; Save the registers
	mov	c$pmtr(r5),r4		; Get IOV pointer
	mov	c$pmtr+4(r5),r0		; Get length in bytes
	mov	c$pmtr+2(r5),r1		; Get address of user buffer
10$:	mov	v$bcnt(r4),r2		; Get count remaining in block buffer
	mov	v$bptr(r4),r3		; Get address of block buffer
15$:	dec	r0			; More bytes?
	blt	99$			; No...done
	dec	r2			; More room?
	blt	20$			; No...try next block
	movb	(r1)+,(r3)+		; Copy a byte into buffer
	bis	#vf$bzy,v$flag(r4)	; Set the buffer buzy flag
	br	15$
20$:	inc	r0			; Backup the byte count
	bit	#vf$bzy,v$flag(r4)	; Current buffer need writing?
	beq	25$			; No...
	jsr	pc,bwrite		; Write current block
	bcs	rwerr			; Branch if write failed
25$:	inc	v$bnbr(r4)		; Bump the block number
	jsr	pc,bread		; Read next block
	bcs	rwerr			; Branch if the read failed
	br	10$			; Continue
99$:	mov	r2,v$bcnt(r4)		; Save remaining byte count
	mov	r3,v$bptr(r4)		; Save remaining byte pointer
	mov	c$pmtr+4(r5),r0		; Success, return full count
	jmp	cret$			; Back we go

; error handler for read and write
rwerr:	mov	c$pmtr+4(r5),r1		; Get full count
	sub	r1,r0			; Compute count transfered
    	jmp	cret$			; Back we go
; block read routine

bread:
	mov	r0,-(sp)		; Save R0
	clr	-(sp)			; Make an arg block for .READW
	mov	#256.,-(sp)		; Get the block length in words
	mov	r4,-(sp)		; Get address of block buffer
	add	#v$buff,(sp)
	mov	v$bnbr(r4),-(sp)	; Get the block number
	mov	#10*400,-(sp)		; .READW function code
	bisb	v$lun(r4),(sp)		; Channel number
	mov	sp,r0			; R0 -> arg block
	emt	375			; .READW
	bcs	blkerr			; Error...
	add	#5*2,sp			; Clean the stack
	mov	#512.,v$bcnt(r4)	; Reset the count remaining
	mov	r4,v$bptr(r4)		; Reset the buffer pointer
	add	#v$buff,v$bptr(r4)
	bic	#vf$bzy,v$flag(r4)	; Clear buzy bit
	mov	(sp)+,r0		; Restore R0
	clc				; Success return
	rts	pc
; block write routine

bwrite:
	mov	r0,-(sp)		; Save R0
	clr	-(sp)			; Make an arg block for .WRITW
	mov	#256.,-(sp)		; Get the block length in words
	mov	r4,-(sp)		; Get address of block buffer
	add	#v$buff,(sp)
	mov	v$bnbr(r4),-(sp)	; Get the block number
	mov	#11*400,-(sp)		; .WRITW function code
	bisb	v$lun(r4),(sp)		; Channel number
	mov	sp,r0			; R0 -> arg block
	emt	375			; .WRITW
	bcs	blkerr			; Error...
	add	#5*2,sp			; Clean the stack
	mov	#512.,v$bcnt(r4)	; Reset the count remaining
	mov	r4,v$bptr(r4)		; Reset the buffer pointer
	add	#v$buff,v$bptr(r4)
	bic	#vf$bzy,v$flag(r4)	; Clear buzy bit
	mov	(sp)+,r0		; Restore R0
	clc				; Success return
	rts	pc

blkerr:	add	#5*2,sp			; Clean the stack on errors
	movb	@#52,r0			; Get the error code
	beq	10$			; Br if end of file
	bis	#vf$err,(r4)		; Set error bit
10$:	bis	#vf$eof,(r4)		; Always set eof bit
	movb	ioerr(r0),$$ferr	; Save the error code
	mov	(sp)+,r0		; Restore r0
	sec				; Failure return
	rts	pc

	.end
