
		;   EXTENDED LIST/NODE HANDLING
		;
		;   (C)CopyRight May 1988, Matthew Dillon, All Rights Reserved
		;


		;NOTE:	These routines accomodate structures where the
		;	NODE used to traverse the list is not necessarily
		;	at the beginning of the structure.  This, 'sptr'
		;	refers to the structure pointer (not the node
		;	pointer, unless the node is at the beginning), and
		;	'off' offset refers to the offset into the structure
		;	where the NODE resides.

		public	_lGetHead	     ; node = GetHead(list)
		public	_lGetTail	     ; node = GetTail(list)
		public	_lGetSucc	     ; node = GetSucc(node)
		public	_lGetPred	     ; node = GetPred(node)
		public	_lGetHeadOff	     ; sptr = GetHeadOff(list, off)
		public	_lGetTailOff	     ; sptr = GetTailOff(list, off)
		public	_lGetSuccOff	     ; sptr = GetSuccOff(sptr, off)
		public	_lGetPredOff	     ; sptr = GetPredOff(sptr, off)
		public	_lEnqueueLong	     ; (void)EnqueueLong(list, start, sptr, valoff)
		public	_lEnqueueOffLong     ; (void)EnqueueOffLong(list, start, sptr, off, valoff)
		public	_lSearchFwdNode      ; ret  = SearchFwdNode(sptr, func, arg)      ->  func(somesptr,arg)
		public	_lSearchRvsNode      ; ret  = SearchRvsNode(sptr, func, arg)             (ditto)
		public	_lSearchFwdList      ; ret  = SearchFwdList(list, func, arg)             (ditto)
		public	_lSearchRvsList      ; ret  = SearchRvsList(list, func, arg)             (ditto)
		public	_lSearchFwdNodeOff   ; ret  = SearchFwdNode(sptr, func, off, arg) ->  func(somesptr,arg)
		public	_lSearchRvsNodeOff   ; ret  = SearchRvsNode(sptr, func, off, arg)        (ditto)
		public	_lSearchFwdListOff   ; ret  = SearchFwdList(list, func, off, arg)        (ditto)
		public	_lSearchRvsListOff   ; ret  = SearchRvsList(list, func, off, arg)        (ditto)

		;   GETHEAD(list:A0)
		;   GETSUCC(node:A0)
_lGetSucc:
_lGetHead:	move.l	(A0),A0
		tst.l	(A0)
		beq	.gh0
		move.l	A0,D0
		rts

		;   GETTAIL(list:A0)

_lGetTail:	move.l	8(A0),A0
		tst.l	4(A0)
		beq	.gh0
		move.l	A0,D0
		rts

		;   GETPRED(node:A0)

_lGetPred:	move.l	4(A0),A0
		tst.l	4(A0)
		beq	.gh0
		move.l	A0,D0
		rts

.gh0		moveq.l #0,D0
		rts

		;   GETHEADOFF(list:D0, offset:D1)

_lGetHeadOff:	move.l	D0,A0
		move.l	(A0),A0
		tst.l	(A0)
		beq	.gh0
		sub.l	D1,A0
		move.l	A0,D0
		rts

		;   GETTAILOFF(list:D0, offset:D1)

_lGetTailOff:	move.l	D0,A0
		move.l	8(A0),A0
		tst.l	4(A0)
		beq	.gh0
		sub.l	D1,A0
		move.l	A0,D0
		rts

		;   SPTR is a structure pointer, where the node is offset
		;   OFFSET from the base of the structure.

		;   GETSUCCOFF(sptr:D0, offset:D1)

_lGetSuccOff:	move.l	D0,A0
		move.l	(A0,D1.L),A0
		tst.l	(A0)
		beq	.gh0
		suba.l	D1,A0
		move.l	A0,D0
		rts

		;   GETPREDOFF(sptr:D0, offset:D1)

_lGetPredOff:	move.l	D0,A0
		move.l	4(A0,D1.L),A0
		tst.l	4(A0)
		beq	.gh0
		suba.l	D1,A0
		move.l	A0,D0
		rts

		;   ENQUEUELONG(list:D0, start:D1, sptr:D2, valoff:D4)
		;   ENQUEUEOFFLONG(list:D0, start:D1, sptr:D2, off:D3, valoff:D4)
		;
		;   list:	list to queue the object in
		;   start:	sptr to start search at (NULL=beginning of list)
		;   sptr:	pointer to the structure to queue, where
		;   off:	offset into the structure where the embedded Node is
		;   valoff:	offset into structure where the longword holding
		;		the sorting priority of the object is.
		;
		;   The list is already assumed to be sorted.  The search
		;   progresses either forward or reverse along the list until
		;   the proper place is found, then the object is inserted into
		;   the list.  The object is placed AFTER any objects of equal
		;   priority (whether the list is searched forward or backwards).

_lEnqueueLong:
		movem.l D3/A2/A3,-(sp)
		moveq.l #0,D3
		bra	.eol1
_lEnqueueOffLong:
		movem.l D3/A2/A3,-(sp)
.eol1		move.l	D2,A3	    ; A3 = structure to add
		move.l	D1,A2	    ; A2 = roving structure in search
		tst.l	D1
		bne	.eol2
		move.l	D0,A2	    ; use list head instead
		move.l	(A2),A1
		tst.l	(A1)
		beq	.eol100     ; add structure to empty list
		move.l	A1,A2
		sub.l	D3,A2	    ; retrieve structure pointer

		;   D0 = D4(A3)
		;   D3 = offset into A2/A3 of node
		;   D4 = offset into A2/A3 of longword value
		;   A2 = roving structure ptr
		;   A3 = structure to add
		;
		;   Sequence:	if D4(A3) > D4(A2), forward search
		;		if D4(A3) < D4(A2), reverse search

