
%macro jzfar 1
	jnz	%%skip
	jmp	%1
%%skip:

%endmacro

[global _writeCursorPosition]
[global _getCursorPosition]
[global _putc]
[global _puts]
[global _printf]
[global _console_scroll]
[global _console_cls]
[global _putHex]
[global _putDec]
[global _putDecu]


;
;void writeCursorPosition(word pos)
;
_writeCursorPosition:
	push	ebp
	mov	ebp, esp

	push	eax
	push	ebx
	push	edx

	mov	eax, [ebp+8]	;cursor position in ax

	mov	bl, al
	mov	dx, 0x03D4
	mov	al, 0x0E
	out	dx, al

	inc	dx
	mov	al, ah
	out	dx, al

	dec	dx
	mov	al, 0x0F
	out	dx, al

	inc	dx
	mov	al, bl
	out	dx, al

	pop	edx
	pop	ebx
	pop	eax
	pop	ebp

	ret


;
;word getCursorPosition()
;
_getCursorPosition:
	push	ebx
	push	edx

	xor	eax, eax
	mov	dx, 0x03D4
	mov	al, 0x0E
	out	dx, al

	inc	dx
	in	al, dx
	mov	bl, al

	dec	dx
	mov	al, 0x0F
	out	dx, al

	inc	dx
	in	al, dx
	mov	ah, bl

	pop	edx
	pop	ebx

	ret


;
;int putc(int chr)
;
_putc:
	push	ebp
	mov	ebp, esp
	push	ebx
	push	ecx
	push	edx

	call	_getCursorPosition
	mov	ebx, eax
	mov	ecx, ebx

	mov	eax, [ebp+8]			;al=character
	cmp	al, 10				;newline
	jz	putc_newline
	cmp	al, 9				;tab
	jz	putc_tab	

	shl	ebx, 1
	add	ebx, 0xb8000
	mov	ah, 0x07
	mov	[ebx], ax
	mov	eax, ecx
	inc	eax
	cmp	eax, 2000
	jnz	putc_writeit2
	call	_console_scroll
	mov	eax, 2000-80
putc_writeit2:
	push	eax
	call	_writeCursorPosition
	add	esp, 4
	jmp	putc_done

putc_newline:
	mov	eax, ebx			;eax = cursor position
	mov	ebx, 80
	xor	edx, edx
	div	bx				;ax=dx:ax/bx, dx=remainder
	mov	bx, 80
	sub	bx, dx
	mov	eax, ecx
	add	eax, ebx			;eax = new cursor position
	cmp	eax, 2000
	jnz	putc_newline_writeit2
	call	_console_scroll
	mov	eax, 2000-80			;beginning of last row
putc_newline_writeit2:
	push	eax
	call	_writeCursorPosition
	add	esp, 4
	jmp	putc_done

putc_tab:
	mov	eax, ebx			;eax = cursor position
	mov	ebx, 8
	div	bl				;al=ax/bl, ah=remainder
	xor	edx, edx
	mov	dl, ah
	mov	bx, 8
	sub	bx, dx
	mov	eax, ecx
	add	eax, ebx			;eax = new cursor position
	cmp	eax, 2000
	jnz	putc_tab_writeit2
	call	_console_scroll
	mov	eax, 2000-80			;beginning of last row
putc_tab_writeit2:
	push	eax
	call	_writeCursorPosition
	add	esp, 4

putc_done:
	pop	edx
	pop	ecx
	pop	ebx
	pop	ebp

	ret



;
;void printf(char *fmt, ... )
;
_printf:
	push	ebp
	mov	ebp, esp
	pusha
	mov	ebx, [ebp+8]			;ebx = position in format string
	mov	esi, ebp
	add	esi, 12				;esi = to next variable arg
	xor	ecx, ecx			;ecx used if we encounter a '%'
