
; Public Domain

; test install command: install; ldmem; ldmem uninstall
; test run command: ; .; .

%include "lmacros3.mac"

	numdef OTHER, 0
%if _OTHER
 %define ELDOTHER 1
 %define OTH_STRING "OTH"
 %imacro getotherds 0
reloc	mov ds, word [ss:otherds]
internaldatarelocation
 %endmacro
 %imacro resetds 0
	push ss
	pop ds
 %endmacro
 %imacro getotheres 0
reloc	mov es, word [ss:otherds]
internaldatarelocation
 %endmacro
 %imacro resetes 0
	push ss
	pop es
 %endmacro
%else
 %define OTH_STRING ""
 %idefine getotherds
 %idefine resetds
 %idefine getotheres
 %idefine resetes
%endif

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

	struc HANDLERTABLE
htMessage:		resw 1
htHandler:		resw 1
htTemplate:		resw 1
htReturn:		resw 1
htFlags:		resw 1
	endstruc

htfIsAMIS equ 1
htfIsInject equ 2


	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
at eldhxHelpOffset,		dd DATAOFFSET + msg.help - datastart
PUT_ELDHX_DATETIME_OFFSET
header_extension_end:
	iend

description:		asciz "Dump lDebug memory use."


	align 16, db 0

	eldstrict on

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 "LDMEM",OTH_STRING
at eldiListing,		asciz _ELD_LISTING
	iend


	numdef ELD_BUG, 0
	numdef ELD_BUG_RELOC, _ELD_BUG
	numdef ELD_BUG_LINK, _ELD_BUG
	numdef ELD_BUG_LENGTH, _ELD_BUG


%rep _ELD_BUG_LINK
	eldstrict off

	dw relocateddata		; missing linkdatarelocation
%endrep

%rep _ELD_BUG_RELOC
	eldstrict off

	dw msg.ldmem			; missing internaldatarelocation
%endrep

%if _ELD_BUG_LENGTH && _ELD_CODE_VSTART
times 64 db 0
%endif

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.ldmem
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

%if _OTHER
reloc	mov ax, word [otherseg]
internaldatarelocation
	extcallcall ispm
	jnz @F
	xchg dx, ax
	extcallcall setes2dx
reloc	mov ax, word [es:relocateddata]
otherlinkdatarelocation dssel
@@:
reloc	mov word [otherds], ax
internaldatarelocation
%endif

	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


%if _OTHER
get_es_ext_other:
	getotherds
reloc	mov es, word [relocateddata]
otherlinkdatarelocation extdssel
	extcallcall ispm
	jz @F
reloc	mov es, word [relocateddata]
otherlinkdatarelocation extseg
@@:
	resetds
	retn
%else
 get_es_ext_other equ get_es_ext
%endif


run:
	push ss
	pop es
reloc2	mov word [separatormessage], msg.empty
internaldatarelocation -4
internaldatarelocation
	lodsb
	extcallcall iseol?
	jne @F
reloc	mov si, msg.allexceptseg + 1
internaldatarelocation
@@:
	dec si			; -> keyword

	xor ax, ax
	push ax			; on stack = 0

.loopouter:			; si -> next keyword
	lodsb
	extcallcall iseol?
	jne @F
.continue:
	pop si			; get next string
	test si, si		; any ?
	jnz .loopouter		; yes -->
	retn			; done

@@:
	dec si			; -> keyword
	xchg si, cx
reloc	mov si, nountable
internaldatarelocation
.loop:
	lodsb
	mov ah, 0
	add ax, si
	cmp ax, si
	je .notfound
	xchg dx, ax		; -> match string
	xchg si, cx		; si -> keyword
	extcallcall isstring?
	je .got
	xchg si, cx		; si -> table
	lodsb
	lodsw			; skip
	jmp .loop		; try to match next noun -->

.got:
	extcallcall skipcomma
	dec si			; -> next keyword
	push si			; stack next keyword
	xchg si, cx		; si -> table
	lodsb
	cmp al, 1
	lodsw			; ax -> next string or function
	je .sublist
.function:
	call .separator
	call ax			; call code
	 push ss
	 pop es
	 push ss
	 pop ds
	pop si			; restore -> next keyword
	jmp .loopouter		; continue noun loop -->

.sublist:
	xchg si, ax		; si -> sub list
	jmp .loopouter		; handle sub list --> (stack has continue offset)

.notfound:
	call .separator
	mov ax, 0E43h
	extcallcall setrc
reloc	mov dx, msg.notfound.1
internaldatarelocation
	extcallcall putsz
	xchg si, cx		; si -> keyword
	mov dx, si		; dx -> start of keyword
@@:
	lodsb
	extcallcall iseol?	; EOL ?
	je @F
	cmp al, 32		; blank ?
	je @F
	cmp al, 9
	je @F
	cmp al, ','		; comma ?
	jne @B
		; We do not want to loop on trailing commas
		;  indefinitely, so handle this in a special
		;  way here. (Trailing comma after a valid
		;  name will emit the not found message with
		;  an empty name.)
	push si
	extcallcall skipwhite
	extcallcall iseol?	; EOL after comma ?
	jne .nottrailingcomma
	dec si
	pop ax			; -> after keyword + 1
	dec ax			; -> after keyword
	mov cx, ax		; -> after keyword
	jmp @FF

.nottrailingcomma:
	pop si
@@:
	dec si			; -> after keyword
	mov cx, si		; -> after keyword
@@:
	sub cx, dx		; cx = length of keyword
	extcallcall puts
reloc	mov dx, msg.notfound.2
internaldatarelocation
	extcallcall putsz
	extcallcall skipcomma	; skip comma (except trailing comma)
	dec si			; -> next keyword
	jmp .loopouter

.separator:
reloc	mov dx, msg.linebreak
internaldatarelocation
reloc	xchg dx, word [separatormessage]
internaldatarelocation
	extcallcall putsz
	retn


display_seg:
	call sort_mem

reloc	mov si, table_sorted
internaldatarelocation
reloc	mov di, relocateddata
linkdatarelocation line_out
.loop1:
	lodsw
	test ax, ax
	jz .done1

	push si
	xchg si, ax
	call .get_name
	xchg ax, cx
	cmp al, 4
	jae @F
	extcallcall copy_single_counted_string
	xchg ax, cx
	neg cx
	add cx, 4
	jmp @FF
@@:
	extcallcall copy_single_counted_string
@@:
	inc cx
	mov al, 32
	rep stosb
	pop si
	add si, 8
	jmp .loop1

.get_name:
	push si
	xor cx, cx
	mov cl, [si]
	add si, cx
	inc si
	mov cl, [si]
	jcxz @F
	pop dx
	retn
@@:
	pop si
	mov cl, [si]
	retn

.done1:
	extcallcall trimputs

