page@swan.ulowell.edu (Bob Page) (10/25/88)
Submitted-by: dillon@cory.berkeley.edu (Matt Dillon) Posting-number: Volume 2, Issue 16 Archive-name: util/dres.1 # 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: # src/ipc.c # src/misc.c # src/newres.c # src/mem.asm # util/gtd.c # util/testipc.c # util/test.c # util/qtest.c # util/testarg.c # util/x.c # if `test ! -d src` then mkdir src echo "mkdir src" fi if `test ! -s src/ipc.c` then echo "writing src/ipc.c" cat > src/ipc.c << '\Rogue\Monster\' /* * IPC.C 25 September 1988 * * NOTE! the BSS segment is not initialized to 0. */ #include <local/typedefs.h> #include <local/ipc.h> extern EXECBASE *SysBase; static long IPCLock[2] = { 0, 0 }; static MLIST IPCList = { (MNODE *)&IPCList.mlh_Tail, NULL, (MNODE *)&IPCList.mlh_Head }; extern void *FindName(); extern IPCMSG *lSendIPC2(); extern char *CCall(); extern APTR Duplicate(); /* * Three-pass command parser. * (1) Determine # of arguments and allocate argv array, resolve variables * (2) Determine length of each argument and allocate entries in the array * (3) Fill entries in the array * * On return, an filled ARGV array will be returned. To free the argv * array and elements, call FreeParseCmd(argv). Individual argv[] * entries may be modified, including stuffing different pointers in, * without effecting FreeParseCmd(). Note that offset -1 in each entry * contains a status byte, currently only bit 0 (was quoted) is used. */ lParseCmd(buf, pav, varget, varfree, error, reserved) char *buf; char ***pav; char *((*varget)()); char *((*varfree)()); long *error; { short numac; /* # of argv entries */ char **av = NULL; /* argv array */ long *arglen = NULL; /* array of entry lengths */ MLIST VList; /* Hold $variable contents */ char *endstrvar(); /* extracts variable name */ short ttllen = 0; /* sum of lengths of entries */ NewList(&VList); *error = 0; /* * PASS1, determine # of arguments and retrieve variables */ { register char *ptr; register short ac = 0; register short quo = 0; for (ptr = buf; *ptr == ' ' || *ptr == 9; ++ptr); for (; *ptr; ++ptr) { switch(*ptr) { case '(': ++quo; break; case ')': --quo; break; case '\\': case '^': if (ptr[1]) ++ptr; break; case ' ': case 9: if (!quo) { while (*ptr == ' ' || *ptr == 9) ++ptr; if (*ptr) ++ac; --ptr; } break; case '$': { short len; char tmp[64]; char *str; MNODE *vl; ++ptr; str = endstrvar(ptr, &len); if (*ptr == '(') ++ptr; BMov(ptr, tmp, len); tmp[len] = 0; if (varget && (ptr = (char *)CCall(varget, tmp))) { vl = AllocMem(8 + strlen(ptr) + 1, MEMF_PUBLIC); if (!vl) { *error = (PERR_NOMEM << 16) | (ptr - buf); goto fail; } strcpy(vl+1, ptr); if (varfree) CCall(varfree, ptr); } else { *error = (PERR_NOVAR << 16) | (ptr - buf); goto fail; } AddTail(&VList, vl); ptr = str - 1; } break; } } ++ac; numac = ac; } /* * av[-1] = master string pointer (see below) * av[-2] = sizeof av array * av[ac] = NULL * * Pass 2, allocate argv array and storage for the lengths of each * entry. Determine the length of each entry. */ av = AllocMem(sizeof(char *) * (numac + 3), MEMF_PUBLIC); if (!av) { *error = (PERR_NOMEM << 16); goto fail; } av += 2; av[-2] = (char *)(sizeof(char *) * (numac + 3)); arglen = AllocMem(sizeof(long) * numac, MEMF_PUBLIC); if (!arglen) { *error = (PERR_NOMEM << 16); goto fail; } { register char *ptr; register short ac = 0; register short quo = 0; register short len = 0; for (ptr = buf; *ptr == ' ' || *ptr == 9; ++ptr); for (; *ptr; ++ptr) { switch(*ptr) { case '(': ++quo; if (quo != 1) ++len; break; case ')': --quo; if (quo) ++len; break; case '\\': case '^': if (ptr[1]) { ++ptr; ++len; } break; case ' ': case 9: if (!quo) { while (*ptr == ' ' || *ptr == 9) ++ptr; if (*ptr) { arglen[ac] = len; ttllen += len + 2; ++ac; len = 0; } --ptr; } else { ++len; } break; case '$': { register MNODE *node = RemHead(&VList); if (node) { len += strlen(node+1); AddTail(&VList, node); } ptr = endstrvar(ptr + 1, NULL) - 1; } break; case '\n': break; default: ++len; break; } } arglen[ac] = len; ttllen += len + 2; /* 1 byte status & 1 byte separator */ ++ac; } { /* allocate space for entries */ register short i; register char *mem = AllocMem(4+ttllen, MEMF_PUBLIC); register char *ptr = mem + 4; if (!mem) { *error = (PERR_NOMEM << 16); goto fail; } *(long *)mem = 4 + ttllen; for (i = 0; i < numac; ++i) { *ptr++ = 0; /* status byte */ av[i] = ptr; ptr[arglen[i]] = 0; ptr += arglen[i] + 1; } av[-1] = mem; } { register char *ptr; register char *avs = av[0]; register short ac = 0; short quo = 0; for (ptr = buf; *ptr == ' ' || *ptr == 9; ++ptr); for (; *ptr; ++ptr) { switch(*ptr) { case '\\': if (ptr[1]) *avs++ = *++ptr; break; case '^': if (ptr[1]) *avs++ = *++ptr & 0x1F; break; case '(': ++quo; if (quo != 1) *avs++ = '('; else if (avs == av[ac]) /* quoted argument */ avs[-1] = 1; break; case ')': --quo; if (quo) { *avs++ = ')'; break; } /* fall through */ case ' ': case 9: if (!quo) { ++ptr; while (*ptr == ' ' || *ptr == 9) ++ptr; if (*ptr) { *avs = 0; avs = av[++ac]; } --ptr; } else { *avs++ = *ptr; } break; case '$': { register MNODE *node = RemHead(&VList); if (node) { strcpy(avs, node + 1); avs += strlen(avs); FreeMem(node, 8 + strlen(node+1) + 1); } ptr = endstrvar(ptr + 1, NULL) - 1; } break; case '\n': break; default: *avs++ = *ptr; break; } } *avs = 0; ++ac; } FreeMem(arglen, sizeof(long) * numac); *pav = av; av[numac] = NULL; return(numac); fail: { register MNODE *node; if (arglen) FreeMem(arglen, sizeof(long) * numac); if (av) FreeMem(av - 2, (long)av[-2]); while (node = RemHead(&VList)) FreeMem(node, 8 + strlen(node+1) + 1); } *pav = NULL; return(0); } lFreeParseCmd(av) char **av; { FreeMem(av[-1], *(long *)av[-1]); FreeMem(av - 2, (long)av[-2]); } char * endstrvar(ptr, plen) short *plen; register char *ptr; { register short len = 0; if (*ptr == '(') { ++ptr; while (*ptr && *ptr != ')') { ++ptr; ++len; } if (*ptr == ')') ++ptr; } else { while ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= '0' && *ptr <= '9') || (*ptr == '_')) { ++len; ++ptr; } } if (len > 62) len = 62; if (plen) *plen = len; return(ptr); } IPCPORT * lOpenIPC(name, flags) char *name; { register IPCPORT *port; register char *ptr; port = AllocMem(sizeof(IPCPORT), MEMF_PUBLIC|MEMF_CLEAR); if (!port) goto fail; ptr = AllocMem(strlen(name)+1, MEMF_PUBLIC); if (!ptr) goto fail; strcpy(ptr, name); port->Flags = flags; port->Port.mp_Node.ln_Type = NT_MSGPORT; port->Port.mp_Node.ln_Name = ptr; port->Port.mp_Flags = PA_SIGNAL; port->Port.mp_SigBit = AllocSignal(-1); port->Port.mp_SigTask = FindTask(NULL); NewList(&port->Port.mp_MsgList); LockAddr(IPCLock); Insert(&IPCList, port, FindName(&IPCList, name)); UnLockAddr(IPCLock); return(port); fail: if (port) { FreeMem(port, sizeof(IPCPORT)); if (ptr) FreeMem(ptr, strlen(ptr)+1); } return(NULL); } void lCloseIPC(port) register IPCPORT *port; { register IPCMSG *msg; LockAddr(IPCLock); /* remove port (no new messages) */ Remove(port); UnLockAddr(IPCLock); while (msg = GetMsg(port)) /* reply to pending msgs w/error */ ReplyIPC(msg, NULL, 0, IF_NOTFND); FreeMem(port->Port.mp_Node.ln_Name, strlen(port->Port.mp_Node.ln_Name)+1); if (port->Port.mp_Flags == PA_SIGNAL) FreeSignal(port->Port.mp_SigBit); FreeMem(port, sizeof(IPCPORT)); } /* * msg = SendIPC(appname, buf, len, flags) */ IPCMSG * lSendIPC(name, buf, len, flags) char *name; APTR buf; register long len, flags; { register IPCMSG *msg; register PORT *rport; msg = AllocMem(sizeof(IPCMSG)+sizeof(PORT), MEMF_PUBLIC|MEMF_CLEAR); if (msg == NULL) return(NULL); flags |= IF_ALLOCMSG; /* auto-deallocate later on */ rport = (PORT *)(msg + 1); if (buf && !(flags & IF_NOCOPY) && !(flags & IF_ALLOC)) { if (!(buf = Duplicate(buf, len))) { FreeMem(msg, sizeof(IPCMSG)+sizeof(PORT)); return(NULL); } flags |= IF_ALLOC; } rport->mp_Node.ln_Type = NT_MSGPORT; rport->mp_Flags = PA_SIGNAL; rport->mp_SigBit = 4; rport->mp_SigTask = SysBase->ThisTask; NewList(&rport->mp_MsgList); msg->Msg.mn_ReplyPort = rport; msg->Msg.mn_Length = sizeof(IPCMSG) + sizeof(PORT); msg->TBuf = buf; msg->TLen = len; msg->TFlags = flags; return(lSendIPC2(name, msg)); } IPCMSG * lSendIPC2(name, msg) char *name; register IPCMSG *msg; { register IPCPORT *port; msg->RBuf = NULL; msg->RLen = 0; msg->RFlags = 0; msg->Error = 0; msg->Confirm = NULL; LockAddr(IPCLock); if (name) { port = (IPCPORT *)FindName(&IPCList, name); } else { port = GetHead(&IPCList); } msg->ToPort = port; if (port) { if ((port->Flags & IF_ALLOC) && !(msg->TFlags & IF_ALLOC)) { if ((msg->TBuf = Duplicate(msg->TBuf, msg->TLen)) == NULL) { msg->Error = PERR_NOMEM; lReplyIPC(msg, NULL, 0, IF_ERROR); return(msg); } msg->TFlags |= IF_ALLOC; } PutMsg(port, msg); UnLockAddr(IPCLock); } else { UnLockAddr(IPCLock); lReplyIPC(msg, NULL, 0, IF_ERROR|IF_NOTFND|IF_NOAPP); } return(msg); } /* * DoIPC2(name, msg, collfunc, collport) * * Synchronous IPC routine. To prevent lockouts in case the calling task * also owns an IPC port, if this port is provided 'collfunc' will * automatically be called if new requests arrive while we are waiting * for our request to complete. This call is reentrant. */ void lDoIPC2(name, msg, func, port) char *name; IPCMSG *msg; void (*func)(); PORT *port; { SendIPC2(name, msg); /* send the message */ if (port) { register long mask1 = 1 << port->mp_SigBit; register long mask2 = 1 << msg->Msg.mn_ReplyPort->mp_SigBit; while (!CheckMsg(msg)) { if (CheckPort(port)) { CCall(func, port); continue; } Wait(mask1 | mask2); } } WaitMsg(msg); } /* * (void )ReplyIPC(msg, buf, len, flags) */ lReplyIPC(msg, buf, len, flags) register IPCMSG *msg; APTR buf; long len, flags; { if (buf && !(flags & (IF_NOCOPY|IF_ALLOC|IF_NOTFND))) { buf = Duplicate(buf, len); flags |= IF_ALLOC; } if (buf || !(flags & IF_NOTFND)) { if ((msg->RFlags & IF_ALLOC) && msg->RBuf && buf != msg->RBuf) FreeMem(msg->RBuf, msg->RLen); msg->RBuf = buf; msg->RLen = len; } msg->RFlags = flags; LockAddr(IPCLock); if (msg->RFlags & IF_GLOBAL) { register IPCPORT *next; do { next = GetSucc(next); } while (next && !(next->Flags & IF_GLOBAL)); if (next) { msg->ToPort = next; PutMsg(next, msg); } else { if ((msg->TFlags & IF_ALLOC) && msg->TBuf) { FreeMem(msg->TBuf, msg->TLen); msg->TBuf = NULL; } ReplyMsg(msg); } UnLockAddr(IPCLock); return; } if (flags & IF_NOTFND) { register IPCPORT *next = GetSucc(msg->ToPort); if (next && strcmp(msg->ToPort->Port.mp_Node.ln_Name, next->Port.mp_Node.ln_Name) == 0) { msg->ToPort = next; PutMsg(next, msg); } else { if ((msg->TFlags & IF_ALLOC) && msg->TBuf) { FreeMem(msg->TBuf, msg->TLen); msg->TBuf = NULL; } ReplyMsg(msg); msg->RFlags |= IF_ERROR; } UnLockAddr(IPCLock); return; } UnLockAddr(IPCLock); if ((msg->TFlags & IF_ALLOC) && msg->TBuf) { FreeMem(msg->TBuf, msg->TLen); msg->TBuf = NULL; } ReplyMsg(msg); return; } /* * (void) lFreeIPC(msg) * * Free space associated with the reply buffer and possibly the message * itself. This call MUST be made after you receive a reply to your * message. */ void lFreeIPC(msg) register IPCMSG *msg; { if ((msg->RFlags & IF_ALLOC) && msg->RBuf) { FreeMem(msg->RBuf, msg->RLen); msg->RBuf = NULL; } if (msg->Confirm) /* Confirmation requested */ CCall(msg->Confirm, msg); if (msg->TFlags & IF_ALLOCMSG) /* Message was allocated */ FreeMem(msg, msg->Msg.mn_Length); } APTR Duplicate(buf, len) APTR buf; long len; { APTR newbuf; if (newbuf = AllocMem(len, TypeOfMem(buf))) { BMov(buf, newbuf, len); return(newbuf); } return(NULL); } #asm ; CCall(funcptr, argument) _CCall: movem.l 4(sp),A0/A1 movem.l D2/D3/A4/A5/A6,-(sp) move.l A1,-(sp) jsr (A0) addq.l #4,sp movem.l (sp)+,D2/D3/A4/A5/A6 rts #endasm \Rogue\Monster\ else echo "will not over write src/ipc.c" fi if [ `wc -c src/ipc.c | awk '{printf $1}'` -ne 12876 ] then echo `wc -c src/ipc.c | awk '{print "Got " $1 ", Expected " 12876}'` fi if `test ! -s src/misc.c` then echo "writing src/misc.c" cat > src/misc.c << '\Rogue\Monster\' /* * MISC.C * * General Stuff... mostly in assembly. */ #include <local/typedefs.h> typedef struct { NODE ml_Node; uword ml_NumEntries; MEMENTRY ml_ME[2]; } MYMEMLIST; APTR lGetTaskData(name, bytes) char *name; long bytes; { extern EXECBASE *SysBase; extern void *FindName2(); register LIST *list; register MEMLIST *ml; list = &SysBase->ThisTask->tc_MemEntry; if (ml = FindName2(list, name)) return(ml->ml_ME[0].me_Un.meu_Addr); if (!list->lh_Head) NewList(list); { MYMEMLIST Ml; Ml.ml_NumEntries = 2; Ml.ml_ME[0].me_Un.meu_Reqs = MEMF_PUBLIC|MEMF_CLEAR; Ml.ml_ME[0].me_Length = bytes; Ml.ml_ME[1].me_Un.meu_Reqs = MEMF_PUBLIC; Ml.ml_ME[1].me_Length = strlen(name)+1; if (ml = AllocEntry(&Ml)) { ml->ml_Node.ln_Name = (char *)ml->ml_ME[1].me_Un.meu_Addr; strcpy(ml->ml_Node.ln_Name, name); AddHead(list, ml); return(ml->ml_ME[0].me_Un.meu_Addr); } } return(NULL); } lFreeTaskData(name) char *name; { extern EXECBASE *SysBase; extern void *FindName2(); register MEMLIST *ml; if (ml = FindName2(&SysBase->ThisTask->tc_MemEntry, name)) { Remove(ml); FreeEntry(ml); return(1); } return(0); } #asm include "exec/types.i" include "exec/ports.i" include "exec/tasks.i" include "exec/execbase.i" include "exec/ables.i" include "exec/memory.i" ; NOTE: LockAddr/UnLockAddr referenced elsewhere in ; this library ; MISC.ASM public _lWildCmp ; Wildcard compare public _lWaitMsg ; Wait for a message to be replied public _lCheckMsg ; Check if message has been returned public _lCheckPort ; Check if message pending on port public _lDoSyncMsg ; Put and Wait for a message public _lLockAddr public _lLockAddrB public _lUnLockAddr public _lUnLockAddrB public _lFindName2 public _LVOWait public _LVORemove public _LVODisable public _LVOEnable public _LVOFindTask public _LVOSignal public _LVOForbid public _LVOPermit public _LVOPutMsg _lDoSyncMsg: movem.l A2/A3/A6,-(sp) ; A0=port, A1=msg move.l 4,A6 ; A6=execbase sub.w #MP_SIZE,sp ; initialize reply port move.b #NT_MSGPORT,LN_TYPE(sp) move.b #PA_SIGNAL,MP_FLAGS(sp) move.b #4,MP_SIGBIT(sp) ; EXEC semaphore signal move.l ThisTask(A6),MP_SIGTASK(sp) lea MP_MSGLIST(sp),A2 lea MP_MSGLIST+4(sp),A3 move.l A3,(A2) ; &tail -> head move.l #0,(A3) ; NULL -> tail move.l A2,8(A2) ; &head -> tailpred move.l sp,MN_REPLYPORT(A1) move.l A1,A2 ; save message jsr _LVOPutMsg(A6) ; send the message move.l A2,A0 bsr _lWaitMsg ; wait for reply add.w #MP_SIZE,sp movem.l (sp)+,A2/A3/A6 rts _lCheckMsg: moveq.l #0,D0 cmp.b #NT_MESSAGE,LN_TYPE(A0) ;NT_MESSAGE == not replied beq .lcm1 move.l A0,D0 .lcm1 rts _lCheckPort: moveq.l #0,D0 move.l MP_MSGLIST+LH_HEAD(A0),A0 tst.l (A0) ;list empty? beq .lcp1 move.l A0,D0 ;no, return first element .lcp1 rts _lWaitMsg: ;A0 = message to wait for movem.l A2/A3/A6,-(sp) move.l A0,A2 ;A2 = message move.l MN_REPLYPORT(A0),A3 ;A3 = replyport move.l 4,A6 ;A6 = execbase .wmloop cmp.b #NT_MESSAGE,LN_TYPE(A2) ;while msg not replied bne .wm1 move.b MP_SIGBIT(A3),D1 ;Wait on port signal moveq.l #0,D0 bset.l D1,D0 jsr _LVOWait(A6) bra .wmloop .wm1 jsr _LVODisable(A6) ;remove from port move.l A2,A1 ;A1 = message (A2) jsr _LVORemove(A6) jsr _LVOEnable(A6) move.l A2,D0 ;return message movem.l (sp)+,A2/A3/A6 rts ;WILDCMP(wild:D0, name:D1) ; ; Handles * and ? ; ;result: D0, 0 = no match, 1 = match ; ;auto: ; D2 bi ; A2 wildcard string ; A3 name string ; A4 back-array (of size MAXB * 2 * 4) MAXB EQU 8 _lWildCmp: movem.l D2/A2-A4,-(sp) move.l D0,A2 move.l D1,A3 sub.l #MAXB*2*8,sp move.l sp,A4 moveq.l #0,D2 .wcloop moveq.l #1,D0 move.b (A2),D1 bne .w1 tst.b (A3) beq .wcdone .w1 cmp.b #'*',D1 bne .w10 cmp.w #MAXB,D2 bne .w2 moveq.l #-1,D0 ; error bra .wcdone .w2 move.w D2,D0 ; back[bi][0] = w i.e. back+bi*8 asl.w #3,D0 ; back[bi][1] = n move.l A2,(A4,D0.w) move.l A3,4(A4,D0.w) addq.w #1,D2 addq.l #1,A2 bra .wcloop .wgoback subq.w #1,D2 bmi .w5 move.w D2,D0 asl.w #3,D0 move.l 4(A4,D0.w),A0 tst.b (A0) beq .wgoback .w5 tst.w D2 bmi .wcret0 move.w D2,D0 asl.w #3,D0 move.l (A4,D0.w),A2 addq.l #1,A2 add.l #1,4(A4,D0.w) move.l 4(A4,D0.w),A3 addq.l #1,D2 bra .wcloop .w10 cmp.b #'?',D1 bne .w20 tst.b (A3) bne .wcbreak tst.w D2 bne .wgoback bra .wcret0 .w20 move.b (A3),D0 cmp.b #'A',D0 blo .w21 cmp.b #'Z',D0 bhi .w21 or.b #$20,D0 .w21 move.b (A2),D1 cmp.b #'A',D1 blo .w22 cmp.b #'Z',D1 bhi .w22 or.b #$20,D1 .w22 cmp.b D0,D1 beq .wcbreak tst.w D2 bne .wgoback bra .wcret0 .wcbreak tst.b (A2)+ bne .wcb1 subq.l #1,A2 .wcb1 tst.b (A3)+ bne .wcb2 subq.l #1,A3 .wcb2 bra .wcloop .wcret0 moveq.l #0,D0 .wcdone add.l #MAXB*2*8,sp movem.l (sp)+,D2/A2-A4 rts ; long var[2] = { 0, 0 }; ; ; These routines provide fast exclusive ; locks. Up to 8 independant locks may be used for ; each 4 byte address. ; ; LockAddr(&var[0]:A0) ; LockAddrB(bit:D0, &var[0]:A0) ; UnLockAddr(&var[0]:A0) ; UnLockAddrB(bit:D0, &var[0]:A0) _lLockAddr: moveq.l #0,D0 ; bit 0 _lLockAddrB: bset.b D0,4(A0) ; attempt to gain lock bne .la10 rts ; was clear, so got it .la10 movem.l A2/A6,-(sp) ; else failed, move.l 4,A6 ; A6 = SYSBase FORBID bset.b D0,4(A0) ; try again beq .la20 ; got it! move.w D0,-(sp) ; bit# 12(sp) move.l ThisTask(A6),-(sp) ; task# 8(sp) move.l A0,-(sp) ; &var 4(sp) move.l (A0),-(sp) ; Next (sp) move.l sp,(A0) ; (put at head of list) .la15 moveq.l #$10,D0 ; wait (semaphore signal) jsr _LVOWait(A6) move.w 12(sp),D0 ; try for lock move.l 4(sp),A0 bset.b D0,4(A0) bne .la15 ; loop until get it .la16 cmp.l (A0),sp ; unlink, find our node! beq .la18 move.l (A0),A0 bra .la16 .la18 move.l (sp),(A0) add.w #14,sp .la20 PERMIT movem.l (sp)+,A2/A6 rts _lUnLockAddr: moveq.l #0,D0 ; bit 0 _lUnLockAddrB: bclr.b D0,4(A0) ; clear lock bit move.l (A0),D1 ; anybody waiting? beq .ulrts ; no, rts movem.l D2/A2/A6,-(sp) ; yes, wake 'm all up move.b D0,D2 ; D2 = bit# move.l 4,A6 ; A6 = SYSBase FORBID move.l (A0),D1 ; get pointer again after FORBID beq .ul20 ; no, rts (close a window) .ul10 move.l D1,A2 ; A2 = node cmp.b 13(A2),D2 ; waiting on our bit #? bne .ul18 ; no move.l 8(A2),A1 ; yes, signal the node moveq.l #$10,D0 jsr _LVOSignal(A6) ; signal EVERYONE waiting .ul18 move.l (A2),D1 ; next bne .ul10 .ul20 PERMIT movem.l (sp)+,D2/A2/A6 .ulrts rts ; FindName2(list:D0, name:A0) ; ; Search the node list as in FindName(), but also ignore ; NULL ln_name entries, which FindName() does not do. This ; routine will also return NULL if given an uninitialized ; list header (completely zero'd). Finally, it will not ; bother to do a string compare if the two pointers are ; the same. _lFindName2: movem.l A2/A3,-(sp) move.l D0,A1 tst.l (A1) ; uninitialized list header beq .fn2fail .fn2loop move.l (A1),A1 ; get first/next node tst.l (A1) ; end of list? beq .fn2fail move.l LN_NAME(A1),D0 ; name beq .fn2loop ; NULL, skip cmp.l D0,A0 ; pointers are the same! beq .fn2succ ; don't bother w/cmp. move.l D0,A2 move.l A0,A3 .fn2l2 cmpm.b (A2)+,(A3)+ bne .fn2loop tst.b -1(A2) bne .fn2l2 .fn2succ move.l A1,D0 movem.l (sp)+,A2/A3 rts .fn2fail moveq.l #0,D0 movem.l (sp)+,A2/A3 rts #endasm \Rogue\Monster\ else echo "will not over write src/misc.c" fi if [ `wc -c src/misc.c | awk '{printf $1}'` -ne 8171 ] then echo `wc -c src/misc.c | awk '{print "Got " $1 ", Expected " 8171}'` fi if `test ! -s src/newres.c` then echo "writing src/newres.c" cat > src/newres.c << '\Rogue\Monster\' /* *FUNC= GetRes A0 *FUNC= FreeRes A0 *FUNC= FreeAllRes A0 *FUNC= ChownRes D0/D1/A0 *FUNC= UnLinkAllRes A0 *FUNC= ReLinkAllRes A0 *FUNC= SetResFlags D0/D1/A0 *FUNC= AddRes D0/D1/D2/A0 *FUNC= RemRes A0 *FUNC= GetResInfo D0/D1/A0 *FUNC= GetResList D0/D1/D2/A0 *FUNC= GetFileList D0/D1/D2/A0 *FUNC= AddPrivResFile D0/D1 *FUNC= RemPrivResFiles A0 *FUNC= AddGlobResFile D0/D1 *FUNC= RemGlobResFiles A0 *FUNC= AddResSwapDir D0/D1/A0 *FUNC= RemResSwapDirs A0 *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - *FUNC= NULL - * */ #include <local/typedefs.h> #include <local/res.h> #include "file.h" /* * resptr = GetRes(resnametype) char *resnametype; * * (1) The resource is SHARED, is tagged with its name, then * (a) if swapped, swap in * (b) incr. ref. count. * (2) The resource is not shared, re-load from disk * */ GetRes(rnt) register char *rnt; { RMSG RMsg; register char *str; for (str = rnt + strlen(rnt); str >= rnt && *str != '.'; --str); RMsg.Arg1 = (long)rnt; RMsg.Arg2 = (long)str + 1; if ((RMsg.Arg3 = str - rnt) < 0) RMsg.Arg3 = 0; RMsg.Arg4 = strlen(str + 1); DoSyncMsg(&ResPort, &RMsg); return(RMsg.Res1); } 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"); 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. 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 meaning 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. \Rogue\Monster\ else echo "will not over write src/newres.c" fi if [ `wc -c src/newres.c | awk '{printf $1}'` -ne 7611 ] then echo `wc -c src/newres.c | awk '{print "Got " $1 ", Expected " 7611}'` fi if `test ! -s src/mem.asm` then echo "writing src/mem.asm" cat > src/mem.asm << '\Rogue\Monster\' ; MEM.ASM public _lBZero ; Zero a block of memory public _lBSet ; Set a block of memory to (byte val) public _lBMov ; move a block of memory public _lBCmp ; compare two blocks of memory ; BSET(buffer:D0, len:D1, byte:A0.B) ; BZERO(buffer:D0, len:D1) _lBZero: move.w #0,A0 _lBSet: exg A0,D0 ; A0 = buffer (D0=byte) exg D0,D1 ; D0 = length (D1=byte) add.l D0,A0 ; start at end of address cmp.l #40,D0 ; unscientifically chosen bls .bs2 bra .bs10 .bs1 move.b D1,-(A0) ; any count < 65536 .bs2 dbf D0,.bs1 rts ; at least 2 bytes in count (D0) .bs10 movem.l D2-D7/A2-A6,-(sp) ;ant count > 4 move.l A0,D2 btst.l #0,D2 ; is it aligned? beq .bs22 move.b D1,-(A0) ; no, copy one byte subq.l #1,D0 .bs22 andi.l #$FF,D1 ; expand data D1.B -> D2-D7/A1-A6 move.l D1,D2 ; D1 000000xx D2 000000xx asl.w #8,D2 ; 0000xx00 or.w D2,D1 ; 0000xxxx move.w D1,D2 ; 0000xxxx 0000xxxx swap D2 ; 0000xxxx xxxx0000 or.l D1,D2 ; D2.L move.l D2,D3 move.l D2,D4 move.l D2,D5 move.l D2,D6 move.l D2,D7 move.l D2,A1 move.l D2,A2 move.l D2,A3 move.l D2,A4 move.l D2,A5 move.l D2,A6 ; D2-D7/A1-A6 (12 registers) move.l #12*4,D1 ; bytes per transfer (48) .bs30 sub.l D1,D0 ; pre subtract bmi .bs40 .bs31 movem.l D2-D7/A1-A6,-(A0) sub.l D1,D0 bpl .bs31 .bs40 add.w D1,D0 ; less than 48 bytes remaining move.w #4,D1 ; by 4's sub.w D1,D0 bmi .bs50 .bs41 move.l D2,-(A0) sub.w D1,D0 bpl .bs41 .bs50 add.w D1,D0 bra .bs52 .bs51 move.b D2,-(A0) ; by 1's .bs52 dbf D0,.bs51 movem.l (sp)+,D2-D7/A2-A6 rts ; BCMP(src:D0, dst:D1, len:A0) _lBCmp: exg A0,D0 ;A0 = src, D0 = len exg A1,D1 ;A1 = dst tst.l D0 beq .bcsucc cmp.w D0,D0 ;force Z bit bra .bc2 .bc1 cmpm.b (A0)+,(A1)+ .bc2 dbne D0,.bc1 bne .bcfail sub.l #$10000,D0 bcc .bc1 .bcsucc moveq.l #1,D0 ;success! rts .bcfail moveq.l #0,D0 ;failure! rts ; BMOV(src:D0, dst:D1, len:A0) ; ; The memory move algorithm is somewhat more of a mess ; since we must do it either ascending or decending. _lBMov: exg A0,D0 ;A0 = src, D0 = len exg A1,D1 ;A1 = dst cmp.l A0,A1 beq .bmend bls .bmup .bmdown adda.l D0,A0 ;descending copy adda.l D0,A1 move.w A0,D1 ;CHECK WORD ALIGNED btst.l #0,D1 bne .bmdown1 move.w A1,D1 btst.l #0,D1 bne .bmdown1 cmp.l #259,D0 ;chosen by calculation. blo .bmdown8 move.l D0,D1 ;overhead for bmd44: ~360 divu #44,D1 bvs .bmdown8 ;too big (> 2,883,540) movem.l D2-D7/A2-A6,-(sp) ;use D2-D7/A2-A6 (11 regs) move.l #11*4,D0 bra .bmd44b .bmd44a sub.l D0,A0 ;8 total 214/44bytes movem.l (A0),D2-D7/A2-A6 ;12 + 8*11 4.86 cycles/byte movem.l D2-D7/A2-A6,-(A1) ; 8 + 8*11 .bmd44b dbf D1,.bmd44a ;10 swap D1 ;D0<15:7> already contain 0 move.w D1,D0 ;D0 = remainder movem.l (sp)+,D2-D7/A2-A6 .bmdown8 move.w D0,D1 ;D1<2:0> = #bytes left later lsr.l #3,D0 ;divide by 8 bra .bmd8b .bmd8a move.l -(A0),-(A1) ;20 total 50/8bytes move.l -(A0),-(A1) ;20 = 6.25 cycles/byte .bmd8b dbf D0,.bmd8a ;10 sub.l #$10000,D0 bcc .bmd8a move.w D1,D0 ;D0 = 0 to 7 bytes and.l #7,D0 bne .bmdown1 rts .bmd1a move.b -(A0),-(A1) ;12 total 22/byte .bmdown1 ; = 22 cycles/byte .bmd1b dbf D0,.bmd1a ;10 sub.l #$10000,D0 bcc .bmd1a rts .bmup move.w A0,D1 ;CHECK WORD ALIGNED btst.l #0,D1 bne .bmup1 move.w A1,D1 btst.l #0,D1 bne .bmup1 cmp.l #259,D0 ;chosen by calculation blo .bmup8 move.l D0,D1 ;overhead for bmu44: ~360 divu #44,D1 bvs .bmup8 ;too big (> 2,883,540) movem.l D2-D7/A2-A6,-(sp) ;use D2-D7/A2-A6 (11 regs) move.l #11*4,D0 bra .bmu44b .bmu44a movem.l (A0)+,D2-D7/A2-A6 ;12 + 8*11 ttl 214/44bytes movem.l D2-D7/A2-A6,(A1) ;8 + 8*11 4.86 cycles/byte add.l D0,A1 ;8 .bmu44b dbf D1,.bmu44a ;10 swap D1 ;D0<15:7> already contain 0 move.w D1,D0 ;D0 = remainder movem.l (sp)+,D2-D7/A2-A6 .bmup8 move.w D0,D1 ;D1<2:0> = #bytes left later lsr.l #3,D0 ;divide by 8 bra .bmu8b .bmu8a move.l (A0)+,(A1)+ ;20 total 50/8bytes move.l (A0)+,(A1)+ ;20 = 6.25 cycles/byte .bmu8b dbf D0,.bmu8a ;10 sub.l #$10000,D0 bcc .bmu8a move.w D1,D0 ;D0 = 0 to 7 bytes and.l #7,D0 bne .bmup1 rts .bmu1a move.b (A0)+,(A1)+ .bmup1 .bmu1b dbf D0,.bmu1a sub.l #$10000,D0 bcc .bmu1a .bmend rts \Rogue\Monster\ else echo "will not over write src/mem.asm" fi if [ `wc -c src/mem.asm | awk '{printf $1}'` -ne 4649 ] then echo `wc -c src/mem.asm | awk '{print "Got " $1 ", Expected " 4649}'` fi if `test ! -d util` then mkdir util echo "mkdir util" fi if `test ! -s util/gtd.c` then echo "writing util/gtd.c" cat > util/gtd.c << '\Rogue\Monster\' /* * GTD -GetTaskData/FreeTaskData tester * * Matthew Dillon, 30 Sep 1988 * * gtd - show task memlist entries * gtd <name> - remove an entry * gtd <name> <bytes> - add/retrieve an entry, display it, then * store sequential values into the buffer. */ #include <stdio.h> #include <local/typedefs.h> #include <local/xmisc.h> extern int Enable_Abort; extern char *GetTaskData(); main(ac,av) char *av[]; { char *ptr; long bytes; short i; TASK *task = FindTask(NULL); Enable_Abort = 0; if (openlibs(DRES_LIB) == 0) exit(1); if (ac == 1) { MEMLIST *ml; for (ml = GetHead(&task->tc_MemEntry); ml; ml = GetSucc(ml)) { printf("memlist %08lx %ld %s\n", ml, ml->ml_NumEntries, ((ml->ml_Node.ln_Name) ? ml->ml_Node.ln_Name : "NULL") ); } goto fail; } bytes = atoi(av[2]); printf("%s,%ld :", av[1], bytes); fflush(stdout); if (ac == 2) { printf("result %ld\n", FreeTaskData(av[1])); } else { ptr = GetTaskData(av[1], bytes); if (!ptr) { puts("failed"); goto fail; } printf("%08lx ", ptr); fflush(stdout); for (i = 0; i < bytes; ++i) { printf("%02x ", ptr[i]); ptr[i] = i; } } fail: closelibs(-1); } \Rogue\Monster\ else echo "will not over write util/gtd.c" fi if [ `wc -c util/gtd.c | awk '{printf $1}'` -ne 1238 ] then echo `wc -c util/gtd.c | awk '{print "Got " $1 ", Expected " 1238}'` fi if `test ! -s util/testipc.c` then echo "writing util/testipc.c" cat > util/testipc.c << '\Rogue\Monster\' /* * TESTIPC <appname> <file> <file> <file> ... <inputfile * * input file format: * * appname delay file text * */ #include <local/typedefs.h> #include <local/ipc.h> #include <local/xmisc.h> #include <stdio.h> extern int Enable_Abort; extern PORT *OpenIPC(); char **Av; short Ac; main(ac, av) char *av[]; { PORT *port; Av = av; Ac = ac; if (ac == 1) { puts("TESTIPC <appname> <subname> ... <subname> <inputfile"); puts("input file format:"); puts("<appname> <delay-1/50ths> <subname> <text>"); exit(1); } Enable_Abort = 0; if (openlibs(DRES_LIB) <= 0) { puts("Unable to open dres.library"); exit(1); } port = OpenIPC(av[1], 0); if (port == NULL) { puts("unable to open port"); closelibs(-1); exit(1); } printf("port: %08lx\n", port); { char apname[32]; long delay; char subname[32]; char text[64]; char tbuf[128]; IPCMSG msg; extern void handler(); BZero(&msg, sizeof(msg)); msg.Msg.mn_ReplyPort = CreatePort(NULL, 0); puts("scanf"); while (scanf("%s %ld %s %s", apname, &delay, subname, text) == 4) { printf("DO(%s %ld %s %s) ", apname, delay, subname, text); fflush(stdout); strcpy(tbuf, subname); strcpy(tbuf+strlen(subname)+1, text); msg.TBuf = (APTR)tbuf; msg.TLen = strlen(subname)+strlen(text)+2; DoIPC2(apname, &msg, handler, port); if (msg.RFlags & IF_NOTFND) { if (msg.RFlags & IF_NOAPP) puts("Application not found"); else puts("subname not found"); } else { if (msg.RFlags & IF_ERROR) printf("Error: %s\n", msg.RBuf); else printf("OK: %s\n", msg.RBuf); } FreeIPC(&msg); if (delay) Delay(delay); if (CheckPort(port)) handler(port); } DeletePort(msg.Msg.mn_ReplyPort); } CloseIPC(port); closelibs(-1); } void handler(port) PORT *port; { IPCMSG *msg; short i, j; while (msg = GetMsg(port)) { register char *ptr = (char *)msg->TBuf; printf("Received IPC command: %s ", ptr); for (j = 0; ptr[j] && ptr[j] != ' '; ++j); for (i = 2; i < Ac; ++i) { if (strlen(Av[i]) == j && strncmp(Av[i], ptr, j) == 0) break; } if (i < Ac) { puts("MATCH"); ReplyIPC(msg, "GotIt!", 7, 0); } else { puts("PASSED"); ReplyIPC(msg, "Failed", 7, IF_NOTFND); } } } \Rogue\Monster\ else echo "will not over write util/testipc.c" fi if [ `wc -c util/testipc.c | awk '{printf $1}'` -ne 2309 ] then echo `wc -c util/testipc.c | awk '{print "Got " $1 ", Expected " 2309}'` fi if `test ! -s util/test.c` then echo "writing util/test.c" cat > util/test.c << '\Rogue\Monster\' /* * TEST.C * * Test Library Functions. */ #include <typedefs.h> #include <stdio.h> typedef struct Library LIB; LIST ListA; LIST ListB; NODE Node1; NODE Node2; NODE Node3; short Glob; extern int Enable_Abort; LIB *DMiscSupportBase; extern LIB *OpenLibrary(); extern char *AllocMem(); extern char *GetHead(); extern char *GetTail(); extern char *GetSucc(); extern char *GetPred(); extern char *GetHeadOff(); extern char *GetTailOff(); extern char *GetSuccOff(); extern char *GetPredOff(); extern long srch(); main() { Enable_Abort = 0; DMiscSupportBase = OpenLibrary("dmiscsup.library", 0); if (!DMiscSupportBase) { puts("Unable to open library"); exit(1); } printf("library at: %08lx\n", DMiscSupportBase); printf("library flags: %02lx Rev: %ld OpenCnt: %ld\n", DMiscSupportBase->lib_Flags, DMiscSupportBase->lib_Revision, DMiscSupportBase->lib_OpenCnt ); NewList(&ListA); NewList(&ListB); AddTail(&ListA, &Node1); AddTail(&ListA, &Node2); AddTail(&ListA, &Node3); printf("\nGetHead() "); fflush(stdout); results((NODE *)GetHead(&ListA) == &Node1); results(GetHead(&ListB) == NULL); printf("\nGetTail() "); fflush(stdout); results((NODE *)GetTail(&ListA) == &Node3); results(GetTail(&ListB) == NULL); printf("\nGetSucc() "); fflush(stdout); results((NODE *)GetSucc(&Node1) == &Node2); results((NODE *)GetSucc(&Node3) == NULL); printf("\nGetPred() "); fflush(stdout); results((NODE *)GetPred(&Node3) == &Node2); results((NODE *)GetPred(&Node1) == NULL); printf("\nGetHeadOff() "); fflush(stdout); results(GetHeadOff(&ListA, 3) == (char *)&Node1 - 3); results(GetHeadOff(&ListB, 3) == NULL); printf("\nGetTailOff() "); fflush(stdout); results(GetTailOff(&ListA, 3) == (char *)&Node3 - 3); results(GetTailOff(&ListB, 3) == NULL); printf("\nGetSuccOff() "); fflush(stdout); results(GetSuccOff((char *)&Node1 - 3, 3) == (char *)&Node2 - 3); results(GetSuccOff((char *)&Node3 - 3, 3) == NULL); printf("\nGetPredOff() "); fflush(stdout); results(GetPredOff((char *)&Node2 - 3, 3) == (char *)&Node1 - 3); results(GetPredOff((char *)&Node1 - 3, 3) == NULL); printf("\nSearchFwdNode() "); fflush(stdout); Glob = 0; SearchFwdNodeOff(NULL, srch, 3, 27); results(Glob == 0); Glob = 0; SearchFwdNodeOff(GetHeadOff(&ListA, 3), srch, 3, 27); results(Glob == 3); printf("\nSearchRvsNode() "); fflush(stdout); Glob = 0; SearchRvsNodeOff(NULL, srch, 3, 27); results(Glob == 0); Glob = 0; SearchRvsNodeOff(GetTailOff(&ListA, 3), srch, 3, 27); results(Glob == 3); puts(""); wildtest(); memory_test(); RemLibrary(DMiscSupportBase); CloseLibrary(DMiscSupportBase); } results(bool) { if (bool) printf(" ok"); else printf(" fail"); fflush(stdout); } srch(sptr, arg) { ++Glob; printf("."); fflush(stdout); if (arg != 27) /* failure */ return(1); return(NULL); } /* * TEST: WildCmp() */ wildtest() { printf("WildCmp() "); fflush(stdout); results(WildCmp("a??b", "axeb") == 1); results(WildCmp("a??b", "axebx")== 0); results(WildCmp("*/x*y*b", "a/x/u/xcharliey/b") == 1); results(WildCmp("*/x*y*b", "a/x/u/xcharlieq/b") == 0); puts(""); } /* * TEST: BZero(), BSet(), BMov(), and BCmp(); */ memory_test() { long Size = 80000; /* MUST BE 80000 */ short result; short i; char *ary1 = AllocMem(Size, MEMF_PUBLIC); char *ary2 = AllocMem(Size, MEMF_PUBLIC); printf("\nTEST MEMORY SUBROUTINES:\n"); if (!ary1 || !ary2) { puts(" UNABLE TO ALLOCATE TWO CONTIGUOUS 80K SEGMENTS"); puts(" THUS, CANNOT PERFORM MEMORY ROUTINES TEST."); goto fail; } /* * Test BZero/BSet (both are the same subroutine, essentially). * Test: >64K, odd start, odd length. */ printf(" BZero(): "); fflush(stdout); xbset(ary1, Size, 43); xbset(ary2, Size, 43); printf("."); fflush(stdout); BZero(ary1 + 1000, 20); BZero(ary1 + 1200, 70000); BZero(ary2 + 512 + 3, 70000); printf("."); fflush(stdout); results(xbcheck(ary1, 1000, 43)); results(xbcheck(ary1 + 1000, 20, 0)); results(xbcheck(ary1 + 1020, 1200 - 1020, 43)); results(xbcheck(ary1 + 1200, 70000, 0)); results(xbcheck(ary1 + 1200 + 70000, Size - 1200 - 70000, 43)); printf("\n BSet(): "); fflush(stdout); xbset(ary1, Size, 43); xbset(ary2, Size, 43); printf("."); fflush(stdout); BSet(ary1 + 999, 21, 5); BSet(ary1 + 1201, 70001, 6); BSet(ary2 + 512 + 1, 69999, 7); printf("."); fflush(stdout); results(xbcheck(ary1, 999, 43)); results(xbcheck(ary1 + 999, 21, 5)); results(xbcheck(ary1 + 999 + 21, 1201 - 999 - 21, 43)); results(xbcheck(ary1 + 1201, 70001, 6)); results(xbcheck(ary1 + 1201 + 70001, Size - 1201 - 70001, 43)); results(xbcheck(ary2, 512 + 1, 43)); results(xbcheck(ary2 + 512 + 1, 69999, 7)); results(xbcheck(ary2 + 512 + 1 + 69999, Size - 69999 - 512 - 1, 43)); /* * TEST BMov(). Odd start, overlapping blocks in forward and * reverse. */ printf("\n BMov(): 1"); fflush(stdout); xbset(ary1, Size, 43); xbset(ary2, Size, 43); xbiset(ary1 + 1001, 69999, 1); xbiset(ary2 + 1003, 70001, 1); BMov(ary1 + 1001, ary1 + 997, 69999); BMov(ary2 + 1003, ary2 + 1008, 70001); results(xbicheck(ary1 + 997, 69999, 1)); results(xbicheck(ary2 + 1008, 70001, 1)); results(xbcheck(ary1, 997, 43)); results(xbcheck(ary1 + 1001 + 69999, Size - 1001 - 69999, 43)); results(xbcheck(ary2, 1003, 43)); results(xbcheck(ary2 + 1008 + 70001, Size - 1008 - 70001, 43)); printf("\n BMov(): 2"); fflush(stdout); xbset(ary1, Size, 43); xbset(ary2, Size, 43); xbiset(ary1 + 1024, 70000, 1); xbiset(ary2 + 1024, 70000, 1); BMov(ary1 + 1024, ary1 + 1004, 70000); BMov(ary2 + 1024, ary2 + 1044, 70000); results(xbicheck(ary1 + 1004, 70000, 1)); results(xbicheck(ary2 + 1044, 70000, 1)); results(xbcheck(ary1, 1004, 43)); results(xbcheck(ary1 + 1024 + 70000, Size - 70000 - 1024, 43)); results(xbcheck(ary2, 1024, 43)); results(xbcheck(ary1 + 1044 + 70000, Size - 70000 - 1044, 43)); puts(""); printf(" SPEEDTEST (K/sec BMov lw bndry, fastmem): %ld K/sec\n", speedtest(MEMF_FAST, 0, 0)); printf(" SPEEDTEST (K/sec BSet lw bndry, fastmem): %ld K/sec\n", speedtest(MEMF_FAST, 1, 0)); printf(" SPEEDTEST (K/sec BMov lw bndry, chipmem): %ld K/sec\n", speedtest(MEMF_CHIP, 0, 0)); printf(" SPEEDTEST (K/sec BSet lw bndry, chipmem): %ld K/sec\n", speedtest(MEMF_CHIP, 1, 0)); puts(""); printf(" SPEEDTEST (K/sec BMov by bndry, fastmem): %ld K/sec\n", speedtest(MEMF_FAST, 0, 1)); printf(" SPEEDTEST (K/sec BMov by bndry, chipmem): %ld K/sec\n", speedtest(MEMF_CHIP, 0, 1)); fail: if (ary1) FreeMem(ary1, Size); if (ary2) FreeMem(ary2, Size); } speedtest(memtype, zero, off) { char *buf = AllocMem(65536+256, memtype); short i; long s; if (!buf) return(0); s = ltm(); for (i = 0; i < 128; ++i) { if (zero) BSet(buf + off, 65536, 1); else BMov(buf + off, buf + 128 + off, 65536); } s = ltm() - s; /* 1/50ths second for 64K * 128 */ FreeMem(buf, 65536+256); return(64 * 128 * 50 / s); } ltm() { long st[3]; DateStamp(st); return(st[2] + 50 * 60 * st[1] + 50 * 60 * 60 * 24 * st[0]); } xbset(s, n, v) register char *s; register long n; register char v; { while (n--) *s++ = v; } xbiset(s, n, v) register char *s; register long n; register char v; { while (n--) { ++v; *s++ = v; } } xbcheck(s, n, v) register char *s; register long n; register char v; { char *orig = s; short errs = 255; while (n--) { if (*s++ != v) { if (errs) { --errs; printf("(%ld)", s - orig - 1); } else { printf("giveup"); return(0); } } } return(errs == 255); } xbicheck(s, n, v) register char *s; register long n; register char v; { char *orig = s; short errs = 255; while (n--) { ++v; if (*s++ != v) { if (errs) { --errs; printf("(%ld)", s - orig); } else { printf("giveup"); return(0); } } } return(errs == 255); } \Rogue\Monster\ else echo "will not over write util/test.c" fi if [ `wc -c util/test.c | awk '{printf $1}'` -ne 8363 ] then echo `wc -c util/test.c | awk '{print "Got " $1 ", Expected " 8363}'` fi if `test ! -s util/qtest.c` then echo "writing util/qtest.c" cat > util/qtest.c << '\Rogue\Monster\' /* * QTEST.C */ #include <typedefs.h> #include <stdio.h> typedef struct Library LIB; LIB *DMiscSupportBase; long QHan; long Count; long EnErr; long Error; extern LIB *OpenLibrary(); extern TASK *FindTask(); handler(arg) { printf("ARG: %ld ************\n", arg); } main() { int i; DMiscSupportBase = OpenLibrary("dmiscsup.library", 0); if (!DMiscSupportBase) { puts("Unable to open library"); exit(1); } puts("Q-TEST"); QHan = OpenQInts(); if (!QHan) { puts("Unable to alloc. q ints"); CloseLibrary(DMiscSupportBase); exit(1); } printf("QHAn= %08lx\n", QHan); puts("UnSetting NULL vector"); SetQVector(QHan, NULL, SIGBREAKB_CTRL_E, 0, 0); puts("Setting ^D vector"); SetQVector(QHan, handler, SIGBREAKB_CTRL_D, 30, -20); puts("UnSetting NULL vector"); SetQVector(QHan, NULL, SIGBREAKB_CTRL_E, 0, 0); puts("Loop"); for (i = 0; i < 100; ++i) { char oldpri = SetQPri(QHan, 127); EnErr = 1; printf("%ld cnt = %ld error = %ld (old=%ld) %08lx %08lx\n", i, Count, Error, oldpri, SetSignal(0,0), FindTask(NULL)->tc_SigExcept ); EnErr = 0; SetQPri(QHan, oldpri); } puts("UnSetting NULL vector"); SetQVector(QHan, NULL, SIGBREAKB_CTRL_E, 0, 0); printf("%ld cnt = %ld error = %ld\n", i, Count, Error); puts("closing"); CloseQInts(QHan); puts("closelib"); RemLibrary(DMiscSupportBase); CloseLibrary(DMiscSupportBase); } \Rogue\Monster\ else echo "will not over write util/qtest.c" fi if [ `wc -c util/qtest.c | awk '{printf $1}'` -ne 1448 ] then echo `wc -c util/qtest.c | awk '{print "Got " $1 ", Expected " 1448}'` fi if `test ! -s util/testarg.c` then echo "writing util/testarg.c" cat > util/testarg.c << '\Rogue\Monster\' /* * * */ #include <local/xmisc.h> extern int Enable_Abort; char * getv(name) char *name; { printf("GET: '%s'\n", name); return("VAR"); } freev(str) char *str; { printf("FREE: %s\n", str); } main(ac,av) char *av[]; { char buf[256]; char **Av; short Ac; long error; Enable_Abort = 0; openlibs(DRES_LIB); while (gets(buf)) { printf("Cmd: %s\n", buf); Ac = ParseCmd(buf, &Av, getv, freev, &error, NULL); printf("%08lx %ld\n", Av, Ac); if (error) { printf("ERROR!: %08lx\n", error); } if (Av) { short i; for (i = 0; i < Ac; ++i) printf("%2ld: (%ld) \"%s\"\n", i, Av[i][-1], Av[i]); puts("free"); FreeParseCmd(Av); puts("ok"); } } closelibs(-1); } \Rogue\Monster\ else echo "will not over write util/testarg.c" fi if [ `wc -c util/testarg.c | awk '{printf $1}'` -ne 743 ] then echo `wc -c util/testarg.c | awk '{print "Got " $1 ", Expected " 743}'` fi if `test ! -s util/x.c` then echo "writing util/x.c" cat > util/x.c << '\Rogue\Monster\' long Base; main(ac,av) char *av[]; { int ver = atoi(av[1]); Base = OpenLibrary("dres.library", ver); if (Base) { CloseLibrary(Base); puts("openned ok"); } else { puts("open failed"); } } \Rogue\Monster\ else echo "will not over write util/x.c" fi if [ `wc -c util/x.c | awk '{printf $1}'` -ne 215 ] then echo `wc -c util/x.c | awk '{print "Got " $1 ", Expected " 215}'` fi echo "Finished archive 1 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.