printf_loop:
	mov	al, [ebx]
	inc	ebx
	cmp	al, 0
	jzfar	printf_done
	cmp	ecx, 1
	jz	printf_special
	cmp	al, '%'
	jzfar	printf_percent

	push	eax
	call	_putc
	add	esp, 4
	jmp	printf_loop

printf_special:
	xor	ecx, ecx
	cmp	al, 'd'
	jz	printf_decimal
	cmp	al, 'u'
	jz	printf_decimalu
	cmp	al, 'x'
	jz	printf_hex
	cmp	al, '%'
	jz	printf_ppercent
	cmp	al, 's'
	jz	printf_string
	cmp	al, 'c'
	jz	printf_char
	jmp	printf_special_done

printf_decimal:
	mov	eax, [esi]
	push	eax
	call	_putDec
	add	esp, 4
	jmp	printf_special_done

printf_decimalu:
	mov	eax, [esi]
	push	eax
	call	_putDecu
	add	esp, 4
	jmp	printf_special_done

printf_hex:
	mov	eax, [esi]
	push	eax
	call	_putHex
	add	esp, 4
	jmp	printf_special_done

printf_ppercent:
	push	eax
	call	_putc
	add	esp, 4
	jmp	printf_special_done

printf_string:
	mov	eax, [esi]
	push	eax
	call	_puts
	add	esp, 4
	jmp	printf_special_done

printf_char:
	mov	eax, [esi]
	push	eax
	call	_putc
	add	esp, 4
	jmp	printf_special_done

printf_special_done
	add	esi, 4				;point to next extra argument
	jmp	printf_loop

printf_percent:
	mov	ecx, 1
	jmp	printf_loop


printf_done:
	popa
	pop	ebp
	ret



;
;void console_scroll()
;
_console_scroll:
	pusha
	mov	esi, 0xb8000+160
	mov	edi, 0xb8000
	mov	ecx, 960			;(2000-80)/2
console_scroll_loop:
	lodsd
	stosd
	loop	console_scroll_loop
	mov	ax, 0x0720
	mov	ecx, 80
console_scroll_loop2:
	stosw
	loop	console_scroll_loop2
	popa
	ret

;
;void console_cls()
;
_console_cls:
	pusha
	mov	edi, 0xb8000
	mov	ax, 0x0720
	mov	ecx, 2000
console_cls_loop:
	stosw
	loop	console_cls_loop
	push	dword 0
	call	_writeCursorPosition
	add	esp, 4
	popa
	ret

;
;int putHex(dword number)
;
_putHex:
	push	ebp
	mov	ebp, esp
	pusha
	mov	eax, [ebp+8]			;eax = number to print
	xor	ebx, ebx			;we have not printed a character yet
	mov	ecx, 8				;counter for number of characters

putHex_loop:
	push	eax
	push	ecx

	dec	ecx
	shl	ecx, 2				;edx=counter*4 (amount to shift by)
	shr	eax, cl
	and	eax, 0x0F
	cmp	cl, 0
	jz	putHex_notzero			;if number is 0
	cmp	al, 0
	jnz	putHex_notzero
	cmp	bl, 0
	jz	putHex_loop_end
putHex_notzero:
	mov	bl, 1
	add	eax, '0'
	cmp	eax, '9'
	jbe	putHex_dontadjust
	add	eax, 'A'-'9'-1
putHex_dontadjust:
	push	eax
	call	_putc
	add	esp, 4

putHex_loop_end:
	pop	ecx
	pop	eax
	loop	putHex_loop

	popa
	pop	ebp
	ret


;
;int puts(char *str)
;
_puts:
	push	ebp
	mov	ebp, esp
	push	esi
	push	eax
	mov	esi, [ebp+8]			;esi = to string
puts_loop:
	lodsb
	cmp	al, 0
	jz	puts_done
	push	eax
	call	_putc
	add	esp, 4
	jmp	puts_loop

puts_done:
	pop	eax
	pop	esi
	pop	ebp
	ret






