;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;	read_line by fbkotler(NASM)
;;	Input:
;;	BX = handle of file to read
read_line:
	pusha

    mov ah, 3Fh          ; read 512 bytes (max)
;  	mov bx, [file_in_handle]
;	mov cx, 512
	mov cx,word[line_buf_len]
    mov dx, line_buf     ; ds presumed set
    int 21h
    jc .readline_done     ; actual error occurred!

    and ax, ax
    jnz .ok_read

	mov byte[si],0
    mov byte[failure],0x0d            ; no more to read
    jmp short .readline_done
.ok_read
    mov cx, ax           ; what we actually read
    mov si, line_buf
.find_newline
    cmp byte [si], 13
    je .got_cr

    cmp byte [si], 10
    je .got_lf

    inc si
    loop .find_newline    ; dec cx and jump back

    mov byte[si],0

    mov byte[ffailure],0x0d                  ; if we get here, no newline found!
    jmp short .readline_done
.got_cr
    cmp byte [si + 1], 10
    jne .got_newline

    dec cx
    jmp short .got_newline
.got_lf
    cmp byte [si + 1], 13    ; unlikely, but I've seen files like this
    jne .got_newline

    dec cx
.got_newline
    mov byte [si], 0
    dec cx
    je .readline_done         ; if this happens, we've read last line
                             ; don't return CF yet - process it,
                             ; but don't try to move the file-pointer
.more
    neg cx
    mov dx, cx
    mov cx, -1
    mov ax, 4201h            ; move file-pointer cx:dx bytes
    int 21h
.readline_done
	popa
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;	Input:
;;	DS:SI = pointer to line buffer
;;	ES:DI = pointer to buffer to write
;;	Output:
;;	CX = chars read
parse_line:
	push si
	push di
	push ax
	push dx

	add si,cx
	xor cx,cx

	jmp short .loop_first

.loop
	inc cx
.loop_first
	lodsb

	cmp al,','
	je short .loop
	cmp al,' '
	je short .loop
	cmp al,9
	je short .loop
	cmp al,';'
	je short .end_coment
	cmp al,13
	je short .end_line
	cmp al,0x27
	je short .loop@string
	cmp al,0x22
	je short .loop@string
	and al,al
	jz short .end_line

	stosb
	jmp short .loop2
.loop@string
	stosb
	mov dl,al
.loop@string1
	inc cx
	lodsb

	stosb

	cmp al,dl
	jne .loop@string1
.loop2
	inc cx
	lodsb

	cmp al,' '
	je short .end
	cmp al,';'
	je short .end
	cmp al,','
	je short .end
	cmp al,9
	je short .end
	cmp al,13
	je short .end
	and al,al
	jz short .end

	stosb
	jmp short .loop2

.end
	xor al,al
	stosb
	pop dx
	pop ax
	pop di
	pop si
	ret
.end_line
	xor al,al
	stosb
	pop dx
	pop ax
	pop di
	pop si
	mov byte[failure],0x0c
	ret
.end_coment
	xor al,al
	stosb
	pop dx
	pop ax
	pop di
	pop si
	mov byte[failure],0x0e
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
test_clips:
	push ax
	push cx

	lodsb
	dec si
	cmp al,'['
	jne .end_not

	call string_len
	add si,cx
	dec si
	lodsb
	sub si,cx
	cmp al,']'
	jne .end_not

	add si,cx
	dec si
	mov byte[ds:si],0
	inc si
	sub si,cx
	inc si

.end
	pop cx
	pop ax
	xor al,al
	ret
.end_not
	pop cx
	pop ax
	mov al,0xff
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;	DS:SI=pointer to read string
;;	Output :
;;	Al = data
format_numbers_8bit:
	push si
	push di
	push cx
	push dx

	xor dl,dl

	lodsb
	dec si

	cmp al,'-'
	jne .start

	inc dl
	inc si
