;This file contains alternate versions of functions used in DOSLFN.
;Whilst not currently being used, they could still have a future.

;==============
;FASTOPEN CACHE
;==============
;A version of the fastopen cache using a double-linked list.
;TDirCache should start with "next" and "prev" words.

;	mov si,ofs (name|path)_cache
;head:	mov bx,[cachesi.next]
;tail:	mov bx,[cachesi.prev]

proc cache_unlink
;FU: Remove a cache entry from the queue.
;PE: SI=cache
;    BX=entry
;PA: SI=entry
;    DI=cache
	push	si
	 mov	si,[cachebx.next]
	 mov	di,[cachebx.prev]
	 mov	[cachesi.prev],di
	 mov	[cachedi.next],si
	pop	di
	mov	si,bx
	ret
endp

proc to_front
;FU: Move a cache entry to the front of the queue.
;PE: SI=cache
;    BX=entry
;VR: SI,DI
	call	cache_unlink
	xchg	[cachedi.next],si
	mov	[cachebx.next],si
	mov	di,[cachesi.prev]
	mov	[cachebx.prev],di
	mov	[cachesi.prev],bx
	ret
endp

proc to_back
;FU: Move a cache entry to the back of the queue.
;PE: SI=cache
;    BX=entry
;VR: SI,DI
	call	cache_unlink
	xchg	[cachedi.prev],si
	mov	[cachebx.prev],si
	mov	di,[cachesi.next]
	mov	[cachebx.next],di
	mov	[cachesi.next],bx
	ret
endp


name_cache	dw	?,?	;head (next) and tail (prev) pointers
path_cache	dw	?,?
cache_dirs	TDirCache CACHE_ENTRIES dup (<>)
cache_names	TDirCache CACHE_ENTRIES dup (<>)


proc cache_link
;Make all the cache entries point to each other.
;PE: SI=cache
;    BX=first entry
	push	si bx
	mov	[cachesi.next],bx
	mov	cx,CACHE_ENTRIES
@@link: lea	si,[bx+SIZE TDirCache]
	lea	di,[bx-SIZE TDirCache]
	mov	[cachebx.next],si
	mov	[cachebx.prev],di
	mov	bx,si
	loop	@@link
	add	di,SIZE TDirCache
	pop	bx si
	mov	[cachedi.next],si
	mov	[cachebx.prev],si
	mov	[cachesi.prev],di
	ret
endp

	mov	si,ofs path_cache
	mov	bx,ofs cache_dirs
	call	cache_link
	mov	si,ofs name_cache
	mov	bx,ofs cache_names
	call	cache_link


;=================
;Calc_Next_Cluster
;=================
; Cache the next cluster to save re-reading the sector.
; However, don't cache the last cluster, since it's not known when it can grow.
; Not complete, as it has to be reset on drive change and directory removal.
; Whilst it did save a bit, overall it's not really worth it (not with a
; disk cache, anyway).
; Not really a good implementation, since it could overwrite a recently used
; cluster. It might be feasible to modify the fastopen cache to allow this,
; as well. (Place the size of each entry at the head of the cache.)

CLUST_NUM equ 16
clust_buf dd CLUST_NUM*2 dup (0)
clust_ptr dw clust_buf

proc Calc_Next_Cluster pascal
;Berechnung fr Next_Sektor, liest die FAT ein
;PE: EAX=(vorhergehender) Sektor (gerechnet ab UsrSec)
;    CL=Shift
;PA: EAX=n„chster Sektor (erster Sektor des n„chsten Clusters, ab UsrSec)
;    CY=1: Ende der Cluster-Kette, EAX=Cluster-Nr.
;VR: alle, [Sektor]-Inhalt zerst”rt
	shr	eax,cl
	add	eax,2		;EAX ist nun CLUSTER

	mov	di,ofs clust_buf
	push	cx
	 mov	cx,CLUST_NUM
	 repne	scasd
	pop	cx
	jne	@@0
	mov	edx,[di-4+CLUST_NUM*4]
	cmp	eax,edx
	je	@@1
	xchg	eax,edx
	jmp	@@ce
@@0:	mov	di,[clust_ptr]
	cmp	di,ofs clust_buf+CLUST_NUM*4
	jne	@@00
	mov	di,ofs clust_buf
@@00:	mov	[di],eax
	mov	[di+CLUST_NUM*4],eax
	add	di,4
	mov	[clust_ptr],di

@@1:	push	di
	 call	Cluster2FAT
	pop	di
	jc	@@e
;...
@@3b:	cmc
	jc	@@e		;Ende der Clusterkette
	mov	[di-4+CLUST_NUM*4],eax
@@ce:	sub	eax,2
	jc	@@e		;momentaner Cluster ist frei (falsch!)
	shl	eax,cl
_nde_ret:
@@e:	ret
endp


;==========
;LocalAlloc
;==========
;Search for a free block that is the (almost) exact fit. If there are none,
;use first fit.

proc LocalAlloc pascal
;PE: AX=geforderte Speichermenge in Bytes
;PA: CY=1: kein Speicher mehr frei!
;    CY=0 und DI=Zeiger auf Speicherblock (fertig fr STOSx)
;VR: CX,DX,DI,AX(=tats„chliche Alloc-Gr”áe inkl. Gr”áen-WORD)
uses bx,si
	inc	ax		;an additional two bytes are required
	inc	ax		; to store the size
	mov	si,[LocalHeap]
	xor	cx,cx
@@l2:	mov	di,si
	mov	si,[si] 	;si=erster (oder weiterer) Freispeicher
	or	si,si		;Ende erreicht?
	jz	@@r
	mov	dx,[si+2]
	sub	dx,ax		;Block hat genug Platz?
	jc	@@l2		;nein, n„chsten Freispeicher suchen
	je	@@ganz
	cmp	dx,4
	jb	@@fit
	inc	cx
	loop	@@l2
	mov	bx,di		;Kandidat gefunden: BX=Vorheriger Freispeicher
	mov	cx,si		;Kandidat gefunden: CX=Jetziger Freispeicher
	jmp	@@l2
@@r:
	jcxz	@@nomem
	mov	si,cx
	mov	cx,[si+2]
	sub	cx,ax
	mov	di,si
	add	di,ax		;auf neue Position
	mov	[bx],di
	mov	[di+2],cx	;neue (kleinere) Gr”áe
	db	0b9h
@@fit:	add	ax,dx		;increase allocation to fit free block
@@ganz: movsw			;Next-Pointer
	lea	di,[si-2]
@@1:	stosw			;Gr”áe allozierter Block eintragen
@@e:	ret
@@nomem:mov	[LastError],4	;"not enough memory"
	stc
	jmp	@@e
endp

