mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Use commit 0e1e780fd6f18ce93119061e36a4fca9711bc020 Excluded multibuild folder, as this caused git issues
856 lines
24 KiB
C
856 lines
24 KiB
C
/*
|
|
Copyright (C) 2011 Equinor ASA, Norway.
|
|
|
|
The file 'fortio.c' is part of ERT - Ensemble based Reservoir Tool.
|
|
|
|
ERT 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 of the License, or
|
|
(at your option) any later version.
|
|
|
|
ERT 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 at <http://www.gnu.org/licenses/gpl.html>
|
|
for more details.
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <ert/util/util.h>
|
|
#include <ert/util/type_macros.h>
|
|
#include <ert/ecl/fortio.h>
|
|
|
|
#include <ecl/fortio.h>
|
|
|
|
#define FORTIO_ID 345116
|
|
|
|
/**
|
|
The fortio struct is implemented to handle fortran io. The problem is
|
|
that when a Fortran program writes unformatted data to file in a
|
|
statemente like:
|
|
|
|
integer array(100)
|
|
write(unit) array
|
|
|
|
it actually writes a head and tail in addition to the actual
|
|
data. The header and tail is a 4 byte integer, which value is the
|
|
number of bytes in the immediately following record. I.e. what is
|
|
actually found on disk after the Fortran code above is:
|
|
|
|
| 400 | array ...... | 400 |
|
|
|
|
Where the "400" head and tail is the number of bytes in the following
|
|
record. Fortran IO handles this transparently, but when mixing with
|
|
other programming languages care must be taken. This file implements
|
|
functionality to read and write these fortran generated files
|
|
transparently. The three functions:
|
|
|
|
1. fortio_fopen()
|
|
2. fortio_fread_record()
|
|
3. fortio_fwrite_record()
|
|
|
|
together constitute something very similar to fopen() , fread() and
|
|
fwrite() from the standard library.
|
|
*/
|
|
|
|
|
|
#define READ_MODE_TXT "r"
|
|
#define READ_MODE_BINARY "rb"
|
|
#define WRITE_MODE_TXT "w"
|
|
#define WRITE_MODE_BINARY "wb"
|
|
#define READ_WRITE_MODE_TXT "r+"
|
|
#define READ_WRITE_MODE_BINARY "r+b"
|
|
#define APPEND_MODE_TXT "a"
|
|
#define APPEND_MODE_BINARY "ab"
|
|
|
|
|
|
struct fortio_struct {
|
|
UTIL_TYPE_ID_DECLARATION;
|
|
FILE * stream;
|
|
char * filename;
|
|
bool endian_flip_header;
|
|
bool fmt_file; /* This is not really used by the fortio instance - but it is very convenient to store it here. */
|
|
const char * fopen_mode;
|
|
bool stream_owner;
|
|
|
|
/*
|
|
The internal variable read_size is used in the functions
|
|
fortio_fseek() and fortio_read_at_eof() - if-and-only-if - the
|
|
file is opened in read only mode.
|
|
|
|
Observe that the semantics of the fortio_fseek() function depends
|
|
on whether the file is writable.
|
|
*/
|
|
bool writable;
|
|
offset_type read_size;
|
|
char opts[3];
|
|
};
|
|
|
|
|
|
UTIL_IS_INSTANCE_FUNCTION( fortio , FORTIO_ID );
|
|
UTIL_SAFE_CAST_FUNCTION( fortio, FORTIO_ID );
|
|
|
|
static fortio_type * fortio_alloc__(const char *filename , bool fmt_file , bool endian_flip_header , bool stream_owner , bool writable) {
|
|
fortio_type * fortio = (fortio_type*)util_malloc(sizeof * fortio );
|
|
UTIL_TYPE_ID_INIT( fortio, FORTIO_ID );
|
|
fortio->filename = util_alloc_string_copy(filename);
|
|
fortio->endian_flip_header = endian_flip_header;
|
|
fortio->fmt_file = fmt_file;
|
|
fortio->stream_owner = stream_owner;
|
|
fortio->writable = writable;
|
|
fortio->read_size = 0;
|
|
strcpy( fortio->opts, endian_flip_header ? "c" : "ce" );
|
|
|
|
return fortio;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Helper function for fortio_is_fortran_stream__().
|
|
*/
|
|
|
|
static bool __read_int(FILE * stream , int * value, bool endian_flip) {
|
|
/* This fread() can legitemately fail - can not use util_fread() here. */
|
|
if (fread(value , sizeof * value , 1 , stream) == 1) {
|
|
if (endian_flip)
|
|
util_endian_flip_vector(value , sizeof * value , 1);
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
Helper function for fortio_is_fortran_file(). Checks whether a
|
|
particular stream is formatted according to fortran io, for a fixed
|
|
endian ness.
|
|
*/
|
|
|
|
static bool fortio_is_fortran_stream__(FILE * stream , bool endian_flip) {
|
|
const bool strict_checking = true; /* True: requires that *ALL* records in the file are fortran formatted */
|
|
offset_type init_pos = util_ftell(stream);
|
|
bool is_fortran_stream = false;
|
|
int header , tail;
|
|
bool cont;
|
|
|
|
do {
|
|
cont = false;
|
|
if (__read_int(stream , &header , endian_flip)) {
|
|
if (header >= 0) {
|
|
if (util_fseek(stream , (offset_type) header , SEEK_CUR) == 0) {
|
|
if (__read_int(stream , &tail , endian_flip)) {
|
|
cont = true;
|
|
/*
|
|
OK - now we have read a header and a tail - it might be
|
|
a fortran file.
|
|
*/
|
|
if (header == tail) {
|
|
if (header != 0) {
|
|
/* This is (most probably) a fortran file */
|
|
is_fortran_stream = true;
|
|
if (strict_checking)
|
|
cont = true;
|
|
else
|
|
cont = false;
|
|
}
|
|
/* Header == tail == 0 - we don't make any inference on this. */
|
|
} else {
|
|
/* Header != tail => this is *not* a fortran file */
|
|
cont = false;
|
|
is_fortran_stream = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (cont);
|
|
util_fseek(stream , init_pos , SEEK_SET);
|
|
return is_fortran_stream;
|
|
}
|
|
|
|
|
|
/**
|
|
This function tries (using some heuristic) to guess whether a
|
|
particular file is a Fortran file.
|
|
|
|
The heuristic algorithm which is used is as follows:
|
|
|
|
1. Read four bytes as an integer (header)
|
|
2. Skip that number of bytes forward.
|
|
3. Read four bytes again (tail).
|
|
|
|
Now, when this is done we do the following test:
|
|
|
|
If header == tail. This is (probably) a fortran file, however if
|
|
header == 0, we might have a normal file with two consequitive
|
|
zeroes. In that case it is difficult to determine, and we continue.
|
|
|
|
*/
|
|
|
|
bool fortio_looks_like_fortran_file(const char * filename, bool endian_flip) {
|
|
FILE * stream = util_fopen(filename , "rb");
|
|
bool is_fortran_stream = fortio_is_fortran_stream__(stream , endian_flip);
|
|
fclose(stream);
|
|
return is_fortran_stream;
|
|
}
|
|
|
|
|
|
static void fortio_init_size(fortio_type * fortio) {
|
|
fortio->read_size = util_fd_size( fortio_fileno( fortio ));
|
|
}
|
|
|
|
|
|
|
|
|
|
fortio_type * fortio_alloc_FILE_wrapper(const char *filename , bool endian_flip_header , bool fmt_file , bool writable , FILE * stream) {
|
|
fortio_type * fortio = fortio_alloc__(filename , fmt_file , endian_flip_header , false , writable);
|
|
fortio->stream = stream;
|
|
return fortio;
|
|
}
|
|
|
|
/*****************************************************************/
|
|
/*
|
|
Observe that the stream open functions accept a failure, and call
|
|
the fopen() function driectly.
|
|
*/
|
|
|
|
static const char * fortio_fopen_read_mode( bool fmt_file ) {
|
|
if (fmt_file)
|
|
return READ_MODE_TXT;
|
|
else
|
|
return READ_MODE_BINARY;
|
|
}
|
|
|
|
static FILE * fortio_fopen_read( const char * filename , bool fmt_file ) {
|
|
FILE * stream;
|
|
const char * mode = fortio_fopen_read_mode( fmt_file );
|
|
stream = fopen(filename , mode);
|
|
return stream;
|
|
}
|
|
|
|
|
|
static const char * fortio_fopen_write_mode( bool fmt_file ) {
|
|
if (fmt_file)
|
|
return WRITE_MODE_TXT;
|
|
else
|
|
return WRITE_MODE_BINARY;
|
|
}
|
|
|
|
static FILE * fortio_fopen_write( const char * filename , bool fmt_file ) {
|
|
FILE * stream;
|
|
const char * mode = fortio_fopen_write_mode( fmt_file );
|
|
stream = fopen(filename , mode);
|
|
return stream;
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char * fortio_fopen_readwrite_mode( bool fmt_file ) {
|
|
if (fmt_file)
|
|
return READ_WRITE_MODE_TXT;
|
|
else
|
|
return READ_WRITE_MODE_BINARY;
|
|
}
|
|
|
|
static FILE * fortio_fopen_readwrite( const char * filename , bool fmt_file ) {
|
|
FILE * stream;
|
|
const char * mode = fortio_fopen_readwrite_mode( fmt_file );
|
|
stream = fopen(filename , mode);
|
|
return stream;
|
|
}
|
|
|
|
|
|
static const char * fortio_fopen_append_mode( bool fmt_file ) {
|
|
if (fmt_file)
|
|
return APPEND_MODE_TXT;
|
|
else
|
|
return APPEND_MODE_BINARY;
|
|
}
|
|
|
|
|
|
static FILE * fortio_fopen_append( const char * filename , bool fmt_file ) {
|
|
FILE * stream;
|
|
const char * mode = fortio_fopen_append_mode( fmt_file );
|
|
stream = fopen(filename , mode);
|
|
return stream;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
|
|
|
|
fortio_type * fortio_open_reader(const char *filename , bool fmt_file , bool endian_flip_header) {
|
|
FILE * stream = fortio_fopen_read( filename , fmt_file );
|
|
if (stream) {
|
|
fortio_type *fortio = fortio_alloc__(filename , fmt_file , endian_flip_header , true , false);
|
|
fortio->stream = stream;
|
|
fortio->fopen_mode = fortio_fopen_read_mode( fmt_file );
|
|
fortio_init_size( fortio );
|
|
return fortio;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
fortio_type * fortio_open_writer(const char *filename , bool fmt_file , bool endian_flip_header ) {
|
|
FILE * stream = fortio_fopen_write( filename , fmt_file );
|
|
if (stream) {
|
|
fortio_type *fortio = fortio_alloc__(filename , fmt_file , endian_flip_header, true , true);
|
|
fortio->stream = stream;
|
|
fortio->fopen_mode = fortio_fopen_write_mode( fmt_file );
|
|
fortio_init_size( fortio );
|
|
return fortio;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
fortio_type * fortio_open_readwrite(const char *filename , bool fmt_file , bool endian_flip_header) {
|
|
FILE * stream = fortio_fopen_readwrite( filename , fmt_file );
|
|
if (stream) {
|
|
fortio_type *fortio = fortio_alloc__(filename , fmt_file , endian_flip_header , true , true);
|
|
fortio->stream = stream;
|
|
fortio->fopen_mode = fortio_fopen_readwrite_mode( fmt_file );
|
|
fortio_init_size( fortio );
|
|
return fortio;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
fortio_type * fortio_open_append(const char *filename , bool fmt_file , bool endian_flip_header) {
|
|
FILE * stream = fortio_fopen_append( filename , fmt_file );
|
|
if (stream) {
|
|
fortio_type *fortio = fortio_alloc__(filename , fmt_file , endian_flip_header , true , true);
|
|
|
|
fortio->stream = stream;
|
|
fortio->fopen_mode = fortio_fopen_append_mode( fmt_file );
|
|
fortio_init_size( fortio );
|
|
|
|
return fortio;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
/*****************************************************************/
|
|
|
|
bool fortio_fclose_stream( fortio_type * fortio ) {
|
|
if (fortio->stream_owner) {
|
|
if (fortio->stream) {
|
|
int fclose_return = fclose( fortio->stream );
|
|
fortio->stream = NULL;
|
|
if (fclose_return == 0)
|
|
return true;
|
|
else
|
|
return false;
|
|
} else
|
|
return false; // Already closed.
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
bool fortio_fopen_stream( fortio_type * fortio ) {
|
|
if (fortio->stream == NULL) {
|
|
fortio->stream = fopen( fortio->filename , fortio->fopen_mode );
|
|
if (fortio->stream)
|
|
return true;
|
|
else
|
|
return false;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
bool fortio_stream_is_open( const fortio_type * fortio ) {
|
|
if (fortio->stream)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
bool fortio_assert_stream_open( fortio_type * fortio ) {
|
|
if (fortio->stream)
|
|
return true;
|
|
else {
|
|
fortio_fopen_stream( fortio );
|
|
return fortio_stream_is_open( fortio );
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
|
|
static void fortio_free__(fortio_type * fortio) {
|
|
free(fortio->filename);
|
|
free(fortio);
|
|
}
|
|
|
|
void fortio_free_FILE_wrapper(fortio_type * fortio) {
|
|
fortio_free__( fortio );
|
|
}
|
|
|
|
|
|
void fortio_fclose(fortio_type *fortio) {
|
|
if (fortio->stream) {
|
|
fclose(fortio->stream);
|
|
fortio->stream = NULL;
|
|
}
|
|
|
|
fortio_free__(fortio);
|
|
}
|
|
|
|
|
|
bool fortio_is_fortio_file(fortio_type * fortio) {
|
|
offset_type init_pos = fortio_ftell(fortio);
|
|
int elm_read;
|
|
bool is_fortio_file = false;
|
|
int record_size;
|
|
elm_read = fread(&record_size , sizeof(record_size) , 1 , fortio->stream);
|
|
if (elm_read == 1) {
|
|
int trailer;
|
|
|
|
if (fortio->endian_flip_header)
|
|
util_endian_flip_vector(&record_size , sizeof record_size , 1);
|
|
|
|
if (fortio_fseek(fortio , (offset_type) record_size , SEEK_CUR) == 0) {
|
|
if (fread(&trailer , sizeof(record_size) , 1 , fortio->stream) == 1) {
|
|
if (fortio->endian_flip_header)
|
|
util_endian_flip_vector(&trailer , sizeof trailer , 1);
|
|
|
|
if (trailer == record_size)
|
|
is_fortio_file = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
fortio_fseek(fortio , init_pos , SEEK_SET);
|
|
return is_fortio_file;
|
|
}
|
|
|
|
|
|
/**
|
|
This function reads the header (i.e. the number of bytes in the
|
|
following record), stores that internally in the fortio struct, and
|
|
also returns it. If the function fails to read a header (i.e. EOF)
|
|
it will return -1.
|
|
*/
|
|
|
|
int fortio_init_read(fortio_type *fortio) {
|
|
int elm_read;
|
|
int record_size;
|
|
|
|
elm_read = fread(&record_size , sizeof(record_size) , 1 , fortio->stream);
|
|
if (elm_read == 1) {
|
|
if (fortio->endian_flip_header)
|
|
util_endian_flip_vector(&record_size , sizeof record_size , 1);
|
|
|
|
return record_size;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
|
|
bool fortio_data_fskip(fortio_type* fortio, const int element_size, const int element_count, const int block_count) {
|
|
int headers = block_count * 4;
|
|
int trailers = block_count * 4;
|
|
int bytes_to_skip = headers + trailers + (element_size * element_count);
|
|
|
|
return fortio_fseek(fortio, bytes_to_skip, SEEK_CUR);
|
|
}
|
|
|
|
|
|
void fortio_data_fseek(fortio_type* fortio, offset_type data_offset, size_t data_element, const int element_size, const int element_count, const int block_size) {
|
|
if(data_element >= element_count) {
|
|
util_abort("%s: Element index is out of range: 0 <= %d < %d \n", __func__, data_element, element_count);
|
|
}
|
|
{
|
|
int block_index = data_element / block_size;
|
|
int headers = (block_index + 1) * 4;
|
|
int trailers = block_index * 4;
|
|
offset_type bytes_to_skip = data_offset + headers + trailers + (data_element * element_size);
|
|
|
|
fortio_fseek(fortio, bytes_to_skip, SEEK_SET);
|
|
}
|
|
}
|
|
|
|
int fortio_fclean(fortio_type * fortio) {
|
|
long current_pos = ftell(fortio->stream);
|
|
if(current_pos == -1)
|
|
return -1;
|
|
|
|
int flush_status = fflush(fortio->stream);
|
|
if(flush_status != 0)
|
|
return flush_status;
|
|
|
|
return fseek(fortio->stream, current_pos, SEEK_SET);
|
|
}
|
|
|
|
bool fortio_complete_read(fortio_type *fortio , int record_size) {
|
|
int trailer;
|
|
size_t read_count = fread(&trailer , sizeof trailer , 1 , fortio->stream );
|
|
|
|
if (read_count == 1) {
|
|
if (fortio->endian_flip_header)
|
|
util_endian_flip_vector(&trailer , sizeof trailer , 1);
|
|
|
|
if (record_size == trailer)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
This function reads one record from the fortio stream, and fills
|
|
the buffer with the content. The return value is the number of
|
|
bytes read; the function will return -1 on failure.
|
|
*/
|
|
|
|
static int fortio_fread_record(fortio_type *fortio , char *buffer) {
|
|
int record_size = fortio_init_read(fortio);
|
|
if (record_size >= 0) {
|
|
size_t items_read = fread(buffer , 1 , record_size , fortio->stream);
|
|
if (items_read == record_size) {
|
|
bool complete_ok = fortio_complete_read(fortio , record_size);
|
|
if (!complete_ok)
|
|
record_size = -1;
|
|
} else
|
|
record_size = -1; /* Failure */
|
|
}
|
|
return record_size;
|
|
}
|
|
|
|
|
|
/**
|
|
This function fills the buffer with 'buffer_size' bytes from the
|
|
fortio stream. The function works by repeated calls to
|
|
fortio_read_record(), until the desired number of bytes of been
|
|
read. The point of this is to handle the ECLIPSE system with blocks
|
|
of e.g. 1000 floats (which then become one fortran record), in a
|
|
transparent, low-level way.
|
|
*/
|
|
|
|
bool fortio_fread_buffer(fortio_type * fortio, char * buffer , int buffer_size) {
|
|
int total_bytes_read = 0;
|
|
|
|
while (true) {
|
|
char * buffer_ptr = &buffer[total_bytes_read];
|
|
int bytes_read = fortio_fread_record(fortio , buffer_ptr);
|
|
|
|
if (bytes_read < 0)
|
|
break;
|
|
else {
|
|
total_bytes_read += bytes_read;
|
|
if (total_bytes_read >= buffer_size)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (total_bytes_read == buffer_size)
|
|
return true;
|
|
|
|
if (total_bytes_read < buffer_size)
|
|
return false;
|
|
|
|
util_abort("%s: internal inconsistency: buffer_size:%d read %d bytes \n",__func__ , buffer_size , total_bytes_read);
|
|
return false;
|
|
}
|
|
|
|
|
|
int fortio_fskip_record(fortio_type *fortio) {
|
|
int record_size = fortio_init_read(fortio);
|
|
fortio_fseek(fortio , (offset_type) record_size , SEEK_CUR);
|
|
fortio_complete_read(fortio , record_size);
|
|
return record_size;
|
|
}
|
|
|
|
void fortio_fskip_buffer(fortio_type * fortio, int buffer_size) {
|
|
int bytes_skipped = 0;
|
|
while (bytes_skipped < buffer_size)
|
|
bytes_skipped += fortio_fskip_record(fortio);
|
|
|
|
if (bytes_skipped > buffer_size)
|
|
util_abort("%s: hmmmm - something is broken. The individual records in %s did not sum up to the expected buffer size \n",__func__ , fortio->filename);
|
|
}
|
|
|
|
|
|
void fortio_copy_record(fortio_type * src_stream , fortio_type * target_stream , int buffer_size , void * buffer , bool *at_eof) {
|
|
int bytes_read;
|
|
int record_size = fortio_init_read(src_stream);
|
|
fortio_init_write(target_stream , record_size);
|
|
|
|
bytes_read = 0;
|
|
while (bytes_read < record_size) {
|
|
int bytes;
|
|
if (record_size > buffer_size)
|
|
bytes = buffer_size;
|
|
else
|
|
bytes = record_size - bytes_read;
|
|
|
|
util_fread(buffer , 1 , bytes , src_stream->stream , __func__);
|
|
util_fwrite(buffer , 1 , bytes , target_stream->stream , __func__);
|
|
|
|
bytes_read += bytes;
|
|
}
|
|
|
|
fortio_complete_read(src_stream , record_size);
|
|
fortio_complete_write(target_stream , record_size);
|
|
|
|
if (feof(src_stream->stream))
|
|
*at_eof = true;
|
|
else
|
|
*at_eof = false;
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
void fortio_init_write(fortio_type *fortio , int record_size) {
|
|
int file_header;
|
|
file_header = record_size;
|
|
if (fortio->endian_flip_header)
|
|
util_endian_flip_vector(&file_header , sizeof file_header , 1);
|
|
|
|
util_fwrite_int( file_header , fortio->stream );
|
|
}
|
|
|
|
void fortio_complete_write(fortio_type *fortio , int record_size) {
|
|
int file_header = record_size;
|
|
if (fortio->endian_flip_header)
|
|
util_endian_flip_vector(&file_header , sizeof file_header , 1);
|
|
|
|
util_fwrite_int( file_header , fortio->stream );
|
|
}
|
|
|
|
|
|
void fortio_fwrite_record(fortio_type *fortio, const char *buffer , int record_size) {
|
|
fortio_init_write(fortio , record_size);
|
|
util_fwrite( buffer , 1 , record_size , fortio->stream , __func__);
|
|
fortio_complete_write(fortio , record_size);
|
|
}
|
|
|
|
|
|
void * fortio_fread_alloc_record(fortio_type * fortio) {
|
|
void * buffer;
|
|
int record_size = fortio_init_read(fortio);
|
|
buffer = util_malloc( record_size );
|
|
util_fread(buffer , 1 , record_size , fortio->stream , __func__);
|
|
fortio_complete_read(fortio , record_size);
|
|
return buffer;
|
|
}
|
|
|
|
|
|
|
|
static fortio_status_type fortio_check_record( FILE * stream , bool endian_flip , int * record_size) {
|
|
int read_count;
|
|
int header, tail;
|
|
fortio_status_type status;
|
|
|
|
read_count = fread( &header , sizeof header , 1 , stream );
|
|
if (read_count == 0)
|
|
status = FORTIO_EOF;
|
|
else {
|
|
if (endian_flip)
|
|
util_endian_flip_vector(&header , sizeof header , 1);
|
|
|
|
if (util_fseek( stream , (offset_type) header , SEEK_CUR ) != 0)
|
|
/* The fseek() failed - i.e. the data section was not sufficiently long. */
|
|
status = FORTIO_MISSING_DATA;
|
|
else {
|
|
read_count = fread( &tail , sizeof tail , 1 , stream );
|
|
if (read_count == 1) {
|
|
if (endian_flip)
|
|
util_endian_flip_vector(&tail , sizeof tail , 1);
|
|
|
|
if (tail == header)
|
|
/* All OK */
|
|
status = FORTIO_OK;
|
|
else
|
|
/* The numerical value of the tail did not agree with the header. */
|
|
status = FORTIO_HEADER_MISMATCH;
|
|
} else
|
|
/* The file ended before we could read the tail mark. */
|
|
status = FORTIO_MISSING_TAIL;
|
|
}
|
|
}
|
|
|
|
*record_size = header;
|
|
return status;
|
|
}
|
|
|
|
|
|
fortio_status_type fortio_check_buffer( FILE * stream , bool endian_flip , size_t buffer_size ) {
|
|
size_t current_size = 0;
|
|
fortio_status_type record_status;
|
|
while (true) {
|
|
int record_size;
|
|
record_status = fortio_check_record( stream , endian_flip , &record_size );
|
|
current_size += record_size;
|
|
if (record_status != FORTIO_OK)
|
|
break;
|
|
}
|
|
if (record_status == FORTIO_EOF) {
|
|
/* We are at the end of file - see if we have read in enough data. */
|
|
if (buffer_size == current_size)
|
|
return FORTIO_OK;
|
|
else
|
|
return FORTIO_EOF;
|
|
} else
|
|
return record_status;
|
|
}
|
|
|
|
|
|
|
|
fortio_status_type fortio_check_file( const char * filename , bool endian_flip) {
|
|
if (util_file_exists( filename )) {
|
|
size_t file_size = util_file_size( filename );
|
|
if (file_size == 0)
|
|
return FORTIO_EOF;
|
|
else {
|
|
fortio_status_type record_status;
|
|
{
|
|
FILE * stream = util_fopen( filename , "r");
|
|
do {
|
|
int record_size;
|
|
record_status = fortio_check_record( stream , endian_flip , &record_size);
|
|
} while ( record_status == FORTIO_OK );
|
|
fclose( stream );
|
|
}
|
|
if (record_status == FORTIO_EOF) /* Normal exit from loop at EOF */
|
|
return FORTIO_OK;
|
|
else
|
|
return record_status;
|
|
}
|
|
} else
|
|
return FORTIO_NOENTRY; /* This is an application error. */
|
|
}
|
|
|
|
|
|
offset_type fortio_ftell( const fortio_type * fortio ) {
|
|
return util_ftell( fortio->stream );
|
|
}
|
|
|
|
|
|
static bool fortio_fseek__(fortio_type * fortio , offset_type offset , int whence) {
|
|
int fseek_return = util_fseek( fortio->stream , offset , whence );
|
|
if (fseek_return == 0)
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
}
|
|
|
|
/*
|
|
The semantics of this function depends on the readbale flag of the
|
|
fortio structure:
|
|
|
|
writable == true: Ordinary fseek() semantics which can potentially
|
|
grow the file.
|
|
|
|
writable == false: The function will only seek within the range of
|
|
the file, and fail if you try to seek beyond the EOF marker.
|
|
|
|
*/
|
|
|
|
|
|
bool fortio_fseek( fortio_type * fortio , offset_type offset , int whence) {
|
|
if (fortio->writable)
|
|
return fortio_fseek__( fortio , offset , whence );
|
|
else {
|
|
offset_type new_offset = 0;
|
|
|
|
switch (whence) {
|
|
case( SEEK_CUR ):
|
|
new_offset = fortio_ftell( fortio ) + offset;
|
|
break;
|
|
case (SEEK_END):
|
|
new_offset = fortio->read_size + offset;
|
|
break;
|
|
case (SEEK_SET):
|
|
new_offset = offset;
|
|
break;
|
|
default:
|
|
util_abort("%s: invalid seek flag \n",__func__);
|
|
}
|
|
|
|
if (new_offset <= fortio->read_size)
|
|
return fortio_fseek__( fortio , new_offset , SEEK_SET );
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool fortio_ftruncate( fortio_type * fortio , offset_type size) {
|
|
fortio_fseek( fortio , size , SEEK_SET);
|
|
return util_ftruncate( fortio->stream , size);
|
|
}
|
|
|
|
|
|
bool fortio_ftruncate_current( fortio_type * fortio ) {
|
|
offset_type size = fortio_ftell( fortio );
|
|
return util_ftruncate( fortio->stream , size);
|
|
}
|
|
|
|
|
|
|
|
int fortio_fileno( fortio_type * fortio ) {
|
|
return fileno( fortio->stream );
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
It is massively undefined behaviour to call this function for a file
|
|
which has been updated; in that case the util_fd_size() function
|
|
will return the size of the file *when it was opened*.
|
|
*/
|
|
|
|
bool fortio_read_at_eof( fortio_type * fortio ) {
|
|
|
|
if (fortio_ftell(fortio) == fortio->read_size)
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
}
|
|
|
|
/*
|
|
When this function is called the underlying file is unlinked, and
|
|
the entry will be removed from the filsystem. Subsequent calls which
|
|
write to this file will still (superficially) succeed.
|
|
*/
|
|
|
|
void fortio_fwrite_error(fortio_type * fortio) {
|
|
if (fortio->writable)
|
|
util_unlink( fortio->filename );
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
void fortio_fflush(fortio_type * fortio) { fflush( fortio->stream); }
|
|
FILE * fortio_get_FILE(const fortio_type *fortio) { return fortio->stream; }
|
|
//bool fortio_endian_flip(const fortio_type *fortio) { return fortio->endian_flip_header; }
|
|
bool fortio_fmt_file(const fortio_type *fortio) { return fortio->fmt_file; }
|
|
void fortio_rewind(const fortio_type *fortio) { util_rewind(fortio->stream); }
|
|
const char * fortio_filename_ref(const fortio_type * fortio) { return (const char *) fortio->filename; }
|
|
|
|
|