
%if 0

lDebug initialisation - Path analyse and search

Copyright (C) 2008-2025 E. C. Masloch

Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.

DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.

%endif


; defines used:
; ELD = nonzero iff included by Extension for lDebug path.asm (for path.eld)
; INTERC3 = nonzero iff included by INTERC3 intercep.asm
; else included by lDebug init.asm
; PART1 = nonzero if to embed main code
; PART2 = nonzero if to embed subfunctions
; PART3 = nonzero if to embed imsg messages

%if PART1
		; INP:	si -> pathname followed by command line
		;	word [ss:sp] = si
		; OUT:	word [ss:sp] -> final buffer
init_analyse_pathname:
	mov bx, si
	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
	call init_ifsep
	jne @B
	dec si			; bx -> name, si -> terminator
				; dh = nonzero if a pathname not just filename
				; dl = nonzero if filename contains a dot
	push ss
	pop es
	mov cx, si
	sub cx, bx		; es:bx -> name, cx = length


init_check_warn_extension:
	push dx
	push es

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

	rol byte [init_data_segment:init_switch_pw], 1
internaldatarelocation
	jnc .done		; warning disabled -->

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

	sub si, 4		; -> possible extension
	push init_data_segment
	pop es
	mov di, imsg.no_warn_extensions
internaldatarelocation		; es:di -> allowed extensions
.loop:
	mov al, 0
	xchg byte [init_data_segment:di+4], al
				; NUL-terminate the candidate extension
	push ax
	mov dx, di
	call init_isstring?	; is it this one ?
	pop ax
	mov byte [init_data_segment:di+4], al
				; restore next extension text
	je .done		; yes, do not warn -->
	scasw
	scasw			; di += 4
	test al, al		; was last ?
	jnz .loop
.warn:
	mov dx, imsg.extension_warning
internaldatarelocation
	call init_putsz_cs

.done:
	pop es
	pop dx


init_find_path:
%if ELD
	extcallcall InDOS
	jnz .done_j
	testopt [relocateddata], tt_while
linkdatarelocation internalflags_with_tt_while, -3
	jnz .done_j
%endif
	cmp word [init_data_segment:\
		init_switch_p_low_pathsearch_high_guessextension], strict byte 0
internaldatarelocation -3
	je .done_j

	jcxz .done_j		; if no filename given -->

				; es:bx -> name, cx = length
	mov di, relocated(while_buffer)
linkdatarelocation while_buffer	; ss:while_buffer -> prefix, ss:di -> after end

	call init_check_filename
	jnc .found

	test dh, dh
	jz @F
.done_j:
	jmp .done
@@:
	rol byte [init_data_segment:init_switch_p_pathsearch], 1
internaldatarelocation
	jnc .done_j

%if _DEVICE && _APPLICATION && ! ELD && ! INTERC3
	testopt [internalflags6], dif6_device_mode
	jnz .device
%endif
%if _APPLICATION || ELD || INTERC3
	mov ax, [2Ch]
 %if _DEVICE && ! ELD && ! INTERC3
	jmp @F
 %endif
%endif

%if _DEVICE && ! ELD && ! INTERC3
.device:
	call init_device_get_environment
@@:
%endif

	push cx
	mov di, imsg.varpath
internaldatarelocation
	mov cx, imsg.varpath.length
	call init_findvar
	jc .done_pop

.pathloop:
	push si
	mov cx, 128		; put a limit
@@:
	lodsb			; get next text
	cmp al, ';'		; separator ?
	je @F			; yes -->
	cmp al, 0		; separator ?
	je @F			; yes -->
	loop @B			; loop up to limit
	jmp .pathtoolong	; error -->
@@:
	mov cx, si
	dec cx			; -> terminator
	pop si			; -> content text
	sub cx, si		; = length excluding terminator
	 push ss
	 pop es
	mov di, relocated(while_buffer)
linkdatarelocation while_buffer	; es:di -> buffer

	mov al, 0		; no backslash if empty
	jcxz @FFF		; skip loop if empty -->
@@:
	lodsb			; load from variable
	cmp al, '/'		; forward slash ?
	jne @F			; no -->
	mov al, '\'		; replace by backslash
@@:
	stosb			; store
	loop @BB		; loop for cx = count
@@:
	cmp al, '\'		; trailing backslash ?
	je @F			; yes -->
	mov al, '\'
	stosb			; append it
@@:
	pop cx

	push ds
	push si
				; ss = es, es:bx -> name, cx = length
				; ss:while_buffer -> prefix, ss:di -> after end
	call init_check_filename
	pop si
	pop ds			; ds:si -> terminator of path element
	jnc .found

	lodsb			; get terminator
	cmp al, ';'		; semicolon ?
	jne .done		; no -->
	push cx
	jmp .pathloop		; try next -->


.found:
	push ss
	pop ds			; ds => PSP
	 pop si
	add si, cx		; ds:si -> behind original name
	push ss
	pop es
	dec di			; es:di -> NUL
%if INTERC3
	mov al, 32		; blank codepoint
	cmp byte [si], al	; <= 32 ?
	ja @F			; no, store a blank first -->
%endif
	jmp @FF			; skip store on first iteration

@@:
	cmp di, relocated(while_buffer.end) - 2
