
; Public Domain

; test run command: ; .; .

%include "lmacros3.mac"
%include "eld.mac"
%include "eldcall.mac"
%include "elddata.mac"


	numdef RESIDENT, 1

	cpu 8086

	addsection RELOCATEDDATA, nobits vstart=_ELD_RELOC_VSTART
relocateddata:

	addsection HEADER, start=0

	istruc ELD_HEADERX
at eldhxHeader
		; ELD executable header
	istruc ELD_HEADER
at eldhSignature,	db "ELD1"
			db 0,0,0
			db 26
at eldhCodeOffset,	dd CODEOFFSET
at eldhCodeImageLength,	dw code_size
at eldhCodeAllocLength,	dw 0
at eldhDataOffset,	dd DATAOFFSET
at eldhDataImageLength,	dw data_size
at eldhDataAllocLength,	dw total_data_size - data_size
at eldhCodeEntrypoint,	dw linker - code
at eldhReserved
at eldhExtensionSize,	dw header_extension_end - $$
	iend
at eldhxDescriptionOffset,	dd description
%if _RESIDENT
at eldhxHelpOffset,		dd DATAOFFSET + msg.help - datastart
%endif
PUT_ELDHX_DATETIME_OFFSET
header_extension_end:
	iend

description:		asciz "Display DOS drive space."


	align 16, db 0

CODEOFFSET equ $ - $$
	addsection CODE, follows=HEADER vstart=_ELD_CODE_VSTART
%define CODEFIXUP - code + 0
code:
		; ELD instance header
	istruc ELD_INSTANCE
at eldiStartCode
at eldiEndCode
at eldiStartData
at eldiEndData
at eldiIdentifier,	fill 8, 32, db "DOSSPACE"
at eldiListing,		asciz _ELD_LISTING
	iend


%if _RESIDENT
command:
	jmp strict short .entry
.chain:
	extcall cmd3_not_ext, required	; must NOT be extcallcall
	times 10 - ($ - command) nop
.entry:
	push si
	cmp al, '-'
	jne @F
	extcallcall skipcomma
@@:
	dec si

reloc	mov dx, msg.dosspace
internaldatarelocation
	extcallcall isstring?
	je .ours
	pop si
	dec si
	lodsb
	jmp .chain

.ours:
	pop ax
	extcallcall skipcomma
	dec si
reloc2	mov word [relocateddata], relocateddata
linkdatarelocation lastcmd, -4
linkdatarelocation dmycmd
reloc	mov dx, relocateddata
linkdatarelocation msg.uninstall
	extcallcall isstring?
	je uninstall

	call run
	extcallcall cmd3

uninstall:
	lodsb
	extcallcall chkeol

	call get_es_ext

	push es
	pop ds
	xor bx, bx		; = 0 (no prior, modify ext_command_handler)
reloc	mov di, command		; di -> us
internalcoderelocation
reloc	mov si, word [ss:relocateddata]
linkdatarelocation ext_command_handler
				; si -> first
	test si, si		; none installed ?
	jz .error		; error -->

.loop:
	cmp di, si		; found ?
	je .bx			; yes, use bx -->
	mov bx, si		; bx -> prior handler
	lodsw			; skip entrypoint jmp strict short
	lodsb			; get first byte of chainer
	cmp al, 0E9h		; expecting jmp near ?
	jne .error		; no, error -->
	lodsw			; get rel16 displacement
	add si, ax		; -> next handler
	jmp .loop

.bx:
	test bx, bx		; any prior ?
	jnz .bxnz		; yes -->
	scasw			; skip entrypoint jmp strict short
	cmp byte [di], 0E8h	; is it a call to cmd3_not_ext ?
	jne @F			; no -->
				; yes, reset ext_command_handler to zero
.setbx:
reloc	mov word [ss:relocateddata], bx
linkdatarelocation ext_command_handler
	jmp .done

