;	Additional runtime support routines for T3X under DOS.
;	Copyright (C) 1997,1998,1999 Nils M Holm.
;	See the file LICENSE for conditions of use.

	.bss
	.globl	_GV_
Input:	dw	*1
Output:	dw	*1
_GV_:	dw	*100
tmp:	dw	*1

	.text
	.globl	__exit
	.globl	_TXINIT

_pack_:	push	bp		; PACK(V,S)
	mov	bp,sp
	mov	si,[bp+6]	; V
	mov	di,[bp+4]	; S
	mov	dx,di
	cld
pknext:	lodsw
	stosb
	or	ax,ax
	jnz	pknext
	sub	di,dx
	inc	di
	shr	di,1
	mov	ax,di
	pop	bp
	ret

_unpack_:			; UNPACK(S,V)
	push	bp
	mov	bp,sp
	mov	si,[bp+6]	; S
	mov	di,[bp+4]	; V
	mov	dx,si
	cld
	xor	ah,ah
upknext:lodsb
	stosw
	or	ax,ax
	jnz	upknext
	sub	si,dx
	mov	ax,si
	pop	bp
	ret

__exit:	mov	bp,sp		; cdecl __exit(n)
	mov	ax,[bp+2]	; n
	mov	ah,$4C
	int	$21
;	ret		; we'll hopefully never get here...

length:	push	bp		; cdecl length(s)
	mov	bp,sp
	mov	di,[bp+4]	; s
	mov	dx,di
	xor	ax,ax
	xor	cx,cx
	dec	cx
	cld
	repnz
	scasw
	sub	di,dx
	shr	di,1
	dec	di
	mov	ax,di
	pop	bp
	ret

badgv:
	push	bp
	mov	bp,sp

	.data
UI_msg:	db	"LIBTX: uninitialized interface\n"
	db	0

	.text
	mov	ax,2
	push	ax
	mov	ax,offset UI_msg
	push	ax
	mov	ax,31
	push	ax
	call	_writepacked_
	add	sp,6
	xor	ax,ax
	push	ax
	call	__exit
	;; NOTREACHED
	ret

_aton_:	push	bp		; ATON(S)
	mov	bp,sp
	mov	si,[bp+4]	; S
	cld
sknext:	lodsw
	cmp	al,'\s'
	jz	sknext
	cmp	al,'\t'
	jz	sknext
	cmp	al,'\n'
	jz	sknext
	cmp	al,'\r'
	jz	sknext
	cmp	al,'\f'
	jz	sknext
	xor	bx,bx
	sub	si,2
	mov	ax,[si]
	cmp	ax,'-'
	jz	dosign
	cmp	ax,'%'
	jz	dosign
	jmps	nominus
dosign:	add	si,2
	not	bx
	jmps	endsign
nominus:cmp	ax,'+'
	jnz	endsign
	add	si,2
endsign:xor	di,di
	mov	cx,10
	xor	ah,ah
parse:	lodsw
	cmp	ax,'0'
	jl	epars
	cmp	ax,'9'
	jg	epars
	sub	ax,'0'
	xchg	ax,di
	mul	cx
	xchg	di,ax
	add	di,ax
	jmps	parse
epars:	or	bx,bx
	jz	nosign
	neg	di
nosign:	mov	ax,di
	pop	bp
	ret

	.bss
nbuf:	dw	*258

	.text
_ntoa_:	push	bp		; NTOA(V,W)
	mov	bp,sp
	mov	si,[bp+6]	; V
	xor	bx,bx
	cmp	si,0
	jge	notneg
	neg	si
	not	bx
notneg:	xor	ax,ax
	mov	di,offset nbuf
	add	di,512
	std
	stosw
	mov	cx,10
cnvnxt:	mov	ax,si
	xor	dx,dx
	div	cx
	mov	si,ax
	mov	ax,dx
	add	ax,'0'
	stosw
	mov	ax,[bp+4]
	dec	ax
	mov	[bp+4],ax
	or	si,si
	jnz	cnvnxt
	or	bx,bx
	jz	psign
	mov	ax,'-'
	stosw
	mov	ax,[bp+4]
	dec	ax
	mov	[bp+4],ax
psign:	mov	cx,[bp+4]
	cmp	cx,0
	jle	nofill
	mov	ax,'\s'
	rep
	stosw
nofill:	mov	ax,di
	inc	ax
	inc	ax
	pop	bp
	ret

