
; Public Domain

; test install command: install; ext extname help; extname uninstall
; test run command: help; .; .

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

	numdef BOOTLDR, 1
	numdef DATABUFFER, 1
	numdef ELDTRAILER, 1
	numdef LIBSCAN, 1

%assign _CATCHINT0C 0
%assign _CATCHINT0D 0
%assign _CATCHINTFAULTCOND 0
%assign _LOADER 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"

	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 "Provide filename extension guessing and warning for EXT/Y."


	align 16, db 0

CODEOFFSET equ $ - $$
	addsection CODE, follows=HEADER vstart=_ELD_CODE_VSTART
%define CODEFIXUP - code + 0
code:
code_start:
		; ELD instance header
	istruc ELD_INSTANCE
at eldiStartCode
at eldiEndCode
at eldiStartData
at eldiEndData
at eldiIdentifier,	fill 8, 32, db "EXTNAME"
at eldiListing,		asciz _ELD_LISTING
	iend
%if _LIBSCAN
		db "NAMELIB0"
		dw nothinglib
internaldatarelocation
		dw nothinglib.end
internaldatarelocation
%endif

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


	usesection CODE

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

	mov dx, msg.extname
internaldatarelocation
	extcallcall isstring?
	je .ourcommand

	xor bx, bx		; = 0 means EXT command
	mov dx, msg.ext
internaldatarelocation
	extcallcall isstring?
	je .ourmodify

	dec bx			; = -1 means Y command
	lodsb
	extcallcall uppercase
	cmp al, 'Y'
	je .ourmodify

.transfer:
	pop si
..@transfer_to_chain_si:
	dec si
	lodsb
	jmp .chain

.ourcommand:
	pop ax
	extcallcall skipcomma
	dec si
reloc2	mov word [relocateddata], relocateddata
linkdatarelocation lastcmd, -4
linkdatarelocation dmycmd
	mov dx, relocateddata
linkdatarelocation msg.uninstall
	extcallcall isstring?
	je uninstall
	mov bx, warnextension
internaldatarelocation
	mov cx, msg.warnextoption
internaldatarelocation
	mov dx, msg.warnext
internaldatarelocation
	extcallcall isstring?
	je .option_ZR
	mov bx, guessextension
internaldatarelocation
	mov cx, msg.guessextoption
internaldatarelocation
	mov dx, msg.guessext
internaldatarelocation
	extcallcall isstring?
%if _LIBSCAN
	je .option_ZR
	mov bx, debuglib
internaldatarelocation
	mov cx, msg.debugliboption
internaldatarelocation
	mov dx, msg.debuglib
internaldatarelocation
	extcallcall isstring?
%endif
.option_ZR:
	je option

%if _LIBSCAN
	mov dx, msg.lib
internaldatarelocation
	extcallcall isstring?
	je libcontrol
%endif
	lodsb
	extcallcall chkeol
	extcallcall cmd3


.ourmodify:
	mov byte [relocateddata], bl
linkdatarelocation yy_is_script
	extcallcall skipcomma
%if _LIBSCAN
	dec si
	mov word [header], si
internaldatarelocation
	inc si
%endif
reloc2	mov word [relocateddata], relocateddata
linkdatarelocation lastcmd, -4
linkdatarelocation dmycmd

%if _BOOTLDR
	xor bx, bx
	extcallcall InDOS
	jz @F
reloc	testopt [relocateddata], nodosloaded
linkdatarelocation internalflags, -3
	jz .transfer		; InDOS while not bootloaded -->
	dec bx
	testopt [relocateddata], dif3_auxbuff_guarded_1 \
		| dif3_auxbuff_guarded_2 \
		| dif3_auxbuff_guarded_3
linkdatarelocation internalflags3, -3
	jnz .transfer		; bootloaded with no auxbuff -->
@@:
	mov byte [isbootloaded], bl
internaldatarelocation
%else
	extcallcall InDOS
	jnz .transfer
%endif

	testopt [relocateddata], tt_while