@@:
	cmp byte [di], 0E9h	; validate
	jne .error		; failure -->
	inc di			; -> rel16 displacement
	mov bx, word [di]	; get displacement
	scasw			; -> after jmp near
	add bx, di		; -> next handler
	jmp .setbx		; set ext_command_handler to next

.bxnz:
	mov si, bx		; -> prior handler with us as downlink
	xchg di, si		; si -> ours, di -> prior
	cmpsw			; skip entrypoint jmp strict short
	movsb			; copy 0E8h/0E9h
	lodsw			; ax = near rel16 displacement
	add ax, si		; add in our base (= absolute offset)
	sub ax, di
	dec ax
	dec ax			; subtract new base (= relative displacement)
	stosw			; store new rel16 displacement
	movsw			; jmp strict short
	movsw			; linkcall target
	movsb			; trailer
.done:
reloc	clropt [code + eldiFlags], eldifResident
internalcoderelocation -3	; mark block as free
reloc	mov dx, msg.uninstall_done
internaldatarelocation
@@:
	push ss
	pop ds
	extcallcall putsz
	extcallcall cmd3	; return

.error:
	mov ax, 0E01h
	extcallcall setrc
reloc	mov dx, msg.uninstall_error
internaldatarelocation
	jmp @B


get_es_ext:
reloc	mov es, word [relocateddata]
linkdatarelocation extdssel
	extcallcall ispm
	jz @F
reloc	mov es, word [relocateddata]
linkdatarelocation extseg
@@:
	retn


run:
%else
start:
	mov bx, es
%endif
	 push ss
	 pop es
	extcallcall skipcomma
	jmp .calldos

.notfound:
	mov ax, 0E67h
	extcallcall setrc
	mov dx, msg.notfound
internaldatarelocation
	extcallcall putsz
	extcallcall cmd3

checkdos: equ $
	extcallcall InDOS
	jz @F
.error:
	extcallcall error

@@:
	retn

.calldos:
	call checkdos
	dec si
	xor bx, bx
	mov dx, msg.expanded
internaldatarelocation
	extcallcall isstring?
	jne @F
	not bx
@@:
	extcallcall skipcomma
	mov byte [expanded], bl
internaldatarelocation

	call getdrive
	mov dh, 0

	mov al, dl
	mov di, msg.return.in_dl
internaldatarelocation
	extcallcall hexbyte

	mov ah, 0
	dec ax
	jns @F
	mov ah, 19h
	extcallcall _doscall
@@:
	add al, 'A'
	mov byte [msg.drive], al
internaldatarelocation

	xor cx, cx
	xor bx, bx
	mov ax, 36FFh
	extcallcall _doscall

	lframe
	lenter
	lvar word, spc
	 push ax
	mov word [buffer_spc], ax
internaldatarelocation
	lvar word, free
	 push bx
	mov word [buffer_free], bx
internaldatarelocation
	lvar word, bps
	 push cx
	mov word [buffer_bps], cx
internaldatarelocation
	lvar word, total
	 push dx
	mov word [buffer_total], dx
internaldatarelocation

	mov dx, msg.return
internaldatarelocation
	mov di, msg.return.ax
internaldatarelocation
	extcallcall hexword
	xchg ax, bx
	mov di, msg.return.bx
internaldatarelocation
	extcallcall hexword
	xchg ax, cx
	mov di, msg.return.cx
internaldatarelocation
	extcallcall hexword
	mov ax, word [bp + ?total]
	mov di, msg.return.dx
internaldatarelocation
	extcallcall hexword
	extcallcall putsz

	cmp word [bp + ?spc], -1
	je .notfound

	mov ax, word [bp + ?free]
	mul word [bp + ?spc]
	mov word [buffer_sfree], ax
internaldatarelocation
	mov word [buffer_sfree + 2], dx
internaldatarelocation

	mov ax, word [bp + ?total]
	mul word [bp + ?spc]
	mov word [buffer_stotal], ax
internaldatarelocation
	mov word [buffer_stotal + 2], dx
