#include #include #include #include #include #include #define D_S(type,name) char a_##name[ sizeof( type )+3]; type *name=(type *)((LONG)(a_##name+3)&~3); #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif static void copymem(UBYTE *s,UBYTE *d,ULONG len) { ULONG l=len&7; len-=l; while(l--) *(d++)=*(s++); while(len) { *(((double *)d)++)=*(((double *)s)++); len-=8; } } static VOID AS_SendPacket(struct AsyncFile *file,APTR arg2) { file->af_Packet.sp_Pkt.dp_Port=&file->af_PacketPort; file->af_Packet.sp_Pkt.dp_Arg2=(LONG)arg2; PutXMsgPPC(file->af_Handler,&file->af_Packet.sp_Msg); file->af_PacketPending=TRUE; } static LONG AS_WaitPacket(AsyncFile *file) { LONG bytes; if(file->af_PacketPending) { while(1) { file->af_PacketPort.mp_Flags=PA_SIGNAL; RemovePPC((struct Node *)WaitPort(&file->af_PacketPort)); /* This dummy call is absolutely necessary to avoid lock-up in some strange cases, e.g. accessing very long files !!, Dont remove it !! */ // SPrintF(0,0); file->af_PacketPort.mp_Flags=PA_IGNORE; file->af_PacketPending=FALSE; bytes=file->af_Packet.sp_Pkt.dp_Res1; if(bytes>=0) return bytes; if(ErrorReport(file->af_Packet.sp_Pkt.dp_Res2,REPORT_STREAM,file->af_File,NULL)) return -1; AS_SendPacket(file,file->af_Buffers[file->af_ReadMode?file->af_CurrentBuf:1-file->af_CurrentBuf]); } } SetIoErr(file->af_Packet.sp_Pkt.dp_Res2); return file->af_Packet.sp_Pkt.dp_Res1; } static VOID AS_RecordSyncFailure(struct AsyncFile *file) { file->af_LastRes1=file->af_Packet.sp_Pkt.dp_Res1; file->af_LastBytesLeft=file->af_BytesLeft; file->af_Packet.sp_Pkt.dp_Res1=-1; file->af_Packet.sp_Pkt.dp_Res2=IoErr(); file->af_BytesLeft=0; } static VOID AS_RequeuePacket(AsyncFile *file) { AddHeadPPC(&file->af_PacketPort.mp_MsgList,&file->af_Packet.sp_Msg.mn_Node); file->af_PacketPending=TRUE; } struct AsyncFile *AS_OpenAsyncFH(BPTR handle,LONG mode,LONG bufferSize,BOOL closeIt) { FileHandle *fh; AsyncFile *file=NULL; BPTR lock=NULL; LONG blockSize,blockSize2; D_S(struct InfoData,infoData); if(mode==MODE_READ) { if(handle) lock=DupLockFromFH(handle); } else { if(mode==MODE_APPEND) { if(handle) { if(Seek(handle,0,OFFSET_END)<0) { if(closeIt) Close(handle); handle=NULL; } } } if(handle) lock=ParentOfFH(handle); } if(handle) { blockSize=512; blockSize2=1024; if(lock) { if(Info(lock,infoData)) { blockSize=infoData->id_BytesPerBlock; blockSize2=blockSize*2; bufferSize=((bufferSize+blockSize2-1)/blockSize2)*blockSize2; } UnLock(lock); } for(;;) { if(file=AllocVecPPC(sizeof(AsyncFile)+bufferSize+15,MEMF_PUBLIC|MEMF_ANY,0)) break; else { if(bufferSize>blockSize2) bufferSize-=blockSize2; else break; } } if(file) { file->af_File=handle; file->af_ReadMode=(mode==MODE_READ); file->af_BlockSize=blockSize; file->af_CloseFH=closeIt; fh=(FileHandle *)BADDR(file->af_File); file->af_Handler=fh->fh_Type; file->af_BufferSize=(ULONG)bufferSize/2; file->af_Buffers[0]=(UBYTE *)(((ULONG)file+sizeof(AsyncFile)+15)&0xfffffff0); file->af_Buffers[1]=file->af_Buffers[0]+file->af_BufferSize; file->af_CurrentBuf=0; file->af_SeekOffset=0; file->af_PacketPending=FALSE; file->af_SeekPastEOF=FALSE; file->af_PacketPort.mp_MsgList.lh_Head=(struct Node *)&file->af_PacketPort.mp_MsgList.lh_Tail; file->af_PacketPort.mp_MsgList.lh_Tail=NULL; file->af_PacketPort.mp_MsgList.lh_TailPred=(struct Node *)&file->af_PacketPort.mp_MsgList.lh_Head; file->af_PacketPort.mp_Node.ln_Type=NT_MSGPORT; file->af_PacketPort.mp_Node.ln_Name=NULL; file->af_PacketPort.mp_Flags=PA_IGNORE; file->af_PacketPort.mp_SigBit=SIGB_SINGLE; file->af_PacketPort.mp_SigTask=FindTask(NULL); file->af_Packet.sp_Pkt.dp_Link=&file->af_Packet.sp_Msg; file->af_Packet.sp_Pkt.dp_Arg1=fh->fh_Arg1; file->af_Packet.sp_Pkt.dp_Arg3=file->af_BufferSize; file->af_Packet.sp_Pkt.dp_Res1=0; file->af_Packet.sp_Pkt.dp_Res2=0; file->af_Packet.sp_Msg.mn_Node.ln_Name=(STRPTR)&file->af_Packet.sp_Pkt; file->af_Packet.sp_Msg.mn_Node.ln_Type=NT_MESSAGE; file->af_Packet.sp_Msg.mn_Length=sizeof(struct StandardPacket); if(mode==MODE_READ) { file->af_Packet.sp_Pkt.dp_Type=ACTION_READ; file->af_BytesLeft=0; file->af_Offset=file->af_Buffers[1]; if(file->af_Handler) AS_SendPacket(file,file->af_Buffers[0]); } else { file->af_Packet.sp_Pkt.dp_Type=ACTION_WRITE; file->af_BytesLeft=file->af_BufferSize; file->af_Offset=file->af_Buffers[0]; } } else { if(closeIt) Close(handle); } } return file; } struct AsyncFile * __saveds OpenAsyncPPC(struct AsyncIOBase *base,STRPTR fileName,LONG mode,LONG bufferSize) { static const WORD PrivateOpenModes[]={MODE_OLDFILE,MODE_NEWFILE,MODE_READWRITE}; BPTR handle; AsyncFile *file=NULL; if(handle=Open(fileName,PrivateOpenModes[mode])) { if(!(file=AS_OpenAsyncFH(handle,mode,bufferSize,TRUE))) Close(handle); } return file; } struct AsyncFile * __saveds OpenAsyncFromFHPPC(struct AsyncIOBase *base,BPTR handle,LONG mode,LONG bufferSize) { return AS_OpenAsyncFH(handle,mode,bufferSize,FALSE); } LONG __saveds CloseAsyncPPC(struct AsyncIOBase *base,struct AsyncFile *file) { LONG result; if(file) { result=AS_WaitPacket(file); if(result>=0) { if(!file->af_ReadMode) { if(file->af_BufferSize>file->af_BytesLeft) { result=Write(file->af_File,file->af_Buffers[file->af_CurrentBuf],file->af_BufferSize-file->af_BytesLeft); } } } if(file->af_CloseFH) Close(file->af_File); FreeVecPPC(file); } else result=-1; return result; } LONG __saveds ReadAsyncPPC(struct AsyncIOBase *base,struct AsyncFile *file,APTR buffer,LONG numBytes) { LONG totalBytes=0; LONG bytesArrived; while(numBytes>file->af_BytesLeft) { copymem(file->af_Offset,buffer,file->af_BytesLeft); numBytes-=file->af_BytesLeft; buffer=(APTR)((ULONG)buffer+file->af_BytesLeft); totalBytes+=file->af_BytesLeft; file->af_BytesLeft=0; bytesArrived=AS_WaitPacket(file); if(bytesArrived<=0) { if(bytesArrived==0) return(totalBytes); return -1; } AS_SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]); if(file->af_SeekOffset>bytesArrived) file->af_SeekOffset=bytesArrived; file->af_Offset=file->af_Buffers[file->af_CurrentBuf]+file->af_SeekOffset; file->af_CurrentBuf=1-file->af_CurrentBuf; file->af_BytesLeft=bytesArrived-file->af_SeekOffset; file->af_SeekOffset=0; } copymem(file->af_Offset,buffer,numBytes); file->af_BytesLeft-=numBytes; file->af_Offset+=numBytes; return totalBytes+numBytes; } LONG __saveds PeekAsyncPPC(struct AsyncIOBase *base,struct AsyncFile *file,APTR buffer,LONG numBytes) { if(!file->af_BytesLeft) { LONG bytes; if((bytes=ReadAsyncPPC(base,file,&bytes,1))<=0) return bytes; --file->af_Offset; ++file->af_BytesLeft; } numBytes=MIN(numBytes,file->af_BytesLeft); copymem(file->af_Offset,buffer,numBytes); return numBytes; } LONG __saveds ReadCharAsyncPPC(struct AsyncIOBase *base,AsyncFile *file) { UBYTE ch; if(file->af_BytesLeft) { ch=*file->af_Offset; --file->af_BytesLeft; ++file->af_Offset; return ch; } if(ReadAsyncPPC(base,file,&ch,1)>0) return ch; return -1; } STRPTR __saveds FGetsLenAsyncPPC(struct AsyncIOBase *base,struct AsyncFile *file,STRPTR buf,LONG numBytes,LONG *len) { UBYTE *p; LONG length=0; p=(UBYTE *)buf; if(--numBytes<=0) return 0; while(TRUE) { UBYTE *ptr; LONG i,count; ptr=(UBYTE *)file->af_Offset; if(count=file->af_BytesLeft) { count=MIN(count,numBytes); for(i=0;(iaf_BytesLeft-=i; file->af_Offset+=i; if((i>=numBytes)||(*(p-1)=='\n')) break; numBytes-=i; } if(ReadAsyncPPC(base,file,p,1)<1) break; --numBytes; ++length; if(*p++=='\n') break; } *p='\0'; *len=length; if(p==(UBYTE *)buf) return 0; return buf; } STRPTR __saveds FGetsAsyncPPC(struct AsyncIOBase *base,struct AsyncFile *file,STRPTR buf,LONG numBytes) { LONG len; return FGetsLenAsyncPPC(base,file,buf,numBytes,&len); } LONG __saveds ReadLineAsyncPPC(struct AsyncIOBase *base,AsyncFile *file,APTR buffer,LONG bufSize) { LONG len; if(FGetsLenAsyncPPC(base,file,buffer,bufSize,&len)) { UBYTE *end; end=((UBYTE *)buffer)+len-1; if(*end!='\n') { UBYTE ch=0; while(TRUE) { UBYTE *ptr; LONG i,count; ptr=(UBYTE *)file->af_Offset; if(count=file->af_BytesLeft) { for(i=0;(iaf_BytesLeft-=i; file->af_Offset+=i; if(iaf_File,fib)) { AS_RecordSyncFailure(file); return FALSE; } *size=fib->fib_Size; return TRUE; } LONG __saveds SeekAsyncPPC(struct AsyncIOBase *base,struct AsyncFile *file,LONG position,LONG mode) { LONG current,target,roundTarget,filePos; LONG minBuf,maxBuf,bytesArrived,diff; LONG fileSize; bytesArrived=AS_WaitPacket(file); if(bytesArrived<0) { if(file->af_SeekPastEOF) { bytesArrived=file->af_LastRes1; file->af_BytesLeft=file->af_LastBytesLeft; } else return -1; } if(file->af_ReadMode) { filePos=Seek(file->af_File,0,OFFSET_CURRENT); if(filePos<0) { AS_RecordSyncFailure(file); return -1; } current=filePos-(file->af_BytesLeft+bytesArrived)+file->af_SeekOffset; if(mode==MODE_CURRENT) target=current+position; else if(mode==MODE_START) target=position; else { if(!GetFileSize(file,&fileSize)) return -1; target=fileSize+position; } minBuf=current-(LONG)(file->af_Offset-file->af_Buffers[1-file->af_CurrentBuf]); maxBuf=current+file->af_BytesLeft+bytesArrived; diff=target-current; if((target=maxBuf)) { if(target>=maxBuf) { if(!GetFileSize(file,&fileSize)) return -1; if(target>fileSize) { file->af_SeekPastEOF=TRUE; SetIoErr(ERROR_SEEK_ERROR); AS_RecordSyncFailure(file); return -1; } } roundTarget=(target/file->af_BlockSize)*file->af_BlockSize; if(Seek(file->af_File,roundTarget-filePos,OFFSET_CURRENT)<0) { AS_RecordSyncFailure(file); return -1; } AS_SendPacket(file,file->af_Buffers[0]); file->af_SeekOffset=target-roundTarget; file->af_BytesLeft=0; file->af_CurrentBuf=0; file->af_Offset=file->af_Buffers[1]; } else if((targetaf_BytesLeft)) { AS_RequeuePacket(file); file->af_BytesLeft-=diff; file->af_Offset+=diff; if(file->af_SeekPastEOF) file->af_Packet.sp_Pkt.dp_Res1=file->af_LastRes1; } else { AS_SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]); diff-=file->af_BytesLeft-file->af_SeekOffset; file->af_Offset=file->af_Buffers[file->af_CurrentBuf]+diff; file->af_BytesLeft=bytesArrived-diff; file->af_SeekOffset=0; file->af_CurrentBuf=1-file->af_CurrentBuf; } } else { if(file->af_BufferSize>file->af_BytesLeft) { if(Write(file->af_File,file->af_Buffers[file->af_CurrentBuf],file->af_BufferSize-file->af_BytesLeft)<0) { AS_RecordSyncFailure(file); return -1; } } current=Seek(file->af_File,position,mode); if(current<0) { AS_RecordSyncFailure(file); return -1; } file->af_BytesLeft=file->af_BufferSize; file->af_CurrentBuf=0; file->af_Offset=file->af_Buffers[0]; } if(file->af_SeekPastEOF) file->af_SeekPastEOF=FALSE; SetIoErr(0); return current; } LONG __saveds WriteAsyncPPC(struct AsyncIOBase *base,struct AsyncFile *file,APTR buffer,LONG numBytes) { LONG totalBytes=0; if(!file->af_Handler) { file->af_Offset=file->af_Buffers[0]; file->af_BytesLeft=file->af_BufferSize; return numBytes; } while(numBytes>file->af_BytesLeft) { if(file->af_BytesLeft) { copymem(buffer,file->af_Offset,file->af_BytesLeft); numBytes-=file->af_BytesLeft; buffer=(APTR)((ULONG)buffer+file->af_BytesLeft); totalBytes+=file->af_BytesLeft; } if(AS_WaitPacket(file)<0) return -1; AS_SendPacket(file,file->af_Buffers[file->af_CurrentBuf]); file->af_CurrentBuf=1-file->af_CurrentBuf; file->af_Offset=file->af_Buffers[file->af_CurrentBuf]; file->af_BytesLeft=file->af_BufferSize; } copymem(buffer,file->af_Offset,numBytes); file->af_BytesLeft-=numBytes; file->af_Offset+=numBytes; return totalBytes+numBytes; } LONG __saveds WriteCharAsyncPPC(struct AsyncIOBase *base,struct AsyncFile *file,ULONG ch) { UBYTE c; if(file->af_BytesLeft) { *file->af_Offset=ch; --file->af_BytesLeft; ++file->af_Offset; return 1; } c=ch; return WriteAsyncPPC(base,file,&c,1); } LONG __saveds WriteLineAsyncPPC(struct AsyncIOBase *base,struct AsyncFile *file,STRPTR line) { return WriteAsyncPPC(base,file,line,strlen(line)); }