Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watmath!clyde!cbosgd!ihnp4!inuxc!iuvax!pur-ee!j.cc.purdue.edu!h.cc.purdue.edu!s.cc.purdue.edu!qix From: qix@s.cc.purdue.edu.UUCP Newsgroups: comp.sources.amiga Subject: P: a pipe-handler (shar 2 of 2) Message-ID: <466@s.cc.purdue.edu> Date: Wed, 8-Jul-87 02:51:34 EDT Article-I.D.: s.466 Posted: Wed Jul 8 02:51:34 1987 Date-Received: Sat, 11-Jul-87 10:45:19 EDT Sender: doc@s.cc.purdue.edu Reply-To: doc@s.cc.purdue.edu (Craig Norborg) Distribution: world Organization: Purdue University Computing Center Lines: 1834 Approved: doc@s.cc.purdue.edu Here is part 2 of 2 of the source to Ed Puckett's pipe handler. This is the latest version including the bug fix he posted to the net. Binaries available in comp.binaries.amiga. # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # Xshar: Extended Shell Archiver. # This is part 2 out of 2. # This archive created: Wed Jul 8 01:44:10 1987 # By: Craig Norborg (Purdue University Computing Center) # Run the following text with /bin/sh to create: # loader_Mount # pipe-handler.h # pipebuf.h # pipecreate.c # pipedir.h # pipelists.c # pipelists.h # pipename.c # pipename.h # pipesched.c # prelude.asm # tap_demo cat << \SHAR_EOF > loader_Mount /* An example MOUNTLIST file enabling a 5" disk to be mounted as DF1: and an interactive serial port mounted as AUX: */ DF1: Device = trackdisk.device Unit = 1 Flags = 1 Surfaces = 2 BlocksPerTrack = 11 Reserved = 2 Interleave = 0 LowCyl = 0 ; HighCyl = 39 Buffers = 5 BufMemType = 3 # /* This is provided as an example of an alternative type of non-filing device mount. Please note that L:aux-handler is not provided, and thus this mount does not work. */ AUX: Handler = L:aux-handler Stacksize = 700 Priority = 5 # P: Handler = L:pipe-handler-loader Stacksize = 3000 Priority = 5 # SHAR_EOF cat << \SHAR_EOF > pipe-handler.h /**************************************************************************** ** File: pipe-handler.h ** Program: pipe-handler - an AmigaDOS handler for named pipes ** Version: 1.2 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 by EpAc Software. All Rights Reserved. ** ** History: 05-Jan-87 Original Version (1.0) ** 07-Feb-87 Added shared locks for individual pipes. ** PIPEDATA structure modified to include ** a FileLock structure. ** 07-Feb-87 Added #if's forautomatic pipe naming "feature" ** for pipes specified with empty names. ** 12-Feb-87 Added ParentDir packet handling. ** 12-Feb-87 Fixed bug in OpenPipe() and PipeLock(): ** they previously ignored the lock passed in ** packet. Bug uncovered when pipes became ** lockable, and thus assignable. ** 26-Mar-87 Fixed bug in ClosePipe() in pipecreate.c: not ** closing r/w mode properly (extraneous else). ** 27-Mar-87 Added PipeDupLock() to pipedir.c and the case ** for it in pipe-handler.c. This was missing ** in the original version! ** 28-Mar-87 Added code to handler() to remove ':' from ** end of handler name. This caused problems ** with Examine(); it expects no ending ':'. */ /*--------------------------------------------------------------------------- ** Compilation Flags ** ----------------- ** DEBUG : add code to open a window for debugging information. ** Messages are output as requests come in, etc. DEBUG is ** active if defined at all. ** ** (The following are active only if #defined nonzero) ** ** CON_TAP_ONLY : only CON: pipe taps are allowed. The full CON: ** specification must be given, though, like CON:0/0/100/100/z. ** ** PIPEDIR : include code so that the handler looks like a directory. ** This allows "Dir" and "List" to work, as well as "CD". ** The functions in pipedir.c are unnecessary if false. ** ** UPDATE_PIPEDATE : if PIPEDIR is true, then this controls whether or not ** the handler's date is updated with each access to a pipe, ** or is just left at its startup time. ** ** AUTONAME : include code so that specifying a null pipe name causes ** the handler to select a new, as yet unused, name. ** Unfortunately, this causes inconsistent behaviour for Lock(), ** since a null name indicates a lock is desired on the handler. ** Thus locking PIPE: and opening PIPE: reference different ** objects. */ #define CON_TAP_ONLY 0 #define PIPEDIR 1 #define UPDATE_PIPEDATE 1 #define AUTONAME 0 #define ALLOCMEM_FLAGS MEMF_PUBLIC /*--------------------------------------------------------------------------- */ typedef struct pipedata { PIPELISTNODE link; /* for list handling */ char name[PIPENAMELEN]; /* the pipe's name */ PIPEBUF *buf; /* see pipebuf.c */ BYTE flags; /* see values below */ PIPELISTHEADER readerlist; /* list of waiting read requests */ PIPELISTHEADER writerlist; /* list of waiting write requests */ BPTR tapfh; /* file handle of tap, 0 if none */ #if PIPEDIR ULONG lockct; /* number of extant locks */ struct FileLock *lock; /* this pipe's lock - see note above */ struct DateStamp accessdate; /* date last accessed */ #endif PIPEDIR } PIPEDATA; #define OPEN_FOR_READ (1 << 0) #define OPEN_FOR_WRITE (1 << 1) /* flags for pipedata struct */ /*--------------------------------------------------------------------------- ** PIPEKEYs are similar to file handles. Each successful pipe open request ** has a PIPEKEY associated with it, which in turn refers to the pipe. ** The filehandle returned to the client has the address of the PIPEKEY ** stored in its Arg1 field, so that read, write and close packets will ** identify the pipe and its mode of opening. */ typedef struct pipekey { PIPEDATA *pipe; int openmode; /* Type field of original open request */ IOTYPE iotype; /* (somewhat redundant) see pipesched.h */ } PIPEKEY; extern struct DeviceNode *DevNode; extern struct MsgPort *PipePort; extern char HandlerName[]; extern PIPELISTHEADER pipelist; extern PIPELISTHEADER tapwaitlist; extern struct MsgPort *TapReplyPort; #if PIPEDIR extern struct DateStamp PipeDate; #endif PIPEDIR #define BPTRtoCptr(Bp) ((char *) ((ULONG) (Bp) << 2)) #define CptrtoBPTR(Cp) ((BPTR) ((ULONG) (Cp) >> 2)) #define ReplyPkt(pkt) PutMsg ((pkt)->dp_Port, (pkt)->dp_Link) extern void handler ( /* StartPkt */ ); extern PIPEDATA *FindPipe ( /* name */ ); /*--------------------- ** references to system */ extern struct Library *OpenLibrary (); extern void CloseLibrary (); extern struct Task *FindTask (); extern struct MsgPort *CreatePort (); extern ULONG Wait (); extern struct Message *GetMsg (); extern void PutMsg (); extern BYTE *AllocMem (); extern void FreeMem (); extern void CopyMem (); extern struct MsgPort *DeviceProc (); extern int IoErr (); #if PIPEDIR extern struct DateStamp *DateStamp (); #endif PIPEDIR extern struct Library *AbsExecBase; /*--------------------------------- ** these are new to the 1.2 release */ #ifndef MODE_READWRITE # define MODE_READWRITE 1004 #endif MODE_READWRITE #ifndef MODE_READONLY # define MODE_READONLY MODE_OLDFILE #endif MODE_READONLY #ifndef ACTION_END # define ACTION_END 1007 /* not really new, just missing */ #endif ACTION_END SHAR_EOF cat << \SHAR_EOF > pipebuf.h /**************************************************************************** ** File: pipebuf.h ** Program: pipe-handler - an AmigaDOS handler for named pipes ** Version: 1.1 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 by EpAc Software. All Rights Reserved. ** ** History: 05-Jan-87 Original Version (1.0) */ #define MAX_PIPELEN (1L << 24) typedef struct pipebuf { ULONG head, /* index of first character */ tail; /* index of last character */ BYTE full; /* flag - takes care of full/empty ambiguity */ ULONG len; /* length of buffer */ BYTE buf[1]; /* buffer proceeds from here */ } PIPEBUF; #define PipebufEmpty(pb) (((pb)->head == (pb)->tail) && (! (pb)->full)) #define PipebufFull(pb) (((pb)->head == (pb)->tail) && ((pb)->full)) #define FreePipebuf(pb) (FreeMem ((pb), sizeof (PIPEBUF) - 1 + (pb)->len)) extern PIPEBUF *AllocPipebuf ( /* len */ ); extern ULONG MoveFromPipebuf ( /* pb, dest, amt */ ); extern ULONG MoveToPipebuf ( /* pb, src, amt */ ); SHAR_EOF cat << \SHAR_EOF > pipecreate.c /**************************************************************************** ** File: pipecreate.c ** Program: pipe-handler - an AmigaDOS handler for named pipes ** Version: 1.2.1 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 by EpAc Software. All Rights Reserved. ** ** History: 05-Jan-87 Original Version (1.0) ** 07-Feb-87 Added lock initialization to OpenPipe() ** for locks on individual pipes. ** 12-Feb-87 Fixed bug in OpenPipe(): previously ignored ** lock passed in packet. Bug uncovered when ** pipes became lockable, and thus assignable. ** 26-Mar-87 Fixed bug in ClosePipe(): not closing r/w ** mode properly (extraneous else). */ #include#include #include #include #include "pipelists.h" #include "pipename.h" #include "pipebuf.h" #include "pipecreate.h" #include "pipesched.h" #include "pipe-handler.h" #if PIPEDIR # include "pipedir.h" #endif PIPEDIR #ifdef DEBUG # include "pipedebug.h" #endif DEBUG /*--------------------------------------------------------------------------- ** pipecreate.c ** ------------ ** This module handles opens and closes for pipes. ** ** Visible Functions ** ----------------- ** void OpenPipe (pkt, tapfh) ** void ClosePipe (pkt) ** void DiscardPipe (pipe) ** ** Macros (in pipecreate.h) ** ------------------------ ** - none - ** ** Local Functions ** --------------- ** int TapFormsLoop (tapfh, pipe) ** void OpenTap (pkt, tapname) ** void CloseTap (tapfh) */ /*--------------------------------------------------------------------------- ** OpenPipe() handles open requests. The DosPacket from the client and the ** filehandle of the tap are sent. If tapfh is 0, but the name sent ** indicates a tap is desired (see ParsePipeName() in pipename.c), then ** an OpenTap() request is initiated and OpenPipe() is immediately exited. ** Later, when the request returns (to HandleTapReply()), OpenPipe() is ** called again with the same client packet and the newly returned tapfh. ** If tapfh is nonzero, or if it is zero but no tap is desired, then ** the an attempt to open the pipe is made. If a existent pipe with a tap is ** to be opened and a new tapfh is given, the old tap is closed. ** If the name's syntax is incorrect, then the request is returned ** unsuccessful. Otherwise, if the pipe named by the request does not ** already exist, a new pipe is created (if there is enough memory). ** If it does exist, but it is already open for the mode requested, an error ** is returned (a maximum of one reader and one writer is allowed). ** A successful open returns the client's filehandle with its Arg1 field ** pointing to a PIPEKEY, which in turn identifies the pipe and open mode. ** Unless an OpenTap() is required, the packet is returned to the cleint ** by this function. If an OpenTap() is required, it will be returned by the ** the later call to this function when the tap open request is returned. ** Note: the code which checks if the lock sent in the packet relies on ** the fact that the pipe-handler does not allow subdirectories. If a lock ** on a pipe is passed in, then that pipe is opened. Otherwise, the name is ** parsed without reference to the lock. */ void OpenPipe (pkt, tapfh) struct DosPacket *pkt; BPTR tapfh; { void OpenTap(), CloseTap(); LONG openmode; struct FileHandle *handle; struct FileLock *lock; char *pipename = NULL, *tapname = NULL; ULONG pipesize; PIPEKEY *pipekey = NULL; PIPEDATA *pipe; int TapFormsLoop(); pkt->dp_Res1= 0; /* error, for now */ if (! ParsePipeName (BPTRtoCptr (pkt->dp_Arg3), &pipename, &pipesize, &tapname)) { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME; goto OPENREPLY; } if ( (tapfh == 0) && (tapname != NULL) && (tapname[0] != '\0') ) { OpenTap (pkt, tapname); /* start tap open request */ return; /* HandleTapReply() re-calls when request returns */ } openmode= pkt->dp_Type; lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg2); pipe= NULL; if ( (lock == NULL) || ((pipe= (PIPEDATA *) lock->fl_Key) == NULL) ) { if (pipename[0] == '\0') #if AUTONAME pipename= get_autoname ((openmode == MODE_NEWFILE) || (openmode == MODE_READWRITE)); #else !AUTONAME { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME; goto OPENREPLY; } #endif AUTONAME pipe= FindPipe (pipename); } else /* packet's lock was on the pipe */ { if (pipename[0] != '\0') { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME; goto OPENREPLY; } pipename= pipe->name; } handle= (struct FileHandle *) BPTRtoCptr (pkt->dp_Arg1); if ((pipekey= (PIPEKEY *) AllocMem (sizeof (PIPEKEY), ALLOCMEM_FLAGS)) == NULL) { pkt->dp_Res2= ERROR_NO_FREE_STORE; goto OPENREPLY; } if (pipe == NULL) /* then PIPE NOT FOUND */ { if (openmode == MODE_READONLY) { pkt->dp_Res2= ERROR_OBJECT_NOT_FOUND; goto OPENREPLY; } pkt->dp_Res2= ERROR_NO_FREE_STORE; /* in case of AllocMem error */ if ((pipe= (PIPEDATA *) AllocMem (sizeof (PIPEDATA), ALLOCMEM_FLAGS)) == NULL) goto OPENMEMERR1; if ((pipe->buf= AllocPipebuf (pipesize)) == NULL) goto OPENMEMERR2; if ((pipe->lock= (struct FileLock *) AllocMem (sizeof (struct FileLock), ALLOCMEM_FLAGS)) == NULL) { FreePipebuf (pipe->buf); OPENMEMERR2: FreeMem (pipe, sizeof (PIPEDATA)); OPENMEMERR1: goto OPENREPLY; } l_strcpy (pipe->name, pipename); pipekey->pipe= pipe; pipekey->openmode= openmode; if (openmode == MODE_READONLY) { pipekey->iotype= PIPEREAD; pipe->flags |= OPEN_FOR_READ; } else if (openmode == MODE_NEWFILE) { pipekey->iotype= PIPEWRITE; pipe->flags= OPEN_FOR_WRITE; } else /* MODE_READWRITE */ { pipekey->iotype= PIPERW; pipe->flags= (OPEN_FOR_READ | OPEN_FOR_WRITE); } InitList (&pipe->readerlist); InitList (&pipe->writerlist); pipe->tapfh= tapfh; #if PIPEDIR pipe->lockct= 0; InitLock (pipe->lock, pipe); #endif PIPEDIR InsertTail (&pipelist, pipe); /* at tail for directory's sake */ #ifdef DEBUG OS ("*** created pipe '"); OS (pipe->name); OS ("' [buflen "); OL (pipe->buf->len); OS ("]\n"); #endif DEBUG } else /* PIPE WAS FOUND */ { if (TapFormsLoop (tapfh, pipe)) { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME; goto OPENREPLY; } pipekey->pipe= pipe; pipekey->openmode= openmode; pkt->dp_Res2= ERROR_OBJECT_IN_USE; /* in case of openmode error */ if (openmode == MODE_READONLY) { if (pipe->flags & OPEN_FOR_READ) goto OPENREPLY; pipekey->iotype= PIPEREAD; pipe->flags |= OPEN_FOR_READ; } else if (openmode == MODE_NEWFILE) { if (pipe->flags & OPEN_FOR_WRITE) goto OPENREPLY; pipekey->iotype= PIPEWRITE; pipe->flags |= OPEN_FOR_WRITE; } else /* MODE_READWRITE */ { if (pipe->flags & (OPEN_FOR_READ | OPEN_FOR_WRITE)) goto OPENREPLY; pipekey->iotype= PIPERW; pipe->flags= (OPEN_FOR_READ | OPEN_FOR_WRITE); } if (tapfh != 0) { if (pipe->tapfh != 0) CloseTap (pipe->tapfh); /* close old tap first */ pipe->tapfh= tapfh; } } handle->fh_Arg1= (LONG) pipekey; /* for identification on Read, Write, Close */ pkt->dp_Res1= 1; pkt->dp_Res2= 0; /* for successful open */ OPENREPLY: if (pkt->dp_Res1 == 0) /* then there was an error */ { if (pipekey != NULL) FreeMem (pipekey, sizeof (PIPEKEY)); if (tapfh != 0) CloseTap (tapfh); } #if PIPEDIR else SetPipeDate (pipe); #endif PIPEDIR ReplyPkt (pkt); } /*--------------------------------------------------------------------------- ** This routine checks for "the old loop in the pipe trick" (86). If the ** handler has a loop through its tap, the handler will endlessly pass ** packets to itself. This would be disastrous if the handler is running at ** high priority. */ static int TapFormsLoop (tapfh, pipe) BPTR tapfh; PIPEDATA *pipe; { struct FileHandle *handle; PIPEKEY *tapkey; PIPEDATA *tappipe; int numchecks; /* protection */ for (numchecks= 0; ((tapfh != 0) && (numchecks < 10000)); ++numchecks) { handle= (struct FileHandle *) BPTRtoCptr (tapfh); if (handle->fh_Type == PipePort) /* then the tap is a pipe, too */ { if ( ((tapkey= (PIPEKEY *) handle->fh_Arg1) == NULL) || ((tappipe= tapkey->pipe) == NULL) ) return FALSE; if (tappipe == pipe) return TRUE; tapfh= tappipe->tapfh; } else return FALSE; } return FALSE; } /*--------------------------------------------------------------------------- ** The previous open performed on a pipe is terminated. The PIPEKEY ** allocated for the client when the pipe was opened is freed. Then, ** CheckWaiting() is called -- it will discard the pipe if it becomes empty ** and is not opened for read or write. */ void ClosePipe (pkt) struct DosPacket *pkt; { PIPEKEY *pipekey; PIPEDATA *pipe; void DeletePipe(); pipekey= (PIPEKEY *) pkt->dp_Arg1; pipe= pipekey->pipe; if ((pipekey->iotype == PIPEREAD) || (pipekey->iotype == PIPERW)) pipe->flags &= ~OPEN_FOR_READ; if ((pipekey->iotype == PIPEWRITE) || (pipekey->iotype == PIPERW)) pipe->flags &= ~OPEN_FOR_WRITE; FreeMem (pipekey, sizeof (PIPEKEY)); CheckWaiting (pipe); /* will discard if empty */ pkt->dp_Res1= 1; pkt->dp_Res2= 0; ReplyPkt (pkt); } /*--------------------------------------------------------------------------- ** Remove a pipe from the pipe list and release its memory. The pipe is ** assumed empty and having no clients. */ void DiscardPipe (pipe) PIPEDATA *pipe; { #ifdef DEBUG OS ("*** discarding pipe '"); OS (pipe->name); OS ("'\n"); #endif DEBUG Delete (&pipelist, pipe); FreePipebuf (pipe->buf); FreeMem (pipe->lock, sizeof (struct FileLock)); if (pipe->tapfh != 0) CloseTap (pipe->tapfh); FreeMem (pipe, sizeof (PIPEDATA)); } /*--------------------------------------------------------------------------- ** An open request for a tap is performed. A WAITINGDATA structure is ** allocated to hold the client packet until later. HandleTapReply() will ** deal with the reply and, if successful, re-call OpenPipe(). */ static void OpenTap (pkt, tapname) struct DosPacket *pkt; char *tapname; { char *Bname; struct FileHandle *handle; WAITINGDATA *wd; struct DosPacket *tappkt; struct MsgPort *Handler; struct FileLock *Lock; void StartTapIO(); if ( (tapname == NULL) || ((Bname= (char *) AllocMem (OPENTAP_STRSIZE, ALLOCMEM_FLAGS)) == NULL) ) goto OPENTAPERR; if ((handle= (struct FileHandle *) AllocMem (sizeof (struct FileHandle), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL) goto OPENTAPERR1; if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL) goto OPENTAPERR2; if ((tappkt= AllocPacket (TapReplyPort)) == NULL) goto OPENTAPERR3; if ((Handler= DeviceProc (tapname)) == NULL) { FreePacket (tappkt); OPENTAPERR3: FreeMem (wd, sizeof (WAITINGDATA)); OPENTAPERR2: FreeMem (handle, sizeof (struct FileHandle)); OPENTAPERR1: FreeMem (Bname, OPENTAP_STRSIZE); OPENTAPERR: pkt->dp_Res1= 0; pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME; ReplyPkt (pkt); return; } Lock= (struct FileLock *) IoErr (); CstrtoBSTR (tapname, Bname, OPENTAP_STRSIZE); handle->fh_Pos= -1; handle->fh_End= -1; handle->fh_Type= Handler; /* initialize file handle */ wd->pkt= tappkt; wd->pktinfo.tapwait.clientpkt= pkt; wd->pktinfo.tapwait.handle= handle; /* for HandleTapReply() */ StartTapIO ( tappkt, MODE_NEWFILE, CptrtoBPTR (handle), CptrtoBPTR (Lock), CptrtoBPTR (Bname), Handler ); InsertHead (&tapwaitlist, wd); } /*--------------------------------------------------------------------------- ** A close request for a tap filehandle is initiated. When HandleTapReply() ** gets the reply, it merely discards it. */ static void CloseTap (tapfh) BPTR tapfh; { struct FileHandle *taphandle; struct DosPacket *tappkt; WAITINGDATA *wd; void StartTapIO(); taphandle= (struct FileHandle *) BPTRtoCptr (tapfh); if ((tappkt= AllocPacket (TapReplyPort)) == NULL) goto CLOSETAPERR; if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL) { FreePacket (tappkt); CLOSETAPERR: FreeMem (taphandle, sizeof (struct FileHandle)); #ifdef DEBUG OS ("!!! ERROR - CloseTap() failed\n"); #endif DEBUG return; } wd->pkt= tappkt; /* don't need ...tapwait.clientpkt */ wd->pktinfo.tapwait.handle= taphandle; /* for HandleTapReply() */ StartTapIO ( tappkt, ACTION_END, taphandle->fh_Arg1, 0, 0, taphandle->fh_Type ); InsertHead (&tapwaitlist, wd); } SHAR_EOF cat << \SHAR_EOF > pipedir.h /**************************************************************************** ** File: pipedir.h ** Program: pipe-handler - an AmigaDOS handler for named pipes ** Version: 1.2 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 by EpAc Software. All Rights Reserved. ** ** History: 05-Jan-87 Original Version (1.0) ** 07-Feb-87 Added modifications for allowing shared locks ** on individual pipes. ** 12-Feb-87 Added PipeParentDir. ** 12-Feb-87 Fixed bug in PipeLock(): previously ignored ** lock passed in packet. Bug uncovered when ** pipes became lockable, and thus assignable. ** 27-Mar-87 Added PipeDupLock(). This was missing ** in the original version! */ extern void SetPipeDate ( /* pipe */ ); extern void PipeLock ( /* pkt */ ); extern void PipeDupLock ( /* pkt */ ); extern void PipeUnLock ( /* pkt */ ); extern void PipeExamine ( /* pkt */ ); extern void PipeExNext ( /* pkt */ ); extern void PipeParentDir ( /* pkt */ ); extern void InitLock ( /* lock, key */ ); SHAR_EOF cat << \SHAR_EOF > pipelists.c /**************************************************************************** ** File: pipelists.c ** Program: pipe-handler - an AmigaDOS handler for named pipes ** Version: 1.1 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 by EpAc Software. All Rights Reserved. ** ** History: 05-Jan-87 Original Version (1.0) */ #include #include "pipelists.h" /*--------------------------------------------------------------------------- ** pipelists.c ** ----------- ** This module contains functions and macros for list manipulation. ** To use its functions, a PIPELISTNODE must be part of the structure to be ** inserted in a list. A list is identified by a PIPELISTHEADER (not a ** pointer to, but an actual PIPELISTHEADER structure). ** These routines, as implemented, use the fact that a PIPELISTHEADER ** and a PIPELISTNODE have the same struture. Loops are started with the ** scanning pointer referencing the header. This makes processing uniform, ** even when the list is empty. ** ** Visible Functions ** ----------------- ** void InsertHead (headerp, nodep) ** void InsertTail (headerp, nodep) ** void Delete (headerp, nodep) ** ** Macros (in pipelists.h) ** ----------------------- ** InitList (headerp) ** FirstItem (headerp) ** NextItem (nodep) ** ** Local Functions ** --------------- ** - none - */ /*--------------------------------------------------------------------------- ** Insert the node pointed to by "nodep" at the head (front) of the list ** identified by "headerp". */ void InsertHead (headerp, nodep) PIPELISTHEADER *headerp; PIPELISTNODE *nodep; { nodep->next= headerp->head; headerp->head= nodep; } /*--------------------------------------------------------------------------- ** Insert the node pointed to by "nodep" at the tail (end) of the list ** identified by "headerp". */ void InsertTail (headerp, nodep) PIPELISTHEADER *headerp; PIPELISTNODE *nodep; { register PIPELISTNODE *l; for (l= (PIPELISTNODE *) headerp; l->next != NULL; l= l->next) ; l->next= nodep; nodep->next= NULL; } /*--------------------------------------------------------------------------- ** Delete the node pointed to by "nodep" from the list identified by ** "headerp". If the node is not found in the list, nothing is done. */ void Delete (headerp, nodep) PIPELISTHEADER *headerp; PIPELISTNODE *nodep; { PIPELISTNODE *l; for (l= (PIPELISTNODE *) headerp; l->next != NULL; l= l->next) if (l->next == nodep) { l->next= l->next->next; break; } } SHAR_EOF cat << \SHAR_EOF > pipelists.h /**************************************************************************** ** File: pipelists.h ** Program: pipe-handler - an AmigaDOS handler for named pipes ** Version: 1.1 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 by EpAc Software. All Rights Reserved. ** ** History: 05-Jan-87 Original Version (1.0) */ typedef struct pipelistnode /* must be first member of list items */ { struct pipelistnode *next; } PIPELISTNODE; typedef struct pipelistheader { struct pipelistnode *head; } PIPELISTHEADER; #define InitList(headerp) ((void) ((headerp)->head= NULL)) #define FirstItem(headerp) ((headerp)->head) #define NextItem(nodep) (((PIPELISTNODE *) (nodep))->next) extern void InsertHead ( /* headerp, nodep */ ); extern void InsertTail ( /* headerp, nodep */ ); extern void Delete ( /* headerp, nodep */ ); SHAR_EOF cat << \SHAR_EOF > pipename.c /**************************************************************************** ** File: pipename.c ** Program: pipe-handler - an AmigaDOS handler for named pipes ** Version: 1.1 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 by EpAc Software. All Rights Reserved. ** ** History: 05-Jan-87 Original Version (1.0) ** 07-Feb-87 Added conditional compilation for autoname. */ #include #include #include #include #include "pipelists.h" #include "pipename.h" #include "pipebuf.h" #include "pipecreate.h" #include "pipesched.h" #include "pipe-handler.h" /*--------------------------------------------------------------------------- ** pipename.c ** ---------- ** This module contains functions related to the parsing of the pipe names. ** ** Visible Functions ** ----------------- ** int ParsePipeName (Bname, nmp, sizep, tapnmp) ** void BSTRtoCstr (BSTRp, str, maxsize) ** void CstrtoBSTR (str, BSTRp, maxsize) ** int inrange (x, lower, upper) ** char uppercase (c) ** char *findchar (str, ch) ** void l_strcpy (to, from) ** char *strdiff (str1, str2) ** char *get_autoname (newflag) (if AUTONAME is true) ** ** Macros (in pipename.h) ** ---------------------- ** isnumeral (c) ** ** Local Functions ** --------------- ** int ParseNum (str, nump) */ /*--------------------------------------------------------------------------- ** ParsePipeName() parses the string "Bname" into three parts: a pipe name, ** a size specification and a tap name. (Bname must be the byte address of a ** BSTR, i.e., a string whose first byte is its length.) The three parts are ** separated by the character PIPE_SPEC_CHAR (defined in pipename.h). ** Assuming that PIPE_SPEC_CHAR is '/', and that '[]' are metacharacters ** which enclose optional parts, the syntax for Bname is [D:][p][/n][/[t]]. ** Here, "D" represents a device name, "p" represents a pipe name, ** "n" represents a number and "t" represents a tap name. ** ParsePipeName() returns nonzero iff "Bname" conforms to the syntax ** and the following restrictions. ** "D:" represents a device name. If it occurs, it is ignored. Notice ** that tap names which contain a ":" force a device name to be specified for ** the pipe. Otherwise, everything up to and including the ":" in the tap ** name will be ignored. ** *nmp returns pointing to a copy of "p", even if it is empty. Default ** pipe names are handled by calling get_autoname(). (This is done by ** OpenPipe() if *nmp returns empty.) ** "n" must begin with a digit. If "n" begins with "0x", it is parsed ** as a hexadecimal number. If it begins with "0" but not "0x", it is parsed ** as an octal number. Otherwise, it is parsed as a decimal number. If the ** size specifier ("/t" above) is not given, *sizep is set to DEFAULT_PIPELEN. ** If the compile-time flag CON_TAP_ONLY is set, "t" may only be a "CON:" ** file specifier, such as "CON:10/10/400/120/TapWindow". If CON_TAP_ONLY is ** not set, string is accepted. If "t" is empty (but the PIPE_SPEC_CHAR was ** given), then a defualt tap name is formed by appending "p" to ** DEFAULT_TAPNAME_PREFIX. If the tap name specifier ("/[t]" above) is not ** given, *tapnmp is set to NULL. */ static char default_tapname_prefix[] = DEFAULT_TAPNAME_PREFIX; static char namebuf[sizeof (default_tapname_prefix) + PIPENAMELEN]; int ParsePipeName (Bname, nmp, sizep, tapnmp) BYTE *Bname; /* reference to BSTR name sent to handler */ char **nmp; /* reference to pipe name pointer */ ULONG *sizep; /* size longword pointer */ char **tapnmp; /* reference to tap name pointer, returns NULL if none */ { char *cp; int ParseNum(); l_strcpy (namebuf, default_tapname_prefix); *nmp= namebuf + (sizeof (default_tapname_prefix) - 1); *sizep= DEFAULT_PIPELEN; *tapnmp= NULL; BSTRtoCstr (Bname, *nmp, PIPENAMELEN); if (*(cp= findchar (*nmp, ':')) == ':') l_strcpy (*nmp, ++cp); /* get rid of "devname:" prefix */ if ( *(cp= findchar (*nmp, PIPE_SPEC_CHAR)) ) /* true if not '\0' */ { *(cp++)= '\0'; /* terminate pipe name */ if (isnumeral (*cp)) { if ( (! ParseNum (cp, sizep)) || (*sizep <= 0) ) return FALSE; if ( *(cp= findchar (cp, PIPE_SPEC_CHAR)) == '\0' ) return TRUE; /* no tap name, but successful anyway */ ++cp; /* skip separator */ } if ( *(*tapnmp= cp) == '\0' ) /* first character of tap name */ *tapnmp= namebuf; /* use default prefix prepended to pipe name */ #if CON_TAP_ONLY else { if ( *(strdiff ("CON:", *tapnmp)) ) /* true if not '\0' */ return FALSE; /* only CON: . . . allowed */ } #endif CON_TAP_ONLY } return TRUE; } /*--------------------------------------------------------------------------- ** BSTRtoCstr() converts the BSTR pointed to by "BSTRp" (a byte address) to ** a null-terminated string, storing the result in the locations pointed to ** by "str". At most "maxsize" bytes will be stored. */ void BSTRtoCstr (BSTRp, str, maxsize) register BYTE *BSTRp; register char *str; unsigned maxsize; { register int i; register int limit; if ((limit= *(BSTRp++)) > ((int) maxsize - 1)) /* leave room for '\0' */ limit= (int) maxsize - 1; for (i= 0; i < limit; ++i) *(str++)= *(BSTRp++); *str= '\0'; } /*--------------------------------------------------------------------------- ** CstrtoBSTR() converts the null-terminated string pointed to by "str" to ** a BSTR located at the byte address "BSTRp". At most "maxsize" bytes will ** be stored. */ void CstrtoBSTR (str, BSTRp, maxsize) register char *str; BYTE *BSTRp; unsigned maxsize; { register char *bp; register int i, limit; bp= BSTRp + 1; limit= maxsize - 1; for (i= 0; i < limit; ++i) if ( (*(bp++)= *(str++)) == '\0' ) break; BSTRp[0]= i; } /*--------------------------------------------------------------------------- ** inrange() returns nonzero iff x is in the range [lower, upper]. ** uppercase() returns the uppercase version of the ASCII character sent. ** These are not implemented as macros to avoid hard-to-find bugs like ** uppercase(c++), where the side-effect occurs more than once. */ int inrange (x, lower, upper) register int x; register int lower; register int upper; { return ((x >= lower) && (x <= upper)); } char uppercase (c) register char c; { return (char) (inrange (c, 'a', 'z') ? (c + ('A' - 'a')) : c); } /*--------------------------------------------------------------------------- ** The null-terminated string "str" is scanned for the character "ch". If ** found, a pointer to its first occurrence in "str" is returned. Otherwise, ** a pointer to the terminating '\0' in "str" is returned. */ char *findchar (str, ch) register char *str; register char ch; { while ((*str != '\0') && (*str != ch)) ++str; return str; /* return position of ch, or end if not found */ } /*--------------------------------------------------------------------------- ** This is just like strcpy(). Its is defined here to avoid including other ** libraries. */ void l_strcpy (to, from) register char *to; register char *from; { STRCPYLOOP: if (*(to++)= *(from++)) goto STRCPYLOOP; } /*--------------------------------------------------------------------------- ** strdiff() returns a pointer to the first difference in the two null- ** terminated strings "str1" and "str2". If no differnce is found, or if ** "str1" is shorter than "str2", then a pointer to '\0' is returned. ** The returned pointer is to a character in "str1". */ char *strdiff (str1, str2) register char *str1; register char *str2; { while ( *str1 && (uppercase (*str1) == uppercase (*str2)) ) { ++str1; ++str2; } return str1; /* return position of first difference, or end of str1 */ } /*--------------------------------------------------------------------------- ** get_autoname() returns a pointer to "autoname". If "newflag" is nonzero, ** autoname is first updated so that it does not conflict with any existing ** pipe name. This is done by looking for a block of ASCII digits in ** "autoname", and incrementing their effective value. "autoname" MUST ** contain such a block of digits. */ #if AUTONAME static char autoname[] = AUTONAME_INIT; char *get_autoname (newflag) BYTE newflag; { char *cp, *cpc; PIPEDATA *FindPipe(); if (newflag) /* then create a new unique pipe name */ { cp= findchar (autoname, '\0'); while (! isnumeral (*cp)) /* find last numeral */ --cp; do { ++(*cp); /* "increment" name */ for (cpc= cp; (! isnumeral (*cpc)); ) /* ripple carry */ { *(cpc--)= '0'; if (! isnumeral (*cpc)) break; /* no more digits */ ++(*cpc); } } while (FindPipe (autoname) != NULL); /* repeat until name is unique */ } return autoname; } #endif AUTONAME /*--------------------------------------------------------------------------- ** ParseNum() parses the null-terminated string pointed to by "str" into a ** number, and stores its value in *nump. ParseNum() returns nonzero iff ** successful. Both '\0' and PIPE_SPEC_CHAR are acceptable terminators for ** the number. ** If the number begins with "0x", it is interpreted as hexadecimal. ** If it begins with "0" but not "0x", it is interpreted as octal. ** Otherwise, it is interpreted as decimal. */ static int ParseNum (str, nump) char *str; ULONG *nump; { int radix = 10; char *digits = "0123456789ABCDEF"; LONG value; if ((*str == '0') && (uppercase (*(str + 1)) == 'X')) { radix= 16; str += 2; } else if (*str == '0') { radix= 8; ++str; } for (*nump= 0; TRUE; ++str) { value= (LONG) findchar (digits, uppercase (*str)) - (LONG) digits; if (! inrange (value, 0, (radix - 1))) break; if (*nump > ((MAX_PIPELEN - value) / radix)) return FALSE; *nump *= radix; *nump += value; } return ( (*str == PIPE_SPEC_CHAR) || (*str == '\0') ); } SHAR_EOF cat << \SHAR_EOF > pipename.h /**************************************************************************** ** File: pipename.h ** Program: pipe-handler - an AmigaDOS handler for named pipes ** Version: 1.1 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 by EpAc Software. All Rights Reserved. ** ** History: 05-Jan-87 Original Version (1.0) ** 07-Feb-87 Added conditional compilation for autoname. */ /*--------------------------------------------------------------------------- ** PIPENAMELEN : this is the maximum length of names ParsePipeName() ** can handle. ** ** DEFAULT_PIPELEN : the default pipe size returned by ParsePipeName() ** if no size is specified. ** ** PIPE_SPEC_CHAR : this is the character used by ParsePipeName() as an ** identifier for specifiers. See pipename.c ** ** DEFAULT_TAPNAME_PREFIX : the prefix for default tap names. See pipename.c ** ** AUTONAME_INIT : Initial value used by get_autoname() to form ** default pipe names. It MUST contain a block of ** digits. See pipename.c. ** This is only used if AUTONAME is true. */ #define PIPENAMELEN 108 #define DEFAULT_PIPELEN 4096 #define PIPE_SPEC_CHAR '/' #define DEFAULT_TAPNAME_PREFIX "CON:10/15/300/70/" #if AUTONAME # define AUTONAME_INIT "$00000000" #endif AUTONAME #define isnumeral(c) inrange ((c), '0', '9') extern int ParsePipeName ( /* Bname, nmp, sizep, tapnmp */ ); extern void BSTRtoCstr ( /* BSTRp, str, maxsize */ ); extern void CstrtoBSTR ( /* str, BSTRp, maxsize */ ); extern int inrange ( /* x, lower, upper */ ); extern char uppercase ( /* c */ ); extern char *findchar ( /* str, ch */ ); extern void l_strcpy ( /* to, from */ ); extern char *strdiff ( /* str1, str2 */ ); #if AUTONAME extern char *get_autoname ( /* newflag */ ); #endif AUTONAME SHAR_EOF cat << \SHAR_EOF > pipesched.c /**************************************************************************** ** File: pipesched.c ** Program: pipe-handler - an AmigaDOS handler for named pipes ** Version: 1.1 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 by EpAc Software. All Rights Reserved. ** ** History: 05-Jan-87 Original Version (1.0) ** 07-Feb-87 Added "lockct" check in CheckWaiting(). */ #include #include #include #include #include "pipelists.h" #include "pipename.h" #include "pipebuf.h" #include "pipecreate.h" #include "pipesched.h" #include "pipe-handler.h" #if PIPEDIR # include "pipedir.h" #endif PIPEDIR #ifdef DEBUG # include "pipedebug.h" #endif DEBUG /*--------------------------------------------------------------------------- ** pipesched.c ** ----------- ** This module handles pipe I/O scheduling. ** ** Visible Functions ** ----------------- ** void StartPipeIO (pkt, iotype) ** void CheckWaiting (pipe) ** struct DosPacket *AllocPacket (ReplyPort) ** void FreePacket (pkt) ** void StartTapIO (pkt, Type, Arg1, Arg2, Arg3, Handler) ** void HandleTapReply (pkt) ** ** Macros (in pipesched.h) ** ----------------------- ** - none - ** ** Local Functions ** --------------- ** void EndPipeIO (pipe, wd) */ /*--------------------------------------------------------------------------- ** A pipe I/O request is begun. A WAITINGDATA structure is allocated and ** the request is stored in it. It is then stored in the appropriate list ** (readerlist or writerlist) of the pipe. Finally, CheckWaiting is called ** to service requests for that pipe. ** Notice that CheckWaiting() is only called when a new I/O request ** comes in, or when the pipe is closed. At no other time will the state of ** the pipe change in such a way that more requests for it can be honored. */ void StartPipeIO (pkt, iotype) struct DosPacket *pkt; IOTYPE iotype; /* assumed only PIPEREAD or PIPEWRITE */ { PIPEKEY *pipekey; PIPEDATA *pipe; WAITINGDATA *wd; if ((iotype != PIPEREAD) && (iotype != PIPEWRITE)) { pkt->dp_Res2= ERROR_ACTION_NOT_KNOWN; SPIOEXIT: pkt->dp_Res1= -1; ReplyPkt (pkt); return; } pipekey= (PIPEKEY *) pkt->dp_Arg1; pipe= pipekey->pipe; if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL) { pkt->dp_Res2= ERROR_NO_FREE_STORE; goto SPIOEXIT; } pkt->dp_Res2= ERROR_INVALID_LOCK; /* in case not open for iotype */ if (iotype == PIPEREAD) { if ((pipekey->iotype != PIPEREAD) && (pipekey->iotype != PIPERW)) goto SPIOEXIT; InsertTail (&pipe->readerlist, wd); } else /* PIPEWRITE */ { if ((pipekey->iotype != PIPEWRITE) && (pipekey->iotype != PIPERW)) goto SPIOEXIT; InsertTail (&pipe->writerlist, wd); } wd->pkt= pkt; wd->pktinfo.pipewait.reqtype= iotype; wd->pktinfo.pipewait.buf= (BYTE *) pkt->dp_Arg2; /* buffer */ wd->pktinfo.pipewait.len= (ULONG) pkt->dp_Arg3; /* length */ CheckWaiting (pipe); } /*--------------------------------------------------------------------------- ** Read requests for the pipe are satisfied until the pipe is empty or no ** more requests are left. Then, write requests are satisifed until the pipe ** is full or no more requests are left. This alternating process is ** repeated until no further changes are possible. ** Finished requests are sent to EndPipeIO() so that replies may be sent ** to their owners. Aftereward, if the pipe is empty and is not open for ** either read or write, then it is discarded. If it is open for read, but ** is empty and has no write requests and is not open for write, then all ** remaining read requests are returned in their current state. (This ** implements EOF.) A pipe with a positive "lockct" will not be discarded. ** UnLock() is expected to call here so that a previously locked, empty pipe ** will be discarded. */ void CheckWaiting (pipe) PIPEDATA *pipe; { BYTE change; WAITINGDATA *wd; ULONG amt; void EndPipeIO(); #if PIPEDIR SetPipeDate (pipe); #endif PIPEDIR for (change= TRUE; change; ) { change= FALSE; while ( (! (PipebufEmpty (pipe->buf))) && ((wd= (WAITINGDATA *) FirstItem (&pipe->readerlist)) != NULL) ) { amt= MoveFromPipebuf (pipe->buf, wd->pktinfo.pipewait.buf, wd->pktinfo.pipewait.len); if (amt) { wd->pktinfo.pipewait.buf += amt; wd->pktinfo.pipewait.len -= amt; change= TRUE; } if (wd->pktinfo.pipewait.len == 0L) /* then finished with request */ EndPipeIO (pipe, wd); } /* end of readerlist loop */ while ( (! (PipebufFull (pipe->buf))) && ((wd= (WAITINGDATA *) FirstItem (&pipe->writerlist)) != NULL) ) { amt= MoveToPipebuf (pipe->buf, wd->pktinfo.pipewait.buf, wd->pktinfo.pipewait.len); if (amt) { wd->pktinfo.pipewait.buf += amt; wd->pktinfo.pipewait.len -= amt; change= TRUE; } if (wd->pktinfo.pipewait.len == 0L) /* then finished with request */ EndPipeIO (pipe, wd); } /* end of writerlist loop */ } if ( PipebufEmpty (pipe->buf) && (! (pipe->flags & OPEN_FOR_WRITE)) && (FirstItem (&pipe->writerlist) == NULL) ) /* then EOF */ { while ((wd= (WAITINGDATA *) FirstItem (&pipe->readerlist)) != NULL) EndPipeIO (pipe, wd); if (! (pipe->flags & OPEN_FOR_READ)) /* readerlist is now empty */ #if PIPEDIR if (pipe->lockct == 0) #endif PIPEDIR DiscardPipe (pipe); } } /*--------------------------------------------------------------------------- ** This routine returns a finished pipe I/O request. If it is a write ** request to a pipe with a tap, then the same write request is sent to the ** tap, and the reply is deferred until HandleTapReply() gets the tap request ** reply. (This lets the user stop a pipe by typing a character into a ** tap window.) */ static void EndPipeIO (pipe, wd) PIPEDATA *pipe; WAITINGDATA *wd; { struct DosPacket *pkt, *tappkt; struct FileHandle *taphandle; pkt= wd->pkt; pkt->dp_Res1= pkt->dp_Arg3 - wd->pktinfo.pipewait.len; pkt->dp_Res2= 0; if (wd->pktinfo.pipewait.reqtype == PIPEREAD) { Delete (&pipe->readerlist, wd); ReplyPkt (pkt); FreeMem (wd, sizeof (WAITINGDATA)); } else /* must be PIPEWRITE -- reqtype is new PIPERW */ { Delete (&pipe->writerlist, wd); if (pipe->tapfh != 0) /* then write to the pipe tap */ { if ((tappkt= AllocPacket (TapReplyPort)) == NULL) { ReplyPkt (pkt); FreeMem (wd, sizeof (WAITINGDATA)); #ifdef DEBUG OS ("!!! ERROR - Could not allocate packet for tap write\n"); #endif DEBUG } else { wd->pkt= tappkt; /* reuse wd for tap write request */ wd->pktinfo.tapwait.clientpkt= pkt; /* don't need ...tapwait.handle */ taphandle= (struct FileHandle *) BPTRtoCptr (pipe->tapfh); StartTapIO ( tappkt, ACTION_WRITE, taphandle->fh_Arg1, pkt->dp_Arg2, pkt->dp_Arg3, taphandle->fh_Type ); InsertHead (&tapwaitlist, wd); /* for HandleTapReply() */ } } else /* otherwise, return finished packet */ { ReplyPkt (pkt); FreeMem (wd, sizeof (WAITINGDATA)); } } } /*--------------------------------------------------------------------------- ** An exec Message and a DosPacket are allocated, and they are initialized. ** A pointer to the packet is returned, or NULL if it could not be allocated. */ struct DosPacket *AllocPacket (ReplyPort) struct MsgPort *ReplyPort; { struct Message *msg; struct DosPacket *pkt; if ((msg = (struct Message *) AllocMem (sizeof (struct Message), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL) return NULL; if ((pkt = (struct DosPacket *) AllocMem (sizeof (struct DosPacket), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL) { FreeMem (msg, sizeof (struct Message)); return NULL; } msg->mn_Node.ln_Type= NT_MESSAGE; msg->mn_Node.ln_Name= (char *) pkt; msg->mn_ReplyPort= ReplyPort; pkt->dp_Link= msg; pkt->dp_Port= ReplyPort; return pkt; } /*--------------------------------------------------------------------------- ** A DosPacket/exec Message pair is freed. */ void FreePacket (pkt) struct DosPacket *pkt; { if (pkt != NULL) { if (pkt->dp_Link != NULL) FreeMem (pkt->dp_Link, sizeof (struct Message)); FreeMem (pkt, sizeof (struct DosPacket)); } } /*--------------------------------------------------------------------------- ** The indicated fields are filled into the packet and it is sent. */ void StartTapIO (pkt, Type, Arg1, Arg2, Arg3, Handler) struct DosPacket *pkt; LONG Type; LONG Arg1; LONG Arg2; LONG Arg3; struct MsgPort *Handler; { pkt->dp_Type= Type; pkt->dp_Arg1= Arg1; pkt->dp_Arg2= Arg2; pkt->dp_Arg3= Arg3; PutMsg (Handler, pkt->dp_Link); } /*--------------------------------------------------------------------------- ** Handle replies from tap I/O requests. These were initiated by OpenTap(), ** CloseTap() and EndPipeIO(). */ void HandleTapReply (pkt) struct DosPacket *pkt; { WAITINGDATA *wd; for (wd= (WAITINGDATA *) FirstItem (&tapwaitlist); wd != NULL; wd= (WAITINGDATA *) NextItem (wd)) if (wd->pkt == pkt) { Delete (&tapwaitlist, wd); break; } if (wd == NULL) { #ifdef DEBUG OS ("!!! ERROR - WAITINGDATA not found in HandleTapReply()\n"); #endif DEBUG FreePacket (pkt); return; /* not found - this should never happen */ } switch (pkt->dp_Type) { case MODE_READWRITE: case MODE_READONLY: case MODE_NEWFILE: /* for a tap open request */ if (pkt->dp_Res1) /* then successful */ OpenPipe (wd->pktinfo.tapwait.clientpkt, pkt->dp_Arg1); else /* couldn't open tap */ { FreeMem (wd->pktinfo.tapwait.handle, sizeof (struct FileHandle)); pkt->dp_Res1= 0; pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME; ReplyPkt (wd->pktinfo.tapwait.clientpkt); } FreeMem (BPTRtoCptr (pkt->dp_Arg3), OPENTAP_STRSIZE); break; case ACTION_END: /* for a tap close request */ FreeMem (wd->pktinfo.tapwait.handle, sizeof (struct FileHandle)); break; case ACTION_WRITE: /* for a tap write request */ ReplyPkt (wd->pktinfo.tapwait.clientpkt); /* return to client */ break; #ifdef DEBUG default: /* should never happen */ OS ("!!! ERROR - bad packet type in HandleTapReply(), type ="); OL (pkt->dp_Type); NL; #endif DEBUG } FreePacket (pkt); FreeMem (wd, sizeof (WAITINGDATA)); } SHAR_EOF cat << \SHAR_EOF > prelude.asm ; prelude.asm XREF _handler StartModule: DC.L (EndModule-StartModule+3)/4 ; for BCPL linking EntryPoint: LEA SPsave(PC),A0 MOVE.L SP,(A0) ; save initial SP LSL.L #2,D1 ; convert to byte pointer MOVE.L D1,-(SP) ; startup packet pointer ; --- Now, call the loaded handler code. ; --- It is sent the byte address of the startup packet, to which ; --- it should reply. JSR _handler ; call handler code MOVEA.L SPsave(PC),SP ; restore SP RTS SPsave: DC.L 0 ; trailing definitions for BCPL linking CNOP 0,4 ; align to lonword boundary DC.L 0 ; End Marker DC.L 1 ; Global 1 DC.L EntryPoint-StartModule ; Offset DC.L 1 ; Highest Global Used EndModule: END SHAR_EOF cat << \SHAR_EOF > tap_demo dir >P:a/P:b/P:c/P:d/CON:0/0/400/100/a->b->c->d list P: dir >P:a/CON:10/10/100/50/a list P: dir >P:b/CON:20/20/100/50/b list P: dir >P:c/CON:30/30/100/50/c list P: dir >P:d/CON:40/40/100/50/d list P: type P:a list P: type P:b list P: type P:c list P: type P:d list P: SHAR_EOF