internaldatarelocation

	mov ax, word [bp + ?bps]
	mul word [bp + ?spc]
	mov word [buffer_bpc], ax
internaldatarelocation
	mov word [buffer_bpc + 2], dx
internaldatarelocation

	mov ax, word [buffer_stotal]
internaldatarelocation
	mov dx, word [buffer_stotal + 2]
internaldatarelocation
	mov bx, buffer_btotal
internaldatarelocation
	call .s_to_b

	mov ax, word [buffer_sfree]
internaldatarelocation
	mov dx, word [buffer_sfree + 2]
internaldatarelocation
	mov bx, buffer_bfree
internaldatarelocation
	call .s_to_b

	mov si, table_base
internaldatarelocation
	call processtable

	lleave code
	jmp ext


.s_to_b:
	push dx
	mul word [bp + ?bps]
	mov word [bx + 0], ax
	mov word [bx + 2], dx
	and word [bx + 4], 0
	pop ax
	mul word [bp + ?bps]
	add word [bx + 2], ax
	adc word [bx + 4], dx
	retn

	lleave ctx


ext:
	mov ax, 7303h
	mov dx, msg.drive
internaldatarelocation
	mov di, buffer_ext
internaldatarelocation
%if _RESIDENT
	and word [di + 2], 0
%endif
	mov cx, buffer_ext.size
	stc
	extcallcall _doscall
	jnc @F
	mov di, msg.noneext.ax
internaldatarelocation
	extcallcall hexword
	mov dx, msg.noneext
internaldatarelocation
	extcallcall putsz
	jmp end

@@:

	mov si, buffer_ext.free
internaldatarelocation
	mov di, buffer_ext.spc
internaldatarelocation
	mov bx, buffer_ext.sfree
internaldatarelocation
	call mul_32_x_32

	mov si, buffer_ext.total
internaldatarelocation
	; mov di, buffer_ext.spc
; internaldatarelocation
	mov bx, buffer_ext.stotal
internaldatarelocation
	call mul_32_x_32

	mov si, buffer_ext.bps
internaldatarelocation
	; mov di, buffer_ext.spc
; internaldatarelocation
	mov bx, buffer_ext.bpc
internaldatarelocation
	call mul_32_x_32

	houdini
	mov si, buffer_ext.stotal
internaldatarelocation
	mov di, buffer_ext.bps
internaldatarelocation
	mov bx, buffer_ext.btotal
internaldatarelocation
	call mul_64_x_32

	mov si, buffer_ext.sfree
internaldatarelocation
	; mov di, buffer_ext.bps
; internaldatarelocation
	mov bx, buffer_ext.bfree
internaldatarelocation
	call mul_64_x_32

	mov si, table_ext
internaldatarelocation
	call processtable

	rol byte [expanded], 1
internaldatarelocation
	jnc end

	mov si, table_ext_expanded
internaldatarelocation
	call processtable

end:
%if _RESIDENT
	retn
%else
	call uninstall_oneshot
	xor ax, ax
	retf
%endif


		; INP:	si -> source (32-bit)
		;	di -> source (32-bit)
		;	bx -> destination (64-bit)
		; CHG:	dx, ax, cx
mul_32_x_32:
	xor cx, cx
	mov ax, [si]
	mul word [di]
	mov word [bx], ax
	mov word [bx + 2], dx
	mov word [bx + 4], cx
	mov word [bx + 6], cx
	mov ax, [si]
	mul word [di + 2]
	add word [bx + 2], ax
	adc word [bx + 4], dx
	adc word [bx + 6], cx
	mov ax, [si + 2]
	mul word [di]
	add word [bx + 2], ax
	adc word [bx + 4], dx
	adc word [bx + 6], cx
	mov ax, [si + 2]
	mul word [di + 2]
	add word [bx + 4], ax
	adc word [bx + 6], dx
	retn


		; INP:	si -> source (64-bit)
		;	di -> source (32-bit)
		;	bx -> destination (64-bit), assumed < 0FFF0h
		;	CY if overflow, destination all 1s
		;	NC if no overflow
		; CHG:	dx, ax, cx