reloc	mov si, table_sorted
internaldatarelocation
reloc	mov di, relocateddata
linkdatarelocation line_out
.loop2:
	lodsw
	test ax, ax
	jz .done2
	push si
	push ax
	lodsw
	lodsw

	extcallcall hexword
	pop si
	call .get_name
	sub cl, 3
	jnz @F
	inc cx
@@:
	mov al, 32
	rep stosb
	pop si
	add si, 8
	jmp .loop2

.done2:
	extcallcall trimputs

	extcallcall ispm
	jnz .end

reloc	mov si, table_sorted
internaldatarelocation
reloc	mov di, relocateddata
linkdatarelocation line_out
.loop3:
	lodsw
	test ax, ax
	jz .done3
	xchg bx, ax
	add si, 6
	lodsw
	test ax, ax
	jnz @F
	mov ax, "no"
	stosw
	mov ax, "ne"
	stosw
	jmp @FF
@@:
	xchg bx, ax
	getotherds
	mov bx, [bx]
	resetds
	xchg bx, ax

	extcallcall hexword
@@:
	push si
	mov si, bx
	call .get_name
	pop si
	sub cl, 3
	jnz @F
	inc cx
@@:
	mov al, 32
	rep stosb
	jmp .loop3

.done3:
	extcallcall trimputs

.end:
	call display_data_sel
	retn


display_patchareas.none:
reloc	mov dx, msg.patch_area.5
internaldatarelocation
	extcallcall putsz
	jmp display_patchareas.next

display_patchareas:
reloc	mov si, store_table
internaldatarelocation

.loop:
	lodsw
	xchg di, ax		; di = offset -> patch area
	lodsw
	xchg bx, ax		; bx -> word [segment] => patch area
	lodsw
	xchg cx, ax		; cx = length
	lodsw			; ax -> name message
	push ax			; name
	jcxz .none		; zero length means not supported -->
	test bx, bx
	jz .none		; zero offset of segment is invalid -->
	; test di, di		; (could be valid)
	; jz .none

	houdini

reloc	mov dx, msg.patch_area.1
internaldatarelocation
	extcallcall putsz	; header
	push di			; preserve -> patch area
	 push cx
	xchg ax, cx		; ax = length
reloc	mov di, relocateddata
linkdatarelocation line_out
	extcallcall decword	; write length
	 push bx
	extcallcall putsline
	 pop bx			; preserve segment variable offset
	 pop cx			; preserve length
	pop di
	getotherds
	mov dx, word [bx]	; => segment of patch area
	resetds
	mov bp, dx		; preserve segment
	extcallcall setes2dx	; es => patch area
reloc	mov dx, msg.patch_area.2.notinuse
internaldatarelocation
	push di
	mov al, 90h		; check if all NOPs, meaning not in use
	repe scasb		; check
	je @F			; if not in use -->
reloc	mov dx, msg.patch_area.2.inuse
internaldatarelocation		; indicate in use
@@:
	 push ss
	 pop es
	extcallcall putsz
reloc	mov dx, msg.patch_area.3.entry
internaldatarelocation
reloc	cmp bx, strict word relocateddata
linkdatarelocation pspdbg	; is entry segment ?
	je @F
reloc	mov dx, msg.patch_area.3.code
internaldatarelocation
reloc2	cmp bx, strict word relocateddata
linkdatarelocation code_seg, -2, optional, next
linkdatarelocation code_movable_seg, -2, optional, last
				; is code segment ?
	je @F
reloc	mov dx, msg.patch_area.3.unknown
internaldatarelocation
reloc	mov di, msg.patch_area.3.unknown.s
internaldatarelocation
	xchg ax, bp		; ax = segment value
	extcallcall hexword
@@:
	extcallcall putsz
reloc	mov dx, msg.patch_area.3.offset
internaldatarelocation
reloc	mov di, msg.patch_area.3.offset.o
internaldatarelocation
	pop ax
	extcallcall hexword
	extcallcall putsz
reloc	mov dx, msg.patch_area.4
internaldatarelocation
	extcallcall putsz
.next:
	pop dx
	extcallcall putsz

reloc	mov dx, msg.linebreak
internaldatarelocation
	extcallcall putsz

reloc	cmp si, strict word store_table.end
internaldatarelocation
	jb .loop
	retn


sort_mem:
reloc	mov si, table
internaldatarelocation
reloc	mov dx, table_sorted
internaldatarelocation

loopprepare:
	lodsw
	test ax, ax
	jz .done
	lodsw
	test ax, ax
	jnz @F
.segzero:
	add si, 6
	jmp .next

@@:
	xchg bx, ax
	getotherds
	mov ax, [bx]
	resetds
	test ax, ax
	jz .segzero
reloc	mov di, table_sorted + 4
internaldatarelocation
@@:
	cmp di, dx
	jae .insert_at_di_minus_4
	scasw
	jb .insert_at_di_minus_6
	add di, 8
	jmp @B

.insert_at_di_minus_4:
	scasw
.insert_at_di_minus_6:
	sub di, 6
.insert_at_di:
	mov cx, dx
	sub cx, di
	push si
	push di
	mov di, dx		; -> end
	add di, 10		; -> after destination
	mov dx, di		; update -> end
	std			; AMD erratum 109 workaround
	scasw			; -> last word destination
	lea si, [di - 10]	; -> last word source (dx - 2)
	shr cx, 1		; = amount of words
	jcxz @FF
	cmp cx, 20
	ja @FF
@@:
	movsw
	loop @B
@@:
	rep movsw		; move up all following entries
	cld
	pop di
	pop si
	sub si, 4
	movsw			; copy message offset
	movsw			; copy seg offset
	stosw			; store seg value
	lodsw			; skip this field
	movsw			; copy size offset
	movsw			; copy sel offset
.next:
	jmp loopprepare

.done:
	xchg dx, di
	xor ax, ax
	stosw			; terminator
	retn


display_mem:
	call sort_mem

reloc	mov bx, relocateddata
otherlinkdatarelocation alloc_seg, -2, optional
	mov dx, bx
	test bx, bx
	jz @F
	getotherds
	mov dx, [bx]
	resetds
@@:

reloc	mov si, table_sorted
internaldatarelocation
loop:
reloc	mov di, relocateddata
linkdatarelocation line_out
	lodsw
	test ax, ax
	jz .done
	push si
	push ax
	lodsw
	test dx, dx
	jz .nogap
	test ax, ax
	jz .nogap
	xchg bx, ax
	getotherds
	mov ax, [bx]
	resetds
	cmp dx, ax
	je .nogap
	jb .gap
	push dx
reloc	mov dx, msg.overlap
internaldatarelocation
	extcallcall putsz
	pop dx
	jmp .nogap
.gap:
	call gap
.nogap:
	pop si
	extcallcall copy_single_counted_string
reloc	mov si, msg.segment_colon
internaldatarelocation
	extcallcall copy_single_counted_string
	pop si
	lodsw
	test ax, ax
	jnz @F
	add si, 6
	push si