linkdatarelocation internalflags_with_tt_while, -3
	jnz .transfer

	pop dx
	mov bx, relocateddata
linkdatarelocation line_out
%if _BOOTLDR
	rol byte [isbootloaded], 1
internaldatarelocation
	jnc @F
	extcallcall yy_boot_parse_name_bx_buffer
	jmp @FF
@@:
%endif
	extcallcall yy_common_parse_name_bx_buffer
				; si + 1 -> trailer, bx -> NUL-terminated pathname
@@:
	dec si
	mov word [trailer], si
internaldatarelocation

analyse_pathname:
	mov si, bx
	xor dx, dx
	mov al, 0
@@:
	cmp al, '/'
	je .slash
	cmp al, '\'
	je .slash
	cmp al, ':'
	je .colon
	cmp al, '.'
	jne .next
.dot:
	mov dl, 1		; set dl (fn with dot)
	jmp .next

.slash:
.colon:
	mov dx, 100h		; set dh (is a pathname), reset dl (fn with dot)
.next:
	lodsb
	cmp al, 0
	jne @B
	dec si			; bx -> name, si -> terminator
				; dh = nonzero if a pathname not just filename
				; dl = nonzero if filename contains a dot
	mov cx, si
	sub cx, bx		; es:bx -> name, cx = length


check_warn_extension:
	push dx

	test dl, dl		; last component has a dot ?
	jz .done		; no, do not warn -->

	rol byte [warnextension], 1
internaldatarelocation
	jnc .done		; warning disabled -->

	cmp cx, 4		; can fit an expected extension ?
	jb .warn		; no, warn -->

	sub si, 4		; -> possible extension
	mov di, msg.extensions_eld
internaldatarelocation		; es:di -> allowed extensions
	rol byte [relocateddata], 1
linkdatarelocation yy_is_script
	jnc @F
	mov di, msg.extensions_sld
internaldatarelocation		; es:di -> allowed extensions
@@:
.loop:
	mov dx, di
	extcallcall isstring?	; is it this one ?
	je .done		; yes, do not warn -->
	add di, 5
	cmp byte [di], 0	; was last ?
	jne .loop
.warn:
	mov dx, msg.extension_warning
internaldatarelocation
	extcallcall putsz

.done:
	pop dx


detect_extension:
%ifn _LIBSCAN
	test dl, dl		; last component has a dot ?
	jnz .done		; yes, do not try open -->
%endif

	mov di, relocateddata
linkdatarelocation while_buffer
	call check_filename
	jc .try_scriptspath
	jz .done		; no extension needs to be appended -->

.finish:
	lea dx, [di - 5]
%if 0
	mov bx, word [relocateddata]
linkdatarelocation terminator_in_line_in.offset
	mov al, byte [relocateddata]
linkdatarelocation terminator_in_line_in.value
	mov byte [bx], al	; undo
%endif

	extcallcall yy_reset_buf

	mov si, relocateddata + 1
linkdatarelocation line_in
	mov ah, 0
	mov al, byte [si]
	cmp al, 254 - 4		; has space ?
	ja .done
	add byte [si], 4	; add length of extension

	inc si			; -> text
	add si, ax		; -> CR
	lea di, [si + 4]	; -> destination for CR (extension length)
	mov cx, word [trailer]
internaldatarelocation
	push cx			; -> trailer
	neg cx			; minus -> trailer
	add cx, si		; -> CR minus -> trailer
	inc cx			; include CR to be moved
	 push cx
	call moveup
	 pop cx
	pop di			; -> trailer source (4 bytes of space)
	mov si, dx		; -> filename extension we guessed
	movsw
	movsw			; write extension

	mov si, relocateddata
linkdatarelocation indirect_array_errfix, -2, optional
	test si, si		; not supported ?
	jz @F
	mov si, [si]		; -> errfix.eld array, or 0
