[comp.sources.amiga] v02i017: dres - an object-oriented resource library, Part02/03

page@swan.ulowell.edu (Bob Page) (10/25/88)

Submitted-by: dillon@cory.berkeley.edu (Matt Dillon)
Posting-number: Volume 2, Issue 17
Archive-name: util/dres.2

# This is a shell archive.  Remove anything before this line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have default permissions).
# This archive contains the following files:
#	notinlib/graph.c
#	notinlib/ioctl.c
#	notinlib/muldiv.asm
#	src/qint.asm
#	src/ires.h
#	src/lists.asm
#	src/timedate.c
#	src/oldfile.c
#	src/oldfile.h
#	src/res.c
#
if `test ! -d notinlib`
then
  mkdir notinlib
  echo "mkdir notinlib"
fi
if `test ! -s notinlib/graph.c`
then
echo "writing notinlib/graph.c"
cat > notinlib/graph.c << '\Rogue\Monster\'


/*
 *  GRAPH.C
 */

#define GRAPH	struct _GRAPH
#define GNODE	struct _GNODE
#define GCTRL	struct _GCTRL

/*
 *  Flags field:    The upper 4 bits are copied to the lower 4 bits after
 *		    the flags are processed, allowing for 'temporary'
 *		    conditions.
 *
 *  FL_SKIP	    Propogate a skip condition.  As soon as the next node
 *		    is ready to begin processing, cause it not to run
 *		    its function and propogate the FL_SKIP to all of its
 *		    children, and all of their children, etc...
 *
 *  FL_SRC	    Infinite source, this arc is always ready with the
 *		    given value.
 */

GLINK {
    MINNODE FNode;	/*  link from, list based at node	*/
    MINNODE TNode;	/*  link to, list based at node 	*/
    GNODE   *FGNode;	/*  from this node			*/
    GNODE   *TGNode;	/*  to this node			*/
    long    FromId;	/*  Identify value slot for source	*/
    long    ToId;	/*  Identify value slot for destination */
    long    Value;	/*  value to pass to 'to' node          */
    ubyte   Ready;	/*  value pending, else no value pending*/
    ubyte   Flags;	/*  FL_SKIP,FL_NULL,FL_SRC		*/
    ubyte   XFlags;	/*  XL_READ				*/
    ubyte   filler;
};

GNODE {
    MINNODE GNode;	/*  master list node			*/
    GRAPH   *Graph;	/*  owning graph			*/
    APTR    Func;	/*  Function				*/
    long    Arg;	/*  Argument				*/
    short   WaitCnt;	/*  # parents who are not ready 	*/
    MINLIST ChildList;	/*  list of children			*/
    MINLIST ParentList; /*  list of parents			*/
    MINLIST WakeUpList; /*  WakeUp tasks waiting for an ARC to clear	*/
};

GRAPH {
    MINLIST GNodes;	/*  list of all graphs in node	*/
    long    A45[2];	/*  global base registers	*/
    long    UsrLen;
};

GRAPH *
AllocGraph(usrdatalen)
{
    GRAPH *graph = AllocMem(sizeof(GRAPH), MEMF_PUBLIC|MEMF_CLEAR);
    NewList(&graph->GNodes);
    graph->a45[0] = A4;
    graph->a45[1] = A5;
    graph->UsrLen = usrdatalen;
}

GNODE *
AllocGraphNode(graph, func, arg, usrdata/NULL)
GRAPH *graph;
long arg;
{
    GNODE *gnode = AllocMem(sizeof(GNODE), MEMF_PUBLIC|MEMF_CLEAR);
    AddTail(&graph->GNodes, &gnode->GNode);
    gnode->Graph = graph;
    gnode->Func  = func;
    gnode->Arg	 = arg;
    NewList(&gnode->ChildList);
    NewList(&gnode->ParentList);
    NewList(&gnode->WakeUpList);
}

/*
 *  Remove all arcs and free a graph node
 */

FreeGraphNode(gnode)
GNODE *gnode;
{
    Forbid();
    Remove(gnode);
    while (glink = GetHead(&gnode->ChildList))
	RemGraphArc(gnode, glink->FGTNode);
    while (glink = GetHeadOff(&gnode->ParentList, 8))
	RemGraphArc(glink->FGFNode, gnode);
    Permit();
    FreeMem(gnode, sizeof(GNODE));
};

FreeGraph(graph)
GRAPH *graph;
{
    Forbid();
    while (gnode = GetHead(&graph->GNodes))
	FreeGraphNode(gnode);
    Permit();
    FreeMem(graph, sizeof(GRAPH));
}

/*
 *  Set the user data for a given node.  The data is copied into an
 *  equivalent buffer for the node.
 */

SetUserData(gnode, usrdata/NULL)
GNODE *gnode;
{
}

/*
 *  Add a directed arc to the graph.  Set the arc to 'not ready' and
 *  increment the child node's WaitCnt
 */

AddGraphArc(from, to)
GNODE *from, *to;
{
    GLINK *glink = AllocMem(sizeof(GLINK), MEMF_PUBLIC);

    Forbid();
    AddTail(&from->ChildList, &glink->FNode);
    AddTail(&to->ParentList, &glink->TNode);
    glink->FGNode = from;
    glink->FTNode = to;
    ++to->WaitCnt;
    Permit();
}

chklink(glink, gnode)
GLINK *glink;
GNODE *gnode;
{
    if (glink->TGNode == gnode)
	return(glink);
    return(NULL);
}

RemGraphArc(from, to)
GNODE *from, *to;
{
    GLINK *glink;

    Forbid();
    if (glink = SearchFwdNode(GetHead(&from->ChildList), chklink, 0, to)) {
	Remove(&glink->FNode);
	Remove(&glink->TNode);
	if (!glink->Ready) {
	    if (--to->WaitCnt == 0 && GetHeadOff(&to->ParentList, 8))
		GHandler(to);
	}
    }
    Permit();
}

SetGNodeFunc(gnode, func)
GNODE *gnode;
APTR func;
{
    gnode->Func = func;
}

SetGNodeArg(gnode, arg)
GNODE *gnode;
{
    gnode->Arg = arg;
}

APTR
GetGNodeFunc(gnode)
GNODE *gnode;
{
    return(gnode->Func);
}

long
GetGNodeArg(gnode)
GNODE *gnode;
{
    return(gnode->Arg);
}

/*
 *  This function may ONLY be called by a node function, and retrieves
 *  the value from one of the parent arcs (arcs comming in).  When the
 *  node function returns, any remaining unread parent arc's values will
 *  be discarded.
 */

long
GetArcValue(ToId)
{

}

/*
 *  This function may ONLY be called by a node function, and sets the
 *  result value to one of its child arcs (arcs going out).  When the
 *  node function returns, any remaining unset child arc's values will
 *  be SKIPd.
 *
 *  NOTE!  This function will block on child nodes which have yet to
 *  read the previous value with GetArcValue() or are still running.
 */

SetArcValue(gnode, FromId, flags)
GNODE *gnode;
{
}

/*
 *  This function may be called by anybody, and forces a value into an
 *  arc.  This function is usually used to 'prime' a graph.
 */

PrimeArc(from, to, value)
GNODE *from, *to;
{
}