_open_:	push	bp		; OPEN(FILE,MODE)
	mov	bp,sp
	sub	sp,512
	mov	ax,[bp+6]	; FILE
	push	ax
	mov	ax,-512		; buffer
	add	ax,bp
	push	ax
	call	_pack_
	add	sp,4
	mov	ax,[bp+4]	; MODE
	cmp	ax,1
	jnz	mode023
	mov	ax,$3C00	; DOS: create file
	mov	dx,-512		; buffer
	add	dx,bp
	xor	cx,cx
	int	$21
	jnc	opened
	mov	ax,-1
	jmps	endopen
mode023:
	cmp	ax,0
	jz	doopen
	cmp	ax,2
	jz	doopen
	cmp	ax,3
	jz	doopen
	mov	ax,-1
	jmp	endopen
doopen:
	mov	ax,[bp+4]	; MODE
	or	ax,$3D00	; DOS: open file
	mov	dx,-512		; buffer
	add	dx,bp
	int	$21
	jnc	opened
	mov	ax,-1
	jmps	endopen
opened:	cmp	ax,0
	jl	endopen
	mov	bx,[bp+4]	; MODE
	cmp	bx,3
	jnz	endopen
	push	ax		; REPOSITION(FD,0,0,SEEK_END)
	xor	ax,ax
	push	ax
	push	ax
	mov	ax,2
	push	ax
	call	_reposition_
	add	sp,6
	pop	ax
endopen:
	add	sp,512
	pop	bp
	ret

_close_:			; CLOSE(FD)
	push	bp
	mov	bp,sp
	mov	ax,$3E00	; DOS: close fd
	mov	bx,[bp+4]	; FD
	int	$21
	jc	iofail
	xor	ax,ax
	jmp	endcl
iofail:	mov	ax,-1
endcl:	pop	bp
	ret

_erase_:			; ERASE(S)
	push	bp
	mov	bp,sp
	sub	sp,512
	mov	ax,[bp+4]	; S
	push	ax
	mov	ax,-512		; buffer
	add	ax,bp
	push	ax
	call	_pack_
	add	sp,4
	mov	dx,-512
	add	dx,bp
	mov	ax,$4100	; DOS: erase file
	int	$21
	jnc	iook
	add	sp,512
	jmp	iofail
iook:
	xor	ax,ax
	add	sp,512
	pop	bp
	ret

_select_:			; SELECT(PORT,FD)
	push	bp
	mov	bp,sp
	mov	bx,[bp+4]	; FD
	mov	ax,[bp+6]	; PORT
	or	ax,ax
	jz	slcin
	mov	ax,Output
	mov	Output,bx
	jmps	endslc
slcin:
	mov	ax,Input
	mov	Input,bx
endslc:	pop	bp
	ret

_reads_:			; READS(S,N)
	push	bp
	mov	bp,sp
	sub	sp,1026
	mov	ax,Input	; READPACKED(Input, buffer, N)
	push	ax
	mov	ax,-1026	; buffer
	add	ax,bp
	push	ax
	mov	ax,[bp+4]	; N
	push	ax
	call	_readpacked_
	mov	tmp,ax
	add	sp,6
	cmp	ax,0
	jge	rdok
	mov	ax,-1
	jmp	endrds
rdok:	mov	si,-1026	; buffer::(bytes_read)
	add	si,bp
	mov	di,[bp+6]	; S
	mov	cx,tmp
	or	cx,cx
	jz	nounpk
	cld
	xor	ah,ah
rdupk:	lodsb
	stosw
	loopz	rdupk
nounpk:	xor	ax,ax
	stosw
endrds:	add	sp,1026
	pop	bp
	mov	ax,tmp
	ret

_writes_:			; WRITES(S)
	push	bp
	mov	bp,sp
	sub	sp,1026
	mov	ax,[bp+4]	; S
	push	ax
	mov	ax,-1026	; buffer
	add	ax,bp
	push	ax
	call	_pack_
	add	sp,4
	mov	ax,Output	; WRITEPACKED(Output, buffer)
	push	ax
	mov	ax,-1026
	add	ax,bp
	push	ax
	mov	ax,[bp+4]	; S
	push	ax
	call	length
	pop	cx
	push	ax
	call	_writepacked_
	add	sp,1032
	pop	bp
	ret

_newline_:			; NEWLINE()
	push	bp
	mov	bp,sp

	.data
NL:	db	13, 10, 0, 0

	.text
	mov	ax,Output
	push	ax
	mov	ax,offset NL
	push	ax
	mov	ax,2
	push	ax
	call	_writepacked_
	add	sp,6
	pop	bp
	ret

