dillon@CORY.BERKELEY.EDU (Matt Dillon) (10/23/87)
Thanks to Steve Beats and Andy Finkel, I've gotten ACTION_INFO
working properly. Here's the update... plus the docs which somehow got
left out of the original distribution.
-Matt
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# DOSDEV.DOC
# Makefile
# bset.asm
# device.c
# device.uue
# dos.h
# flush.c
# mountlist
# This archive created: Thu Oct 22 16:16:12 1987
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'DOSDEV.DOC'" '(3865 characters)'
if test -f 'DOSDEV.DOC'
then
echo shar: "will not over-write existing file 'DOSDEV.DOC'"
else
cat << \!Funky!Stuff! > 'DOSDEV.DOC'
DOS device driver example for AZTEC C
By Matthew Dillon ... for all those people out there (including me!)
who have been struggling with DOS devices. Placed in PUBLIC DOMAIN.
Documentation is sorely lacking... even the RKM examples are sorely
lacking. What programmers need is a working example ... as full an
implementation as possible to figure out all the little DOS quirks that
the manuals don't tell you about... Little things like when the driver
stores a string in a structure it must be in BCPL 'length first'
format. There are literally hundreds of these babies!
REQUIREMENTS:
-Aztec C compiler
-A precompiled symbol table of all sub-directory include's (*/*.H). i.e.
one which does NOT include top level stuff like <stdio.h>. Remember to
compile with the +L option when generating the symbol table.
The LARGE data and code model will be used... It makes life *much*
easier. This will NOT effect performance as there are very few global
elements anyway.
*Alternately, no requirements if you just want to look at the source.
MOUNTLIST:
You will want to change this to a more permanent file path, obviously,
though to run the example you might as well leave the driver in RAM:
THE EXAMPLE:
How 'bout a RAM disk? RAM disks use most DOS packet types... Since my
RAM disk is not meant for normal usage, There will be a lot of minor
items I will leave unimplimented:
-Date stamps are not kept up. In fact, they are garbage.
-I don't check out-of-memory conditions (remember! This is ONLY an
example!)
-The driver EXIT's if no files exist and no references exist.
This allows you to FLUSH (make flush), which should remove all
knowlege of the driver allowing you to make source changes,
recompile, and re-reference without changing the name or
rebooting. Normally, disk-like devices are permanent fixtures.
-The ARCHIVE protection bit is not supported
All packet types normally associated with a RAM disk are supported,
Most especially LOCKS, which *many* people have not been able to figure
out in the past.
DEBUGGING:
Since this is an example, FULL Debugging has been implemented. Since
the DOS device driver cannot make DOS library calls itself (confusion
on the message port), CreatProc() is used to create a secondary process
which will do actual printing of the debugger messages. The messages
are then sent to the debug process via a dedicated message port.
Since Debugging causes a huge efficiency decrease, and since you are
going to want to fool around with the device, you can turn off debug
error message output by:
CD test:
type debugoff (will get an error, but debugging will be turned
off)
alternately, 'type debugon' will turn it back on.
The debugging code itself is a good example.
DOS:
Remember that most addresses are passed as BPTR's, and most strings are
passed as BPTR's to a BSTR (length in byte 0, string in bytes 1..N, no
'end' bytes). The exceptions are obvious by looking at the code (at
least of the packet types supported).
DOS PECULARITIES NOT ADDRESSED:
Newcli assumes it can open the file '*' on whatever device you specify
for the control terminal to get a duplicate stream. This is how it
gets around CON-like devices which like to create separate processes
for each invocation.
ACTION_DISK_INFO, when sent to a CONSOLE device, will return the window
associated with the console as follows:
id_VolumeNode = console window
id_InUse = console IO blvock
There are probably many more.
Matthew Dillon
ARPA: dillon@ucbvax.berkeley.edu
UUCP: ..!ihnp4!ucbvax!dillon
SNAIL: Matthew Dillon
891 Regal Rd.
Berkeley, Ca. 94708
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'Makefile'" '(237 characters)'
if test -f 'Makefile'
then
echo shar: "will not over-write existing file 'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'
CFLAGS= +BCDL +Ivd0:include/symbols.m
OBJS= device.o bset.o
.c.o:
cc $(CFLAGS) $*.c
all: $(OBJS)
ln +Q $(OBJS) -lcl32 -O ram:device
flush:
cc +L +Ivd0:include/symbols.m flush.c -o ram:flush.o
ln +Q ram:flush.o -lc32
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'bset.asm'" '(1076 characters)'
if test -f 'bset.asm'
then
echo shar: "will not over-write existing file 'bset.asm'"
else
cat << \!Funky!Stuff! > 'bset.asm'
;BSET.ASM
;BZERO.ASM
;
; Uses longword operations if data is aligned on a longword boundry
; and the size is a mulitple of 4. Otherwise, uses byte operations.
xdef _bset
xdef _bzero
_bzero
clr.l D1
bra begin
_bset
move.b 15(A7),D1 ;12(A7)-> msb . . lsb (D1 = data)
begin
move.l 4(A7),A0 ;A0 = address
move.l 8(A7),D0 ;D0 = byte count
andi.b #3,11(A7) ;byte count on long word boundry?
bne drop
andi.b #3,7(A7) ;address on longword boundry?
bne drop
bra lwb
loop move.b D1,(A0)+ ;BYTE SET LOOP
drop dbf.w D0,loop ;remember, only effects lower word
sub.l #$10000,D0 ;for buffers >65535
bpl loop ;branch to loop because D0.W now is FFFF
rts
lwb lsr.l #2,D0 ;byte count / 4 (longword chunks)
tst.l D1 ;BZERO
beq dropl
move.b D1,14(A7) ;15(A7) already contains the byte
move.w 14(A7),D1 ;D1 0..15 set
swap D1
move.w 14(A7),D1 ;D1 16..31 set
bra dropl
loopl move.l D1,(A0)+ ;BYTE SET LOOP
dropl dbf.w D0,loopl ;remember, only effects lower word
sub.l #$10000,D0 ;for buffers >65535
bpl loopl ;branch to loop because D0.W now is FFFF
rts
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'device.c'" '(27017 characters)'
if test -f 'device.c'
then
echo shar: "will not over-write existing file 'device.c'"
else
cat << \!Funky!Stuff! > 'device.c'
/*
* 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
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'device.uue'" '(14139 characters)'
if test -f 'device.uue'
then
echo shar: "will not over-write existing file 'device.uue'"
else
cat << \!Funky!Stuff! > 'device.uue'
begin 644 device
M```#\P`````````#``````````(```C>````1P````$```/I```(WDY5_NI(
MYP\P0GD```"80KD```"R0KD```"N0KD```"J(_D````$````HD*G2'H.[$ZY
M```C"%!/(\````"F0J=.N0``(IA83R/`````FB!Y````FDAH`%Q.N0``(V18
M3R!Y````FDAH`%Q.N0``(N)83RM`__P@;?_\)&@`"DJY````IF<P("H`'.6`
M(\````">('D```">(#D```":T+P```!<(4``""5\_____P`,0JH`$&`40JH`
M#"\*3KH/M%A/3-\,\$Y=3G4O"DZZ#Z183TZZ%W(@>0```)X@*``HY8`K0/[R
M(&W^\G``$!`[0/[P2'D```"V3KD``"+V6$](>0```,).N0``(O983TAX`#A(
M>0```.).N0``&OY03S/\``$```#V2'D```$"3KD``"+V6$](>``!,"W^\$C`
M4H`O`$ZY```B<E!/(\````#N,"W^\$C`+P`O.0```.X@;?[R4H@O"$ZY```A
M6D_O``PP+?[P('D```#N0C```"\Y````[C`M_O!(P"\`2'H-EDZZ%ZA/[P`,
M&WP``?_[('D```":2&@`7$ZY```C9%A/3KH5G"!Y````FDAH`%Q.N0``(N)8
M3RM`__QG``RT(&W__"1H``HE?/____\`#$*J`!!X`"\J`"`O*@`<+RH`&"\J
M`!0O*@`(2'H-/TZZ%SQ/[P`8("H`"&``"ZY"+?_[8``,3B\J`!A.NA(<6$\K
M0/[R2&W^^R\J`!Q.N@[X4$](>@TM2&W^^TZY```;5E!/2H!F"#/\``$```"8
M2'H-&DAM_OM.N0``&U903TJ`9@9">0```)A(;?[N2&W^^TAM_O).NA'F3^\`
M#"H`9W`O+?[N+RW^\DAZ#.A.NA:N3^\`#"!%#&@``0`49@@X/`#48```_"!%
M2F@`%FP(.#P`RF```.P,J@```^T`"&8(($52:``68"8@14IH`!9O!C@\`,I@
M&`RJ```#[@`(9@@O!4ZZ#ZY83R!%4V@`%F!82'H,HTZZ%D983TJM_O)F"#@\
M`-)@``":#*H```/N``AF,B\M_NY(>/__+RW^\DZZ#O)/[P`,*@`@15-H`!8@
M12\H``PO!4AZ#&E.NA8`3^\`#&`$.#P`S4I$9E1(>0`!``%(>``83KD``")R
M4$\L`"`J`!3E@"!`(48`)"\&2'H,24ZZ%<A03R!&(44`""!%2&@`($ZZ#BI8
M3R!&(4``#"\&2'D```"V3KD``"*(4$](>0```+9.N@X(6$]*@&842'D```#"
M3KH-^%A/2H!F!$(M__M@``J<*BH`%"!%+"@`#"XJ`!@K:@`<_O(O!B\%($4B
M12`H`!#0J0`4+P!(>@O?3KH52$_O`!!*K?[R9P``KDJ&9P``J"!&(D4@*``,
MD*D`%"M`_NXO+?[R+RW^[DAZ"]!.NA463^\`#"`M_O*PK?[N;"XO+?[R+P<@
M12)&+&@`%-WI``@O#DZY```A6D_O``P@12`M_O+1J``40JW^\F!&+RW^[B\'
M($4B1BQH`!3=Z0`(+PY.N0``(5I/[P`,("W^[I&M_O+>K?[N($4B1B`I``S1
MJ``0($5"J``4+P9.N@SL6$\L`&``_TX@12%&``P@*@`<D*W^\B5```Q@``F@
M*BH`%"!%+"@`#"XJ`!@K:@`<_O(O!4AZ"SE.NA1<4$]*K?[R9P`!2DJ&9P``
MJB!&+R@`#"\M_O)(>@LC3KH4.D_O``P@1B)%("@`#)"I`!0K0/[N("W^\K"M
M_NYL+B\M_O(@12)&+&@`%-WI``@O#B\'3KD``"%:3^\`#"!%("W^\M&H`!1"
MK?[R8$8O+?[N($4B1BQH`!3=Z0`(+PXO!TZY```A6D_O``S>K?[N("W^[I&M
M_O(@12)&("D`#-&H`!`@14*H`!0O!DZZ#`!83RP`8```F"\M_O)(>@J53KH3
MF%!/2'@``4AX`!!.N0``(G)03RP`2'@``2\M_O).N0``(G)03R!&(4``""!&
M(6W^\@`,($4B:``(("W^\M&I`!P@12`M_O+1J``0($5"J``4("W^\M&Y````
MJB\&($4B:``(2&D`($ZY```A-E!/+RW^\B!&+R@`""\'3KD``"%:3^\`#$*M
M_O)\`&``_K(@*@`<D*W^\B5```P@12%&``Q@``@:*BH`%"!%+"@`""\%3KD`
M`"-(6$](>``8+P5.N0``(KQ03R!&4V@`%DIH`!9L!B!&0F@`%DAY````MDZZ
M"RI83TJ`9A1(>0```,).N@L:6$]*@&8$0BW_^V``![XJ*@`4($4B12`H`!#0
MJ0`4)4``#"XJ`!A*J@`<9@X@12)%("@`$-"I`!3>@`RJ`````0`<9@H@12)H
M``C>J0`<2H=M#"!%(F@`"+ZI`!QC"#@\`-M@``=F($5"J``4(D5"J0`0($4B
M:``(2&D`($ZZ"II83RP`8#8@12)&("@`$-"I``RPAV,0($4B12`'D*D`$"%`
M`!1@&B!%(D8@*0`,T:@`$"\&3KH*0EA/+`!*AF;&($4A1@`,8``'`B`J`!CE
M@"H`+RH`%$ZZ#,A83RP`($8,:/__`!1F"#@\`-1@``;<($5*D&8(.#P`Z&``
M!LX@12P0+P9.N@GR6$\@12"`*T;^]GC_("H`&.6`*@!*1&<&+"W^]F`<+RH`
M%$ZZ#'183RP`($9(:``@3KH)WEA/($4@@'@`($8P*``42,`B12-```0@1B\H
M``PB14AI``E.N0``&X903R!&+R@`#$ZY```@G%A/($410``(($8B12-H`!@`
M="!%0J@`>"!&(D4C:``<`'P@12)&("D`''()XJ@A0`"`($71_````(0B1M/\
M````+"#9(-D@V2!&2J@`$&<J($8O*``0(D5(:0"13KD``!N&4$\@1B\H`!!.
MN0``()Q83R!%$4``D&`&($5"*`"08``%UB`J`!CE@"M`_O9X_TI$9P8J+?[V
M8`@@*@`4Y8`J`'@`2'@`)"\%3KD``!K^4$\@12%\````4@`(($4@.0```*IR
M">*@4H`A0``,($4@.0```*IR">*@4H`A0``0($4A?````@``%"!%(7Q$3U,`
M`!@@.0```)[D@"!%(4``'$AY````PDZZ")Q83R!%(4``(&``!4(O*@`43KH+
M$%A/*@`@10QH__\`%&8(.#P`S6``!20@14IH`!9L"#@\`,I@``44($5*J``(
M9QA(>/_^($4O*``(3KH*`E!/Y(`E0``,8`0X/`#-8``$["\J`!1.N@JZ6$\K
M0/[R2&W^^R\J`!A.N@>64$]"ITAM_OM(;?[R3KH*O$_O``PK0/[N9UX@;?[N
M2F@`%F8.0_D```#B+&W^[KW)9@@X/`#*8``$F"!M_NX,:``!`!1F&"!M_NY(
M:``@3KH'SEA/2H!G!#@\`-A@"B\M_NY.N@B<6$]*1&8*+RW^[DZZ".Q83V`0
M2JW^\F8&.#P`TF`$.#P`S4AY````MDZZ!XY83TJ`9A1(>0```,).N@=^6$]*
M@&8$0BW_^V``!"(O*@`43KH)\%A/*T#^\DAM_OLO*@`83KH&S%!/2&W^ZDAM
M_OM(;?[R3KH)\$_O``PK0/[N9P@X/`#+8``#Y$JM_O)F"#@\`-)@``/6+RW^
MZDAX``$O+?[R3KH'=D_O``PK0/[N2'C__R\M_NY.N@BV4$_D@"5```Q@``.F
M+RH`%$ZZ"7183RM`_O)(;?[[+RH`&$ZZ!E!03T*G2&W^^TAM_O).N@EV3^\`
M#"M`_NYG/"!M_NY*:``6;10B;?[N2FD`%F<2#*K_____`!QF"#@\`,I@``-,
M+RH`'"\M_NY.N@A$4$_D@"5```Q@$$JM_O)F!C@\`-)@!#@\`,U@``,B+RH`
M%$ZZ"/!83RH`($5*:``6;`8X/`#*8!)(>/_^+P5.N@@"4$_D@"5```Q@``+R
M2JH`%"`J`!3E@"\`3KH(;%A/2'D```"V3KH&)%A/2H!F%$AY````PDZZ!A18
M3TJ`9@1"+?_[8``"N"\J`!A.N@B&6$\K0/[R2&W^^R\J`!Q.N@5B4$](;?[N
M2&W^^TAM_O).N@B&3^\`#"H`9PH@12%J`"``&&`02JW^\F<&.#P`S6`$.#P`
MTF```F8O*@`83KH(-%A/*T#^\DAM_OLO*@`<3KH%$%!/2&W^[DAM_OM(;?[R
M3KH(-$_O``PJ`&=L2&W^^R\J`"!.N@3J4$\@14JH`!!G("!%+R@`$$ZY```@
MG%A/4H`O`"!%+R@`$$ZY```BO%!/2'@``4AM_OM.N0``()Q83U*`+P!.N0``
M(G)03R!%(4``$$AM_OL@12\H`!!.N0``&X903V`02JW^\F<&.#P`S6`$.#P`
MTF```;(O*@`43KH'@%A/*T#^\B\J`!Q.N@=R6$\K0/[N2&W^^R\J`!A.N@1.
M4$]"ITAM_OM(;?[R3KH'=$_O``PJ`&<``*Q(;?[[+RH`($ZZ!"A03TAM_NI(
M;?[[2&W^[DZZ!TQ/[P`,+`!G!C@\`,M@?$JM_NYG<B\%3KD``"-(6$\O!2!M
M_NY(:``@3KD``"$V4$\@12\H``Q.N0``()Q83U*`+P`@12\H``Q.N0``(KQ0
M3TAX``$O+?[J3KD``""<6$]2@"\`3KD``")R4$\@12%```PO+?[J($4O*``,
M3KD``!N&4$]@!#@\`-)@$$JM_O)G!C@\`,U@!#@\`-)@``"R.#P`T6```*I;
M@&<`]%!7@&<`_/I3@&?H78!G`/VD4X!G`/ND4X!G`/[84X!GTE.`9P#]7E.`
M9\A3@&<`_;Y3@&<`_$Y3@&<`^;)3@&<`^6)3@&<`^I13@&<`^H)3@&>@4X!G
M`/WH4X!G`/L&58!GD)"\````,V<`]9Y;@&<`]I20O````XMG`/]XD+P````*
M9P#STE.`9P#SS%.`9P#SQE.`9P#W]%.`9P#X2F``_U(@"F<82D1G#$*J``PP
M!$C`)4``$"\*3KH!^%A/8`#S-DHM__MF`/,82'H!NTZZ"JQ83TAX`#).N0``
M(/Q83TZY```BK"\Y````FDZZ`@183TJ`9C!(>0```+9.N@+R6$]*@&8@2'D`
M``#"3KH"XEA/2H!F$$AY```!`DZZ`M)83TJ`9Q1.N0``(R!(>@%M3KH*2EA/
M8`#RHB!Y````GD*H``A.N@G:+SD```"F3KD``"%&6$]@`/&J9&]S+FQI8G)A
M<GD`4D]/5"!.04U%.B`E;&0@)R5S)PH`4&%C:V5T.B`E,VQD("4P.&QX("4P
M.&QX("4P.&QX("4P.&QX"@!D96)U9V]F9@!D96)U9V]N`$9O=6YD.B!P87)E
M;G1D:7(@)3`X;'@@('1A:6P@)R5S)PH`3F]T(&9O=6YD+BX`861D:6YG(&9I
M;&4@)3`X;'@@)R5S)PH`4T54($9(+4%21S$@=&\@)3`X;'@*`%)%040@4V5E
M:SHE;&0@349(.B4P.&QX($9%3CHE,#AL>`H`("5L9"!B>71E<R!A=F%I;"!T
M;R!R96%D+B!R97$@)6QD"@!-1D@Z("4P.&QX"@!74DE413H@)6QD($9%3B`E
M;&0*`%=2251%.B`E;&0@3D]&14X*`%)%34]624Y'($1/4R!$159)0T4`3F]T
M(')E861Y('1O(&1I92!Y970A"@!.50``2.<(,"1M``@H*@`$)E(@.0```)K0
MO````%PE0``$)TH`"D*30JL`!"\++P1.N0``(RI03TS?#!!.74YU3E4``"!Y
M````FB)Y````FM/\````="QH`'"]R6<$<`%@`G``3EU.=4Y5``!(YP@@*"T`
M"%B$2'D``0`!+P1.N0``(G)03R1`)(0@"EB`3-\$$$Y=3G5.50``+PHD;0`(
M68HO$B\*3KD``"*\4$\D7TY=3G5.50``("T`".6`*T``""!M``AP`!`0+P`O
M+0`,(FT`"%*)+PE.N0``(5I/[P`,(&T`"'``$!`B;0`,0C$(`"\M``P@;0`(
M<``0$"\`2'H`#DZZ!\1/[P`,3EU.=6)T;W,Z("5L9"`E<PH`3E4``"!M``@K
M4``((&T`"$J09@9P`$Y=3G4@+0`(8/9.50``(&T`"%B((FT`"+'19PH@;0`(
M(!!.74YU<`!@^$Y5``!(YP@P)&T`""9M``PX+0`24T1*1&TD<``0,D``",``
M!7(`$C-```C!``6P@6<*<`!,WPP03EU.=6#6<`%@\DY5```O"DAY``$``4AX
M`#A.N0``(G)03R1`+PH@;0`(2&@`($ZY```A-E!/)6T`"``(2'@``2\M`!!.
MN0``()Q83U*`+P!.N0``(G)03R5```PO+0`0+RH`#$ZY```;AE!/-6T`#@`4
M0JH`&$AJ`"!.N0``(O983R`*)%].74YU3E7__"!M``@@*``<D;D```"J(&T`
M"$AH`"!.N0``(SI83RM`__QG*B!M__PO*``,(FW__"\I``A.N0``(KQ03TAX
M`!`O+?_\3KD``"*\4$]@P"!M``A"J``<3EU.=4Y5```O+0`(3KD``"-(6$\@
M;0`(+R@`#$ZY```@G%A/4H`O`"!M``@O*``,3KD``"*\4$\@;0`(2J@`$&<D
M(&T`""\H`!!.N0``()Q83U*`+P`@;0`(+R@`$$ZY```BO%!/2'@`."\M``A.
MN0``(KQ03TY=3G5.5?_\2'@`($ZZ_6I83RM`__P@;?_\2&@`%$AY````PDZY
M```BB%!/(&W__"%M``P`""!M__P@.0```)K0O````%PA0``,(#D```">Y(`@
M;?_\(4``$"!M__PA;0`(`!P,K?____X`#&8*(&T`"%)H`!9@"B!M``@Q?/__
M`!8@+?_\3EU.=4Y5__P@;0`(*V@`'/_\(&T`"$AH`!1.N0``(TA83R!M``@,
MJ/____X`"&8*(&W__%-H`!9@""!M__Q":``6+RT`"$ZZ_-A83TY=3G5.50``
M2JT`"&<0("T`".6`($`@*``<3EU.=4'Y````XB`(8/).5?_R(&T`""M0__PO
M+0`,2'H!H$ZZ!,I03R!M``A"D&```3Y(;?_V2&T`#$ZZ`C!03RM`__(@;0`,
M#!``.F8<2'H!@DZZ!)I83U*M``Q!^0```.(K2/_\8``!!B!M__(,$``O9D`@
M;?_\2J@`"&802'H!84ZZ!&I83W``3EU.=2!M__PK:``(__P@;?_\+R@`#"\M
M__Q(>@%03KH$1$_O``Q@``"\(&W__`QH__\`%&8$<`!@QB!M__Q(:``@3KK\
ME%A/*T#_^&!0(&W_^"\H``Q.N0``()Q83S(M__9(P;"!9B@P+?_V2,`O`"\M
M__(@;?_X+R@`#$ZZ_'I/[P`,2H!G""MM__C__&`4+RW_^$ZZ_")83RM`__A*
MK?_X9JI*K?_X9CH@;0`,2A!F%"!M``@@K?_\2'H`RDZZ`Z183V`*2'H`UDZZ
M`YA83TJM`!!G""!M`!`@K?_R<`!@`/\>(&T`#$H09PA*K?_\9@#^MDJM`!!G
M""!M`!`@K?_R(&W__")M``@BJ``((&W__"\H``@B;?_\+RD`#"\M__Q(>@":
M3KH#/$_O`!`@+?_\8`#^S'-E87)C:'!A=&@Z("<E<R<*`&-O;&]N(&5L96UE
M;G0*`$)A8VMD:7(N+B!N;R!P87)E;G0*`&)A8VMD:7(Z(&9I;&4@)3`X;'@@
M*"5S*0H`96QE;65N="!N;W0@9F]U;F0N+B!O:PH`96QE;65N="!N;W0@9F]U
M;F0N+B!P871H(&5R<F]R"@!$3TY%+B!&:6QE("4P.&QX("@E<RD@<&%R96YT
M("4P.&QX"@!.5?_\2.<(("!M``@D4'@`*TK__$H29RH,$@`O9@92BE)$8!Y*
M$F<2#!(`+V<,#!(`.F<&4HI21&#J#!(`+V8"4HH@;0`(((H@;0`,,(0O"B\M
M__PP!$C`+P!(>@`63KH"(D_O`!`@+?_\3-\$$$Y=3G50051(($5,14U%3E0Z
M("5L9"`G)7,G(&YE>'1`("<E<R<*``!.50``2.<`,$AY```!`DZZ^E!83R1`
M8"`O*@`<+RH`#"\*2'H`@DZZ`<1/[P`0+PI.NOH.6$\D0"`*9MQ(>0```+9.
MNOH<6$\F0&`J+RL`%"\K`!`@:P`(+R@`#"\K``A(>@!>3KH!AD_O`!0O"TZZ
M^=!83R9`(`MFTDAY````PDZZ^=Y83TJ`9PI(>@!13KH!7%A/2'H`7DZZ`5)8
M3TS?#`!.74YU4F]O="!E;G1R>3H@)3`X;'@@)7,@)6QD"@!/<&5N9FEL93H@
M)3`X;'@@)7,@0"5L9"`E;&0*`$%#5$E612!,3T-+4R!$3R!%6$E35`H`"@!.
M5?_\0J=.N0``(IA83RM`__Q"IT*G3KD``"%N4$\CP````+)(>!``0?H"=B`(
MY(`O`"!M__P2*``)2(%(P5*!+P%(>@`V3KD``"#F3^\`$"\Y````LDZY```C
M9%A/+SD```"R3KD``"+B6$](>@`33KH`A%A/3EU.=41%5E]$0@!$96)U9V=E
M<B!R=6YN:6YG(%8Q+C`P"@``3E7_[$JY````KF=,0FW__DAM_^PO.0```*Y.
MN0``(RI03R\Y````LDZY```C9%A/+SD```"R3KD``"+B6$\O.0```+).N0``
M(@983TAX`#).N0``(/Q83TY=3G5.5?[\2KD```"N9P``HDIY````F&8``)@O
M+0`L+RT`*"\M`"0O+0`@+RT`'"\M`!@O+0`4+RT`$"\M``PO+0`(2&W_`$ZY
M```;ED_O`"Q(>0`!``%(;?\`3KD``""<6$\@0$AH`!5.N0``(G)03RM`_OQ(
M;?\`3KD``""<6$]2@"!M_OPQ0``22&W_`"!M_OQ(:``43KD``!N&4$\O+?[\
M+SD```"N3KD``",J4$].74YU3E7_]D*G0J=.N0``(6Y03R/`````KDAX`^Y(
M>@#`3KD``"$*4$\K0/_V2'D```#.+SD```"R3KD``",J4$\O.0```*Y.N0``
M(V183R\Y````KDZY```BXEA/*T#__"!M__P[:``2__I*;?_Z9SQ3;?_Z,"W_
M^DC`+P`@;?_\2&@`%"\M__9.N0``(2!/[P`,,"W_^DC`($!(:``5+RW__$ZY
M```BO%!/8)0O+?_V3KD``"#26$\O.0```*Y.N0``(@983TAY````SB\Y````
MLDZY```C*E!/3EU.=6-O;CHP+S`O-C0P+S$P,"]D96)U9W=I;F1O=P!.<4YQ
M3G%.<4YQ2.<_/DZZ_OA,WWS\3G5"@6`$$B\`#R!O``0@+P`(`B\``P`+9@P"
M+P`#``=F!&`0$,%1R/_\D+P``0``:O).=>2(2H%G$A]!``XR+P`.2$$R+P`.
M8`(@P5'(__R0O``!``!J\DYU,#Q__V`$,"\`#E-`:Q0@;P`$(F\`"+$)9@Q3
M2$H85\C_]G``3G5C!'`!3G5P_TYU(&\`!"`((F\`"!#99OQ.=4Y5``!(YS@`
M(^T`"````)1(;0`0+RT`#$AZ`"!.N0``'(A/[P`,*``@>0```)1"$"`$3-\`
M'$Y=3G5.50``2.<P`"!Y````E%*Y````E!`M``L0@$B`2,#`O````/],WP`,
M3EU.=4Y5``!(YS@@)&T`$`RM````!``49@@@;0`(*!!@%$JM``QO""!M``@H
M$&`&(&T`""@00JT`%$JM``QL$D2M``Q*A&P*1(0K?`````$`%"(M``P@!$ZY
M```@-D'Y`````%.*%+`(`"(M``P@!$ZY```@0B@`9MA*K0`49P93BA2\`"T@
M"DS?!!Q.74YU3E7_%$CG.#`D;0`()FT`#$*M__@K;0`0__P@2U*+$!!(@$C`
M*`!G``,\N+P````E9@`#%D(M_R(K?`````'_]"M\````(/_P*WP``"<0_^P@
M2U*+$!!(@$C`*`"PO````"UF$$*M__0@2U*+$!!(@$C`*`"XO````#!F%"M\
M````,/_P($M2BQ`02(!(P"@`N+P````J9AH@;?_\6*W__"M0_^@@2U*+$!!(
M@$C`*`!@.$*M_^A@)'(*("W_Z$ZY```@KM"$D+P````P*T#_Z"!+4HL0$$B`
M2,`H`$'Y````$P@P``)(`&;.N+P````N9F8@2U*+$!!(@$C`*`"PO````"IF
M&B!M__Q8K?_\*U#_["!+4HL0$$B`2,`H`&`X0JW_[&`D<@H@+?_L3KD``""N
MT(20O````#`K0/_L($M2BQ`02(!(P"@`0?D````3"#```D@`9LXK?`````3_
MY+B\````;&86($M2BQ`02(!(P"@`*WP````$_^1@%+B\````:&8,($M2BQ`0
M2(!(P"@`(`1@``""*WP````(_^!@'"M\````"O_@8!(K?````!#_X&`(*WS_
M___V_^`O+?_D2&W_(B\M_^`O+?_\3KK]I$_O`!`K0/_<("W_Y-&M__Q@7"!M
M__Q8K?_\*U#_W"\M_]Q.N0``()Q83RM`_^1@2B!M__Q8K?_\*!!![?\A*TC_
MW!"$8"B0O````&-GXE.`9Y*0O`````MG`/]L68!GLE6`9P#_;%>`9P#_<&#,
M0>W_(I'M_]PK2/_D("W_Y+"M_^QO!BMM_^S_Y$JM__1G<"!M_]P,$``M9PHB
M;?_<#!$`*V8T#*T````P__!F*E.M_^@@;?_<4JW_W!`02(!(P"\`3I)83["\
M_____V8*</],WPP<3EU.=6`8+RW_\$Z26$^PO/____]F!'#_8.)2K?_X("W_
MZ%.M_^BPK?_D;MI"K?_@8"0@;?_<4JW_W!`02(!(P"\`3I)83["\_____V8$
M</]@JE*M_^`@;?_<2A!G"B`M_^"PK?_L;<H@+?_@T:W_^$JM__1F*F`:2'@`
M($Z26$^PO/____]F!G#_8`#_<%*M__@@+?_H4ZW_Z+"M_^1NV&`8+P1.DEA/
ML+S_____9@9P_V``_TA2K?_X8`#\N"`M__A@`/\X2.=(`$*$2H!J!$2`4D1*
M@6H&1($*1``!83Y*1&<"1(!,WP`22H!.=4CG2`!"A$J`:@1$@%)$2H%J`D2!
M81H@`6#8+P%A$B`!(A]*@$YU+P%A!B(?2H!.=4CG,`!(04I!9B!(038!-`!"
M0$A`@,,B`$A`,@*"PS`!0D%(04S?``Q.=4A!)@$B`$)!2$%(0$)`=`_0@-.!
MMH%B!)*#4D!1RO_R3-\`#$YU(&\`!"`(2AAF_)'`(`A3@$YU2.=P`#0!Q,`F
M`4A#QL!(0T)#U(-(0,#!2$!"0-""3-\`#DYU3OD``"#8(B\`!"QY````ID[N
M_]PO!$SO`!X`""QY````IDZN_W8H'TYU(B\`!"QY````ID[N_SI.^0``(1!,
M[P`&``0L>0```*9.[O_B3OD``"$F3.\`#@`$+'D```"F3N[_T$SO`P``!"QY
M````HD[N_PI.^0``(4PB;P`$+'D```"B3N[^8DSO`P``!"`O``PL>0```*).
M[OV03E4``$CG."!(>/__3KD``")D6$\H`+"\_____V8*<`!,WP0<3EU.=4AY
M``$``4AX`").N0``(G)03R1`2H!F#B\$3KD``"+46$]P`)6T`"``*%6T`
M#P`)%7P`!``(0BH`#A5$``]"ITZY```BF%A/)4``$$JM``AG#"\*3KD``")6
M6$]@#$AJ`!1.N0``(O983R`*8(A.50``2.<P("1M``A*J@`*9PHO"DZY```C
M5EA/%7P`_P`()7S_____`!1P`!`J``\O`$ZY```BU%A/2'@`(B\*3KD``"*\
M4$],WP0,3EU.=2)O``0L>0```*).[OZ>("\`!"QY````HD[N_K9.^0``(GA,
M[P`#``0L>0```*).[O\Z3.\#```$+'D```"B3N[_$$[Y```BGB)O``0L>0``
M`*).[O[:3OD``"*R+'D```"B3N[_?$[Y```BPB)O``0@+P`(+'D```"B3N[_
M+B`O``0L>0```*).[OZP3OD``"+H(&\`!"QY````HD[N_HP@;P`$((A8D$*H
M``0A2``(3G5.^0``(PXL>0```*(B;P`$("\`"$[N_=@L>0```*).[O]V3.\#
M```$+'D```"B3N[^DB!O``0L>0```*).[O[^(F\`!"QY````HD[N_P0B;P`$
M+'D```"B3N[^F$[Y```C:B!O``0L>0```*).[OZ````#[````'D`````````
M,@```$(```!:````;````/H```$(```!&@```3````%&```!:@```:P```'"
M```"/````E@```-8```#F@``!$P```1Z```%.```!68```6R```%Q```!@X`
M``8B```&6```!F8```?X```(!@``"&@```AV```(M@``#%````QB```,<@``
M#'X```R6```-*@``#3P```U*```-7```#6P```UX```-D```#IH```ZB```.
MZ```#Q```!"D```0\@``$1H``!%,```2)```$C@``!).```26@``$FX``!*$
M```2K@``$LP``!+<```2^@``$PH``!,>```3.```$TP``!-<```3B```%`0`
M`!4P```83@``&%X``!B.```8G@``&*P``!C\```9"@``&1@``!DF```9,@``
M&8(``!F6```9I```&;0``!G2```9Y```&?@``!H.```:)@``&C0``!I"```:
M=@``&I```!J>```:K```&L```!NT```<4@``'&H``!U(```=M@``'GX``"#4
M```A#```(2(``"%(```A?```(:(``"&R```AV@``(>X``"'\```B'```(CH`
M`")(```B=```(IH``"*N```BO@``(N0``",*```C9@```&X````!````"@``
M`!`````6````'````"8````Z````2@```%````!B````@````(X```"4````
MF@```-@```#T```!`@```10```$D```!*@```4X```%<```!>````8(```&B
M```!N````DH```)D```#E````Z(```.R```%_```!H````:0```(R@``"-P`
M``D````)#@``";@```H<```*+```"X8```N6```.J```#K@```[(```.V```
M#OP```\*```0A@``$+@``!"^```2H```$X(``!.>```3K@``%%0``!2L```7
M6@``%XX``!?,```89@``&)@``!BF```8Y@``&/8``!D$```9$@``&2```!E"
M```93```&=X``!H````:&@``&B```!HN```:/```&J8``!JT```:N@``&Z(`
M`!O````;V@``&^```!Q8```=9@``'=0``"#>```@\```(0(``"$8```A+@``
M(3X``"%2```A9@``(EP``")J```B@```(I```"*D```BM```(LP``"+:```B
M[@``(Q```",B```C,@``(T```"-.```C7```(W`````````#\@```^H````E
M,#$R,S0U-C<X.6%B8V1E9@```"`@("`@("`@(#`P,#`P("`@("`@("`@("`@
M("`@("`@D$!`0$!`0$!`0$!`0$!`0`P,#`P,#`P,#`Q`0$!`0$!`"0D)"0D)
M`0$!`0$!`0$!`0$!`0$!`0$!`0%`0$!`0$`*"@H*"@H"`@("`@("`@("`@("
=`@("`@("`D!`0$`@`````_(```/K`````0```_(*
`
end
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'dos.h'" '(2163 characters)'
if test -f 'dos.h'
then
echo shar: "will not over-write existing file 'dos.h'"
else
cat << \!Funky!Stuff! > 'dos.h'
/*
* PARALLEL NETWORK INTERFACE
*/
#define ACTION_OPENRW 1004
#define ACTION_OPENOLD 1005
#define ACTION_OPENNEW 1006
#define ACTION_CLOSE 1007
#define ACTION_SEEK 1008
#define ACTION_RAWMODE 994
#define ACTION_MORECACHE 18
#define ACTION_FLUSH 27
#define CTOB(x) (void *)(((long)(x))>>2)
#define BTOC(x) (void *)(((long)(x))<<2)
#define bmov(ss,dd,nn) CopyMem(ss,dd,nn)
#define DOS_FALSE 0
#define DOS_TRUE -1
#define RAMFILE struct _RAMFILE
#define FENTRY struct _FENTRY
#define MYLOCK struct _MYLOCK
#define MYFH struct _MYFH
typedef unsigned char ubyte;
typedef unsigned short uword;
typedef unsigned long ulong;
typedef struct Interrupt INTERRUPT;
typedef struct Task TASK;
typedef struct FileLock LOCK;
typedef struct FileInfoBlock FIB;
typedef struct DosPacket PACKET;
typedef struct Process PROC;
typedef struct DeviceNode DEVNODE;
typedef struct FileHandle FH;
typedef struct MsgPort PORT;
typedef struct Message MSG;
typedef struct MinList LIST;
typedef struct MinNode NODE;
typedef struct DateStamp STAMP;
typedef struct InfoData INFODATA;
#define FILE_DIR 1
#define FILE_FILE -1
RAMFILE {
NODE node;
RAMFILE *parent;
char *name;
char *comment;
short type; /* -1 = file, 1 = dir */
short locks; /* <0:exclusive 0:none >0:shared */
ulong protection;
ulong bytes;
LIST list; /* list of FENTRY's or RAMFILE's */
STAMP date;
};
FENTRY {
NODE node;
ubyte *buf;
ulong bytes;
};
MYLOCK {
LOCK lock;
NODE node;
RAMFILE *file;
};
MYFH {
NODE node;
RAMFILE *file; /* file header */
FENTRY *fentry;
long base; /* base of FENTRY */
long offset; /* offset into FENTRY */
};
extern long AbsExecBase;
extern void *AllocMem(), *RemHead(), *CreatePort(), *GetMsg();
extern void *FindTask(), *Open();
extern void *dosalloc(), *NextNode(), *GetHead();
extern void freedata(), freeramfile(), ramunlock(), btos(), returnpacket();
extern MYLOCK *ramlock();
extern RAMFILE *searchpath(), *createramfile(), *getlockfile();
extern char *getpathelement();
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'flush.c'" '(302 characters)'
if test -f 'flush.c'
then
echo shar: "will not over-write existing file 'flush.c'"
else
cat << \!Funky!Stuff! > 'flush.c'
/*
* Allocate memory until we can't ... force the system to flush all
* non-active DOS devices, libraries, fonts, etc....
*/
extern void *AllocMem();
main()
{
char *ptr;
long bytes = 1 << 9;
while (ptr = AllocMem(bytes, MEMF_PUBLIC)) {
FreeMem(ptr, bytes);
bytes <<= 1;
}
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: "extracting 'mountlist'" '(89 characters)'
if test -f 'mountlist'
then
echo shar: "will not over-write existing file 'mountlist'"
else
cat << \!Funky!Stuff! > 'mountlist'
TEST: Handler = ram:device
Stacksize = 2048
Priority = 5
GlobVec = 1
#
!Funky!Stuff!
fi # end of overwriting check
exit 0
# End of shell archive