reloc	mov si, msg.none
internaldatarelocation
.next_string:
	extcallcall copy_single_counted_string
	xor dx, dx
	pop si
	jmp .next

@@:
	xchg bx, ax
reloc	mov cx, relocateddata + 26
linkdatarelocation line_out
	sub cx, di
	jbe @F
	mov al, 32
	rep stosb
@@:
	getotherds
	mov ax, [bx]
	resetds
	mov dx, ax
	extcallcall hexword
	push si
reloc	mov si, msg.address.1
internaldatarelocation
	extcallcall copy_single_counted_string
	pop si
	lodsw
	lodsw
	test ax, ax
	jnz @F
	lodsw
	push si
reloc	mov si, msg.nonesize
internaldatarelocation
	xor dx, dx
	extcallcall copy_single_counted_string
	jmp .next_sel

@@:
	push dx
	push si
reloc	mov si, msg.size.1
internaldatarelocation
	extcallcall copy_single_counted_string
	xchg bx, ax
	getotherds
	mov ax, [bx]
	resetds
	extcallcall hexword
reloc	mov si, msg.size.2
internaldatarelocation
	extcallcall copy_single_counted_string
	xor dx, dx
	mov cx, 1
	mov bx, 9
	extcallcall disp_dxax_times_cx_width_bx_size.store
	pop si
	pop dx
	add ax, 15
	shr ax, 1
	shr ax, 1
	shr ax, 1
	shr ax, 1
	add dx, ax
	lodsw
	push si
.next_sel:
	extcallcall ispm
	jnz @F
	test ax, ax
	jz @F
	xchg bx, ax
	getotherds
	mov ax, [bx]
	resetds
reloc	mov si, msg.sel
internaldatarelocation
	extcallcall copy_single_counted_string
	extcallcall hexword

@@:
	pop si

.next:
	push dx
	extcallcall putsline_crlf
	pop dx
	jmp loop

.done:
loop_done:

reloc	mov bx, relocateddata
otherlinkdatarelocation alloc_seg, -2, optional
	test bx, bx
	jz .nogap
	getotherds
	mov ax, [bx]
reloc	mov bx, relocateddata
otherlinkdatarelocation alloc_size, -2, optional
	test bx, bx
	jz .nogap
	add ax, [bx]
	resetds
	test dx, dx
	jz .nogap
	cmp dx, ax
	jae .nogap
	call gap
.nogap:
	resetds


display_alloc:
reloc	mov dx, msg.alloc
internaldatarelocation
	extcallcall putsz

reloc	mov bx, relocateddata
otherlinkdatarelocation alloc_seg, -2, optional
	test bx, bx
	jnz @F
reloc	mov si, msg.none
internaldatarelocation
.eol_string:
	extcallcall copy_single_counted_string
	jmp .eol

@@:
	getotherds
	mov ax, [bx]
	resetds
	extcallcall hexword
reloc	mov si, msg.address.1
internaldatarelocation
	extcallcall copy_single_counted_string

reloc	mov bx, relocateddata
otherlinkdatarelocation alloc_size, -2, optional
	test bx, bx
	jnz @F
reloc	mov si, msg.nonesize
internaldatarelocation
	jmp .eol_string

@@:
	getotherds
	mov ax, [bx]
	resetds
	call parasize
.eol:
	extcallcall putsline_crlf


display_data_sel:
	extcallcall ispm
	jnz .end

reloc	mov di, relocateddata
linkdatarelocation line_out
	mov cx, 2
@@:
reloc	mov bx, relocateddata
otherlinkdatarelocation dssel, -2, optional
	cmp cl, 2
	je .dssel
reloc	mov bx, relocateddata
otherlinkdatarelocation extdssel, -2, optional
.dssel:
	test bx, bx
	jz .next
	getotherds
	mov ax, [bx]
	resetds
reloc	mov si, msg.dssel
internaldatarelocation
	cmp cl, 2
	je .msgdssel
reloc	mov si, msg.extdssel
internaldatarelocation
.msgdssel:
	push cx
	extcallcall copy_single_counted_string
	pop cx
	extcallcall hexword
	mov ax, 2020h
	stosw
.next:
	loop @B
reloc	cmp di, strict word relocateddata
linkdatarelocation line_out
	je .end
	extcallcall trimputs

.end:
	retn


historysize:
	lframe none
	lenter
reloc	mov byte [history_data_entry], 0
internaldatarelocation -3
reloc	mov ax, relocateddata
otherlinkdatarelocation historyformat, -2, optional
	test ax, ax
	jnz @F
reloc	mov dx, msg.history_none
internaldatarelocation
.putsz_end:
	extcallcall putsz
	jmp .end

@@:
reloc	mov dx, msg.history_data_entry
internaldatarelocation
	; houdini
@@:
	cmp ax, 2
	jb .in_data_entry
reloc	mov dx, msg.history_separate
internaldatarelocation
	je .in_separate

%if 0
reloc	mov di, relocateddata
linkdatarelocation line_out
	extcallcall hexword
	mov al, 32
	stosb
reloc	mov si, @B
internalcoderelocation
	mov cx, 16
@@:
	cs lodsb
	extcallcall hexbyte
	mov al, 32
	stosb
	loop @B
	extcallcall trimputs
%endif

reloc	mov dx, msg.history_unknown
internaldatarelocation
	jmp .putsz_end

.in_data_entry:
reloc	not byte [history_data_entry]
internaldatarelocation
.in_separate:
	extcallcall putsz
reloc	mov bx, relocateddata
otherlinkdatarelocation history.last, -2, optional
reloc	mov dx, relocateddata
otherlinkdatarelocation history.first, -2, optional
	test bx, bx
	jz @F
	test dx, dx
	jnz @FF

@@:
.missing:
	resetds
reloc	mov dx, msg.history_missing
internaldatarelocation
	jmp .putsz_end

@@:
reloc	mov di, relocateddata
linkdatarelocation line_out
reloc	mov si, msg.history.1
internaldatarelocation
	extcallcall copy_single_counted_string
	getotherds
	xchg dx, bx
	mov ax, [bx]
	xchg dx, bx
	sub ax, [bx]
	resetds
	shr ax, 1
	extcallcall decword
	push ax
reloc	mov si, msg.history.2
internaldatarelocation
	extcallcall copy_single_counted_string
	getotherds
	mov bx, [bx]
	resetds
reloc	rol byte [history_data_entry], 1
internaldatarelocation
	getotherds
	jc .not_seg
	push bx
reloc	mov bx, relocateddata
otherlinkdatarelocation history.segorsel, -2, optional
	test bx, bx
	jz .missing
	mov ds, word [bx]
	pop bx
.not_seg:
	mov ax, [bx]
	 push ss
	 pop ds
	pop cx
	add ax, cx
	add ax, cx
	push cx
	inc ax
	inc ax
	extcallcall decword
	push ax
reloc	mov si, msg.history.3
internaldatarelocation
	extcallcall copy_single_counted_string
	mov bx, dx
	getotherds
	mov ax, [bx]
	resetds
