
%if 0

lDebug DI commands - Dump data

Copyright (C) 1995-2003 Paul Vojta
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


		; DI command
gateout:
	xor cx, cx
	lodsb
%if !_LOADER
	extcallcall capitalise
	cmp al, 'R'
	jne @F
	inc cx		; always 86 Mode
	lodsb
@@:
	extcallcall capitalise
	cmp al, 'M'
	jne @F
	inc ch		; show MCB names
	lodsb
@@:
	extcallcall capitalise
	cmp al, 'L'
	jne @F
	or ch, 2	; follow AMIS interrupt lists
	lodsb
@@:
%endif
	extcallcall skipcomm0

	dec si
	mov dx, relocated(msg.in)
linkdatarelocation msg.in
	extcallcall isstring?
	jne .not_in

	extcallcall skipcomma
	dec si
	push si
	push cx
.in.loop:
	extcallcall skipwhite
	dec si

	extcallcall get_value_range; OUT:	cx:di = from, bx:dx = to
	jnc @F
	jnz .error
	cmp di, 255
	ja .error
	jcxz .in.next
.error:
	jmp error

@@:
	cmp di, 255
	ja .error
	jcxz @F
	jmp .error

@@:
	test bx, bx
	jnz .error
	cmp dx, 255
	ja .error

.in.next:
@@:
	extcallcall skipwh0
	cmp al, ','
	je .in.loop
	extcallcall chkeol
	pop cx
	call .prepare
	pop si

.indo.loop:
	extcallcall skipwhite
	dec si

	push cx
	extcallcall get_value_range; OUT:	cx:di = from, bx:dx = to
	pop cx
	jc .indo.next

	mov bx, di
	db __TEST_IMM8		; (skip inc)
@@:
	inc bx
	push dx
	call .do
	pop dx
	cmp bx, dx
	jb @B

.indo.next:
	dec si
	extcallcall skipwhite
	cmp al, ','
	je .indo.loop
	retn



.not_in:
	lodsb
	extcallcall getbyte; get byte into DL
	xor dh, dh
	mov bx, dx
	extcallcall skipcomm0
	mov dx, 1
	extcallcall iseol?
	je .onlyone
	extcallcall capitalise
	cmp al, 'L'
	jne .notlength
	extcallcall skipcomma
	extcallcall getword; get byte into DL
	test dx, dx
	jz .err
	cmp dx, 100h
	je .checkrange
	push ax
	and ah, 1Fh
	cmp ah, 8
	pop ax
	ja .err
.checkrange:
	push dx
	add dx, bx
	cmp dx, 100h
	pop dx
	jna .rangeok
.err:
	jmp error

.last:
	xor bx, bx
	mov bl, byte [lastint]
internaldatarelocation
	mov cx, word [lastint_is_86m_and_mcb]
internaldatarelocation
	mov dx, 1
	inc bl
	jnz .onlyone
	mov word [relocated(lastcmd)], relocated(dmycmd)
linkdatarelocation lastcmd, -4
linkdatarelocation dmycmd
	retn

.notlength:
	extcallcall getbyte
	xor dh, dh
	sub dl, bl
	jc .err
	inc dx
.rangeok:
	extcallcall chkeol
.onlyone:
	call .prepare
	mov si, dx	; save count
.next:
	call .do
	inc bx
	dec si
	jnz .next
	retn


.prepare:
	test ch, 2
	jz @F
	extcallcall guard_auxbuff
@@:
%if ELD
	mov word [relocateddata], .last
linkdatarelocation lastcmd_transfer_ext_address, -4
internalcoderelocation
	mov word [relocateddata], relocateddata
linkdatarelocation lastcmd, -4
linkdatarelocation lastcmd_transfer_ext_entry
%else
	mov word [lastcmd], .last
%endif
	mov word [lastint_is_86m_and_mcb], cx
internaldatarelocation
%if ELD
	extcallcall prephack
	retn
%else
	jmp prephack
%endif


		; INP:	bx = interrupt number
		;	cx = options
		; CHG:	di, eax. edx, bp
		; STT:	ds = es = ss
		;	prephack called
.do:
	mov byte [lastint], bl
internaldatarelocation
	extcallcall handle_serial_flags_ctrl_c
	extcallcall dohack
	mov di, relocated(line_out)
