home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 1
/
FishNMoreVol1.bin
/
more
/
code_examples
/
device
/
device.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-10-23
|
27KB
|
1,044 lines
/*
* DOSDEVICE.C
*
* EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C PUBLIC DOMAIN.
*
* By Matthew Dillon.
*
* Debugging routines are disabled by simply attempting to access the
* file "debugoff"
*/
#include "dos.h"
/*
* Since this code might be called as a processes multiple times, or
* might exit and be recalled later by DOS, you CANNOT ASSUME GLOBALS
* HAVE BEEN ZERO'D!!!. This also goes for static assignments that
* running the code might change.
*/
PROC *DosProc;
DEVNODE *DosNode;
long SysBase;
long DOSBase;
RAMFILE RFRoot; /* Directory/File structure (root node) */
LIST FHBase; /* Open Files */
LIST LCBase; /* Open Locks */
long TotalBytes;
/* DEBUGGING */
PORT *Dbport; /* owned by the debug process */
PORT *Dback; /* owned by the DOS device driver */
short DBDisable;
MSG DummyMsg;
void
noname()
{
register PACKET *packet;
register short error;
MSG *msg;
ubyte notdone;
ubyte buf[256];
void *tmp;
/*
* Initialize all global variables. SysBase MUST be initialized before
* we can make Exec calls. AbsExecBase is a library symbol
* referencing absolute memory location 4. The DOS library is openned
* for the debug process.
*/
DBDisable = 0;
Dbport = Dback = NULL;
TotalBytes = 0;
SysBase = AbsExecBase;
DOSBase = OpenLibrary("dos.library",0);
DosProc = FindTask(NULL);
{
WaitPort(&DosProc->pr_MsgPort); /* Startup Packet */
msg = GetMsg(&DosProc->pr_MsgPort);
packet = (PACKET *)msg->mn_Node.ln_Name;
/*
* Loading DosNode->dn_Task causes DOS *NOT* to startup a new
* instance of the device driver for every reference. E.G. if
* you were writing a CON device you would want this field to
* be NULL.
*/
if (DOSBase) {
DosNode = BTOC(packet->dp_Arg3);
DosNode->dn_Task = &DosProc->pr_MsgPort;
packet->dp_Res1 = DOS_TRUE;
packet->dp_Res2 = 0;
} else {
packet->dp_Res1 = DOS_FALSE;
returnpacket(packet);
return;
}
returnpacket(packet);
}
/* DEBUGGING */
dbinit(); /* this can be removed */
/* Initialize RAM disk */
{
ubyte *ptr = BTOC(DosNode->dn_Name);
short len = *ptr;
NewList(&FHBase);
NewList(&LCBase);
bzero(&RFRoot,sizeof(RFRoot));
RFRoot.type = FILE_DIR;
NewList(&RFRoot.list);
RFRoot.name = AllocMem(len+1, MEMF_PUBLIC);
bmov(ptr+1,RFRoot.name,len);
RFRoot.name[len] = 0;
dbprintf("ROOT NAME: %ld '%s'\n", len, RFRoot.name);
}
top:
for (notdone = 1; notdone;) {
WaitPort(&DosProc->pr_MsgPort);
stats();
while (msg = GetMsg(&DosProc->pr_MsgPort)) {
register ubyte *ptr;
packet = (PACKET *)msg->mn_Node.ln_Name;
packet->dp_Res1 = DOS_TRUE;
packet->dp_Res2 = 0;
error = 0;
dbprintf("Packet: %3ld %08lx %08lx %08lx %08lx\n",
packet->dp_Type, packet->dp_Arg1, packet->dp_Arg2, packet->dp_Arg3, packet->dp_Arg4
);
switch(packet->dp_Type) {
case ACTION_DIE: /* attempt to die? */
notdone = 0;
break;
case ACTION_OPENRW: /* FileHandle,Lock,Name Bool */
case ACTION_OPENOLD: /* FileHandle,Lock,Name Bool */
case ACTION_OPENNEW: /* FileHandle,Lock,Name Bool */
{
register RAMFILE *ramfile;
RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
char *ptr;
btos(packet->dp_Arg3,buf);
if (strcmp(buf,"debugoff") == 0)
DBDisable = 1;
if (strcmp(buf,"debugon") == 0)
DBDisable = 0;
if (ramfile = searchpath(&parentdir,buf,&ptr)) {
dbprintf("Found: parentdir %08lx tail '%s'\n", parentdir, ptr);
if (ramfile->type == FILE_DIR) {
error = ERROR_OBJECT_WRONG_TYPE;
goto openbreak;
}
if (ramfile->locks < 0) {
error = ERROR_OBJECT_IN_USE;
goto openbreak;
}
if (packet->dp_Type == ACTION_OPENOLD) {
++ramfile->locks;
} else {
if (ramfile->locks > 0) {
error = ERROR_OBJECT_IN_USE;
} else {
if (packet->dp_Type == ACTION_OPENNEW)
freedata(ramfile);
--ramfile->locks;
}
}
} else {
dbprintf("Not found..");
if (!parentdir) {
error = ERROR_INVALID_COMPONENT_NAME;
goto openbreak;
}
if (packet->dp_Type == ACTION_OPENNEW) {
ramfile = createramfile(parentdir, FILE_FILE, ptr);
--ramfile->locks;
dbprintf("adding file %08lx '%s'\n", ramfile, ramfile->name);
} else {
error = ERROR_OBJECT_NOT_FOUND;
}
}
if (!error) {
register MYFH *mfh = AllocMem(sizeof(MYFH), MEMF_PUBLIC|MEMF_CLEAR);
((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long)mfh;
dbprintf("SET FH-ARG1 to %08lx\n", mfh);
mfh->file = ramfile;
mfh->fentry = GetHead(&ramfile->list);
AddHead(&FHBase,mfh);
}
}
openbreak:
if (!GetHead(&FHBase) && !GetHead(&LCBase))
notdone = 0;
break;
case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */
{
register MYFH *mfh = (MYFH *)packet->dp_Arg1;
register FENTRY *fen = mfh->fentry;
register ubyte *ptr = (ubyte *)packet->dp_Arg2;
register long left = packet->dp_Arg3;
register long scr;
dbprintf("READ Seek:%ld MFH:%08lx FEN:%08lx\n", mfh->base + mfh->offset, mfh, fen);
while (left && fen) {
scr = fen->bytes - mfh->offset;
dbprintf(" %ld bytes avail to read. req %ld\n", scr, left);
if (left < scr) {
bmov(fen->buf + mfh->offset, ptr, left);
mfh->offset += left;
left = 0;
} else {
bmov(fen->buf + mfh->offset, ptr, scr);
left -= scr;
ptr += scr;
mfh->base += fen->bytes;
mfh->offset = 0;
fen = NextNode(fen);
}
}
mfh->fentry = fen;
packet->dp_Res1 = packet->dp_Arg3 - left;
}
break;
case ACTION_WRITE: /* FHArg1,CPTRBuffer,Length ActLength */
{
register MYFH *mfh = (MYFH *)packet->dp_Arg1;
register FENTRY *fen = (FENTRY *)mfh->fentry;
register ubyte *ptr = (ubyte *)packet->dp_Arg2;
register long left = packet->dp_Arg3;
register long scr;
dbprintf("MFH: %08lx\n", mfh);
while (left) {
if (fen) {
dbprintf("WRITE: %ld FEN %ld\n", left, fen->bytes);
scr = fen->bytes - mfh->offset;
if (left < scr) {
bmov(ptr, fen->buf + mfh->offset, left);
mfh->offset += left;
left = 0;
} else {
bmov(ptr, fen->buf + mfh->offset, scr);
ptr += scr;
left -= scr;
mfh->base += fen->bytes;
mfh->offset = 0;
fen = NextNode(fen);
}
} else {
dbprintf("WRITE: %ld NOFEN\n", left);
fen = AllocMem(sizeof(FENTRY), MEMF_PUBLIC);
fen->buf = AllocMem(left, MEMF_PUBLIC);
fen->bytes = left;
mfh->file->bytes += left;
mfh->base += left;
mfh->offset = 0;
TotalBytes += left;
AddTail(&mfh->file->list, fen);
bmov(ptr, fen->buf, left);
left = 0;
fen = NULL; /* cause append */
}
}
packet->dp_Res1 = packet->dp_Arg3 - left;
mfh->fentry = fen;
}
break;
case ACTION_CLOSE: /* FHArg1 Bool:TRUE */
{
register MYFH *mfh = (MYFH *)packet->dp_Arg1;
register RAMFILE *file = mfh->file;
Remove(mfh);
FreeMem(mfh,sizeof(*mfh));
if (--file->locks < 0)
file->locks = 0;
}
if (!GetHead(&FHBase) && !GetHead(&LCBase))
notdone = 0;
break;
case ACTION_SEEK: /* FHArg1,Position,Mode OldPosition*/
{
register MYFH *mfh = (MYFH *)packet->dp_Arg1;
register FENTRY *fen;
register long absseek;
packet->dp_Res1 = mfh->base + mfh->offset;
absseek = packet->dp_Arg2;
if (packet->dp_Arg3 == 0)
absseek += mfh->base + mfh->offset;
if (packet->dp_Arg3 == 1)
absseek = mfh->file->bytes + absseek;
if (absseek < 0 || absseek > mfh->file->bytes) {
error = ERROR_SEEK_ERROR;
break;
}
mfh->base = mfh->offset = 0;
/*
* Stupid way to do it but....
*/
for (fen = GetHead(&mfh->file->list); fen; fen = NextNode(fen)) {
if (mfh->base + fen->bytes > absseek) {
mfh->offset = absseek - mfh->base;
break;
}
mfh->base += fen->bytes;
}
mfh->fentry = fen;
}
break;
case ACTION_EXAMINE_NEXT: /* Lock,Fib Bool */
{
register FIB *fib = BTOC(packet->dp_Arg2);
register RAMFILE *file = getlockfile(packet->dp_Arg1);
if (file->type == FILE_FILE) {
error = ERROR_OBJECT_WRONG_TYPE;
break;
}
if (fib->fib_DiskKey == NULL) {
error = ERROR_NO_MORE_ENTRIES;
break;
}
file = (RAMFILE *)fib->fib_DiskKey;
fib->fib_DiskKey = (long)NextNode(file);
tmp = file;
error = -1;
}
/* fall through */
case ACTION_EXAMINE_OBJECT: /* Lock,Fib Bool */
{
register FIB *fib;
register RAMFILE *file;
fib = BTOC(packet->dp_Arg2);
if (error) {
file = tmp;
} else {
file = getlockfile(packet->dp_Arg1);
fib->fib_DiskKey = (long)GetHead(&file->list);
}
error = 0;
fib->fib_DirEntryType = file->type;
strcpy(fib->fib_FileName+1, file->name);
fib->fib_FileName[0] = strlen(file->name);
fib->fib_Protection = file->protection;
fib->fib_EntryType = NULL;
fib->fib_Size = file->bytes;
fib->fib_NumBlocks = file->bytes >> 9;
fib->fib_Date = file->date;
if (file->comment) {
strcpy(fib->fib_Comment+1, file->comment);
fib->fib_Comment[0] = strlen(file->comment);
} else {
fib->fib_Comment[0] = 0;
}
}
break;
case ACTION_INFO: /* Lock, InfoData Bool:TRUE */
tmp = BTOC(packet->dp_Arg2);
error = -1;
/* fall through */
case ACTION_DISK_INFO: /* InfoData Bool:TRUE */
{
register INFODATA *id;
/*
* Note: id_NumBlocks is never 0, but only to get
* around a bug I found in my shell (where I divide
* by id_NumBlocks)
*/
(error) ? (id = tmp) : (id = BTOC(packet->dp_Arg1));
error = 0;
bzero(id, sizeof(*id));
id->id_DiskState = ID_VALIDATED;
id->id_NumBlocks = (TotalBytes >> 9) + 1;
id->id_NumBlocksUsed = (TotalBytes >> 9) + 1;
id->id_BytesPerBlock = 512;
id->id_DiskType = ID_DOS_DISK;
id->id_VolumeNode = (long)CTOB(DosNode);
id->id_InUse = (long)GetHead(&LCBase);
}
break;
case ACTION_PARENT: /* Lock ParentLock */
{
register RAMFILE *file = getlockfile(packet->dp_Arg1);
if (file->type == FILE_FILE) {
error = ERROR_OBJECT_NOT_FOUND;
break;
}
if (file->locks < 0) {
error = ERROR_OBJECT_IN_USE;
break;
}
if (file->parent)
packet->dp_Res1 = (long)CTOB(ramlock(file->parent, ACCESS_READ));
else
error = ERROR_OBJECT_NOT_FOUND;
}
break;
case ACTION_DELETE_OBJECT: /*Lock,Name Bool */
{
RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
RAMFILE *ramfile;
btos(packet->dp_Arg2, buf);
if (ramfile = searchpath(&parentdir,buf,NULL)) {
if (ramfile->locks || ramfile == &RFRoot) {
error = ERROR_OBJECT_IN_USE;
break;
}
if (ramfile->type == FILE_DIR) {
if (GetHead(&ramfile->list))
error = ERROR_DIRECTORY_NOT_EMPTY;
} else {
freedata(ramfile);
}
if (!error)
freeramfile(ramfile);
} else {
if (!parentdir)
error = ERROR_INVALID_COMPONENT_NAME;
else
error = ERROR_OBJECT_NOT_FOUND;
}
}
if (!GetHead(&FHBase) && !GetHead(&LCBase))
notdone = 0;
break;
case ACTION_CREATE_DIR: /* Lock,Name Lock */
{
RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
RAMFILE *ramfile;
char *ptr;
btos(packet->dp_Arg2, buf);
if (ramfile = searchpath(&parentdir,buf,&ptr)) {
error = ERROR_OBJECT_EXISTS;
break;
}
if (!parentdir) {
error = ERROR_INVALID_COMPONENT_NAME;
break;
}
ramfile = createramfile(parentdir, FILE_DIR, ptr);
packet->dp_Res1 = (long)CTOB(ramlock(ramfile, ACCESS_WRITE));
}
break;
case ACTION_LOCATE_OBJECT: /* Lock,Name,Mode Lock */
{
RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
RAMFILE *ramfile;
btos(packet->dp_Arg2, buf);
if (ramfile = searchpath(&parentdir,buf,NULL)) {
if (ramfile->locks < 0 || (ramfile->locks && packet->dp_Arg3 == ACCESS_WRITE)) {
error = ERROR_OBJECT_IN_USE;
break;
}
packet->dp_Res1 = (long)CTOB(ramlock(ramfile, packet->dp_Arg3));
} else {
if (!parentdir)
error = ERROR_INVALID_COMPONENT_NAME;
else
error = ERROR_OBJECT_NOT_FOUND;
}
}
break;
case ACTION_COPY_DIR: /* Lock, Lock */
{
register RAMFILE *ramfile = getlockfile(packet->dp_Arg1);
if (ramfile->locks < 0)
error = ERROR_OBJECT_IN_USE;
else
packet->dp_Res1 = (long)CTOB(ramlock(ramfile, ACCESS_READ));
}
break;
case ACTION_FREE_LOCK: /* Lock, Bool */
if (packet->dp_Arg1);
ramunlock(BTOC(packet->dp_Arg1));
if (!GetHead(&FHBase) && !GetHead(&LCBase))
notdone = 0;
break;
case ACTION_SET_PROTECT:/* -,Lock,Name,Mask Bool */
{
register RAMFILE *ramfile;
RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
char *ptr;
btos(packet->dp_Arg3, buf);
if (ramfile = searchpath(&parentdir,buf,&ptr)) {
ramfile->protection = packet->dp_Arg4;
} else {
if (parentdir)
error = ERROR_OBJECT_NOT_FOUND;
else
error = ERROR_INVALID_COMPONENT_NAME;
}
}
break;
case ACTION_SET_COMMENT:/* -,Lock,Name,Comment Bool */
{
register RAMFILE *ramfile;
RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
char *ptr;
btos(packet->dp_Arg3, buf);
if (ramfile = searchpath(&parentdir,buf,&ptr)) {
btos(packet->dp_Arg4, buf);
if (ramfile->comment)
FreeMem(ramfile->comment,strlen(ramfile->comment)+1);
ramfile->comment = AllocMem(strlen(buf)+1, MEMF_PUBLIC);
strcpy(ramfile->comment, buf);
} else {
if (parentdir)
error = ERROR_OBJECT_NOT_FOUND;
else
error = ERROR_INVALID_COMPONENT_NAME;
}
}
break;
case ACTION_RENAME_OBJECT:/* SLock,SName,DLock,DName Bool */
{
register RAMFILE *file1, *file2;
RAMFILE *sourcedir = getlockfile(packet->dp_Arg1);
RAMFILE *destdir = getlockfile(packet->dp_Arg3);
char *ptr;
btos(packet->dp_Arg2,buf);
if (file1 = searchpath(&sourcedir,buf,NULL)) {
btos(packet->dp_Arg4,buf);
if (file2 = searchpath(&destdir,buf,&ptr)) {
error = ERROR_OBJECT_EXISTS;
} else {
if (destdir) {
Remove(file1);
AddTail(&destdir->list, file1);
FreeMem(file1->name,strlen(file1->name)+1);
file1->name = AllocMem(strlen(ptr)+1,MEMF_PUBLIC);
strcpy(file1->name,ptr);
} else {
error = ERROR_INVALID_COMPONENT_NAME;
}
}
} else {
if (sourcedir)
error = ERROR_OBJECT_NOT_FOUND;
else
error = ERROR_INVALID_COMPONENT_NAME;
}
}
break;
/*
* A few other packet types which we do not support
*/
case ACTION_RENAME_DISK:/* BSTR:NewName Bool */
case ACTION_MORECACHE: /* #BufsToAdd Bool */
case ACTION_INHIBIT: /* Bool Bool */
case ACTION_WAIT_CHAR: /* Timeout, ticks Bool */
case ACTION_FLUSH: /* writeout bufs, disk motor off */
case ACTION_RAWMODE: /* Bool(-1:RAW 0:CON) OldState */
default:
error = ERROR_ACTION_NOT_KNOWN;
break;
}
if (packet) {
if (error) {
packet->dp_Res1 = DOS_FALSE;
packet->dp_Res2 = error;
}
returnpacket(packet);
}
}
}
dbprintf("REMOVING DOS DEVICE");
Delay(50); /* I wanna even see the debug message! */
Forbid();
if (packetsqueued(DosProc) || GetHead(&FHBase) || GetHead(&LCBase)
|| GetHead(&RFRoot.list)) {
Permit();
dbprintf("Not ready to die yet!\n");
goto top; /* sorry... can't exit */
}
DosNode->dn_Task = FALSE;
dbuninit();
CloseLibrary(DOSBase);
}
/*
* PACKET ROUTINES. Dos Packets are in a rather strange format as you
* can see by this and how the PACKET structure is extracted in the
* GetMsg() of the main routine.
*/
void
returnpacket(packet)
register struct DosPacket *packet;
{
register struct Message *mess;
register struct MsgPort *replyport;
replyport = packet->dp_Port;
mess = packet->dp_Link;
packet->dp_Port = &DosProc->pr_MsgPort;
mess->mn_Node.ln_Name = (char *)packet;
mess->mn_Node.ln_Succ = NULL;
mess->mn_Node.ln_Pred = NULL;
PutMsg(replyport, mess);
}
/*
* Are there any packets queued to our device?
*/
packetsqueued()
{
return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
(void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
}
/*
* DOS MEMORY ROUTINES
*
* DOS makes certain assumptions about LOCKS. A lock must minimally be
* a FileLock structure, with additional private information after the
* FileLock structure. The longword before the beginning of the structure
* must contain the length of structure + 4.
*/
void *
dosalloc(bytes)
register ulong bytes;
{
register ulong *ptr;
bytes += 4;
ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
*ptr = bytes;
return(ptr+1);
}
dosfree(ptr)
register ulong *ptr;
{
--ptr;
FreeMem(ptr, *ptr);
}
/*
* Convert a BSTR into a normal string.. copying the string into buf
*/
void
btos(bstr,buf)
ubyte *bstr;
ubyte *buf;
{
bstr = BTOC(bstr);
bmov(bstr+1,buf,*bstr);
buf[*bstr] = 0;
dbprintf("btos: %ld %s\n", *bstr, buf);
}
void *
NextNode(node)
NODE *node;
{
node = node->mln_Succ;
if (node->mln_Succ == NULL)
return(NULL);
return(node);
}
void *
GetHead(list)
LIST *list;
{
if ((void *)list->mlh_Head != (void *)&list->mlh_Tail)
return(list->mlh_Head);
return(NULL);
}
nccmp(p1,p2,n)
register ubyte *p1, *p2;
register short n;
{
while (--n >= 0) {
if ((p1[n]|0x20) != (p2[n]|0x20))
return(0);
}
return(1);
}
/*
* Create a file or directory and link it into it's parent directory.
*/
RAMFILE *
createramfile(parentdir, type, name)
RAMFILE *parentdir;
char *name;
{
register RAMFILE *ramfile;
ramfile = AllocMem(sizeof(RAMFILE), MEMF_CLEAR|MEMF_PUBLIC);
AddTail(&parentdir->list, ramfile);
ramfile->parent = parentdir;
ramfile->name = AllocMem(strlen(name)+1, MEMF_PUBLIC);
strcpy(ramfile->name, name);
ramfile->type = type;
ramfile->protection = 0;
NewList(&ramfile->list);
/* SET DATE! */
return(ramfile);
}
/*
* Free all data associated with a file
*/
void
freedata(ramfile)
RAMFILE *ramfile;
{
FENTRY *fen;
TotalBytes -= ramfile->bytes;
while (fen = RemHead(&ramfile->list)) {
FreeMem(fen->buf, fen->bytes);
FreeMem(fen, sizeof(*fen));
}
ramfile->bytes = 0;
}
/*
* Any data associated with the file or directory has already been
* freed up.
*/
void
freeramfile(ramfile)
RAMFILE *ramfile;
{
Remove(ramfile); /* unlink from parent directory */
FreeMem(ramfile->name,strlen(ramfile->name)+1);
if (ramfile->comment)
FreeMem(ramfile->comment,strlen(ramfile->comment)+1);
FreeMem(ramfile,sizeof(*ramfile));
}
MYLOCK *
ramlock(ramfile, mode)
RAMFILE *ramfile;
{
MYLOCK *lock = dosalloc(sizeof(MYLOCK));
AddHead(&LCBase,&lock->node);
lock->lock.fl_Access = mode;
lock->lock.fl_Task = &DosProc->pr_MsgPort;
lock->lock.fl_Volume = (BPTR)CTOB(DosNode);
lock->file = ramfile;
if (mode == ACCESS_READ)
++ramfile->locks;
else
ramfile->locks = -1;
return(lock);
}
void
ramunlock(lock)
MYLOCK *lock;
{
RAMFILE *file = lock->file;
Remove(&lock->node);
if (lock->lock.fl_Access == ACCESS_READ)
--file->locks;
else
file->locks = 0;
dosfree(lock);
}
/*
* GETLOCKFILE(bptrlock)
*
* Return the RAMFILE entry (file or directory) associated with the
* given lock, which is passed as a BPTR.
*
* According to the DOS spec, the only way a NULL lock will ever be
* passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
* In anycase, If a NULL lock is passed to me I simply assume it means
* the root directory of the RAM disk.
*/
RAMFILE *
getlockfile(lock)
void *lock; /* actually BPTR to MYLOCK */
{
if (lock)
return(((MYLOCK *)BTOC(lock))->file);
return(&RFRoot);
}
/*
* Search the specified path beginning at the specified directory.
* The directory pointer is updated to the directory containing the
* actual file. Return the file node or NULL if not found. If the
* path is illegal (an intermediate directory was not found), set *ppar
* to NULL and return NULL.
*
* *ppar may also be set to NULL if the search path IS the root.
*
* If pptr not NULL, Set *pptr to the final component in the path.
*/
RAMFILE *
searchpath(ppar,buf,pptr)
RAMFILE **ppar;
char *buf;
char **pptr;
{
RAMFILE *file = *ppar;
RAMFILE *srch;
short len;
char *ptr;
dbprintf("searchpath: '%s'\n", buf);
*ppar = NULL;
for (;*buf && file;) {
ptr = getpathelement(&buf,&len);
if (buf[0] == ':') { /* go to root */
dbprintf("colon element\n");
++buf;
file = &RFRoot;
continue;
}
if (*ptr == '/') { /* go back a directory */
if (!file->parent) { /* no parent directory */
dbprintf("Backdir.. no parent\n");
return(NULL);
}
file = file->parent;
dbprintf("backdir: file %08lx (%s)\n", file, file->name);
continue;
}
if (file->type == FILE_FILE)
return(NULL);
for (srch = GetHead(&file->list); srch; srch = NextNode(srch)) {
if (strlen(srch->name) == len && nccmp(srch->name, ptr, len)) {
file = srch; /* element found */
break;
}
}
if (srch == NULL) {
if (*buf == 0) { /* Element not found. If it was the final */
*ppar = file; /* element the parent directory is valid */
dbprintf("element not found.. ok\n");
} else {
dbprintf("element not found.. path error\n");
}
if (pptr)
*pptr = ptr;
return(NULL);
}
}
if (pptr)
*pptr = ptr;
*ppar = file->parent;
dbprintf("DONE. File %08lx (%s) parent %08lx\n", file, file->name, file->parent);
return(file);
}
/*
* Return the next path element in the string. The routine effectively
* removes any trailing '/'s, but treats ':' as part of the next component
* (i.e. ':' is checked and skipped in SEARCHPATH()).
*/
char *
getpathelement(pstr,plen)
char **pstr;
short *plen;
{
char *base;
register char *ptr = *pstr;
register short len = 0;
if (*(base = ptr)) {
if (*ptr == '/') {
++ptr;
++len;
} else {
while (*ptr && *ptr != '/' && *ptr != ':') {
++ptr;
++len;
}
if (*ptr == '/')
++ptr;
}
}
*pstr = ptr;
*plen = len;
dbprintf("PATH ELEMENT: %ld '%s' next@ '%s'\n", len, base, ptr);
return(base);
}
stats()
{
register RAMFILE *file;
register MYFH *mfh;
for (file = GetHead(&RFRoot.list); file; file = NextNode(file)) {
dbprintf("Root entry: %08lx %s %ld\n", file, file->name, file->bytes);
}
for (mfh = GetHead(&FHBase); mfh; mfh = NextNode(mfh)) {
dbprintf("Openfile: %08lx %s @%ld %ld\n", mfh->file, mfh->file->name, mfh->base, mfh->offset);
}
/*
* Note that the NODE entry in the MYLOCK structure is not (cannot) be
* at the beginning of the structure and thus if you want to traverse
* the active lock list you must subtract it's position in the
* structure from any list pointers.
*/
if (GetHead(&LCBase)) {
dbprintf("ACTIVE LOCKS DO EXIST\n");
}
dbprintf("\n");
}
/*
* DEBUGGING CODE. You cannot make DOS library calls that access other
* devices from within a DOS device driver because they use the same
* message port as the driver. If you need to make such calls you must
* create a port and construct the DOS messages yourself. I do not
* do this. To get debugging info out another PROCESS is created to which
* debugging messages can be sent.
*
* You want the priority of the debug process to be larger than the
* priority of your DOS handler. This is so if your DOS handler crashes
* you have a better idea of where it died from the debugging messages
* (remember that the two processes are asyncronous from each other).
*/
extern void debugproc();
dbinit()
{
TASK *task = FindTask(NULL);
Dback = CreatePort(NULL,NULL);
CreateProc("DEV_DB", task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096);
WaitPort(Dback); /* handshake startup */
GetMsg(Dback); /* remove dummy msg */
dbprintf("Debugger running V1.00\n");
}
dbuninit()
{
MSG killmsg;
if (Dbport) {
killmsg.mn_Length = 0; /* 0 means die */
PutMsg(Dbport,&killmsg);
WaitPort(Dback); /* He's dead jim! */
GetMsg(Dback);
DeletePort(Dback);
/*
* Since the debug process is running at a greater priority, I
* am pretty sure that it is guarenteed to be completely removed
* before this task gets control again. Still, it doesn't hurt...
*/
Delay(50); /* ensure he's dead */
}
}
dbprintf(a,b,c,d,e,f,g,h,i,j)
{
char buf[256];
MSG *msg;
if (Dbport && !DBDisable) {
sprintf(buf,a,b,c,d,e,f,g,h,i,j);
msg = AllocMem(sizeof(MSG)+strlen(buf)+1, MEMF_PUBLIC|MEMF_CLEAR);
msg->mn_Length = strlen(buf)+1; /* Length NEVER 0 */
strcpy(msg+1,buf);
PutMsg(Dbport,msg);
}
}
/*
* BTW, the DOS library used by debugmain() was actually openned by
* the device driver. Note: DummyMsg cannot be on debugmain()'s stack
* since debugmain() goes away on the final handshake.
*/
debugmain()
{
MSG *msg;
short len;
void *fh;
Dbport = CreatePort(NULL,NULL);
fh = Open("con:0/0/640/100/debugwindow", 1006);
PutMsg(Dback, &DummyMsg);
for (;;) {
WaitPort(Dbport);
msg = GetMsg(Dbport);
len = msg->mn_Length;
if (len == 0)
break;
--len; /* Fix length up */
Write(fh, msg+1, len);
FreeMem(msg,sizeof(MSG)+len+1);
}
Close(fh);
DeletePort(Dbport);
PutMsg(Dback,&DummyMsg); /* Kill handshake */
}
/*
* The assembly tag for the DOS process: CNOP causes alignment problems
* with the Aztec assembler for some reason. I assume then, that the
* alignment is unknown. Since the BCPL conversion basically zero's the
* lower two bits of the address the actual code may start anywhere
* within 8 bytes of address (remember the first longword is a segment
* pointer and skipped). Sigh.... (see CreatProc() above).
*/
#asm
public _debugproc
public _debugmain
cseg
_debugproc:
nop
nop
nop
nop
nop
movem.l D2-D7/A2-A6,-(sp)
jsr _debugmain
movem.l (sp)+,D2-D7/A2-A6
rts
#endasm