@@:
	test si, si
	jz .transfer

	add si, ax		; -> array entry for CR
	inc si			; -> entry for byte after CR
	inc cx			; count byte after CD
	lea di, [si + 4]	; -> destination for byte after CR
				;  (calculated from extension length)
	call moveup
	std
	mov al, [si]
	stosb
	stosb
	stosb
	stosb
	cld

	jmp .transfer

.done:
%if 0
	mov di, word [relocateddata]
linkdatarelocation terminator_in_line_in.offset
	mov al, byte [relocateddata]
linkdatarelocation terminator_in_line_in.value
	mov byte [di], al	; undo
%endif

.transfer:
	mov si, relocateddata + 2
linkdatarelocation line_in
	extcallcall skipwhite
	jmp ..@transfer_to_chain_si


.try_scriptspath:

%if _LIBSCAN
	mov word [nothingoffset], bx
internaldatarelocation
%endif
	mov di, bx
		; INP:	di -> filepath tried
		;	word [yy_try_scriptspath]
		; OUT:	ZR if to retry,
		;	 bx -> new filepath
		;	NZ if not
		; STT:	es = ds = ss
	extcallcall retry_open_scriptspath
	jnz nothingfound	; not retrying -->

	mov di, bx
	mov al, 0
	mov cx, -1
	repne scasb
	not cx			; neg cx, dec cx
	dec cx

	mov di, relocateddata
linkdatarelocation while_buffer
	call check_filename
	jc nothingfound		; not found -->
	jz .done		; no extension needs to be appended -->
	jmp .finish		; found with an extension -->


moveup:
	std
	cmp cx, 20
	ja @FF
@@:
	movsb
	loop @B
@@:
	rep movsb
	cld
	retn


%ifn _LIBSCAN
 nothingfound equ detect_extension.done
%endif

%if _LIBSCAN
notfound_invalid:
	mov sp, word [nothingsp]
internaldatarelocation
	jmp detect_extension.done


nothingfound:
.done equ notfound_invalid
	mov word [nothingsp], sp
internaldatarelocation

	rol byte [relocateddata], 1
linkdatarelocation yy_is_script	; is it a Y command ?
	jc .done		; yes, skip special handling -->
	test dh, dh		; pathname contains colons or slashes ?
	jnz .done		; yes, skip special handling -->

	rol byte [debuglib], 1
internaldatarelocation
	jnc @F

	mov dx, msg.nothingfound.1
internaldatarelocation
	extcallcall putsz
	mov dx, word [nothingoffset]
internaldatarelocation
	extcallcall putsz
	mov dx, msg.nothingfound.2
internaldatarelocation
	extcallcall putsz
	mov dx, nothinglib
internaldatarelocation
	extcallcall putsz
	mov dx, msg.nothingfound.3
internaldatarelocation
	extcallcall putsz

@@:
	xor ax, ax

	cmp byte [nothinglib], al
internaldatarelocation
	je .done

	mov cx, -1
	mov di, [nothingoffset]
internaldatarelocation
	mov bx, di
	repne scasb
	not cx
	dec cx
	jz notfound_invalid

	cmp cx, 4
	jb .notext
	lea si, [bx - 4]
	add si, cx
	cmp byte [si], '.'
	jne .notext
	mov ax, word [si + 2]
	and ax, ~2020h
	cmp ax, "LD"
	jne .notext
	mov al, byte [si + 1]
	and al, ~20h
	cmp al, 'E'
	je .ext
	cmp al, 'X'
	jne .notext
.ext:
	sub cx, 4
	jz notfound_invalid
.notext:

	cmp cx, 8
	ja notfound_invalid
	mov si, bx
	mov di, namebuffer
internaldatarelocation
	mov dx, cx
@@:
	lodsb
	extcallcall uppercase
	stosb
	loop @B
	neg dx
	add dx, 8
	xchg cx, dx
	mov al, 32
	rep stosb

	mov bx, nothinglib
internaldatarelocation
%if _BOOTLDR
reloc	testopt [relocateddata], nodosloaded
linkdatarelocation internalflags, -3
	jz libdos
