| /* do not edit automatically generated by mc from FIO. */ |
| /* FIO.mod provides a simple buffered file input/output library. |
| |
| Copyright (C) 2001-2025 Free Software Foundation, Inc. |
| Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
| |
| This file is part of GNU Modula-2. |
| |
| GNU Modula-2 is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GNU Modula-2 is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| Under Section 7 of GPL version 3, you are granted additional |
| permissions described in the GCC Runtime Library Exception, version |
| 3.1, as published by the Free Software Foundation. |
| |
| You should have received a copy of the GNU General Public License and |
| a copy of the GCC Runtime Library Exception along with this program; |
| see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include <stdbool.h> |
| # if !defined (PROC_D) |
| # define PROC_D |
| typedef void (*PROC_t) (void); |
| typedef struct { PROC_t proc; } PROC; |
| # endif |
| |
| # if !defined (TRUE) |
| # define TRUE (1==1) |
| # endif |
| |
| # if !defined (FALSE) |
| # define FALSE (1==0) |
| # endif |
| |
| #include <stddef.h> |
| #include <string.h> |
| #include <limits.h> |
| #include <stdlib.h> |
| # include "GStorage.h" |
| # include "Gmcrts.h" |
| #include <unistd.h> |
| #if defined(__cplusplus) |
| # undef NULL |
| # define NULL 0 |
| #endif |
| #define _FIO_C |
| |
| #include "GFIO.h" |
| # include "GSYSTEM.h" |
| # include "GASCII.h" |
| # include "GStrLib.h" |
| # include "GStorage.h" |
| # include "GNumberIO.h" |
| # include "GIndexing.h" |
| # include "GM2RTS.h" |
| # include "Glibc.h" |
| # include "Gwrapc.h" |
| |
| typedef unsigned int FIO_File; |
| |
| # define MaxBufferLength (1024*16) |
| # define MaxErrorString (1024*8) |
| # define CreatePermissions 0666 |
| typedef struct FIO_NameInfo_r FIO_NameInfo; |
| |
| typedef struct FIO_buf_r FIO_buf; |
| |
| typedef FIO_buf *FIO_Buffer; |
| |
| typedef struct FIO_fds_r FIO_fds; |
| |
| typedef FIO_fds *FIO_FileDescriptor; |
| |
| typedef struct FIO__T7_a FIO__T7; |
| |
| typedef char *FIO_PtrToChar; |
| |
| typedef enum {FIO_successful, FIO_outofmemory, FIO_toomanyfilesopen, FIO_failed, FIO_connectionfailure, FIO_endofline, FIO_endoffile} FIO_FileStatus; |
| |
| typedef enum {FIO_unused, FIO_openedforread, FIO_openedforwrite, FIO_openedforrandom} FIO_FileUsage; |
| |
| struct FIO_NameInfo_r { |
| void *address; |
| unsigned int size; |
| }; |
| |
| struct FIO_buf_r { |
| bool valid; |
| long int bufstart; |
| unsigned int position; |
| void *address; |
| unsigned int filled; |
| unsigned int size; |
| unsigned int left; |
| FIO__T7 *contents; |
| }; |
| |
| struct FIO__T7_a { char array[MaxBufferLength+1]; }; |
| struct FIO_fds_r { |
| int unixfd; |
| FIO_NameInfo name; |
| FIO_FileStatus state; |
| FIO_FileUsage usage; |
| bool output; |
| FIO_Buffer buffer; |
| long int abspos; |
| }; |
| |
| static Indexing_Index FileInfo; |
| static FIO_File Error; |
| |
| /* |
| IsNoError - returns a TRUE if no error has occured on file, f. |
| */ |
| |
| extern "C" bool FIO_IsNoError (FIO_File f); |
| |
| /* |
| IsActive - returns TRUE if the file, f, is still active. |
| */ |
| |
| extern "C" bool FIO_IsActive (FIO_File f); |
| extern "C" bool FIO_Exists (const char *fname_, unsigned int _fname_high); |
| extern "C" FIO_File FIO_OpenToRead (const char *fname_, unsigned int _fname_high); |
| extern "C" FIO_File FIO_OpenToWrite (const char *fname_, unsigned int _fname_high); |
| extern "C" FIO_File FIO_OpenForRandom (const char *fname_, unsigned int _fname_high, bool towrite, bool newfile); |
| |
| /* |
| Close - close a file which has been previously opened using: |
| OpenToRead, OpenToWrite, OpenForRandom. |
| It is correct to close a file which has an error status. |
| */ |
| |
| extern "C" void FIO_Close (FIO_File f); |
| |
| /* |
| exists - returns TRUE if a file named, fname exists for reading. |
| */ |
| |
| extern "C" bool FIO_exists (void * fname, unsigned int flength); |
| |
| /* |
| openToRead - attempts to open a file, fname, for reading and |
| it returns this file. |
| The success of this operation can be checked by |
| calling IsNoError. |
| */ |
| |
| extern "C" FIO_File FIO_openToRead (void * fname, unsigned int flength); |
| |
| /* |
| openToWrite - attempts to open a file, fname, for write and |
| it returns this file. |
| The success of this operation can be checked by |
| calling IsNoError. |
| */ |
| |
| extern "C" FIO_File FIO_openToWrite (void * fname, unsigned int flength); |
| |
| /* |
| openForRandom - attempts to open a file, fname, for random access |
| read or write and it returns this file. |
| The success of this operation can be checked by |
| calling IsNoError. |
| towrite, determines whether the file should be |
| opened for writing or reading. |
| */ |
| |
| extern "C" FIO_File FIO_openForRandom (void * fname, unsigned int flength, bool towrite, bool newfile); |
| |
| /* |
| FlushBuffer - flush contents of file, f. |
| */ |
| |
| extern "C" void FIO_FlushBuffer (FIO_File f); |
| |
| /* |
| ReadNBytes - reads nBytes of a file into memory area, dest, returning |
| the number of bytes actually read. |
| This function will consume from the buffer and then |
| perform direct libc reads. It is ideal for large reads. |
| */ |
| |
| extern "C" unsigned int FIO_ReadNBytes (FIO_File f, unsigned int nBytes, void * dest); |
| |
| /* |
| ReadAny - reads HIGH (a) + 1 bytes into, a. All input |
| is fully buffered, unlike ReadNBytes and thus is more |
| suited to small reads. |
| */ |
| |
| extern "C" void FIO_ReadAny (FIO_File f, unsigned char *a, unsigned int _a_high); |
| |
| /* |
| WriteNBytes - writes nBytes from memory area src to a file |
| returning the number of bytes actually written. |
| This function will flush the buffer and then |
| write the nBytes using a direct write from libc. |
| It is ideal for large writes. |
| */ |
| |
| extern "C" unsigned int FIO_WriteNBytes (FIO_File f, unsigned int nBytes, void * src); |
| |
| /* |
| WriteAny - writes HIGH (a) + 1 bytes onto, file, f. All output |
| is fully buffered, unlike WriteNBytes and thus is more |
| suited to small writes. |
| */ |
| |
| extern "C" void FIO_WriteAny (FIO_File f, unsigned char *a, unsigned int _a_high); |
| |
| /* |
| WriteChar - writes a single character to file, f. |
| */ |
| |
| extern "C" void FIO_WriteChar (FIO_File f, char ch); |
| |
| /* |
| EOF - tests to see whether a file, f, has reached end of file. |
| */ |
| |
| extern "C" bool FIO_EOF (FIO_File f); |
| |
| /* |
| EOLN - tests to see whether a file, f, is upon a newline. |
| It does NOT consume the newline. |
| */ |
| |
| extern "C" bool FIO_EOLN (FIO_File f); |
| |
| /* |
| WasEOLN - tests to see whether a file, f, has just seen a newline. |
| */ |
| |
| extern "C" bool FIO_WasEOLN (FIO_File f); |
| |
| /* |
| ReadChar - returns a character read from file f. |
| Sensible to check with IsNoError or EOF after calling |
| this function. |
| */ |
| |
| extern "C" char FIO_ReadChar (FIO_File f); |
| |
| /* |
| UnReadChar - replaces a character, ch, back into file f. |
| This character must have been read by ReadChar |
| and it does not allow successive calls. It may |
| only be called if the previous read was successful |
| or end of file was seen. |
| If the state was previously endoffile then it |
| is altered to successful. |
| Otherwise it is left alone. |
| */ |
| |
| extern "C" void FIO_UnReadChar (FIO_File f, char ch); |
| |
| /* |
| WriteLine - writes out a linefeed to file, f. |
| */ |
| |
| extern "C" void FIO_WriteLine (FIO_File f); |
| |
| /* |
| WriteString - writes a string to file, f. |
| */ |
| |
| extern "C" void FIO_WriteString (FIO_File f, const char *a_, unsigned int _a_high); |
| |
| /* |
| ReadString - reads a string from file, f, into string, a. |
| It terminates the string if HIGH is reached or |
| if a newline is seen or an error occurs. |
| */ |
| |
| extern "C" void FIO_ReadString (FIO_File f, char *a, unsigned int _a_high); |
| |
| /* |
| WriteCardinal - writes a CARDINAL to file, f. |
| It writes the binary image of the cardinal |
| to file, f. |
| */ |
| |
| extern "C" void FIO_WriteCardinal (FIO_File f, unsigned int c); |
| |
| /* |
| ReadCardinal - reads a CARDINAL from file, f. |
| It reads a binary image of a CARDINAL |
| from a file, f. |
| */ |
| |
| extern "C" unsigned int FIO_ReadCardinal (FIO_File f); |
| |
| /* |
| GetUnixFileDescriptor - returns the UNIX file descriptor of a file. |
| */ |
| |
| extern "C" int FIO_GetUnixFileDescriptor (FIO_File f); |
| |
| /* |
| SetPositionFromBeginning - sets the position from the beginning of the file. |
| */ |
| |
| extern "C" void FIO_SetPositionFromBeginning (FIO_File f, long int pos); |
| |
| /* |
| SetPositionFromEnd - sets the position from the end of the file. |
| */ |
| |
| extern "C" void FIO_SetPositionFromEnd (FIO_File f, long int pos); |
| |
| /* |
| FindPosition - returns the current absolute position in file, f. |
| */ |
| |
| extern "C" long int FIO_FindPosition (FIO_File f); |
| |
| /* |
| GetFileName - assigns, a, with the filename associated with, f. |
| */ |
| |
| extern "C" void FIO_GetFileName (FIO_File f, char *a, unsigned int _a_high); |
| |
| /* |
| getFileName - returns the address of the filename associated with, f. |
| */ |
| |
| extern "C" void * FIO_getFileName (FIO_File f); |
| |
| /* |
| getFileNameLength - returns the number of characters associated with filename, f. |
| */ |
| |
| extern "C" unsigned int FIO_getFileNameLength (FIO_File f); |
| |
| /* |
| FlushOutErr - flushes, StdOut, and, StdErr. |
| It is also called when the application calls M2RTS.Terminate. |
| (which is automatically placed in program modules by the GM2 |
| scaffold). |
| */ |
| |
| extern "C" void FIO_FlushOutErr (void); |
| |
| /* |
| Max - returns the maximum of two values. |
| */ |
| |
| static unsigned int Max (unsigned int a, unsigned int b); |
| |
| /* |
| Min - returns the minimum of two values. |
| */ |
| |
| static unsigned int Min (unsigned int a, unsigned int b); |
| |
| /* |
| GetNextFreeDescriptor - returns the index to the FileInfo array indicating |
| the next free slot. |
| */ |
| |
| static FIO_File GetNextFreeDescriptor (void); |
| |
| /* |
| SetState - sets the field, state, of file, f, to, s. |
| */ |
| |
| static void SetState (FIO_File f, FIO_FileStatus s); |
| |
| /* |
| InitializeFile - initialize a file descriptor |
| */ |
| |
| static FIO_File InitializeFile (FIO_File f, void * fname, unsigned int flength, FIO_FileStatus fstate, FIO_FileUsage use, bool towrite, unsigned int buflength); |
| |
| /* |
| ConnectToUnix - connects a FIO file to a UNIX file descriptor. |
| */ |
| |
| static void ConnectToUnix (FIO_File f, bool towrite, bool newfile); |
| |
| /* |
| ReadFromBuffer - attempts to read, nBytes, from file, f. |
| It firstly consumes the buffer and then performs |
| direct unbuffered reads. This should only be used |
| when wishing to read large files. |
| |
| The actual number of bytes read is returned. |
| -1 is returned if EOF is reached. |
| */ |
| |
| static int ReadFromBuffer (FIO_File f, void * a, unsigned int nBytes); |
| |
| /* |
| BufferedRead - will read, nBytes, through the buffer. |
| Similar to ReadFromBuffer, but this function will always |
| read into the buffer before copying into memory. |
| |
| Useful when performing small reads. |
| */ |
| |
| static int BufferedRead (FIO_File f, unsigned int nBytes, void * dest); |
| |
| /* |
| HandleEscape - translates |
| and \t into their respective ascii codes. |
| */ |
| |
| static void HandleEscape (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, unsigned int *i, unsigned int *j, unsigned int HighSrc, unsigned int HighDest); |
| |
| /* |
| Cast - casts a := b |
| */ |
| |
| static void Cast (unsigned char *a, unsigned int _a_high, const unsigned char *b_, unsigned int _b_high); |
| |
| /* |
| StringFormat1 - converts string, src, into, dest, together with encapsulated |
| entity, w. It only formats the first %s or %d with n. |
| */ |
| |
| static void StringFormat1 (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, const unsigned char *w_, unsigned int _w_high); |
| |
| /* |
| FormatError - provides a orthoganal counterpart to the procedure below. |
| */ |
| |
| static void FormatError (const char *a_, unsigned int _a_high); |
| |
| /* |
| FormatError1 - generic error procedure taking standard format string |
| and single parameter. |
| */ |
| |
| static void FormatError1 (const char *a_, unsigned int _a_high, const unsigned char *w_, unsigned int _w_high); |
| |
| /* |
| FormatError2 - generic error procedure taking standard format string |
| and two parameters. |
| */ |
| |
| static void FormatError2 (const char *a_, unsigned int _a_high, const unsigned char *w1_, unsigned int _w1_high, const unsigned char *w2_, unsigned int _w2_high); |
| |
| /* |
| CheckAccess - checks to see whether a file f has been |
| opened for read/write. |
| */ |
| |
| static void CheckAccess (FIO_File f, FIO_FileUsage use, bool towrite); |
| |
| /* |
| SetEndOfLine - |
| */ |
| |
| static void SetEndOfLine (FIO_File f, char ch); |
| |
| /* |
| BufferedWrite - will write, nBytes, through the buffer. |
| Similar to WriteNBytes, but this function will always |
| write into the buffer before copying into memory. |
| |
| Useful when performing small writes. |
| */ |
| |
| static int BufferedWrite (FIO_File f, unsigned int nBytes, void * src); |
| |
| /* |
| PreInitialize - preinitialize the file descriptor. |
| */ |
| |
| static void PreInitialize (FIO_File f, const char *fname_, unsigned int _fname_high, FIO_FileStatus state, FIO_FileUsage use, bool towrite, int osfd, unsigned int bufsize); |
| |
| /* |
| Init - initialize the modules, global variables. |
| */ |
| |
| static void Init (void); |
| |
| |
| /* |
| Max - returns the maximum of two values. |
| */ |
| |
| static unsigned int Max (unsigned int a, unsigned int b) |
| { |
| if (a > b) |
| { |
| return a; |
| } |
| else |
| { |
| return b; |
| } |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| Min - returns the minimum of two values. |
| */ |
| |
| static unsigned int Min (unsigned int a, unsigned int b) |
| { |
| if (a < b) |
| { |
| return a; |
| } |
| else |
| { |
| return b; |
| } |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| GetNextFreeDescriptor - returns the index to the FileInfo array indicating |
| the next free slot. |
| */ |
| |
| static FIO_File GetNextFreeDescriptor (void) |
| { |
| FIO_File f; |
| FIO_File h; |
| FIO_FileDescriptor fd; |
| |
| f = Error+1; |
| h = Indexing_HighIndice (FileInfo); |
| for (;;) |
| { |
| if (f <= h) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd == NULL) |
| { |
| return f; |
| } |
| } |
| f += 1; |
| if (f > h) |
| { |
| Indexing_PutIndice (FileInfo, f, NULL); /* create new slot */ |
| return f; /* create new slot */ |
| } |
| } |
| ReturnException ("../../gcc/m2/gm2-libs/FIO.def", 25, 1); |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| SetState - sets the field, state, of file, f, to, s. |
| */ |
| |
| static void SetState (FIO_File f, FIO_FileStatus s) |
| { |
| FIO_FileDescriptor fd; |
| |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| fd->state = s; |
| } |
| |
| |
| /* |
| InitializeFile - initialize a file descriptor |
| */ |
| |
| static FIO_File InitializeFile (FIO_File f, void * fname, unsigned int flength, FIO_FileStatus fstate, FIO_FileUsage use, bool towrite, unsigned int buflength) |
| { |
| FIO_PtrToChar p; |
| FIO_FileDescriptor fd; |
| |
| Storage_ALLOCATE ((void **) &fd, sizeof (FIO_fds)); |
| if (fd == NULL) |
| { |
| SetState (Error, FIO_outofmemory); |
| return Error; |
| } |
| else |
| { |
| Indexing_PutIndice (FileInfo, f, reinterpret_cast<void *> (fd)); |
| fd->name.size = flength+1; /* need to guarantee the nul for C */ |
| fd->usage = use; /* need to guarantee the nul for C */ |
| fd->output = towrite; |
| Storage_ALLOCATE (&fd->name.address, fd->name.size); |
| if (fd->name.address == NULL) |
| { |
| fd->state = FIO_outofmemory; |
| return f; |
| } |
| fd->name.address = libc_strncpy (fd->name.address, fname, flength); |
| /* and assign nul to the last byte */ |
| p = static_cast<FIO_PtrToChar> (fd->name.address); |
| p += flength; |
| (*p) = ASCII_nul; |
| fd->abspos = 0; |
| /* now for the buffer */ |
| Storage_ALLOCATE ((void **) &fd->buffer, sizeof (FIO_buf)); |
| if (fd->buffer == NULL) |
| { |
| SetState (Error, FIO_outofmemory); |
| return Error; |
| } |
| else |
| { |
| fd->buffer->valid = false; |
| fd->buffer->bufstart = 0; |
| fd->buffer->size = buflength; |
| fd->buffer->position = 0; |
| fd->buffer->filled = 0; |
| if (fd->buffer->size == 0) |
| { |
| fd->buffer->address = NULL; |
| } |
| else |
| { |
| Storage_ALLOCATE (&fd->buffer->address, fd->buffer->size); |
| if (fd->buffer->address == NULL) |
| { |
| fd->state = FIO_outofmemory; |
| return f; |
| } |
| } |
| if (towrite) |
| { |
| fd->buffer->left = fd->buffer->size; |
| } |
| else |
| { |
| fd->buffer->left = 0; |
| } |
| fd->buffer->contents = static_cast<FIO__T7 *> (fd->buffer->address); /* provides easy access for reading characters */ |
| fd->state = fstate; /* provides easy access for reading characters */ |
| } |
| } |
| return f; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| ConnectToUnix - connects a FIO file to a UNIX file descriptor. |
| */ |
| |
| static void ConnectToUnix (FIO_File f, bool towrite, bool newfile) |
| { |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| if (towrite) |
| { |
| if (newfile) |
| { |
| fd->unixfd = libc_creat (fd->name.address, CreatePermissions); |
| } |
| else |
| { |
| fd->unixfd = libc_open (fd->name.address, (int ) (wrapc_WriteOnly ()), 0); |
| } |
| } |
| else |
| { |
| fd->unixfd = libc_open (fd->name.address, (int ) (wrapc_ReadOnly ()), 0); |
| } |
| if (fd->unixfd < 0) |
| { |
| fd->state = FIO_connectionfailure; |
| } |
| } |
| } |
| } |
| |
| |
| /* |
| ReadFromBuffer - attempts to read, nBytes, from file, f. |
| It firstly consumes the buffer and then performs |
| direct unbuffered reads. This should only be used |
| when wishing to read large files. |
| |
| The actual number of bytes read is returned. |
| -1 is returned if EOF is reached. |
| */ |
| |
| static int ReadFromBuffer (FIO_File f, void * a, unsigned int nBytes) |
| { |
| typedef unsigned char *ReadFromBuffer__T1; |
| |
| void * t; |
| int result; |
| unsigned int total; |
| unsigned int n; |
| ReadFromBuffer__T1 p; |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| total = 0; /* how many bytes have we read */ |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); /* how many bytes have we read */ |
| /* extract from the buffer first */ |
| if ((fd->buffer != NULL) && fd->buffer->valid) |
| { |
| if (fd->buffer->left > 0) |
| { |
| /* avoid gcc warning by using compound statement even if not strictly necessary. */ |
| if (nBytes == 1) |
| { |
| /* too expensive to call memcpy for 1 character */ |
| p = static_cast<ReadFromBuffer__T1> (a); |
| (*p) = static_cast<unsigned char> ((*fd->buffer->contents).array[fd->buffer->position]); |
| fd->buffer->left -= 1; /* remove consumed bytes */ |
| fd->buffer->position += 1; /* move onwards n bytes */ |
| nBytes = 0; /* reduce the amount for future direct */ |
| /* read */ |
| return 1; |
| } |
| else |
| { |
| n = Min (fd->buffer->left, nBytes); |
| t = fd->buffer->address; |
| t = reinterpret_cast<void *> (reinterpret_cast<char *> (t)+fd->buffer->position); |
| p = static_cast<ReadFromBuffer__T1> (libc_memcpy (a, t, static_cast<size_t> (n))); |
| fd->buffer->left -= n; /* remove consumed bytes */ |
| fd->buffer->position += n; /* move onwards n bytes */ |
| /* move onwards ready for direct reads */ |
| a = reinterpret_cast<void *> (reinterpret_cast<char *> (a)+n); |
| nBytes -= n; /* reduce the amount for future direct */ |
| /* read */ |
| total += n; |
| return total; /* much cleaner to return now, */ |
| } |
| /* difficult to record an error if */ |
| } |
| /* the read below returns -1 */ |
| } |
| if (nBytes > 0) |
| { |
| /* still more to read */ |
| result = static_cast<int> (libc_read (fd->unixfd, a, static_cast<size_t> ((int ) (nBytes)))); |
| if (result > 0) |
| { |
| /* avoid dangling else. */ |
| total += result; |
| fd->abspos += result; |
| /* now disable the buffer as we read directly into, a. */ |
| if (fd->buffer != NULL) |
| { |
| fd->buffer->valid = false; |
| } |
| } |
| else |
| { |
| if (result == 0) |
| { |
| /* eof reached */ |
| fd->state = FIO_endoffile; |
| } |
| else |
| { |
| fd->state = FIO_failed; |
| } |
| /* indicate buffer is empty */ |
| if (fd->buffer != NULL) |
| { |
| fd->buffer->valid = false; |
| fd->buffer->left = 0; |
| fd->buffer->position = 0; |
| if (fd->buffer->address != NULL) |
| { |
| (*fd->buffer->contents).array[fd->buffer->position] = ASCII_nul; |
| } |
| } |
| return -1; |
| } |
| } |
| return total; |
| } |
| else |
| { |
| return -1; |
| } |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| BufferedRead - will read, nBytes, through the buffer. |
| Similar to ReadFromBuffer, but this function will always |
| read into the buffer before copying into memory. |
| |
| Useful when performing small reads. |
| */ |
| |
| static int BufferedRead (FIO_File f, unsigned int nBytes, void * dest) |
| { |
| typedef unsigned char *BufferedRead__T3; |
| |
| void * src; |
| int total; |
| int n; |
| BufferedRead__T3 p; |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| total = 0; /* how many bytes have we read */ |
| if (fd != NULL) /* how many bytes have we read */ |
| { |
| /* extract from the buffer first */ |
| if (fd->buffer != NULL) |
| { |
| while (nBytes > 0) |
| { |
| if ((fd->buffer->left > 0) && fd->buffer->valid) |
| { |
| if (nBytes == 1) |
| { |
| /* too expensive to call memcpy for 1 character */ |
| p = static_cast<BufferedRead__T3> (dest); |
| (*p) = static_cast<unsigned char> ((*fd->buffer->contents).array[fd->buffer->position]); |
| fd->buffer->left -= 1; /* remove consumed byte */ |
| fd->buffer->position += 1; /* move onwards n byte */ |
| total += 1; /* move onwards n byte */ |
| return total; |
| } |
| else |
| { |
| n = Min (fd->buffer->left, nBytes); |
| src = fd->buffer->address; |
| src = reinterpret_cast<void *> (reinterpret_cast<char *> (src)+fd->buffer->position); |
| p = static_cast<BufferedRead__T3> (libc_memcpy (dest, src, static_cast<size_t> (n))); |
| fd->buffer->left -= n; /* remove consumed bytes */ |
| fd->buffer->position += n; /* move onwards n bytes */ |
| /* move onwards ready for direct reads */ |
| dest = reinterpret_cast<void *> (reinterpret_cast<char *> (dest)+n); |
| nBytes -= n; /* reduce the amount for future direct */ |
| /* read */ |
| total += n; |
| } |
| } |
| else |
| { |
| /* refill buffer */ |
| n = static_cast<int> (libc_read (fd->unixfd, fd->buffer->address, static_cast<size_t> (fd->buffer->size))); |
| if (n >= 0) |
| { |
| /* avoid dangling else. */ |
| fd->buffer->valid = true; |
| fd->buffer->position = 0; |
| fd->buffer->left = n; |
| fd->buffer->filled = n; |
| fd->buffer->bufstart = fd->abspos; |
| fd->abspos += n; |
| if (n == 0) |
| { |
| /* eof reached */ |
| fd->state = FIO_endoffile; |
| return -1; |
| } |
| } |
| else |
| { |
| fd->buffer->valid = false; |
| fd->buffer->position = 0; |
| fd->buffer->left = 0; |
| fd->buffer->filled = 0; |
| fd->state = FIO_failed; |
| return total; |
| } |
| } |
| } |
| return total; |
| } |
| } |
| } |
| return -1; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| HandleEscape - translates |
| and \t into their respective ascii codes. |
| */ |
| |
| static void HandleEscape (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, unsigned int *i, unsigned int *j, unsigned int HighSrc, unsigned int HighDest) |
| { |
| char src[_src_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (src, src_, _src_high+1); |
| |
| if (((((*i)+1) < HighSrc) && (src[(*i)] == '\\')) && ((*j) < HighDest)) |
| { |
| /* avoid gcc warning by using compound statement even if not strictly necessary. */ |
| if (src[(*i)+1] == 'n') |
| { |
| /* requires a newline */ |
| const_cast<char *>(dest)[(*j)] = ASCII_nl; |
| (*j) += 1; |
| (*i) += 2; |
| } |
| else if (src[(*i)+1] == 't') |
| { |
| /* avoid dangling else. */ |
| /* requires a tab (yuck) tempted to fake this but I better not.. */ |
| const_cast<char *>(dest)[(*j)] = ASCII_tab; |
| (*j) += 1; |
| (*i) += 2; |
| } |
| else |
| { |
| /* avoid dangling else. */ |
| /* copy escaped character */ |
| (*i) += 1; |
| const_cast<char *>(dest)[(*j)] = src[(*i)]; |
| (*j) += 1; |
| (*i) += 1; |
| } |
| } |
| } |
| |
| |
| /* |
| Cast - casts a := b |
| */ |
| |
| static void Cast (unsigned char *a, unsigned int _a_high, const unsigned char *b_, unsigned int _b_high) |
| { |
| unsigned int i; |
| unsigned char b[_b_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (b, b_, _b_high+1); |
| |
| if (_a_high == _b_high) |
| { |
| for (i=0; i<=_a_high; i++) |
| { |
| const_cast<unsigned char *>(a)[i] = b[i]; |
| } |
| } |
| else |
| { |
| FormatError ((const char *) "cast failed", 11); |
| } |
| } |
| |
| |
| /* |
| StringFormat1 - converts string, src, into, dest, together with encapsulated |
| entity, w. It only formats the first %s or %d with n. |
| */ |
| |
| static void StringFormat1 (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, const unsigned char *w_, unsigned int _w_high) |
| { |
| typedef struct StringFormat1__T8_a StringFormat1__T8; |
| |
| typedef char *StringFormat1__T4; |
| |
| struct StringFormat1__T8_a { char array[MaxErrorString+1]; }; |
| unsigned int HighSrc; |
| unsigned int HighDest; |
| unsigned int c; |
| unsigned int i; |
| unsigned int j; |
| StringFormat1__T8 str; |
| StringFormat1__T4 p; |
| char src[_src_high+1]; |
| unsigned char w[_w_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (src, src_, _src_high+1); |
| memcpy (w, w_, _w_high+1); |
| |
| HighSrc = StrLib_StrLen ((const char *) src, _src_high); |
| HighDest = _dest_high; |
| p = NULL; |
| c = 0; |
| i = 0; |
| j = 0; |
| while ((((i < HighSrc) && (src[i] != ASCII_nul)) && (j < HighDest)) && (src[i] != '%')) |
| { |
| if (src[i] == '\\') |
| { |
| HandleEscape ((char *) dest, _dest_high, (const char *) src, _src_high, &i, &j, HighSrc, HighDest); |
| } |
| else |
| { |
| const_cast<char *>(dest)[j] = src[i]; |
| i += 1; |
| j += 1; |
| } |
| } |
| if ((((i+1) < HighSrc) && (src[i] == '%')) && (j < HighDest)) |
| { |
| /* avoid gcc warning by using compound statement even if not strictly necessary. */ |
| if (src[i+1] == 's') |
| { |
| Cast ((unsigned char *) &p, (sizeof (p)-1), (const unsigned char *) w, _w_high); |
| while ((j < HighDest) && ((*p) != ASCII_nul)) |
| { |
| const_cast<char *>(dest)[j] = (*p); |
| j += 1; |
| p += 1; |
| } |
| if (j < HighDest) |
| { |
| const_cast<char *>(dest)[j] = ASCII_nul; |
| } |
| j = StrLib_StrLen ((const char *) dest, _dest_high); |
| i += 2; |
| } |
| else if (src[i+1] == 'd') |
| { |
| /* avoid dangling else. */ |
| const_cast<char *>(dest)[j] = ASCII_nul; |
| Cast ((unsigned char *) &c, (sizeof (c)-1), (const unsigned char *) w, _w_high); |
| NumberIO_CardToStr (c, 0, (char *) &str.array[0], MaxErrorString); |
| StrLib_StrConCat ((const char *) dest, _dest_high, (const char *) &str.array[0], MaxErrorString, (char *) dest, _dest_high); |
| j = StrLib_StrLen ((const char *) dest, _dest_high); |
| i += 2; |
| } |
| else |
| { |
| /* avoid dangling else. */ |
| const_cast<char *>(dest)[j] = src[i]; |
| i += 1; |
| j += 1; |
| } |
| } |
| /* and finish off copying src into dest */ |
| while (((i < HighSrc) && (src[i] != ASCII_nul)) && (j < HighDest)) |
| { |
| if (src[i] == '\\') |
| { |
| HandleEscape ((char *) dest, _dest_high, (const char *) src, _src_high, &i, &j, HighSrc, HighDest); |
| } |
| else |
| { |
| const_cast<char *>(dest)[j] = src[i]; |
| i += 1; |
| j += 1; |
| } |
| } |
| if (j < HighDest) |
| { |
| const_cast<char *>(dest)[j] = ASCII_nul; |
| } |
| } |
| |
| |
| /* |
| FormatError - provides a orthoganal counterpart to the procedure below. |
| */ |
| |
| static void FormatError (const char *a_, unsigned int _a_high) |
| { |
| char a[_a_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (a, a_, _a_high+1); |
| |
| FIO_WriteString (FIO_StdErr, (const char *) a, _a_high); |
| } |
| |
| |
| /* |
| FormatError1 - generic error procedure taking standard format string |
| and single parameter. |
| */ |
| |
| static void FormatError1 (const char *a_, unsigned int _a_high, const unsigned char *w_, unsigned int _w_high) |
| { |
| typedef struct FormatError1__T9_a FormatError1__T9; |
| |
| struct FormatError1__T9_a { char array[MaxErrorString+1]; }; |
| FormatError1__T9 s; |
| char a[_a_high+1]; |
| unsigned char w[_w_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (a, a_, _a_high+1); |
| memcpy (w, w_, _w_high+1); |
| |
| StringFormat1 ((char *) &s.array[0], MaxErrorString, (const char *) a, _a_high, (const unsigned char *) w, _w_high); |
| FormatError ((const char *) &s.array[0], MaxErrorString); |
| } |
| |
| |
| /* |
| FormatError2 - generic error procedure taking standard format string |
| and two parameters. |
| */ |
| |
| static void FormatError2 (const char *a_, unsigned int _a_high, const unsigned char *w1_, unsigned int _w1_high, const unsigned char *w2_, unsigned int _w2_high) |
| { |
| typedef struct FormatError2__T10_a FormatError2__T10; |
| |
| struct FormatError2__T10_a { char array[MaxErrorString+1]; }; |
| FormatError2__T10 s; |
| char a[_a_high+1]; |
| unsigned char w1[_w1_high+1]; |
| unsigned char w2[_w2_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (a, a_, _a_high+1); |
| memcpy (w1, w1_, _w1_high+1); |
| memcpy (w2, w2_, _w2_high+1); |
| |
| StringFormat1 ((char *) &s.array[0], MaxErrorString, (const char *) a, _a_high, (const unsigned char *) w1, _w1_high); |
| FormatError1 ((const char *) &s.array[0], MaxErrorString, (const unsigned char *) w2, _w2_high); |
| } |
| |
| |
| /* |
| CheckAccess - checks to see whether a file f has been |
| opened for read/write. |
| */ |
| |
| static void CheckAccess (FIO_File f, FIO_FileUsage use, bool towrite) |
| { |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| /* avoid dangling else. */ |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd == NULL) |
| { |
| if (f != FIO_StdErr) |
| { |
| FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96); |
| } |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| else |
| { |
| if ((use == FIO_openedforwrite) && (fd->usage == FIO_openedforread)) |
| { |
| FormatError1 ((const char *) "this file (%s) has been opened for reading but is now being written\\n", 69, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| else if ((use == FIO_openedforread) && (fd->usage == FIO_openedforwrite)) |
| { |
| /* avoid dangling else. */ |
| FormatError1 ((const char *) "this file (%s) has been opened for writing but is now being read\\n", 66, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| else if (fd->state == FIO_connectionfailure) |
| { |
| /* avoid dangling else. */ |
| FormatError1 ((const char *) "this file (%s) was not successfully opened\\n", 44, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| else if (towrite != fd->output) |
| { |
| /* avoid dangling else. */ |
| if (fd->output) |
| { |
| FormatError1 ((const char *) "this file (%s) was opened for writing but is now being read\\n", 61, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| else |
| { |
| FormatError1 ((const char *) "this file (%s) was opened for reading but is now being written\\n", 64, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| } |
| } |
| } |
| else |
| { |
| FormatError ((const char *) "this file has not been opened successfully\\n", 44); |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| } |
| |
| |
| /* |
| SetEndOfLine - |
| */ |
| |
| static void SetEndOfLine (FIO_File f, char ch) |
| { |
| FIO_FileDescriptor fd; |
| |
| CheckAccess (f, FIO_openedforread, false); |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (ch == ASCII_nl) |
| { |
| fd->state = FIO_endofline; |
| } |
| else |
| { |
| fd->state = FIO_successful; |
| } |
| } |
| } |
| |
| |
| /* |
| BufferedWrite - will write, nBytes, through the buffer. |
| Similar to WriteNBytes, but this function will always |
| write into the buffer before copying into memory. |
| |
| Useful when performing small writes. |
| */ |
| |
| static int BufferedWrite (FIO_File f, unsigned int nBytes, void * src) |
| { |
| typedef unsigned char *BufferedWrite__T5; |
| |
| void * dest; |
| int total; |
| int n; |
| BufferedWrite__T5 p; |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| total = 0; /* how many bytes have we read */ |
| if (fd->buffer != NULL) /* how many bytes have we read */ |
| { |
| /* place into the buffer first */ |
| while (nBytes > 0) |
| { |
| if (fd->buffer->left > 0) |
| { |
| if (nBytes == 1) |
| { |
| /* too expensive to call memcpy for 1 character */ |
| p = static_cast<BufferedWrite__T5> (src); |
| (*fd->buffer->contents).array[fd->buffer->position] = static_cast<char> ((*p)); |
| fd->buffer->left -= 1; /* reduce space */ |
| fd->buffer->position += 1; /* move onwards n byte */ |
| total += 1; /* move onwards n byte */ |
| return total; |
| } |
| else |
| { |
| n = Min (fd->buffer->left, nBytes); |
| dest = fd->buffer->address; |
| dest = reinterpret_cast<void *> (reinterpret_cast<char *> (dest)+fd->buffer->position); |
| p = static_cast<BufferedWrite__T5> (libc_memcpy (dest, src, static_cast<size_t> ((unsigned int ) (n)))); |
| fd->buffer->left -= n; /* remove consumed bytes */ |
| fd->buffer->position += n; /* move onwards n bytes */ |
| /* move ready for further writes */ |
| src = reinterpret_cast<void *> (reinterpret_cast<char *> (src)+n); |
| nBytes -= n; /* reduce the amount for future writes */ |
| total += n; /* reduce the amount for future writes */ |
| } |
| } |
| else |
| { |
| FIO_FlushBuffer (f); |
| if ((fd->state != FIO_successful) && (fd->state != FIO_endofline)) |
| { |
| nBytes = 0; |
| } |
| } |
| } |
| return total; |
| } |
| } |
| } |
| return -1; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| PreInitialize - preinitialize the file descriptor. |
| */ |
| |
| static void PreInitialize (FIO_File f, const char *fname_, unsigned int _fname_high, FIO_FileStatus state, FIO_FileUsage use, bool towrite, int osfd, unsigned int bufsize) |
| { |
| FIO_FileDescriptor fd; |
| FIO_FileDescriptor fe; |
| char fname[_fname_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (fname, fname_, _fname_high+1); |
| |
| if ((InitializeFile (f, const_cast<void*> (static_cast<const void*>(fname)), StrLib_StrLen ((const char *) fname, _fname_high), state, use, towrite, bufsize)) == f) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (f == Error) |
| { |
| fe = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, FIO_StdErr)); |
| if (fe == NULL) |
| { |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| else |
| { |
| fd->unixfd = fe->unixfd; /* the error channel */ |
| } |
| } |
| else |
| { |
| fd->unixfd = osfd; |
| } |
| } |
| else |
| { |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| } |
| |
| |
| /* |
| Init - initialize the modules, global variables. |
| */ |
| |
| static void Init (void) |
| { |
| FileInfo = Indexing_InitIndex (0); |
| Error = 0; |
| PreInitialize (Error, (const char *) "error", 5, FIO_toomanyfilesopen, FIO_unused, false, -1, 0); |
| FIO_StdIn = 1; |
| PreInitialize (FIO_StdIn, (const char *) "<stdin>", 7, FIO_successful, FIO_openedforread, false, 0, MaxBufferLength); |
| FIO_StdOut = 2; |
| PreInitialize (FIO_StdOut, (const char *) "<stdout>", 8, FIO_successful, FIO_openedforwrite, true, 1, MaxBufferLength); |
| FIO_StdErr = 3; |
| PreInitialize (FIO_StdErr, (const char *) "<stderr>", 8, FIO_successful, FIO_openedforwrite, true, 2, MaxBufferLength); |
| if (! (M2RTS_InstallTerminationProcedure ((PROC ) {(PROC_t) FIO_FlushOutErr}))) |
| { |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| } |
| |
| |
| /* |
| IsNoError - returns a TRUE if no error has occured on file, f. |
| */ |
| |
| extern "C" bool FIO_IsNoError (FIO_File f) |
| { |
| FIO_FileDescriptor fd; |
| |
| if (f == Error) |
| { |
| return false; |
| } |
| else |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| return (fd != NULL) && (((fd->state == FIO_successful) || (fd->state == FIO_endoffile)) || (fd->state == FIO_endofline)); |
| } |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| IsActive - returns TRUE if the file, f, is still active. |
| */ |
| |
| extern "C" bool FIO_IsActive (FIO_File f) |
| { |
| if (f == Error) |
| { |
| return false; |
| } |
| else |
| { |
| return (Indexing_GetIndice (FileInfo, f)) != NULL; |
| } |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| extern "C" bool FIO_Exists (const char *fname_, unsigned int _fname_high) |
| { |
| char fname[_fname_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (fname, fname_, _fname_high+1); |
| |
| /* |
| The following functions are wrappers for the above. |
| */ |
| return FIO_exists (const_cast<void*> (static_cast<const void*>(fname)), StrLib_StrLen ((const char *) fname, _fname_high)); |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| extern "C" FIO_File FIO_OpenToRead (const char *fname_, unsigned int _fname_high) |
| { |
| char fname[_fname_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (fname, fname_, _fname_high+1); |
| |
| return FIO_openToRead (const_cast<void*> (static_cast<const void*>(fname)), StrLib_StrLen ((const char *) fname, _fname_high)); |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| extern "C" FIO_File FIO_OpenToWrite (const char *fname_, unsigned int _fname_high) |
| { |
| char fname[_fname_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (fname, fname_, _fname_high+1); |
| |
| return FIO_openToWrite (const_cast<void*> (static_cast<const void*>(fname)), StrLib_StrLen ((const char *) fname, _fname_high)); |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| extern "C" FIO_File FIO_OpenForRandom (const char *fname_, unsigned int _fname_high, bool towrite, bool newfile) |
| { |
| char fname[_fname_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (fname, fname_, _fname_high+1); |
| |
| return FIO_openForRandom (const_cast<void*> (static_cast<const void*>(fname)), StrLib_StrLen ((const char *) fname, _fname_high), towrite, newfile); |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| Close - close a file which has been previously opened using: |
| OpenToRead, OpenToWrite, OpenForRandom. |
| It is correct to close a file which has an error status. |
| */ |
| |
| extern "C" void FIO_Close (FIO_File f) |
| { |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| /* |
| we allow users to close files which have an error status |
| */ |
| if (fd != NULL) |
| { |
| FIO_FlushBuffer (f); |
| if (fd->unixfd >= 0) |
| { |
| if ((libc_close (fd->unixfd)) != 0) |
| { |
| FormatError1 ((const char *) "failed to close file (%s)\\n", 27, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); |
| fd->state = FIO_failed; /* --fixme-- too late to notify user (unless we return a BOOLEAN) */ |
| } |
| } |
| if (fd->name.address != NULL) |
| { |
| Storage_DEALLOCATE (&fd->name.address, fd->name.size); |
| } |
| if (fd->buffer != NULL) |
| { |
| if (fd->buffer->address != NULL) |
| { |
| Storage_DEALLOCATE (&fd->buffer->address, fd->buffer->size); |
| } |
| Storage_DEALLOCATE ((void **) &fd->buffer, sizeof (FIO_buf)); |
| fd->buffer = NULL; |
| } |
| Storage_DEALLOCATE ((void **) &fd, sizeof (FIO_fds)); |
| Indexing_PutIndice (FileInfo, f, NULL); |
| } |
| } |
| } |
| |
| |
| /* |
| exists - returns TRUE if a file named, fname exists for reading. |
| */ |
| |
| extern "C" bool FIO_exists (void * fname, unsigned int flength) |
| { |
| FIO_File f; |
| |
| f = FIO_openToRead (fname, flength); |
| if (FIO_IsNoError (f)) |
| { |
| FIO_Close (f); |
| return true; |
| } |
| else |
| { |
| FIO_Close (f); |
| return false; |
| } |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| openToRead - attempts to open a file, fname, for reading and |
| it returns this file. |
| The success of this operation can be checked by |
| calling IsNoError. |
| */ |
| |
| extern "C" FIO_File FIO_openToRead (void * fname, unsigned int flength) |
| { |
| FIO_File f; |
| |
| f = GetNextFreeDescriptor (); |
| if (f == Error) |
| { |
| SetState (f, FIO_toomanyfilesopen); |
| } |
| else |
| { |
| f = InitializeFile (f, fname, flength, FIO_successful, FIO_openedforread, false, MaxBufferLength); |
| ConnectToUnix (f, false, false); |
| } |
| return f; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| openToWrite - attempts to open a file, fname, for write and |
| it returns this file. |
| The success of this operation can be checked by |
| calling IsNoError. |
| */ |
| |
| extern "C" FIO_File FIO_openToWrite (void * fname, unsigned int flength) |
| { |
| FIO_File f; |
| |
| f = GetNextFreeDescriptor (); |
| if (f == Error) |
| { |
| SetState (f, FIO_toomanyfilesopen); |
| } |
| else |
| { |
| f = InitializeFile (f, fname, flength, FIO_successful, FIO_openedforwrite, true, MaxBufferLength); |
| ConnectToUnix (f, true, true); |
| } |
| return f; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| openForRandom - attempts to open a file, fname, for random access |
| read or write and it returns this file. |
| The success of this operation can be checked by |
| calling IsNoError. |
| towrite, determines whether the file should be |
| opened for writing or reading. |
| */ |
| |
| extern "C" FIO_File FIO_openForRandom (void * fname, unsigned int flength, bool towrite, bool newfile) |
| { |
| FIO_File f; |
| |
| f = GetNextFreeDescriptor (); |
| if (f == Error) |
| { |
| SetState (f, FIO_toomanyfilesopen); |
| } |
| else |
| { |
| f = InitializeFile (f, fname, flength, FIO_successful, FIO_openedforrandom, towrite, MaxBufferLength); |
| ConnectToUnix (f, towrite, newfile); |
| } |
| return f; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| FlushBuffer - flush contents of file, f. |
| */ |
| |
| extern "C" void FIO_FlushBuffer (FIO_File f) |
| { |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| if (fd->output && (fd->buffer != NULL)) |
| { |
| if ((fd->buffer->position == 0) || ((libc_write (fd->unixfd, fd->buffer->address, static_cast<size_t> (fd->buffer->position))) == ((int ) (fd->buffer->position)))) |
| { |
| fd->abspos += fd->buffer->position; |
| fd->buffer->bufstart = fd->abspos; |
| fd->buffer->position = 0; |
| fd->buffer->filled = 0; |
| fd->buffer->left = fd->buffer->size; |
| } |
| else |
| { |
| fd->state = FIO_failed; |
| } |
| } |
| } |
| } |
| } |
| |
| |
| /* |
| ReadNBytes - reads nBytes of a file into memory area, dest, returning |
| the number of bytes actually read. |
| This function will consume from the buffer and then |
| perform direct libc reads. It is ideal for large reads. |
| */ |
| |
| extern "C" unsigned int FIO_ReadNBytes (FIO_File f, unsigned int nBytes, void * dest) |
| { |
| typedef char *ReadNBytes__T2; |
| |
| int n; |
| ReadNBytes__T2 p; |
| |
| if (f != Error) |
| { |
| CheckAccess (f, FIO_openedforread, false); |
| n = ReadFromBuffer (f, dest, nBytes); |
| if (n <= 0) |
| { |
| return 0; |
| } |
| else |
| { |
| p = static_cast<ReadNBytes__T2> (dest); |
| p += n-1; |
| SetEndOfLine (f, (*p)); |
| return n; |
| } |
| } |
| else |
| { |
| return 0; |
| } |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| ReadAny - reads HIGH (a) + 1 bytes into, a. All input |
| is fully buffered, unlike ReadNBytes and thus is more |
| suited to small reads. |
| */ |
| |
| extern "C" void FIO_ReadAny (FIO_File f, unsigned char *a, unsigned int _a_high) |
| { |
| CheckAccess (f, FIO_openedforread, false); |
| if ((BufferedRead (f, _a_high+1, a)) == ((int ) (_a_high+1))) |
| { |
| SetEndOfLine (f, static_cast<char> (a[_a_high])); |
| } |
| } |
| |
| |
| /* |
| WriteNBytes - writes nBytes from memory area src to a file |
| returning the number of bytes actually written. |
| This function will flush the buffer and then |
| write the nBytes using a direct write from libc. |
| It is ideal for large writes. |
| */ |
| |
| extern "C" unsigned int FIO_WriteNBytes (FIO_File f, unsigned int nBytes, void * src) |
| { |
| int total; |
| FIO_FileDescriptor fd; |
| |
| CheckAccess (f, FIO_openedforwrite, true); |
| FIO_FlushBuffer (f); |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| total = static_cast<int> (libc_write (fd->unixfd, src, static_cast<size_t> ((int ) (nBytes)))); |
| if (total < 0) |
| { |
| fd->state = FIO_failed; |
| return 0; |
| } |
| else |
| { |
| fd->abspos += (unsigned int ) (total); |
| if (fd->buffer != NULL) |
| { |
| fd->buffer->bufstart = fd->abspos; |
| } |
| return (unsigned int ) (total); |
| } |
| } |
| } |
| return 0; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| WriteAny - writes HIGH (a) + 1 bytes onto, file, f. All output |
| is fully buffered, unlike WriteNBytes and thus is more |
| suited to small writes. |
| */ |
| |
| extern "C" void FIO_WriteAny (FIO_File f, unsigned char *a, unsigned int _a_high) |
| { |
| CheckAccess (f, FIO_openedforwrite, true); |
| if ((BufferedWrite (f, _a_high+1, a)) == ((int ) (_a_high+1))) |
| {} /* empty. */ |
| } |
| |
| |
| /* |
| WriteChar - writes a single character to file, f. |
| */ |
| |
| extern "C" void FIO_WriteChar (FIO_File f, char ch) |
| { |
| CheckAccess (f, FIO_openedforwrite, true); |
| if ((BufferedWrite (f, sizeof (ch), &ch)) == ((int ) (sizeof (ch)))) |
| {} /* empty. */ |
| } |
| |
| |
| /* |
| EOF - tests to see whether a file, f, has reached end of file. |
| */ |
| |
| extern "C" bool FIO_EOF (FIO_File f) |
| { |
| FIO_FileDescriptor fd; |
| |
| CheckAccess (f, FIO_openedforread, false); |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| return fd->state == FIO_endoffile; |
| } |
| } |
| return true; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| EOLN - tests to see whether a file, f, is upon a newline. |
| It does NOT consume the newline. |
| */ |
| |
| extern "C" bool FIO_EOLN (FIO_File f) |
| { |
| char ch; |
| FIO_FileDescriptor fd; |
| |
| CheckAccess (f, FIO_openedforread, false); |
| /* |
| we will read a character and then push it back onto the input stream, |
| having noted the file status, we also reset the status. |
| */ |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| if ((fd->state == FIO_successful) || (fd->state == FIO_endofline)) |
| { |
| ch = FIO_ReadChar (f); |
| if ((fd->state == FIO_successful) || (fd->state == FIO_endofline)) |
| { |
| FIO_UnReadChar (f, ch); |
| } |
| return ch == ASCII_nl; |
| } |
| } |
| } |
| return false; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| WasEOLN - tests to see whether a file, f, has just seen a newline. |
| */ |
| |
| extern "C" bool FIO_WasEOLN (FIO_File f) |
| { |
| FIO_FileDescriptor fd; |
| |
| CheckAccess (f, FIO_openedforread, false); |
| if (f == Error) |
| { |
| return false; |
| } |
| else |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| return (fd != NULL) && (fd->state == FIO_endofline); |
| } |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| ReadChar - returns a character read from file f. |
| Sensible to check with IsNoError or EOF after calling |
| this function. |
| */ |
| |
| extern "C" char FIO_ReadChar (FIO_File f) |
| { |
| char ch; |
| |
| CheckAccess (f, FIO_openedforread, false); |
| if ((BufferedRead (f, sizeof (ch), &ch)) == ((int ) (sizeof (ch)))) |
| { |
| SetEndOfLine (f, ch); |
| return ch; |
| } |
| else |
| { |
| return ASCII_nul; |
| } |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| UnReadChar - replaces a character, ch, back into file f. |
| This character must have been read by ReadChar |
| and it does not allow successive calls. It may |
| only be called if the previous read was successful |
| or end of file was seen. |
| If the state was previously endoffile then it |
| is altered to successful. |
| Otherwise it is left alone. |
| */ |
| |
| extern "C" void FIO_UnReadChar (FIO_File f, char ch) |
| { |
| FIO_FileDescriptor fd; |
| unsigned int n; |
| void * a; |
| void * b; |
| |
| CheckAccess (f, FIO_openedforread, false); |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (((fd->state == FIO_successful) || (fd->state == FIO_endoffile)) || (fd->state == FIO_endofline)) |
| { |
| /* avoid dangling else. */ |
| if ((fd->buffer != NULL) && fd->buffer->valid) |
| { |
| /* we assume that a ReadChar has occurred, we will check just in case. */ |
| if (fd->state == FIO_endoffile) |
| { |
| fd->buffer->position = MaxBufferLength; |
| fd->buffer->left = 0; |
| fd->buffer->filled = 0; |
| fd->state = FIO_successful; |
| } |
| if (fd->buffer->position > 0) |
| { |
| fd->buffer->position -= 1; |
| fd->buffer->left += 1; |
| (*fd->buffer->contents).array[fd->buffer->position] = ch; |
| } |
| else |
| { |
| /* if possible make room and store ch */ |
| if (fd->buffer->filled == fd->buffer->size) |
| { |
| FormatError1 ((const char *) "performing too many UnReadChar calls on file (%d)\\n", 51, (const unsigned char *) &f, (sizeof (f)-1)); |
| } |
| else |
| { |
| n = fd->buffer->filled-fd->buffer->position; |
| b = &(*fd->buffer->contents).array[fd->buffer->position]; |
| a = &(*fd->buffer->contents).array[fd->buffer->position+1]; |
| a = libc_memcpy (a, b, static_cast<size_t> (n)); |
| fd->buffer->filled += 1; |
| (*fd->buffer->contents).array[fd->buffer->position] = ch; |
| } |
| } |
| } |
| } |
| else |
| { |
| FormatError1 ((const char *) "UnReadChar can only be called if the previous read was successful or end of file, error on file (%d)\\n", 102, (const unsigned char *) &f, (sizeof (f)-1)); |
| } |
| } |
| } |
| |
| |
| /* |
| WriteLine - writes out a linefeed to file, f. |
| */ |
| |
| extern "C" void FIO_WriteLine (FIO_File f) |
| { |
| FIO_WriteChar (f, ASCII_nl); |
| } |
| |
| |
| /* |
| WriteString - writes a string to file, f. |
| */ |
| |
| extern "C" void FIO_WriteString (FIO_File f, const char *a_, unsigned int _a_high) |
| { |
| unsigned int l; |
| char a[_a_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (a, a_, _a_high+1); |
| |
| l = StrLib_StrLen ((const char *) a, _a_high); |
| if ((FIO_WriteNBytes (f, l, const_cast<void*> (static_cast<const void*>(a)))) != l) |
| {} /* empty. */ |
| } |
| |
| |
| /* |
| ReadString - reads a string from file, f, into string, a. |
| It terminates the string if HIGH is reached or |
| if a newline is seen or an error occurs. |
| */ |
| |
| extern "C" void FIO_ReadString (FIO_File f, char *a, unsigned int _a_high) |
| { |
| unsigned int high; |
| unsigned int i; |
| char ch; |
| |
| CheckAccess (f, FIO_openedforread, false); |
| high = _a_high; |
| i = 0; |
| do { |
| ch = FIO_ReadChar (f); |
| if (i <= high) |
| { |
| /* avoid gcc warning by using compound statement even if not strictly necessary. */ |
| if (((ch == ASCII_nl) || (! (FIO_IsNoError (f)))) || (FIO_EOF (f))) |
| { |
| const_cast<char *>(a)[i] = ASCII_nul; |
| i += 1; |
| } |
| else |
| { |
| const_cast<char *>(a)[i] = ch; |
| i += 1; |
| } |
| } |
| } while (! ((((ch == ASCII_nl) || (i > high)) || (! (FIO_IsNoError (f)))) || (FIO_EOF (f)))); |
| } |
| |
| |
| /* |
| WriteCardinal - writes a CARDINAL to file, f. |
| It writes the binary image of the cardinal |
| to file, f. |
| */ |
| |
| extern "C" void FIO_WriteCardinal (FIO_File f, unsigned int c) |
| { |
| FIO_WriteAny (f, (unsigned char *) &c, (sizeof (c)-1)); |
| } |
| |
| |
| /* |
| ReadCardinal - reads a CARDINAL from file, f. |
| It reads a binary image of a CARDINAL |
| from a file, f. |
| */ |
| |
| extern "C" unsigned int FIO_ReadCardinal (FIO_File f) |
| { |
| unsigned int c; |
| |
| FIO_ReadAny (f, (unsigned char *) &c, (sizeof (c)-1)); |
| return c; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| GetUnixFileDescriptor - returns the UNIX file descriptor of a file. |
| */ |
| |
| extern "C" int FIO_GetUnixFileDescriptor (FIO_File f) |
| { |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| return fd->unixfd; |
| } |
| } |
| FormatError1 ((const char *) "file %d has not been opened or is out of range\\n", 48, (const unsigned char *) &f, (sizeof (f)-1)); |
| return -1; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| SetPositionFromBeginning - sets the position from the beginning of the file. |
| */ |
| |
| extern "C" void FIO_SetPositionFromBeginning (FIO_File f, long int pos) |
| { |
| long int offset; |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| /* always force the lseek, until we are confident that abspos is always correct, |
| basically it needs some hard testing before we should remove the OR TRUE. */ |
| if ((fd->abspos != pos) || true) |
| { |
| FIO_FlushBuffer (f); |
| if (fd->buffer != NULL) |
| { |
| if (fd->output) |
| { |
| fd->buffer->left = fd->buffer->size; |
| } |
| else |
| { |
| fd->buffer->left = 0; |
| } |
| fd->buffer->position = 0; |
| fd->buffer->filled = 0; |
| } |
| offset = static_cast<long int> (libc_lseek (fd->unixfd, (off_t ) (pos), wrapc_SeekSet ())); |
| if ((offset >= 0) && (pos == offset)) |
| { |
| fd->abspos = pos; |
| } |
| else |
| { |
| fd->state = FIO_failed; |
| fd->abspos = 0; |
| } |
| if (fd->buffer != NULL) |
| { |
| fd->buffer->valid = false; |
| fd->buffer->bufstart = fd->abspos; |
| } |
| } |
| } |
| } |
| } |
| |
| |
| /* |
| SetPositionFromEnd - sets the position from the end of the file. |
| */ |
| |
| extern "C" void FIO_SetPositionFromEnd (FIO_File f, long int pos) |
| { |
| long int offset; |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| FIO_FlushBuffer (f); |
| if (fd->buffer != NULL) |
| { |
| if (fd->output) |
| { |
| fd->buffer->left = fd->buffer->size; |
| } |
| else |
| { |
| fd->buffer->left = 0; |
| } |
| fd->buffer->position = 0; |
| fd->buffer->filled = 0; |
| } |
| offset = static_cast<long int> (libc_lseek (fd->unixfd, (off_t ) (pos), wrapc_SeekEnd ())); |
| if (offset >= 0) |
| { |
| fd->abspos = offset; |
| } |
| else |
| { |
| fd->state = FIO_failed; |
| fd->abspos = 0; |
| offset = 0; |
| } |
| if (fd->buffer != NULL) |
| { |
| fd->buffer->valid = false; |
| fd->buffer->bufstart = offset; |
| } |
| } |
| } |
| } |
| |
| |
| /* |
| FindPosition - returns the current absolute position in file, f. |
| */ |
| |
| extern "C" long int FIO_FindPosition (FIO_File f) |
| { |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd != NULL) |
| { |
| if ((fd->buffer == NULL) || ! fd->buffer->valid) |
| { |
| return fd->abspos; |
| } |
| else |
| { |
| return fd->buffer->bufstart+((long int ) (fd->buffer->position)); |
| } |
| } |
| } |
| return 0; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| GetFileName - assigns, a, with the filename associated with, f. |
| */ |
| |
| extern "C" void FIO_GetFileName (FIO_File f, char *a, unsigned int _a_high) |
| { |
| typedef char *GetFileName__T6; |
| |
| unsigned int i; |
| GetFileName__T6 p; |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd == NULL) |
| { |
| FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96); |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| else |
| { |
| if (fd->name.address == NULL) |
| { |
| StrLib_StrCopy ((const char *) "", 0, (char *) a, _a_high); |
| } |
| else |
| { |
| p = static_cast<GetFileName__T6> (fd->name.address); |
| i = 0; |
| while (((*p) != ASCII_nul) && (i <= _a_high)) |
| { |
| const_cast<char *>(a)[i] = (*p); |
| p += 1; |
| i += 1; |
| } |
| } |
| } |
| } |
| } |
| |
| |
| /* |
| getFileName - returns the address of the filename associated with, f. |
| */ |
| |
| extern "C" void * FIO_getFileName (FIO_File f) |
| { |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd == NULL) |
| { |
| FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96); |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| else |
| { |
| return fd->name.address; |
| } |
| } |
| return NULL; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| getFileNameLength - returns the number of characters associated with filename, f. |
| */ |
| |
| extern "C" unsigned int FIO_getFileNameLength (FIO_File f) |
| { |
| FIO_FileDescriptor fd; |
| |
| if (f != Error) |
| { |
| fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); |
| if (fd == NULL) |
| { |
| FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96); |
| M2RTS_HALT (-1); |
| __builtin_unreachable (); |
| } |
| else |
| { |
| return fd->name.size; |
| } |
| } |
| return 0; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| FlushOutErr - flushes, StdOut, and, StdErr. |
| It is also called when the application calls M2RTS.Terminate. |
| (which is automatically placed in program modules by the GM2 |
| scaffold). |
| */ |
| |
| extern "C" void FIO_FlushOutErr (void) |
| { |
| if (FIO_IsNoError (FIO_StdOut)) |
| { |
| FIO_FlushBuffer (FIO_StdOut); |
| } |
| if (FIO_IsNoError (FIO_StdErr)) |
| { |
| FIO_FlushBuffer (FIO_StdErr); |
| } |
| } |
| |
| extern "C" void _M2_FIO_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[]) |
| { |
| Init (); |
| } |
| |
| extern "C" void _M2_FIO_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[]) |
| { |
| FIO_FlushOutErr (); |
| } |