reloc	rol byte [history_data_entry], 1
internaldatarelocation
	jnc .not_entry
	push bx
reloc	mov bx, relocateddata
otherlinkdatarelocation historybuffer, -2, optional
	test bx, bx
	jz .missing
	sub ax, bx
	pop bx
.not_entry:
	inc ax
	inc ax
	extcallcall decword
	pop ax
	pop dx
	test dx, dx
	jnz @F

reloc	mov si, msg.history.average.none
internaldatarelocation
	jmp .string_end

@@:
reloc	mov si, msg.history.average.1
internaldatarelocation
	extcallcall copy_single_counted_string

	xor cx, cx
	xchg cx, dx
	div cx
	test dx, dx
	jz @F
	inc ax
@@:
	extcallcall decword
reloc	mov si, msg.history.average.2
internaldatarelocation
.string_end:
	extcallcall copy_single_counted_string
	extcallcall putsline_crlf
.end:
	lleave , forcerestoresp
	retn


stacksize:
reloc	mov di, relocateddata
linkdatarelocation line_out
reloc	mov bx, relocateddata
otherlinkdatarelocation stack, -2, optional
reloc	mov dx, relocateddata
otherlinkdatarelocation stack_end, -2, optional
	test bx, bx
	jz @F
	test dx, dx
	jnz @FF
@@:
reloc	mov si, msg.stack.none
internaldatarelocation
	jmp .string_end

@@:
reloc	mov si, msg.stack.1
internaldatarelocation
	extcallcall copy_single_counted_string
	mov ax, dx
	sub ax, bx
	extcallcall decword
reloc	mov si, msg.stack.2
internaldatarelocation
	extcallcall copy_single_counted_string
	getotherds
	mov al, [bx]
	resetds
	extcallcall hexbyte
reloc	mov si, msg.stack.3
internaldatarelocation
	extcallcall copy_single_counted_string
	xchg di, bx
	getotheres
	mov cx, -1
	repe scasb
	resetes
	not cx
	dec cx
	xchg ax, cx
	xchg di, bx
	extcallcall decword
reloc	mov si, msg.stack.4
internaldatarelocation

.string_end:
	extcallcall copy_single_counted_string
	extcallcall putsline
	retn


display_eld_memory:
reloc	mov dx, msg.eld.1
internaldatarelocation
	extcallcall putsz

	xor ax, ax
.loop:
reloc	mov di, relocateddata
linkdatarelocation line_out
	getotherds
reloc	cmp word [relocateddata], ax
otherlinkdatarelocation extseg_used
	ja @F

	xor bp, bp
reloc	mov dx, word [relocateddata]
otherlinkdatarelocation extseg_size
	sub dx, ax
	xor bx, bx
	xor cx, cx
.free:
	 push ss
	 pop ds
	push cx
reloc	mov si, msg.eld.free
internaldatarelocation
	extcallcall copy_single_counted_string
	pop cx
	jmp .have

@@:
reloc	mov bx, relocateddata
otherlinkdatarelocation extdssel, -2, optional
	extcallcall ispm
	jz @F
reloc	mov bx, relocateddata
otherlinkdatarelocation extseg, -2, optional
@@:
	test bx, bx
	jnz @F
.error:
	resetds
reloc	mov dx, msg.eld.error
internaldatarelocation
	extcallcall putsz
	jmp .end

@@:
	mov es, word [bx]
	mov bx, ax
	cmp word [es:bx + eldiStartCode], ax
	jne .error
	mov dx, ax
	add dx, ELD_INSTANCE_size
	jc .error
	cmp word [es:bx + eldiEndCode], dx
	jb .error
reloc	mov dx, word [relocateddata]
otherlinkdatarelocation extseg_used
	cmp word [es:bx + eldiEndCode], dx
	ja .error
	je @F
	sub dx, ELD_INSTANCE_size
	jc .error
	cmp word [es:bx + eldiEndCode], dx
	ja .error
@@:
	mov dx, word [es:bx + eldiEndCode]
	mov bp, dx
	sub dx, ax
	jc .error
	push word [es:bx + eldiStartData]
	push bx
	mov bx, word [es:bx + eldiEndData]
	pop si
	testopt [es:si + eldiFlags], eldifResident
	lea si, [si + eldiIdentifier]
	push es
	pop ds
	 push ss
	 pop es
	pop cx
	jnz .nonfree

	push cx
	push ds
	push si
	 push ss
	 pop ds
reloc	mov si, msg.eld.free
internaldatarelocation
	extcallcall copy_single_counted_string

reloc	mov si, msg.eld.2
internaldatarelocation
	push bx
	call display_eld_size
	pop bx

reloc	mov si, msg.eld.free.2
internaldatarelocation
	extcallcall copy_single_counted_string

	pop si
	pop ds

	call .copyname

reloc	mov si, msg.eld.free.3
internaldatarelocation
	extcallcall copy_single_counted_string

	pop cx

	jmp .havedata

.copyname:
	push cx
	push ax
	mov al, '"'
	stosb
	mov cx, 4
	rep movsw
	stosb
	pop ax
	 push ss
	 pop ds
	pop cx
	retn

.nonfree:
	call .copyname

.have:
reloc	mov si, msg.eld.2
internaldatarelocation
	push bx
	call display_eld_size
	pop bx

.havedata:
	mov ax, bx
	sub ax, cx
	jz .next
	xchg dx, ax
	mov ax, cx
reloc	mov si, msg.eld.5
internaldatarelocation
	call display_eld_size

.next:
	extcallcall putsline_crlf
	test bp, bp
	mov ax, bp
	jnz .loop
.end:

reloc	mov di, relocateddata
linkdatarelocation line_out
	getotherds
reloc	mov ax, word [relocateddata]
otherlinkdatarelocation extdata_used
reloc	mov dx, word [relocateddata]
otherlinkdatarelocation extdata_size
	sub dx, ax
	jz @F
reloc	add ax, [relocateddata]
otherlinkdatarelocation extdata
reloc	mov si, msg.eld.6
internaldatarelocation
	resetds
	call display_eld_size
	extcallcall putsline_crlf
@@:
	resetds
	retn


display_eld_variables:
reloc	mov di, relocateddata
linkdatarelocation line_out

reloc	mov si, msg.var.format
internaldatarelocation
	extcallcall copy_single_counted_string

reloc	mov ax, relocateddata
otherlinkdatarelocation ext_var_format
	cmp ax, 1
	je .known

.unknown:
reloc	mov di, msg.varunknown.format
internaldatarelocation
	extcallcall hexword

reloc	mov dx, msg.varunknown
internaldatarelocation
	extcallcall putsz
	jmp .end

.known:
	extcallcall hexword

reloc	mov si, msg.var.size
internaldatarelocation
	extcallcall copy_single_counted_string

