
; Public Domain

; test install command: install; .; path uninstall
; test run command: help; .; .

%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"

	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 PATH search and filename extension warning for N/K."


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


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.path
internaldatarelocation
	extcallcall isstring?
	je .ourcommand

	lodsb
	extcallcall uppercase
	cmp al, 'K'
	je .ourmodify
	cmp al, 'N'
	je .ourmodify

	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, init_switch_pw
internaldatarelocation
	mov cx, msg.warnextoption
internaldatarelocation
	mov dx, msg.warnext
internaldatarelocation
	extcallcall isstring?
	je .option_ZR

	mov bx, init_switch_p_guessextension
internaldatarelocation
	mov cx, msg.guessextoption
internaldatarelocation
	mov dx, msg.guessext
internaldatarelocation
	extcallcall isstring?
	je .option_ZR

	mov bx, init_switch_p_pathsearch
internaldatarelocation
	mov cx, msg.pathsearchoption
internaldatarelocation
	mov dx, msg.pathsearch
internaldatarelocation
	extcallcall isstring?
.option_ZR:
	je option

	lodsb
	extcallcall chkeol
	extcallcall cmd3


.ourmodify:
	pop ax
	extcallcall skipcomma
	dec si
reloc2	mov word [relocateddata], relocateddata
linkdatarelocation lastcmd, -4
linkdatarelocation dmycmd

%assign ELD 1
%define relocated(address) relocateddata
%define init_data_segment ss
%define section_of_function
%assign _APPLICATION 1
%assign _DEVICE 1
TOUPPER		equ ~32

	call do
	je .transfer

	mov si, relocateddata + 2
linkdatarelocation line_in
	extcallcall skipwhite
	cmp al, '-'
	jne @F
	extcallcall skipcomma	; lod dash
@@:
	extcallcall skipcomma	; lod N/K letter
	dec si			; si -> where to append

	mov di, bx		; di -> new buffer
	mov al, 13
	mov cx, 256
	repne scasb		; di -> behind CR
	jne .error
	mov cx, di
	sub cx, bx		; cx = length including CR

	mov di, si		; -> where to append
	mov ax, si
	add ax, cx
	cmp ax, strict word relocateddata
linkdatarelocation line_in.end
	ja .error

	extcallcall yy_reset_buf

	mov si, bx
	rep movsb
	xchg ax, di
	sub ax, strict word relocateddata + 2 + 1
linkdatarelocation line_in
	mov byte [relocateddata + 1], al
linkdatarelocation line_in

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


.error:
	mov ax, 0E4Ch
	extcallcall setrc
	mov dx, imsg.kktoolong
internaldatarelocation
	extcallcall putsz
	extcallcall cmd3


		; INP:	si -> pathname (first nonblank, after comma)
		; OUT:	bx -> buffer to use
		;	di = INP:si
		;	ZR if bx == di
do:
	push si
	push si
		; INP:	si -> pathname followed by command line
		;	word [ss:sp] = si
		; OUT:	word [ss:sp] -> final buffer
%assign PART1 1
%assign PART2 0
%assign PART3 0
%include "pathshar.asm"

	push ss
	pop ds
	push ss
	pop es

	pop bx			; bx -> new buffer
	pop di			; di -> old buffer
	cmp bx, di
	retn


init_putsz_cs:
	extcallcall putsz
	retn

%define PREFIX init_
%include "isstring.asm"

%assign PART1 0
%assign PART2 1
%assign PART3 0
%include "pathshar.asm"


		; 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


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, si
	lodsb
	call uppercase
	cmp al, 'N'
	je oneshot
	cmp al, 'K'
	je oneshot

	mov dx, msg.help
internaldatarelocation
	call putsz
	call uninstall_oneshot
	xor ax, ax
	retf


oneshot.warn:
	push dx
	mov dx, msg.oneshot.warn
internaldatarelocation
	call putsz
	pop dx
	jmp @F

oneshot:
	call InDOS
	jnz .warn
	testopt [relocateddata], tt_while
linkdatarelocation internalflags_with_tt_while, -3
	jnz .warn

@@:
	call skipcomma
	dec si
	push dx
	call do
	pop dx
	push di
	mov di, bx		; di -> (modified) program load name
	mov al, 13
	mov cx, 255
	repne scasb		; scan for EOL (CR)
	je @F