mul_64_x_32:
	lframe
	lenter
	lea ax, [bx + 8]
	lvar word, pastdest
	 push ax		; -> behind dest (assumed no carry)
	xor ax, ax
	lvar word, ofs_si
	 push ax
	lvar word, ofs_di
	 push ax
	lvar word, dest
	 push bx		; -> dest
	mov [bx], ax
	mov [bx + 2], ax
	mov [bx + 4], ax
	mov [bx + 6], ax	; clear buffer
	mov ch, 4		; 4 words in si
.outer:
	mov cl, 2		; 2 words in di
.inner:
	mov bx, word [bp + ?ofs_di]
	mov ax, [di + bx]	; read di word (+0 or +2)
	mov bx, word [bp + ?ofs_si]
	mul word [si + bx]	; multiply by si word (+0, +2, +4, or +6)
	add bx, word [bp + ?ofs_di]
				; add offsets to get destination offset
	add bx, word [bp + ?dest]
				; -> destination (64 to 0 bits, +0 to +8)
	cmp bx, [bp + ?pastdest]; 0 bits left ?
	jae .checkoverflow	; yes, just check for overflow -->

	add word [bx], ax	; add low word
	lahf			; preserve CF
@@:
	inc bx
	inc bx
	cmp bx, [bp + ?pastdest]; now 0 bits left ?
	jae @F			; yes, check for CF / dx for overflow -->
	sahf			; get CF
	adc word [bx], dx	; adc to next word, dx (high mul word or 0)
	lahf			; preserve next CF
	xor dx, dx		; dx = 0 for next word if any
	jmp @B

.checkoverflow:
	cmp ax, 1		; CY if 0
	cmc			; NC if 0
	lahf			; load CF into ah
@@:
	sahf
	jc .overflow		; ax > 0 at too high, or carry out of MSB
	test dx, dx
	jnz .overflow		; dx > 0 at too high

	add byte [bp + ?ofs_di], 2
				; next word of di -> source
	dec cl			; another word from di ?
	jnz .inner		; yes -->
	mov byte [bp + ?ofs_di], 0
				; reset to di first word
	add byte [bp + ?ofs_si], 2
				; next word of si -> source (NC)
	dec ch			; another word from si ?
	jnz .outer		; yes -->
	pop bx			; get ?dest
		; NC from add byte ?ofs_si
	jmp @F

.overflow:
	mov bx, word [bp + ?dest]
	mov ax, -1
	mov [bx], ax
	mov [bx + 2], ax
	mov [bx + 4], ax
	mov [bx + 6], ax	; clear buffer
	stc
@@:
	lleave
	retn


processtable:
.loop:
	lodsw
	test ax, ax
	jz .end
	xchg bx, ax

	lodsw
	xchg cx, ax

	mov di, relocateddata
linkdatarelocation line_out

	push si
	mov ax, word [bx]
	mov dx, word [bx + 2]
	mov si, word [bx + 4]

	cmp cl, 8
	jne .notqword
.qword:
	push ax
	mov ax, [bx + 6]
	extcallcall hexword
	mov byte [di], '_'
	inc di
	mov ax, si
	extcallcall hexword
	mov byte [di], '_'
	inc di
	mov ax, dx
	extcallcall hexword
	mov byte [di], '_'
	inc di
	pop ax
	extcallcall hexword

	mov word [di], 2020h
	scasw
	mov bx, word [bx + 6]
	call decqword

	test ch, ch
	jz @F
	mov word [di], 2020h
	scasw
	test bx, bx
	jz .qword_size
	mov si, msg.toolarge
internaldatarelocation
	extcallcall copy_single_counted_string
@@:
	jmp @FFF

.qword_size:
	xor cx, cx
	mov bx, 10
	extcallcall disp_dxax_times_cx_width_bx_size.store
	jmp @FFF


.notqword:
	cmp cl, 6
	jne .not6byte
