
; Public Domain

; test run command: list.eld; .; .

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

%assign _CATCHINT0C 0
%assign _CATCHINT0D 0
%assign _CATCHINTFAULTCOND 0
%assign _DEBUG 0
%assign _DELAY_BEFORE_BP 0
%assign _DHIGHLIGHT 0
%assign _GETLINEHIGHLIGHT 0
%assign _IMMASM 0
%assign _INPUT_FILE_BOOT 0
%assign _INPUT_FILE_HANDLES 0
%assign _MS_0RANGE_COMPAT 0
%assign _PM 0
%assign _RH 0
%assign _SYMBOLIC 0
%assign _VXCHG 0
%include "options.mac"

%include "iniload.mac"

	numdef BOOTLDR, 1
	numdef BOOTLDR_WILD, 1
	numdef COMPRESSED, 1
	numdef DATABUFFER, 1
	numdef ELDTRAILER, 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
at eldhxHelpOffset,		dd DATAOFFSET + msg.help - datastart
PUT_ELDHX_DATETIME_OFFSET
header_extension_end:
	iend

description:		asciz "Display ELD description lines."

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


run:
	push ss
	pop es
%if _BOOTLDR
reloc	testopt [relocateddata], nodosloaded
linkdatarelocation internalflags, -3
	jz run_dos
.boot:
	extcallcall yy_boot_parse_name2
	call parse_verbose

boot_find:
reloc	mov word [boot_parsed], bx
internaldatarelocation
 %if _BOOTLDR_WILD
	push bx
	mov di, bx
	call find_dir
	pop bx
	mov dx, di
	db __TEST_IMM8			; (skip inc)
@@:
	inc di
	cmp byte [di], 0
	je boot_no_wild
	cmp byte [di], '?'
	je boot_wild
	cmp byte [di], '*'
	jne @B

boot_wild:
reloc	mov word [wild_pattern], dx
internaldatarelocation

	extcall yy_boot_init_dir2	; calls initialise_fs
reloc	mov byte [relocateddata], 0
linkdatarelocation load_check_dir_attr, -3
reloc	mov si, word [relocateddata]
linkdatarelocation load_yyname_input
	cmp byte [si], '/'
	jne @F
	inc si
@@:
	cmp byte [si], 0
	jne @F
	extcall ..@yy_filename_empty
@@:
	 push ss
	 pop es
	call boot_parse_name
	cmp al, '/'
	jne @F
reloc	mov byte [relocateddata], ATTR_DIRECTORY
linkdatarelocation load_check_dir_attr, -3
reloc	mov word [relocateddata], si
linkdatarelocation load_yyname_next
@@:

	mov di, -1
	mov si, di
	mov [bp + lsvFATSector], di
	mov [bp + lsvFATSector + 2], si

	xor ax, ax
	xor dx, dx

scan_dir_yyname_loop:
	mov word [bp + ldDirCluster], ax
	mov word [bp + ldDirCluster + 2], dx

	push ss
	pop es
reloc	mov bx, relocateddata
linkdatarelocation load_yy_direntry

reloc2	mov word [relocateddata], relocateddata
linkdatarelocation handle_scan_dir_not_found, -4
;linkdatarelocation near_transfer_ext_entry
linkdatarelocation dmycmd
	extcall scan_dir_aux
	jc end_of_directory

reloc	cmp byte [relocateddata], ATTR_DIRECTORY
linkdatarelocation load_check_dir_attr, -3
	jne got_single_yyentry

	push si
	push di
reloc	mov byte [relocateddata], 0
linkdatarelocation load_check_dir_attr, -3
reloc	mov si, word [relocateddata]
linkdatarelocation load_yyname_next
	cmp byte [si], 0
	jne @F
	extcall ..@yy_filename_empty
@@:
	push es
	 push ss
	 pop es
	call boot_parse_name
	pop es
	cmp al, '/'
	jne @F
reloc	mov byte [relocateddata], ATTR_DIRECTORY
linkdatarelocation load_check_dir_attr, -3
reloc	mov word [relocateddata], si
linkdatarelocation load_yyname_next
@@:
	pop di
	pop si

	xor dx, dx
	mov ax, [es:bx + deClusterLow]
				; = first cluster (not FAT32)
	cmp byte [bp + ldFATType], 32
	jne @F
	mov dx, [es:bx + deClusterHigh]
				; dx:ax = first cluster (FAT32)
@@:

	jmp scan_dir_yyname_loop

boot_parse_name:
reloc	cmp word [wild_pattern], si
internaldatarelocation
	je @F
	extcallcall boot_parse_fn	; get next pathname

reloc2	mov word [relocateddata], relocateddata
linkdatarelocation handle_scan_dir_entry, -4
linkdatarelocation scan_dir_entry

	retn

@@:
	extcallcall boot_parse_fn	; get next pathname

reloc2	mov word [relocateddata], match_wildcard
linkdatarelocation near_transfer_ext_address, -4
internalcoderelocation
reloc2	mov word [relocateddata], relocateddata
linkdatarelocation handle_scan_dir_entry, -4
linkdatarelocation near_transfer_ext_entry

	push ax
reloc	mov di, relocateddata
linkdatarelocation load_kernel_name
	mov cx, 8
	call .handle_asterisk		; handle in basename
	mov cl, 3
	call .handle_asterisk		; handle in extension
	pop ax
	retn

.handle_asterisk:
	mov al, '*'
	repne scasb			; scan for asterisk
	jne @F				; not found -->
	mov al, '?'			; fill with question marks
	dec di				; -> at the asterisk
	inc cx				; = how many bytes remain
	rep stosb			; fill this field
@@:
	retn


		; INP:	es:di -> DIRENTRY
		;	dx:ax - 1 = sector
		;	cx, si in use
		; OUT:	CY if end of directory
		;	NC if to continue,
		;	 ZR if match
		;	 NZ if mismatch
		; CHG:	bx
match_wildcard:
	cmp byte [es:di], 0
	stc
	je .ret
	mov bl, byte [es:di + deAttrib]
	test bl, ATTR_VOLLABEL
	jnz .ret_NC		; skip volume labels (and LFNs) --> (NZ)
	and bl, ATTR_DIRECTORY	; isolate directory bit
	; cmp bl, byte [load_check_dir_attr]	; is it what we're searching?
	; jne .ret_NC				; no -->
	jnz .ret_NC		; must not be directory -->
	push si
	push di
	push cx
reloc	mov si, relocateddata	; ds:si-> name to match
linkdatarelocation load_kernel_name
	mov cx, 11		; length of padded 8.3 FAT filename
@@:
	repe cmpsb		; check entry
	je @F			; match -->
	cmp byte [si - 1], '?'	; wildcard ?
	je @B			; yes --> (ZR)
				; no (NZ)
@@:
	pop cx
	pop di
	pop si
	jne .ret_NC

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

	mov cx, DIRENTRY_size
	push ds
	 push es
	 pop ds
	mov si, di		; ds:si -> entry in directory buffer
	push ss
	pop es
reloc	mov di, relocateddata	; es:di -> destination for entry
linkdatarelocation load_yy_direntry
	push di
	rep movsb
	pop si
	pop ds

reloc	mov di, pathnamebuffer - 1
internaldatarelocation		; di -> buffer
	mov al, 0
	stosb
	push di
	mov cl, 8
	cmp byte [si], 05h
	jne @F
	mov al, 0E5h
	stosb
	dec cx
	inc si
@@:
	rep movsb
	mov cl, 9
	db __TEST_IMM8
@@:
	dec di
	cmp byte [di - 1], 32
	loope @B
	mov al, '.'
	stosb
	mov cl, 3
	rep movsb
	mov cl, 4
	db __TEST_IMM8
