gno/sys/fileport/support/Read.c

344 lines
13 KiB
C

/*
* Copyright (c) Kopriha Software, 1990-1991
* All Rights Reserved
*
* Read.CC
*
* Description:
* This module exists to abstract the data of the file I/O
* primitives of GS/OS.
*
*
* History:Oct 13, 1990 Dave Created this file
*
* Feb 25, 1991 Dave Added I/O buffering
*
* May 26, 1991 Dave Added set EOF
*
* Jun 07, 1991 Dave Broke the single source into lots
* of small sources so we can build
* a library to use...
*
* Jun 30, 1991 Dave Added support for no target buffer
* (IE: This allows me to open a file
* with a buffer then do I/O to only
* that buffer - we will assume that
* the caller will know what he is doing).
*
* This functionallity is invoked when
* we are called with a data_buffer
* pointer to NULL (then the user must
* understand that the file_ptr->buffer
* is where he will find his data).
*
* Note: This functionallity is only
* implemented for the buffered I/O case!
*
*/
/*
* define DEBUG_CODE
* - add # to define to create the local
* debug code (IE:module)
*/
#ifndef _KS_FILEIO_
#include "ks.fileio.h"
#endif
#pragma noroot
/* ****************************************************************** *
* ks_file_read - Perform an read from an open file (possibly using *
* an internal buffer). *
* *
* History: Feb 26, 1991 Dave Created this routine *
* ****************************************************************** */
#undef ROUTINE_NAME
#define ROUTINE_NAME "ks_file_read"
KS_E_ERROR ks_file_read(KS_FILE_PTR file_ptr,
LongWord position,
LongWord data_size,
Pointer data_buffer)
{
/* ************************************************************** *
* Local declarations: *
* ************************************************************** */
KS_E_ERROR error; /* Holds error codes for subroutine*/
/* calls */
LongWord data_offset; /* Offset into the buffer to return*/
LongWord remaining_space; /* Space remaining in file buffer */
LongWord buffer_request; /* Size of each copy from the */
/* file buffer */
ROUTINE_ENTER();
/* ************************************************************** *
* Verify the structure ID passed in is the correct one. *
* ************************************************************** */
if (file_ptr->struct_id != KS_FILE_ID)
{
KS_ERROR(KS_E_INVALID_STRUCT_ID, KS_FILE_ID);
};
/* ************************************************************** *
* Zero the number of bytes transfered in the KS_FILE structure. *
* ************************************************************** */
file_ptr->data_size = 0;
/* ************************************************************** *
* If there is a buffer, then lets get data from the file buffer.*
* ************************************************************** */
if (file_ptr->buffer_size != NULL)
{
/* ********************************************************** *
* If we hit the end of file last time, then we have no *
* choice but to return an error. *
* ********************************************************** */
if (file_ptr->end_of_file == TRUE)
{
error = eofEncountered;
goto EXIT_NOW;
};
/* ********************************************************** *
* Loop till we satisfy the request (or take an error) *
* ********************************************************** */
data_offset = 0;
while (data_size > 0)
{
/* ****************************************************** *
* Calculate the remaining space in the buffer. If *
* there is any space left in the buffer then lets copy *
* as much as we need to into the output buffer. *
* ****************************************************** */
remaining_space = (file_ptr->buffer_available) -
(file_ptr->buffer_offset);
if (remaining_space > 0)
{
buffer_request = MIN(data_size,
remaining_space);
/* ************************************************** *
* Copy the available bytes (or the required bytes) *
* to the target buffer (if one was supplied). *
* ************************************************** */
if (data_buffer != NULL)
{
COPY_BYTES(file_ptr->buffer,
file_ptr->buffer_offset,
data_buffer,
data_offset,
buffer_request);
};
/* ************************************************** *
* Now modify the parameters of the buffers by: *
* *
* 1) Adding the size of the request to the file *
* buffer ofset and the data offset (IE: Indices to *
* the file buffer and the read request buffer). *
* *
* 2) Subtracting the request size from the read *
* request size and the remaining number of *
* characters in the file buffer. *
* ************************************************** */
file_ptr->buffer_offset = file_ptr->buffer_offset +
buffer_request;
data_offset = data_offset + buffer_request;
file_ptr->data_size = data_offset;
data_size = data_size - buffer_request;
remaining_space = remaining_space - buffer_request;
};
/* ****************************************************** *
* If isn't anything in the file buffer, the we have to *
* re-fill it. The problem is that the buffer size may *
* have changed due to what our user wants (users are *
* bound to be the end of all computing...). This means *
* that we'll junp through a few hoops if we must change *
* buffer sizes - so expect some weirdness here. *
* ****************************************************** */
if (remaining_space == 0)
{
/* ************************************************** *
* This is the above mentioned weirdness - if the *
* user specified a different size buffer we will *
* no comply with their wishes. *
* ************************************************** */
if (file_ptr->buffer_size != KSf_FileBufferSize)
{
KS_MEMORY_DEALLOCATE(file_ptr->buffer_handle,
error);
if (error != KS_E_SUCCESS)
{
goto EXIT_NOW;
};
KS_MEMORY_ALLOCATE(attrFixed + attrLocked,
KSf_FileBufferSize,
BUFFER_USERID,
file_ptr->buffer_handle,
error);
if (error != KS_E_SUCCESS)
{
goto EXIT_NOW;
};
file_ptr->buffer = (Byte *)
*(file_ptr->buffer_handle);
file_ptr->buffer_size = KSf_FileBufferSize;
file_ptr->buffer_available = KSf_FileBufferSize;
};
/* ************************************************** *
* Issue a Read to the file into our buffer. *
* ************************************************** */
KSf_pkts.IO.pCount = 4;
KSf_pkts.IO.refNum = file_ptr->refNum;
KSf_pkts.IO.dataBuffer = TO_POINTER(file_ptr->buffer);
KSf_pkts.IO.requestCount = file_ptr->buffer_size;
ReadGS(&KSf_pkts.IO);
/* ************************************************** *
* Now for the error processing. *
* *
* Any error means we return to our caller. *
* *
* The end of file error (eofEncountered or $4c) is *
* special. At EOF we mark the KS_FILE structure *
* so the next READ call will return EOF right away. *
* We will return SUCCESS in this case because the *
* user will be able to find some data in the input *
* buffer (total amount == ).
* ************************************************** */
if ((error = GET_ERROR()) != KS_E_SUCCESS)
{
if (error == eofEncountered)
{
error = KS_E_SUCCESS;
file_ptr->end_of_file = TRUE;
}
goto EXIT_NOW;
};
file_ptr->buffer_available = KSf_pkts.IO.transferCount;
file_ptr->buffer_offset = 0;
}; /* End if there is no remaining buffer space */
}; /* End while there are characters to be read... */
KS_SUCCESS();
}; /* End if we are doing buffer I/O from the file */
/* ************************************************************** *
* Ok, we've done enough buffering... lets do some real input... *
* *
* Position the 'mark' (where we will read from) in the file. *
* Note: We'll move the mark only if our user asks us to. *
* ************************************************************** */
if (position != KS_NEXT_FILE_POSITION)
{
KSf_pkts.position.pCount = 3;
KSf_pkts.position.refNum = file_ptr->refNum;
KSf_pkts.position.base = startPlus;
KSf_pkts.position.displacement = position;
SetMarkGS(&KSf_pkts.position);
if ((error = GET_ERROR()) != KS_E_SUCCESS)
{
goto EXIT_NOW;
};
}; /* End if we must change the file position */
/* ************************************************************** *
* Setup the I/O packet and read what our user is asking for. *
* ************************************************************** */
KSf_pkts.IO.pCount = 4;
KSf_pkts.IO.refNum = file_ptr->refNum;
KSf_pkts.IO.dataBuffer = data_buffer;
KSf_pkts.IO.requestCount = data_size;
ReadGS(&KSf_pkts.IO);
if ((error = GET_ERROR()) != KS_E_SUCCESS)
{
goto EXIT_NOW;
};
/* ************************************************************** *
* Save the number of bytes transfered in the KS_FILE structure. *
* ************************************************************** */
file_ptr->data_size = KSf_pkts.IO.transferCount;
/* ************************************************************** *
* Return the status back to our caller. *
* ************************************************************** */
EXIT_NOW:
if (error != KS_E_SUCCESS)
{
KS_ERROR(error, KS_FILE_ID);
};
KS_SUCCESS();
} /* End of ks_file_read() */