;
; math for sprintf/scanf/atof floating point support
;
	.386p
	.model use32 small
	.code
;
; this basically does NO checking for exceptions.
; It does clear them after the fact :)
; however, I do try to keep everything in bounds before doing any math...
;
;
; rounding is done towards zero...
;
; later I will fix it...
;
; note I AM using log functions rather than a table-driven approach
;
	public __fextract, __fnd, __fpow

;
; get exponent and mantissa and sign
;
; returns 
;  0 = ok vals
;  -1 = nan
;  1 = infinity or denormal
;
; int _fextract(long double *val, int *exp, int *sign);
;
__fextract 	PROC
	enter	4,0
	push	esi
	push	ebx
	fstcw	[ebp-2]
	mov	ax,[ebp-2]
	or	ah,0ch		; round toward zero
	mov	[ebp-4],ax
	fldcw	[ebp-4]

	mov	esi,[ebp + 8]	; get val
	fld	tbyte ptr [esi]

	ftst       		; test to get sign
	fstsw	ax
	sahf
	jnz	dosign		; check for zero (can't take log of zero)
	sub	eax,eax		; if so all vals = 0
	mov	esi,[ebp+12]
	mov	dword ptr [esi],eax
	mov	esi,[ebp+16]
	mov	dword ptr [esi],eax
	jmp	fxxr
dosign:
	mov	eax,1		; nonzero, finally get sign
	jnc	pos
	fabs       		; we will work with positive nums hereafter
	mov	eax,-1
pos:
	mov	esi,[ebp+16]	; store sign
	mov	[esi],eax

	fxam			; retest to get class
	fstsw	ax
	mov	bl,ah
	and	bl,45h
	mov	eax,-1		; assume Nan
	cmp	bl,1
	jz	fxxr
	mov	eax,1		; assume infinite
	cmp	bl,5
	jz	fxxr
	cmp	bl,44h		; denormal
	jz	fxxr

	fldlg2       		; log to base 10
	fxch
	fyl2x
	
	fld	st(0)		; get int part
	frndint
	mov	esi,[ebp+12]
	fist	dword ptr [esi]

	fsubp			; fraction
	fldl2t			; convert back to base 2
	fmulp

	fld	st(0)		; lovely exponentiation
	frndint
	fxch
	fsub	st(0),st(1)
	f2xm1			;
	fld1
	faddp
	fscale
	fxch
	fcomp


	mov	esi,[ebp+8]
	fstp	tbyte ptr [esi]
	sub	eax,eax
fxx:
	fnclex
	fldcw	[ebp-2]
	fwait
	pop	ebx
	pop	esi
	leave
	ret
fxxr:
	fstp	st(0)
	jmp	fxx
__fextract	ENDP
;
; get next digit from mantissa
;
; int _fnd(long double *val);
;
ten	dd	10
__fnd	PROC
	ENTER	8,0
	push	esi

	fstcw	[ebp-2]
	mov	ax,[ebp-2]
	or	ah,0ch		; round toward zero
	mov	[ebp-4],ax
	fldcw	[ebp-4]

	mov	esi,[ebp+8]
	fld	tbyte ptr [esi]

	fld	st(0)		; next digit
	frndint
	fist	dword ptr [ebp-8]

	fsubp			; new mantissa
	fimul	dword ptr [ten]
	fstp	tbyte ptr [esi]

	fnclex
	fldcw	[ebp-2]
	fwait
	pop	esi
	pop	eax		; cute trick to get result :)
	leave
	ret
__fnd	ENDP

;
; calculate a power of 10
;
; long double __fpow(int exp);
;
__fpow	PROC
	enter	4,0
	fstcw	[ebp-2]
	mov	ax,[ebp-2]
	or	ah,0ch		; round toward zero
	mov	[ebp-4],ax
	fldcw	[ebp-4]

	fild	dword ptr [ebp + 8] ; y * log base 2 of 10
	fldl2t
	fmulp

	fld	st(0)		; integral part
	frndint

	fsub	st(1),st(0)
	fxch 			; fractional part

	f2xm1                 	; exponentiate fraction
	fld1			; base 2
	faddp

	fscale  		; now scale in integral part

	fxch			; aren't intel processors a blast?
	fcomp			; have to clear stack

	fnclex
	fldcw	[ebp-2]
	leave
	ret
__fpow	ENDP
	end