@@:
	dec di
	cmp byte [di - 1], 32
	loope @B
	cmp byte [di - 1], '.'
	jne @F
	dec di
@@:
	mov al, 0
	stosb

	extcallcall got_yyentry
reloc	clropt [relocateddata], dif3_auxbuff_guarded_1
linkdatarelocation internalflags3, -3
	 push ss
	 pop es
	pop dx
reloc	mov ax, relocateddata
linkdatarelocation load_data_lowest	; make yy_boot_get and yy_boot_update no-ops
	call commonhandle
reloc	setopt [relocateddata], dif3_auxbuff_guarded_1
linkdatarelocation internalflags3, -3
	pop cx
	pop ax
	pop dx
	pop di
	pop es
	pop si			; restore registers

	sub ax, 1
	sbb dx, 0
reloc	mov bx, [relocateddata]
linkdatarelocation load_adr_dirbuf_segment
	extcall read_sector	; restore sector

reloc	or byte [found], -1
internaldatarelocation -3	; NZ
.ret_NC:
	clc
.ret:
	extcall near_transfer_ext_return, required ; must NOT be extcallcall


end_of_directory:
reloc	rol byte [found], 1
internaldatarelocation
	jc @F

	; pushf
reloc	clropt [relocateddata], dif3_auxbuff_guarded_1
linkdatarelocation internalflags3, -3
	; popf

	houdini
;reloc	mov di, word [relocateddata]
;linkdatarelocation load_yyname_input
reloc	mov di, word [boot_parsed]
internaldatarelocation
	extcallcall retry_open_scriptspath
	jz boot_find

	mov ax, 0E47h
	extcallcall setrc
reloc	mov dx, msg.notfound
internaldatarelocation
	extcallcall putsz
@@:
	extcallcall cmd3

got_single_yyentry:
	extcallcall got_yyentry
	jmp @F

boot_no_wild:
 %endif

	extcallcall yy_boot_open_file2	; calls initialise_fs
@@:
reloc	clropt [relocateddata], dif3_auxbuff_guarded_1
linkdatarelocation internalflags3, -3

%if _DATABUFFER
reloc	testopt [relocateddata], nodosloaded
linkdatarelocation internalflags, -3
	jz .skipdatabuffer
	mov cl, 4
	mov ax, ss
reloc	mov bx, databuffer
internaldatarelocation
	test bl, 15
	jnz .skipdatabuffer
	shr bx, cl
	add ax, bx
reloc	mov word [relocateddata - LOADDATA2 + ldDataSegment], ax
linkdatarelocation load_data
	xor ax, ax
reloc	mov word [relocateddata - LOADDATA2 + ldDataSector + 2], ax
linkdatarelocation load_data
reloc	mov word [relocateddata - LOADDATA2 + ldDataSector], ax
linkdatarelocation load_data
reloc	setopt [relocateddata - LOADDATA2 + ldFlags], ldfDataBuffered
linkdatarelocation load_data, -3
.skipdatabuffer:
%endif

reloc	mov di, word [relocateddata]
linkdatarelocation load_yyname_input
	call find_dir
	mov dx, di
reloc	mov ax, relocateddata
linkdatarelocation load_data_lowest	; make yy_boot_get and yy_boot_update no-ops
	call commonhandle
	extcallcall cmd3
%endif

run_dos:
	extcallcall InDOS
	extcallcall yy_dos_parse_name
	call parse_verbose

	push bx

	mov ah, 2Fh			; get DTA
	extcallcall ispm
	jnz .rm

subcpu 286
	push word 0
	push word 21h
	extcall intcall_ext_return_es, PM required	; must NOT be extcallcall
	pop dx				; discard interrupt number
	pop dx				; get es
subcpureset
	jmp @F
.rm:
	int 21h
	mov dx, es
@@:

reloc	mov word [originaldta], bx
internaldatarelocation
reloc	mov word [originaldta + 2], dx
internaldatarelocation

reloc	mov ax, word [relocateddata]
linkdatarelocation ext_inject_handler
reloc	mov word [originalinject], ax
internaldatarelocation
reloc2	mov word [relocateddata], inject
linkdatarelocation ext_inject_handler, -4
internalcoderelocation
	call get_es_ext
reloc	setopt [es:code + eldiFlags], eldifResident
internalcoderelocation -3	; mark block as resident
	 push ss
	 pop es

	houdini
reloc	mov dx, dta
internaldatarelocation
	mov ah, 1Ah		; set DTA
	extcallcall _doscall

	pop dx

.find:
reloc	mov word [findnext_function_number], 714Fh
internaldatarelocation -4
	mov ax, 714Eh
	mov cx, 6		; find all files, no directories
	mov si, 1
reloc	mov di, finddata
internaldatarelocation
reloc	rol byte [prefersfn], 1
internaldatarelocation
	jc .sfn_try
	stc
	extcallcall _doscall
	jnc .lfn_found
	cmp ax, 1
	je .sfn_try
	cmp ax, 7100h
	je .sfn_try
	jmp .notfound

.lfn_found:
reloc	mov word [findhandle], ax
internaldatarelocation
reloc	mov byte [findhandle_set], 0FFh
internaldatarelocation -3
	jmp .next

.sfn_try:
reloc	mov word [findnext_function_number], 4F00h
internaldatarelocation -4
	mov ax, 4E00h
	mov cx, 6		; find all files, no directories
	extcallcall _doscall
	jc .notfound

.next:
	push dx
	mov di, dx
	call find_dir
	mov si, bx		; si -> path
	mov cx, di
	sub cx, si		; cx = length of path
reloc	mov di, pathnamebuffer
internaldatarelocation		; di -> buffer
	mov bx, di		; bx -> buffer
	rep movsb
	mov dx, di		; dx -> where we store filename
reloc	mov si, dta.name
internaldatarelocation
	mov cx, 13

reloc	cmp byte [findnext_function_number + 1], 71h
internaldatarelocation -3
	jne .sfn_copy

reloc	mov si, finddata.fullname
internaldatarelocation
	push di
	mov cx, -1
	mov al, 0
	mov di, si
	repne scasb		; cx = -2, copy 1 byte
	not cx
	pop di

.sfn_copy:
	rep movsb

	push dx
	extcallcall yy_open_file
	pop dx
reloc	mov word [relocateddata], ax
linkdatarelocation ext_handle
@@:
	call commonhandle
	extcallcall close_ext
	pop dx
reloc	mov ax, word [findnext_function_number]
internaldatarelocation
reloc	mov bx, word [findhandle]
internaldatarelocation
	mov si, 1
reloc	mov di, finddata
internaldatarelocation
	stc
	extcallcall _doscall
	jnc .next

	extcallcall cmd3


.notfound:
	mov di, dx
	extcallcall retry_open_scriptspath
	mov dx, bx
	jz .find

	mov ax, 0E48h
	extcallcall setrc
reloc	mov dx, msg.notfound
internaldatarelocation
	extcallcall putsz
	extcallcall cmd3


parse_verbose.loop:
	lodsb
parse_verbose:
	extcallcall skipcomm0
	extcallcall iseol?
	jne @F
	retn

@@:
	dec si
reloc	mov dx, msg.verbose
internaldatarelocation
	extcallcall isstring?
	jne @F
reloc	mov byte [verbose], 0FFh
internaldatarelocation -3
	jmp .loop

@@:
reloc	mov dx, msg.string_help
internaldatarelocation
	extcallcall isstring?
	jne @F
reloc	mov byte [do_help], 0FFh
internaldatarelocation -3
	jmp .loop

@@:
reloc	mov dx, msg.string_sfn
internaldatarelocation
	extcallcall isstring?
	jne @F
reloc	mov byte [prefersfn], 0FFh
internaldatarelocation -3
	jmp .loop