linkdatarelocation line_out
	mov ax, "in"
	stosw
	mov ax, "t "
	stosw
	mov al, bl
	extcallcall hexbyte
	mov al, 32
	stosb
%if _PM
	test cl, cl
	jnz .rm
	extcallcall ispm
	jnz .rm

	mov ax, 0204h
	cmp bl, 20h
	adc bh, 1	; if below, bh = 2
.loopexception:
	push cx
	int 31h
	mov ax, cx
	pop cx
	jc .failed
	extcallcall hexword
	mov al, ':'
	stosb
%if ELD && 1
	testopt [relocateddata], 8000h
linkdatarelocation internalflags, -3
	jz @F
	o32
@@:
%else
	_386_PM_o32	; mov eax, edx
%endif
	mov ax, dx
	cmp byte [relocated(dpmi32)], 0
linkdatarelocation dpmi32, -3
	jz .gate16
	extcallcall hexword_high
.gate16:
	extcallcall hexword
	mov al, 32
	stosb
	mov ax, 0202h
	dec bh
	jnz .loopexception
	dec di
	extcallcall unhack
	push bx
	push cx
	extcallcall putsline_crlf
	pop cx
	pop bx
	retn

.rm:
%endif
	push bx
	push cx
	push si

	push bx
	xor bp, bp
	shl bx, 1
	shl bx, 1
	xor dx, dx
%if _PM
	extcallcall setes2dx
%else
	mov es, dx			; es => IVT
%endif
	mov ax, word [es:bx + 2]	; ax = segment
	mov dx, word [es:bx]
	pop bx

%if !_LOADER
	test ch, 2
	jnz int_list
%endif

.loop_chain:
	push ax				; segment
	push dx

	 push ss
	 pop es				; ! es = ss
	extcallcall hexword
	mov al, ':'
	stosb
	mov ax, dx
	extcallcall hexword

	pop bx
	pop dx				; segment

	mov word [intaddress + 2], dx
internaldatarelocation
	mov word [intaddress], bx
internaldatarelocation

	inc bp
	cmp bp, 256
	ja .toomany			; --> (! es = ss)

	call check_int_chain
	jc .end_chain

	push dx				; segment
	push ax
	 push ss
	 pop es
	extcallcall unhack
	push cx
	extcallcall copy_single_counted_string
	pop cx
	call .mcbname
	push cx
	extcallcall putsline_crlf
	pop cx
	extcallcall handle_serial_flags_ctrl_c
	extcallcall dohack
	mov di, relocated(line_out)
linkdatarelocation line_out
	mov ax, " -"
	stosw
	mov ax, "->"
	stosw
	mov al, 32
	stosb

	pop dx
	pop ax				; (ax = segment)
	jmp .loop_chain

.end_chain:
	 push ss
	 pop es
	jnz @F
.end_chain_string:
	extcallcall unhack
	push cx
	extcallcall copy_single_counted_string
	pop cx
	jmp @FF
@@:
	extcallcall unhack
@@:
	call .mcbname
	extcallcall putsline_crlf
.86next:
	pop si
	pop cx
	pop bx
	retn

.toomany:
	mov si, msg.di_toomany
internaldatarelocation
	jmp .end_chain_string

 %if _PM
.failed:
	extcallcall unhack
	pop dx				; discard a near return address
	mov dx, gatewrong
internaldatarelocation
	mov ax, 0134h
	extcallcall setrc
%if ELD
	extcallcall putsz
	retn
%else
	jmp putsz
%endif
 %endif


%if 0

For the DIL command we fill the auxiliary buffer with entries
for each interrupt entrypoint. They are found by starting from
the IVT as well as the AMIS interrupt lists. Of course, any
entrypoint may be found from more than one point.

The format is as follows:

dword - vector
word - flags and AMIS multiplex number (low byte)
	flag 200h = unclaimed, AMIS multiplex number not initialised
	flag 100h = immediately from IVT (and is the very first entry in auxbuff)
	if this word is -1 then it is not an entry, it is a terminator
word - which entry in an AMIS interrupt list

A terminator is an entry with all ones (-1).
Two consecutive terminators indicate the last chain ended.
After a single terminator another chain follows.
Any chain after the very first is a hidden chain,
that is, its handlers are not reachable from the IVT
by walking the downlinks.

