format pe gui 4.0
entry start

include '%fasminc%\win32ax.inc'

BUFF_SIZE	= 256

section '.rdata' data readable writeable

  figure1	dq 0.003
  figure2	dq -0.003
  figure3	dq 1234.567
  figure4	dq -1234.567
  figure5	dq 123456.789
  figure6	dq -123456.789

  zero		dq 0.0
  z1		dq 0.01
  z3		dq 0.03
  d1		dq 0.1
  one		dq 1.0
  ten		dq 10.0
  mten		dq -10.0
  nine		dq 9999.9

  szMinus	db "-",0
  szNullDot	db "0.",0
  szNull	db "0",0
  szDot 	db ".",0
  szExp 	db "E",0

  digits	db "0123456789ABCDEF",0

section '.data' readable writeable

  szBuffer	rb BUFF_SIZE

section '.text' code readable writable executable

  ; -------------------------------------------------
  ;
  ; entry-point
  ;
  ; -------------------------------------------------

  start:
	stdcall _ftoa,double [figure1],szBuffer
	invoke	MessageBox,NULL,szBuffer,szBuffer,MB_OK+MB_ICONINFORMATION

	stdcall _ftoa,double [figure2],szBuffer
	invoke	MessageBox,NULL,szBuffer,szBuffer,MB_OK+MB_ICONINFORMATION

	stdcall _ftoa,double [figure3],szBuffer
	invoke	MessageBox,NULL,szBuffer,szBuffer,MB_OK+MB_ICONINFORMATION

	stdcall _ftoa,double [figure4],szBuffer
	invoke	MessageBox,NULL,szBuffer,szBuffer,MB_OK+MB_ICONINFORMATION

	stdcall _ftoa,double [figure5],szBuffer
	invoke	MessageBox,NULL,szBuffer,szBuffer,MB_OK+MB_ICONINFORMATION

	stdcall _ftoa,double [figure6],szBuffer
	invoke	MessageBox,NULL,szBuffer,szBuffer,MB_OK+MB_ICONINFORMATION

	invoke	ExitProcess,NULL

  ; -------------------------------------------------
  ;
  ; convert double or float to ascii with proper
  ; rounding and formatting
  ;
  ; -------------------------------------------------

  proc	_ftoa uses ebx esi edi,hx:QWORD,hstr
  locals
	hdecm	dd ?
  endl

	mov	esi,[hstr]
	xor	ebx,ebx
	xor	edi,edi
	cmp	esi,ebx
	mov	[hdecm],ebx
	je	.out
	fld	[zero]
	fld	[hx]
	fucompp
	fnstsw	ax
	test	ah,68
	jp	@F
	invoke	lstrcpy,esi,szNull
	jmp	.out
  @@:
	fld	[hx]
	fcomp	[zero]
	fnstsw	ax
	test	ah,5
	jp	@F
	mov	ebx,1
	fld	[hx]
	fchs
	fstp	[hx]
  @@:
	fld	[hx]
	fcomp	[z1]
	fld	[hx]
	fnstsw	ax
	test	ah,5
	jp	.a
	fcomp	[d1]
	fnstsw	ax
	test	ah,5
	jp	.conv
  @@:
	fld	[hx]
	dec	edi
	fmul	[ten]
	fstp	[hx]
	fld	[hx]
	fcomp	[d1]
	fnstsw	ax
	test	ah,5
	jnp	@B
	jmp	.conv
  .a:
	fcomp	[nine]
	fnstsw	ax
	test	ah,65
	jne	.conv
	fld	[hx]
	fcomp	[ten]
	fnstsw	ax
	test	ah,1
	jne	.conv
  @@:
	fld	[hx]
	inc	edi
	fdiv	[ten]
	fstp	[hx]
	fld	[hx]
	fcomp	[ten]
	fnstsw	ax
	test	ah,1
	je	@B
  .conv:
	lea	edx,[hdecm]
	stdcall _cvt,double [hx],3,edx,esi
	mov	eax,[hdecm]
	stdcall _formatstring,esi,eax,ebx,edi
  .out:
	ret
  endp

  ; -------------------------------------------------
  ;
  ; format ascii figure according to decimal place
  ; and exponent
  ;
  ; -------------------------------------------------

  proc	_formatstring uses ebx esi edi,hstr,hdec,hsign,hexp
  locals
	buf1	rb 64
	buf2	rb 64
  endl

	xor	eax,eax
	mov	[buf1],al
	mov	[buf2],al
	mov	eax,[hsign]
	test	eax,eax
	je	@F
	lea	eax,[buf1]
	invoke	lstrcat,eax,szMinus

  @@:
	mov	esi,[hdec]
	test	esi,esi
	jg	.b
	lea	ecx,[buf1]
	invoke	lstrcat,ecx,szNullDot
	test	esi,esi
	jge	.a
	neg	esi
  @@:
	lea	edx,[buf1]
	invoke	lstrcat,edx,szNull
	dec	esi
	jne	@B
  .a:
	mov	ebx,[hstr]
	lea	eax,[buf1]
	invoke	lstrcat,eax,ebx
	jmp	.d
  .b:
	mov	ebx,[hstr]
	stdcall _strlen_fog,ebx
	lea	ecx,[buf1]
	mov	edi,eax
	stdcall _strncat,ecx,ebx,esi
	cmp	edi,esi
	je	.d
	lea	edx,[buf1]
	invoke	lstrcat,edx,szDot
	lea	eax,[ebx+esi]
	lea	ecx,[buf1]
	invoke	lstrcat,ecx,eax
  .d:
	lea	edx,[buf1]
	stdcall _strlen_fog,edx
	dec	eax
	je	.c
  @@:
	cmp	byte [buf1+eax],'0'
	jne	.c
	dec	eax
	mov	byte [buf1+eax+1],0
	jne	@B

  .c:
	mov	cl,byte [buf1+eax]
	cmp	cl,'.'
	lea	eax,[buf1+eax]
	jne	@F
	mov	byte [eax],0
  @@:
	mov	eax,[hexp]
	test	eax,eax
	je	@F
	lea	ecx,[buf2]
	stdcall _itoa,eax,ecx
	lea	edx,[buf1]
	invoke	lstrcat,edx,szExp
	lea	eax,[buf2]
	lea	ecx,[buf1]
	invoke	lstrcat,ecx,eax
  @@:
	lea	edx,[buf1]
	invoke	lstrcpy,ebx,edx
  .out:
	ret
  endp

  ; -------------------------------------------------
  ;
  ; convert double/float to a string with proper
  ; rounding
  ;
  ; -------------------------------------------------

  proc	_cvt uses ebx esi edi, harg:QWORD,hdigits,hdecpt,hbuf
  locals
	r2	dd ?
	fi	dq ?
	fj	dq ?
	tmp	dq ?
  endl

	mov	eax,[hdigits]
	xor	esi,esi
	cmp	eax,esi
	jge	@F
	mov	[hdigits],esi
	jmp	.a
  @@:
	cmp	eax,BUFF_SIZE-1
	jl	.a
	mov	[hdigits],BUFF_SIZE-2
  .a:
	mov	ebx,[hbuf]
	mov	[r2],esi
	mov	edi,ebx
	fld	[harg]
	fcomp	[zero]
	fnstsw	ax
	test	ah,5
	jp	@F
	fld	[harg]
	fchs
	fstp	[harg]
  @@:
	lea	eax,[fi]
	stdcall _modf,double [harg],eax
	fstp	[harg]
	fld	[zero]
	fld	[fi]
	fucompp
	fnstsw	ax
	test	ah,68
	jnp	.int_is_zero
	lea	esi,[ebx+BUFF_SIZE]
  @@:
	fld	[fi]
	fdiv	[ten]
	fstp	[tmp]
	lea	ecx,[fi]
	stdcall _modf,double [tmp],ecx
	fadd	[z3]
	fmul	[mten]
	fistp	[tmp]
	dec	esi
	mov	dl,byte [tmp]
	mov	al,'0'
	sub	al,dl
	mov	[esi],al
	mov	eax,[r2]
	inc	eax
	mov	[r2],eax
	fld	[zero]
	fld	[fi]
	fucompp
	fnstsw	ax
	test	ah,68
	jp	@b
	lea	eax,[ebx+BUFF_SIZE]
	cmp	esi,eax
	jae	.b
  @@:
	mov	cl,[esi]
	mov	[edi],cl
	inc	edi
	inc	esi
	cmp	esi,eax
	jb	@B
  .b:
	mov	esi,[r2]
  .j:
	mov	edx,[hdigits]
	mov	eax,[r2]
	mov	ecx,[hdecpt]
	add	esi,edx
	add	esi,ebx
	cmp	esi,ebx
	mov	[ecx],eax
	jae	.h
	mov	byte [ebx],0
	jmp	.out

  .int_is_zero:
	fld	[harg]
	fcomp	[zero]
	fnstsw	ax
	test	ah,65
	jnz	.j
	fld	[harg]
	fmul	[ten]
	fstp	[fj]
	fld	[fj]
	fcomp	[one]
	fnstsw	ax
	test	ah,5
	jp	.j
  @@:
	dec	esi
	fld	[fj]
	fstp	[harg]
	fld	[fj]
	fmul	[ten]
	fstp	[fj]
	fld	[fj]
	fcomp	[one]
	fnstsw	ax
	test	ah,5
	jnp	@B
	mov	[r2],esi
	jmp	.j
  .h:
	cmp	edi,esi
	ja	.c
  @@:
	lea	eax,[ebx+BUFF_SIZE]
	cmp	edi,eax
	jae	.c
	lea	ecx,[fj]
	fld	[harg]
	fmul	[ten]
	fstp	[harg]
	stdcall _modf,double [harg],ecx
	mov	ecx,[hdecpt]
	fstp	[harg]
	fld	[fj]
	fistp	[tmp]
	mov	dl,byte [tmp]
	add	dl,'0'
	mov	[edi],dl
	inc	edi
	cmp	edi,esi
	jbe	@B
  .c:
	lea	eax,[ebx+BUFF_SIZE]
	cmp	esi,eax
	jb	@F
	mov	byte [ebx+255],0
	jmp	.out

  @@:
	mov	dl,[esi]
	add	dl,5
	mov	eax,esi
	mov	[esi],dl
	cmp	dl,'9'
	jle	.d
  .g:
	mov	byte [esi],'0'
	cmp	esi,ebx
	jbe	.e
	mov	dl,[esi-1]
	dec	esi
	inc	dl
	mov	[esi],dl
	jmp	.f
  .e:
	mov	byte [esi],'1'
	mov	edi,[ecx]
	inc	edi
	cmp	eax,ebx
	mov	[ecx],edi
	jbe	@F
	mov	byte [eax],'0'
  @@:
	inc	eax
  .f:
	cmp	byte [esi],'9'
	jg	.g
  .d:
	mov	byte [eax],0
  .out:
	mov	eax,ebx
	ret
  endp

  ; -------------------------------------------------
  ;
  ; return fractional part in st0 and integer
  ; part in y (pointer to a qword)
  ;
  ; -------------------------------------------------

  proc	_modf uses edi, x:QWORD,y
  locals
	cw1	dw ?
	cw2	dw ?
  endl
	mov	edi,[y]
	fnstcw	[cw1]
	fwait
	mov	ax,[cw1]
	or	ax,110000111111b
	mov	[cw2],ax
	fldcw	[cw2]
	fwait
	fld	[x]
	frndint
	fstp	qword [edi]
	fwait
	fld	[x]
	fsub	qword [edi]
	fldcw	[cw1]
	fwait
	ret
  endp

  ; -------------------------------------------------
  ;
  ; integer to ascii conversion (reverend)
  ;
  ; -------------------------------------------------

  proc	_itoa uses ebx esi edi, number,result_buffer
  locals
	temp_buffer		      rb 32+1
  endl

	push	10
	pop	esi
	lea	edi,[temp_buffer+32]
	mov	ebx,digits
	cmp	esi,16
	ja	.error
	std
	xor	al,al
	stosb
	mov	eax,[number]
	test	eax,80000000h
	jz	@F
	neg	eax
  @@:
	xor	edx,edx
	idiv	esi
	xchg	eax,edx
	xlatb
	stosb
	xchg	eax,edx
	test	eax,eax
	jnz	@B
	lea	esi,[edi+1]
	mov	edi,[result_buffer]
	cld
	test	[number],80000000h
	jz	@F
	mov	al,'-'
	stosb
  @@:
	lodsb
	stosb
	test	al,al
	jnz	@B
	sub	edi,[result_buffer]
	lea	eax,[edi-1]
	stc
	jmp	.theend
  .error:
	clc
  .theend:
	cld
	ret
  endp

  ; -------------------------------------------------
  ;
  ; return length of hstr string in eax (Agner Fog)
  ; pretty fast algorithm
  ;
  ; -------------------------------------------------

  proc	_strncat uses ebx esi edi, hfront,hback,hcount
	mov	esi,[hfront]
	stdcall _strlen_fog,esi
	mov	edx,eax
	add	edx,esi
	mov	edi,[hcount]
	test	edi,edi
	jz	.out_null
	mov	esi,[hback]
  @@:
	mov	cl,[esi]
	mov	[edx],cl
	dec	edi
	inc	edx
	inc	esi
	test	cl,cl
	jz	.out
	test	edi,edi
	jnz	@B
  .out_null:
	xor	al,al
	mov	byte [edx],al
  .out:
	ret
  endp

  ; -------------------------------------------------
  ;
  ; return length of hstr string in eax (Agner Fog)
  ; pretty fast algorithm
  ;
  ; -------------------------------------------------

  proc	_strlen_fog uses ebx esi edi, hstr
	mov	eax,[hstr]
	lea	edx,[eax+3]
  @@:
	mov	ebx,[eax]
	add	eax,4
	lea	ecx,[ebx-01010101h]
	not	ebx
	and	ecx,ebx
	and	ecx,80808080h
	jz	@B
	test	ecx,00008080h
	jnz	@F
	shr	ecx,16
	add	eax,2
  @@:
	shl	cl,1
	sbb	eax,edx
	ret
  endp

  ; -------------------------------------------------
  ;
  ; fast memory copying algorithm (tuned asmpack ver)
  ; qword -> dword -> byte
  ;
  ; -------------------------------------------------

  proc	_memcpy_fast uses esi edi, hdst,hsrc,hsize
	mov	eax,[hsize]
	mov	edi,[hdst]
	mov	esi,[hsrc]
	mov	ecx,eax
	shr	ecx,3
	jz	.next1
  @@:
	movq	mm0,qword [esi]
	movq	qword [edi],mm0
	add	esi,8
	add	edi,8
	dec	ecx
	jnz	@B
  .next1:
	mov	ecx,eax
	and	ecx,7
	shr	ecx,2
	jz	.next2
  @@:
	mov	edx,[esi]
	mov	[edi],edx
	add	esi,4
	add	edi,4
	dec	ecx
	jnz	@B
  .next2:
	and	eax,3
	jz	.out
  @@:
	mov	dl,byte [esi]
	mov	byte [edi],dl
	inc	esi
	inc	edi
	dec	eax
	jnz	@B
  .out:
	sub	edi,[hsize]
	mov	eax,edi
	ret
  endp

section '.idata' import data readable writeable

  library	kernel32,'kernel32.dll',\
		user32,'user32.dll',\
		gdi32,'gdi32.dll',\
		comdlg32,'comdlg32.dll',\
		advapi32,'advapi32.dll'

  include	'%fasminc%\api\kernel32.inc'
  include	'%fasminc%\api\user32.inc'
  include	'%fasminc%\api\gdi32.inc'
  include	'%fasminc%\api\comdlg32.inc'
  include	'%fasminc%\api\advapi32.inc'

; eof