
/*
 *  MISC.C
 *
 *  General Stuff... mostly in assembly.
 */

#include <local/typedefs.h>

typedef struct {
    NODE     ml_Node;
    uword    ml_NumEntries;
    MEMENTRY ml_ME[2];
} MYMEMLIST;

APTR
lGetTaskData(name, bytes)
char *name;
long bytes;
{
    extern EXECBASE *SysBase;
    extern void *FindName2();
    register LIST *list;
    register MEMLIST *ml;

    list = &SysBase->ThisTask->tc_MemEntry;
    if (ml = FindName2(list, name))
	return(ml->ml_ME[0].me_Un.meu_Addr);
    if (!list->lh_Head)
	NewList(list);
    {
	MYMEMLIST Ml;

	Ml.ml_NumEntries = 2;
	Ml.ml_ME[0].me_Un.meu_Reqs = MEMF_PUBLIC|MEMF_CLEAR;
	Ml.ml_ME[0].me_Length = bytes;
	Ml.ml_ME[1].me_Un.meu_Reqs = MEMF_PUBLIC;
	Ml.ml_ME[1].me_Length = strlen(name)+1;
	if (ml = AllocEntry(&Ml)) {
	    ml->ml_Node.ln_Name = (char *)ml->ml_ME[1].me_Un.meu_Addr;
	    strcpy(ml->ml_Node.ln_Name, name);
	    AddHead(list, ml);
	    return(ml->ml_ME[0].me_Un.meu_Addr);
	}
    }
    return(NULL);
}

lFreeTaskData(name)
char *name;
{
    extern EXECBASE *SysBase;
    extern void *FindName2();
    register MEMLIST *ml;

    if (ml = FindName2(&SysBase->ThisTask->tc_MemEntry, name)) {
	Remove(ml);
	FreeEntry(ml);
	return(1);
    }
    return(0);
}


#asm


		include "exec/types.i"
		include "exec/ports.i"
		include "exec/tasks.i"
		include "exec/execbase.i"
		include "exec/ables.i"
		include "exec/memory.i"

		;   NOTE:   LockAddr/UnLockAddr referenced elsewhere in
		;	    this library

		;   MISC.ASM

		public	_lWildCmp	; Wildcard compare
		public	_lWaitMsg	; Wait for a message to be replied
		public	_lCheckMsg	; Check if message has been returned
		public	_lCheckPort	; Check if message pending on port
		public	_lDoSyncMsg	; Put and Wait for a message
		public	_lLockAddr
		public	_lLockAddrB
		public	_lUnLockAddr
		public	_lUnLockAddrB
		public	_lFindName2

		public	_LVOWait
		public	_LVORemove
		public	_LVODisable
		public	_LVOEnable
		public	_LVOFindTask
		public	_LVOSignal
		public	_LVOForbid
		public	_LVOPermit
		public	_LVOPutMsg


_lDoSyncMsg:	movem.l A2/A3/A6,-(sp)              ; A0=port, A1=msg
		move.l	4,A6			    ; A6=execbase

		sub.w	#MP_SIZE,sp		    ; initialize reply port
		move.b	#NT_MSGPORT,LN_TYPE(sp)
		move.b	#PA_SIGNAL,MP_FLAGS(sp)
		move.b	#4,MP_SIGBIT(sp)            ; EXEC semaphore signal
		move.l	ThisTask(A6),MP_SIGTASK(sp)
		lea	MP_MSGLIST(sp),A2
		lea	MP_MSGLIST+4(sp),A3
		move.l	A3,(A2)                     ; &tail -> head
		move.l	#0,(A3)                     ; NULL  -> tail
		move.l	A2,8(A2)                    ; &head -> tailpred

		move.l	sp,MN_REPLYPORT(A1)
		move.l	A1,A2			    ; save message
		jsr	_LVOPutMsg(A6)              ; send the message
		move.l	A2,A0
		bsr	_lWaitMsg		    ; wait for reply

		add.w	#MP_SIZE,sp
		movem.l (sp)+,A2/A3/A6
		rts

_lCheckMsg:	moveq.l #0,D0
		cmp.b	#NT_MESSAGE,LN_TYPE(A0) ;NT_MESSAGE == not replied
		beq	.lcm1
		move.l	A0,D0