.start
	mov di,hex_pref
	cmpsw
	je .@hex_pref

	dec si
	dec si

	call string_len
	dec cx

	add si,cx
	lodsb
	dec si

	cmp al,'h'
	je .@hex_suf

	cmp al,'b'
	je .@bin_suf

	sub si,cx

	lodsb
	dec si

	cmp al,0x27
	je .@ascii

	cmp al,0x22
	je .@ascii

	cmp al,':'
	jb .@dec

	jmp short .end_error
.@hex_pref
	call hexascii2bin

	jc .end_error

	cmp dl,1
	jne .end

	neg eax

	jmp short .end
.@hex_suf
	mov byte[si],0
	sub si,cx

	call hexascii2bin

	jc .end_error

	cmp dl,1
	jne .end

	neg eax

	jmp short .end
.@bin_suf
	sub si,9

	call ascii_8bytebin2bin

	jmp short .end
.@dec
	call decascii2bin

	cmp dl,1
	jne .end

	neg eax

	jmp short .end
.@ascii
	mov dl,al

	inc si
	lodsb

	push ax
	lodsb
	cmp al,dl
	pop ax

	jne .end_error

.end
	pop dx
	pop cx
	pop di
	pop si
	clc
	ret
.end_error
	pop dx
	pop cx
	pop di
	pop si
	stc
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;	Input :
;;	DS:SI = pointer to read string
;;	Output :
;;	AX = data
format_numbers_16bit:
	push si
	push di
	push cx
	push dx

	xor dl,dl

	lodsb
	dec si
	cmp al,'-'
	jne .start

	inc dl
	inc si
.start
	mov di,hex_pref
	cmpsw
	je .@hex_pref

	dec si
	dec si

	call string_len
	dec cx

	add si,cx
	lodsb
	dec si

	cmp al,'h'
	je .@hex_suf

	cmp al,'b'
	je .@bin_suf

	sub si,cx

	lodsb
	dec si
	cmp al,':'
	jb .@dec

	jmp short .end_error
.@hex_pref
	call hexascii2bin

	jc .end_error

	cmp dl,1
	jne .end

	neg eax

	jmp short .end
.@hex_suf
	mov byte[si],0
	sub si,cx

	call hexascii2bin

	jc .end_error

	cmp dl,1
	jne .end

	neg eax

	jmp short .end
.@bin_suf
	sub si,17

	call ascii_16bytebin2bin

	jmp short .end
.@dec
	call decascii2bin

	cmp dl,1
	jne .end

	neg eax

.end
	pop dx
	pop cx
	pop di
	pop si
	clc
	ret
.end_error
	pop dx
	pop cx
	pop di
	pop si
	stc
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;	Input :
;;	DS:SI=pointer to read string
;;	Output :
;;	EAX = data
format_numbers_32bit:
	push si
	push di
	push cx
	push dx

	xor dl,dl

	lodsb
	dec si

	cmp al,'-'
	jne .start

	inc dl
	inc si
.start
	mov di,hex_pref
	cmpsw
	je .@hex_pref

	dec si
	dec si

	call string_len
	dec cx

	add si,cx
	lodsb
	dec si

	cmp al,'h'
	je .@hex_suf

	cmp al,'b'
	je .@bin_suf

	sub si,cx

	lodsb
	dec si
	cmp al,':'
	jb .@dec

	jmp short .end_error
.@hex_pref
	call hexascii2bin

	jc .end_error

	cmp dl,1
	jne .end

	neg eax

	jmp short .end
.@hex_suf
	mov byte[si],0
	sub si,cx

	call hexascii2bin

	jc .end_error

	cmp dl,1
	jne .end

	neg eax

	jmp short .end
.@bin_suf
	sub si,33

	call ascii_32bytebin2bin

	jmp short .end
.@dec
	call decascii2bin

	cmp dl,1
	jne .end

	neg eax

.end
	pop dx
	pop cx
	pop di
	pop si
	clc
	ret