@@:
reloc	mov dx, msg.string_lib
internaldatarelocation
	extcallcall isstring?
	jne @F
reloc	mov byte [lib], 0FFh
internaldatarelocation -3
	jmp .loop

.error:
	jmp error

@@:
	lodsb
	cmp al, '/'
	jne .error
reloc	mov di, libnamebuffer
internaldatarelocation
	mov ax, 2020h
	push di
	times 4 stosw
	pop di
reloc	rol byte [libname], 1
internaldatarelocation
	jc .error
reloc	not byte [libname]
internaldatarelocation
@@:
	lodsb
	extcallcall iseol?
	je .nameend
	cmp al, 32
	je .nameend
	cmp al, 9
	je .nameend
	cmp al, ','
	je .nameend
reloc	cmp di, strict word libnamebuffer + 8
internaldatarelocation
	jae .error
	extcallcall uppercase
	stosb
	cmp al, '*'
	jne @B
	dec di
	mov al, '?'
@@:
	stosb
reloc	cmp di, strict word libnamebuffer + 8
internaldatarelocation
	jb @B
	lodsb
	extcallcall iseol?
	je .nameend
	cmp al, 32
	je .nameend
	cmp al, 9
	je .nameend
	cmp al, ','
	jne .error
.nameend:
	dec si
	jmp .loop


find_dir:
	mov bx, di		; bx -> start of path
	mov cx, -1
	mov al, 0
	repne scasb
	dec di
@@:
	cmp di, bx
	jbe .di
	dec di
	cmp byte [di], '/'
	je .di_plus_one
	cmp byte [di], '\'
	je .di_plus_one
	cmp byte [di], ':'
	jne @B
.di_plus_one:
	inc di
.di:				; di -> end of path
	retn


		; INP:	file is opened
		;	file seek is at ELD/SLD header
		;	ax = file handle or bootloaded file structure offset
		;	 (write to bx for file access functions)
		;	dx -> ASCIZ name of matched file
commonhandle:
%if _COMPRESSED
	stc
%endif
	mov bl, 0
.lib:
		; INP:	CY, bl = 0 if top level file (SLD or ELD),
		;	 file seek is zero
		;	CY, bl = 1 if uncompressed library's ELD,
		;	 file seek is at ELD header
		;	NC, bl = 1 if compressed library's ELD,
		;	 cx:di = offset within compressed library
	lframe
	lvar word, more_help
	lvar dword, liboffset
	lvar dword, libnext
	lvar word, libamount
	lvar 12 + 2, libentry
	lequ ?libentry, state
	lequ ?libentry + 2, tail
	lequ ?libentry + 4, next
	lequ ?libentry + 6, helpstarted
	lenter
	lvar word, not_sld_bit_0
	 push bx
%if _COMPRESSED
	lvar word, uncompressed_bit_0
	 pushf
reloc	mov word [depackskip], di
internaldatarelocation
reloc	mov word [depackskip + 2], cx
internaldatarelocation
%endif
	lvar word, handle
	 push ax
	xchg bx, ax		; bx = handle
	extcallcall putsz
	mov di, dx

	xor cx, cx
	xor dx, dx
	mov ax, 4201h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error
	lvar dword, eldheader
	 push dx
	 push ax

reloc	mov dx, msg.colon
internaldatarelocation
	extcallcall putsz

	mov al, 0
	mov cx, -1
	repne scasb		; cx = -2 means 0 bytes, -3 means 1 bytes
%if 0
	not cx			; cx = 1 means 0 bytes
	cmp cx, 8 + 1 + 3 + 1
	jae @FF
	neg cx
	add cx, 8 + 1 + 3 + 1
%else
		; I give up, it's magic
	add cx, (8 + 1 + 3 + 1) + 1
	jnc @FF
	jz @FF
%endif
@@:
	mov al, 32
	extcallcall putc
	loop @B
@@:

%if _ELDTRAILER
	testopt [bp + ?not_sld_bit_0], 1
	jnz .no_trailer_no_seek
	mov ax, 4202h
	xor cx, cx
	xor dx, dx
	call seek_compressed_or_dos_or_boot_io
	jc .io_error

	test dx, dx
	jnz @F
	cmp ax, ELD_HEADER_size + ELD_TRAILER_HEADER_size
	jb .no_trailer
@@:

	mov ax, 4201h
	mov cx, -1
	mov dx, - ELD_TRAILER_HEADER_size
	call seek_compressed_or_dos_or_boot_io
	jc .io_error

	push dx
	push ax

	mov cx, fromwords(ELD_TRAILER_HEADER_size_w)
	sub sp, cx
	mov dx, sp

	mov ah, 3Fh
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	mov di, sp
	mov si, sp

	cmp ax, cx
	jne .no_trailer_pop

	xor dx, dx
	shr cx, 1
@@:
	lodsw
	add dx, ax
	loop @B
	jnz .no_trailer_pop

	pop ax
	cmp ax, "EL"
	jne .no_trailer_pop
	pop ax
	cmp ax, "D1"
	jne .no_trailer_pop
	pop ax
	cmp ax, "TA"
	jne .no_trailer_pop
	pop ax
	cmp ax, "IL"
	jne .no_trailer_pop

	pop si
	pop cx			; cx:si = displacement to subtract
	pop ax			; reserved
	pop ax			; checksum

	pop ax
	pop dx			; dx:ax = offset of trailer header
	add ax, si
	adc dx, cx		; dx:ax = offset of header
	jnc .io_error

	mov word [bp + ?eldheader], ax
	mov word [bp + ?eldheader + 2], dx

.no_trailer_pop:
	lea sp, [di + fromwords(ELD_TRAILER_HEADER_size_w) + 4]

.no_trailer:
	mov ax, 4200h
	mov dx, word [bp + ?eldheader]
	mov cx, word [bp + ?eldheader + 2]
	call seek_compressed_or_dos_or_boot_io
	jc .io_error

.no_trailer_no_seek:
%endif

	mov ah, 3Fh
	mov cx, fromwords(ELD_HEADER_size_w)
	lvar fromwords(ELD_HEADER_size_w), header
	sub sp, cx
	mov dx, sp
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	cmp ax, cx
	jne .invalid_check_sld_NZ
	cmp word [bp + ?header + eldhSignature], "EL"
	jne .invalid_check_sld_NZ
	cmp word [bp + ?header + eldhSignature + 2], "D1"
.invalid_check_sld_NZ:
	jne .invalid_check_sld
	houdini
	cmp word [bp + ?header + eldhExtensionSize], eldhxDescriptionOffset + 4
	jb .nodesc
	sub sp, 4
%if eldhxDescriptionOffset - ELD_HEADER_size
	mov dx, eldhxDescriptionOffset - ELD_HEADER_size
	xor cx, cx
	mov ax, 4201h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error
%endif
	mov dx, sp
	mov cx, 4
	mov ah, 3Fh
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	cmp ax, cx
	jne .invalid
	pop dx
	pop cx
	mov ax, dx
	or ax, cx
	jz .nodesc
	add dx, word [bp + ?eldheader]
	adc cx, word [bp + ?eldheader + 2]
	mov ax, 4200h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error

reloc	mov di, relocateddata
linkdatarelocation line_out
	mov cx, words(128)
	xor ax, ax
	mov dx, di
	rep stosw
	mov ah, 3Fh
	mov cx, 127
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	extcallcall putsz
reloc	mov dx, msg.linebreak
internaldatarelocation
.putsz_desc_done:
	extcallcall putsz

reloc	rol byte [verbose], 1
internaldatarelocation
	jnc .help