.lcm1		rts

_lCheckPort:	moveq.l #0,D0
		move.l	MP_MSGLIST+LH_HEAD(A0),A0
		tst.l	(A0)                    ;list empty?
		beq	.lcp1
		move.l	A0,D0			;no, return first element
.lcp1		rts

_lWaitMsg:					;A0 = message to wait for
		movem.l A2/A3/A6,-(sp)
		move.l	A0,A2			;A2 = message
		move.l	MN_REPLYPORT(A0),A3     ;A3 = replyport
		move.l	4,A6			;A6 = execbase
.wmloop 	cmp.b	#NT_MESSAGE,LN_TYPE(A2) ;while msg not replied
		bne	.wm1
		move.b	MP_SIGBIT(A3),D1        ;Wait on port signal
		moveq.l #0,D0
		bset.l	D1,D0
		jsr	_LVOWait(A6)
		bra	.wmloop
.wm1		jsr	_LVODisable(A6)         ;remove from port
		move.l	A2,A1			;A1 = message (A2)
		jsr	_LVORemove(A6)
		jsr	_LVOEnable(A6)
		move.l	A2,D0			;return message
		movem.l (sp)+,A2/A3/A6
		rts


		;WILDCMP(wild:D0, name:D1)
		;
		;   Handles * and ?
		;
		;result:  D0, 0 = no match, 1 = match
		;
		;auto:
		;   D2	bi
		;   A2	wildcard string
		;   A3	name	 string
		;   A4	back-array (of size MAXB * 2 * 4)


MAXB		EQU	8

_lWildCmp:	movem.l D2/A2-A4,-(sp)
		move.l	D0,A2
		move.l	D1,A3
		sub.l	#MAXB*2*8,sp
		move.l	sp,A4

		moveq.l #0,D2

.wcloop 	moveq.l #1,D0
		move.b	(A2),D1
		bne	.w1
		tst.b	(A3)
		beq	.wcdone

.w1		cmp.b	#'*',D1
		bne	.w10
		cmp.w	#MAXB,D2
		bne	.w2
		moveq.l #-1,D0		; error
		bra	.wcdone
.w2		move.w	D2,D0		; back[bi][0] = w  i.e. back+bi*8
		asl.w	#3,D0		; back[bi][1] = n
		move.l	A2,(A4,D0.w)
		move.l	A3,4(A4,D0.w)
		addq.w	#1,D2
		addq.l	#1,A2
		bra	.wcloop

.wgoback	subq.w	#1,D2
		bmi	.w5
		move.w	D2,D0
		asl.w	#3,D0
		move.l	4(A4,D0.w),A0
		tst.b	(A0)
		beq	.wgoback
.w5		tst.w	D2
		bmi	.wcret0
		move.w	D2,D0
		asl.w	#3,D0
		move.l	(A4,D0.w),A2
		addq.l	#1,A2
		add.l	#1,4(A4,D0.w)
		move.l	4(A4,D0.w),A3
		addq.l	#1,D2
		bra	.wcloop

.w10		cmp.b	#'?',D1
		bne	.w20
		tst.b	(A3)
		bne	.wcbreak
		tst.w	D2
		bne	.wgoback
		bra	.wcret0

.w20		move.b	(A3),D0
		cmp.b	#'A',D0
		blo	.w21
		cmp.b	#'Z',D0
		bhi	.w21
		or.b	#$20,D0
.w21		move.b	(A2),D1
		cmp.b	#'A',D1
		blo	.w22
		cmp.b	#'Z',D1
		bhi	.w22
		or.b	#$20,D1
.w22		cmp.b	D0,D1
		beq	.wcbreak
		tst.w	D2
		bne	.wgoback
		bra	.wcret0

.wcbreak	tst.b	(A2)+
		bne	.wcb1
		subq.l	#1,A2
.wcb1		tst.b	(A3)+
		bne	.wcb2
		subq.l	#1,A3
.wcb2		bra	.wcloop

