home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d8xx / d832 / term.lha / Term / term-3.1-Source.lha / termFileBuffer.c < prev    next >
C/C++ Source or Header  |  1993-02-18  |  18KB  |  883 lines

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