libboot:
	extcallcall init_bootcmd
;reloc	mov word [boot_parsed], bx
;internaldatarelocation

boot_no_wild:
	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 ax, relocateddata
linkdatarelocation load_data_lowest	; make yy_boot_get and yy_boot_update no-ops
	jmp libcommon
%endif

libdos:
	extcallcall InDOS
	jnz error

	call open_file
	jc detect_extension.done

reloc	mov word [relocateddata], ax
linkdatarelocation ext_handle
@@:
libcommon:


		; 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)
		;	word [nothingoffset] -> ASCIZ name of entry to search
	lframe
	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, handle
	 push ax
	xchg bx, ax		; bx = handle

	xor ax, ax
	lvar dword, eldheader
	 push ax
	 push ax

%if _ELDTRAILER
	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

	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



	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
@@:
	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

	add sp, fromwords(ELD_LIBTABLE_size_w)

	xor dx, dx
	push dx
	push dx

.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:
	lea si, [bp + ?libentry + 4]
	mov di, namebuffer
internaldatarelocation
	mov cx, 8
@@:
	lodsb
	extcallcall uppercase
	scasb
	jne @F
	loop @B
@@:
	jne .libskip
	lleave code
	extcallcall close_ext
	jmp insertlib

.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

.io_error:
.invalid_instance:
.invalid:
.invalid_check_sld:
.ret:
.lib_done:
.nolib:
	lleave , forcerestoresp
	extcallcall close_ext
	jmp detect_extension.done


insertlib:
.finish:
	mov dx, nothinglib
internaldatarelocation
	mov di, dx
	mov cx, -1
	xor ax, ax
	repne scasb
	not cx
	dec cx

	mov byte [escape], al
internaldatarelocation
	push cx
	mov di, dx
	mov al, ','
	repne scasb
	pop cx
	je .escape
	push cx
	mov di, dx
	mov al, ';'
	repne scasb
	pop cx
	je .escape
	push cx
	mov di, dx
	mov al, 32
	repne scasb
	pop cx
	je .escape
	push cx
	mov di, dx
	mov al, 9
	repne scasb
	pop cx
	jne .noescape
.escape:
	not byte [escape]
internaldatarelocation
	inc cx			; opening quote
	inc cx			; closing quote
.noescape:
	inc cx			; blank

	extcallcall yy_reset_buf

	test ch, ch
	jnz .done

	mov si, relocateddata + 1
linkdatarelocation line_in
	mov ah, 0
	mov al, byte [si]
	mov bx, 254
	sub bx, cx
	cmp ax, bx		; has space ?
	ja .done
	add byte [si], cl	; add length of extension

	inc si			; -> text
	add si, ax		; -> CR
	mov di, si
	add di, cx		; -> destination for CR (extension length)
    push cx
	mov cx, word [header]
internaldatarelocation
	push cx			; -> header
	neg cx			; minus -> header
	add cx, si		; -> CR minus -> header
	inc cx			; include CR to be moved
	 push cx
	call moveup
	 pop cx
	pop di			; -> trailer source (4 bytes of space)
	mov si, dx		; -> library
	mov bx, ax
    pop cx
	push cx
	push ax
	dec cx
	rol byte [escape], 1
internaldatarelocation
	jc .escaped
	rep movsb
	jmp @F
.escaped:
	mov al, '"'
	stosb
	dec cx
	dec cx
	rep movsb
	stosb
@@:
	mov al, 32
	stosb
	pop ax
	pop cx

	mov si, relocateddata
linkdatarelocation indirect_array_errfix, -2, optional
	test si, si		; not supported ?
	jz @F
	mov si, [si]		; -> errfix.eld array, or 0
@@:
	test si, si
	jz .transfer

	add si, ax		; -> array entry for CR
	inc si			; -> entry for byte after CR
	mov di, si
	add di, cx		; -> destination for byte after CR
				;  (calculated from extension length)
	push cx
	lea cx, [bx + 1]	; count byte after CD
	call moveup
	pop cx
	std
	mov al, [si]
	rep stosb
	cld