reloc	mov di, relocateddata
linkdatarelocation line_out
reloc	mov si, msg.verbose.1
internaldatarelocation
	extcallcall copy_single_counted_string

	lea si, [bp + ?header]
	movsw
	movsw

	sub sp, 8
	mov ax, 4200h
	mov cx, word [bp + ?header + eldhCodeOffset + 2]
	mov dx, word [bp + ?header + eldhCodeOffset]
	add dx, word [bp + ?eldheader]
	adc cx, word [bp + ?eldheader + 2]
		; ELD header is at seek 0
	add dx, eldiIdentifier
	adc cx, 0
	jc .invalid_instance
	call seek_compressed_or_dos_or_boot_io
	jc .io_error
	mov dx, sp
	mov ah, 3Fh
	mov cx, 8
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	cmp ax, cx
	jne .invalid_instance

reloc	mov si, msg.verbose.2
internaldatarelocation
	push cx
	extcallcall copy_single_counted_string
	pop cx

	mov si, sp
	rep movsb
	db __TEST_IMM8		; (skip dec)
@@:
	dec di
	cmp byte [di - 1], 32
	je @B

	add sp, 8

	mov al, '"'
	stosb

.after_invalid_instance:
	push bx
	extcallcall putsline_crlf
	pop bx
reloc	mov di, relocateddata
linkdatarelocation line_out

	mov ax, 2020h
	stosw

	mov ax, word [bp + ?header + eldhCodeImageLength]
	extcallcall decword

reloc	mov si, msg.verbose.3
internaldatarelocation
	extcallcall copy_single_counted_string

	add ax, word [bp + ?header + eldhCodeAllocLength]
	add ax, 15
	and al, ~15
	extcallcall decword

reloc	mov si, msg.verbose.4
internaldatarelocation
	extcallcall copy_single_counted_string

	mov ax, word [bp + ?header + eldhDataImageLength]
	extcallcall decword

reloc	mov si, msg.verbose.5
internaldatarelocation
	extcallcall copy_single_counted_string

	add ax, word [bp + ?header + eldhDataAllocLength]
	add ax, 15
	and al, ~15
	extcallcall decword

reloc	mov si, msg.verbose.6
internaldatarelocation
	extcallcall copy_single_counted_string

	push bx
	extcallcall putsline_crlf
	pop bx

.help:
reloc	rol byte [do_help], 1
internaldatarelocation
	jnc .help_done

	cmp word [bp + ?header + eldhExtensionSize], eldhxHelpOffset + 4
	jb .nohelp
	sub sp, 4
	mov dx, eldhxHelpOffset
	xor cx, cx
	add dx, word [bp + ?eldheader]
	adc cx, word [bp + ?eldheader + 2]
	mov ax, 4200h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error
	mov dx, sp
	mov cx, 4
	mov ah, 3Fh
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	cmp ax, cx
	jne .invalid
	pop dx
	pop cx
	mov ax, dx
	or ax, cx
	jz .nohelp
	add dx, word [bp + ?eldheader]
	adc cx, word [bp + ?eldheader + 2]
	mov ax, 4200h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error

reloc	mov di, relocateddata
linkdatarelocation line_out
	mov byte [bp + ?more_help], 0FFh

.loop:
	mov ax, di
reloc	sub ax, strict word relocateddata
linkdatarelocation line_out	; ax = how much already buffered

	push ax
	mov dx, di		; dx -> buffer tail
	mov ah, 3Fh		; read
reloc	mov cx, 256 + relocateddata
linkdatarelocation line_out
	sub cx, dx		; cx = how much space in buffer
	call read_compressed_or_dos_or_boot_io
	jc .io_error
%if 0
	mov si, dx
	add si, ax		; -> behind read data
	mov byte [si], 0	; may write byte [line_out + 256]
%endif
	pop cx
	add cx, ax		; = how much data we have now
	jz .help_done		; if done -->

reloc	mov di, relocateddata
linkdatarelocation line_out

	push di
	push cx			; cx = 8 if 8 bytes
	mov al, 0
	repne scasb		; if cx was = 8 and second byte is NUL, cx = 6
	xchg ax, cx		; ax = 6
	pop cx
	pop di
	jne @F
	not byte [bp + ?more_help]
	sub cx, ax		; cx = 8 - 6 = 2
	dec cx			; cx = 1 (one data byte)
@@:

	mov al, 10
	add di, cx		; di -> behind data
	push cx
	dec di			; NZ, di -> last data byte
	std
	repne scasb		; scan for last LF
	cld
	pop cx
	je .partial		; found an LF -->
.full:
reloc	mov di, relocateddata - 2
linkdatarelocation line_out	; minus 2 to counteract inc inc
	add di, cx		; -> behind last data byte (minus 2)
.partial:
	inc di			; -> at LF
	inc di			; -> behind LF
	push cx
	push bx
	extcallcall putsline	; display line_out .. di-1
	pop bx
	pop cx
	mov si, di		; -> behind data displayed
reloc	mov di, relocateddata
linkdatarelocation line_out
		; cx = cx - (si - di)
	add cx, di
	sub cx, si		; cx = how much data remains
	rep movsb		; move data to start of line_out
				; di -> where to write
	rol byte [bp + ?more_help], 1
	jc .loop

.help_done:
	cmp word [bp + ?header + eldhExtensionSize], eldhxLibTable + 4
	jb .nolib
	sub sp, 4
	mov dx, eldhxLibTable
	xor cx, cx
	add dx, word [bp + ?eldheader]
	adc cx, word [bp + ?eldheader + 2]
	mov ax, 4200h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error
	mov dx, sp
	mov cx, 4
	mov ah, 3Fh
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	cmp ax, cx
	jne .invalid
	pop dx
	pop cx
	mov ax, dx
	or ax, cx
	jz .nolib
	add dx, word [bp + ?eldheader]
	adc cx, word [bp + ?eldheader + 2]
	mov ax, 4200h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error

	mov cx, fromwords(ELD_LIBTABLE_size_w)
	sub sp, cx
	mov dx, sp
	mov ah, 3Fh
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	cmp ax, cx
	jne .invalid
	mov di, sp
%ifn _COMPRESSED
	cmp word [di + eldltFormat], 0
	jne .invalid
%else
	xor dx, dx		; init to zero compression layers
	mov ax, word [di + eldltFormat]
		; 0 = uncompressed
		; 2 = compressed heatshrink
		; 3 = compressed lzexedat -4
		; 4 = compressed lzexedat -4 -l
	cmp ax, 4
	ja .invalid
	cmp al, 1
	je .invalid
	jb @F
reloc	mov byte [depack_format], al
internaldatarelocation

	mov cx, 4
reloc	mov dx, libtab_compressed_length
internaldatarelocation
	mov ah, 3Fh
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	cmp ax, cx
	jne .invalid

	mov dx, 1
@@:
	testopt [bp + ?uncompressed_bit_0], 1
 %if 0
	jnz @F
	inc dx			; count compression layers
	inc dh			; was already compressed
@@:
	cmp dl, 2		; compressed within compressed ?
	jae .doublepacked	; yes -->
 %else
	jz .doublepacked	; lib inside compressed is invalid -->
 %endif
%endif
	mov cx, word [di + eldltAmount]
	test cx, cx
	jz .nolib
	mov word [bp + ?libamount], cx
	mov ax, word [di + eldltOffset]
	add ax, word [bp + ?eldheader]
	mov word [bp + ?liboffset], ax
	mov ax, word [di + eldltOffset + 2]
	adc ax, word [bp + ?eldheader + 2]
	mov word [bp + ?liboffset + 2], ax

%if _COMPRESSED
	push dx			; on stack: ah = was compressed,
				;  al = next is compressed
%endif
reloc	rol byte [verbose], 1
internaldatarelocation
	jnc .lib_verbose_done

	push bx
	mov bx, di
