home *** CD-ROM | disk | FTP | other *** search
/ Micro R&D 1 / MicroRD-CD-ROM-Vol1-1994.iso / os30 / gfx / animdemo.lha / asyncio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-22  |  22.2 KB  |  741 lines

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