.wcret0 	moveq.l #0,D0
.wcdone 	add.l	#MAXB*2*8,sp
		movem.l (sp)+,D2/A2-A4
		rts

		;   long var[2] = { 0, 0 };
		;
		;   These routines provide fast exclusive
		;   locks.  Up to 8 independant locks may be used for
		;   each 4 byte address.
		;
		;   LockAddr(&var[0]:A0)
		;   LockAddrB(bit:D0, &var[0]:A0)
		;   UnLockAddr(&var[0]:A0)
		;   UnLockAddrB(bit:D0, &var[0]:A0)


_lLockAddr:	moveq.l #0,D0			; bit 0
_lLockAddrB:	bset.b	D0,4(A0)                ; attempt to gain lock
		bne	.la10
		rts				; was clear, so got it
.la10		movem.l A2/A6,-(sp)             ; else failed,
		move.l	4,A6			; A6 = SYSBase
		FORBID
		bset.b	D0,4(A0)                ; try again
		beq	.la20			; got it!

		move.w	D0,-(sp)                ; bit#    12(sp)
		move.l	ThisTask(A6),-(sp)      ; task#    8(sp)
		move.l	A0,-(sp)                ; &var     4(sp)
		move.l	(A0),-(sp)              ; Next      (sp)
		move.l	sp,(A0)                 ; (put at head of list)
.la15		moveq.l #$10,D0 		; wait (semaphore signal)
		jsr	_LVOWait(A6)

		move.w	12(sp),D0               ; try for lock
		move.l	4(sp),A0
		bset.b	D0,4(A0)
		bne	.la15			; loop until get it

.la16		cmp.l	(A0),sp                 ; unlink, find our node!
		beq	.la18
		move.l	(A0),A0
		bra	.la16
.la18		move.l	(sp),(A0)
		add.w	#14,sp
.la20
		PERMIT
		movem.l (sp)+,A2/A6
		rts

_lUnLockAddr:	moveq.l #0,D0			; bit 0
_lUnLockAddrB:	bclr.b	D0,4(A0)                ; clear lock bit
		move.l	(A0),D1                 ; anybody waiting?
		beq	.ulrts			; no, rts

		movem.l D2/A2/A6,-(sp)          ; yes, wake 'm all up
		move.b	D0,D2			; D2 = bit#
		move.l	4,A6			; A6 = SYSBase
		FORBID

		move.l	(A0),D1                 ; get pointer again after FORBID
		beq	.ul20			; no, rts (close a window)

.ul10		move.l	D1,A2			; A2 = node
		cmp.b	13(A2),D2               ; waiting on our bit #?
		bne	.ul18			; no
		move.l	8(A2),A1                ; yes, signal the node
		moveq.l #$10,D0
		jsr	_LVOSignal(A6)          ; signal EVERYONE waiting
.ul18		move.l	(A2),D1                 ; next
		bne	.ul10

.ul20
		PERMIT
		movem.l (sp)+,D2/A2/A6
.ulrts		rts

		;   FindName2(list:D0, name:A0)
		;
		;   Search the node list as in FindName(), but also ignore
		;   NULL ln_name entries, which FindName() does not do.  This
		;   routine will also return NULL if given an uninitialized
		;   list header (completely zero'd).  Finally, it will not
		;   bother to do a string compare if the two pointers are
		;   the same.

_lFindName2:	movem.l A2/A3,-(sp)
		move.l	D0,A1
		tst.l	(A1)                        ; uninitialized list header
		beq	.fn2fail
.fn2loop	move.l	(A1),A1                     ; get first/next node
		tst.l	(A1)                        ; end of list?
		beq	.fn2fail
		move.l	LN_NAME(A1),D0              ; name
		beq	.fn2loop		    ; NULL, skip
		cmp.l	D0,A0			    ; pointers are the same!
		beq	.fn2succ		    ;  don't bother w/cmp.
		move.l	D0,A2
		move.l	A0,A3
.fn2l2		cmpm.b	(A2)+,(A3)+
		bne	.fn2loop
		tst.b	-1(A2)
		bne	.fn2l2
.fn2succ	move.l	A1,D0
		movem.l (sp)+,A2/A3
		rts
.fn2fail	moveq.l #0,D0
		movem.l (sp)+,A2/A3
		rts

#endasm