.transfer:
	jmp detect_extension.transfer

.done equ detect_extension.done


 seek_compressed_or_dos_or_boot_io equ dos_or_boot_io
 read_compressed_or_dos_or_boot_io equ dos_or_boot_io


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
@@:
	jmp notfound_invalid
%endif
%endif	; _LIBSCAN


		; INP:	bx -> name to try, cx = length
		;	dl = zero if to attempt filename extensions
		;	while_buffer -> prefix, di -> after
		; OUT:	NC if file found,
		;	 while_buffer = name, di -> after NUL
		;	 ZR if no extension appended
		;	 NZ if extension appended
		;	CY if file not found
		; STT:	es = ds = ss
		; CHG:	si, ax
check_filename:
	push cx

	mov si, bx		; ds:si -> name
	rep movsb		; append the name
	push di			; on stack: at initial terminator
	mov si, msg.extensions_eld
internaldatarelocation
	rol byte [relocateddata], 1
linkdatarelocation yy_is_script
	jnc @F
	mov si, msg.extensions_sld
internaldatarelocation		; si -> extensions to try
@@:
	mov al, 0
	stosb
			; cx = 0
.loop:
	mov ax, 4300h		; get attributes
	push dx
	push cx
	mov dx, relocateddata	; ds:dx -> pathname to try
linkdatarelocation while_buffer
%if _BOOTLDR
	rol byte [isbootloaded], 1
internaldatarelocation
	jnc @F
	call boot_does_file_exist
	jmp @FF
@@:
%endif
	stc
	extcallcall _doscall	; try to get attributes
	jc @F			; not found --> CY
	test cl, 10h		; directory ?
	jz @F			; no --> NC
	stc			; yes, handle as not found: CY
@@:
	pop cx
	pop dx
	jnc .ret_NC_cx_ZF	; --> (NC)

	test dl, dl		; had an extension originally ?
	jnz .ret_CY		; yes, do not try to append one -->
	rol byte [guessextension], 1
internaldatarelocation
	jnc .ret_CY		; if no guessing extension -->

	pop di
	push di
	cmp byte [si], 0	; last attempt done ?
	je .ret_CY		; yes -->
	movsw			; ".x"
	movsw			; "LD"
	movsb			; NUL
	inc cx		; cx = nonzero
	jmp .loop

.ret_NC_cx_ZF:
	test cx, cx
	jmp @F
.ret_CY:
	stc			; CY
@@:
	pop ax			; (discard)
	pop cx
	retn


%if _BOOTLDR
		; INP:	ds:dx -> pathname
		; OUT:	CY if file does not exist
		;	NC if file exists
		; CHG:	ax, cx, dx
		; STT:	es = ds = ss
boot_does_file_exist:
	push si
	push di
	push bx

	mov bx, dx

	extcall yy_boot_init_dir2
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 boot_does_file_exist_NO

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

	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:
	extcallcall boot_parse_fn	; get next pathname

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

	retn


boot_does_file_exist_YES:
	db __TEST_IMM8		; NC, skip stc
boot_does_file_exist_NO:
	stc

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

	pop bx
	pop di
	pop si
	retn
%endif


%if _LIBSCAN
libcontrol:
	extcallcall skipcomma
	extcallcall iseol?
	je .display
	dec si
	mov dx, msg.set
internaldatarelocation
	extcallcall isstring?
	je .set
	jmp error

.display:
	mov dx, nothinglib
internaldatarelocation
	extcallcall putsz
	mov dx, msg.linebreak
internaldatarelocation
	extcallcall putsz
	extcallcall cmd3

.set:
	extcallcall skipcomma
	extcallcall iseol?
	jne @F
	xor ax, ax
	mov byte [nothinglib], al
internaldatarelocation
	extcallcall cmd3
@@:

	mov bx, relocateddata