reloc	mov di, relocateddata
linkdatarelocation line_out

;	mov ax, 2020h
;	stosw

reloc	mov si, msg.verbose.lib.1
internaldatarelocation
	extcallcall copy_single_counted_string

	mov ax, word [bx + eldltAmount]
	extcallcall decword

reloc	mov si, msg.verbose.lib.2
internaldatarelocation
	extcallcall copy_single_counted_string

	mov ax, word [bx + eldltFormat]
	extcallcall decword

reloc	mov si, msg.verbose.lib.3.un
internaldatarelocation
	cmp al, 0
	je @F
reloc	mov si, msg.verbose.lib.3.hs
internaldatarelocation
	cmp al, 2
	je @F
reloc	mov si, msg.verbose.lib.3.lze
internaldatarelocation
	cmp al, 3
	je @F
reloc	mov si, msg.verbose.lib.3.lzel
internaldatarelocation
@@:
	extcallcall copy_single_counted_string

	cmp al, 0
	je @F
reloc	mov si, msg.verbose.lib.4
internaldatarelocation
	extcallcall copy_single_counted_string

reloc	mov dx, [libtab_compressed_length + 2]
internaldatarelocation
reloc	mov ax, [libtab_compressed_length]
internaldatarelocation
	extcallcall decdword
@@:

	extcallcall putsline_crlf
	pop bx

.lib_verbose_done:
%if _COMPRESSED
	pop dx
%endif
	add sp, fromwords(ELD_LIBTABLE_size_w)
%if _COMPRESSED
	push dx			; on stack: ah = was compressed,
				;  al = next is compressed
%endif

reloc	rol byte [lib], 1
internaldatarelocation
	jnc .lib_done

 %if _COMPRESSED
	xor dx, dx
	push dx
	push dx
 %endif

.looplib:
	lea dx, [bp + ?libentry]
	mov cx, 12
	mov ah, 3Fh
	call read_compressed_or_dos_or_boot_io
	jc .io_error
	cmp ax, cx
	jne .invalid

	xor cx, cx
	xor dx, dx
	mov ax, 4201h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error
	mov word [bp + ?libnext], ax
	mov word [bp + ?libnext + 2], dx

.libname:
%if _ELDTRAILER
	testopt [bp + ?not_sld_bit_0], 1
	jnz .nolibname
%else
	cmp word [bp + ?eldheader], 0
	jne .nolibname
	cmp word [bp + ?eldheader + 2], 0
	jne .nolibname
%endif
reloc	rol byte [libname], 1
internaldatarelocation
	jnc .nolibname
	lea si, [bp + ?libentry + 4]
reloc	mov di, libnamebuffer
internaldatarelocation
	mov cx, 8
@@:
	lodsb
	extcallcall uppercase
	scasb
	je @F
	cmp byte [di - 1], '?'
@@:
	loope @BB
	jne .libskip
.nolibname:

%if _COMPRESSED
	mov ax, 4200h
	pop dx
	pop cx
	call dos_or_boot_io

	pop ax
	push ax
	cmp al, 1		; CY if uncompressed
	jb .uncomp_seek

	mov di, word [bp + ?libentry]
	mov cx, word [bp + ?libentry + 2]

 %if 0
	test ah, ah
	jz .comp_in_uncomp_seek
.uncomp_in_comp_seek:
	add di, word [bp + ?eldheader]
	adc cx, word [bp + ?eldheader]
 %endif

.comp_in_uncomp_seek:
	jmp .seek_done
%endif
.uncomp_seek:
	mov dx, word [bp + ?liboffset]
	mov cx, word [bp + ?liboffset + 2]
	add dx, word [bp + ?libentry]
	adc cx, word [bp + ?libentry + 2]
	mov ax, 4200h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error
%if _COMPRESSED
	xor cx, cx
	xor di, di

.seek_done:
	push di
%endif

	lea di, [bp + ?libentry + 12 + 1]
	lea dx, [bp + ?libentry + 4]
@@:
	dec di
	cmp di, dx
	jbe @F
	cmp byte [di - 1], 32
	je @B
@@:
	mov byte [di], 0

	mov al, 32
	extcallcall putc

%if _COMPRESSED
	pop di

	pop ax
	push ax

reloc	push word [libseek + 2]
internaldatarelocation
reloc	push word [libseek]
internaldatarelocation

%if 0
	test ah, ah		; already was compressed ?
	jnz @F			; yes, leave libseek as is -->
%endif
	push word [bp + ?liboffset + 2]
reloc	pop word [libseek + 2]
internaldatarelocation
	push word [bp + ?liboffset]
reloc	pop word [libseek]
internaldatarelocation
@@:

	cmp al, 1		; CY if uncompressed
%endif
	mov ax, word [bp + ?handle]
	mov bl, 1
	call commonhandle.lib
	mov bx, word [bp + ?handle]

%if _COMPRESSED
	mov ax, 4201h
	xor cx, cx
	xor dx, dx
	call dos_or_boot_io

reloc	pop word [libseek]
internaldatarelocation
reloc	pop word [libseek + 2]
internaldatarelocation

	push dx
	push ax
%endif

.libskip:
	mov dx, word [bp + ?libnext]
	mov cx, word [bp + ?libnext + 2]
	mov ax, 4200h
	call seek_compressed_or_dos_or_boot_io
	jc .io_error
	dec word [bp + ?libamount]
	jnz .looplib
	jmp .lib_done

.nodesc:
reloc	mov dx, msg.nodesc
internaldatarelocation
	jmp .putsz_desc_done

.nohelp:
reloc	mov dx, msg.nohelp
internaldatarelocation
	extcallcall putsz
	jmp .help_done

.io_error:
	mov ax, 0E49h
	extcallcall setrc
reloc	mov dx, msg.io_error
internaldatarelocation
	jmp .error

%if _COMPRESSED
.doublepacked:
	mov ax, 0E4Ah
	extcallcall setrc
reloc	mov dx, msg.doublepacked_error
internaldatarelocation
	jmp .error
%endif

.invalid_instance:
reloc	mov si, msg.invalid_instance
internaldatarelocation
	extcallcall copy_single_counted_string

	add sp, 8
	jmp .after_invalid_instance

.invalid_check_sld:
	test byte [bp + ?not_sld_bit_0], 1
	jnz .invalid			; in a lib -->
	cmp ax, 6			; "@;SLD0"
	jb @F
	cmp word [bp + ?header], "@;"
	jne @F
	cmp word [bp + ?header + 2], "SL"
	jne @F
	cmp word [bp + ?header + 4], "D0"
	jne @F
	jmp .sld

@@:
reloc	mov dx, msg.invalid_sld
internaldatarelocation
	jmp .error

.invalid:
	mov ax, 0E4Bh
	extcallcall setrc
reloc	mov dx, msg.invalid
internaldatarelocation
.error:
.putsz_ret:
	extcallcall putsz
.ret:
.lib_done:
.nolib:
	lleave code, forcerestoresp
	retn


.sld:
%if 0
	mov cx, word [bp + ?eldheader + 2]
	mov dx, word [bp + ?eldheader]
	add dx, 6
	adc cx, 0
%else
	xor cx, cx
	mov dx, 6
%endif
	mov ax, 4200h
	; call seek_compressed_or_dos_or_boot_io
	call dos_or_boot_io
	jc .io_error

reloc	mov cx, .check_d
internalcoderelocation

.sldreload:
reloc	mov dx, relocateddata
linkdatarelocation line_out
	mov word [bp + ?next], dx	; reset ?next
	push cx				; ! preserve state
	mov cx, 256
	mov ah, 3Fh
	call dos_or_boot_io		; fill buffer
	pop cx				; ! preserve state
	jc .io_error
	test ax, ax			; no more data ?
	jz .sld_no_desc			; yes -->
	add ax, dx
	mov word [bp + ?tail], ax	; set ?tail