linkdatarelocation while_buffer.end
	ja .toolong
	stosb
@@:
	lodsb
	cmp al, 0
	je @F
	cmp al, 13
	jne @BB
@@:			; (targeted from both directions)
	mov al, 13
	stosb
	mov si, relocated(while_buffer)
linkdatarelocation while_buffer
	 push si		; offset for N/K command (kk)
	jmp .done

.toolong:
	mov dx, imsg.kktoolong
internaldatarelocation
	call init_putsz_cs
	jmp @B

.pathtoolong:
 %if ELD
	push ss
	pop ds
 %endif
	mov dx, imsg.pathtoolong
internaldatarelocation
	call init_putsz_cs

	pop ax			; (discard si)
.done_pop:
	pop ax			; (discard cx)
.done:
%endif


%if PART2
		; Compare character with separators
		;
		; INP:	al = character
		; OUT:	ZR if al is CR, NUL, blank, tab, comma, semicolon, or equal sign
		;	ZR if switch character is a slash and al is a slash
		;	NZ else
		; REM:	This is only used for parsing FCBs.
init_ifsep:
	cmp al, 0
	je .return
	cmp al, 13
	je .return
	cmp al, ';'
	je .return
	cmp al, 32
	je .return
	cmp al, 9
	je .return
	cmp al, ','
	je .return
	cmp al, '='
	je .return
	cmp al, byte [ss:relocated(swch1)]
linkdatarelocation swch1
.return:
	retn


%if _APPLICATION || _DEVICE
		; INP:	es:bx -> name to try, cx = length
		;	dl = zero if to attempt filename extensions
		;	ss:while_buffer -> prefix, ss:di -> after
		; OUT:	NC if file found,
		;	 ss:while_buffer = name, ss:di -> after NUL
		;	CY if file not found
		;	ds = ss
		; CHG:	si, ax
init_check_filename:
	push es
	push cx

	push es
	pop ds
	mov si, bx		; ds:si -> name
	 push ss
	 pop es			; es:di -> where to append name
	rep movsb		; append the name
	push di			; on stack: at initial terminator
	mov si, imsg.p_extensions
internaldatarelocation
				; cs:si -> extensions to try
.loop:
	mov al, 0
	stosb			; zero-terminate name
	mov ax, 4300h		; get attributes
	push dx
	 push ss
	 pop ds
	mov dx, relocated(while_buffer)	; ds:dx -> pathname to try
linkdatarelocation while_buffer
	stc
%if ELD
	extcallcall _doscall
%else
	int 21h			; try to get attributes
%endif
	jc @F			; not found --> CY
	test cl, 10h		; directory ?
	jz @F			; no --> NC
	stc			; yes, handle as not found: CY
@@:
	pop dx
	jnc .ret		; --> (NC)
	test dl, dl		; had an extension originally ?
	jnz .ret_CY		; yes, do not try to append one -->
	rol byte [init_data_segment:init_switch_p_guessextension], 1
internaldatarelocation
	jnc .ret_CY		; if no guessing extension -->
	pop di
	push di
	cmp byte [init_data_segment:si], 0
				; last attempt done ?
	je .ret_CY		; yes -->
	init_data_segment movsw	; ".C"
	init_data_segment movsw	; "OM"
	jmp .loop

.ret_CY:
	stc			; CY
.ret:
	pop ax			; (discard)
	pop cx
	pop es
	retn
%endif


		; INP:	ax => environment, zero if none
		;	cs:di -> variable name, including '=' terminator
		;	cx = variable name length, including '=' terminator
		; OUT:	CY if not found
		;	NC if found,
		;	 ds:si -> behind '=' of found variable
		; CHG:	ax, es, di, ds, si, cx
init_findvar:
	test ax, ax
	jz .notvar
	mov ds, ax
	xor si, si

@@:
	push init_data_segment
	pop es
	push cx
	push di
	push si
	repe cmpsb
	je .foundvar		; --> (NC)
	pop si
	pop di
	pop cx
	call init_nextvar
	jnz @B
.notvar:
	stc
	retn

.foundvar:
	pop ax
	pop ax
	pop ax
	retn


init_nextvar:
@@:
	lodsb
	test al, al
	jnz @B
	cmp byte [si], 0
	retn
%endif


%if PART3
 %if INTERC3
  %define _PROGNAME ""
 %endif
	align 2, db 0
.no_warn_extensions:
 %ifn INTERC3
		db ".HEX",".ROM"
 %endif
%if (($ - .no_warn_extensions) % 4) != 0
 %error Wrong extensions length
%endif
.p_extensions:	db ".COM"
		db ".EXE"
 %ifn INTERC3
		db ".BIN"
 %endif
		asciz
%if (($ - 1 - .p_extensions) % 4) != 0
 %error Wrong extensions length
%endif
.varpath:	db "PATH="
.varpath.length equ $ - .varpath
.extension_warning:
%ifn ELD
	db _PROGNAME,": "
%endif
	asciz "Warning, unknown filename extension specified!",13,10
.kktoolong:
%ifn ELD
	db _PROGNAME,": "
%endif
	asciz "Error, too long command line tail!",13,10
.pathtoolong:
%ifn ELD
	db _PROGNAME,": "
%endif
	asciz "Error, too long %PATH% variable element!",13,10
%endif