linkdatarelocation line_out

		; INP:	si - 1 -> text
		;	bx -> buffer to store to, 256 Bytes
		; OUT:	al = first text byte of trailer
		;	si - 1 -> trailer
		;	byte [si - 1] may be NUL written there
		;	 in case that INP:bx == INP:si - 1
		;	bx -> pathname, NUL-terminated
		;	di -> terminator NUL
		;	bx may point into a config path buffer
	extcallcall yy_common_parse_name_bx_buffer
				; si + 1 -> trailer, bx -> NUL-terminated pathname
	extcallcall skipwh0
	extcallcall chkeol

	mov cx, di
	inc cx
	sub cx, bx
	cmp cx, 256
	ja error

	mov di, nothinglib
internaldatarelocation
	mov si, bx
	rep movsb
	extcallcall cmd3
%endif


		; INP:	si -> separator
		;	bx -> option byte to modify
		;	cx -> message for display
option:
	extcallcall skipcomma
	extcallcall iseol?
	je .display
	dec si
	mov dx, msg.on
internaldatarelocation
	extcallcall isstring?
	je .on
	mov dx, msg.off
internaldatarelocation
	extcallcall isstring?
	je .off
	mov dx, msg.toggle
internaldatarelocation
	extcallcall isstring?
	je .toggle
.error:
	extcallcall error

.display:
	mov dx, cx
	extcallcall putsz
	mov dx, msg.optionon
internaldatarelocation
	rol byte [bx], 1
	jc @F
	mov dx, msg.optionoff
internaldatarelocation
@@:
	extcallcall putsz
.cmd3:
	extcallcall cmd3

.on:
	lodsb
	extcallcall chkeol
	mov byte [bx], 0FFh
	jmp .cmd3

.off:
	lodsb
	extcallcall chkeol
	mov byte [bx], 0
	jmp .cmd3

.toggle:
	lodsb
	extcallcall chkeol
	not byte [bx]
	jmp .cmd3


%if _LIBSCAN
		; INP:	ds:bx -> filename
		; OUT:	NC if file opened,
		;	 ax = file handle
		;	CY if open failed
		; STT:	ds = es = ss = debugger data selector/segment
open_file:
	mov di, bx
	call .setup_opencreate			; ds:si -> pathname
	mov ax, 716Ch				; LFN open-create
	push di
	xor di, di				; alias hint
	stc
	extcallcall _doscall
	pop di
	jnc .got		; LFN call succeeded -->

		; Early case for no-LFN-interface available.
	; cmp ax, 1
	; je .try_sfn
	cmp ax, 7100h
	je .try_sfn

	extcallcall yy_check_lfn
	jnc .error		; if LFN interface is available, actual error
				; if LFN interface is not available, try SFN

.try_sfn:
	call .setup_opencreate
	mov ax, 6C00h				; Open-create
	stc
	extcallcall _doscall
	jnc .got

	cmp ax, 1
	je .try_old_open
	cmp ax, 6C00h
	jne .error

.try_old_open:
	mov al, bl				; access and sharing modes
	mov ah, 3Dh				; Open
	mov dx, si				; -> filename
	stc
	extcallcall _doscall
	jnc .got

.error:
	extcallcall retry_open_scriptspath
	je open_file
	stc
.got:
	retn

.setup_opencreate:
	mov si, di				; -> filename
	mov bx, 0110_0000_1010_0000b		; Auto-commit, no int 24h
						; No inherit
						; DENY WRITE, Read-only
	xor cx, cx				; create attribute
	mov dx, 0000_0000_0000_0001b		; no create / open, no truncate
	retn
%endif


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


uninstall:
	lodsb
	extcallcall chkeol

	call get_es_ext

	push es
	pop ds
	xor bx, bx		; = 0 (no prior, modify ext_command_handler)
	mov di, command		; di -> us
internalcoderelocation
	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:
	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:
	clropt [code + eldiFlags], eldifResident
internalcoderelocation -3	; mark block as free
	mov dx, msg.uninstall_done
