/* * XFIO.C * * Simple File IO with asyncronous READ and WRITE capability * Perfect for protocol transfer applications * * xfi = xfopen(name, modes, bufsize) ("r", "w", "w+") * n = xfread(xfi, buf, bytes) ASYNCRONOUS READ * err = xfwrite(xfi, buf, bytes) ASYNCRONOUS WRITE * err = xfclose(xfi) * * RESTRICTIONS: NO seeking. You can do one of xfread() or xfwrite() * for a given open XFIle handle (not both). * * xfwrite() returns a cumulative error (once an error occurs, it will not * do any more writes). xfclose() returns the cumulative write error * (since the last write may have been asyncronous and thus the error * unknown at the time). * * Two buffers are created each bufsize/2 bytes in size. for writing, * one buffers is sent asyncronously while the other fills. For reading, * one buffer is filling while the other is being read. */ #define XFI struct _XFI #define XFBUF struct _XFBUF #define MSGPORT struct MsgPort #define FH struct FileHandle #define STDPKT struct StandardPacket XFBUF { long bufsize; long idx; long max; char buf[4]; /* actually bufsize bytes long */ }; XFI { char ro; /* read only, else write only */ char pend; /* packet pending */ char err; /* cumulative error */ char reserved; XFBUF *asbuf; XFBUF *usbuf; FH *fh; STDPKT sp; /* asyncronous message */ MSGPORT rp; /* reply port for pending pkts */ }; extern FH *Open(); extern void *malloc(), *FindTask(); void * xfopen(file, mode, bytes) char *file; char *mode; { register XFI *xfi = malloc(sizeof(XFI)); register long nbytes = bytes >> 1; int ap = 0; bzero(xfi, sizeof(XFI)); if (mode[0] == 'w') { if (mode[1] == '+') { ap = 1; if ((xfi->fh = Open(file, 1005)) == NULL) xfi->fh = Open(file, 1006); goto ok; } xfi->fh = Open(file, 1006); goto ok; } xfi->fh = Open(file, 1005); ok: if (xfi->fh) { if (ap) Seek(xfi->fh, 0, 1); xfi->fh = (FH *)((long)xfi->fh << 2); xfi->asbuf = malloc(sizeof(XFBUF) + nbytes); /* a little more */ xfi->usbuf = malloc(sizeof(XFBUF) + nbytes); /* then we need */ bzero(xfi->asbuf, sizeof(XFBUF)); bzero(xfi->usbuf, sizeof(XFBUF)); xfi->ro = (mode[0] == 'r'); xfi->asbuf->bufsize = xfi->usbuf->bufsize = nbytes; xfi->rp.mp_Node.ln_Type = NT_MSGPORT; xfi->rp.mp_Node.ln_Name = "XFIO-Async"; xfi->rp.mp_Flags = PA_SIGNAL; xfi->rp.mp_SigBit = AllocSignal(-1); xfi->rp.mp_SigTask = FindTask(NULL); NewList(&xfi->rp.mp_MsgList); if (xfi->ro) xfstartasync(xfi, ACTION_READ); } else { free(xfi); xfi = NULL; } return(xfi); } xfclose(xfi) register XFI *xfi; { int err = 1; if (xfi) { if (xfi->pend) { xfi->pend = 0; WaitPort (&xfi->rp); GetMsg (&xfi->rp); } if (!xfi->ro && xfi->usbuf->idx) Write((long)xfi->fh >> 2, xfi->usbuf->buf, xfi->usbuf->idx); err = xfi->err; Close((long)xfi->fh >> 2); free(xfi->asbuf); free(xfi->usbuf); FreeSignal(xfi->rp.mp_SigBit); free(xfi); } return(err); } xfgets(xfi, buf, n) XFI *xfi; char *buf; { register XFBUF *usbuf = xfi->usbuf; register int i, idx; if (!xfi->ro) return(-1); --n; for (i = 0;;) { for (idx = usbuf->idx; idx < usbuf->max && i < n; ++idx, ++i) { if ((buf[i] = usbuf->buf[idx]) == '\n') { buf[i] = 0; usbuf->idx = idx+1; return(i); } } usbuf->idx = idx; buf[i] = 0; if (i == n) return(i); if (xfi->pend == 0) /* EOF */ return(-1); WaitPort (&xfi->rp); GetMsg (&xfi->rp); xfi->pend = 0; if (xfi->sp.sp_Pkt.dp_Res1 <= 0) { /* EOF */ if (i == 0) return(-1); return(i); } xfi->asbuf->max = xfi->sp.sp_Pkt.dp_Res1; xfi->asbuf->idx = 0; usbuf = xfi->asbuf; /* swap bufs*/ xfi->asbuf = xfi->usbuf; xfi->usbuf = usbuf; xfstartasync(xfi, ACTION_READ); /* new async*/ } } xfread(xfi, buf, n) XFI *xfi; char *buf; { register XFBUF *usbuf = xfi->usbuf; register int orig = n; register int diff; if (!xfi->ro) return(0); while ((diff = usbuf->max - usbuf->idx) < n) { movmem(usbuf->buf + usbuf->idx, buf, diff); /* copy entire buf */ buf += diff; n -= diff; if (xfi->pend == 0) { xfi->usbuf->idx = xfi->usbuf->max; return(orig - n); } WaitPort (&xfi->rp); GetMsg (&xfi->rp); xfi->pend = 0; if (xfi->sp.sp_Pkt.dp_Res1 <= 0) { /* EOF */ xfi->usbuf->idx = xfi->usbuf->max; return(orig - n); } xfi->asbuf->max = xfi->sp.sp_Pkt.dp_Res1; xfi->asbuf->idx = 0; usbuf = xfi->asbuf; /* swap bufs*/ xfi->asbuf = xfi->usbuf; xfi->usbuf = usbuf; xfstartasync(xfi, ACTION_READ); /* new async*/ } movmem(usbuf->buf + usbuf->idx, buf, n); usbuf->idx += n; return(orig); } xfwrite(xfi, buf, n) XFI *xfi; char *buf; { register XFBUF *usbuf = xfi->usbuf; register int diff; if (xfi->ro || xfi->err) return(1); while ((diff = usbuf->bufsize - usbuf->idx) < n) { movmem(buf, usbuf->buf + usbuf->idx, diff); /* copy buf */ buf += diff; n -= diff; if (xfi->pend) { WaitPort(&xfi->rp); GetMsg (&xfi->rp); xfi->pend = 0; if (xfi->sp.sp_Pkt.dp_Res1 != xfi->sp.sp_Pkt.dp_Arg3) { xfi->err = 1; return(1); } } usbuf = xfi->asbuf; xfi->asbuf = xfi->usbuf; xfi->usbuf = usbuf; usbuf->idx = 0; xfstartasync(xfi, ACTION_WRITE); } movmem(buf, usbuf->buf + usbuf->idx, n); usbuf->idx += n; return(xfi->err); } static xfstartasync(xfi, action) register XFI *xfi; { xfi->sp.sp_Msg.mn_Node.ln_Name = (char *)&(xfi->sp.sp_Pkt); xfi->sp.sp_Pkt.dp_Link = &(xfi->sp.sp_Msg); xfi->sp.sp_Pkt.dp_Port = &xfi->rp; xfi->sp.sp_Pkt.dp_Type = action; xfi->sp.sp_Pkt.dp_Arg1 = xfi->fh->fh_Arg1; xfi->sp.sp_Pkt.dp_Arg2 = (long)xfi->asbuf->buf; xfi->sp.sp_Pkt.dp_Arg3 = xfi->asbuf->bufsize; PutMsg (xfi->fh->fh_Type, &xfi->sp); xfi->pend = 1; }