.6byte:
	xchg ax, si
	extcallcall hexword
	mov byte [di], '_'
	inc di
	xchg ax, si
	xchg ax, dx
	extcallcall hexword
	mov byte [di], '_'
	inc di
	xchg ax, dx
	extcallcall hexword

	mov word [di], 2020h
	scasw
	xor bx, bx
	call decqword
	jmp @FF

.not6byte:
	xor si, si
	cmp cl, 2
	jbe .byte_or_word
.dword:
	xchg ax, dx
	extcallcall hexword
	mov byte [di], '_'
	inc di
	xchg ax, dx
	extcallcall hexword

	mov word [di], 2020h
	scasw
	extcallcall decdword
	jmp @FF


.byte_or_word:
	mov dx, 0		; ! preserve flags
	jb .byte
.word:
	extcallcall hexword
	jmp @F

.byte:
	extcallcall hexbyte

	mov ah, 0
@@:
	mov word [di], 2020h
	scasw
	extcallcall decword
@@:

	test ch, ch
	jz @F
	mov word [di], 2020h
	scasw
	xor cx, cx
	mov bx, 10
	extcallcall disp_dxax_times_cx_width_bx_size.store
@@:

	pop si
	lodsw
	xchg dx, ax
	extcallcall putsz
	extcallcall putsline_crlf
	jmp .loop

.end:
	retn


decqword:
	push cx
	xor cx, cx
	call dec_qword_minwidth
	pop cx
	retn


		; Dump qword as decimal number string
		;
		; INP:	bx:si:dx:ax = qword
		;	cx = minimum width (<= 1 for none, must be < 10)
		;	es:di -> where to store
		; OUT:	es:di -> behind variable-length string
		; CHG:	-
		; STT:	UP
dec_qword_minwidth:
	lframe near
	lequ 20,	bufferlen
	lvar ?bufferlen,buffer
	lenter
	lvar 8,	dividend
	 push bx
	 push si
	 push dx
	 push ax
	dec cx
	lvar word,	minwidth
	 push cx
	inc cx

	push ax
	push bx
	push cx
	push dx
	push si
	push di
	push es

	 push ss
	 pop es

	lea di, [bp + ?buffer + ?bufferlen - 1]
	mov bx, di
	std			; _AMD_ERRATUM_109_WORKAROUND does not apply

		; dword [bp + ?dividend] = number to display
	mov cx, 10		; divisor
.loop_write:

	xor dx, dx
	push di
	mov di, 8
.loop_divide:
	mov ax, [bp + ?dividend - 2 + di]
	div cx
	mov word [bp + ?dividend - 2 + di], ax
	dec di
	dec di
	jnz .loop_divide
				; dx = last remainder
	pop di
	xchg ax, dx		; ax = remainder (next digit)
				; dword [bp + ?dividend] = result of div
	add al, '0'
	stosb
	dec word [bp + ?minwidth]
	jns .loop_write

	cmp word [bp + ?dividend + 6], 0
	jnz .loop_write
	cmp word [bp + ?dividend + 4], 0
	jnz .loop_write
	cmp word [bp + ?dividend + 2], 0
	jnz .loop_write
	cmp word [bp + ?dividend], 0
				; any more ?
	jnz .loop_write		; loop -->

	cld

	sub bx, di
	mov cx, bx
	mov si, di
	inc si

	pop es
	pop di

@@:
	ss movsb		; do not replace by rep ss movsb, because
				;  some 8086 don't like two-prefix opcodes
	loop @B

	pop si
	pop dx
	pop cx
	pop bx
	pop ax

	lleave
	retn


getdrive:
	xor dl, dl
	extcallcall iseol?
	je .ret
	cmp byte [si], ':'
	jne .number
	extcallcall uppercase
	mov dl, al
	sub dl, 'A'
	cmp dl, 32
	jae .number
	inc dx
	inc si
	lodsb
	jmp @F

.number:
	extcallcall getbyte