internaldatarelocation
@@:
	push ss
	pop ds
	extcallcall putsz
	extcallcall cmd3	; return

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


	eldcall_dump_callcall ELDCALL_CALLCALL_LIST

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


start:
	mov bx, es
	 push ss
	 pop es

	call skipcomma
	dec si
	mov dx, relocateddata
linkdatarelocation msg.install
	call isstring?
	je install
	mov dx, msg.help
internaldatarelocation
	call putsz
	call uninstall_oneshot
	xor ax, ax
	retf


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

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

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


	usesection DATA

guessextension:		db 0FFh
warnextension:		db 0FFh
%if _LIBSCAN
debuglib:		db 0
%endif

msg:
	align 2, db 0
.extensions_eld:
		asciz ".ELD"
		asciz ".XLD"
		db 0
.extensions_sld:
		asciz ".SLD"
		db 0
.extension_warning:
		asciz "Warning, unknown filename extension specified!",13,10
%if _LIBSCAN
.nothingfound.1:	asciz "Nothing found in extname ",'"'
.nothingfound.2:	asciz '", trying with lib "'
.nothingfound.3:	db '"'
.linebreak:		asciz 13,10
%endif
.ext:			asciz "EXT"
.extname:		asciz "EXTNAME"
.on:			asciz "ON"
.off:			asciz "OFF"
.toggle:		asciz "TOGGLE"
%if _LIBSCAN
.lib:			asciz "LIB"
.set:			asciz "SET"
%endif
.guessext:		asciz "GUESSEXT"
.warnext:		asciz "WARNEXT"
%if _LIBSCAN
.debuglib:		asciz "DEBUGLIB"
%endif
.optionon:		asciz " is ON.",13,10
.optionoff:		asciz " is OFF.",13,10
.guessextoption:	asciz "Guessing EXT/Y filename extension"
.warnextoption:		asciz "Warning on unknown EXT/Y filename extension"
%if _LIBSCAN
.debugliboption:	asciz "Debug LIB scan"
%endif
.uninstall_done:	db "EXTNAME uninstalled."
%if _ELD_RECLAIM_HINT
			db " (Don't forget to use reclaim.eld)"
%endif
			asciz 13,10
.uninstall_error:	asciz "EXTNAME unable to uninstall!",13,10

uinit_data: equ $

.installed:	asciz "EXTNAME installed.",13,10
.help:		db "Install this ELD using the INSTALL keyword parameter.",13,10
		db 13,10
		db "Running EXT or Y command will invoke filename extension guessing.",13,10
		db "Run as EXTNAME keyword [ON|OFF|TOGGLE] to configure this ELD,",13,10
		db " where keyword is one of WARNEXT, GUESSEXT.",13,10
		db "Run as EXTNAME UNINSTALL to uninstall this ELD.",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
%if _LIBSCAN
nothinglib:			resb 256
.end:
namebuffer:			resb 8
libtab_compressed_length:	resd 1
nothingsp:			resw 1
nothingoffset:			resw 1

header:			resw 1
%endif
trailer:		resw 1
isbootloaded:		resb 1
%if _LIBSCAN
escape:			resb 1

%if _DATABUFFER
	alignb 16
databuffer:
	resb 512
%endif
%endif

	alignb 16
resident_data_end:
uinit_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
	sub word [es:code + eldiEndCode], ax
internalcoderelocation		; adjust size
	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
	sub word [es:code + eldiEndData], ax
internalcoderelocation		; adjust size
	sub word [relocateddata], ax
linkdatarelocation extdata_used	; adjust size
%endif

	mov bx, word [relocateddata]
linkdatarelocation ext_command_handler
				; -> prior
	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:
	setopt [es:code + eldiFlags], eldifResident
internalcoderelocation -3	; mark block as resident
	mov word [relocateddata], command
linkdatarelocation ext_command_handler, -4
internalcoderelocation		; -> our entrypoint

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


%include "eldlink.asm"

	align 16
code_size equ $ - code