.sldloop:
	mov si, word [bp + ?next]	; -> next data
	cmp si, word [bp + ?tail]	; have one more byte ?
	je .sldreload			; no -->

	lodsb				; get the byte
	mov word [bp + ?next], si	; update ?next
	jmp cx				; jump to state

.sldnext: equ .sldloop			; get next byte -->

.sld_no_desc:
reloc	mov dx, msg.nodesc
internaldatarelocation
	extcallcall putsz
	jmp .sld_desc_done

.check_d:				; D may be prepended by blanks,
					;  commas, or semicolons
				; state unchanged
	cmp al, ','			; skip any commas
	je .sldnext
	cmp al, ';'			; or semicolons
	je .sldnext
	cmp al, 32
	je .sldnext
	cmp al, 9			; or blanks
	je .sldnext
	extcallcall uppercase
reloc	mov cx, .check_e 	; change state if D found
internalcoderelocation
	cmp al, 'D'			; is it a D ?
.sldnext_ZR_else_skip_to_eol:
	je .sldnext			; yes -->
				; skip to next line
.skip_to_eol:
reloc	mov cx, .check_at	; change state if EOL found
internalcoderelocation
	cmp al, 13			; EOL ?
	je .sldnext
	cmp al, 10
	je .sldnext
	cmp al, 0
	je .sldnext			; yes -->
reloc	mov cx, .skip_to_eol		; loop back to this state
internalcoderelocation
	jmp .sldnext

.check_at:				; @ must be in first column
reloc	mov cx, .check_semicolon
internalcoderelocation
	cmp al, '@'
	jmp .sldnext_ZR_else_skip_to_eol

.check_semicolon:			; semicolon may be prepended by blanks
	cmp al, 32
	je .sldnext
	cmp al, 9
.sldnext_ZR_j1:
	je .sldnext
reloc	mov cx, .check_d
internalcoderelocation
	cmp al, ';'
	jmp .sldnext_ZR_else_skip_to_eol

.check_e:				; E must be immediately after D
	extcallcall uppercase
reloc	mov cx, .check_s
internalcoderelocation
	cmp al, 'E'
	jmp .sldnext_ZR_else_skip_to_eol

.check_s:				; S must be immediately after E
	extcallcall uppercase
reloc	mov cx, .check_c
internalcoderelocation
	cmp al, 'S'
	jmp .sldnext_ZR_else_skip_to_eol

.check_c:				; C must be immediately after S
	extcallcall uppercase
reloc	mov cx, .check_equals_sign
internalcoderelocation
	cmp al, 'C'
	jmp .sldnext_ZR_else_skip_to_eol

.check_equals_sign:			; = or : may be prepended by blanks
	cmp al, 32
	je .sldnext_ZR_j1
	cmp al, 9
	je .sldnext_ZR_j1
reloc	mov cx, .skip_blanks
internalcoderelocation
	cmp al, '='
	je .sldnext_ZR_j1
	cmp al, ':'
	jmp .sldnext_ZR_else_skip_to_eol

.skip_blanks:				; description may be prepended by blanks
	cmp al, 32
	je .sldnext_ZR_j1
	cmp al, 9
	je .sldnext_ZR_j1

reloc	mov di, relocateddata
linkdatarelocation line_out		; -> start of buffer
	mov si, word [bp + ?next]
	dec si				; -> first nonblank (at least 1 byte)
	mov cx, word [bp + ?tail]	; -> after last buffered byte
	sub cx, si			; = length of buffered data
	rep movsb			; move down in buffer
	mov dx, di			; -> after buffered data
reloc	mov cx, relocateddata + 127
linkdatarelocation line_out		; -> after last byte we want to read
	mov di, cx			; -> where to place terminator
	sub cx, dx			; = length to read after buffered data
	jbe @F				; if below-or-equal zero, none to read -->
	mov ah, 3Fh
	call dos_or_boot_io		; read it
	jc .io_error			; on error -->
					; (valid to read 0 up to 126 Bytes)
	mov di, ax
	add di, dx			; -> after last read byte
@@:
	mov byte [di], 0		; store a terminator

reloc	mov dx, relocateddata
linkdatarelocation line_out		; -> message data
	mov si, dx			; -> text to scan
@@:
	lodsb				; get a text byte
	cmp al, 0			; EOL ?
	je @F
	cmp al, 13
	je @F
	cmp al, 10
	jne @B				; not yet -->
@@:
	inc si				; (si - 2) -> behind message data
	mov word [si - 2], 13 | (10 << 8)
					; append a linebreak
	mov cx, si
	sub cx, dx			; cx = message data length including CR LF
	push bx
	extcallcall puts		; display message
	pop bx

.sld_desc_done:
reloc	rol byte [verbose], 1
internaldatarelocation
	jnc .sld_verbose_done
reloc	mov di, relocateddata
linkdatarelocation line_out
reloc	mov si, msg.verbose.1
internaldatarelocation
	extcallcall copy_single_counted_string

	lea si, [bp + ?header + 2]
	movsw
	movsw

reloc	mov si, msg.verbose.2.sld
internaldatarelocation
	extcallcall copy_single_counted_string

	xor dx, dx
	xor cx, cx
	mov ax, 4202h
%if 0
	call dos_or_boot_io
	jc .io_error
%else
 %if _BOOTLDR
reloc	testopt [relocateddata], nodosloaded
linkdatarelocation internalflags, -3
	jz @F
reloc	mov ax, word [relocateddata - LOADDATA2 + ldFileSize]
linkdatarelocation load_data
reloc	mov dx, word [relocateddata - LOADDATA2 + ldFileSize + 2]
linkdatarelocation load_data
	jmp @FF
@@:
 %endif
	call dos_or_boot_io.dos
	jc .io_error
@@:
%endif
	extcallcall decdword

reloc	mov si, msg.verbose.3.sld
internaldatarelocation
	extcallcall copy_single_counted_string

	push bx
	extcallcall putsline_crlf
	pop bx

.sld_verbose_done:
sld_help:
reloc	rol byte [do_help], 1
internaldatarelocation
	jnc .done

	xor dx, dx
	xor cx, cx
	mov word [bp + ?helpstarted], cx
	mov ax, 4200h
	call dos_or_boot_io
	jc commonhandle.io_error

reloc	mov cx, .check_at_or_semicolon
internalcoderelocation

.reload:
reloc	mov dx, relocateddata
linkdatarelocation line_out
	mov word [bp + ?next], dx	; reset ?next
	push cx				; ! preserve state
	mov cx, 256
	mov ah, 3Fh
	call dos_or_boot_io		; fill buffer
	pop cx				; ! preserve state
	jc commonhandle.io_error
	test ax, ax			; no more data ?
	jz .eof				; yes -->
	add ax, dx
	mov word [bp + ?tail], ax	; set ?tail

.loop:
	mov si, word [bp + ?next]	; -> next data
	cmp si, word [bp + ?tail]	; have one more byte ?
	je .reload			; no -->

	lodsb				; get the byte
	mov word [bp + ?next], si	; update ?next
	jmp cx				; jump to state

.next: equ .loop			; get next byte -->

.eof:
	rol byte [bp + ?helpstarted], 1
	jc .done

.no_help:
reloc	mov dx, msg.nohelp
internaldatarelocation
	extcallcall putsz
.done:
	jmp commonhandle.ret

.check_at_or_semicolon:
reloc	mov cx, .check_semicolon
internalcoderelocation
	cmp al, '@'			; is it an @ ?
	je .next
.check_semicolon:
	cmp al, 32			; blanks
	je .next
	cmp al, 9			; or tabs
	je .next