reloc	mov ax, relocateddata
otherlinkdatarelocation ext_var_size

	extcallcall hexword
	xchg dx, ax

reloc	mov si, msg.var.amount
internaldatarelocation
	extcallcall copy_single_counted_string

	xor bx, bx
reloc	mov cx, relocateddata
otherlinkdatarelocation ext_var_amount
	push cx
	jcxz .donecount

	push di
reloc	mov di, relocateddata
otherlinkdatarelocation ext_var
reloc	mov si, relocateddata
otherlinkdatarelocation isvariable_morebyte_nameheaders.ext
	getotherds
.loopcount:
	cmp word [di], 0
	je .nextcount
	inc bx
.nextcount:
	add di, dx
	lodsw
	loop .loopcount
	pop di
.donecount:
	resetds

	xchg ax, bx
	extcallcall decword

reloc	mov si, msg.var.amountbetween
internaldatarelocation
	extcallcall copy_single_counted_string

	pop ax
	extcallcall decword
	push ax

reloc	mov si, msg.var.amountafter
internaldatarelocation
	extcallcall copy_single_counted_string
	push dx
	extcallcall putsline_crlf
	pop dx
	pop cx

reloc	mov bx, relocateddata
otherlinkdatarelocation ext_var
reloc	mov si, relocateddata
otherlinkdatarelocation isvariable_morebyte_nameheaders.ext

	getotherds
	jcxz .donelist
.looplist:
	cmp word [bx], 0
	je .nextlist
	push cx
	push si

reloc	mov di, relocateddata
linkdatarelocation line_out

	resetds
reloc	mov si, msg.var.list.flags
internaldatarelocation
	extcallcall copy_single_counted_string

	getotherds
	mov ax, word [bx + ivFlags]
	extcallcall hexword

	resetds
reloc	mov si, msg.var.list.array
internaldatarelocation
	extcallcall copy_single_counted_string

	getotherds
	mov al, byte [bx + ivArrayLast]
	extcallcall hexbyte

	mov al, byte [bx + ivArrayBetween]
	resetds
	test al, al
	jz @F

reloc	mov si, msg.var.list.between
internaldatarelocation
	extcallcall copy_single_counted_string

	extcallcall hexbyte
@@:

reloc	mov si, msg.var.list.name
internaldatarelocation
	extcallcall copy_single_counted_string

	pop si
	getotherds
	movsw
	push si

	mov si, word [bx + ivName]
	mov cx, word [bx + ivFlags]
	and cx, ivfNameLengthMask
	rep movsb

	push bx
	push dx

	mov ax, word [bx + ivAddress]
	resetds
reloc	mov si, msg.var.list.entry
internaldatarelocation
	call display_entry_and_instance

	extcallcall putsline_crlf
	pop dx
	pop bx

	pop si
	pop cx
	db __TEST_IMM8		; skip lodsw
.nextlist:
	lodsw
	add bx, dx
	loop .looplist
.donelist:

.end:
	retn


display_command_handler:
reloc	mov bx, handlertable.command
internaldatarelocation
	jmp @F

display_amis_handler:
reloc	mov bx, handlertable.amis
internaldatarelocation
	jmp @F

display_asm_handler:
reloc	mov bx, handlertable.asm
internaldatarelocation
	jmp @F

display_puts_handler:
reloc	mov bx, handlertable.puts
internaldatarelocation
	jmp @F

display_inject_handler:
reloc	mov bx, handlertable.inject
internaldatarelocation
@@:

display_handlers:
	houdini
	lframe
	lenter
	 push bx
	lvar word, table
	jmp @F

.next_table:
reloc	mov dx, msg.handler.init.pre
internaldatarelocation
	extcallcall putsz
@@:
	mov dx, word [bx + htMessage]
	extcallcall putsz
reloc	mov dx, msg.handler.init.post
internaldatarelocation
	extcallcall putsz

	mov dx, word [bx + htMessage]
	mov bx, word [bx + htHandler]
	test bx, bx
	jnz @F
	push dx
reloc	mov dx, msg.handler.notpresent.pre
internaldatarelocation
	extcallcall putsz
	pop dx
	extcallcall putsz
reloc	mov dx, msg.handler.notpresent.post
internaldatarelocation
	jmp .putsz_end

@@:
	getotherds
	mov bx, [bx]
	resetds
	test bx, bx
	jnz @F
	push dx
reloc	mov dx, msg.handler.none.pre
internaldatarelocation
	extcallcall putsz
	pop dx
	extcallcall putsz
reloc	mov dx, msg.handler.none.post
internaldatarelocation
.putsz_end:
	extcallcall putsz
	jmp .end

@@:
.loop:
	push ss
	pop es
	push bx
reloc	mov di, relocateddata
linkdatarelocation line_out
	xchg ax, bx
reloc	mov si, msg.commandhandler.entry
internaldatarelocation
	call display_entry_and_instance
	extcallcall putsline_crlf
	pop bx
	call get_es_ext_other
	houdini
	mov si, word [bp + ?table]
	testopt [si + htFlags], htfIsInject
	jnz .end
	testopt [si + htFlags], htfIsAMIS
	jz .notamis
	cmp word [es:bx], 03EBh
	jne .error
	cmp byte [es:bx + 2], 0E9h
	je .next
	cmp byte [es:bx + 2], 0CBh	; retf
	jne .error
	jmp .end

.notamis:
	cmp word [es:bx], 08EBh
	jne .error
	cmp byte [es:bx + 2], 0E9h
	jne @F
.next:
	add bx, word [es:bx + 2 + 1]
	add bx, 2 + 3
	jmp .loop

@@:
%if ! _OTHER
	mov si, word [si + htTemplate]	; cs:si -> template
	mov cx, template_size
	sub sp, fromwords(words(template_size))
	push cs
	pop ds				; ds:si -> template
	mov di, sp			; ss:di -> stack
	push es
	 push ss
	 pop es				; es:di
	 push cx
	rep movsb
	 pop cx				; restore template length
	pop es				; => ELD instance
	push ss
	pop ds				; reset ds
	mov si, sp			; ds:si -> template on stack
	mov ax, [si + 1]
	mov di, word [bp + ?table]
	add ax, word [di + htTemplate]	; change to (biased) absolute offset
	lea di, [bx + 2]		; es:di -> downlink
	sub ax, di			; change to rel16 displacement
	mov word [si + 1], ax		; enter into template
	lea ax, [si + fromwords(words(template_size))]
					; -> prior stack
	rep cmpsb			; does it match expected downlink ?
	mov sp, ax			; reset stack
%else
	cmp byte [es:bx + 2], 0E8h
	jne .error
	mov ax, word [si + htReturn]
	cmp word [es:bx + 2 + 1 + 4], ax
%endif
	je .end
.error:
	push ss
	pop es
	mov bx, word [bp + ?table]
reloc	mov dx, msg.handler.error.pre
internaldatarelocation
	extcallcall putsz
	mov dx, word [bx + htMessage]
	extcallcall putsz