/*
 *  GetGraph()
 *
 *  Load the two buffers with entries corrosponding to the graph.  arcen
 *  and nodeen initially contain the number of ARC and NODE structure
 *  entries that have been allocated.  These variables will hold the
 *  actual number of ARC and NODE entries in the graph regardless of
 *  whether the operation succeeds.
 *
 *  0 is returned if the operation does not succeed, 1 if it does.
 *  The size of the node structure depends on the size of attached
 *  user information.
 *
 *  ARC structure:  two words / entry, representing an arc (from, to),
 *		    where each word is an index (by entry #) into nodebuf.
 *		    i.e. 0, 1, 2 ... even if usrdatalen is 0.
 *
 *  NODE structure: any user data that has been applied to the node, as
 *		    specified by AllocGraphNode().
 */

GetArcs(graph, arcbuf, &arcen, nodebuf, &nodeen)
GRAPH *graph;
{


}

\Rogue\Monster\
else
  echo "will not over write notinlib/graph.c"
fi
if [ `wc -c notinlib/graph.c | awk '{printf $1}'` -ne 5849 ]
then
echo `wc -c notinlib/graph.c | awk '{print "Got " $1 ", Expected " 5849}'`
fi
if `test ! -s notinlib/ioctl.c`
then
echo "writing notinlib/ioctl.c"
cat > notinlib/ioctl.c << '\Rogue\Monster\'

/*
 *FUNC= IoCreate	D0/D1/A0
 *FUNC= IoDelete	D0
 *FUNC= IoOpen		D0/D1/A0
 *FUNC= IoClose 	A0
 ;FUNC= IoCtl		D0/D1/D2/A0
 *FUNC= NULL		-
 *FUNC= NULL		-
 *FUNC= NULL		-
 *FUNC= NULL		-
 *FUNC= NULL		-
 *FUNC= NULL		-
 *FUNC= NULL		-
 */

#include <local/typedefs.h>
#include <local/ioctl.h>

typedef long	(*FPTR)();

#define HAN struct _HAN
#define MHAN struct _MHAN

#define HANSIZE     8

HAN {
    long    Reserved;
    MHAN    *MHan;		/*  Related MHandle	    */
		    /*	USER STRUCTURE	*/
};

MHAN {
    NODE    Node;
    long    (*IoCtlFunc)();     /*  Control Function / NULL */
    uword   Refs;		/*  Total References	    */
    uword   HanSize;		/*  Size of a HANdle	    */
};

#asm

MHA_IOCTLFUNC	equ	14

#endasm

static MLIST  MList = { (MNODE *)&MList.mlh_Tail, NULL, (MNODE *)&MList.mlh_Head };
static long   Lock[2] = { 0,0 };