.end_error
	pop dx
	pop cx
	pop di
	pop si
	stc
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
translate_32bit_reg:
	push si
	push di

	mov di,reg_eax
	call string_cmp
	and ax,ax
	jnz .@ebx

	xor al,al

	jmp short .end
.@ebx
	mov di,reg_ebx
	call string_cmp
	and ax,ax
	jnz .@ecx

	mov al,3

	jmp short .end
.@ecx
	mov di,reg_ecx
	call string_cmp
	and ax,ax
	jnz .@edx

	mov al,1

	jmp short .end
.@edx
	mov di,reg_edx
	call string_cmp
	and ax,ax
	jnz .@esi

	mov al,2

	jmp short .end
.@esi
	mov di,reg_esi
	call string_cmp
	and ax,ax
	jnz .@edi

	mov al,6

	jmp short .end
.@edi
	mov di,reg_edi
	call string_cmp
	and ax,ax
	jnz .@esp

	mov al,7

	jmp short .end
.@esp
	mov di,reg_esp
	call string_cmp
	and ax,ax
	jnz .@ebp

	mov al,4

	jmp short .end
.@ebp
	mov di,reg_esp
	call string_cmp
	and ax,ax
	jnz .@not

	mov al,5

	jmp short .end
.@not
	mov al,0xff
.end
	pop di
	pop si
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
translate_16bit_reg:
	push si
	push di

	mov di,reg_ax
	call string_cmp
	and ax,ax
	jnz .@bx

	xor al,al

	jmp short .end
.@bx
	mov di,reg_bx
	call string_cmp
	and ax,ax
	jnz .@cx

	mov al,3

	jmp short .end
.@cx
	mov di,reg_cx
	call string_cmp
	and ax,ax
	jnz .@dx

	mov al,1

	jmp short .end
.@dx
	mov di,reg_dx
	call string_cmp
	and ax,ax
	jnz .@si

	mov al,2

	jmp short .end
.@si
	mov di,reg_si
	call string_cmp
	and ax,ax
	jnz .@di

	mov al,6

	jmp short .end
.@di
	mov di,reg_di
	call string_cmp
	and ax,ax
	jnz .@sp

	mov al,7

	jmp short .end
.@sp
	mov di,reg_sp
	call string_cmp
	and ax,ax
	jnz .@bp

	mov al,4

	jmp short .end
.@bp
	mov di,reg_sp
	call string_cmp
	and ax,ax
	jnz .@not

	mov al,5

	jmp short .end
.@not
	mov al,0xff
.end
	pop di
	pop si
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
translate_8bit_reg:
	push si
	push di

	mov di,reg_al
	call string_cmp
	and ax,ax
	jnz .@bl

	xor al,al

	jmp short .end
.@bl
	mov di,reg_bl
	call string_cmp
	and ax,ax
	jnz .@cl

	mov al,3

	jmp short .end
.@cl
	mov di,reg_cl
	call string_cmp
	and ax,ax
	jnz .@dl

	mov al,1

	jmp short .end
.@dl
	mov di,reg_dl
	call string_cmp
	and ax,ax
	jnz .@dh

	mov al,2

	jmp short .end
.@dh
	mov di,reg_dh
	call string_cmp
	and ax,ax
	jnz .@bh

	mov al,6

	jmp short .end
.@bh
	mov di,reg_bh
	call string_cmp
	and ax,ax
	jnz .@ah

	mov al,7

	jmp short .end
.@ah
	mov di,reg_ah
	call string_cmp
	and ax,ax
	jnz .@ch

	mov al,4

	jmp short .end
.@ch
	mov di,reg_ch
	call string_cmp
	and ax,ax
	jnz .@not

	mov al,5

	jmp short .end
.@not
	mov al,0xff
.end
	pop di
	pop si
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
translate_seg_reg:
	push si
	push di

	mov di,reg_cs
	call string_cmp
	and ax,ax
	jnz .@ds

	mov al,1

	jmp short .end