reloc	mov dx, msg.handler.error.post
internaldatarelocation
	jmp .putsz_end

.end:
	push ss
	pop es
	mov bx, word [bp + ?table]
	add bx, HANDLERTABLE_size
	mov word [bp + ?table], bx
	cmp word [bx], 0
	jne .next_table

	lleave
emptyfunction:
	retn


template_commandhandler:
template:
	extcall cmd3_not_ext, required	; must NOT be extcallcall
	endarea template
template_preprocesshandler:
	extcall cmd3_preprocessed, required	; must NOT be extcallcall
template_aabeforehandler:
	extcall aa_before_getline, optional	; must NOT be extcallcall
template_aaafterhandler:
	extcall aa_after_getline, optional	; must NOT be extcallcall
template_putshandler:
	extcall puts_ext_done, required		; must NOT be extcallcall
template_putscohandler:
	extcall puts_copyoutput_ext_done, required
				; must NOT be extcallcall
template_putsgetlinehandler:
	extcall puts_getline_ext_done, required
				; must NOT be extcallcall


display_entry_and_instance:
	extcallcall copy_single_counted_string
	extcallcall hexword

	xchg dx, ax

	call get_es_ext_other
	xor si, si
	xor bx, bx
.loop:
	getotherds
reloc	cmp si, word [relocateddata]
otherlinkdatarelocation extseg_used
	resetds
	jae .notfound
	cmp si, [es:si + eldiStartCode]
	jne .error
	lea bx, [si + ELD_INSTANCE_size]
	cmp bx, word [es:si + eldiEndCode]
	ja .error
	mov bx, word [es:si + eldiEndCode]
	cmp bx, dx
	je .error
	ja .found
.next:
	mov si, bx
	jmp .loop

.found:
	push es				; stack => ext seg
	xchg ax, si			; ax -> instance
	 push ss
	 pop es
reloc	mov si, msg.instance.1
internaldatarelocation
	extcallcall copy_single_counted_string
	extcallcall hexword		; write offset -> instance

reloc	mov si, msg.instance.2
internaldatarelocation
	extcallcall copy_single_counted_string

	xchg si, ax			; si -> instance
	lea si, [si + eldiIdentifier]	; si -> id
	pop ds				; => ext seg
	mov cl, 4			; cx = 4
	rep movsw			; copy id

	push ss
	pop ds

reloc	mov si, msg.instance.3
internaldatarelocation
@@:
	push ss
	pop es
	extcallcall copy_single_counted_string
	retn

.notfound:
reloc	mov si, msg.instance.notfound
internaldatarelocation
	jmp @B

.error:
reloc	mov si, msg.instance.error
internaldatarelocation
	jmp @B


		; INP:	si -> first string
		;	ax = start
		;	dx = length
display_eld_size:
	push cx
	extcallcall copy_single_counted_string
	call hexword
reloc	mov si, msg.eld.3
internaldatarelocation
	extcallcall copy_single_counted_string
	add ax, dx
	call hexword
reloc	mov si, msg.eld.4
internaldatarelocation
	extcallcall copy_single_counted_string
	mov ax, dx
	call hexword
reloc	mov si, msg.size.2
internaldatarelocation
	extcallcall copy_single_counted_string
	xor dx, dx
	mov cx, 1
	mov bx, 9
	extcallcall disp_dxax_times_cx_width_bx_size.store
	pop cx
	retn


parasize:
reloc	mov si, msg.size.1
internaldatarelocation
	extcallcall copy_single_counted_string
	mov cl, 4
	push ax
	mov dx, ax
	rol ax, cl
	test al, 15
	jz @F
	dec di
	extcallcall hexnyb
@@:
	xchg ax, dx
	shl ax, cl
	extcallcall hexword
reloc	mov si, msg.size.2
internaldatarelocation
	extcallcall copy_single_counted_string
	pop ax
	xor dx, dx
	mov cx, 16
	mov bx, 9
	extcallcall disp_dxax_times_cx_width_bx_size.store
	retn


		; INP:	dx => end of prior
		;	ax => start of next
gap:
	push dx
	neg dx
	add dx, ax
reloc	mov si, msg.gap
internaldatarelocation
	extcallcall copy_single_counted_string
	pop ax
	extcallcall hexword
reloc	mov si, msg.address.1
internaldatarelocation
	extcallcall copy_single_counted_string
	xchg ax, dx
	call parasize
	extcallcall putsline_crlf
reloc	mov di, relocateddata
linkdatarelocation line_out
	retn


	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


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

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

reloc	mov ax, word [cs:code + eldiEndData]
internalcoderelocation
reloc	sub ax, word [cs:code + eldiStartData]
internalcoderelocation
reloc	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

%rep _ELD_BUG
	eldstrict off

	dw msg.ldmem			; missing internaldatarelocation
%endrep

%if _OTHER
	align 2, db 0
otherds:	dw 0
otherseg:	dw 0
%endif

	align 8, db 0
table:
.:
reloc	dw msg.entryseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation pspdbg, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation entryseg_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation cssel, -2, optional

reloc	dw msg.messageseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation messageseg, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation messageseg_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation messagesel, -2, optional

reloc	dw msg.auxbuffseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation auxbuff_segment, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation auxbuff_current_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation auxbuff_segorsel, -2, optional

reloc	dw msg.auxbuffmovableseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation auxbuff_movable_segment, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation auxbuff_movable_current_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation auxbuff_movable_segorsel, -2, optional

reloc	dw msg.codeseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation code_seg, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation code_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation code_sel, -2, optional

reloc	dw msg.codemovableseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation code_movable_seg, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation code_movable_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation code_movable_sel, -2, optional

reloc	dw msg.code2seg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation code2_seg, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation code2_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation code2_sel, -2, optional

reloc	dw msg.code2movableseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation code2_movable_seg, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation code2_movable_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation code2_movable_sel, -2, optional

reloc	dw msg.historyseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation history_segment, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation historyseg_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation history.segorsel, -2, optional

reloc	dw msg.extseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation extseg, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation extseg_size, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation extcssel, -2, optional

reloc	dw msg.envseg
internaldatarelocation
reloc	dw relocateddata
otherlinkdatarelocation envseg, -2, optional
	dw 0
reloc	dw relocateddata
otherlinkdatarelocation env_size, -2, optional
	dw 0
.end:
.amount equ (.end - .) / 10

	dw 0

	align 2, db 0
handlertable:
.command:
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.commandhandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_command_handler
at htTemplate,reloc	dw template_commandhandler
internalcoderelocation
at htReturn,reloc	dw relocateddata
otherlinkdatarelocation cmd3_not_ext
	iend
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.preprocesshandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_preprocess_handler
at htTemplate,reloc	dw template_preprocesshandler
internalcoderelocation
at htReturn,reloc	dw relocateddata
otherlinkdatarelocation cmd3_preprocessed
	iend
	dw 0