lIoCreate(name, func, hansize)
char *name;
long (*func)();
{
    register MHAN *mh;
    long res = -1;

    hansize += HANSIZE;
    LockAddr(Lock);
    for (mh = GetHead(&MList); mh; mh = GetSucc(mh)) {
	if (strcmp(name, mh->Node.ln_Name) == 0)
	    goto fail;
    }
    if ((mh = AllocMem(sizeof(MHAN), MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	goto fail;
    if ((mh->Node.ln_Name = AllocMem(strlen(name)+1, MEMF_PUBLIC)) == NULL) {
	FreeMem(mh, sizeof(MHAN));
	goto fail;
    }
    strcpy(mh->Node.ln_Name, name);
    mh->IoCtlFunc = func;
    mh->HanSize = HANSIZE + hansize;
    AddHead(&MList, mh);
    fioctl(func, _IOC_CREATE, NULL, 0);
    res = 0;
fail:
    UnLockAddr(Lock);
    return(res);
}

/*
 *  Delete an IO device.  The device's name is removed from the nameslist
 *  and any further non-internal IoCtl's on active connections will return
 *  -1.
 */

lIoDelete(name)
char *name;
{
    register MHAN *mh;
    long (*func)();

    LockAddr(Lock);
    for (mh = GetHead(&MList); mh; mh = GetSucc(mh)) {
	if (mh->Node.ln_Name && strcmp(name, mh->Node.ln_Name) == 0)
	    break;
    }
    if (!mh) {
	UnLockAddr(mh);
	return(-1);
    }

    /*	Prevent further opens & flag for removal	*/

    FreeMem(mh->Node.ln_Name, strlen(mh->Node.ln_Name)+1);
    mh->Node.ln_Name = NULL;
    func = mh->IoCtlFunc;
    mh->IoCtlFunc = NULL;

    /*	Call _IOC_DELETE if no more references & delete */

    UnLockAddr(Lock);
    fioctl(func, _IOC_DELETE, NULL, 0);

    if (mh->Refs == 0) {
	Remove(mh);
	FreeMem(mh, sizeof(MHAN));
	return(0);
    }
    return(1);
}

HAN *
lIoOpen(name, arg1, arg2)
char *name;
ulong arg1, arg2;
{
    register MHAN *mh;
    register HAN *han;

    LockAddr(Lock);
    for (mh = GetHead(&MList); mh; mh = GetSucc(mh)) {
	if (mh->Node.ln_Name && strcmp(name, mh->Node.ln_Name) == 0)
	    break;
    }
    if (!mh) {
	UnLockAddr(Lock);
	return(NULL);
    }
    if (!(han = AllocMem(mh->HanSize, MEMF_CLEAR|MEMF_PUBLIC))) {
	UnLockAddr(Lock);
	return(NULL);
    }
    ++mh->Refs;
    UnLockAddr(Lock);
    han->MHan = mh;
    if (IoCtl(han, _IOC_OPEN, arg1, arg2) == -1) {
	FreeMem(han, mh->HanSize);
	LockAddr(Lock);
	if (--mh->Refs == 0 && mh->Node.ln_Name == NULL) {
	    Remove(mh);
	    FreeMem(mh, sizeof(MHAN));
	}
	UnLockAddr(Lock);
	return(NULL);
    }
    UnLockAddr(Lock);
    return(han);
}

lIoClose(han)
register HAN *han;
{
    register MHAN *mh = han->MHan;
    long hansize = mh->HanSize;

    IoCtl(han, _IOC_CLOSE, NULL, NULL);        /*  finishup    */
    LockAddr(Lock);
    if (--mh->Refs == 0 && mh->Node.ln_Name == NULL) {
	Remove(mh);
	FreeMem(mh, sizeof(MHAN));
    }
    UnLockAddr(Lock);
    FreeMem(han, hansize);
    return(0);
}

#asm
	    ;	IoCtl(han:D0, cmd:D1, buf:D2, bytes:A0)
	    ;
	    ;	(1) Call IoctlFunc if it exists,    (*func)(han,cmd,buf,bytes)
	    ;	(2) else call internal function or if IoctlFunc returns -1

	    public  _lIoCtl
	    public  _AutoFunc

_lIoCtl:
	    addq.l  #8,D0			    ; skip handle header
	    movem.l D2/D3/A4/A5/A6,-(sp)            ; C compatibility
	    movem.l D0/D1/D2/A0,-(sp)               ; function call params
	    move.l  D0,A0
	    move.l  -4(A0),A0                       ; A0 = master handle
	    move.l  MHA_IOCTLFUNC(A0),A1            ; A1 = function to call
	    move.l  A1,D0			    ; NULL function
	    beq     .iocn
	    jsr     (A1)
	    cmp.l   #-1,D0			    ; result -1 ?
	    bne     .iocr
.iocn	    lea     _AutoFunc,A1		    ; error, try internal func
	    jsr     (A1)
.iocr	    lea     16(sp),sp
	    movem.l (sp)+,D2/D3/A4/A5/A6
	    rts

	    ;	fioctl(func, cmd, buf1, buf2) .. called as: (NULL,cmd,buf1,buf2)
	    ;	(i.e. handleless)

_fioctl:    movem.l 4(sp),D0/D1/A0/A1       ; get stack args
	    movem.l D2/D3/A4/A5/A6,-(sp)    ; save regs that might get trashed
	    move.l  D0,A6		    ; function to call
	    moveq.l #0,D0		    ; (usually is the handle)
	    movem.l D0/D1/A0/A1,-(sp)       ; push args
	    jsr     (A6)                    ; make call
	    lea     16(sp),sp               ; pop args
	    movem.l (sp)+,D2/D3/A4/A5/A6    ; restore regs
	    rts

#endasm

AutoFunc(han, cmd, arg1, arg2)
register HAN *han;
ulong cmd, arg1, arg2;
{
    han = (HAN *)((char *)han - 8);

    switch(cmd) {
    case IOC_GETFUNC:
	return ((long)han->MHan->IoCtlFunc);
    case IOC_SETFUNC:
	han->MHan->IoCtlFunc = (FPTR)arg1;
	return(0);
    case IOC_DEVCLAS:
	return(0);
    case IOC_DUP:
	{
	    register long hansize = han->MHan->HanSize;
	    register HAN *new = AllocMem(hansize, MEMF_PUBLIC);
	    register long res;
	    if (new) {
		BMov(han, new, hansize);
		res = IoCtl(new, _IOC_DUP, arg1, arg2);
		if (res != -1)
		    return((long)new);
		FreeMem(new, hansize);
	    }
	}
	break;
    }
    return(-1);
}

\Rogue\Monster\
else
  echo "will not over write notinlib/ioctl.c"
fi
if [ `wc -c notinlib/ioctl.c | awk '{printf $1}'` -ne 5581 ]
then
echo `wc -c notinlib/ioctl.c | awk '{print "Got " $1 ", Expected " 5581}'`
fi
if `test ! -s notinlib/muldiv.asm`
then
echo "writing notinlib/muldiv.asm"
cat > notinlib/muldiv.asm << '\Rogue\Monster\'

;FUNC=	MulDiv	    D0/D1/D2
;FUNC=	UMulDiv     D0/D1/D2
;FUNC=	MulShift    D0/D1/D2
;FUNC=	UMulShift   D0/D1/D2

	    ;	MulDiv	(a ,b ,c)   32x32->64 64/32->32     (signed)
	    ;	MulShift(a ,b ,n)   32x32->64 64>>n->32     (signed)
	    ;		 D0,D1,D2
	    ;
	    ;	32x32->64 64/32->32
	    ;	32x32->64 64>>n->32
	    ;
	    ;	note:	n is a word

	    public  _MulDiv
	    public  _UMulDiv
	    public  _MulShift
	    public  _UMulShift

	    ;	Various connotations specifying which arguments are
	    ;	unsigned (you gain a bit when using unsigned arguments)

REGS	    eqr     D2-D7

_UMulDiv    movem.l REGS,-(sp)
	    clr.w   D7
	    bra     .md10
_MulDiv     movem.l REGS,-(sp)
	    clr.w   D7
	    tst.l   D0
	    bpl     .md2
	    neg.l   D0
	    tst.l   D1	    ; neg
	    bpl     .md1    ; neg
	    neg.l   D1
	    tst.l   D2	    ; neg neg
	    bpl     .md10   ; neg neg
	    neg.l   D2
	    bra     .md9    ; neg neg neg
.md1	    tst.l   D2	    ; neg
	    bpl     .md9    ; neg
	    neg.l   D2
	    bra     .md10   ; neg neg
.md2	    tst.l   D1
	    bpl     .md3
	    neg.l   D1
	    tst.l   D2	    ; neg
	    bpl     .md9    ; neg
	    neg.l   D2
	    bra     .md10   ; neg neg
.md3	    tst.l   D2
	    bpl     .md10
	    neg.l   D2
	    bra     .md9

_UMulShift  movem.l REGS,-(sp)
	    clr.w   D7
	    bra     .md6
_MulShift   movem.l REGS,-(sp)
	    clr.w   D7
	    tst.l   D0
	    bpl     .md4
	    neg.l   D0
	    tst.l   D1
	    bpl     .md5
	    neg.l   D0
	    bra     .md6
.md4	    tst.l   D1
	    bpl     .md6
	    neg.l   D1
.md5	    addq.w  #1,D7

.md6	    swap    D0
	    swap    D1
	    tst.w   D0
	    beq     .md601
	    bsr     .md0huge
	    beq     .md602a
	    bra     .md603
.md601	    tst.w   D1
	    beq     .md602
	    bsr     .md1huge
	    beq     .md602a
	    bra     .md603
.md602	    swap    D0
	    swap    D1
	    mulu    D1,D0
.md602a     lsr.l   D2,D0
	    bra     .mddone
.md603	    subq.w  #1,D2
	    bmi     .mddone
.md604	    lsr.l   #1,D3
	    roxr.l  #1,D0
	    dbf     D2,.md604
	    bra     .mddone


.md10	    swap    D0
	    swap    D1
	    tst.w   D0
	    beq     .md101
	    bsr     .md0huge
	    beq     .mdsdiv
	    bsr     div64
	    bra     .mddone
.md101	    tst.w   D1
	    beq     .md105
	    bsr     .md1huge
	    beq     .mdsdiv
	    bsr     div64
	    bra     .mddone
.md105	    swap    D0		; both word sized
	    swap    D1
	    mulu    D1,D0	; D1.WxD0.W -> D0.L
.mdsdiv     move.l  D2,D1
	    jsr     .divu#

	    ;
	    ;

.md9	    addq.w  #1,D7

	    ;	All elements now unsigned, D7.W determines whether to
	    ;	negate at end.

.mddone     btst.l  #0,D7
	    beq     .mddone2
	    neg.l   D0
.mddone2    movem.l (sp)+,REGS
	    rts


	    ;	NOTE:	entered with register halves reversed
	    ;
	    ;	D2 not effected
	    ;	Test D3 on return

.md0huge    tst.w   D1
	    beq     .md1hugex	; D0.L, D1.W
				; D0.L, D1.L	(long x long)
	    move.w  D0,D4	; save ah
	    move.w  D0,D3	; ah bh
	    mulu.w  D1,D3
	    swap    D0		; al bh
	    move.w  D0,D5
	    mulu.w  D1,D5
	    swap    D1
	    mulu.w  D1,D0	; al bl
	    mulu.w  D4,D1	; ah bl
	    add.l   D1,D5	; combine blah and bhal
	    bcc     .mud1
	    add.l   #$10000,D3
.mud1	    swap    D0		; LSB MSB
	    add.w   D5,D0
	    swap    D0
	    clr.w   D5
	    swap    D5
	    addx.l  D5,D3	;64 bit mul result: D3|D0
	    rts 		;Test D3

	    ; D2 not effected

.md1huge    exg     D0,D1
.md1hugex
	    ; D0.L, D1.W	al ah
	    ;			   bl

	    move.w  D0,D3
	    mulu.w  D1,D3	; D3 = bl x ah
	    swap    D0
	    mulu.w  D1,D0	; D0 = bl x al
	    swap    D0		; add lsb byte of D3 to msb byte of D0
	    add.w   D3,D0
	    swap    D0
	    clr.w   D3		; doesn't effect X
	    swap    D3		; msb of D3 actually lsb of second longword
	    moveq.l #0,D1
	    addx    D1,D3	; possible x(carry) from previous addition
				; 64 bit mul result: D3|D0
				; Test D3
	    rts

	    ;	DIV64
	    ;
	    ;	64/32->32   D3|D0 / D2 -> D0

div64:
	    move.l  #0,A0	;Divide!    D1 into D3|D0, D2 = cntr, A0 = rslt
	    move.w  #31,D2	;(no initial compare).  31 + 1 iterations
.mud10	    adda.l  A0,A0	;shift result left
	    asl.l   #1,D0	;Shift left
	    roxl.l  #1,D3
	    cmp.l   D1,D3
	    blo     .mud11	;if D3	< D1, skip
	    sub.l   D1,D3	;   D3 >= D1
	    addq.l  #1,A0	;result = result | 1
.mud11	    dbf     D2,.mud10

	    ;	If remainder (D3) larger than 1/2 C (D1 >> 1), then
	    ;	round up result.

	    lsr.l   #1,D1
	    cmp.l   D1,D3
	    blo     .mud12	; skip if remainder < 1/2C
	    addq.l  #1,A0
.mud12
	    move.l  A0,D0	;return result
	    rts

\Rogue\Monster\
else
  echo "will not over write notinlib/muldiv.asm"
fi
if [ `wc -c notinlib/muldiv.asm | awk '{printf $1}'` -ne 4567 ]
then
echo `wc -c notinlib/muldiv.asm | awk '{print "Got " $1 ", Expected " 4567}'`
fi
if `test ! -d src`
then
  mkdir src
  echo "mkdir src"
fi
if `test ! -s src/qint.asm`
then
echo "writing src/qint.asm"
cat > src/qint.asm << '\Rogue\Monster\'

;   QINT.ASM
;
;   handle= OpenQInts()
;	    CloseQInts(handle:A0)
;	    SetQPri(handle:D0, pri:D1)
;	    SetQVector(handle:D0, vector:D1, signo:D2, arg:D3, pri:A0)

		public	_lOpenQInts
		public	_lCloseQInts
		public	_lSetQPri
		public	_lSetQVector

		public	_LVOFindTask
		public	_LVOAllocMem
		public	_LVOFreeMem
		public	_LVOForbid
		public	_LVOPermit
		public	_LVODisable
		public	_LVOEnable
		public	_LVOEnqueue
		public	_LVORemove
		public	_LVOSetSignal
		public	_LVOSetExcept

QINT_SIZE	EQU	32

QINT_NODE	EQU	0
QINT_VECTOR	EQU	14
QINT_SIGMASK	EQU	18
QINT_ARG	EQU	22
QINT_UNUSED	EQU	26

HAN_SIZE	EQU	36+32*QINT_SIZE
HAN_A4		EQU	0
HAN_A5		EQU	4
HAN_EXCODE	EQU	8
HAN_EXDATA	EQU	12
HAN_INTS	EQU	16
HAN_INHAN	EQU	18
HAN_PRI 	EQU	20
HAN_LIST	EQU	22
HAN_QINT	EQU	36

MEMF_CLEAR	EQU	$10000
MEMF_PUBLIC	EQU	$1

LH_HEAD 	EQU	0
LH_TAIL 	EQU	4
LH_TAILPRED	EQU	8

LN_TYPE 	EQU	8
LN_PRI		EQU	9

TC_EXCEPTCODE	EQU	42
TC_EXCEPTDATA	EQU	38


_lOpenQInts:
	    movem.l D2/D3/A2/A6,-(sp)
	    move.l  4,A6
	    move.l  #HAN_SIZE,D0
	    move.l  #MEMF_CLEAR|MEMF_PUBLIC,D1
	    jsr     _LVOAllocMem(A6)
	    tst.l   D0
	    beq     .oqi1
	    move.l  D0,A2
	    move.b  #-128,HAN_PRI(A2)
	    movem.l A4/A5,HAN_A4(A2)
	    lea.l   HAN_LIST+LH_HEAD(A2),A0
	    lea.l   HAN_LIST+LH_TAIL(A2),A1
	    move.l  A1,(A0)
	    move.l  A0,LH_TAILPRED(A0)
.oqi1	    movem.l (sp)+,D2/D3/A2/A6
	    rts

_lCloseQInts:			     ; A0 = handle
	    movem.l D2/D3/A2/A6,-(sp)
	    move.l  4,A6
	    move.l  A0,A2	    ; A2 = handle
	    move.l  A0,D0	    ; skip if null
	    beq     .cqi1
	    moveq.l #31,D3	    ; D3 = sig number.
.cqi2	    move.w  D3,-(sp)
	    move.l  D3,D2	    ; SetQVector(han, NULL, sig#, 0, 0)
	    move.l  A2,D0	    ;		 D0   D1    D2	 D3  A0
	    moveq.l #0,D1
	    move.l  D1,D3
	    move.l  D1,A0
	    jsr     _lSetQVector
	    move.w  (sp)+,D3
	    dbf     D3,.cqi2

.cqi1	    movem.l (sp)+,D2/D3/A2/A6
	    rts



	    ;	_EXCEPT ,  Exception handler.
	    ;
	    ;entry:
	    ;	D0 = exceptions that occured
	    ;	A1 = Handle
	    ;
	    ;auto:
	    ;	A2	= Handle
	    ;	A4/A5	= Possible Global Base Registers
	    ;	D4	= Bit# count
	    ;	D6	= Exceptions that occured


_except:
	    move.l	4,A6		;A6 = Exec Base
	    move.l	D0,D6		;D6 = Exception Bit Mask
	    movem.l	HAN_A4(A1),A4/A5;get global base register(s).
	    move.l	A1,A2		;A2 = HANDLE BASE

	    ;	Queue any exceptions which are interrupts.  Exceptions
	    ;	for interrupts which are queued are NOT reenabled until
	    ;	they are actually run.
	    ;
	    ;	Note that in the loop we must loop to .ex2 to decrement
	    ;	D4, which doesn't occur when we find a '1'.  The Z bit
	    ;	must be set when we loop to .ex2

.ex0	    moveq.l	#31,D4		;D4 = BIT NUMBER
.ex1	    btst.l	D4,D6		; test bits
.ex2	    dbne	D4,.ex1 	; until found a '1'
	    beq 	.ex10		;or loop exhausted (D4 == -1)

	    move.l	D4,D5		;Calculate address of QINT.
	    asl.l	#5,D5		;D5 = index * sizeof(QINT)
	    pea.l	HAN_QINT(A2)
	    add.l	(sp)+,D5        ;     + Base of QINT array
	    move.l	D5,A3		;A3 = QINT address
	    tst.l	QINT_VECTOR(A3) ;Is this exception vectored?
	    beq 	.ex2		;no, somebody else owns it

.ex3	    bclr.l	D4,D6		;clear exception bit.
	    jsr 	_LVOForbid(A6)  ;Important operation!
	    move.l	A3,A1		;A1 = node
	    lea.l	HAN_LIST(A2),A0 ;A0 = List Base
	    move.b	#5,LN_TYPE(A1)  ;mark node as being queued
	    jsr 	_LVOEnqueue(A6)
	    jsr 	_LVOPermit(A6)  ;enable exceptions
	    clr.w	D7		;Force Z cc set.
	    bra 	.ex2		;loop (force decrement/loop)

	    ;	Call the handler.  The handler is allowed to trash
	    ;	everything except D6/A7.  Called with A2 = Handle,
	    ;	A6 = Exec Base

.ex10	    tst.w	HAN_INHAN(A2)   ;no need to call handler?
	    bne 	.ex11
	    bsr 	_handler	;call handler
.ex11	    move.l	D6,D0		;D0 = exception mask
	    beq 	.ex12		;we processed all exceptions
	    move.l	HAN_EXCODE(A2),A0 ;somebody else owns some exceptions
	    move.l	HAN_EXDATA(A2),A1 ;restore exception data pointer
	    jmp 	(A0)            ;call him with remaining exceptions.
.ex12	    rts

	    ;entry:
	    ;	A2	= Handle
	    ;	A4/A5	= Possible Global Base Registers
	    ;	A6	= EXEC base
	    ;
	    ;auto:
	    ;	A2	= Handle;
	    ;	A3	= Qint
	    ;	A4/A5	= GBRs
	    ;	A6	= EXEC base
	    ;	D4	= savepri

_handler:
	    move.b	#1,HAN_INHAN(A2)
	    jsr 	_LVOForbid(A6)
.hloop	    move.l	HAN_LIST+LH_HEAD(A2),A3
	    lea.l	HAN_LIST+LH_TAIL(A2),A0
	    cmp.l	A0,A3			;List is empty
	    beq 	.hbreak
	    move.b	HAN_PRI(A2),D4          ;Check priority of node
	    cmp.b	QINT_NODE+LN_PRI(A3),D4
	    bgt 	.hbreak 		;savepri > qintpri
	    move.l	A3,A1			;A1 = node to remove
	    jsr 	_LVORemove(A6)
	    move.b	#0,QINT_NODE+LN_TYPE(A3)
	    move.b	QINT_NODE+LN_PRI(A3),HAN_PRI(A2)
	    jsr 	_LVOPermit(A6)
	    move.l	QINT_ARG(A3),-(sp)
	    move.l	QINT_VECTOR(A3),A0
	    jsr 	(A0)
	    move.l	4,A6
	    addq.l	#4,sp
	    move.b	D4,HAN_PRI(A2)
	    tst.l	QINT_VECTOR(A3)         ;Reenable the exception
	    beq 	.h1			;only if the vector still
	    move.l	QINT_SIGMASK(A3),D0     ;exists.
	    move.l	D0,D1
	    jsr 	_LVOSetExcept(A6)
.h1	    jsr 	_LVOForbid(A6)
	    bra 	.hloop

.hbreak     moveq.l	#0,D2
	    move.b	D2,HAN_INHAN(A2)
	    jsr 	_LVOPermit(A6)
	    move.l	D2,D0
	    move.l	D2,D1
	    jsr 	_LVOSetExcept(A6)
	    rts

	    ;	SetQVector()
	    ;
	    ;	D0 = handle (copy to A2)
	    ;	D1 = vector (copy to A3)
	    ;	D2 = signo
	    ;	D3 = arg    (copy to D5)
	    ;	A0 = pri
	    ;
	    ;	A2 = handle
	    ;	A3 = vector
	    ;	A4 = qint
	    ;	A5 = task
	    ;
	    ;	D2 = pri
	    ;	D3 = sigmask
	    ;	D4 = oldvector
	    ;	D5 = arg
	    ;	D6 =
	    ;	D7 =

_lSetQVector:
	    movem.l D2-D7/A2-A6,-(sp)
	    move.l  4,A6
	    move.l  D0,A2		;   A2 = Handle
	    move.l  D1,A3		;   A3 = Vector
	    move.l  D3,D5		;   D5 =

	    moveq.l #0,D3		;   D3 = signal mask
	    bset.l  D2,D3		;   D2 = signal
	    asl.l   #5,D2		;   A4 = qint (han->QInt + signo)
	    add.l   #HAN_QINT,D2
	    add.l   A2,D2
	    move.l  D2,A4		;   A4 = QINT
	    move.l  A0,D2		;   D2 = priority
	    move.w  #0,A1		;   A5 = task
	    jsr     _LVOFindTask(A6)
	    move.l  D0,A5

	    jsr     _LVOForbid(A6)      ;   Forbid
	    move.l  QINT_VECTOR(A4),D4  ;   D4 = oldvector
	    move.l  A3,D0
	    bne     .sq100

	    ;	If new vector is NULL, remove old vector if it exists.

	    tst.l   D4
	    beq     .sqdone
	    moveq.l #0,D0
	    move.l  D3,D1
	    jsr     _LVOSetExcept(A6)
	    cmp.b   #5,QINT_NODE+LN_TYPE(A4)
	    bne     .sq1
	    move.l  A4,A1
	    jsr     _LVORemove(A6)
	    move.b  #0,QINT_NODE+LN_TYPE(A4)
.sq1	    sub.w   #1,HAN_INTS(A2)
	    bne     .sq2
	    jsr     _LVODisable(A6)
	    move.l  HAN_EXCODE(A2),TC_EXCEPTCODE(A5)
	    move.l  HAN_EXDATA(A2),TC_EXCEPTDATA(A5)
	    jsr     _LVOEnable(A6)
.sq2	    bra     .sqdone

	    ;	If new vector not null, replace (possibly NULL) old vector

.sq100	    tst.l   D4
	    bne     .sq150
	    add.w   #1,HAN_INTS(A2)     ; oldvector is null, setup task
	    cmp.w   #1,HAN_INTS(A2)
	    bne     .sq150
	    jsr     _LVODisable(A6)
	    move.l  TC_EXCEPTCODE(A5),HAN_EXCODE(A2)
	    move.l  TC_EXCEPTDATA(A5),HAN_EXDATA(A2)
	    move.l  #_except,TC_EXCEPTCODE(A5)
	    move.l  A2,TC_EXCEPTDATA(A5)
	    jsr     _LVOEnable(A6)

.sq150	    move.l  D5,QINT_ARG(A4)
	    move.b  D2,QINT_NODE+LN_PRI(A4)
	    move.l  D3,QINT_SIGMASK(A4)
	    move.l  D3,D0
	    move.l  D3,D1
	    jsr     _LVOSetExcept(A6)
	    bra     .sqdone

.sqdone     move.l  A3,QINT_VECTOR(A4)
	    jsr     _LVOPermit(A6)
	    moveq.l #0,D0
	    move.l  D0,D1
	    jsr     _LVOSetExcept(A6)
	    move.l  D4,D0
	    movem.l (sp)+,D2-D7/A2-A6
	    rts

	    ;	SetQPri
	    ;
	    ;	D0 = handle
	    ;	D1 = newpri
	    ;
	    ;	A2 = handle
	    ;	D2 = newpri
	    ;	D3 = oldpri
_lSetQPri:
	    movem.l D2/D3/A2/A6,-(sp)
	    move.l  4,A6
	    move.l  D0,A2
	    move.l  D1,D2
	    jsr     _LVODisable(A6)
	    move.b  HAN_PRI(A2),D3
	    move.b  D2,HAN_PRI(A2)
	    jsr     _LVOEnable(A6)
	    cmp.b   D2,D3
	    ble     .sqpdone		    ; D3 <= D2 (old <= new)
	    lea.l   HAN_LIST+LH_TAIL(A2),A0
	    cmp.l   HAN_LIST+LH_HEAD(A2),A0
	    beq     .sqpdone

	    movem.l D4/A3,-(sp)
	    jsr     _handler		    ;A2 = handle, A6 = execbase
	    movem.l (sp)+,D4/A3
.sqpdone:
	    moveq.l #0,D0
	    move.b  D3,D0
	    movem.l (sp)+,D2/D3/A2/A6
	    rts

\Rogue\Monster\
else
  echo "will not over write src/qint.asm"
fi
if [ `wc -c src/qint.asm | awk '{printf $1}'` -ne 8366 ]
then
echo `wc -c src/qint.asm | awk '{print "Got " $1 ", Expected " 8366}'`
fi
if `test ! -s src/ires.h`
then
echo "writing src/ires.h"
cat > src/ires.h << '\Rogue\Monster\'

/*
 *  Internal Resource Header Files
 */

#define TML	struct _TML
#define TREN	struct _TREN
#define SVS	struct _SVS
#define RFILE	struct _RFILE
#define FTABLE	struct _FTABLE
#define HTABLE	struct _HTABLE

/*
 *  Task Mem-List Resource structure
 */

TML {
    long    XLock[2];
    MLIST   RENList;	/*  List of resources		    */
    MLIST   RFList;	/*  List of private resource Files  */
};

/*
 *  Task Resource Entry
 */

TREN {
    MNODE   Node;
    APTR    Ptr;
    long    (*Func)();
};

/*
 *  Swap Volume Structure
 */

SVS {
    MNODE   Node;
    long    XLock[2];
    long    Fh; 	/*  associated fh or lock	*/
    uword   Flags;	/*  HAVHANDLE, HAVLOCK		*/
    long    Swapped;	/*  bytes swapped		*/
    long    FileSize;	/*  current file size		*/
    long    Free;	/*  bytes free			*/
    long    Link[32];	/*  swap area free lists	*/
    char    *Name;	/*  swap volume name		*/
};

/*
 *  Resource File Structure
 */

RFILE {
    MNODE   Node;
    long    XLock[2];
    long    Fh; 	/*  associated fh or lock	*/
    long    HTsize;	/*  hash table size in file	*/
    long    Loaded;	/*  bytes loaded		*/
    long    Swapped;	/*  bytes swapped		*/
    uword   Flags;	/*  HAVHANDLE, HAVLOCK		*/
    uword   HTSize;	/*  pwr of 2, # of entries	*/
    FTABLE  **HTab;	/*  [n]&3:0-mem 1-seek.  file access dict.  */
    HTABLE  **LTab;	/*  active resource access table (by name)  */
    char    *Name;	/*  resource file name		*/
};

/*
 *  Hash table entry for dictionary
 */

FTABLE {
    long    Next;	/*  Next entry 0-end, &3:0-mem 1-seek	    */
    uword   Flags;	/*  all applicable flags, inc load state    */
    ubyte   NLen;	/*  name length 			    */
    ubyte   TLen;	/*  type length 			    */
    long    Seek;	/*  seek position in file		    */
    long    Len;	/*  size of resource in file / htable ptr   */
    ubyte   Name[2];	/*  extend structure to [n]		    */
};

/*
 *  Hash table entry for active resource
 */

HTABLE {
    long    Next;	/*  Next entry 0-end, &3:0-mem 1-swapped    */
    uword   Flags;	/*  all applicable flags, inc load state    */
    uword   Refs;
    long    Ptr;	/*  data ptr, swap ptr			    */
    long    Func;	/*  control function			    */
};

\Rogue\Monster\
else
  echo "will not over write src/ires.h"
fi
if [ `wc -c src/ires.h | awk '{printf $1}'` -ne 2194 ]
then
echo `wc -c src/ires.h | awk '{print "Got " $1 ", Expected " 2194}'`
fi
if `test ! -s src/lists.asm`
then
echo "writing src/lists.asm"
cat > src/lists.asm << '\Rogue\Monster\'

		;   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

\Rogue\Monster\
else
  echo "will not over write src/lists.asm"
fi
if [ `wc -c src/lists.asm | awk '{printf $1}'` -ne 7630 ]
then
echo `wc -c src/lists.asm | awk '{print "Got " $1 ", Expected " 7630}'`
fi
if `test ! -s src/timedate.c`
then
echo "writing src/timedate.c"
cat > src/timedate.c << '\Rogue\Monster\'

/*
 *  DATETOS.C
 *
 *  leap year:	every four years but 3 out of 4 century marks are not leap years
 *		(2000 is) the year 0 was.  year&3==0 is
 *  timestamp is since 1978
 *
 *  valid range:    Jan 1 1976	to  Dec 31 2099
 */

#include <local/typedefs.h>

static char dim[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static char *Month[12] = { "Jan","Feb","Mar","Apr","May","Jun","Jul",
			   "Aug","Sep","Oct","Nov","Dec" };

char *
lDateToS(date, str, ctl)
DATESTAMP *date;
char *str;
char *ctl;
{
    long days, years;
    short leap, month;

    if (ctl == NULL)
	ctl = "D M Y h:m:s";
    days = date->ds_Days + 731; 	    /*	1976	    */
    years = days / (365*3+366);             /*  #quad yrs   */
    days -= years * (365*3+366);
    leap = (days < 366);                    /*  is a leap yr*/
    years = 1976 + 4 * years;
    if (!leap) {
	days -= 366;
	++years;
    }
    years += days / 365;
    days -= (days / 365) * 365;
    for (month = 0; (month==1) ? (days >= 28 + leap) : (days >= dim[month]); ++month)
	days -= (month==1) ? (28 + leap) : dim[month];
    {
	register short i = 0;
	for (; *ctl; ++ctl) {
	    switch(*ctl) {
	    case 'h':
		utos(str+i, 1, 2, date->ds_Minute / 60);
		/*sprintf(str+i, "%02d", date->ds_Minute / 60);*/
		break;
	    case 'm':
		utos(str+i, 1, 2, date->ds_Minute % 60);
		/*sprintf(str+i, "%02d", date->ds_Minute % 60);*/
		break;
	    case 's':
		utos(str+i, 1, 2, date->ds_Tick / 50 % 60);
		/*sprintf(str+i, "%02d", date->ds_Tick / 50 % 60);*/
		break;
	    case 'Y':
		utos(str+i, 0, 4, years);
		/*sprintf(str+i, "%ld", years);*/
		break;
	    case 'M':
		strcpy(str+i, Month[month]);
		break;
	    case 'D':
		utos(str+i, 0, 2, days+1);
		/*sprintf(str+i,"%2ld", days+1);*/
		break;
	    default:
		str[i] = *ctl;
		str[i+1] = 0;
		break;
	    }
	    i += strlen(str+i);
	}
    }
    return(str);
}

utos(buf, zfill, flen, val)
register char *buf;
register short flen;
{
    buf[flen] = 0;
    while (flen--) {
	if (val)
	    buf[flen] = '0' + (val % 10);
	else
	    buf[flen] = (zfill) ? '0' : ' ';
	val /= 10;
    }
}

#define BTOC(bptr)    ((long)(bptr) << 2)
#define CTOB(cptr)    ((long)(cptr) >> 2)

#ifndef ACTION_SET_DATE
#define ACTION_SET_DATE 34
#endif

typedef struct StandardPacket STDPKT;
typedef struct MsgPort	      MSGPORT;

extern void *AllocMem();

lSetFileDate(file, date)
char *file;
DATESTAMP *date;
{
    register STDPKT *packet;
    register char   *buf;
    register PROC   *proc;
    long	result;
    long	lock;

    {
	register long flock = Lock(file, SHARED_LOCK);
	register short i;
	register char *ptr = file;

	if (flock == NULL)
	    return(NULL);
	lock = ParentDir(flock);
	UnLock(flock);
	if (!lock)
	    return(NULL);
	for (i = strlen(ptr) - 1; i >= 0; --i) {
	    if (ptr[i] == '/' || ptr[i] == ':')
		break;
	}
	file += i + 1;
    }
    proc   = (PROC *)FindTask(NULL);
    packet = (STDPKT   *)AllocMem(sizeof(STDPKT), MEMF_CLEAR|MEMF_PUBLIC);
    buf = AllocMem(strlen(file)+2, MEMF_PUBLIC);
    strcpy(buf+1,file);
    buf[0] = strlen(file);

    packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
    packet->sp_Pkt.dp_Link = &packet->sp_Msg;
    packet->sp_Pkt.dp_Port = &proc->pr_MsgPort;
    packet->sp_Pkt.dp_Type = ACTION_SET_DATE;
    packet->sp_Pkt.dp_Arg1 = NULL;
    packet->sp_Pkt.dp_Arg2 = (long)lock;        /*  lock on parent dir of file  */
    packet->sp_Pkt.dp_Arg3 = (long)CTOB(buf);   /*  BPTR to BSTR of file name   */
    packet->sp_Pkt.dp_Arg4 = (long)date;        /*  APTR to datestamp structure */
    PutMsg(((LOCK *)BTOC(lock))->fl_Task, packet);
    WaitPort(&proc->pr_MsgPort);
    GetMsg(&proc->pr_MsgPort);
    result = packet->sp_Pkt.dp_Res1;
    FreeMem(packet, sizeof(STDPKT));
    FreeMem(buf, strlen(file)+2);
    UnLock(lock);
    return(result);
}

\Rogue\Monster\
else
  echo "will not over write src/timedate.c"
fi
if [ `wc -c src/timedate.c | awk '{printf $1}'` -ne 3802 ]
then
echo `wc -c src/timedate.c | awk '{print "Got " $1 ", Expected " 3802}'`
fi
if `test ! -s src/oldfile.c`
then
echo "writing src/oldfile.c"
cat > src/oldfile.c << '\Rogue\Monster\'

#include <local/res.h>

#define SFILE	struct _SFILE
#define RFILE	struct _RFILE
#define FTABLE	struct _FTABLE
#define HTABLE	struct _HTABLE

SFILE {
    long    XLock[2];
    long    Fh; 	/*  associated fh or lock	*/
    uword   Flags;	/*  HAVHANDLE, HAVLOCK		*/
    long    Swapped;	/*  bytes swapped		*/
    long    FileSize;	/*  current file size		*/
    long    Free;	/*  bytes free			*/
    long    Link[32];	/*  swap area free lists	*/
    char    *Name;	/*  file name			*/
};

RFILE {
    long    XLock[2];
    long    Fh; 	/*  associated fh or lock	*/
    long    HTsize;	/*  hash table size in file	*/
    long    Loaded;	/*  bytes loaded		*/
    long    Swapped;	/*  bytes swapped		*/
    uword   Flags;	/*  HAVHANDLE, HAVLOCK		*/
    uword   HTSize;	/*  pwr of 2, # of entries	*/
    FTABLE  **HTab;	/*  [n]&3:0-mem 1-seek.  file access dict.  */
    HTABLE  **LTab;	/*  active resource access table	    */
    char    *Name;	/*  file name			*/
};

FTABLE {
    long    Next;	/*  Next entry 0-end, &3:0-mem 1-seek	    */
    uword   Flags;	/*  all applicable flags, inc load state    */
    ubyte   NLen;	/*  name length 			    */
    ubyte   TLen;	/*  type length 			    */
    long    Seek;	/*  seek position in file		    */
    long    Len;	/*  size of resource in file / htable ptr   */
    ubyte   Name[2];	/*  extend structure to [n]		    */
};

HTABLE {
    long    Next;	/*  Next entry 0-end, &3:0-mem 1-swapped    */
    uword   Flags;	/*  all applicable flags, inc load state    */
    uword   Refs;
    long    Ptr;	/*  data ptr, swap ptr			    */
    long    Func;	/*  control function			    */
};

\Rogue\Monster\
else
  echo "will not over write src/oldfile.c"
fi
if [ `wc -c src/oldfile.c | awk '{printf $1}'` -ne 1623 ]
then
echo `wc -c src/oldfile.c | awk '{print "Got " $1 ", Expected " 1623}'`
fi
if `test ! -s src/oldfile.h`
then
echo "writing src/oldfile.h"
cat > src/oldfile.h << '\Rogue\Monster\'

/*
 *  FILE.H
 *
 *  Message Passing structure.
 */

#define RMSG struct _RMSG

RMSG {
    MSG     Mesg;	/*  exec message    */
    long    Arg1;
    long    Arg2;
    long    Arg3;
    long    Arg4;
    long    Res1;
};

#define RACT_GETRES	1   /*	(name,type,nmlen,tylen)     */
#define RACT_

extern PORT	ResPort;


\Rogue\Monster\
else
  echo "will not over write src/oldfile.h"
fi
if [ `wc -c src/oldfile.h | awk '{printf $1}'` -ne 319 ]
then
echo `wc -c src/oldfile.h | awk '{print "Got " $1 ", Expected " 319}'`
fi
if `test ! -s src/res.c`
then
echo "writing src/res.c"
cat > src/res.c << '\Rogue\Monster\'

/*
 *  RES.C
 *
 *  System Overview:
 *	GetRes()            -
 *	DupRes()            -
 *	FreeRes()           -
 *	FreeAllRes()        -
 *	ChownRes()          -
 *	UnLinkAllRes()      -
 *	ReLinkAllRes()      -
 *	SetResFlags()       -
 *	AddRes()            -
 *	RemRes()            -
 *	GetResInfo()        -
 *	GetResList()        -
 *	GetFileList()       -
 *	AddPrivResFile()    -
 *	RemPrivResFiles()   -
 *	AddGlobResFile()    -
 *	RemGlobResFiles()   -
 *	AddResSwapDir()     -
 *	RemResSwapDirs()    -
 *
 */

#include <local/typedefs.h>
#include <local/ipc.h>
#include <local/res.h>
#include "/src/ires.h"

static long SysLock[2] = { 0, 0 };

extern TML *GetTML();

/*
 *  Search order:   Private-mem, Private-disk, System-mem, System-disk,
 *		    OtherTaskGlob-mem, OtherTaskGlob-disk
 */

APTR
GetRes(name)
char *name;
{
    TML *tml = GetTML();




    resptr= GetRes(resnametype)             char *resnametype;

	This function retrieves the requested resource, doing any
	translations required to get the resource into the requested
	type.  NULL is returned if the resource could not be found
	or could not be translated to the requested type.

	In-Memory private resources are searched first, then the private
	resource files for the task, then In-Memory system resources, then
	the global resource files for the system.  Openning an already-open
	resource causes one of two actions depending on whether the resource
	is shared or not.  If shared, the reference count is simply
	incremented, otherwise a private copy of the resource is made.

	Example:    Win = GetRes("Charlie.Window");

    resptr2 = DupRes(resptr1)               APTR resptr1, resptr2;

	This call duplicates a resource.  If the resource is shared
	resptr2 will be the same as resptr1 and the reference count will
	be bumped.  Otherwise, a new resource data area is allocated and
	the old copied to the new.

	Things like fixing pointers and such within a resource that is
	physically duplicated are handled by the interface code (since
	raw resources do not contain pointers, only VIRTUAL resources
	will contain pointers and all VIRTUAL resources have some
	interface code).

    error = FreeRes(resptr)

	Free a resource that you retrieved via GetRes().  Only the task
	that owns the resource may free it (though several tasks may own
	a resource through duplication and ownership changes).	1 is
	returned on success, 0 on error.

	That is, if task #1 GetRes()'s the resource and duplicates it once,
	then task #2 duplicates it once, task #1 must call FreeRes() twice
	and task #2 must call FreeRes() once.  Ownership is strictly
	tracked.

    numres= FreeAllRes(task)

	Free all resources associated with the specified task (NULL for
	self).

    error = ChownRes(resptr, fromtask, totask)

	Change ownership of a resource from the source task to the
	destination task.  The resource must be owned by the source
	task or an error will occur (0 return value).  1 is returned
	on success.  NULL may be specified for either or both tasks
	and means the calling task.

    handle= UnLinkAllRes(task)

	Unlink all resources associated with the specified task (NULL
	for self) and return a handle representing those resources.

	This is useful for shells and such to keep their resources from
	getting removed by commands they run.  Combined with the NUNLINK
	flag one can pass resources to a Command and keep the rest out of
	reach.

    (void)  ReLinkAllRes(handle, task)

	Link all the resources represented by the handle to the specified
	task (NULL for self).

    oldfl = SetResFlags(resptr, newflags, flagsmask)

	Modify the flags associated with a resource.  NOTE:  If multiple
	references to a shared resource exist, all are modified.  Some
	modifications may be disallowed by the system.	This call is
	normally used to modify the LOCKED and SWAPABLE flags (note that
	the SWAPABLE flag can be changed back and forth only for resource
	which support it).

    error = AddRes(resnametype, flags, ptr, ctlcode);
						    char *resnametype;
						    long flags;
						    APTR ptr;
						    long (*ctlcode)();

	Add a resource to the system.  The resource is placed either in
	the task's privately accessable in-memory resource list or
	in the system global accessable in-memory resource list depending
	on the specified flags.  One may now GetRes() the resource.

	ONLY VIRTUAL RESOURCES MAY BE ADDED IN THIS WAY.  The VIRTUAL
	and LOCKED flags are automatically set.

	If flags specifies a VIRTUAL resource

    error = RemRes(resname)

	Remove the specified resource.	An error will occur and the resource
	will not be removed (1) if it does not exist in memory, or (2) it
	is currently being referenced.	(Note: the resource is removed even
	if it is swapped or locked).

    error = GetResInfo(resname, &flags, &bytes)

	Get information on a resource.	Information may not exist for a
	resource if it is not currently in memory and would have to be
	translated to get to the right type.

    error = GetResList(wildcard, from, &av, &ac);

	from:	mask, bit 0  search private list
			  1  search system list
			  2  <not used>
			  3  search in-memory private list
			  4  search in-memory global list

	Return an ARGC/ARGV list of resource names.  Note that some names
	might be duplicated if searching multiple lists.  Restricting the
	search to in-memory lists give resources which are already in
	memory (but might be swapped out or removed at any time for those
	with no references)

			     RESOURCE FILES

    error = GetFileList(wildcard, from, &av, &ac);

	from:	mask, bit 0  search private list
			  1  search system list
			  2  search swap list

	Return an ARGC/ARGV list of the files which match the specified
	wildcard from the private list, system list, or system swap dir
	list (in which case you get directory names).  This list has been
	allocated, and can be freed as follows:

	    Loop through all entries for (i = 0; i < ac; ++i)
					FreeMem(av[i], strlen(av[i])+1);
	    Free the array itself:  FreeMem(av, sizeof(char *) * (ac+1));

    num   = AddPrivResFile(filename, pri)

	Add a file name to the list of resource files for this task.  These
	are scanned before global files when a resource is requested.  All
	files in the list are write protected (i.e. a shared lock is kept
	for each file).  Thus, such files cannot be updated until removed
	from the list.

	Can also be used to modify the priority of an existing file

    num   = RemPrivResFiles(wildcard)

	Remove zero or more file names from the list of resource files for
	this task.  A wildcard pattern (* and ?) is accepted.

	Note for command processors:	commands you run might execute
	this command for *.

    num   = AddGlobResFile(filename, pri)

	Same as AddPrivResFile() but applies to the system list, which is
	searched last and by any requesting task.  Wildcard file names are
	NOT accepted.  The file need not exist at this time, and references
	to unmounted volumes are allowed.

	Can also be used to modify the priority of an existing entry

    num   = RemGlobResFiles(wildcard)

	Remove zero or more resource files from the global list.  Again,
	a wildcard filename is accepted.

    num   = AddResSwapDir(dirname, pri, maxkbytes)      char *dirname;
							char pri;
							long maxkbytes

	Add a directory to the list of directories the resource system
	can swap to.  The maximum number of KBytes of material allowed
	in the directory should be specified.  You can also use this
	call to modify the priority and maxkbytes for an entry.

	The highest priority directories are used before lower priority
	directories.  Not all directories need be mounted, but if a swapin
	occurs from an unmounted directory a requester will appear.

	A lock is kept on each specified directory.

    num   = RemResSwapDirs(wildcard)

	Remove directories associated with the resource swap areas.


			    RESOURCE FILE IFF FORMAT




static
TML *
GetTML()
{
    TML *tml = GetTaskData(RESMLNAME, sizeof(TML));
    if (tml && !tml->RFList.mlh_Head) {
	NewList(&tml->RENList);
	NewList(&tml->RFList);
    }
    return(tml);
}

\Rogue\Monster\
else
  echo "will not over write src/res.c"
fi
if [ `wc -c src/res.c | awk '{printf $1}'` -ne 8107 ]
then
echo `wc -c src/res.c | awk '{print "Got " $1 ", Expected " 8107}'`
fi
echo "Finished archive 2 of 3"
# if you want to concatenate archives, remove anything after this line
exit
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.