_putDecu:
	push	ebp
	mov	ebp, esp
	sub	esp, 24
	mov	DWORD [ebp-4], 1
	mov	BYTE [ebp-5], 0
L2:
	mov	edx, DWORD [ebp+8]
	mov	eax, -858993459
	mul	edx
	mov	eax, edx
	shr	eax, 3
	cmp	eax, DWORD [ebp-4]
	jae	L4
	jmp	L3
L4:
	mov	eax, DWORD [ebp-4]
	mov	edx, eax
	sal	edx, 2
	add	edx, eax
	lea	eax, [edx+edx]
	mov	DWORD [ebp-4], eax
	jmp	L2
L3:
	nop
L5:
	cmp	DWORD [ebp-4], 1
	ja	L7
	jmp	L6
L7:
	mov	edx, DWORD [ebp+8]
	mov	eax, edx
	mov	edx, 0
	div	DWORD [ebp-4]
	mov	DWORD [ebp-12], eax
	mov	al, BYTE [ebp-12]
	mov	BYTE [ebp-5], al
	mov	eax, 0
	mov	al, BYTE [ebp-5]
	imul	eax, DWORD [ebp-4]
	sub	DWORD [ebp+8], eax
	mov	edx, DWORD [ebp-4]
	mov	eax, -858993459
	mul	edx
	mov	eax, edx
	shr	eax, 3
	mov	DWORD [ebp-4], eax
	lea	eax, [ebp-5]
	add	BYTE [eax], 48
	sub	esp, 12
	mov	eax, 0
	mov	al, BYTE [ebp-5]
	push	eax
	call	_putc
	add	esp, 16
	jmp	L5
L6:
	sub	esp, 12
	mov	al, BYTE [ebp+8]
	add	eax, 48
	and	eax, 255
	push	eax
	call	_putc
	add	esp, 16
	leave
	ret




_putDec:
	push	ebp
	mov	ebp, esp
	sub	esp, 24
	cmp	DWORD [ebp+8], 0
	jns	L9
	sub	esp, 12
	push	45
	call	_putc
	add	esp, 16
	neg	DWORD [ebp+8]
L9:
	mov	DWORD [ebp-4], 1
	mov	BYTE [ebp-5], 0
L10:
	mov	eax, DWORD [ebp+8]
	cmp	eax, DWORD [ebp-4]
	jae	L12
	jmp	L11
L12:
	mov	eax, DWORD [ebp-4]
	mov	edx, eax
	sal	edx, 2
	add	edx, eax
	lea	eax, [edx+edx]
	mov	DWORD [ebp-4], eax
	jmp	L10
L11:
	mov	edx, DWORD [ebp-4]
	mov	eax, -858993459
	mul	edx
	mov	eax, edx
	shr	eax, 3
	mov	DWORD [ebp-4], eax
L13:
	cmp	DWORD [ebp-4], 1
	ja	L15
	jmp	L14
L15:
	mov	edx, DWORD [ebp+8]
	mov	eax, edx
	mov	edx, 0
	div	DWORD [ebp-4]
	mov	DWORD [ebp-12], eax
	mov	al, BYTE [ebp-12]
	mov	BYTE [ebp-5], al
	mov	eax, 0
	mov	al, BYTE [ebp-5]
	imul	eax, DWORD [ebp-4]
	sub	DWORD [ebp+8], eax
	mov	edx, DWORD [ebp-4]
	mov	eax, -858993459
	mul	edx
	mov	eax, edx
	shr	eax, 3
	mov	DWORD [ebp-4], eax
	lea	eax, [ebp-5]
	add	BYTE [eax], 48
	sub	esp, 12
	mov	eax, 0
	mov	al, BYTE [ebp-5]
	push	eax
	call	_putc
	add	esp, 16
	jmp	L13
L14:
	sub	esp, 12
	mov	al, BYTE [ebp+8]
	add	eax, 48
	and	eax, 255
	push	eax
	call	_putc
	add	esp, 16
	leave
	ret




