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.