#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 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; PutMsg(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(TRUE) { file->af_PacketPort.mp_Flags=PA_SIGNAL; Remove((struct Node *)WaitPort(&file->af_PacketPort)); 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) { AddHead(&file->af_PacketPort.mp_MsgList,&file->af_Packet.sp_Msg.mn_Node); file->af_PacketPending=TRUE; } 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=(AsyncFile *)AllocVec(sizeof(AsyncFile)+bufferSize+15,MEMF_PUBLIC|MEMF_ANY)) 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 *OpenAsync(register __a0 STRPTR fileName,register __d0 LONG mode,register __d1 LONG bufferSize,register __a6 struct AsyncIOBase *base) { 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 *OpenAsyncFromFH(register __a0 BPTR handle,register __d0 LONG mode,register __d1 LONG bufferSize,register __a6 struct AsyncIOBase *base) { return AS_OpenAsyncFH(handle,mode,bufferSize,FALSE); } LONG CloseAsync(register __a0 struct AsyncFile *file,register __a6 struct AsyncIOBase *base) { 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); FreeVec(file); } else result=-1; return result; } LONG ReadAsync(register __a0 struct AsyncFile *file,register __a1 APTR buffer,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base) { 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 PeekAsync(register __a0 struct AsyncFile *file,register __a1 APTR buffer,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base) { if(!file->af_BytesLeft) { LONG bytes; if((bytes=ReadAsync(file,&bytes,1,base))<=0) return bytes; --file->af_Offset; ++file->af_BytesLeft; } numBytes=MIN(numBytes,file->af_BytesLeft); CopyMem(file->af_Offset,buffer,numBytes); return numBytes; } LONG ReadCharAsync(register __a0 AsyncFile *file,register __a6 struct AsyncIOBase *base) { UBYTE ch; if(file->af_BytesLeft) { ch=*file->af_Offset; --file->af_BytesLeft; ++file->af_Offset; return ch; } if(ReadAsync(file,&ch,1,base)>0) return ch; return -1; } STRPTR FGetsLenAsync(register __a0 struct AsyncFile *file,register __a1 STRPTR buf,register __d0 LONG numBytes,register __a2 LONG *len,register __a6 struct AsyncIOBase *base) { 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(ReadAsync(file,p,1,base)<1) break; --numBytes; ++length; if(*p++=='\n') break; } *p='\0'; *len=length; if(p==(UBYTE *)buf) return 0; return buf; } STRPTR FGetsAsync(register __a0 struct AsyncFile *file,register __a1 STRPTR buf,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base) { LONG len; return FGetsLenAsync(file,buf,numBytes,&len,base); } LONG ReadLineAsync(register __a0 AsyncFile *file,register __a1 APTR buffer,register __d0 LONG bufSize,register __a6 struct AsyncIOBase *base) { LONG len; if(FGetsLenAsync(file,buffer,bufSize,&len,base)) { 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 SeekAsync(register __a0 struct AsyncFile *file,register __d0 LONG position,register __d1 LONG mode,register __a6 struct AsyncIOBase *base) { 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 WriteAsync(register __a0 struct AsyncFile *file,register __a1 APTR buffer,register __d0 LONG numBytes,register __a6 struct AsyncIOBase *base) { 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 WriteCharAsync(register __a0 struct AsyncFile *file,register __d0 ULONG ch,register __a6 struct AsyncIOBase *base) { UBYTE c; if(file->af_BytesLeft) { *file->af_Offset=ch; --file->af_BytesLeft; ++file->af_Offset; return 1; } c=ch; return WriteAsync(file,&c,1,base); } LONG WriteLineAsync(register __a0 struct AsyncFile *file,register __a1 STRPTR line,register __a6 struct AsyncIOBase *base) { return WriteAsync(file,line,strlen(line),base); }