home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / comm / term33so.lha / termFileBuffer.c < prev    next >
C/C++ Source or Header  |  1993-04-30  |  22KB  |  1,122 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.     /* ObtainInfo(struct Buffer *File):
  30.      *
  31.      *    Obtain information on the disk a buffered file
  32.      *    resides on.
  33.      */
  34.  
  35. STATIC VOID __regargs
  36. ObtainInfo(struct Buffer *File)
  37. {
  38.         /* Lock on the path available? */
  39.  
  40.     if(File -> DirLock)
  41.     {
  42.             /* Obtain information... */
  43.  
  44.         if(!Info(File -> DirLock,&File -> InfoData))
  45.         {
  46.                 /* No success, release resources. */
  47.  
  48.             UnLock(File -> DirLock);
  49.  
  50.             File -> DirLock = NULL;
  51.  
  52.             File -> InfoData . id_NumBlocks        = 0;
  53.             File -> InfoData . id_BytesPerBlock    = 0;
  54.         }
  55.     }
  56. }
  57.  
  58.     /* FileBufferServer():
  59.      *
  60.      *    Background process to handle the buffering
  61.      *    of a filehandle, automatically gets invoked
  62.      *    when a file is opened.
  63.      */
  64.  
  65. STATIC VOID __saveds
  66. FileBufferServer(VOID)
  67. {
  68.     struct MsgPort    *Port;
  69.     struct Buffer    *Buffer;
  70.     BYTE         Terminated = FALSE,
  71.              Done,
  72.              WasFull;
  73.     UBYTE        *String;
  74.     APTR         Data;
  75.     LONG         Length;
  76.     BPTR         SomeLock;
  77.  
  78.         /* Wait for startup message (-> Buffer). */
  79.  
  80.     Port = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
  81.  
  82.     WaitPort(Port);
  83.  
  84.     Buffer = (struct Buffer *)GetMsg(Port);
  85.  
  86.         /* Open the file and obtain a filehandle. */
  87.  
  88.     String = (STRPTR)Buffer -> ActionData[ARG_MODE];
  89.  
  90.     Buffer -> WriteAccess = TRUE;
  91.  
  92.         /* Put the message into the list. */
  93.  
  94.     ObtainSemaphore(&DoubleBufferSemaphore);
  95.  
  96.     AddTail(&DoubleBufferList,(struct Node *)Buffer);
  97.  
  98.     ReleaseSemaphore(&DoubleBufferSemaphore);
  99.  
  100.         /* Remember the opening date. */
  101.  
  102.     DateStamp(&Buffer -> OpenDate);
  103.  
  104.         /* Check for the open type. */
  105.  
  106.     switch(String[0])
  107.     {
  108.         case 'r':
  109.  
  110.             if(String[1] == '+')
  111.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  112.             else
  113.             {
  114.                 Buffer -> WriteAccess = FALSE;
  115.  
  116.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_OLDFILE);
  117.             }
  118.  
  119.             break;
  120.  
  121.         case 'w':
  122.  
  123.             if(String[1] == '+')
  124.             {
  125.                 if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  126.                 {
  127.                     UnLock(SomeLock);
  128.  
  129.                     DeleteFile((STRPTR)Buffer -> ActionData[ARG_NAME]);
  130.                 }
  131.  
  132.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  133.             }
  134.             else
  135.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  136.  
  137.             break;
  138.  
  139.         case 'a':
  140.  
  141.             if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  142.             {
  143.                 UnLock(SomeLock);
  144.  
  145.                 if(Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE))
  146.                 {
  147.                     if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  148.                     {
  149.                         Close(Buffer -> FileHandle);
  150.  
  151.                         Buffer -> FileHandle = NULL;
  152.                     }
  153.                 }
  154.             }
  155.             else
  156.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  157.  
  158.             break;
  159.     }
  160.  
  161.         /* Clear signal bit. */
  162.  
  163.     ClrSignal(SIG_COMMAND);
  164.  
  165.         /* Did the file open? */
  166.  
  167.     if(Buffer -> FileHandle)
  168.     {
  169.         Buffer -> Data        = Buffer -> DataBuffer[0];
  170.         Buffer -> DataCount    = 1;
  171.         Buffer -> Fresh        = TRUE;
  172.  
  173.             /* If not in write mode fill the buffers. */
  174.  
  175.         if(!Buffer -> WriteAccess)
  176.         {
  177.                 /* Fill the first one synchronously. */
  178.  
  179.             Buffer -> ReadBufFull    = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  180.             Buffer -> Read        = TRUE;
  181.             Buffer -> RealPosition    = Buffer -> ReadBufFull;
  182.  
  183.                 /* Restart caller. */
  184.  
  185.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  186.  
  187.                 /* Fill the second buffe asynchronously. */
  188.  
  189.             Buffer -> DataLength[1]    = Buffer -> Cached = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  190.             Buffer -> RealPosition += Buffer -> Cached;
  191.         }
  192.         else
  193.         {
  194.             UBYTE TempBuffer[MAX_FILENAME_LENGTH],*Stop;
  195.  
  196.             strcpy(TempBuffer,(STRPTR)Buffer -> ActionData[ARG_NAME]);
  197.  
  198.             Stop = PathPart(TempBuffer);
  199.  
  200.             *Stop = 0;
  201.  
  202.             Buffer -> DirLock = Lock(TempBuffer,ACCESS_READ);
  203.  
  204.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  205.         }
  206.     }
  207.     else
  208.         Terminated = TRUE;
  209.  
  210.         /* Go into loop waiting for commands. */
  211.  
  212.     while(!Terminated)
  213.     {
  214.         Wait(SIG_COMMAND);
  215.  
  216.         Done = FALSE;
  217.  
  218.         Buffer -> Result = 0;
  219.  
  220.             /* Take care of each action. */
  221.  
  222.         switch(Buffer -> Action)
  223.         {
  224.                 /* Close the file, flush any dirty
  225.                  * buffers and exit.
  226.                  */
  227.  
  228.             case BUF_CLOSE:
  229.  
  230.                 Buffer -> Result = TRUE;
  231.  
  232.                 if(Buffer -> BufPosition && Buffer -> Written)
  233.                 {
  234.                     if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  235.                         Buffer -> Result = FALSE;
  236.                 }
  237.  
  238.                 if(!Close(Buffer -> FileHandle))
  239.                     Buffer -> Result = FALSE;
  240.  
  241.                 if(Buffer -> DirLock)
  242.                     UnLock(Buffer -> DirLock);
  243.  
  244.                 Terminated = TRUE;
  245.  
  246.                 break;
  247.  
  248.                 /* Seek to a specific file position. */
  249.  
  250.             case BUF_SEEK:
  251.  
  252.                 Buffer -> Result = 0;
  253.  
  254.                     /* Do nothing if buffer is still
  255.                      * untouched and we are required
  256.                      * to seek back to the beginning
  257.                      * of the file.
  258.                      */
  259.  
  260.                 if(Buffer -> Fresh && !Buffer -> ActionData[ARG_OFFSET] && Buffer -> ActionData[ARG_ORIGIN] == SEEK_SET)
  261.                 {
  262.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  263.  
  264.                     Done = TRUE;
  265.                 }
  266.                 else
  267.                 {
  268.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  269.                     Buffer -> Read        = FALSE;
  270.  
  271.                     if(Buffer -> BufPosition && Buffer -> Written)
  272.                     {
  273.                         if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  274.                             Buffer -> Result = -1;
  275.                         else
  276.                             ObtainInfo(Buffer);
  277.                     }
  278.  
  279.                     if(!Buffer -> Result)
  280.                     {
  281.                         Buffer -> Result = Buffer -> RealPosition - (Buffer -> ReadBufFull + Buffer -> Cached);
  282.  
  283.                         switch(Buffer -> ActionData[ARG_ORIGIN])
  284.                         {
  285.                             case SEEK_SET:
  286.  
  287.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_BEGINNING) != -1)
  288.                                     Buffer -> RealPosition = Buffer -> ActionData[ARG_OFFSET];
  289.                                 else
  290.                                     Buffer -> Result = -1;
  291.  
  292.                                 break;
  293.  
  294.                             case SEEK_CURR:
  295.  
  296.                                 if(!Buffer -> WriteAccess && Buffer -> ActionData[ARG_OFFSET] >= 0 && Buffer -> ReadBufFull - Buffer -> ActionData[ARG_OFFSET] >= 0)
  297.                                 {
  298.                                     Buffer -> ReadBufFull    -= Buffer -> ActionData[ARG_OFFSET];
  299.                                     Buffer -> Data        += Buffer -> ActionData[ARG_OFFSET];
  300.  
  301.                                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  302.  
  303.                                     Done = TRUE;
  304.  
  305.                                     break;
  306.                                 }
  307.  
  308.                                 if(Seek(Buffer -> FileHandle,-(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET],OFFSET_CURRENT) != -1)
  309.                                     Buffer -> RealPosition += -(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET];
  310.                                 else
  311.                                     Buffer -> Result = -1;
  312.  
  313.                                 break;
  314.  
  315.                             case SEEK_END:
  316.  
  317.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_END) != -1)
  318.                                     Buffer -> RealPosition = Seek(Buffer -> FileHandle,0,OFFSET_CURRENT);
  319.                                 else
  320.                                     Buffer -> Result = -1;
  321.  
  322.                                 break;
  323.  
  324.                             default:
  325.  
  326.                                 Buffer -> Result = -1;
  327.                         }
  328.  
  329.                         Buffer -> ReadBufFull = 0;
  330.  
  331.                         if(Buffer -> Result != -1)
  332.                         {
  333.                             Buffer -> Data        = Buffer -> DataBuffer[0];
  334.                             Buffer -> DataCount    = 1;
  335.  
  336.                             if(!Buffer -> WriteAccess)
  337.                             {
  338.                                 Buffer -> ReadBufFull     = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  339.                                 Buffer -> WriteBufFull     = 0;
  340.                                 Buffer -> Read         = TRUE;
  341.                                 Buffer -> RealPosition    += Buffer -> ReadBufFull;
  342.  
  343.                                 if(Buffer -> ReadBufFull)
  344.                                 {
  345.                                     Buffer -> Cached = Buffer -> DataLength[1] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  346.  
  347.                                     Buffer -> RealPosition += Buffer -> Cached;
  348.                                 }
  349.                             }
  350.                         }
  351.                         else
  352.                             Buffer -> LastActionFailed = TRUE;
  353.                     }
  354.                     else
  355.                         Buffer -> ReadBufFull = 0;
  356.  
  357.                     Buffer -> BufPosition    = 0;
  358.                     Buffer -> Written    = FALSE;
  359.                 }
  360.  
  361.                 break;
  362.  
  363.                 /* Fill the buffer with fresh data. */
  364.  
  365.             case BUF_FILL:
  366.  
  367.                 Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  368.                 Buffer -> ReadBufFull    = Buffer -> DataLength[Buffer -> DataCount];
  369.                 Buffer -> WriteBufFull    = 0;
  370.                 Buffer -> BufPosition    = 0;
  371.                 Buffer -> Read        = TRUE;
  372.                 Buffer -> Written    = FALSE;
  373.                 Buffer -> Fresh        = FALSE;
  374.  
  375.                 if(Buffer -> ReadBufFull)
  376.                     WasFull = TRUE;
  377.                 else
  378.                     WasFull = FALSE;
  379.  
  380.                     /* The buffer contents have been
  381.                      * swapped, now wake the caller
  382.                      * up and fill the next buffer
  383.                      * asynchronously.
  384.                      */
  385.  
  386.                 Signal(Buffer -> Caller,SIG_HANDSHAKE);
  387.  
  388.                 Done = TRUE;
  389.  
  390.                 if(WasFull)
  391.                 {
  392.                     Buffer -> DataCount = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  393.  
  394.                     Buffer -> Cached = Buffer -> DataLength[Buffer -> DataCount] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[Buffer -> DataCount],Buffer -> BufLength);
  395.  
  396.                     Buffer -> RealPosition += Buffer -> Cached;
  397.  
  398.                     if(!Buffer -> DataLength[Buffer -> DataCount])
  399.                     {
  400.                         if(IoErr())
  401.                             Buffer -> LastActionFailed = TRUE;
  402.                     }
  403.                 }
  404.  
  405.                 break;
  406.  
  407.                 /* Flush the contents of the buffer to disk. */
  408.  
  409.             case BUF_FLUSH:
  410.  
  411.                 if(Buffer -> BufPosition && Buffer -> Written)
  412.                 {
  413.                     Data            = Buffer -> Data;
  414.                     Length            = Buffer -> BufPosition;
  415.  
  416.                     Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  417.                     Buffer -> DataCount    = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  418.  
  419.                     Buffer -> ReadBufFull    = 0;
  420.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  421.                     Buffer -> BufPosition    = 0;
  422.                     Buffer -> Read        = FALSE;
  423.                     Buffer -> Written    = FALSE;
  424.  
  425.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  426.  
  427.                     Done = TRUE;
  428.  
  429.                     if(Write(Buffer -> FileHandle,Data,Length) != Length)
  430.                         Buffer -> LastActionFailed = TRUE;
  431.                     else
  432.                     {
  433.                         ObtainInfo(Buffer);
  434.  
  435.                         Buffer -> RealPosition += Length;
  436.                     }
  437.                 }
  438.                 else
  439.                 {
  440.                     Buffer -> ReadBufFull    = 0;
  441.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  442.                     Buffer -> BufPosition    = 0;
  443.                     Buffer -> Read        = FALSE;
  444.                     Buffer -> Written    = FALSE;
  445.                 }
  446.  
  447.                 Buffer -> Fresh = FALSE;
  448.  
  449.                 break;
  450.         }
  451.  
  452.             /* Ring back if necessary. */
  453.  
  454.         if(!Done && !Terminated)
  455.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  456.     }
  457.  
  458.         /* Remove the message from the list. */
  459.  
  460.     ObtainSemaphore(&DoubleBufferSemaphore);
  461.  
  462.     Remove((struct Node *)Buffer);
  463.  
  464.     ReleaseSemaphore(&DoubleBufferSemaphore);
  465.  
  466.         /* Lock & quit. */
  467.  
  468.     Forbid();
  469.  
  470.     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  471. }
  472.  
  473.     /* BufferFill(struct Buffer *Buffer):
  474.      *
  475.      *    Fills a given buffer with fresh data.
  476.      */
  477.  
  478. STATIC BYTE __inline
  479. BufferFill(struct Buffer *Buffer)
  480. {
  481.     if(Buffer -> LastActionFailed)
  482.         return(FALSE);
  483.     else
  484.     {
  485.         if(!Buffer -> ReadBufFull)
  486.         {
  487.             Buffer -> Action = BUF_FILL;
  488.  
  489.             Forbid();
  490.  
  491.             Signal(Buffer -> Child,SIG_COMMAND);
  492.  
  493.             ClrSignal(SIG_HANDSHAKE);
  494.  
  495.             Wait(SIG_HANDSHAKE);
  496.  
  497.             Permit();
  498.         }
  499.  
  500.         return(TRUE);
  501.     }
  502. }
  503.  
  504.     /* BufferFlush(struct Buffer *Buffer):
  505.      *
  506.      *    Flush the contents of a given buffer to disk.
  507.      */
  508.  
  509. STATIC BYTE __inline
  510. BufferFlush(struct Buffer *Buffer)
  511. {
  512.     if(Buffer -> LastActionFailed)
  513.         return(FALSE);
  514.     else
  515.     {
  516.         if(Buffer -> BufPosition && Buffer -> Written)
  517.         {
  518.             Buffer -> Action = BUF_FLUSH;
  519.  
  520.             Forbid();
  521.  
  522.             Signal(Buffer -> Child,SIG_COMMAND);
  523.  
  524.             ClrSignal(SIG_HANDSHAKE);
  525.  
  526.             Wait(SIG_HANDSHAKE);
  527.  
  528.             Permit();
  529.         }
  530.  
  531.         return(TRUE);
  532.     }
  533. }
  534.  
  535.     /* IsValidBuffer(struct Buffer *Buffer):
  536.      *
  537.      *    Scans the double buffered file list for
  538.      *    a valid entry.
  539.      */
  540.  
  541. STATIC BYTE __inline
  542. IsValidBuffer(struct Buffer *Buffer)
  543. {
  544.     BYTE         GotIt = FALSE;
  545.     struct Node    *Node;
  546.  
  547.     ObtainSemaphore(&DoubleBufferSemaphore);
  548.  
  549.     Node = DoubleBufferList . lh_Head;
  550.  
  551.     while(Node -> ln_Succ)
  552.     {
  553.         if(Buffer == (struct Buffer *)Node)
  554.         {
  555.             GotIt = TRUE;
  556.  
  557.             break;
  558.         }
  559.  
  560.         Node = Node -> ln_Succ;
  561.     }
  562.  
  563.     ReleaseSemaphore(&DoubleBufferSemaphore);
  564.  
  565.     return(GotIt);
  566. }
  567.  
  568.     /* OpenFileSimple(STRPTR Name,STRPTR AccessMode):
  569.      *
  570.      *    Open simple (unbuffered) file.
  571.      */
  572.  
  573. STATIC struct Buffer * __regargs
  574. OpenFileSimple(STRPTR Name,STRPTR AccessMode)
  575. {
  576.     struct Buffer *Buffer;
  577.  
  578.         /* Allocate buffer handle (dummy). */
  579.  
  580.     if(Buffer = (struct Buffer *)AllocVec(sizeof(struct Buffer),MEMF_ANY | MEMF_CLEAR))
  581.     {
  582.         BPTR SomeLock;
  583.  
  584.             /* Provide basic information. */
  585.  
  586.         DateStamp(&Buffer -> OpenDate);
  587.  
  588.         Buffer -> WriteAccess = TRUE;
  589.  
  590.         Buffer -> SimpleIO = TRUE;
  591.  
  592.             /* Open the file. */
  593.  
  594.         switch(AccessMode[0])
  595.         {
  596.             case 'r':
  597.  
  598.                 if(AccessMode[1] == '+')
  599.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  600.                 else
  601.                 {
  602.                     Buffer -> WriteAccess = FALSE;
  603.  
  604.                     Buffer -> FileHandle = Open(Name,MODE_OLDFILE);
  605.                 }
  606.  
  607.                 break;
  608.  
  609.             case 'w':
  610.  
  611.                 if(AccessMode[1] == '+')
  612.                 {
  613.                     if(SomeLock = Lock(Name,ACCESS_WRITE))
  614.                     {
  615.                         UnLock(SomeLock);
  616.  
  617.                         DeleteFile(Name);
  618.                     }
  619.  
  620.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  621.                 }
  622.                 else
  623.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  624.  
  625.                 break;
  626.  
  627.             case 'a':
  628.  
  629.                 if(SomeLock = Lock(Name,ACCESS_WRITE))
  630.                 {
  631.                     UnLock(SomeLock);
  632.  
  633.                     if(Buffer -> FileHandle = Open(Name,MODE_READWRITE))
  634.                     {
  635.                         if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  636.                         {
  637.                             Close(Buffer -> FileHandle);
  638.  
  639.                             Buffer -> FileHandle = NULL;
  640.                         }
  641.                     }
  642.                 }
  643.                 else
  644.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  645.  
  646.                 break;
  647.         }
  648.  
  649.             /* Did we succeed in opening the file? */
  650.  
  651.         if(Buffer -> FileHandle)
  652.         {
  653.                 /* Try to obtain a lock on the destination directory. */
  654.  
  655.             if(Buffer -> WriteAccess)
  656.             {
  657.                 UBYTE TempBuffer[MAX_FILENAME_LENGTH],*Stop;
  658.  
  659.                 strcpy(TempBuffer,(STRPTR)Buffer -> ActionData[ARG_NAME]);
  660.  
  661.                 Stop = PathPart(TempBuffer);
  662.  
  663.                 *Stop = 0;
  664.  
  665.                 Buffer -> DirLock = Lock(TempBuffer,ACCESS_READ);
  666.  
  667.                 ObtainInfo(Buffer);
  668.             }
  669.  
  670.                 /* Link the file into the list. */
  671.  
  672.             ObtainSemaphore(&DoubleBufferSemaphore);
  673.  
  674.             AddTail(&DoubleBufferList,(struct Node *)Buffer);
  675.  
  676.             ReleaseSemaphore(&DoubleBufferSemaphore);
  677.  
  678.             return(Buffer);
  679.         }
  680.         else
  681.             FreeVec(Buffer);
  682.     }
  683.  
  684.     return(NULL);
  685. }
  686.  
  687.     /* OpenFileBuffered(STRPTR Name,STRPTR AccessMode):
  688.      *
  689.      *    Open double-buffered file.
  690.      */
  691.  
  692. STATIC struct Buffer * __regargs
  693. OpenFileBuffered(STRPTR Name,STRPTR AccessMode)
  694. {
  695.     struct Buffer *Buffer;
  696.  
  697.         /* Allocate the buffer data. */
  698.  
  699.     if(Buffer = (struct Buffer *)AllocVec(sizeof(struct Buffer) + BUFFER_SIZE * BUFFER_NUMBER,MEMF_ANY|MEMF_CLEAR))
  700.     {
  701.         struct Process    *Process;
  702.         WORD         i;
  703.  
  704.             /* Set up the first buffer. */
  705.  
  706.         Buffer -> DataBuffer[0] = (STRPTR)(Buffer + 1);
  707.  
  708.             /* Set up the individual buffers. */
  709.  
  710.         for(i = 1 ; i < BUFFER_NUMBER ; i++)
  711.             Buffer -> DataBuffer[i] = Buffer -> DataBuffer[i - 1] + BUFFER_SIZE;
  712.  
  713.         Buffer -> BufLength    = BUFFER_SIZE;
  714.         Buffer -> WriteBufFull    = Buffer -> BufLength;
  715.  
  716.             /* Create the asynchronous file server. */
  717.  
  718.         if(!(Process = CreateNewProcTags(
  719.             NP_Entry,    FileBufferServer,
  720.             NP_Name,    "term file process",
  721.             NP_Priority,    SysBase -> ThisTask -> tc_Node . ln_Pri,
  722.             NP_StackSize,    8192,
  723.             NP_WindowPtr,    -1,
  724.         TAG_DONE)))
  725.         {
  726.             FreeVec(Buffer);
  727.  
  728.             return(NULL);
  729.         }
  730.  
  731.             /* Set up the message header. */
  732.  
  733.         Buffer -> Message . mn_Length    = sizeof(struct Buffer);
  734.  
  735.         Buffer -> ActionData[ARG_NAME]    = (LONG)Name;
  736.         Buffer -> ActionData[ARG_MODE]    = (LONG)AccessMode;
  737.  
  738.         Buffer -> Child            = Process;
  739.         Buffer -> Caller        = (struct Process *)SysBase -> ThisTask;
  740.  
  741.         Forbid();
  742.  
  743.             /* Send it to the waiting server process. */
  744.  
  745.         PutMsg(&Process -> pr_MsgPort,&Buffer -> Message);
  746.  
  747.             /* Wait for ringback. */
  748.  
  749.         ClrSignal(SIG_HANDSHAKE);
  750.  
  751.         Wait(SIG_HANDSHAKE);
  752.  
  753.         Permit();
  754.  
  755.             /* Do we have a valid filehandle? */
  756.  
  757.         if(!Buffer -> FileHandle)
  758.         {
  759.             FreeVec(Buffer);
  760.  
  761.             return(NULL);
  762.         }
  763.         else
  764.             return(Buffer);
  765.     }
  766.  
  767.     return(NULL);
  768. }
  769.  
  770.     /* BPrintf():
  771.      *
  772.      *    Prints text into a buffered file.
  773.      */
  774.  
  775. LONG __stdargs
  776. BPrintf(struct Buffer *Buffer,STRPTR Format,...)
  777. {
  778.     UBYTE    String[256];
  779.     va_list    VarArgs;
  780.  
  781.     va_start(VarArgs,Format);
  782.     VSPrintf(String,Format,VarArgs);
  783.     va_end(VarArgs);
  784.  
  785.     return(BufferWrite(Buffer,String,strlen(String)));
  786. }
  787.  
  788.     /* BufferClose(struct Buffer *Buffer):
  789.      *
  790.      *    Close a buffered filehandle.
  791.      */
  792.  
  793. BYTE __regargs
  794. BufferClose(struct Buffer *Buffer)
  795. {
  796.     if(IsValidBuffer(Buffer))
  797.     {
  798.         BYTE Success;
  799.  
  800.             /* Unbuffered file handle? */
  801.  
  802.         if(Buffer -> SimpleIO)
  803.         {
  804.                 /* Drop the destination drawer lock. */
  805.  
  806.             if(Buffer -> DirLock)
  807.                 UnLock(Buffer -> DirLock);
  808.  
  809.                 /* Close the file. */
  810.  
  811.             if(Close(Buffer -> FileHandle))
  812.                 Success = TRUE;
  813.             else
  814.                 Success = FALSE;
  815.  
  816.                 /* Unlink the handle. */
  817.  
  818.             ObtainSemaphore(&DoubleBufferSemaphore);
  819.  
  820.             Remove((struct Node *)Buffer);
  821.  
  822.             ReleaseSemaphore(&DoubleBufferSemaphore);
  823.         }
  824.         else
  825.         {
  826.             Buffer -> Action = BUF_CLOSE;
  827.  
  828.             Forbid();
  829.  
  830.             Signal(Buffer -> Child,SIG_COMMAND);
  831.  
  832.             ClrSignal(SIG_HANDSHAKE);
  833.  
  834.             Wait(SIG_HANDSHAKE);
  835.  
  836.             Permit();
  837.  
  838.             Success = Buffer -> Result;
  839.         }
  840.  
  841.         FreeVec(Buffer);
  842.  
  843.         return(Success);
  844.     }
  845.     else
  846.         return(FALSE);
  847. }
  848.  
  849.     /* BufferOpen(STRPTR Name,STRPTR AccessMode):
  850.      *
  851.      *    Open a file for buffered I/O.
  852.      */
  853.  
  854. struct Buffer * __regargs
  855. BufferOpen(STRPTR Name,STRPTR AccessMode)
  856. {
  857.         /* Simple file handling? */
  858.  
  859.     if(Config -> MiscConfig -> SimpleIO || InRexx)
  860.         return(OpenFileSimple(Name,AccessMode));
  861.     else
  862.     {
  863.         struct Buffer *Buffer;
  864.  
  865.             /* Try to open a buffered file, if unsuccessful
  866.              * fall back to simple file I/O.
  867.              */
  868.  
  869.         if(!(Buffer = OpenFileBuffered(Name,AccessMode)))
  870.             Buffer = OpenFileSimple(Name,AccessMode);
  871.  
  872.         return(Buffer);
  873.     }
  874. }
  875.  
  876.     /* BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin):
  877.      *
  878.      *    Move the read/write pointer to a specific position
  879.      *    in a file (not really buffered).
  880.      */
  881.  
  882. BYTE __regargs
  883. BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin)
  884. {
  885.     if(Buffer -> SimpleIO)
  886.     {
  887.         if(Seek(Buffer -> FileHandle,Offset,Origin) == -1)
  888.             return(FALSE);
  889.         else
  890.             return(TRUE);
  891.     }
  892.     else
  893.     {
  894.         Buffer -> Action            = BUF_SEEK;
  895.         Buffer -> ActionData[ARG_OFFSET]    = Offset;
  896.         Buffer -> ActionData[ARG_ORIGIN]    = Origin;
  897.  
  898.         Forbid();
  899.  
  900.         Signal(Buffer -> Child,SIG_COMMAND);
  901.  
  902.         ClrSignal(SIG_HANDSHAKE);
  903.  
  904.         Wait(SIG_HANDSHAKE);
  905.  
  906.         Permit();
  907.  
  908.         if(Buffer -> Result == -1)
  909.             return(FALSE);
  910.         else
  911.             return(TRUE);
  912.     }
  913. }
  914.  
  915.     /* BufferRead():
  916.      *
  917.      *    Read data from a file (buffered).
  918.      */
  919.  
  920. LONG __regargs
  921. BufferRead(struct Buffer *Buffer,STRPTR Destination,LONG Size)
  922. {
  923.     if(Buffer -> SimpleIO)
  924.     {
  925.         LONG Bytes;
  926.  
  927.         Buffer -> Used = TRUE;
  928.  
  929.         if((Bytes = Read(Buffer -> FileHandle,Destination,Size)) < 0)
  930.             Bytes = 0;
  931.  
  932.         return(Bytes);
  933.     }
  934.     else
  935.     {
  936.         LONG     BytesRead = 0,ToCopy,BufPosition,ReadBufFull;
  937.         UBYTE    *Data;
  938.  
  939.             /* If there is still data to be written in
  940.              * the buffer, write it.
  941.              */
  942.  
  943.         if(Buffer -> Written)
  944.         {
  945.             if(!BufferFlush(Buffer))
  946.                 return(0);
  947.         }
  948.  
  949.             /* Set up for read access. */
  950.  
  951.         BufPosition    = Buffer -> BufPosition;
  952.         ReadBufFull    = Buffer -> ReadBufFull;
  953.         Data        = &Buffer -> Data[BufPosition];
  954.  
  955.             /* Remember access. */
  956.  
  957.         Buffer -> Used    = TRUE;
  958.  
  959.             /* Continue until all data has been processed. */
  960.  
  961.         while(Size)
  962.         {
  963.                 /* Determine number of bytes to transfer. */
  964.  
  965.             if(ToCopy = (Size > ReadBufFull) ? ReadBufFull : Size)
  966.             {
  967.                 CopyMem(Data,Destination,ToCopy);
  968.  
  969.                 Size        -= ToCopy;
  970.                 BufPosition    += ToCopy;
  971.                 ReadBufFull    -= ToCopy;
  972.                 Destination    += ToCopy;
  973.                 Data        += ToCopy;
  974.                 BytesRead    += ToCopy;
  975.             }
  976.             else
  977.             {
  978.                     /* Refill buffer with data. */
  979.  
  980.                 Buffer -> BufPosition    = BufPosition;
  981.                 Buffer -> ReadBufFull    = ReadBufFull;
  982.  
  983.                 if(!BufferFill(Buffer))
  984.                     return(BytesRead);
  985.  
  986.                 if(!Buffer -> ReadBufFull)
  987.                 {
  988.                     Buffer -> BufPosition = BufPosition;
  989.  
  990.                     return(BytesRead);
  991.                 }
  992.  
  993.                     /* Pick up new data. */
  994.  
  995.                 BufPosition        = Buffer -> BufPosition;
  996.                 ReadBufFull        = Buffer -> ReadBufFull;
  997.                 Data            = Buffer -> Data;
  998.             }
  999.         }
  1000.  
  1001.             /* Install new data. */
  1002.  
  1003.         Buffer -> BufPosition    = BufPosition;
  1004.         Buffer -> ReadBufFull    = ReadBufFull;
  1005.  
  1006.         return(BytesRead);
  1007.     }
  1008. }
  1009.  
  1010.     /* BufferWrite():
  1011.      *
  1012.      *    Write data to a file (buffered).
  1013.      */
  1014.  
  1015. LONG __regargs
  1016. BufferWrite(struct Buffer *Buffer,STRPTR Source,LONG Size)
  1017. {
  1018.     if(Buffer -> SimpleIO)
  1019.     {
  1020.         LONG Bytes;
  1021.  
  1022.         Buffer -> Used = TRUE;
  1023.  
  1024.         Buffer -> WriteAccess = TRUE;
  1025.  
  1026.         if((Bytes = Write(Buffer -> FileHandle,Source,Size)) < 0)
  1027.             Bytes = 0;
  1028.         else
  1029.         {
  1030.             Buffer -> BufPosition += Bytes;
  1031.  
  1032.             if(Buffer -> BufPosition >= BUFFER_SIZE)
  1033.             {
  1034.                 Buffer -> BufPosition = 0;
  1035.  
  1036.                 ObtainInfo(Buffer);
  1037.             }
  1038.         }
  1039.  
  1040.         return(Bytes);
  1041.     }
  1042.     else
  1043.     {
  1044.         LONG     BytesWritten = 0,ToCopy,BufPosition,WriteBufFull;
  1045.         UBYTE    *Data;
  1046.  
  1047.             /* If there is still read data in the buffer,
  1048.              * reset the control information.
  1049.              */
  1050.  
  1051.         if(Buffer -> Read)
  1052.         {
  1053.             Buffer -> WriteBufFull    = Buffer -> BufLength;
  1054.             Buffer -> BufPosition    = 0;
  1055.             Buffer -> Read        = FALSE;
  1056.         }
  1057.  
  1058.             /* Set up for write access. */
  1059.  
  1060.         Buffer -> Written = TRUE;
  1061.  
  1062.         BufPosition    = Buffer -> BufPosition;
  1063.         WriteBufFull    = Buffer -> WriteBufFull;
  1064.         Data        = &Buffer -> Data[BufPosition];
  1065.  
  1066.             /* Remember access. */
  1067.  
  1068.         Buffer -> Used    = TRUE;
  1069.  
  1070.             /* Continue until all data has been processed. */
  1071.  
  1072.         while(Size)
  1073.         {
  1074.                 /* Determine number of bytes to transfer. */
  1075.  
  1076.             if(ToCopy = (Size > WriteBufFull ? WriteBufFull : Size))
  1077.             {
  1078.                 CopyMem(Source,Data,ToCopy);
  1079.  
  1080.                 Size        -= ToCopy;
  1081.                 BufPosition    += ToCopy;
  1082.                 WriteBufFull    -= ToCopy;
  1083.                 Source        += ToCopy;
  1084.                 Data        += ToCopy;
  1085.                 BytesWritten    += ToCopy;
  1086.             }
  1087.             else
  1088.             {
  1089.                     /* Flush the contents of the
  1090.                      * write buffer.
  1091.                      */
  1092.  
  1093.                 Buffer -> BufPosition    = BufPosition;
  1094.                 Buffer -> WriteBufFull    = WriteBufFull;
  1095.  
  1096.                 if(!BufferFlush(Buffer))
  1097.                     return(BytesWritten);
  1098.  
  1099.                     /* Pick up new data. */
  1100.  
  1101.                 BufPosition        = Buffer -> BufPosition;
  1102.                 WriteBufFull        = Buffer -> WriteBufFull;
  1103.                 Data            = Buffer -> Data;
  1104.  
  1105.                     /* Important - or BufferFlush() won't
  1106.                      * write the final buffer contents when
  1107.                      * the buffered file handle is freed up.
  1108.                      */
  1109.  
  1110.                 Buffer -> Written = TRUE;
  1111.             }
  1112.         }
  1113.  
  1114.             /* Install new data. */
  1115.  
  1116.         Buffer -> BufPosition    = BufPosition;
  1117.         Buffer -> WriteBufFull    = WriteBufFull;
  1118.  
  1119.         return(BytesWritten);
  1120.     }
  1121. }
  1122.