home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / ftp.vapor.com / microdot-1 / md1_src_02.lzx / asyncio.c < prev    next >
C/C++ Source or Header  |  2014-05-19  |  26KB  |  863 lines

  1. /* (c)  Copyright 1993 Commodore-Amiga, Inc.   All rights reserved. */
  2. /* The information contained herein is subject to change without    */
  3. /* notice, and is provided "as is" without warranty of any kind,    */
  4. /* either expressed or implied.  The entire risk as to the use of   */
  5. /* this information is assumed by the user.                         */
  6.  
  7. /*#include <exec/types.h>
  8. #include <exec/memory.h>
  9. #include <dos/dos.h>
  10. #include <dos/dosextens.h>
  11.  
  12. #include <clib/exec_protos.h>
  13. #include <clib/dos_protos.h>
  14.  
  15. #include <pragmas/exec_pragmas.h>
  16. #include <pragmas/dos_pragmas.h>*/
  17.  
  18. #include "microdot.h"
  19. #include "asyncio.h"
  20.  
  21. /*****************************************************************************/
  22.  
  23.  
  24. /*extern struct Library *DOSBase;
  25. extern struct Library *SysBase;*/
  26.  
  27.  
  28. /*****************************************************************************/
  29.  
  30.  
  31. /* this macro lets us long-align structures on the stack */
  32. #define D_S(type,name) char a_##name[sizeof(type)+3]; \
  33.                        type *name = (type *)((LONG)(a_##name+3) & ~3);
  34.  
  35.  
  36. /*****************************************************************************/
  37.  
  38.  
  39. /* send out an async packet to the file system. */
  40. static VOID SendPacket(struct AsyncFile *file, APTR arg2)
  41. {
  42.     file->af_Packet.sp_Pkt.dp_Port = &file->af_PacketPort;
  43.     file->af_Packet.sp_Pkt.dp_Arg2 = (LONG)arg2;
  44.     PutMsg(file->af_Handler, &file->af_Packet.sp_Msg);
  45.     file->af_PacketPending = TRUE;
  46. }
  47.  
  48.  
  49. /*****************************************************************************/
  50.  
  51.  
  52. /* this function waits for a packet to come back from the file system. If no
  53.  * packet is pending, state from the previous packet is returned. This ensures
  54.  * that once an error occurs, it state is maintained for the rest of the life
  55.  * of the file handle.
  56.  *
  57.  * This function also deals with IO errors, bringing up the needed DOS
  58.  * requesters to let the user retry an operation or cancel it.
  59.  */
  60. static LONG WaitPacket(struct AsyncFile *file)
  61. {
  62. LONG bytes;
  63.  
  64.     if (file->af_PacketPending)
  65.     {
  66.         while (TRUE)
  67.         {
  68.             /* This enables signalling when a packet comes back to the port */
  69.             file->af_PacketPort.mp_Flags = PA_SIGNAL;
  70.  
  71.             /* Wait for the packet to come back, and remove it from the message
  72.              * list. Since we know no other packets can come in to the port, we can
  73.              * safely use Remove() instead of GetMsg(). If other packets could come in,
  74.              * we would have to use GetMsg(), which correctly arbitrates access in such
  75.              * a case
  76.              */
  77.             Remove((struct Node *)WaitPort(&file->af_PacketPort));
  78.  
  79.             /* set the port type back to PA_IGNORE so we won't be bothered with
  80.              * spurious signals
  81.              */
  82.             file->af_PacketPort.mp_Flags = PA_IGNORE;
  83.  
  84.             /* mark packet as no longer pending since we removed it */
  85.             file->af_PacketPending = FALSE;
  86.  
  87.             bytes = file->af_Packet.sp_Pkt.dp_Res1;
  88.             if (bytes >= 0)
  89.             {
  90.                 /* packet didn't report an error, so bye... */
  91.                 return(bytes);
  92.             }
  93.  
  94.             /* see if the user wants to try again... */
  95.             if (ErrorReport(file->af_Packet.sp_Pkt.dp_Res2,REPORT_STREAM,file->af_File,NULL))
  96.                 return(-1);
  97.  
  98.             /* user wants to try again, resend the packet */
  99.             if (file->af_ReadMode)
  100.                 SendPacket(file,file->af_Buffers[file->af_CurrentBuf]);
  101.             else
  102.                 SendPacket(file,file->af_Buffers[1 - file->af_CurrentBuf]);
  103.         }
  104.     }
  105.  
  106.     /* last packet's error code, or 0 if packet was never sent */
  107.     SetIoErr(file->af_Packet.sp_Pkt.dp_Res2);
  108.  
  109.     return(file->af_Packet.sp_Pkt.dp_Res1);
  110. }
  111.  
  112.  
  113. /*****************************************************************************/
  114.  
  115.  
  116. /* this function puts the packet back on the message list of our
  117.  * message port.
  118.  */
  119. static VOID RequeuePacket(struct AsyncFile *file)
  120. {
  121.     AddHead(&file->af_PacketPort.mp_MsgList,&file->af_Packet.sp_Msg.mn_Node);
  122.     file->af_PacketPending = TRUE;
  123. }
  124.  
  125.  
  126. /*****************************************************************************/
  127.  
  128.  
  129. /* this function records a failure from a synchronous DOS call into the
  130.  * packet so that it gets picked up by the other IO routines in this module
  131.  */
  132. static VOID RecordSyncFailure(struct AsyncFile *file)
  133. {
  134.     file->af_Packet.sp_Pkt.dp_Res1 = -1;
  135.     file->af_Packet.sp_Pkt.dp_Res2 = IoErr();
  136. }
  137.  
  138.  
  139. /*****************************************************************************/
  140.  
  141.  
  142. struct AsyncFile *OpenAsync(const STRPTR fileName, UBYTE accessMode, LONG bufferSize)
  143. {
  144. struct AsyncFile  *file;
  145. struct FileHandle *fh;
  146. BPTR               handle;
  147. BPTR               lock;
  148. LONG               blockSize;
  149. ULONG              startOffset = 0;
  150. D_S(struct InfoData,infoData);
  151.  
  152.     handle = NULL;
  153.     lock   = NULL;
  154.     file   = NULL;
  155.  
  156.     if( !isv37 )
  157.     {
  158.         FILE *f;
  159.         switch( accessMode )
  160.         {
  161.             case MODE_READ:
  162.                 f = fopen( fileName, "r" );
  163.                 if( f )
  164.                     fsetbuf( f, bufferSize );
  165.                 break;
  166.  
  167.             case MODE_WRITE:
  168.                 f = fopen( fileName, "w" );
  169.                 if( f )
  170.                     fsetbuf( f, bufferSize );
  171.                 break;
  172.  
  173.             case MODE_APPEND:
  174.                 f = fopen( fileName, "r+" );
  175.                 if( !f )
  176.                 {
  177.                     f = fopen( fileName, "w" );
  178.                     if( f )
  179.                         fsetbuf( f, bufferSize );
  180.                 }
  181.                 else
  182.                 {
  183.                     fsetbuf( f, bufferSize );
  184.                     fseek( f, 0, 2 );
  185.                 }
  186.                 break;
  187.         }
  188.         return( ( struct AsyncFile * ) f );
  189.     }
  190.  
  191.     if (accessMode == MODE_READ)
  192.     {
  193.         if (handle = Open(fileName,MODE_OLDFILE))
  194.             lock = Lock(fileName,ACCESS_READ);
  195.     }
  196.     else
  197.     {
  198.         if (accessMode == MODE_WRITE)
  199.         {
  200.             handle = Open(fileName,MODE_NEWFILE);
  201.         }
  202.         else if (accessMode == MODE_APPEND)
  203.         {
  204.             /* in append mode, we open for writing, and then seek to the
  205.              * end of the file. That way, the initial write will happen at
  206.              * the end of the file, thus extending it
  207.              */
  208.  
  209.             if (handle = Open(fileName,MODE_READWRITE))
  210.             {
  211.                 if (Seek(handle,0,OFFSET_END) < 0)
  212.                 {
  213.                     Close(handle);
  214.                     handle = NULL;
  215.                 }
  216.                 /* Obtain real offset */
  217.                 startOffset = Seek( handle, 0, OFFSET_CURRENT );
  218.             }
  219.         }
  220.  
  221.         /* we want a lock on the same device as where the file is. We can't
  222.          * use DupLockFromFH() for a write-mode file though. So we get sneaky
  223.          * and get a lock on the parent of the file
  224.          */
  225.         if (handle)
  226.             lock = ParentOfFH(handle);
  227.     }
  228.  
  229.     if (handle)
  230.     {
  231.         /* if it was possible to obtain a lock on the same device as the
  232.          * file we're working on, get the block size of that device and
  233.          * round up our buffer size to be a multiple of the block size.
  234.          * This maximizes DMA efficiency.
  235.          */
  236.  
  237.         blockSize = 512;
  238.         if (lock)
  239.         {
  240.             if (Info(lock,infoData))
  241.             {
  242.                 blockSize = infoData->id_BytesPerBlock;
  243.                 bufferSize = (((bufferSize + blockSize - 1) / blockSize) * blockSize) * 2;
  244.             }
  245.             UnLock(lock);
  246.         }
  247. reallocate:
  248.  
  249.         /* now allocate the ASyncFile structure, as well as the read buffers.
  250.          * Add 15 bytes to the total size in order to allow for later
  251.          * quad-longword alignement of the buffers
  252.          */
  253.  
  254.         if (file = AllocVec(sizeof(struct AsyncFile) + bufferSize + 15,MEMF_ANY))
  255.         {
  256.             file->af_File      = handle;
  257.             file->af_ReadMode  = (accessMode == MODE_READ);
  258.             file->af_BlockSize = blockSize;
  259.             file->af_CurrentFileOffset = startOffset;
  260.  
  261.             /* initialize the ASyncFile structure. We do as much as we can here,
  262.              * in order to avoid doing it in more critical sections
  263.              *
  264.              * Note how the two buffers used are quad-longword aligned. This
  265.              * helps performance on 68040 systems with copyback cache. Aligning
  266.              * the data avoids a nasty side-effect of the 040 caches on DMA.
  267.              * Not aligning the data causes the device driver to have to do
  268.              * some magic to avoid the cache problem. This magic will generally
  269.              * involve flushing the CPU caches. This is very costly on an 040.
  270.              * Aligning things avoids the need for magic, at the cost of at
  271.              * most 15 bytes of ram.
  272.              */
  273.  
  274.             fh                     = BADDR(file->af_File);
  275.             file->af_Handler       = fh->fh_Type;
  276.             file->af_BufferSize    = bufferSize / 2;
  277.             file->af_Buffers[0]    = (APTR)(((ULONG)file + sizeof(struct AsyncFile) + 15) & 0xfffffff0);
  278.             file->af_Buffers[1]    = (APTR)((ULONG)file->af_Buffers[0] + file->af_BufferSize);
  279.             file->af_Offset        = file->af_Buffers[0];
  280.             file->af_CurrentBuf    = 0;
  281.             file->af_SeekOffset    = 0;
  282.             file->af_PacketPending = FALSE;
  283.  
  284.             /* this is the port used to get the packets we send out back.
  285.              * It is initialized to PA_IGNORE, which means that no signal is
  286.              * generated when a message comes in to the port. The signal bit
  287.              * number is initialized to SIGB_SINGLE, which is the special bit
  288.              * that can be used for one-shot signalling. The signal will never
  289.              * be set, since the port is of type PA_IGNORE. We'll change the
  290.              * type of the port later on to PA_SIGNAL whenever we need to wait
  291.              * for a message to come in.
  292.              *
  293.              * The trick used here avoids the need to allocate an extra signal
  294.              * bit for the port. It is quite efficient.
  295.              */
  296.  
  297.             file->af_PacketPort.mp_MsgList.lh_Head     = (struct Node *)&file->af_PacketPort.mp_MsgList.lh_Tail;
  298.             file->af_PacketPort.mp_MsgList.lh_Tail     = NULL;
  299.             file->af_PacketPort.mp_MsgList.lh_TailPred = (struct Node *)&file->af_PacketPort.mp_MsgList.lh_Head;
  300.             file->af_PacketPort.mp_Node.ln_Type        = NT_MSGPORT;
  301.             file->af_PacketPort.mp_Flags               = PA_IGNORE;
  302.             file->af_PacketPort.mp_SigBit              = SIGB_SINGLE;
  303.             file->af_PacketPort.mp_SigTask             = FindTask(NULL);
  304.  
  305.             file->af_Packet.sp_Pkt.dp_Link          = &file->af_Packet.sp_Msg;
  306.             file->af_Packet.sp_Pkt.dp_Arg1          = fh->fh_Arg1;
  307.             file->af_Packet.sp_Pkt.dp_Arg3          = file->af_BufferSize;
  308.             file->af_Packet.sp_Pkt.dp_Res1          = 0;
  309.             file->af_Packet.sp_Pkt.dp_Res2          = 0;
  310.             file->af_Packet.sp_Msg.mn_Node.ln_Name  = (STRPTR)&file->af_Packet.sp_Pkt;
  311.             file->af_Packet.sp_Msg.mn_Node.ln_Type  = NT_MESSAGE;
  312.             file->af_Packet.sp_Msg.mn_Length        = sizeof(struct StandardPacket);
  313.  
  314.             if (accessMode == MODE_READ)
  315.             {
  316.                 /* if we are in read mode, send out the first read packet to
  317.                  * the file system. While the application is getting ready to
  318.                  * read data, the file system will happily fill in this buffer
  319.                  * with DMA transfers, so that by the time the application
  320.                  * needs the data, it will be in the buffer waiting
  321.                  */
  322.  
  323.                 file->af_Packet.sp_Pkt.dp_Type = ACTION_READ;
  324.                 file->af_BytesLeft             = 0;
  325.                 if (file->af_Handler)
  326.                     SendPacket(file,file->af_Buffers[0]);
  327.             }
  328.             else
  329.             {
  330.                 file->af_Packet.sp_Pkt.dp_Type = ACTION_WRITE;
  331.                 file->af_BytesLeft             = file->af_BufferSize;
  332.             }
  333.         }
  334.         else
  335.         {
  336.             if( bufferSize >= ( blockSize * 4 ) )
  337.             {
  338.                 bufferSize /= 2;
  339.                 goto reallocate;
  340.             }
  341.             Close(handle);
  342.         }
  343.     }
  344.  
  345.     return(file);
  346.  
  347. }
  348.  
  349.  
  350. /*****************************************************************************/
  351.  
  352.  
  353. LONG CloseAsync(struct AsyncFile *file)
  354. {
  355. LONG result;
  356.  
  357.     if( !isv37 )
  358.     {
  359.         if( file )
  360.             fclose( (FILE *) file );
  361.         return( 0 );
  362.     }
  363.  
  364.     if (file)
  365.     {
  366.         result = WaitPacket(file);
  367.         if (result >= 0)
  368.         {
  369.             if (!file->af_ReadMode)
  370.             {
  371.                 /* this will flush out any pending data in the write buffer */
  372.                 if (file->af_BufferSize > file->af_BytesLeft)
  373.                     result = Write(file->af_File,file->af_Buffers[file->af_CurrentBuf],file->af_BufferSize - file->af_BytesLeft);
  374.             }
  375.         }
  376.  
  377.         Close(file->af_File);
  378.         FreeVec(file);
  379.     }
  380.     else
  381.     {
  382.         SetIoErr(ERROR_INVALID_LOCK);
  383.         result = -1;
  384.     }
  385.  
  386.     return(result);
  387.  
  388. }
  389.  
  390.  
  391. /*****************************************************************************/
  392.  
  393.  
  394. LONG ReadAsync(struct AsyncFile *file, APTR buffer, LONG numBytes)
  395. {
  396. LONG totalBytes;
  397. LONG bytesArrived;
  398.  
  399.     if( !isv37 )
  400.     {
  401.         return( ( LONG ) fread( buffer, 1, numBytes, ( FILE * ) file ) );
  402.     }
  403.  
  404.     totalBytes = 0;
  405.  
  406.     /* if we need more bytes than there are in the current buffer, enter the
  407.      * read loop
  408.      */
  409.  
  410.     while (numBytes > file->af_BytesLeft)
  411.     {
  412.         /* drain buffer */
  413.         CopyMem(file->af_Offset,buffer,file->af_BytesLeft);
  414.  
  415.         numBytes           -= file->af_BytesLeft;
  416.         buffer              = (APTR)((ULONG)buffer + file->af_BytesLeft);
  417.         totalBytes         += file->af_BytesLeft;
  418.         file->af_BytesLeft  = 0;
  419.  
  420.         bytesArrived = WaitPacket(file);
  421.         if (bytesArrived <= 0)
  422.         {
  423.             if (bytesArrived == 0)
  424.             {
  425.                 file->af_CurrentFileOffset += totalBytes;
  426.                 return(totalBytes);
  427.             }
  428.  
  429.             return(-1);
  430.         }
  431.  
  432.         /* ask that the buffer be filled */
  433.         SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]);
  434.  
  435.         if (file->af_SeekOffset > bytesArrived)
  436.             file->af_SeekOffset = bytesArrived;
  437.  
  438.         file->af_Offset      = (APTR)((ULONG)file->af_Buffers[file->af_CurrentBuf] + file->af_SeekOffset);
  439.         file->af_CurrentBuf  = 1 - file->af_CurrentBuf;
  440.         file->af_BytesLeft   = bytesArrived - file->af_SeekOffset;
  441.         file->af_SeekOffset  = 0;
  442.     }
  443.  
  444.     CopyMem(file->af_Offset,buffer,numBytes);
  445.     file->af_BytesLeft -= numBytes;
  446.     file->af_Offset     = (APTR)((ULONG)file->af_Offset + numBytes);
  447.  
  448.     file->af_CurrentFileOffset += totalBytes + numBytes;
  449.     return (totalBytes + numBytes);
  450.  
  451. }
  452.  
  453.  
  454. /*****************************************************************************/
  455.  
  456.  
  457. LONG ReadCharAsync(struct AsyncFile *file)
  458. {
  459.     UBYTE ch;
  460.  
  461.     if( !isv37 )
  462.     {
  463.         return( fgetc( ( FILE * ) file ) );
  464.     }
  465.  
  466.     if (file->af_BytesLeft)
  467.     {
  468.         /* if there is at least a byte left in the current buffer, get it
  469.          * directly. Also update all counters
  470.          */
  471.  
  472.         ch = *(char *)file->af_Offset;
  473.         file->af_BytesLeft--;
  474.         file->af_Offset = (APTR)((ULONG)file->af_Offset + 1);
  475.         file->af_CurrentFileOffset++;
  476.  
  477.         return((LONG)ch);
  478.     }
  479.  
  480.     /* there were no characters in the current buffer, so call the main read
  481.      * routine. This has the effect of sending a request to the file system to
  482.      * have the current buffer refilled. After that request is done, the
  483.      * character is extracted for the alternate buffer, which at that point
  484.      * becomes the "current" buffer
  485.      */
  486.  
  487.     if (ReadAsync(file,&ch,1) > 0)
  488.         return((LONG)ch);
  489.  
  490.     /* We couldn't read above, so fail */
  491.  
  492.     return(-1);
  493.  
  494. }
  495.  
  496. UBYTE *FGetsAsync( struct AsyncFile *file, UBYTE *buffer, int maxlen )
  497. {
  498.     int ch;
  499.     int len = 0;
  500.  
  501.     while( --maxlen )
  502.     {
  503.         ch = ReadCharAsync( file );
  504.         if( ch < 0 )
  505.             break;
  506.         buffer[ len++ ] = ch;
  507.         if( ch == 10 )
  508.             break;
  509.     }
  510.  
  511.     if( !maxlen && ch != 10 )
  512.     {
  513.         for(;;)
  514.         {
  515.             ch = ReadCharAsync( file );
  516.             if( ch < 0 || ch == 10 )
  517.                 break;
  518.         }
  519.     }
  520.  
  521.     buffer[álen ] = 0;
  522.     return( len ? buffer : NULL );
  523. }
  524.  
  525. /*****************************************************************************/
  526.  
  527.  
  528. LONG WriteAsync(struct AsyncFile *file, APTR buffer, LONG numBytes)
  529. {
  530. LONG totalBytes;
  531.  
  532.     totalBytes = 0;
  533.  
  534.     if( !isv37 )
  535.     {
  536.         return( ( LONG ) fwrite( buffer, 1, numBytes, ( FILE * ) file ) );
  537.     }
  538.  
  539.     while (numBytes > file->af_BytesLeft)
  540.     {
  541.         /* this takes care of NIL: */
  542.         if (!file->af_Handler)
  543.         {
  544.             file->af_Offset    = file->af_Buffers[0];
  545.             file->af_BytesLeft = file->af_BufferSize;
  546.             return(numBytes);
  547.         }
  548.  
  549.         if (file->af_BytesLeft)
  550.         {
  551.             CopyMem(buffer,file->af_Offset,file->af_BytesLeft);
  552.  
  553.             numBytes   -= file->af_BytesLeft;
  554.             buffer      = (APTR)((ULONG)buffer + file->af_BytesLeft);
  555.             totalBytes += file->af_BytesLeft;
  556.         }
  557.  
  558.         if (WaitPacket(file) < 0)
  559.             return(-1);
  560.  
  561.         /* send the current buffer out to disk */
  562.         SendPacket(file,file->af_Buffers[file->af_CurrentBuf]);
  563.  
  564.         file->af_CurrentBuf = 1 - file->af_CurrentBuf;
  565.         file->af_Offset     = file->af_Buffers[file->af_CurrentBuf];
  566.         file->af_BytesLeft  = file->af_BufferSize;
  567.     }
  568.  
  569.     CopyMem(buffer,file->af_Offset,numBytes);
  570.     file->af_BytesLeft -= numBytes;
  571.     file->af_Offset     = (APTR)((ULONG)file->af_Offset + numBytes);
  572.  
  573.     file->af_CurrentFileOffset += totalBytes + numBytes;
  574.     return (totalBytes + numBytes);
  575.  
  576. }
  577.  
  578.  
  579. /*****************************************************************************/
  580.  
  581.  
  582. LONG WriteCharAsync(struct AsyncFile *file, UBYTE ch)
  583. {
  584.     if( !isv37 )
  585.     {
  586.         return( fputc( ch, ( FILE * ) file ) >= 0 ? 1 : -1 );
  587.     }
  588.  
  589.     if (file->af_BytesLeft)
  590.     {
  591.         /* if there's any room left in the current buffer, directly write
  592.          * the byte into it, updating counters and stuff.
  593.          */
  594.  
  595.         *( (UBYTE *)file->af_Offset ) = ch;
  596.         file->af_BytesLeft--;
  597.         file->af_Offset = (APTR)(((ULONG)file->af_Offset) + 1);
  598.  
  599.         /* one byte written */
  600.         file->af_CurrentFileOffset++;
  601.         return(1);
  602.     }
  603.  
  604.     /* there was no room in the current buffer, so call the main write
  605.      * routine. This will effectively send the current buffer out to disk,
  606.      * wait for the other buffer to come back, and then put the byte into
  607.      * it.
  608.      */
  609.  
  610.     return(WriteAsync(file,&ch,1));
  611.  
  612. }
  613.  
  614.  
  615. /*****************************************************************************/
  616.  
  617.  
  618. LONG SeekAsync(struct AsyncFile *file, LONG position, BYTE mode)
  619. {
  620. LONG  current, target;
  621. LONG  minBuf, maxBuf;
  622. LONG  bytesArrived;
  623. LONG  diff;
  624. LONG  filePos;
  625. LONG  roundTarget;
  626. D_S(struct FileInfoBlock,fib);
  627.  
  628.     if( !isv37 )
  629.     {
  630.         LONG v;
  631.  
  632.         v = ftell( ( FILE * ) file );
  633.         if( !fseek( ( FILE * ) file, position, ( (int) mode ) + 1 ) )
  634.             return( v );
  635.         else
  636.             return( -1 );
  637.     }
  638.  
  639.     bytesArrived = WaitPacket(file);
  640.  
  641.     if (bytesArrived < 0)
  642.         return(-1);
  643.  
  644. //    Printf( "SeekAsync: pos %ld, mode %ld\n", position, mode );
  645.  
  646.     if (file->af_ReadMode)
  647.     {
  648.         /* figure out what the actual file position is */
  649. //        Printf( "before seek, file %lx, file->af_file %lx\n",
  650. //            file, file->af_File );
  651.         filePos = Seek(file->af_File,OFFSET_CURRENT,0);
  652. //        Printf( "after seek, filepos %ld\n", filePos );
  653.         if (filePos < 0)
  654.         {
  655.             RecordSyncFailure(file);
  656.             return(-1);
  657.         }
  658.  
  659.         /* figure out what the caller's file position is */
  660.         current = filePos - (file->af_BytesLeft+bytesArrived) + file->af_SeekOffset;
  661.         file->af_SeekOffset = 0;
  662.  
  663.         /* figure out the absolute offset within the file where we must seek to */
  664.         if (mode == MODE_CURRENT)
  665.         {
  666.             target = current + position;
  667.         }
  668.         else if (mode == MODE_START)
  669.         {
  670.             target = position;
  671.         }
  672.         else /* if (mode == MODE_END) */
  673.         {
  674.             if (!ExamineFH(file->af_File,fib))
  675.             {
  676.                 RecordSyncFailure(file);
  677.                 return(-1);
  678.             }
  679.  
  680.             target = fib->fib_Size + position;
  681.         }
  682.  
  683. //        Printf( "SeekAsync: filepos %ld, current %ld, target %ld\n", filePos, current, target );
  684.  
  685.         file->af_CurrentFileOffset = target;
  686.  
  687.         /* figure out what range of the file is currently in our buffers */
  688.         minBuf = current - (LONG)((ULONG)file->af_Offset - (ULONG)file->af_Buffers[ 1 - file->af_CurrentBuf]);
  689.         maxBuf = current + file->af_BytesLeft + bytesArrived;  /* WARNING: this is one too big */
  690.  
  691.         diff = target - current;
  692.  
  693. //        Printf( "minBuf %ld, maxBuf %ld, diff %ld\n", minBuf, maxBuf, diff );
  694.  
  695.         if ((target < minBuf) || (target >= maxBuf))
  696.         {
  697. //            Printf( "AS: out of range\n" );
  698.             /* the target seek location isn't currently in our buffers, so
  699.              * move the actual file pointer to the desired location, and then
  700.              * restart the async read thing...
  701.              */
  702.  
  703.             /* this is to keep our file reading block-aligned on the device.
  704.              * block-aligned reads are generally quite a bit faster, so it is
  705.              * worth the trouble to keep things aligned
  706.              */
  707.             roundTarget = (target / file->af_BlockSize) * file->af_BlockSize;
  708.  
  709.             if (Seek(file->af_File,roundTarget-filePos,OFFSET_CURRENT) < 0)
  710.             {
  711.                 RecordSyncFailure(file);
  712.                 return(-1);
  713.             }
  714.  
  715.             SendPacket(file,file->af_Buffers[0]);
  716.  
  717.             file->af_SeekOffset = target-roundTarget;
  718.             file->af_BytesLeft  = 0;
  719.             file->af_CurrentBuf = 0;
  720.             file->af_Offset     = file->af_Buffers[0];
  721.         }
  722.         else if ((target < current) || (diff <= file->af_BytesLeft))
  723.         {
  724. //            Printf( "AS: within current\n" );
  725.             /* one of the two following things is true:
  726.              *
  727.              * 1. The target seek location is within the current read buffer,
  728.              * but before the current location within the buffer. Move back
  729.              * within the buffer and pretend we never got the pending packet,
  730.              * just to make life easier, and faster, in the read routine.
  731.              *
  732.              * 2. The target seek location is ahead within the current
  733.              * read buffer. Advance to that location. As above, pretend to
  734.              * have never received the pending packet.
  735.              */
  736.  
  737.             RequeuePacket(file);
  738.  
  739.             file->af_BytesLeft -= diff;
  740.             file->af_Offset     = (APTR)((ULONG)file->af_Offset + diff);
  741.         }
  742.         else
  743.         {
  744. //            Printf( "AS: inside just got\n" );
  745.             /* at this point, we know the target seek location is within
  746.              * the buffer filled in by the packet that we just received
  747.              * at the start of this function. Throw away all the bytes in the
  748.              * current buffer, send a packet out to get the async thing going
  749.              * again, readjust buffer pointers to the seek location, and return
  750.              * with a grin on your face... :-)
  751.              */
  752.  
  753.             diff -= file->af_BytesLeft;
  754.  
  755.             SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]);
  756.  
  757.             file->af_Offset    = (APTR)((ULONG)file->af_Buffers[file->af_CurrentBuf] + diff);
  758.             file->af_BytesLeft = bytesArrived - diff;
  759.  
  760.             file->af_CurrentBuf = 1 - file->af_CurrentBuf;
  761.         }
  762.     }
  763.     else
  764.     {
  765.         if (file->af_BufferSize > file->af_BytesLeft)
  766.         {
  767.             if (Write(file->af_File,file->af_Buffers[file->af_CurrentBuf],file->af_BufferSize - file->af_BytesLeft) < 0)
  768.             {
  769.                 RecordSyncFailure(file);
  770.                 return(-1);
  771.             }
  772.         }
  773.  
  774.         /* this will unfortunately generally result in non block-aligned file
  775.          * access. We could be sneaky and try to resync our file pos at a
  776.          * later time, but we won't bother. Seeking in write-only files is
  777.          * relatively rare (except when writing IFF files with unknown chunk
  778.          * sizes, where the chunk size has to be written after the chunk data)
  779.          */
  780.  
  781.         current = Seek(file->af_File,position,mode);
  782.  
  783.         if (current < 0)
  784.         {
  785.             RecordSyncFailure(file);
  786.             return(-1);
  787.         }
  788.  
  789.         switch( mode )
  790.         {
  791.             case MODE_START:
  792.                 file->af_CurrentFileOffset = position;
  793.                 break;
  794.  
  795.             case MODE_CURRENT:
  796.                 file->af_CurrentFileOffset = current + position;
  797.                 break;
  798.  
  799.             case MODE_END:
  800.                 file->af_CurrentFileOffset = Seek( file->af_File, 0, OFFSET_CURRENT ) + position;
  801.                 break;
  802.         }
  803.  
  804.         file->af_BytesLeft  = file->af_BufferSize;
  805.         file->af_CurrentBuf = 0;
  806.         file->af_Offset     = file->af_Buffers[0];
  807.     }
  808.  
  809.     return(current);
  810.  
  811. }
  812.  
  813. LONG FtellAsync( struct AsyncFile *file )
  814. {
  815.     if( !isv37 )
  816.     {
  817.         return( ftell( ( FILE * ) file ) );
  818.     }
  819.  
  820.     return( ( LONG ) file->af_CurrentFileOffset );
  821. }
  822.  
  823. struct fpi
  824. {
  825.     struct AsyncFile *to;
  826.     int error;
  827.     int count;
  828. };
  829. void __asm __saveds dofpi( register __d0 char ch, register __a3 struct fpi *fpi )
  830. {
  831.     if( !ch )
  832.         return;
  833.     if( fpi->error )
  834.         return;
  835.     fpi->count++;
  836.     if( WriteCharAsync( fpi->to, ch ) != 1 )
  837.         fpi->error = 1;
  838. }
  839.  
  840. int __stdargs FPrintfAsync( struct AsyncFile *file, char *string, ... )
  841. {
  842.     struct fpi fpi;
  843.  
  844.     fpi.error = fpi.count = 0;
  845.     fpi.to = file;
  846.  
  847.     RawDoFmt( string, &string + 1, dofpi, &fpi );
  848.  
  849.     return( fpi.error ? -1 : fpi.count );
  850. }
  851.  
  852. void UnGetCAsync( struct AsyncFile *file )
  853. {
  854.     if( file->af_Offset != file->af_Buffers[á1 - file->af_CurrentBuf ] )
  855.     {
  856.         file->af_BytesLeft++;
  857.         file->af_Offset = (APTR)((ULONG)file->af_Offset - 1);
  858.         file->af_CurrentFileOffset--;
  859.     }
  860.     else
  861.         SeekAsync( file, -1, OFFSET_CURRENT );
  862. }
  863.