reloc	mov cx, .check_h
internalcoderelocation
	cmp al, ';'			; semicolon ?
.next_ZR_else_skip_to_eol:
	je .next			; yes -->
				; skip to next line
.skip_to_eol:
reloc	mov cx, .check_at_or_semicolon	; change state if EOL found
internalcoderelocation
	cmp al, 13			; EOL ?
	je .next
	cmp al, 10
	je .next
	cmp al, 0
	je .next			; yes -->
.next_skip_to_eol:
reloc	mov cx, .skip_to_eol		; loop back to this state
internalcoderelocation
	jmp .next

.check_h:
	cmp al, 32			; blanks
	je .next
	cmp al, 9			; or tabs
	je .next
	extcallcall uppercase
	cmp al, 'H'
	jne .skip_to_eol
	call .fill
reloc	cmp dx, relocateddata + msg.helpstart.length + 1
linkdatarelocation line_out
	jb .no_help
reloc	mov al, byte [relocateddata + msg.helpstart.length]
linkdatarelocation line_out
	cmp al, 32			; blank ?
	je @F
	cmp al, 9
	je @F
	cmp al, 13			; CR ?
	je @F
	cmp al, 0			; NUL ?
	je @F
	cmp al, 10			; LF ?
.next_skip_to_eol_NZ:
	jne .next_skip_to_eol
reloc	mov byte [relocateddata + msg.helpstart.length], 13
linkdatarelocation line_out, -3		; insert CR for isstring?
		; Modifying the buffered data!
@@:
reloc	mov si, relocateddata
linkdatarelocation line_out
reloc	mov dx, msg.helpstart
internaldatarelocation
	extcallcall isstring?
	jne .next_skip_to_eol_NZ

	mov word [bp + ?next], si
reloc	mov cx, .check_eol
internalcoderelocation
.next_j:
	jmp .next

.check_eol:
	cmp al, 32
	je .next_j
	cmp al, 9
	je .next_j
	cmp al, 13
	je @F
	cmp al, 10
	je @F
	cmp al, 0
	jne .next_skip_to_eol_NZ
@@:
reloc	mov cx, .check_help_at_or_semicolon
internalcoderelocation
	not byte [bp + ?helpstarted]
.next_j2:
	jmp .next_j

.check_help_at_or_semicolon:
reloc	mov cx, .check_help_semicolon
internalcoderelocation
	cmp al, '@'			; is it an @ ?
	je .next_j2
.check_help_semicolon:
	cmp al, 32			; blanks
	je .next_j2
	cmp al, 9			; or tabs
	je .next_j2
reloc	mov cx, .display_help
internalcoderelocation
	cmp al, ';'			; semicolon ?
;.next_ZR_else_skip_to_eol:
	je .next_j2			; yes -->
				; skip to next line
.help_skip_to_eol:
reloc	mov cx, .check_help_at_or_semicolon
internalcoderelocation			; change state if EOL found
	cmp al, 13			; EOL ?
	je .next_j2
	cmp al, 10
	je .next_j2
	cmp al, 0
	je .next_j2			; yes -->
.next_help_skip_to_eol:
reloc	mov cx, .help_skip_to_eol	; loop back to this state
internalcoderelocation
	jmp .next_j2

.display_help:
	call .fill
	dec word [bp + ?next]
reloc	mov si, relocateddata
linkdatarelocation line_out		; -> buffer
@@:
	cmp si, dx
	jae .do_display_help
	lodsb
	cmp al, 32
	je @B
	cmp al, 9
	je @B
	extcallcall uppercase
	cmp al, 'H'
	jne .do_display_help

	dec si				; -> at the H
	lea di, [si + msg.helpend.length]
					; -> at candidate separator
	cmp dx, di			; string is in buffer ?
	jb .do_display_help		; no -->
	ja .havesep			; yes, separator too -->
	mov byte [di], 0		; store a separator here
					;  (can overflow line_out+256)
.havesep:
	mov al, byte [di]		; get separator
	cmp al, 32			; one of the valid separators ?
	je @F
	cmp al, 9
	je @F
	cmp al, 13
	je @F
	cmp al, 0
	je @F
	cmp al, 10			; LF ?
	jne .do_display_help		; no -->
	mov byte [di], 13		; insert CR for isstring?
		; Modifying the buffered data!
@@:
	push dx
reloc	mov dx, msg.helpend
internaldatarelocation
	extcallcall isstring?		; is it "helpend" ?
	pop dx
	jne .do_display_help		; no -->
@@:
	cmp si, dx			; reached EOL ?
	jae .done			; then it was helpend
	lodsb
	cmp al, 32			; blank ?
	je @B
	cmp al, 9
	je @B				; yes, loop here -->
	cmp al, 13			; linebreak ?
	je .done
	cmp al, 10
	je .done
	cmp al, 0
	je .done			; yes, it was helpend -->

		; Not "helpend". Display this line.
.do_display_help:
reloc	mov si, relocateddata
linkdatarelocation line_out		; -> buffer
	push si				; -> buffer
@@:
	cmp si, dx			; reached end ?
	jae .si				; yes, si -> end
	lodsb				; get next byte
	cmp al, 13			; linebreak ?
	je .si_minus_1
	cmp al, 10
	je .si_minus_1
	cmp al, 0
	jne @B				; no, loop -->
.si_minus_1:
	dec si				; -> end of text
.si:
	mov cx, si			; -> end of text
	pop dx
	sub cx, dx			; = length
	push bx
	extcallcall puts
	pop bx
reloc	mov dx, msg.linebreak		; display a linebreak
internaldatarelocation
	extcallcall putsz
	jmp .next_help_skip_to_eol	; skip to next line


		; INP:	?next, ?tail
		;	?next - 1 -> buffered data, at least 1 byte
		; OUT:	line_out -> buffered data, at least 1 byte
		;	?next = line_out + 1
		;	dx = ?tail -> behind buffered data
		;	 (up to EOF or == line_out + 256)
		;	branches to commonhandle.io_error on I/O error
		; CHG:	di, si, ax, cx
.fill:
reloc	mov di, relocateddata
linkdatarelocation line_out		; -> buffer
	mov si, word [bp + ?next]
	dec si				; -> H in buffer
	mov cx, word [bp + ?tail]	; -> behind last buffered text
	sub cx, si			; length of buffered data
	lea dx, [di + 1]		; -> behind the H's destination
	rep movsb			; move down buffered data
	mov word [bp + ?next], dx	; -> behind the H
	; mov word [bp + ?tail], di
	mov dx, di
reloc	mov cx, relocateddata + 256
linkdatarelocation line_out
	sub cx, dx
	jz @F
	mov ah, 3Fh
	call dos_or_boot_io		; fill buffer
	jc commonhandle.io_error
	add dx, ax
	mov word [bp + ?tail], dx
	retn


inject:
reloc	mov dx, word [originaldta]	; dx -> original DTA
internaldatarelocation
	mov ah, 1Ah			; set DTA (restoring)
	extcallcall ispm
	jnz .rm

subcpu 286
reloc	push word [originaldta + 2]
internaldatarelocation			; ds => original DTA (86M segment)
	push word 21h
	extcall intcall_ext_return_es, PM required	; must NOT be extcallcall
	pop dx				; discard interrupt number
	pop dx				; discard es
subcpureset
	jmp @F
.rm:
reloc	mov ds, word [originaldta + 2]	; ds => original DTA
internaldatarelocation
	int 21h
	 push ss
	 pop ds
@@:

reloc	mov bx, word [findhandle]	; bx = find handle, if any
internaldatarelocation
reloc	rol byte [findhandle_set], 1	; find handle set ?
internaldatarelocation
	jnc @F				; no -->