.@ds
	mov di,reg_ds
	call string_cmp
	and ax,ax
	jnz .@es

	mov al,3

	jmp short .end
.@es
	mov di,reg_es
	call string_cmp
	and ax,ax
	jnz .@fs

	xor al,al

	jmp short .end
.@fs
	mov di,reg_fs
	call string_cmp
	and ax,ax
	jnz .@gs

	mov al,4

	jmp short .end
.@gs
	mov di,reg_gs
	call string_cmp
	and ax,ax
	jnz .@ss

	mov al,5

	jmp short .end
.@ss
	mov di,reg_ss
	call string_cmp
	and ax,ax
	jnz .@not

	mov al,2

	jmp short .end
.@not
	mov al,0xff
.end
	pop di
	pop si
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
format_address_16bit:
	push si
	push di

	add si,2
	lodsb
	cmp al,':'
	jne near .error
	sub si,3

	push si
	mov di,reg_cs
	cmpsw
	pop si
	jne .seg_ss
	mov al,0x2e
	jmp short .seg_reg@bx
.seg_ss
	push si
	mov di,reg_ss
	cmpsw
	pop si
	jne .seg_ds
	mov al,0x36
	jmp short .seg_reg@bx
.seg_ds
	push si
	mov di,reg_ds
	cmpsw
	pop si
	jne .seg_es
	mov al,0x3e
	jmp short .seg_reg@bx
.seg_es
	push si
	mov di,reg_es
	cmpsw
	pop si
	jne .seg_fs
	mov al,0x26
	jmp short .seg_reg@bx
.seg_fs
	push si
	mov di,reg_fs
	cmpsw
	pop si
	jne .seg_gs
	mov al,0x64
	jmp short .seg_reg@bx
.seg_gs
	push si
	mov di,reg_gs
	cmpsw
	pop si
	jne .error
	mov al,0x65
	jmp short .seg_reg@bx
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.seg_reg@bx
	add si,3

	push ax
	mov di,reg_bx
	call string_cmp
	and ax,ax
	pop ax
	jne .seg_reg@si

	mov ah,7

	jmp	short .end
.seg_reg@si
	push ax
	mov di,reg_si
	call string_cmp
	and ax,ax
	pop ax
	jne .seg_reg@di

	mov ah,4

	jmp	short .end
.seg_reg@di
	push ax
	mov di,reg_di
	call string_cmp
	and ax,ax
	pop ax
	jne .seg_reg@reg_bx_plus_si

	mov ah,5

	jmp short .end
.seg_reg@reg_bx_plus_si
	push ax
	mov di,reg_bx_plus_si
	call string_cmp
	and ax,ax
	pop ax
	jnz .seg_reg@reg_bx_plus_di

	xor ah,ah

	jmp short .end
.seg_reg@reg_bx_plus_di
	push ax
	mov di,reg_bx_plus_di
	call string_cmp
	and ax,ax
	pop ax
	jnz .seg_reg@reg_bp_plus_si

	mov ah,1

	jmp short .end
.seg_reg@reg_bp_plus_si
	push ax
	mov di,reg_bp_plus_si
	call string_cmp
	and ax,ax
	pop ax
	jnz .seg_reg@reg_bp_plus_di

	mov ah,2

	jmp short .end
.seg_reg@reg_bp_plus_di
	push ax
	mov di,reg_bp_plus_di
	call string_cmp
	and ax,ax
	pop ax
	jnz .error

	mov ah,3

.end
	pop di
	pop si
	ret
.error
	mov ax,0xffff
	pop di
	pop si
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;	Input :
;;	CX = pointer to label
;;	AL = type of offset :
;;						1 = normal offset
;;						2 = near jump offset
;;						3 = short jump offset
add_offset2offset_table:
	pusha
	push fs

	mov fs,[mem_offset]
	mov si,word[offset_free]