.amis:
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.amishandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_amis_handler, -2, optional
at htTemplate,		dw 0
at htReturn,		dw 0
at htFlags,		dw htfIsAMIS
	iend
	dw 0

.asm:
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.aabeforehandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_aa_before_getline_handler, -2, optional
at htTemplate,reloc	dw template_aabeforehandler
internalcoderelocation
at htReturn,reloc	dw relocateddata
otherlinkdatarelocation aa_before_getline, -2, optional
	iend
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.aaafterhandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_aa_after_getline_handler, -2, optional
at htTemplate,reloc	dw template_aaafterhandler
internalcoderelocation
at htReturn,reloc	dw relocateddata
otherlinkdatarelocation aa_after_getline, -2, optional
	iend
	dw 0

.puts:
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.putshandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_puts_handler
at htTemplate,reloc	dw template_putshandler
internalcoderelocation
at htReturn,reloc	dw relocateddata
otherlinkdatarelocation puts_ext_done
	iend
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.putscohandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_puts_copyoutput_handler
at htTemplate,reloc	dw template_putscohandler
internalcoderelocation
at htReturn,reloc	dw relocateddata
otherlinkdatarelocation puts_copyoutput_ext_done
	iend
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.putsgetlinehandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_puts_getline_handler
at htTemplate,reloc	dw template_putsgetlinehandler
internalcoderelocation
at htReturn,reloc	dw relocateddata
otherlinkdatarelocation puts_getline_ext_done
	iend
	dw 0

.inject:
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.commandinjecthandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_inject_handler
at htTemplate,		dw 0
at htReturn,		dw 0
at htFlags,		dw htfIsInject
	iend
	istruc HANDLERTABLE
at htMessage,reloc	dw msg.aainjecthandler
internaldatarelocation
at htHandler,reloc	dw relocateddata
otherlinkdatarelocation ext_aa_inject_handler, -2, optional
at htTemplate,		dw 0
at htReturn,		dw 0
at htFlags,		dw htfIsInject
	iend
	dw 0

	align 2, db 0
store_table:
reloc	dw relocateddata
otherlinkdatarelocation patcharea_run, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation patcharea_run.segment, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation patcharea_run.size, -2, optional
reloc	dw msg.patch_area_run
internaldatarelocation

reloc	dw relocateddata
otherlinkdatarelocation patcharea_intrtn, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation patcharea_intrtn.segment, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation patcharea_intrtn.size, -2, optional
reloc	dw msg.patch_area_intrtn
internaldatarelocation

reloc	dw relocateddata
otherlinkdatarelocation patcharea_pm_exc, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation patcharea_pm_exc.segment, -2, optional
reloc	dw relocateddata
otherlinkdatarelocation patcharea_pm_exc.size, -2, optional
reloc	dw msg.patch_area_pm_exc
internaldatarelocation

.end:

	struc STORETABLEENTRY
steAreaOffset:		resw 1
steAreaSegmentVariable:	resw 1
steAreaLength:		resw 1
steName:		resw 1
	endstruc


	align 2, db 0
nountable:
	db msg.all - $ - 1
	db 1
reloc	dw msg.all_replace
internaldatarelocation
	db msg.allexceptseg - $ - 1
	db 1
reloc	dw msg.allnoseg_replace
internaldatarelocation
	db msg.eldall - $ - 1
	db 1
reloc	dw msg.eldall_replace
internaldatarelocation
	db msg.eldhandlers - $ - 1
	db 1
reloc	dw msg.eldhandlers_replace
internaldatarelocation
	db msg.mem - $ - 1
	db 0
reloc	dw display_mem
internalcoderelocation
	db msg.history - $ - 1
	db 0
reloc	dw historysize
internalcoderelocation
	db msg.stack - $ - 1
	db 0
reloc	dw stacksize
internalcoderelocation
	db msg.eld - $ - 1
	db 0
reloc	dw display_eld_memory
internalcoderelocation
	db msg.eldvar - $ - 1
	db 0
reloc	dw display_eld_variables
internalcoderelocation
	db msg.commandhandler_noun - $ - 1
	db 0
reloc	dw display_command_handler
internalcoderelocation
	db msg.amishandler_noun - $ - 1
	db 0
reloc	dw display_amis_handler
internalcoderelocation
	db msg.asmhandler - $ - 1
	db 0
reloc	dw display_asm_handler
internalcoderelocation
	db msg.putshandler_noun - $ - 1
	db 0
reloc	dw display_puts_handler
internalcoderelocation
	db msg.injecthandler_noun - $ - 1
	db 0
reloc	dw display_inject_handler
internalcoderelocation
	db msg.seg - $ - 1
	db 0
reloc	dw display_seg
internalcoderelocation
	db msg.patch - $ - 1
	db 0
reloc	dw display_patchareas
internalcoderelocation
	dw 0

history_data_entry:
	db 0

msg:
.all:		asciz "ALL"
.allexceptseg:	asciz "ALLNOSEG"
.seg:		asciz "SEG"
.patch:		asciz "PATCH"
.mem:		asciz "MEM"
.history:	asciz "HISTORY"
.stack:		asciz "STACK"
.eldall:	asciz "ELDALL"
.eld:		asciz "ELD"
.eldvar:	asciz "ELDVAR"
.eldhandlers:	asciz "ELDHANDLERS"
.commandhandler_noun:	asciz "COMMANDHANDLER"
.amishandler_noun:	asciz "AMISHANDLER"
.asmhandler:		asciz "ASMHANDLER"
.putshandler_noun:	asciz "PUTSHANDLER"
.injecthandler_noun:	asciz "INJECTHANDLER"
.all_replace:		asciz "MEM SEG HISTORY STACK ELDALL PATCH"
.allnoseg_replace:	asciz "MEM HISTORY STACK ELDALL PATCH"
.eldall_replace:	asciz "ELD ELDVAR ELDHANDLERS"
.eldhandlers_replace:	asciz "COMMANDHANDLER AMISHANDLER ASMHANDLER PUTSHANDLER INJECTHANDLER"
.notfound.1:		asciz 'Noun "'
.notfound.2:		asciz '" not found!',13,10
.ldmem:			asciz "LDMEM",OTH_STRING
.uninstall_done:	db "LDMEM",OTH_STRING," uninstalled."
%if _ELD_RECLAIM_HINT
			db " (Don't forget to use reclaim.eld)"
%endif
			asciz 13,10
.uninstall_error:	asciz "LDMEM",OTH_STRING," unable to uninstall!",13,10
.entryseg:	counted "Entry"
		counted
.messageseg:	counted "Message"
		counted
.codeseg:	counted "First code"
		counted "Code1"
.codemovableseg:counted "First code (M)"
		counted "Code1(M)"
.code2seg:	counted "Second code"
		counted "Code2"
.code2movableseg:
		counted "Second code (M)"
		counted "Code2(M)"