.eol2		move.l	(A3,D4.L),D0    ; Search forwards or backwards?
		cmp.l	(A2,D4.L),D0
		blt	.eol50
.eol10		move.l	(A2,D3.L),A2    ; SEARCH FORWARDS (A2 = next node)
		tst.l	(A2)            ; reached list tail
		beq	.eol30		; Add to tail
		sub.l	D3,A2		; A2 = structure
		cmp.l	(A2,D4.L),D0
		bge	.eol10		; loop while value > roving_value
		add.l	D3,A2		; ADDBEFORE current node, A2 = listnode
		add.l	D3,A3		; A3 = node to add

		move.l	A2,(A3)         ; INSERT BEFORE (listnode:A2, node:A3)
		move.l	4(A2),A0        ; A0 is node before A2  (seq A0-A3-A2)
		move.l	A0,4(A3)
		move.l	A3,4(A2)
		move.l	A3,(A0)
		bra	.eolend
					; (A2 points to lh_Tail here)
.eol30		move.l	4(A2),A2        ; ADDTOEND, A2 = tail element
		bra	.eol100
.eol50		move.l	4(A2,D3.L),A2   ;SEARCH BACKWARDS (A2 = prev. node)
		tst.l	4(A2)           ;reached list head .. AddHead()
		beq	.eol100
		sub.l	D3,A2		;A2 = structure pointer
		cmp.l	(A2,D4.L),D0    ;loop while value < roving_value
		blt	.eol50
		add.l	D3,A2		;add after NODE A2
.eol100 	add.l	D3,A3		;INSERT AFTER(list/node:A2, structure:A3)
		move.l	(A2),A0
		move.l	A0,(A3)
		move.l	4(A0),4(A3)
		move.l	A3,(A2)
		move.l	A3,4(A0)
.eolend 	movem.l (sp)+,D3/A2/A3
		rts

		;   SEARCHFWDLIST[OFF](list:D0, func:D1, [offset:A0,] funcarg:A1)
		;   SEARCHRVSLIST[OFF](list:D0, func:D1, [offset:A0,] funcarg:A1)
		;
		;	Get head/tail of list then call Search???Node

_lSearchFwdList:
		sub.l	A0,A0
_lSearchFwdListOff:
		movem.l D2-D5/A2/A3/A6,-(sp)
		move.l	D0,A2
		move.l	(A2),A2             ; get head of list
		tst.l	(A2)                ; empty list?
		bne	SFN
		bra	.sfn0

_lSearchRvsList:
		sub.l	A0,A0
_lSearchRvsListOff:
		movem.l D2-D5/A2/A3/A6,-(sp)
		move.l	D0,A2
		move.l	8(A2),A2            ; get tail of list
		tst.l	4(A2)               ; empty list?
		bne	SRN
		bra	.sfr0

		;   For compatibility with various C compilers, neither
		;   A4 or A5 is touched.  D2,D3, and A6 are also assumed
		;   to be destroyed by the function.
		;
		;   The search ends when the function returns a non-NULL
		;   value or the list is exhausted (NULL is returned)
		;
		;   SEARCHFWDNODE(sptr:D0, func:D1, offset:A0, funcarg:A1)


_lSearchFwdNode:
		sub.l	A0,A0
_lSearchFwdNodeOff:
		movem.l D2-D5/A2/A3/A6,-(sp)
		move.l	D0,A2
SFN:		move.l	D1,A3
		move.l	A0,D4
		move.l	A1,D5
		move.l	A2,D0		    ; test for initial NULL
		beq	.sfndone
		adda.l	D4,A2
.sfnloop	suba.l	D4,A2
		move.l	D5,-(sp)            ; call function(sptr, funcarg)
		move.l	A2,-(sp)
		jsr	(A3)
		addq.l	#8,sp
		tst.l	D0		    ; non-zero ret. value
		bne	.sfndone
		adda.l	D4,A2		    ; GetSuccOff()
		move.l	(A2),A2
		tst.l	(A2)
		bne	.sfnloop
.sfn0		moveq.l #0,D0
.sfndone	movem.l (sp)+,D2-D5/A2/A3/A6
		rts

		;   SEARCHRVSNODE(node:D0, func:D1, offset:A0, funcarg:A1)

_lSearchRvsNode:
		sub.l	A0,A0

_lSearchRvsNodeOff:
		movem.l D2-D5/A2/A3/A6,-(sp)
		move.l	D0,A2
SRN:		move.l	D1,A3
		move.l	A0,D4
		move.l	A1,D5
		move.l	A2,D0		    ; test for initial NULL
		beq	.sfrdone
		adda.l	D4,A2
.sfrloop	suba.l	D4,A2
		move.l	D5,-(sp)            ; call function(sptr, funcarg)
		move.l	A2,-(sp)            ; args also in A2 and D5
		jsr	(A3)
		addq.l	#8,sp
		tst.l	D0		    ; non-zero ret. value
		bne	.sfrdone
		adda.l	D4,A2		    ; GetPredOff()
		move.l	4(A2),A2
		tst.l	4(A2)
		bne	.sfrloop
.sfr0		moveq.l #0,D0
.sfrdone	movem.l (sp)+,D2-D5/A2/A3/A6
		rts