A hidden chain may be found which eventually feeds into
another hidden chain found previously. In this case, the
new unique handlers (at least 1) are prepended to the
pre-existing hidden chain, and the downlinks past this
point are not walked further (as they're already known).

If an AMIS interface points to a handler that we already
know (in the first IVT-based chain or any hidden chain)
then its downlink will not be walked again. However, the
multiplex number and list index will be entered into the
entry for this interrupt handler.

Finally, after the IVT and all interrupt lists of all AMIS
multiplexers have been processed, the auxbuff list is used
to display the found chains (one IVT, any amount hidden).

%endif

%if !_LOADER
int_list:
	push di
	push cx
	push bx
	xchg ax, dx			; dx = segment

	mov es, word [ss:relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
	xor di, di			; -> auxbuff
	stosw				; store offset
	xchg ax, dx			; dx = offset
	stosw				; store segment
	xchg ax, dx			; dx = segment
	xchg bx, ax			; bx = offset
	mov ax, 300h			; flag for IVT | unused
	stosw				; which multiplex number
	xor ax, ax
	stosw				; which int list entry = none = 0

.loop_ivt_chain:
	call check_int_chain
	jc .end_ivt_chain

%if ! ELD && _AUXBUFFSIZE == _AUXBUFFMAXSIZE
	cmp di, _AUXBUFFSIZE - 8 * 3	; enough for 1 entry + 2 terminators ?
%else
	cmp di, word [ss:relocated(auxbuff_current_size_minus_24)]
linkdatarelocation auxbuff_current_size_minus_24
%endif
	ja .error
	mov es, word [ss:relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
	stosw				; store offset
	xchg ax, dx
	stosw				; store segment
	xchg ax, dx
	xchg bx, ax
	mov ax, 200h			; flag for unused
	stosw				; found in chain = 200h
	xor ax, ax
	stosw
	jmp .loop_ivt_chain

.end_ivt_chain:
	mov ax, -1
	mov es, word [ss:relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
	mov cx, 8
	rep stosw			; terminator is all-ones
					; (two terminators actually)

	mov al, 2Dh
	extcallcall intchk			; ZR if offset = -1 or segment = 0
					; CHG: ax, dx, bx
	jz .done

	xor ax, ax
.loopplex:
	mov al, 00h			; AMIS installation check
		; function 0 changes dx, di, cx, al
%if _PM
	extcallcall call_int2D
%else
	int 2Dh				; enquire whether there's anyone
					;  but we don't care who it might be
%endif
	inc al				; = FFh ?
	jz .search			; yes, it is in use -->
.nextplex:
	inc ah
	jnz .loopplex			; try next multiplexer -->

.done:
	db __TEST_IMM8			; (NC)
.error:
	stc

	pop bx
	pop cx
	pop di
	 push ss
	 pop ds
	 push ss
	 pop es

	mov si, msg.di_error
internaldatarelocation
	jc .error_string

	xor si, si

.loop_chain:
	mov ds, word [relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
	lodsw
	xchg ax, dx
	lodsw
	cmp word [si], -1
	lea si, [si + 4]
	je .next_seq

.next_chain:
	 push ss
	 pop ds

	push ax				; segment
	push dx

	 push ss
	 pop es
	extcallcall hexword
	mov al, ':'
	stosb
	mov ax, dx
	extcallcall hexword

	pop bx
	pop dx				; segment

	mov word [intaddress + 2], dx
internaldatarelocation
	mov word [intaddress], bx
internaldatarelocation

	push si
	call check_int_chain
	jc .end_chain

	 push ss
	 pop es
	extcallcall unhack
	push cx
	extcallcall copy_single_counted_string
	pop cx
	pop si
	call .mpx
	push si
	call gateout.mcbname
	push cx
	extcallcall putsline_crlf
	pop cx
	extcallcall handle_serial_flags_ctrl_c
	extcallcall dohack
	mov di, relocated(line_out)
linkdatarelocation line_out
	mov ax, " -"
	stosw
	mov ax, "->"
	stosw
	mov al, 32
	stosb

	pop si
	jmp .loop_chain

.end_chain:
	 push ss
	 pop es
	jnz @F
	extcallcall unhack
	push cx
	extcallcall copy_single_counted_string
	pop cx
	jmp @FF
@@:
	extcallcall unhack
@@:
	pop si
	call .mpx
	push si
	call gateout.mcbname
	push cx
	extcallcall putsline_crlf
	pop cx
	mov di, relocated(line_out)
linkdatarelocation line_out
	extcallcall handle_serial_flags_ctrl_c
	extcallcall dohack
	pop si
	jmp .loop_chain

.next_seq:
	lodsw
	xchg ax, dx
	lodsw
	cmp word [si], -1
	lea si, [si + 4]
	je @F

	 push ss
	 pop ds
	 push ss
	 pop es
	extcallcall unhack
	push cx
	push si
	mov si, msg.di_hidden
internaldatarelocation
	extcallcall copy_single_counted_string
	pop si
	pop cx
	extcallcall handle_serial_flags_ctrl_c
	extcallcall dohack

	jmp .next_chain

@@:
	 push ss
	 pop ds
	 push ss
	 pop es
	extcallcall unhack
	jmp @F


.error_string:
	extcallcall copy_single_counted_string

	extcallcall unhack
	extcallcall putsline_crlf
	mov ax, 0133h
	extcallcall setrc
@@:
%if 0	; _DEBUG
	mov es, word [auxbuff_segorsel]
	int3
	push ss
	pop es
%endif
	jmp gateout.86next


.mpx:
	mov es, word [relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
	mov ax, word [es:si - 4]
	mov dx, word [es:si - 2]
	push ss
	pop es
	test ah, 2
	jnz @F
	push si
	push cx
	mov si, msg.di_multiplex.1
internaldatarelocation
	extcallcall copy_single_counted_string
	extcallcall hexbyte
	mov si, msg.di_multiplex.2
internaldatarelocation
	extcallcall copy_single_counted_string
	xchg ax, dx
	extcallcall hexword
	mov si, msg.di_multiplex.3
internaldatarelocation
	extcallcall copy_single_counted_string
	pop cx
	pop si
@@:
	retn


		; INP:	ah = multiplex number of AMIS TSR to search through
		;	ss:sp-> interrupt number (byte), must be preserved
		; CHG:	es, di, dx, bx
.search:
	mov al, 04h
	pop bx
	push bx				; low byte is the interrupt number
		; function 4 changes dx, bx, al
%if _PM
	extcallcall call_int2D
%else
	int 2Dh
%endif
	cmp al, 03h			; returned its interrupt entry ?
		; RBIL doesn't explicitly state that this interrupt entry has to
		; be IISP compatible. But I'm too lazy to look up the older AMIS,
		; and SearchIISPChain checks the interrupt entry anyway.
	je .search_dxbx
	cmp al, 04h			; returned list of hooked interrupts ?
	jne .nextplex			; no, try next multiplexer -->
	mov di, bx
	pop bx
	push bx				; bl = interrupt number
	xor cx, cx			; = index into list
	mov al, bl
.search_intlist_seg:
%if _PM
	extcallcall setes2dx
%else
	mov es, dx			; es:di-> list
%endif
.search_intlist:		; Search the returned list for the required interrupt number.
	scasb				; our interrupt number ?
	je .search_found_intlist
	cmp byte [es:di-1], 2Dh		; was last in list ?
	je .nextplex
	scasw				; skip pointer
	inc cx
	jmp short .search_intlist	; try next entry -->

.search_found_intlist:
	mov bx, word [es:di]		; dx:bx = es:bx -> IISP entry
	scasw				; skip pointer
	push dx				; preserve dx for .search_intlist_seg
	push di
	call .add
	pop di
	pop dx
	jc .error
	; je .search_found		; found entry -->
		; This specific jump supports TSRs that hook the same
		; interrupt more than once; jumping to .nextplex instead
		; (as previously) aborts the search after the first match
		; in the interrupt list. This support might become useful.
	cmp al, 2Dh			; was last in list ?
	je .nextplex
	inc cx
	jmp short .search_intlist_seg

.search_dxbx:
%if _PM
	extcallcall setes2dx
%else
	mov es, dx			; es:bx-> (IISP) interrupt entry
%endif
		; The entry we found now is possibly behind the non-IISP entry that
		; terminated our first SearchIISPChain call (at .hard). We then
		; possibly might find our entry in this hidden part of the chain.
	mov cx, -1			; indicator for return = 3 (no list)
	call .add
	jc .error
	; jne .nextplex			; didn't find our entry in the chain -->
	jmp .nextplex


int_list.add:
	xor di, di			; start at beginning of buffer
	mov ds, word [ss:relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
					; ds => auxbuff
	mov si, -1			; check all
	call .check			; check for match
	jne @F				; not matched, di -> second terminator
	testopt [di + 4], 200h		; not yet claimed by a multiplexer ?
	jz .error			; no, error -->
	mov byte [di + 4], ah		; store the multiplex number
	clropt [di + 4], 200h		; indicate it is claimed
	mov word [di + 6], cx		; = how many list entries before ours,
					;  or = -1 if not from a list
	jmp .done

@@:
		; ds:di -> second terminator (will be overwritten)
%if ! ELD && _AUXBUFFSIZE == _AUXBUFFMAXSIZE
	cmp di, _AUXBUFFSIZE - 8 * 3	; enough for 1 entry + 2 terminators ?
%else
	cmp di, word [ss:relocated(auxbuff_current_size_minus_24)]
linkdatarelocation auxbuff_current_size_minus_24
%endif
	ja .error
	lea si, [di - 8]		; check up to this point later
					;  si -> first of two terminators

	xchg ax, bx
	mov es, word [ss:relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
					; => auxbuff
	stosw				; store offset
	xchg ax, dx			; dx = offset
	stosw				; store segment
	xchg ax, dx			; dx = segment
	xchg ax, bx			; dx:bx = vector -> handler
	push ax
	mov al, 0			; flags = 0 (claimed, not IVT)
	xchg al, ah
	stosw				; which multiplex number
	mov ax, cx
	stosw				; which int list entry
	pop ax				; preserve multiplex number

.loop_chain:
	push ax
	push si
	call check_int_chain		; does it go on ?
	pop si
	pop bx
	jnc @F		; for _LINK compat
	jmp strict near .end_chain	; no -->
@@:

%if ! ELD && _AUXBUFFSIZE == _AUXBUFFMAXSIZE
	cmp di, _AUXBUFFSIZE - 8 * 3	; enough for 1 entry + 2 terminators ?
%else
	cmp di, word [ss:relocated(auxbuff_current_size_minus_24)]
linkdatarelocation auxbuff_current_size_minus_24
%endif
	ja .error
	mov es, word [ss:relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
	stosw				; store offset
	xchg ax, dx
	stosw				; store segment
	xchg ax, dx
	xchg bx, ax			; ah = multiplex number, bx = offset
	push ax
	mov ax, 200h
	stosw				; found in chain = 200h (unclaimed)
	xor ax, ax
	stosw
	pop ax
	push di
	xor di, di			; start at beginning
	call .check			; already listed in another chain ?
	je @F
	pop di
	jmp .loop_chain			; no, try to walk downlink -->

@@:
	pop bx

		; The idea is that if the AMIS interrupt list
		;  pointed to an entry not yet matched then
		;  it is the start of a hidden chain. If a
		;  subsequent handler in this hidden chain
		;  points to another handler that does match
		;  this can only be a valid case if this other
		;  handler also was the start of a hidden chain.
		; If this is the case, prepend the unique new
		;  handlers to that hidden chain in the buffer.
	testopt [di + 4], 100h		; is it from the IVT ? (very first entry)
	jnz .error			; yes, error -->
	cmp word [di - 8 + 4], -1	; is it the start of a hidden chain ?
	jne .error			; no, error -->
		; di -> match (insert to move here)
		; bx -> after repeat
		; bx - 8 -> repeat
		; bx - 16 -> last entry to move (at least 1 to move)
		; si -> single terminator
		; si + 8 -> first entry to move (at least 1 to move)

	sub bx, 16			; -> last entry to move

.insert:
		; di -> match (insert to move here)
		; bx + 8 -> repeat
		; bx -> last entry to move
		; si -> single terminator
		; si + 8 -> first entry to move

	push word [bx + 6]
	push word [bx + 4]
	push word [bx + 2]
	push word [bx]			; get the last entry
	push di
	push si
	push cx				; preserve interrupt list index
	mov es, word [ss:relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
	mov cx, di			; = where to insert
					;  -> first to displace
	neg cx
	mov si, bx			; -> after end of source
	lea di, [bx + 8]		; -> after end of dest
	add cx, si			; after end of source - first to displace
					; = how many bytes to displace
	shr cx, 1
	std				; _AMD_ERRATUM_109_WORKAROUND as below
	cmpsw				; si -= 2, di -= 2

	numdef AMD_ERRATUM_109_WORKAROUND, 1
		; Refer to comment in init.asm init_movp.

%if _AMD_ERRATUM_109_WORKAROUND
	jcxz @FF
	cmp cx, 20
	ja @FF
@@:
	movsw
	loop @B
@@:
%endif
	rep movsw			; relocate up the following entries
					;  by 8 bytes (size of 1 entry)
	cld
	pop cx
	pop si
	pop di
	pop word [di]
	pop word [di + 2]
	pop word [di + 4]
	pop word [di + 6]		; insert moved entry
	add si, 8			; -> at moved single terminator

		; di -> match (inserted here, insert next here)
		; bx + 8 -> repeat
		; bx -> last entry to move (if any)
		; si -> single terminator
		; si + 8 -> first entry to move
	cmp si, bx			; if last to move != terminator
	jne .insert			; then move another ->
	mov di, si			; -> where to put double terminator

	xchg ax, bx
.end_chain:
	push bx
	push cx				; preserve interrupt list index
	mov ax, -1
	mov es, word [ss:relocated(auxbuff_segorsel)]
linkdatarelocation auxbuff_segorsel
	mov cx, 8
	rep stosw			; terminator is all-ones
					; (two terminators actually)
	pop cx
	pop ax				; preserve multiplex number

.done:
	db __TEST_IMM8			; (NC)
.error:
	stc

	retn


		; INP:	dx:bx = 86 Mode far pointer to handler
		;	di -> to check
		;	si = end of area to check (-1 = check all)
		; OUT:	ZR if match found, ds:di -> matching entry
		;	NZ if no match found,
		;	 di -> at second consecutive terminator
		;	 or di >= si
		; CHG:	-
		; STT:	ds => auxbuff
		; REM:	continues loop if di < si and the flags word
		;	 is not -1 in two consecutive entries.
		;	an entry with a flags word -1 is skipped.
.check:
	cmp word [di + 0], bx
	jne .mismatch
	cmp word [di + 2], dx
	jne .mismatch
.match:
	retn				; (ZR)

.mismatch:
	add di, 8

	cmp di, si
	jae .checkret

	cmp word [di + 4], -1
	jne .check

	add di, 8
	cmp word [di + 4], -1
	jne .check
.checkret:
	test di, di			; (NZ)
	retn
%endif	; !_LOADER


		; INP:	dx:bx = 86 Mode far pointer to int handler
		; OUT:	NC if chain found,
		;	 dx:ax = 86 Mode far pointer to next
		;	 ss:si -> type message (counted)
		;	CY if chain not found,
		;	 NZ if no chain
		;	 ZR if chain but next is FFFFh:FFFFh,
		;	  ss:si -> type message
		; STT:	es != ss, ds != ss
check_int_chain:
%if _PM
	extcallcall setes2dx
%else
	mov es, dx			; es:bx -> entrypoint
%endif
	extcallcall IsIISPEntry?
	jnz .not_iisp

	push word [es:bx + ieNext + 2]
	push word [es:bx + ieNext]

	mov si, msg.di_uninst_iisp
internaldatarelocation
	cmp word [ es:bx + ieEntry ], 0EA90h	; nop\jmp far imm16:imm16 ?
	je @F
	mov si, msg.di_iisp
internaldatarelocation
	cmp byte [ es:bx + ieJmphwreset ], 0EBh	; jmp short ?
	jne .nonstd
	cmp word [ es:bx + ieEntry ], 010EBh	; jmp short $+18 ?
	je @F
.nonstd:
	mov si, msg.di_nonstd_iisp
internaldatarelocation
@@:
	pop ax
	pop dx				; segment

	push ax
	and ax, dx
	inc ax
	pop ax
	jz .CY

	clc
	retn


.not_iisp:
	cmp bx, -8
	ja .not_fd
	cmp byte [es:bx], 0E8h
	jne .not_fd
	cmp byte [es:bx + 3], 0EAh
	jne .not_fd
	push word [es:bx + 4 + 2]
	push word [es:bx + 4]
	mov si, msg.di_freedos_reloc
internaldatarelocation
	jmp @B

.not_fd:
	cmp bx, -5
	ja .not_jmpfar
	mov si, msg.di_jmpfar
internaldatarelocation
	cmp byte [es:bx], 0EAh
	jne .not_jmpfar
	push word [es:bx + 1 + 2]
	push word [es:bx + 1]
	jmp @B

.not_jmpfar:
	mov si, msg.di_jmpfarindirect
internaldatarelocation
	cmp byte [es:bx], 0EBh
	jne .not_testhook_try_jmpfarindirect
	mov si, msg.di_testhook
internaldatarelocation
	mov al, byte [es:bx + 1]
	cbw
	add ax, 2
	add bx, ax
.not_testhook_try_jmpfarindirect:
	cmp bx, -6
	ja .not_testhook_or_jmpfarindirect
	cmp word [es:bx], 0FF2Eh
	jne .not_testhook_or_jmpfarindirect
	cmp byte [es:bx + 2], 2Eh
	jne .not_testhook_or_jmpfarindirect
	mov bx, word [es:bx + 3]
	cmp bx, -4
	ja .not_testhook_or_jmpfarindirect
	push word [es:bx + 2]
	push word [es:bx]
	jmp @B

.not_testhook_or_jmpfarindirect:
	test sp, sp			; NZ
.CY:
	stc
	retn


gateout.mcbname:
%if !_LOADER
	test ch, 1
	jz .ret
	mov dx, word [relocated(firstmcb)]
linkdatarelocation firstmcb
	cmp dx, -1
	je .ret
	push cx
	mov ax, word [intaddress]
internaldatarelocation
	mov cl, 4
	shr ax, cl
	add ax, word [intaddress + 2]	; => segment of handler
internaldatarelocation
	jc .hma
.loop:
%if _PM
	extcallcall setes2dx
%else
	mov es, dx
%endif
	mov cx, dx
	add cx, word [es:3]
	inc cx
	cmp ax, dx
	jb .next
	cmp ax, cx
	jae .next
	mov dx, word [es:1]
	mov si, msg.di_system_mcb
internaldatarelocation
	cmp dx, 50h
	jb .copy
	dec dx
%if _PM
	extcallcall setes2dx
%else
	mov es, dx
%endif
	 push es
	 pop ds
	 push ss
	 pop es
	mov al, 32
	stosb
	mov ax, di
	mov si, 8
	mov cx, si
	push di
	rep movsb
	mov al, 0
	stosb			; append zero-value byte
	pop di			; -> name in buffer
	 push ss
	 pop ds
@@:
	scasb			; is it zero ?
	jne @B			; no, continue -->
				; first dec makes it -> at the zero
@@:
	dec di
	cmp ax, di
	je .empty
	cmp byte [di - 1], 32
	je @B
	jmp .ret_cx

.empty:
	dec di
	mov si, msg.di_empty
internaldatarelocation
	jmp .copy

.hma:
	mov si, msg.di_hma
internaldatarelocation
	jmp .copy

.next:
	mov dx, cx
	cmp dx, word [relocated(firstumcb)]
linkdatarelocation firstumcb
				; is next one the first UMCB ?
	je .loop		; yes, ignore the "Z" (if any) -->
	cmp byte [es:0], "M"	; check current signature
	je .loop		; if "M" then loop to next -->

	mov si, word [relocated(firstumcb)]
linkdatarelocation firstumcb
	inc si
	jnz @F
	mov si, 0A000h
@@:
	cmp ax, si
	mov si, msg.di_system_upper
internaldatarelocation
	jae @F
	mov si, msg.di_system_low
internaldatarelocation
@@:
.copy:
	 push ss
	 pop es
	extcallcall copy_single_counted_string
.ret_cx:
	pop cx
.ret:
%endif	; !_LOADER
	retn