reloc	not byte [findhandle_set]
internaldatarelocation
	mov ax, 71A1h
	extcallcall _doscall		; LFN find close
@@:

reloc	mov cx, word [originalinject]
internaldatarelocation
	call get_es_ext
reloc	clropt [es:code + eldiFlags], eldifResident
internalcoderelocation -3		; mark block as no longer resident
	 push ss
	 pop es
	jcxz @F
	jmp cx

@@:
	extcall cmd3_not_inject


%if _COMPRESSED
seek_compressed_or_dos_or_boot_io:
	testopt [bp + ?uncompressed_bit_0], 1
	jnz dos_or_boot_io
	cmp ah, 42h
	jne @F
	cmp al, 1
	ja @F
	jb .abs
reloc	add dx, word [depackskip]
internaldatarelocation
reloc	adc cx, word [depackskip + 2]
internaldatarelocation
.abs:
reloc	mov word [depackskip], dx
internaldatarelocation
reloc	mov word [depackskip + 2], cx
internaldatarelocation
	mov ax, cx
	xchg ax, dx
	clc
	retn


read_compressed_or_dos_or_boot_io:
	testopt [bp + ?uncompressed_bit_0], 1
	jnz dos_or_boot_io
	cmp ah, 3Fh
	jne @F
	jmp read_and_depack

@@:
	extcallcall error
%else
 seek_compressed_or_dos_or_boot_io equ dos_or_boot_io
 read_compressed_or_dos_or_boot_io equ dos_or_boot_io
%endif

	lleave ctx


dos_or_boot_io:
%if _BOOTLDR
reloc	testopt [relocateddata], nodosloaded
linkdatarelocation internalflags, -3
	jnz .boot
%endif
.dos:
	extcall _doscall
	retn

%if _BOOTLDR
.boot:
	cmp ah, 3Fh
	jne @F
	extcall yy_boot_read.bx
	retn

@@:
	cmp ax, 4200h
	jne @F
.boot_seek_absolute:
reloc	sub dx, word [relocateddata - LOADDATA2 + ldCurrentSeek]
linkdatarelocation load_data
reloc	sbb cx, word [relocateddata - LOADDATA2 + ldCurrentSeek + 2]
linkdatarelocation load_data

.boot_seek_current:
	extcall yy_boot_seek_current.bx
reloc	mov ax, word [relocateddata - LOADDATA2 + ldCurrentSeek]
linkdatarelocation load_data
reloc	mov dx, word [relocateddata - LOADDATA2 + ldCurrentSeek + 2]
linkdatarelocation load_data
	retn

@@:
	cmp ax, 4201h
	je .boot_seek_current
 %if _ELDTRAILER
	cmp ax, 4202h
	jne @F
.boot_seek_eof:
reloc	add dx, word [relocateddata - LOADDATA2 + ldFileSize]
linkdatarelocation load_data
reloc	adc cx, word [relocateddata - LOADDATA2 + ldFileSize + 2]
linkdatarelocation load_data
	jmp .boot_seek_absolute
 %endif
@@:
	extcallcall error
%endif


%if _COMPRESSED
 %assign _STANDALONE 0
 %assign _MULTI 1
 %include "depack.asm"
%endif


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


start:
	mov bx, es
	 push ss
	 pop es
	extcallcall skipcomma
	extcallcall iseol?
	je .help
	call run
@@:
	call uninstall_oneshot
	xor ax, ax
	retf

.help:
reloc	mov dx, msg.help
internaldatarelocation
	extcallcall 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

%if _COMPRESSED
	align 2, db 0
depack_saved_sp:	dw 0FFFFh
partialdepack:		db 0FFh
depack_format:		db 0
%endif

findhandle_set:		db 0
found:			db 0
verbose:		db 0
do_help:		db 0
prefersfn:		db 0
lib:			db 0
libname:		db 0

msg:
.verbose:		asciz "VERBOSE"
.string_help:		asciz "HELP"
.string_sfn:		asciz "SFN"
.string_lib:		asciz "LIB"
.colon:			asciz ": "
.notfound:		asciz "File not found.",13,10
.nodesc:		asciz "No description.",13,10
.nohelp:		asciz "No help.",13,10
.helpstart:		asciz "HELPSTART"
.helpstart.length equ $ - 1 - .helpstart
.helpend:		asciz "HELPEND"
.helpend.length equ $ - 1 - .helpend
.io_error:		asciz "LIST ELD got I/O error.",13,10
%if _COMPRESSED
.doublepacked_error:	asciz "LIST ELD cannot recurse into nested compressed library ELDs.",13,10
%endif
.invalid_instance:	counted '". Invalid instance header.'
.invalid:		db "No or invalid Extension for lDebug header."
.linebreak:		asciz 13,10
.invalid_sld:		asciz "No or invalid Script/Extension for lDebug header.",13,10
.verbose.1:	counted "  Format: ",'"'
.verbose.2:	counted '", ELD name: "'
.verbose.3:	counted " code, "
.verbose.4:	counted " alloc, "
.verbose.5:	counted " data, "
.verbose.6:	counted " alloc"
.verbose.2.sld:	counted '", file size '
.verbose.3.sld:	counted " bytes"
.verbose.lib.1:	counted "  Library contains "
.verbose.lib.2:	counted " ELDs, format "
.verbose.lib.3.un:	counted " (uncompressed)"
.verbose.lib.3.hs:	counted " (heatshrink)"
.verbose.lib.3.lze:	counted " (lzexedat -4)"
.verbose.lib.3.lzel:	counted " (lzexedat -4 -l)"
.verbose.lib.4:	counted ", packed size "

depack_stack: equ $

.help:		db "Run with a pathname as parameter.",13,10
		db "Last component may include wildcards.",13,10
		db 13,10
		db "After the pathname, keywords may follow:",13,10
		db 9,"VERBOSE",9,"Display ELD format, name, sizes",13,10
		db 9,"HELP",9,"Display ELD help",13,10
		db 9,"SFN",9,"Use DOS SFN search even if LFN available",13,10
		db 9,"LIB",9,"Recurse into library ELDs",13,10
		db 9,"/name",9,"Only display library ELDs matching the name",13,10
		asciz

uinit_data: equ $

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

%if _COMPRESSED
	absolute depack_stack
	alignb 2
		resb 256
depack_stack.top:

 %if uinit_data > depack_stack.top
	absolute uinit_data
 %endif
%else
	absolute uinit_data
%endif

	alignb 2
libnamebuffer:	resb 8
wild_pattern:		; overlaps next variable
boot_parsed:	equ $+2	; overlaps next variable
originaldta:	resd 1
originalinject:	resw 1
findnext_function_number:
		resw 1
findhandle:	resw 1
dta:		resb 1Eh
.name:		resb 13

	alignb 2
pathnamebuffer:	resb 512

finddata:	resb 2Ch
.fullname:	resb 260
.shortname:	resb 14

%if _COMPRESSED
	alignb 2
libtab_compressed_length:
		resd 1
libseek:	resd 1
eldheader:	resd 1
depackskip:	resd 1
depackseek:	resd 1
depacked_buffer:resd 1
depack_left_length:	resw 1
depack_left_address:	resw 1
depacked_length:resw 1
depack_prior_sp:resw 1
	alignb 2
filebuffer:	resb 512
.end:
	alignb 2
.next:		resw 1
.tail:		resw 1
handle:		resw 1

	alignb 16
resultbuffer:
.size equ 4096
		resb .size
.end:
%endif

%if _DATABUFFER
	alignb 16
databuffer:
	resb 512
%endif

	alignb 16
uinit_data_end:

total_data_size equ $ - datastart
%assign _DATA_SIZE total_data_size

	usesection CODE

%include "eldlink.asm"

	align 16
code_size equ $ - code