.type1
	cmp al,1
	jne .type2

	mov ax,word[pointer_write]
	mov byte[fs:si],1
	inc si
	mov word[fs:si],ax
	add si,2
	mov word[fs:si],cx
	add si,2

	mov word[offset_free],si

	jmp .end

.type2
	cmp al,2
	jne .type3

	mov ax,word[pointer_write]
	mov byte[fs:si],2
	inc si
	mov word[fs:si],ax
	add si,2
	mov ax,word[act_org]
	mov word[fs:si],ax
	add si,2
	mov word[fs:si],cx
	add si,2

	mov word[offset_free],si

	jmp .end

.type3
	mov ax,word[pointer_write]
	mov byte[fs:si],3
	inc si
	mov word[fs:si],ax
	add si,2
	mov ax,word[act_org]
	mov word[fs:si],ax
	add si,2
	mov word[fs:si],cx
	add si,2
	mov ax,word[line]
	mov word[fs:si],ax
	add si,2

	mov word[offset_free],si

	jmp .end

.end
	pop fs
	popa
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
create_fileout:
	pusha

	mov es,[mem_label]
	mov fs,[mem_offset]
	mov gs,[mem_fileout]

	xor si,si
.loop
	cmp si,[offset_free]
	je .end

	mov al,byte[fs:si]
	inc si

.loop_type1
	cmp al,1
	jne .loop_type2

	mov di,word[fs:si]		;load offset in file_out to di
	add si,2
	mov bx,word[fs:si]		;load offset of label in label table to bx
	add si,2

	add bx,2
	mov ax,word[es:bx]		;load offset of label from label table to ax

	mov word[gs:di],ax

	jmp .loop

.loop_type2
	cmp al,2
	jne .loop_type3

	mov di,word[fs:si]
	add si,2
	mov cx,word[fs:si]
	add si,2
	mov bx,word[fs:si]
	add si,2

	add bx,2
	mov ax,word[es:bx]

	add cx,di
	add cx,2
	sub ax,cx

	mov word[gs:di],ax

	jmp .loop

.loop_type3
	mov di,word[fs:si]
	add si,2
	mov cx,word[fs:si]
	add si,2
	mov bx,word[fs:si]
	add si,2

	add bx,2
	mov ax,word[es:bx]

	add cx,di
	inc cx
	sub ax,cx

	cmp ax,128
	jg .error

	mov byte[gs:di],al

	add si,2
	jmp .loop

.end
	popa
	ret
.error
	mov ax,word[fs:si]
	mov si,msg_short_jmp_range
	call print_error
	popa
	mov al,0xff
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
hex_pref				db '0x',0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
reg_al					db 'al',0
reg_ah					db 'ah',0
reg_ax					db 'ax',0
reg_eax					db 'eax',0
reg_bl					db 'bl',0
reg_bh					db 'bh',0
reg_bx					db 'bx',0
reg_ebx					db 'ebx',0
reg_cl					db 'cl',0
reg_ch					db 'ch',0
reg_cx					db 'cx',0
reg_ecx					db 'ecx',0
reg_dl					db 'dl',0
reg_dh					db 'dh',0
reg_dx					db 'dx',0
reg_edx					db 'edx',0

reg_bp					db 'bp',0
reg_ebp					db 'ebp',0
reg_di					db 'di',0
reg_edi					db 'edi',0
reg_si					db 'si',0
reg_esi					db 'esi',0
reg_sp					db 'sp',0
reg_esp					db 'esp',0

reg_cs					db 'cs',0
reg_ds					db 'ds',0
reg_es					db 'es',0
reg_fs					db 'fs',0
reg_gs					db 'gs',0
reg_ss					db 'ss',0

reg_bx_plus_si			db 'bx+si',0
reg_bx_plus_di			db 'bx+di',0
reg_bp_plus_si			db 'bp+si',0
reg_bp_plus_di			db 'bp+di',0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
offset_free				dw 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;