@@:
	extcallcall chkeol
.ret:
	retn


%if _RESIDENT
	eldcall_dump_callcall ELDCALL_CALLCALL_LIST

endinstalled equ ($ + CODEFIXUP + 15) & ~15


start:
	mov bx, es
	 push ss
	 pop es
	call skipcomma
	dec si
reloc	mov dx, relocateddata
linkdatarelocation msg.install
	call isstring?
	je install
reloc	mov dx, msg.keyword_help
internaldatarelocation
	call isstring?
	je help
	call run
@@:
	call uninstall_oneshot
	xor ax, ax
	retf

help:
	lodsb
	call chkeol
reloc	mov dx, msg.help
internaldatarelocation
	call putsz
	jmp @B
%endif


uninstall_oneshot:
	testopt [ss:relocateddata], 1
linkdatarelocation options7, -3
	jnz @F

	mov ax, word [cs:code + eldiEndCode]
internalcoderelocation
	sub ax, word [cs:code + eldiStartCode]
internalcoderelocation
	sub word [relocateddata], ax
linkdatarelocation extseg_used

	mov ax, word [cs:code + eldiEndData]
internalcoderelocation
	sub ax, word [cs:code + eldiStartData]
internalcoderelocation
	sub word [relocateddata], ax
linkdatarelocation extdata_used
@@:
	retn


DATAOFFSET equ CODEOFFSET + code_size
	addsection DATA, follows=CODE vstart=_ELD_DATA_VSTART
%define DATAFIXUP - datastart + 0
datastart:
PUT_ELD_DATETIME

%define NAMES db ""
%define DUPLICATES empty, empty

%imacro duplicatecheck 2-*.nolist
 %define DUPLICATE
 %rep (%0 / 2) - 1
  %rotate 2
  %ifidn %1, CHECKNAME
   %xdefine DUPLICATE %2
   %exitrep
  %endif
 %endrep
%endmacro

%imacro item 2-3.nolist
	dw buffer_%1
internaldatarelocation
	dw %2
	dw %%name
internaldatarelocation
 %defstr %%string %1
 %xdefine CHECKNAME %1
 duplicatecheck DUPLICATES
 %ifnempty DUPLICATE
%%name equ DUPLICATE
 %else
  %xdefine DUPLICATES DUPLICATES, %1, %%name
  %xdefine NAMES NAMES, %%name:, {fill 16,32,db %%string}, db 0
 %endif
%endmacro

%imacro dumpnames 1-*.nolist
 %rep %0
	%1
  %rotate 1
 %endrep
%endmacro

	align 4, db 0
buffer_ext:
.:
.outsize:	dw 0
.inoutversion:	dw 0
.spc:		dd 2642h
.bps:		dd 0
.free:		dd 0
.total:		dd 0
	; not used
.physsfree:	dd 0
.physstotal:	dd 0
.physfree:	dd 0
.phystotal:	dd 0
.reserved:	dq 0
.size equ $ - .

.bpc:		dq 0
.sfree:		dq 0
.stotal:	dq 0
.bfree:		dq 0
.btotal:	dq 0

	align 2, db 0
buffer_spc:	dw 0
buffer_free:	dw 0
buffer_bps:	dw 0
buffer_total:	dw 0
buffer_bpc:	dd 0
buffer_sfree:	dd 0		; spc * free
buffer_stotal:	dd 0		; spc * total
buffer_bfree:	times 3 dw 0	; bps * sfree
buffer_btotal:	times 3 dw 0	; bps * stotal


table_base:
item spc, 2
item free, 2
item bps, 2 + 100h
item total, 2
item bpc, 4 + 100h
item sfree, 4
item stotal, 4
item bfree, 6 + 100h
item btotal, 6 + 100h
	dw 0


table_ext:
item ext.spc, 4
item ext.free, 4
item ext.bps, 4 + 100h
item ext.total, 4
item ext.bpc, 8 + 100h
item ext.sfree, 8
item ext.stotal, 8
item ext.bfree, 8 + 100h
item ext.btotal, 8 + 100h
	dw 0