_readpacked_:			; READPACKED(FD,BUF,LEN)
	push	bp
	mov	bp,sp
	mov	ax,$3F00	; DOS: read block
	mov	bx,[bp+8]	; FD
	mov	dx,[bp+6]	; BUF
	mov	cx,[bp+4]	; LEN
	int	$21
	jnc	rdpok
	mov	ax,-1
rdpok:	pop	bp
	ret

_writepacked_:			; WRITEPACKED(FD,BUF,LEN)
	push	bp
	mov	bp,sp
	mov	ax,$4000	; DOS: write block
	mov	bx,[bp+8]	; FD
	mov	dx,[bp+6]	; BUF
	mov	cx,[bp+4]	; LEN
	int	$21
	jnc	wrpok
	mov	ax,-1
wrpok:	pop	bp
	ret

_reposition_:			; REPOSITION(FD,OFFH,OFFL,ORG)
	push	bp
	mov	bp,sp
	mov	ax,[bp+4]	; ORG
	mov	ah,$42		; DOS: move file pointer
	mov	bx,[bp+10]	; FD
	mov	dx,[bp+6]	; OFFL
	mov	cx,[bp+8]	; OFFH
	int	$21
	jnc	mvok
	mov	ax,-1
mvok:
	pop	bp
	ret

_rename_:			; RENAME(OLD,NEW)
	push	bp
	mov	bp,sp
	sub	sp,512
	mov	ax,[bp+6]	; OLD
	push	ax
	mov	ax,-512		; buffer0
	add	ax,bp
	push	ax
	call	_pack_
	add	sp,4
	mov	ax,[bp+4]	; NEW
	push	ax
	mov	ax,-256		; buffer1
	add	ax,bp
	push	ax
	call	_pack_
	add	sp,4
	mov	ax,$5600	; DOS: change directory entry
	mov	dx,-512		; buffer0
	add	dx,bp
	mov	di,-256		; buffer1
	add	di,bp
	int	$21
	jnc	renok
	mov	ax,-1
renok:
	add	sp,512
	pop	bp
	ret

_memcopy_:			; MEMCOPY(D,S,L)
	push	bp
	mov	bp,sp
	mov	di,[bp+8]	;; D
	mov	si,[bp+6]	;; S
	mov	cx,[bp+4]	;; L
	cld
	cmp	di,si
	jz	endmove		;; src == dest
domove:	jb	nmove		;; src < dest ==> normal move
	std
	add	si,cx		;; start at the end
	add	di,cx		;; for reverse copy
	dec	si
	dec	di
nmove:	rep
	movsb			;; doit
endmove:pop	bp
	ret

_memcomp_:			; MEMCOMP(R1,R2,L)
	push	bp
	mov	bp,sp
	mov	di,[bp+8]	; R1
	mov	si,[bp+6]	; R2
	mov	cx,[bp+4]	; L
	cmp	si,di
	jnz	docmp
	xor	ax,ax
	jmps	cmpret
docmp:	inc	cx
	cld
	rep
	cmpsb
	or	cx,cx
	jnz	notequ
	xor	ax,ax
	jmps	cmpret
notequ:	mov	al,[di-1]
	sub	al,[si-1]
	cbw
cmpret:	pop	bp
	ret

_TXINIT:			; _TXINIT() ! internal
	mov	ax,0
	mov	Input,ax
	mov	ax,1
	mov	Output,ax
	mov	ax,offset badgv
	mov	di,offset _GV_
	mov	cx,100
	cld
	rep
	stosw
	mov	di,offset _GV_
	mov	ax,offset _open_
	stosw
	mov	ax,offset _close_
	stosw
	mov	ax,offset _erase_
	stosw
	mov	ax,offset _select_
	stosw
	mov	ax,offset _reads_
	stosw
	mov	ax,offset _writes_
	stosw
	mov	ax,offset _newline_
	stosw
	mov	ax,offset _aton_
	stosw
	mov	ax,offset _ntoa_
	stosw
	mov	ax,offset _pack_
	stosw
	mov	ax,offset _unpack_
	stosw
	mov	ax,offset _readpacked_
	stosw
	mov	ax,offset _writepacked_
	stosw
	mov	ax,offset _reposition_
	stosw
	mov	ax,offset _rename_
	stosw
	mov	ax,offset _memcopy_
	stosw
	mov	ax,offset _memcomp_
	stosw
	ret
