home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 500-599 / ff589.lza / Term / TermSrc.lha / Buffer.c < prev    next >
C/C++ Source or Header  |  1991-12-01  |  17KB  |  790 lines

  1. /* $Revision Header * Header built automatically - do not edit! *************
  2.  *
  3.  *    (C) Copyright 1991 by Olaf 'Olsen' Barthel & MXM
  4.  *
  5.  *    Name .....: Buffer.c
  6.  *    Created ..: Tuesday 03-Sep-91 17:44
  7.  *    Revision .: 3
  8.  *
  9.  *    Date            Author          Comment
  10.  *    =========       ========        ====================
  11.  *    23-Oct-91    Olsen        Closing files twice fixed.
  12.  *    19-Sep-91    Olsen        Nasty bugs fixed.
  13.  *    03-Sep-91    Olsen        Created this file!
  14.  *
  15.  * $Revision Header ********************************************************/
  16.  
  17. #include "termGlobal.h"
  18.  
  19.     /* Size of a file buffer. */
  20.  
  21. #define BUFFER_SIZE    32768
  22.  
  23.     /* The two message signals. */
  24.  
  25. #define    BUFFER_COMMAND    SIGBREAKF_CTRL_E
  26. #define BUFFER_SYNC    SIGBREAKF_CTRL_F
  27.  
  28.     /* Argument types. */
  29.  
  30. enum    {    ARG_NAME,ARG_MODE };
  31. enum    {    ARG_OFFSET,ARG_ORIGIN };
  32.  
  33.     /* Seek offsets. */
  34.  
  35. enum    {    SEEK_SET,SEEK_CURR,SEEK_END };
  36.  
  37.     /* Command codes. */
  38.  
  39. enum    {    BUF_CLOSE,BUF_SEEK,BUF_FILL,BUF_FLUSH };
  40.  
  41.     /* FileBufferServer():
  42.      *
  43.      *    Background process to handle the buffering
  44.      *    of a filehandle, automatically gets invoked
  45.      *    when a file is opened.
  46.      */
  47.  
  48. STATIC VOID __saveds
  49. FileBufferServer()
  50. {
  51.     struct MsgPort    *Port;
  52.     struct Buffer    *Buffer;
  53.     BYTE         Terminated = FALSE,Done,WasFull;
  54.     UBYTE        *String;
  55.     APTR         Data;
  56.     LONG         Length;
  57.     BPTR         SomeLock;
  58.  
  59.         /* Wait for startup message (-> Buffer). */
  60.  
  61.     Port = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
  62.  
  63.     WaitPort(Port);
  64.  
  65.     Buffer = (struct Buffer *)GetMsg(Port);
  66.  
  67.         /* Open the file and obtain a filehandle. */
  68.  
  69.     String = (UBYTE *)Buffer -> ActionData[ARG_MODE];
  70.  
  71.     Buffer -> WriteAccess = TRUE;
  72.  
  73.         /* Put the message into the list. */
  74.  
  75.     ObtainSemaphore(&DoubleBufferSemaphore);
  76.  
  77.     AddTail(&DoubleBufferList,(struct Node *)Buffer);
  78.  
  79.     ReleaseSemaphore(&DoubleBufferSemaphore);
  80.  
  81.         /* Check for the open type. */
  82.  
  83.     switch(String[0])
  84.     {
  85.         case 'r':    if(String[1] == '+')
  86.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  87.                 else
  88.                 {
  89.                     Buffer -> WriteAccess = FALSE;
  90.  
  91.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_OLDFILE);
  92.                 }
  93.  
  94.                 break;
  95.  
  96.         case 'w':    if(String[1] == '+')
  97.                 {
  98.                     if(SomeLock = Lock((UBYTE *)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  99.                     {
  100.                         UnLock(SomeLock);
  101.  
  102.                         DeleteFile((UBYTE *)Buffer -> ActionData[ARG_NAME]);
  103.                     }
  104.  
  105.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  106.                 }
  107.                 else
  108.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  109.  
  110.                 break;
  111.  
  112.         case 'a':    if(SomeLock = Lock((UBYTE *)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  113.                 {
  114.                     UnLock(SomeLock);
  115.  
  116.                     if(Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_READWRITE))
  117.                     {
  118.                         if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  119.                         {
  120.                             Close(Buffer -> FileHandle);
  121.  
  122.                             Buffer -> FileHandle = NULL;
  123.                         }
  124.                     }
  125.                 }
  126.                 else
  127.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  128.  
  129.                 break;
  130.  
  131.         default:    break;
  132.     }
  133.  
  134.         /* Clear signal bit. */
  135.  
  136.     SetSignal(0,BUFFER_COMMAND);
  137.  
  138.         /* Did the file open? */
  139.  
  140.     if(Buffer -> FileHandle)
  141.     {
  142.         Buffer -> Data        = Buffer -> DataBuffer[0];
  143.         Buffer -> DataCount    = 1;
  144.         Buffer -> Fresh        = TRUE;
  145.  
  146.             /* If not in write mode fill the buffers. */
  147.  
  148.         if(!Buffer -> WriteAccess)
  149.         {
  150.                 /* Fill the first one synchronously. */
  151.  
  152.             Buffer -> ReadBufFull    = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  153.             Buffer -> Read        = TRUE;
  154.             Buffer -> RealPosition    = Buffer -> ReadBufFull;
  155.  
  156.                 /* Restart caller. */
  157.  
  158.             Signal(Buffer -> Caller,BUFFER_SYNC);
  159.  
  160.                 /* Fill the second buffe asynchronously. */
  161.  
  162.             Buffer -> DataLength[1]    = Buffer -> Cached = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  163.             Buffer -> RealPosition += Buffer -> Cached;
  164.         }
  165.         else
  166.             Signal(Buffer -> Caller,BUFFER_SYNC);
  167.     }
  168.     else
  169.         Terminated = TRUE;
  170.  
  171.         /* Go into loop waiting for commands. */
  172.  
  173.     while(!Terminated)
  174.     {
  175.         Wait(BUFFER_COMMAND);
  176.  
  177.         Done = FALSE;
  178.  
  179.         Buffer -> Result = 0;
  180.  
  181.             /* Take care of each action. */
  182.  
  183.         switch(Buffer -> Action)
  184.         {
  185.                 /* Close the file, flush any dirty
  186.                  * buffers and exit.
  187.                  */
  188.  
  189.             case BUF_CLOSE:    if(Buffer -> BufPosition && Buffer -> Written)
  190.                         Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition);
  191.  
  192.                     Close(Buffer -> FileHandle);
  193.  
  194.                     Terminated = TRUE;
  195.  
  196.                     break;
  197.  
  198.                 /* Seek to a specific file position. */
  199.  
  200.             case BUF_SEEK:    Buffer -> Result = 0;
  201.  
  202.                         /* Do nothing if buffer is still
  203.                          * untouched and we are required
  204.                          * to seek back to the beginning
  205.                          * of the file.
  206.                          */
  207.  
  208.                     if(Buffer -> Fresh && !Buffer -> ActionData[ARG_OFFSET] && Buffer -> ActionData[ARG_ORIGIN] == SEEK_SET)
  209.                     {
  210.                         Signal(Buffer -> Caller,BUFFER_SYNC);
  211.  
  212.                         Done = TRUE;
  213.                     }
  214.                     else
  215.                     {
  216.                         Buffer -> WriteBufFull    = Buffer -> BufLength;
  217.                         Buffer -> Read        = FALSE;
  218.  
  219.                         if(Buffer -> BufPosition && Buffer -> Written)
  220.                         {
  221.                             if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  222.                                 Buffer -> Result = -1;
  223.                         }
  224.  
  225.                         if(!Buffer -> Result)
  226.                         {
  227.                             Buffer -> Result = Buffer -> RealPosition - (Buffer -> ReadBufFull + Buffer -> Cached);
  228.  
  229.                             switch(Buffer -> ActionData[ARG_ORIGIN])
  230.                             {
  231.                                 case SEEK_SET:    if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_BEGINNING) != -1)
  232.                                             Buffer -> RealPosition = Buffer -> ActionData[ARG_OFFSET];
  233.                                         else
  234.                                             Buffer -> Result = -1;
  235.  
  236.                                         break;
  237.  
  238.                                 case SEEK_CURR:    if(!Buffer -> WriteAccess && Buffer -> ActionData[ARG_OFFSET] >= 0 && Buffer -> ReadBufFull - Buffer -> ActionData[ARG_OFFSET] >= 0)
  239.                                         {
  240.                                             Buffer -> ReadBufFull    -= Buffer -> ActionData[ARG_OFFSET];
  241.                                             Buffer -> Data        += Buffer -> ActionData[ARG_OFFSET];
  242.  
  243.                                             Signal(Buffer -> Caller,BUFFER_SYNC);
  244.  
  245.                                             Done = TRUE;
  246.  
  247.                                             break;
  248.                                         }
  249.  
  250.                                         if(Seek(Buffer -> FileHandle,-(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET],OFFSET_CURRENT) != -1)
  251.                                             Buffer -> RealPosition += -(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET];
  252.                                         else
  253.                                             Buffer -> Result = -1;
  254.  
  255.                                         break;
  256.  
  257.                                 case SEEK_END:    if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_END) != -1)
  258.                                             Buffer -> RealPosition = Seek(Buffer -> FileHandle,0,OFFSET_CURRENT);
  259.                                         else
  260.                                             Buffer -> Result = -1;
  261.  
  262.                                         break;
  263.  
  264.                                 default:    Buffer -> Result = -1;
  265.                             }
  266.  
  267.                             Buffer -> ReadBufFull = 0;
  268.  
  269.                             if(Buffer -> Result != -1)
  270.                             {
  271.                                 Buffer -> Data        = Buffer -> DataBuffer[0];
  272.                                 Buffer -> DataCount    = 1;
  273.  
  274.                                 if(!Buffer -> WriteAccess)
  275.                                 {
  276.                                     Buffer -> ReadBufFull     = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  277.                                     Buffer -> WriteBufFull     = 0;
  278.                                     Buffer -> Read         = TRUE;
  279.                                     Buffer -> RealPosition    += Buffer -> ReadBufFull;
  280.  
  281.                                     if(Buffer -> ReadBufFull)
  282.                                     {
  283.                                         Buffer -> Cached = Buffer -> DataLength[1] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  284.  
  285.                                         Buffer -> RealPosition += Buffer -> Cached;
  286.                                     }
  287.                                 }
  288.                             }
  289.                             else
  290.                                 Buffer -> LastActionFailed = TRUE;
  291.                         }
  292.                         else
  293.                             Buffer -> ReadBufFull = 0;
  294.  
  295.                         Buffer -> BufPosition    = 0;
  296.                         Buffer -> Written    = FALSE;
  297.                     }
  298.  
  299.                     break;
  300.  
  301.                 /* Fill the buffer with fresh data. */
  302.  
  303.             case BUF_FILL:    Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  304.                     Buffer -> ReadBufFull    = Buffer -> DataLength[Buffer -> DataCount];
  305.                     Buffer -> WriteBufFull    = 0;
  306.                     Buffer -> BufPosition    = 0;
  307.                     Buffer -> Read        = TRUE;
  308.                     Buffer -> Written    = FALSE;
  309.                     Buffer -> Fresh        = FALSE;
  310.  
  311.                     if(Buffer -> ReadBufFull)
  312.                         WasFull = TRUE;
  313.                     else
  314.                         WasFull = FALSE;
  315.  
  316.                         /* The buffer contents have been
  317.                          * swapped, now wake the caller
  318.                          * up and fill the next buffer
  319.                          * asynchronously.
  320.                          */
  321.  
  322.                     Signal(Buffer -> Caller,BUFFER_SYNC);
  323.  
  324.                     Done = TRUE;
  325.  
  326.                     if(WasFull)
  327.                     {
  328.                         Buffer -> DataCount = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  329.  
  330.                         Buffer -> Cached = Buffer -> DataLength[Buffer -> DataCount] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[Buffer -> DataCount],Buffer -> BufLength);
  331.  
  332.                         Buffer -> RealPosition += Buffer -> Cached;
  333.  
  334.                         if(!Buffer -> DataLength[Buffer -> DataCount])
  335.                         {
  336.                             if(IoErr())
  337.                                 Buffer -> LastActionFailed = TRUE;
  338.                         }
  339.                     }
  340.  
  341.                     break;
  342.  
  343.                 /* Flush the contents of the buffer to disk. */
  344.  
  345.             case BUF_FLUSH:    if(Buffer -> BufPosition && Buffer -> Written)
  346.                     {
  347.                         Data            = Buffer -> Data;
  348.                         Length            = Buffer -> BufPosition;
  349.  
  350.                         Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  351.                         Buffer -> DataCount    = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  352.  
  353.                         Buffer -> ReadBufFull    = 0;
  354.                         Buffer -> WriteBufFull    = Buffer -> BufLength;
  355.                         Buffer -> BufPosition    = 0;
  356.                         Buffer -> Read        = FALSE;
  357.                         Buffer -> Written    = FALSE;
  358.  
  359.                         Signal(Buffer -> Caller,BUFFER_SYNC);
  360.  
  361.                         Done = TRUE;
  362.  
  363.                         if(Write(Buffer -> FileHandle,Data,Length) != Length)
  364.                             Buffer -> LastActionFailed = TRUE;
  365.                         else
  366.                             Buffer -> RealPosition += Length;
  367.                     }
  368.                     else
  369.                     {
  370.                         Buffer -> ReadBufFull    = 0;
  371.                         Buffer -> WriteBufFull    = Buffer -> BufLength;
  372.                         Buffer -> BufPosition    = 0;
  373.                         Buffer -> Read        = FALSE;
  374.                         Buffer -> Written    = FALSE;
  375.                     }
  376.  
  377.                     Buffer -> Fresh = FALSE;
  378.  
  379.                     break;
  380.         }
  381.  
  382.             /* Ring back if necessary. */
  383.  
  384.         if(!Done && !Terminated)
  385.             Signal(Buffer -> Caller,BUFFER_SYNC);
  386.     }
  387.  
  388.         /* Remove the message from the list. */
  389.  
  390.     ObtainSemaphore(&DoubleBufferSemaphore);
  391.  
  392.     Remove((struct Node *)Buffer);
  393.  
  394.     ReleaseSemaphore(&DoubleBufferSemaphore);
  395.  
  396.         /* Lock & quit. */
  397.  
  398.     Forbid();
  399.  
  400.     Signal(Buffer -> Caller,BUFFER_SYNC);
  401. }
  402.  
  403.     /* BufferFill(struct Buffer *Buffer):
  404.      *
  405.      *    Fills a given buffer with fresh data.
  406.      */
  407.  
  408. STATIC BYTE __regargs
  409. BufferFill(struct Buffer *Buffer)
  410. {
  411.     if(Buffer -> LastActionFailed)
  412.         return(FALSE);
  413.     else
  414.     {
  415.         if(!Buffer -> ReadBufFull)
  416.         {
  417.             Buffer -> Action = BUF_FILL;
  418.  
  419.             Signal(Buffer -> Child,BUFFER_COMMAND);
  420.  
  421.             Wait(BUFFER_SYNC);
  422.         }
  423.  
  424.         return(TRUE);
  425.     }
  426. }
  427.  
  428.     /* BufferFlush(struct Buffer *Buffer):
  429.      *
  430.      *    Flush the contents of a given buffer to disk.
  431.      */
  432.  
  433. STATIC BYTE __regargs
  434. BufferFlush(struct Buffer *Buffer)
  435. {
  436.     if(Buffer -> LastActionFailed)
  437.         return(FALSE);
  438.     else
  439.     {
  440.         if(Buffer -> BufPosition && Buffer -> Written)
  441.         {
  442.             Buffer -> Action = BUF_FLUSH;
  443.  
  444.             Signal(Buffer -> Child,BUFFER_COMMAND);
  445.  
  446.             Wait(BUFFER_SYNC);
  447.         }
  448.  
  449.         return(TRUE);
  450.     }
  451. }
  452.  
  453.     /* IsValidBuffer(struct Buffer *Buffer):
  454.      *
  455.      *    Scans the double buffered file list for
  456.      *    a valid entry.
  457.      */
  458.  
  459. STATIC BYTE __regargs
  460. IsValidBuffer(struct Buffer *Buffer)
  461. {
  462.     BYTE         GotIt = FALSE;
  463.     struct Node    *Node;
  464.  
  465.     ObtainSemaphore(&DoubleBufferSemaphore);
  466.  
  467.     Node = DoubleBufferList . lh_Head;
  468.  
  469.     while(Node -> ln_Succ)
  470.     {
  471.         if(Buffer == (struct Buffer *)Node)
  472.         {
  473.             GotIt = TRUE;
  474.  
  475.             break;
  476.         }
  477.  
  478.         Node = Node -> ln_Succ;
  479.     }
  480.  
  481.     ReleaseSemaphore(&DoubleBufferSemaphore);
  482.  
  483.     return(GotIt);
  484. }
  485.  
  486.     /* BPrintf():
  487.      *
  488.      *    Prints text into a buffered file.
  489.      */
  490.  
  491. LONG __stdargs
  492. BPrintf(struct Buffer *Buffer,UBYTE *Format,...)
  493. {
  494.     UBYTE    String[256];
  495.     va_list    VarArgs;
  496.  
  497.     va_start(VarArgs,Format);
  498.     VSPrintf(String,Format,VarArgs);
  499.     va_end(VarArgs);
  500.  
  501.     return(BufferWrite(Buffer,String,strlen(String)));
  502. }
  503.  
  504.     /* BufferClose(struct Buffer *Buffer):
  505.      *
  506.      *    Close a buffered filehandle.
  507.      */
  508.  
  509. BYTE __regargs
  510. BufferClose(struct Buffer *Buffer)
  511. {
  512.     if(IsValidBuffer(Buffer))
  513.     {
  514.         BYTE Success;
  515.  
  516.         Buffer -> Action = BUF_CLOSE;
  517.  
  518.         Signal(Buffer -> Child,BUFFER_COMMAND);
  519.  
  520.         Wait(BUFFER_SYNC);
  521.  
  522.         Success = Buffer -> Result;
  523.  
  524.         FreeVec(Buffer);
  525.  
  526.         return(Success);
  527.     }
  528.     else
  529.         return(FALSE);
  530. }
  531.  
  532.     /* BufferOpen(UBYTE *Name,UBYTE *AccessMode):
  533.      *
  534.      *    Open a file for buffered I/O.
  535.      */
  536.  
  537. struct Buffer * __regargs
  538. BufferOpen(UBYTE *Name,UBYTE *AccessMode)
  539. {
  540.     struct Buffer *Buffer;
  541.  
  542.         /* Allocate the buffer data. */
  543.  
  544.     if(Buffer = (struct Buffer *)AllocVec(sizeof(struct Buffer) + BUFFER_SIZE * BUFFER_NUMBER,MEMF_PUBLIC|MEMF_CLEAR))
  545.     {
  546.         struct Process    *Process;
  547.         WORD         i;
  548.  
  549.             /* Set up the first buffer. */
  550.  
  551.         Buffer -> DataBuffer[0] = (UBYTE *)(Buffer + 1);
  552.  
  553.             /* Set up the individual buffers. */
  554.  
  555.         for(i = 1 ; i < BUFFER_NUMBER ; i++)
  556.             Buffer -> DataBuffer[i] = &Buffer -> DataBuffer[i - 1][BUFFER_SIZE];
  557.  
  558.         Buffer -> BufLength    = BUFFER_SIZE;
  559.         Buffer -> WriteBufFull    = Buffer -> BufLength;
  560.  
  561.             /* Create the asynchronous file server. */
  562.  
  563.         if(!(Process = CreateNewProcTags(
  564.             NP_Entry,    FileBufferServer,
  565.             NP_Name,    "term File Server",
  566.             NP_Priority,    0,
  567.             NP_StackSize,    8192,
  568.             NP_WindowPtr,    -1,
  569.         TAG_DONE)))
  570.         {
  571.             FreeVec(Buffer);
  572.  
  573.             return(NULL);
  574.         }
  575.  
  576.             /* Set up the message header. */
  577.  
  578.         Buffer -> Message . mn_Length    = sizeof(struct Buffer);
  579.  
  580.         Buffer -> ActionData[ARG_NAME]    = (LONG)Name;
  581.         Buffer -> ActionData[ARG_MODE]    = (LONG)AccessMode;
  582.  
  583.         Buffer -> Child            = Process;
  584.         Buffer -> Caller        = (struct Process *)SysBase -> ThisTask;
  585.  
  586.             /* Send it to the waiting server process. */
  587.  
  588.         PutMsg(&Process -> pr_MsgPort,&Buffer -> Message);
  589.  
  590.             /* Wait for ringback. */
  591.  
  592.         Wait(BUFFER_SYNC);
  593.  
  594.             /* Do we have a valid filehandle? */
  595.  
  596.         if(!Buffer -> FileHandle)
  597.         {
  598.             FreeVec(Buffer);
  599.  
  600.             return(NULL);
  601.         }
  602.         else
  603.             return(Buffer);
  604.     }
  605.  
  606.     return(NULL);
  607. }
  608.  
  609.     /* BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin):
  610.      *
  611.      *    Move the read/write pointer to a specific position
  612.      *    in a file (not really buffered).
  613.      */
  614.  
  615. BYTE __regargs
  616. BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin)
  617. {
  618.     Buffer -> Action            = BUF_SEEK;
  619.     Buffer -> ActionData[ARG_OFFSET]    = Offset;
  620.     Buffer -> ActionData[ARG_ORIGIN]    = Origin;
  621.  
  622.     Signal(Buffer -> Child,BUFFER_COMMAND);
  623.  
  624.     Wait(BUFFER_SYNC);
  625.  
  626.     if(Buffer -> Result == -1)
  627.         return(FALSE);
  628.     else
  629.         return(TRUE);
  630. }
  631.  
  632.     /* BufferRead():
  633.      *
  634.      *    Read data from a file (buffered).
  635.      */
  636.  
  637. LONG __regargs
  638. BufferRead(struct Buffer *Buffer,UBYTE *Destination,LONG Size)
  639. {
  640.     LONG     BytesRead = 0,ToCopy,BufPosition,ReadBufFull;
  641.     UBYTE    *Data;
  642.  
  643.         /* If there is still data to be written in
  644.          * the buffer, write it.
  645.          */
  646.  
  647.     if(Buffer -> Written)
  648.     {
  649.         if(!BufferFlush(Buffer))
  650.             return(0);
  651.     }
  652.  
  653.         /* Set up for read access. */
  654.  
  655.     BufPosition    = Buffer -> BufPosition;
  656.     ReadBufFull    = Buffer -> ReadBufFull;
  657.     Data        = &Buffer -> Data[BufPosition];
  658.  
  659.         /* Continue until all data has been processed. */
  660.  
  661.     while(Size)
  662.     {
  663.             /* Determine number of bytes to transfer. */
  664.  
  665.         if(ToCopy = (Size > ReadBufFull) ? ReadBufFull : Size)
  666.         {
  667.             memcpy(Destination,Data,ToCopy);
  668.  
  669.             Size        -= ToCopy;
  670.             BufPosition    += ToCopy;
  671.             ReadBufFull    -= ToCopy;
  672.             Destination    += ToCopy;
  673.             Data        += ToCopy;
  674.             BytesRead    += ToCopy;
  675.         }
  676.         else
  677.         {
  678.                 /* Refill buffer with data. */
  679.  
  680.             Buffer -> BufPosition    = BufPosition;
  681.             Buffer -> ReadBufFull    = ReadBufFull;
  682.  
  683.             if(!BufferFill(Buffer))
  684.                 return(BytesRead);
  685.  
  686.             if(!Buffer -> ReadBufFull)
  687.             {
  688.                 Buffer -> BufPosition = BufPosition;
  689.  
  690.                 return(BytesRead);
  691.             }
  692.  
  693.                 /* Pick up new data. */
  694.  
  695.             BufPosition        = Buffer -> BufPosition;
  696.             ReadBufFull        = Buffer -> ReadBufFull;
  697.             Data            = Buffer -> Data;
  698.         }
  699.     }
  700.  
  701.         /* Install new data. */
  702.  
  703.     Buffer -> BufPosition    = BufPosition;
  704.     Buffer -> ReadBufFull    = ReadBufFull;
  705.  
  706.     return(BytesRead);
  707. }
  708.  
  709.     /* BufferWrite():
  710.      *
  711.      *    Write data to a file (buffered).
  712.      */
  713.  
  714. LONG __regargs
  715. BufferWrite(struct Buffer *Buffer,UBYTE *Source,LONG Size)
  716. {
  717.     LONG     BytesWritten = 0,ToCopy,BufPosition,WriteBufFull;
  718.     UBYTE    *Data;
  719.  
  720.         /* If there is still read data in the buffer,
  721.          * reset the control information.
  722.          */
  723.  
  724.     if(Buffer -> Read)
  725.     {
  726.         Buffer -> WriteBufFull    = Buffer -> BufLength;
  727.         Buffer -> BufPosition    = 0;
  728.         Buffer -> Read        = FALSE;
  729.     }
  730.  
  731.         /* Set up for write access. */
  732.  
  733.     Buffer -> Written = TRUE;
  734.  
  735.     BufPosition    = Buffer -> BufPosition;
  736.     WriteBufFull    = Buffer -> WriteBufFull;
  737.     Data        = &Buffer -> Data[BufPosition];
  738.  
  739.         /* Continue until all data has been processed. */
  740.  
  741.     while(Size)
  742.     {
  743.             /* Determine number of bytes to transfer. */
  744.  
  745.         if(ToCopy = (Size > WriteBufFull ? WriteBufFull : Size))
  746.         {
  747.             memcpy(Data,Source,ToCopy);
  748.  
  749.             Size        -= ToCopy;
  750.             BufPosition    += ToCopy;
  751.             WriteBufFull    -= ToCopy;
  752.             Source        += ToCopy;
  753.             Data        += ToCopy;
  754.             BytesWritten    += ToCopy;
  755.         }
  756.         else
  757.         {
  758.                 /* Flush the contents of the
  759.                  * write buffer.
  760.                  */
  761.  
  762.             Buffer -> BufPosition    = BufPosition;
  763.             Buffer -> WriteBufFull    = WriteBufFull;
  764.  
  765.             if(!BufferFlush(Buffer))
  766.                 return(BytesWritten);
  767.  
  768.                 /* Pick up new data. */
  769.  
  770.             BufPosition        = Buffer -> BufPosition;
  771.             WriteBufFull        = Buffer -> WriteBufFull;
  772.             Data            = Buffer -> Data;
  773.  
  774.                 /* Important - or BufferFlush() won't
  775.                  * write the final buffer contents when
  776.                  * the buffered file handle is freed up.
  777.                  */
  778.  
  779.             Buffer -> Written = TRUE;
  780.         }
  781.     }
  782.  
  783.         /* Install new data. */
  784.  
  785.     Buffer -> BufPosition    = BufPosition;
  786.     Buffer -> WriteBufFull    = WriteBufFull;
  787.  
  788.     return(BytesWritten);
  789. }
  790.