table_ext_expanded:
item ext.physsfree, 4
item ext.physstotal, 4
item ext.physfree, 4
item ext.phystotal, 4
item ext.reserved, 8
	dw 0

expanded:	db 0

msg:
.return:	db "DOS function 36h dl="
.return.in_dl:	db "--h call returned ax="
.return.ax:	db "----h, bx="
.return.bx:	db "----h, cx="
.return.cx:	db "----h, dx="
.return.dx:	asciz "----h.",13,10
.notfound:		asciz "Drive not found!",13,10
.noneext:		db "DOS function 7303h not supported, error="
.noneext.ax:		asciz "----h!",13,10
.toolarge:		counted ">= 256 TiB"
.drive:			asciz "A:\"
.expanded:		asciz "EXPANDED"

%if _RESIDENT
.dosspace:		asciz "DOSSPACE"
.uninstall_done:	db "DOSSPACE command uninstalled."
%if _ELD_RECLAIM_HINT
			db " (Don't forget to use reclaim.eld)"
%endif
			asciz 13,10
.uninstall_error:	asciz "DOSSPACE command unable to uninstall!",13,10
%endif

dumpnames NAMES

uinit_data: equ $

%if _RESIDENT
.installed:		asciz "DOSSPACE command installed.",13,10
.keyword_help:		asciz "HELP"
.help:		db "This ELD can be installed residently or used transiently.",13,10
		db 13,10
		db "DOSSPACE command may be used with a drive specified like so:",13,10
		db 9,"DOSSPACE A:",9,9,"Access drive A: using DOS call 21.36",13,10
		asciz
%endif

	align 16, db 0
init_data_end:
data_size equ $ - datastart
transient_data_size equ data_size

	absolute uinit_data

	alignb 16
uinit_data_end:
resident_data_end:
resident_data_size equ resident_data_end - datastart

%if uinit_data_end >= init_data_end
 total_data_size equ $ - datastart
%else
 total_data_size equ init_data_end - datastart
%endif
%assign _DATA_SIZE total_data_size

	usesection CODE

%if _RESIDENT
install:
	lodsb
	extcall chkeol

	houdini
	mov es, bx		; => ext seg (writable)

	mov ax, endresident - endinstalled
reloc	sub word [es:code + eldiEndCode], ax
internalcoderelocation		; adjust size
reloc	sub word [relocateddata], ax
linkdatarelocation extseg_used	; adjust size

%if (transient_data_size - resident_data_size) > 0
	mov ax, transient_data_size - resident_data_size
reloc	sub word [es:code + eldiEndData], ax
internalcoderelocation		; adjust size
reloc	sub word [relocateddata], ax
linkdatarelocation extdata_used	; adjust size
%endif

reloc	mov bx, word [relocateddata]
linkdatarelocation ext_command_handler
				; -> prior
reloc	mov di, command		; -> our handler
internalcoderelocation
	test bx, bx		; installing as first ?
	jz .only_first		; yes, simple --> (leave as extcall cmd3_not_ext)
	scasw			; skip entrypoint jmp strict short
	mov al, 0E9h		; = jmp near opcode
	stosb			; store
	xchg ax, bx		; ax -> next handler
	sub ax, di
	dec ax
	dec ax			; ax = ax - (di + 2)
	stosw			; store our downlink as rel16 displacement

.only_first:
reloc	setopt [es:code + eldiFlags], eldifResident
internalcoderelocation -3	; mark block as resident
reloc2	mov word [relocateddata], command
linkdatarelocation ext_command_handler, -4
internalcoderelocation		; -> our entrypoint

reloc	testopt [relocateddata], 4
linkdatarelocation options7, -3
	jnz @F
reloc	mov dx, msg.installed
internaldatarelocation
	call putsz
@@:
	xor ax, ax
	retf
%endif


%include "eldlink.asm"

	align 16
code_size equ $ - code