.auxbuffseg:	counted "Auxiliary buffer"
		counted "Auxiliary"
.auxbuffmovableseg:
		counted "Aux (M) buffer"
		counted "Aux(M)"
.historyseg:	counted "History"
		counted
.extseg:	counted "ELD code"
		counted
.envseg:	counted "Environment"
		counted "Env"
.segment_colon:	counted " segment: "
.none:		counted "None (Segment data not available.)"
.nonesize:	counted "Size data not available."
.address.1:	counted "  "
.size.1:	counted "Size:  "
.size.2:	counted "  "
.sel:		counted "  selector: "
.dssel:		counted "Entry/data selector: "
.extdssel:	counted "ELD code segment data selector: "
.alloc:		fill 26, 32, db "Total allocation: "
		asciz
.gap:		db .gap.end - ($ + 1)
		fill 26, 32, db "Gap: "
.gap.end:
.overlap:		asciz "Overlap!",13,10
.history_none:		asciz "No history format link found.",13,10
.history_data_entry:	asciz "History in data entry section.",13,10
.history_separate:	asciz "History in a separate segment.",13,10
.history_unknown:	asciz "Unknown history format.",13,10
.history_missing:	asciz "History last or first displacement or segment missing.",13,10
.history.1:		counted "History entries: "
.history.2:		counted 13,10,"History bytes: "
.history.3:		counted " used / "
.history.average.1:	counted " total",13,10,"Average history entry size is <= "
.history.average.2:	counted " bytes."
.history.average.none:	counted " total",13,10,"Cannot calculate average, no history entries."
.stack.none:		counted "No stack link found.",13,10
.stack.1:		counted "Stack size: "
.stack.2:		counted " bytes",13,10,"Heuristic match byte: "
.stack.3:		counted "h",13,10,"Heuristic unused stack: "
.stack.4:		counted " bytes",13,10
.eld.1:			asciz "Loaded ELDs:",13,10
.eld.error:		asciz "Error during ELD enumeration.",13,10
.eld.free:		counted "Free space"
.eld.free.2:		counted " ("
.eld.free.3:		counted ")"
.eld.2:			counted ", code start "
.eld.3:			counted ", stop "
.eld.4:			counted ", size "
.eld.5:			db .eld.5.end - ($ + 1)
			db 13,10
			times 8 + 2 + 2 db 32
			db "Data start "
.eld.5.end:
.eld.6:			counted "Free space, data start "
.var.format:		counted "Ext variables format="
.var.size:		counted "h, structure size="
.var.amount:		counted "h",13,10,"Amount ext variables: "
.var.amountbetween:	counted " used / "
.var.amountafter:	counted " total"
.varunknown:		db 13,10,"Unknown ext variables format="
.varunknown.format:	db "----h"
.linebreak:		db 13,10
.empty:			asciz
.var.list.flags:	counted "Flags="
.var.list.array:	counted "h array="
.var.list.between:	counted "h between="
.var.list.name:		counted "h name=",'"'
.var.list.entry:	counted '"',13,10," Entry="
.instance.1:		counted "h, instance="
.instance.2:		counted "h, identifier=",'"'
.instance.3:		counted '"'
.instance.notfound:	counted "h. Instance not found!"
.instance.error:	counted "h. Instance error!"
.commandhandler.entry:	counted " Entry="
.handler.init.pre:	asciz 13,10
.handler.init.post:	asciz " handlers:",13,10
.handler.none.pre:	asciz " Entry=0000h - No "
.handler.none.post:	asciz " handler installed.",13,10
.handler.notpresent.pre:	asciz " No "
.handler.notpresent.post:	asciz " handler hook present.",13,10
.handler.error.pre:	asciz " "
.handler.error.post:	asciz " handler error!",13,10
.commandhandler:	asciz "Command"
.preprocesshandler:	asciz "Preprocess"
.amishandler:		asciz "AMIS"
.aabeforehandler:	asciz "Assembler before"
.aaafterhandler:	asciz "Assembler after"
.putshandler:		asciz "Multi-purpose puts"
.putscohandler:		asciz "COPYOUTPUT puts"
.putsgetlinehandler:	asciz "GETLINE puts"
.commandinjecthandler:	asciz "Command inject"
.aainjecthandler:	asciz "Assembler inject"
.patch_area.1:		asciz "Patch area, length "
.patch_area.2.inuse:	asciz " (in use), "
.patch_area.2.notinuse:	asciz " (free), "
.patch_area.3.entry:	asciz "entry"
.patch_area.3.code:	asciz "code"
.patch_area.3.unknown:	db "unknown="
.patch_area.3.unknown.s:asciz "----h"
.patch_area.3.offset:	db ":"
.patch_area.3.offset.o:	asciz "----h, "
.patch_area.4:		asciz "name: "
.patch_area.5:		asciz "Patch area not present: "
.patch_area_run:	asciz "Run"
.patch_area_intrtn:	asciz "86 Mode intrtn"
.patch_area_pm_exc:	asciz "Protected Mode exc"

uinit_data: equ $
.installed:		asciz "LDMEM",OTH_STRING," installed.",13,10
.keyword_help:		asciz "HELP"
.help:		db "This ELD can be installed residently or used transiently.",13,10
		db 13,10
		db "Any number of keywords can be passed to this ELD to choose output:",13,10
		db 9,"(none)",9,9,"Alias to ALLNOSEG",13,10
		db 9,"ALL",9,9,"Display all output",13,10
		db 9,"ALLNOSEG",9,"Display all output except SEG",13,10
		db 9,"ELDALL",9,9,"Display all ELD output",13,10
		db 9,"ELDHANDLERS",9,"Display all ELD handlers",13,10
		db 9,"MEM",9,9,"Display memory areas with segments/selectors",13,10
		db 9,"SEG",9,9,"Display segments/selectors mostly on one line",13,10
		db 9,"HISTORY",9,9,"Display history utilisation",13,10
		db 9,"STACK",9,9,"Display stack utilisation",13,10
		db 9,"ELD",9,9,"Display ELD code instances and data blocks use",13,10
		db 9,"ELDVAR",9,9,"Display ELD variables",13,10
		db 9,"COMMANDHANDLER",9,"Display ELD command and preprocess handlers",13,10
		db 9,"AMISHANDLER",9,"Display ELD AMIS handlers",13,10
		db 9,"ASMHANDLER",9,"Display ELD assembly handlers",13,10
		db 9,"PUTSHANDLER",9,"Display ELD puts-related handlers",13,10
		db 9,"INJECTHANDLER",9,"Display ELD inject handlers",13,10
		db 9,"PATCH",9,9,"Display patch areas",13,10
		asciz

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

	absolute uinit_data
	alignb 2
separatormessage:
	resw 1

	alignb 8
table_sorted:
	resb 10 * table.amount + 2

	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

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


%include "eldlink.asm"

	align 16
code_size equ $ - code