.error:
	mov dx, msg.oneshot.error
internaldatarelocation
	mov ax, 0E4Dh
	call setrc
	call putsz
	call cmd3

@@:
	mov cx, di		; -> after CR
	sub cx, bx		; -> after CR minus -> program load name
				; cx = length of remainder line

	pop di			; -> original program load name
	xchg ax, cx		; ax = length of remainder line
	sub di, dx		; -> original name minus -> command letter
				; di = length of start line
	mov cx, di
	add cx, ax		; = length of total line (including CR)
	cmp cx, 255		; fits ?
	ja .error		; no -->

	mov cx, di		; = length of start line
	mov si, dx		; -> command letter
	mov di, buffer + 1
internaldatarelocation
	rep movsb		; move down start line
	mov si, bx		; -> (modified) name
	xchg cx, ax		; cx = length of remainder line
	rep movsb		; store it

	xchg ax, di
	sub ax, strict word buffer + 2
internaldatarelocation
	mov byte [buffer], al
internaldatarelocation

	mov ax, word [relocateddata]
linkdatarelocation ext_inject_handler
	mov word [priorinject], ax
internaldatarelocation

	call get_es_ext
	setopt [es:code + eldiFlags], eldifResident
internalcoderelocation -3		; mark block as resident

	mov word [relocateddata], .inject
linkdatarelocation ext_inject_handler, -4
internalcoderelocation
	call cmd3

.inject:
	houdini

	mov di, relocateddata + 1
linkdatarelocation line_in
	mov si, buffer
internaldatarelocation

	extcall yy_reset_buf
	push di
	mov cx, words(256)
	rep movsw
	pop si

	mov ax, word [priorinject]
internaldatarelocation
	mov word [relocateddata], ax
linkdatarelocation ext_inject_handler

	inc si
	extcall skipwhite

	call get_es_ext
	clropt [es:code + eldiFlags], eldifResident
internalcoderelocation -3		; mark block as free
	 push ss
	 pop es

	extcall cmd3_injected


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

init_switch_p_low_pathsearch_high_guessextension:
init_switch_p_pathsearch:	db 0FFh
init_switch_p_guessextension:	db 0FFh
init_switch_pw:		db 0FFh

imsg:
%assign PART1 0
%assign PART2 0
%assign PART3 1
%include "pathshar.asm"

msg:
.path:			asciz "PATH"
.on:			asciz "ON"
.off:			asciz "OFF"
.toggle:		asciz "TOGGLE"
.guessext:		asciz "GUESSEXT"
.warnext:		asciz "WARNEXT"
.pathsearch:		asciz "PATHSEARCH"
.optionon:		asciz " is ON.",13,10
.optionoff:		asciz " is OFF.",13,10
.guessextoption:	asciz "Guessing N/K filename extension"
.warnextoption:		asciz "Warning on unknown N/K filename extension"
.pathsearchoption:	asciz "Path search for N/K filename"
.uninstall_done:	db "PATH uninstalled."
%if _ELD_RECLAIM_HINT
			db " (Don't forget to use reclaim.eld)"
%endif
			asciz 13,10
.uninstall_error:	asciz "PATH command unable to uninstall!",13,10

uinit_data: equ $

.installed:	asciz "PATH installed.",13,10
.help:		db "Install this ELD using the INSTALL keyword parameter.",13,10
		db 13,10
		db "Run N or K command to invoke path search.",13,10
		db "Run as PATH keyword [ON|OFF|TOGGLE] to configure this ELD,",13,10
		db " where keyword is one of WARNEXT, GUESSEXT, PATHSEARCH.",13,10
		db "Run as PATH UNINSTALL to uninstall this ELD.",13,10
		asciz
.oneshot.warn:	asciz "Warning: WHILE buffer not available or InDOS! Cannot path search.",13,10
.oneshot.error:	asciz "Error: Path search result does not fit in buffer!",13,10

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

	absolute uinit_data
transient_uinit_data:

	alignb 16
resident_data_end:
resident_data_size equ resident_data_end - datastart

	absolute transient_uinit_data
	alignb 2
priorinject:	resw 1
buffer:		resb 256

	alignb 16
uinit_data_end:

%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 (total_data_size - resident_data_size) > 0
	mov ax, total_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
	retf


%include "eldlink.asm"

	align 16
code_size equ $ - code
