Merge pull request #439 from michaeltryby/dev-filemanager

Dev filemanager
This commit is contained in:
Michael Tryby
2019-04-02 17:11:38 -04:00
committed by GitHub
14 changed files with 578 additions and 151 deletions

View File

@@ -28,7 +28,7 @@ env:
- TEST_HOME=nrtestsuite
before_install:
- sudo apt-get -qq update
# - sudo apt-get -qq update
- eval "${MATRIX_EVAL}"
#install:

View File

@@ -21,7 +21,6 @@ environment:
GENERATOR: "Visual Studio 15 2017"
GROUP: "SUPPORTED"
BOOST_ROOT: "C:/Libraries/boost_1_67_0"
PLATFORM: "win32"
REF_BUILD_ID: "220dev5"
# New build on Visual Studio 15 2017

View File

@@ -21,7 +21,9 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
# configure file groups
set(EPANET_OUT_SOURCES src/epanet_output.c
../util/errormanager.c)
../util/errormanager.c
../util/filemanager.c
../util/cstr_helper.c)
# the binary output file API

View File

@@ -2,8 +2,9 @@
//
// epanet_output.c -- API for reading results from EPANET binary output file
//
// Version: 0.30
// Date 09/06/2017
// Version: 0.40
// Date 04/02/2019
// 09/06/2017
// 06/17/2016
// 08/05/2014
// 05/21/2014
@@ -40,18 +41,13 @@
#include <string.h>
#include "util/errormanager.h"
#include "util/filemanager.h"
#include "epanet_output.h"
#include "messages.h"
// NOTE: These depend on machine data model and may change when porting
// F_OFF Must be a 8 byte / 64 bit integer for large file support
#ifdef _WIN32 // Windows (32-bit and 64-bit)
#define F_OFF __int64
#else // Other platforms
#define F_OFF off_t
#endif
#define INT4 int // Must be a 4 byte / 32 bit integer type
#define REAL4 float // Must be a 4 byte / 32 bit real type
#define WORDSIZE 4 // Memory alignment 4 byte word size for both int and real
@@ -71,33 +67,28 @@
// Typedefs for opaque pointer
typedef struct data_s {
char name[MAXFNAME+1]; // file path/name
FILE* file; // FILE structure pointer
INT4 nodeCount, tankCount, linkCount, pumpCount, valveCount, nPeriods;
F_OFF outputStartPos; // starting file position of output data
F_OFF bytesPerPeriod; // bytes saved per simulation time period
error_handle_t* error_handle;
error_handle_t *error_handle;
file_handle_t *file_handle;
} data_t;
//-----------------------------------------------------------------------------
// Local functions
//-----------------------------------------------------------------------------
void errorLookup(int errcode, char* errmsg, int length);
int validateFile(ENR_Handle);
float getNodeValue(ENR_Handle, int, int, int);
float getLinkValue(ENR_Handle, int, int, int);
void errorLookup(int errcode, char* errmsg, int length);
int validateFile(ENR_Handle);
float getNodeValue(ENR_Handle, int, int, int);
float getLinkValue(ENR_Handle, int, int, int);
int _fopen(FILE **f, const char *name, const char *mode);
int _fseek(FILE* stream, F_OFF offset, int whence);
F_OFF _ftell(FILE* stream);
float* newFloatArray(int n);
int* newIntArray(int n);
char* newCharArray(int n);
float *newFloatArray(int n);
int *newIntArray(int n);
char *newCharArray(int n);
int EXPORT_OUT_API ENR_init(ENR_Handle* dp_handle)
int EXPORT_OUT_API ENR_init(ENR_Handle *dp_handle)
// Purpose: Initialized pointer for the opaque ENR_Handle.
//
// Returns: Error code 0 on success, -1 on failure
@@ -114,6 +105,7 @@ int EXPORT_OUT_API ENR_init(ENR_Handle* dp_handle)
if (p_data != NULL){
p_data->error_handle = create_error_manager(&errorLookup);
p_data->file_handle = create_file_manager();
*dp_handle = p_data;
}
else
@@ -123,7 +115,7 @@ int EXPORT_OUT_API ENR_init(ENR_Handle* dp_handle)
return errorcode;
}
int EXPORT_OUT_API ENR_close(ENR_Handle* p_handle)
int EXPORT_OUT_API ENR_close(ENR_Handle *p_handle)
/*------------------------------------------------------------------------
** Input: *p_handle = pointer to ENR_Handle struct
**
@@ -143,13 +135,16 @@ int EXPORT_OUT_API ENR_close(ENR_Handle* p_handle)
p_data = (data_t*)(*p_handle);
if (p_data == NULL || p_data->file == NULL)
if (p_data == NULL || p_data->file_handle == NULL)
errorcode = -1;
else
{
close_file(p_data->file_handle);
delete_error_manager(p_data->error_handle);
fclose(p_data->file);
delete_file_manager(p_data->file_handle);
free(p_data);
*p_handle = NULL;
@@ -178,23 +173,22 @@ int EXPORT_OUT_API ENR_open(ENR_Handle p_handle, const char* path)
if (p_data == NULL) return -1;
else
{
strncpy(p_data->name, path, MAXFNAME);
// Attempt to open binary output file for reading only
if ((_fopen(&(p_data->file), path, "rb")) != 0) errorcode = 434;
if ((open_file(p_data->file_handle, path, "rb")) != 0)
errorcode = 434;
// Perform checks to insure the file is valid
else if ((err = validateFile(p_data)) != 0) errorcode = err;
// If a warning is encountered read file header
if (errorcode < 400 ) {
// read network size
fseek(p_data->file, 2*WORDSIZE, SEEK_SET);
fread(&(p_data->nodeCount), WORDSIZE, 1, p_data->file);
fread(&(p_data->tankCount), WORDSIZE, 1, p_data->file);
fread(&(p_data->linkCount), WORDSIZE, 1, p_data->file);
fread(&(p_data->pumpCount), WORDSIZE, 1, p_data->file);
fread(&(p_data->valveCount), WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, 2*WORDSIZE, SEEK_SET);
read_file(&(p_data->nodeCount), WORDSIZE, 1, p_data->file_handle);
read_file(&(p_data->tankCount), WORDSIZE, 1, p_data->file_handle);
read_file(&(p_data->linkCount), WORDSIZE, 1, p_data->file_handle);
read_file(&(p_data->pumpCount), WORDSIZE, 1, p_data->file_handle);
read_file(&(p_data->valveCount), WORDSIZE, 1, p_data->file_handle);
// Compute positions and offsets for retrieving data
// fixed portion of header + title section + filenames + chem names
@@ -240,8 +234,8 @@ int EXPORT_OUT_API ENR_getVersion(ENR_Handle p_handle, int* version)
if (p_data == NULL) return -1;
else
{
fseek(p_data->file, 1*WORDSIZE, SEEK_SET);
if (fread(version, WORDSIZE, 1, p_data->file) != 1)
seek_file(p_data->file_handle, 1*WORDSIZE, SEEK_SET);
if (read_file(version, WORDSIZE, 1, p_data->file_handle) != 1)
errorcode = 436;
}
@@ -319,26 +313,26 @@ int EXPORT_OUT_API ENR_getUnits(ENR_Handle p_handle, ENR_Units code, int* unitFl
switch (code)
{
case ENR_flowUnits:
_fseek(p_data->file, 9*WORDSIZE, SEEK_SET);
fread(unitFlag, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, 9*WORDSIZE, SEEK_SET);
read_file(unitFlag, WORDSIZE, 1, p_data->file_handle);
break;
case ENR_pressUnits:
_fseek(p_data->file, 10*WORDSIZE, SEEK_SET);
fread(unitFlag, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, 10*WORDSIZE, SEEK_SET);
read_file(unitFlag, WORDSIZE, 1, p_data->file_handle);
break;
case ENR_qualUnits:
offset = 7*WORDSIZE;
_fseek(p_data->file, offset, SEEK_SET);
fread(unitFlag, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, offset, SEEK_SET);
read_file(unitFlag, WORDSIZE, 1, p_data->file_handle);
if (*unitFlag == 0) *unitFlag = ENR_NONE;
else if (*unitFlag == 1) {
offset = 15*WORDSIZE + 3*MAXMSG_P1 + 2*(MAXFNAME+1) + MAXID_P1;
_fseek(p_data->file, offset, SEEK_SET);
fread(temp, MAXID_P1, 1, p_data->file);
seek_file(p_data->file_handle, offset, SEEK_SET);
read_file(temp, MAXID_P1, 1, p_data->file_handle);
if (!strcmp(temp, "mg/L")) *unitFlag = ENR_MGL;
else *unitFlag = ENR_UGL;
@@ -379,18 +373,18 @@ int EXPORT_OUT_API ENR_getTimes(ENR_Handle p_handle, ENR_Time code, int* time)
switch (code)
{
case ENR_reportStart:
fseek(p_data->file, 12*WORDSIZE, SEEK_SET);
fread(time, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, 12*WORDSIZE, SEEK_SET);
read_file(time, WORDSIZE, 1, p_data->file_handle);
break;
case ENR_reportStep:
fseek(p_data->file, 13*WORDSIZE, SEEK_SET);
fread(time, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, 13*WORDSIZE, SEEK_SET);
read_file(time, WORDSIZE, 1, p_data->file_handle);
break;
case ENR_simDuration:
fseek(p_data->file, 14*WORDSIZE, SEEK_SET);
fread(time, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, 14*WORDSIZE, SEEK_SET);
read_file(time, WORDSIZE, 1, p_data->file_handle);
break;
case ENR_numPeriods:
@@ -405,7 +399,6 @@ int EXPORT_OUT_API ENR_getTimes(ENR_Handle p_handle, ENR_Time code, int* time)
}
int EXPORT_OUT_API ENR_getChemData(ENR_Handle p_handle, char** name, int* length)
{
return 0;
}
@@ -459,8 +452,8 @@ int EXPORT_OUT_API ENR_getElementName(ENR_Handle p_handle, ENR_ElementType type,
if (!errorcode)
{
_fseek(p_data->file, offset, SEEK_SET);
fread(temp, 1, MAXID_P1, p_data->file);
seek_file(p_data->file_handle, offset, SEEK_SET);
read_file(temp, 1, MAXID_P1, p_data->file_handle);
*name = temp;
*length = MAXID_P1;
@@ -505,9 +498,9 @@ int EXPORT_OUT_API ENR_getEnergyUsage(ENR_Handle p_handle, int pumpIndex,
offset += (pumpIndex - 1)*(WORDSIZE + 6*WORDSIZE);
// Power summary is 1 int and 6 floats for each pump
_fseek(p_data->file, offset, SEEK_SET);
fread(linkIndex, WORDSIZE, 1, p_data->file);
fread(temp, WORDSIZE, 6, p_data->file);
seek_file(p_data->file_handle, offset, SEEK_SET);
read_file(linkIndex, WORDSIZE, 1, p_data->file_handle);
read_file(temp, WORDSIZE, 6, p_data->file_handle);
*outValues = temp;
*length = NENERGYRESULTS;
@@ -541,8 +534,8 @@ int EXPORT_OUT_API ENR_getNetReacts(ENR_Handle p_handle, float** outValues, int*
// Reaction summary is 4 floats located right before epilogue.
// This offset is relative to the end of the file.
offset = - 3*WORDSIZE - 4*WORDSIZE;
_fseek(p_data->file, offset, SEEK_END);
fread(temp, WORDSIZE, 4, p_data->file);
seek_file(p_data->file_handle, offset, SEEK_END);
read_file(temp, WORDSIZE, 4, p_data->file_handle);
*outValues = temp;
*length = NREACTRESULTS;
@@ -670,8 +663,8 @@ int EXPORT_OUT_API ENR_getNodeAttribute(ENR_Handle p_handle, int periodIndex,
// add offset for node and attribute
offset += ((attr - 1)*p_data->nodeCount)*WORDSIZE;
_fseek(p_data->file, offset, SEEK_SET);
fread(temp, WORDSIZE, p_data->nodeCount, p_data->file);
seek_file(p_data->file_handle, offset, SEEK_SET);
read_file(temp, WORDSIZE, p_data->nodeCount, p_data->file_handle);
*outValueArray = temp;
*length = p_data->nodeCount;
@@ -720,8 +713,8 @@ int EXPORT_OUT_API ENR_getLinkAttribute(ENR_Handle p_handle, int periodIndex,
// add offset for link and attribute
offset += ((attr - 1)*p_data->linkCount)*WORDSIZE;
_fseek(p_data->file, offset, SEEK_SET);
fread(temp, WORDSIZE, p_data->linkCount, p_data->file);
seek_file(p_data->file_handle, offset, SEEK_SET);
read_file(temp, WORDSIZE, p_data->linkCount, p_data->file_handle);
*outValueArray = temp;
*length = p_data->linkCount;
@@ -852,16 +845,16 @@ int validateFile(ENR_Handle p_handle)
p_data = (data_t*)p_handle;
// Read magic number from beginning of file
fseek(p_data->file, 0L, SEEK_SET);
fread(&magic1, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, 0L, SEEK_SET);
read_file(&magic1, WORDSIZE, 1, p_data->file_handle);
// Fast forward to end and read file epilogue
fseek(p_data->file, -3*WORDSIZE, SEEK_END);
fread(&(p_data->nPeriods), WORDSIZE, 1, p_data->file);
fread(&hydcode, WORDSIZE, 1, p_data->file);
fread(&magic2, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, -3*WORDSIZE, SEEK_END);
read_file(&(p_data->nPeriods), WORDSIZE, 1, p_data->file_handle);
read_file(&hydcode, WORDSIZE, 1, p_data->file_handle);
read_file(&magic2, WORDSIZE, 1, p_data->file_handle);
filepos = _ftell(p_data->file);
filepos = tell_file(p_data->file_handle);
// Is the file an EPANET binary file?
if (magic1 != magic2) errorcode = 435;
@@ -891,8 +884,8 @@ float getNodeValue(ENR_Handle p_handle, int periodIndex, int nodeIndex,
// add byte position for attribute and node
offset += ((attr - 1)*p_data->nodeCount + (nodeIndex - 1))*WORDSIZE;
_fseek(p_data->file, offset, SEEK_SET);
fread(&y, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, offset, SEEK_SET);
read_file(&y, WORDSIZE, 1, p_data->file_handle);
return y;
}
@@ -915,56 +908,12 @@ float getLinkValue(ENR_Handle p_handle, int periodIndex, int linkIndex,
// add byte position for attribute and link
offset += ((attr - 1)*p_data->linkCount + (linkIndex - 1))*WORDSIZE;
_fseek(p_data->file, offset, SEEK_SET);
fread(&y, WORDSIZE, 1, p_data->file);
seek_file(p_data->file_handle, offset, SEEK_SET);
read_file(&y, WORDSIZE, 1, p_data->file_handle);
return y;
}
int _fopen(FILE **f, const char *name, const char *mode) {
//
// Purpose: Substitute for fopen_s on platforms where it doesn't exist
// Note: fopen_s is part of C++11 standard
//
int ret = 0;
#ifdef _WIN32
ret = (int)fopen_s(f, name, mode);
#else
*f = fopen(name, mode);
if (!*f)
ret = -1;
#endif
return ret;
}
int _fseek(FILE* stream, F_OFF offset, int whence)
//
// Purpose: Selects platform fseek() for large file support
//
{
#ifdef _WIN32 // Windows (32-bit and 64-bit)
#define FSEEK64 _fseeki64
#else // Other platforms
#define FSEEK64 fseeko
#endif
return FSEEK64(stream, offset, whence);
}
F_OFF _ftell(FILE* stream)
//
// Purpose: Selects platform ftell() for large file support
//
{
#ifdef _WIN32 // Windows (32-bit and 64-bit)
#define FTELL64 _ftelli64
#else // Other platforms
#define FTELL64 ftello
#endif
return FTELL64(stream);
}
float* newFloatArray(int n)
//
// Warning: Caller must free memory allocated by this function.

48
src/util/cstr_helper.c Normal file
View File

@@ -0,0 +1,48 @@
/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: util/cstr_helper.c
Description: Provides a simple interface for managing files
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/02/2019
******************************************************************************
*/
#include <stdlib.h>
#include <string.h>
#include "cstr_helper.h"
int copy_cstr(const char *source, char **dest)
// Determines length, allocates memory, and returns a null terminated copy
// Be Aware: caller is responsible for freeing memory
{
size_t size;
size = 1 + strlen(source);
*dest = (char *) calloc(size, sizeof(char));
if (*dest == NULL)
return -1;
else {
#ifdef _MSC_VER
strncpy_s(*dest, size, source, size);
#else
strncpy(*dest, source, size);
#endif
}
return 0;
}
bool isnullterm_cstr(const char *source)
{
if (strchr(source, '\0'))
return true;
else
return false;
}

25
src/util/cstr_helper.h Normal file
View File

@@ -0,0 +1,25 @@
/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: util/cstr_helper.h
Description: Provides a simple interface for managing files
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/02/2019
******************************************************************************
*/
#ifndef CSTR_HELPER_H_
#define CSTR_HELPER_H_
#include <stdbool.h>
int copy_cstr(const char *source, char **destination);
bool isnullterm_cstr(const char *source);
#endif /* CSTR_HELPER_H_ */

View File

@@ -1,14 +1,15 @@
//-----------------------------------------------------------------------------
//
// errormanager.c
//
// Purpose: Provides a simple interface for managing runtime error messages.
//
// Date: 08/25/2017
//
// Author: Michael E. Tryby
// US EPA - ORD/NRMRL
//-----------------------------------------------------------------------------
/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: util/errormanager.c
Description: Provides a simple interface for managing files
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/02/2019
******************************************************************************
*/
//#ifdef _WIN32
//#define _CRTDBG_MAP_ALLOC
@@ -22,6 +23,12 @@
#include "errormanager.h"
typedef struct error_s {
int error_status;
void (*p_msg_lookup)(int, char*, int);
} error_handle_t;
error_handle_t *create_error_manager(void (*p_error_message)(int, char*, int))
//
// Purpose: Constructs a new error handle.

View File

@@ -1,11 +1,15 @@
/*
* errormanager.h
*
* Created on: Aug 25, 2017
*
* Author: Michael E. Tryby
* US EPA - ORD/NRMRL
*/
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: util/errormanager.h
Description: Provides a simple interface for managing files
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/02/2019
******************************************************************************
*/
#ifndef ERRORMANAGER_H_
#define ERRORMANAGER_H_
@@ -17,11 +21,8 @@
extern "C" {
#endif
typedef struct error_s {
int error_status;
void (*p_msg_lookup)(int, char*, int);
} error_handle_t;
// Forward declaration
typedef struct error_s error_handle_t;
error_handle_t* create_error_manager(void (*p_error_message)(int, char*, int));
void delete_error_manager(error_handle_t* error_handle);

211
src/util/filemanager.c Normal file
View File

@@ -0,0 +1,211 @@
/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: util/filemanager.c
Description: Provides a simple interface for managing files
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/01/2019
******************************************************************************
*/
// MSVC ONLY
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include <stdarg.h>
#include "filemanager.h"
typedef struct file_s {
char *filename; // Assumes this is a null terminated string
FILE *file;
} file_handle_t;
// local (private) functions
int _fopen(FILE **f, const char *name, const char *mode);
int _get_temp_filename(char **tempname);
file_handle_t *create_file_manager() {
file_handle_t *file_handle;
file_handle = (file_handle_t *)calloc(1, sizeof(file_handle_t));
file_handle->filename = NULL;
file_handle->file = NULL;
return file_handle;
}
void delete_file_manager(file_handle_t *file_handle) {
if (file_handle->file != NULL)
close_file(file_handle);
free(file_handle->filename);
free(file_handle);
}
void get_filename(file_handle_t *file_handle, char **filename, size_t *size)
//
// BE AWARE: The memory allocated here must be freed by the caller
//
{
copy_cstr(file_handle->filename, filename);
}
int open_file(file_handle_t *file_handle, const char *filename, const char *file_mode) {
int error = 0;
if (filename == NULL)
_get_temp_filename(&(file_handle->filename));
else
copy_cstr(filename, &(file_handle->filename));
if (file_mode == NULL)
error = -1;
else {
error = _fopen(&(file_handle->file), file_handle->filename, file_mode);
}
return error;
}
int seek_file(file_handle_t *file_handle, F_OFF offset, int whence)
{
#ifdef _WIN32 // Windows (32-bit and 64-bit)
#define FSEEK64 _fseeki64
#else // Other platforms
#define FSEEK64 fseeko
#endif
return FSEEK64(file_handle->file, offset, whence);
}
F_OFF tell_file(file_handle_t *file_handle)
{
#ifdef _WIN32 // Windows (32-bit and 64-bit)
#define FTELL64 _ftelli64
#else // Other platforms
#define FTELL64 ftello
#endif
return FTELL64(file_handle->file);
}
// Read and write to a binary file
size_t read_file(void *ptr, size_t size, size_t nmemb, file_handle_t *file_handle)
{
return fread(ptr, size, nmemb, file_handle->file);
}
size_t write_file(const void * ptr, size_t size, size_t count, file_handle_t *file_handle)
{
return fwrite(ptr, size, count, file_handle->file);
}
// print and get from a text file
int printf_file(file_handle_t *file_handle, const char *format, ... )
{
int error = 0;
va_list args;
va_start(args, format);
error = vfprintf(file_handle->file, format, args);
va_end(args);
return error;
}
int gets_file(char *str, int num, file_handle_t *file_handle)
{
fgets(str, num, file_handle->file);
return 0;
}
int close_file(file_handle_t *file_handle) {
int error = 0;
if (file_handle->file != NULL) {
error = fclose(file_handle->file);
file_handle->file = NULL;
}
return error;
}
int remove_file(file_handle_t *file_handle) {
return remove(file_handle->filename);
}
bool is_valid(file_handle_t *file_handle)
{
if ((file_handle->filename == NULL && file_handle->file == NULL) ||
(isnullterm_cstr(file_handle->filename) && file_handle != NULL))
return true;
else
return false;
}
int _fopen(FILE **f, const char *name, const char *mode)
//
// Purpose: Substitute for fopen_s on platforms where it doesn't exist
// Note: fopen_s is part of C++11 standard
//
{
int ret = 0;
#ifdef _WIN32
ret = (int)fopen_s(f, name, mode);
#else
*f = fopen(name, mode);
if (!*f)
ret = -1;
#endif
return ret;
}
int _get_temp_filename(char **tempname)
{
int error = 0;
#ifdef _WIN32
char *name = NULL;
// --- use Windows _tempnam function to get a pointer to an
// unused file name that begins with "en"
if ((name = _tempnam(name, "en")) == NULL) {
error = -1;
return error;
}
else
copy_cstr(name, tempname);
// --- free the pointer returned by _tempnam
if (name)
free(name);
// --- for non-Windows systems:
#else
// --- use system function mkstemp() to create a temporary file name
copy_cstr("enXXXXXX", tempname);
error = mkstemp(*tempname);
#endif
return error;
}

81
src/util/filemanager.h Normal file
View File

@@ -0,0 +1,81 @@
/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: util/filemanager.h
Description: Provides a simple interface for managing files
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/01/2019
******************************************************************************
*/
#ifndef FILEMANAGER_H_
#define FILEMANAGER_H_
#include <stdio.h>
#include <stdarg.h>
#include "cstr_helper.h"
// F_OFF Must be a 8 byte / 64 bit integer for large file support
#ifdef _WIN32 // Windows (32-bit and 64-bit)
#define F_OFF __int64
#else // Other platforms
#define F_OFF off_t
#endif
#define FILE_MAXNAME 259
#if defined(__cplusplus)
extern "C" {
#endif
// Forward declariation of file_handle_t
typedef struct file_s file_handle_t;
file_handle_t *create_file_manager();
void delete_file_manager(file_handle_t *file_handle);
void get_filename(file_handle_t *file_handle, char **filename, size_t *size);
int open_file(file_handle_t *file_handle, const char *filename, const char *file_mode);
int seek_file(file_handle_t *file_handle, F_OFF offset, int whence);
F_OFF tell_file(file_handle_t *file_handle);
// Functions for working with binary files
size_t read_file(void *ptr, size_t size, size_t nmemb, file_handle_t *file_handle);
size_t write_file(const void *ptr, size_t size, size_t count, file_handle_t *file_handle);
// Functions for working with text files
int printf_file(file_handle_t *file_handle, const char *format, ... );
int gets_file(char *str, int num, file_handle_t *file_handle);
int close_file(file_handle_t *file_handle);
int remove_file(file_handle_t *file_handle);
bool is_valid(file_handle_t *file_handle);
#if defined(__cplusplus)
}
#endif
#endif /* FILEMANAGER_H_ */

View File

@@ -59,6 +59,10 @@ add_test(NAME test_reent
add_test(NAME test_errormanager
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_errormanager)
add_test(NAME test_filemanager
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_filemanager
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/outfile/data)
add_test(NAME test_output
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_output
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/outfile/data)

View File

@@ -7,11 +7,14 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set (test_source
./test_errormanager.cpp
../../src/util/errormanager.c
)
add_executable(test_errormanager ${test_source})
add_executable(test_errormanager ./test_errormanager.cpp
../../src/util/errormanager.c)
target_include_directories(test_errormanager PUBLIC ../../src/)
target_link_libraries(test_errormanager ${Boost_LIBRARIES})
add_executable(test_filemanager ./test_filemanager.cpp
../../src/util/filemanager.c
../../src/util/cstr_helper.c)
target_include_directories(test_filemanager PUBLIC ../../src/)
target_link_libraries(test_filemanager ${Boost_LIBRARIES})

View File

@@ -1,7 +1,7 @@
#define BOOST_TEST_MODULE errormanager
//#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include "util/errormanager.h"

View File

@@ -0,0 +1,97 @@
/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: util/test_filemanager.cpp
Description: Tests for util/filemanager.c
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/01/2019
******************************************************************************
*/
#define BOOST_TEST_MODULE filemanager
#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>
#include "util/filemanager.h"
#define DATA_PATH_OUTPUT "./example1.out"
boost::test_tools::predicate_result check_string(std::string test, std::string ref)
{
if (ref.compare(test) == 0)
return true;
else
return false;
}
BOOST_AUTO_TEST_SUITE(test_filemanager)
BOOST_AUTO_TEST_CASE (test_create_destroy)
{
file_handle_t *file_handle = NULL;
file_handle = create_file_manager();
BOOST_CHECK(file_handle != NULL);
BOOST_CHECK(is_valid(file_handle) == true);
delete_file_manager(file_handle);
}
BOOST_AUTO_TEST_CASE(test_open_close)
{
int error = 0;
file_handle_t *file_handle = NULL;
file_handle = create_file_manager();
BOOST_CHECK(file_handle != NULL);
error = open_file(file_handle, DATA_PATH_OUTPUT, "rb");
BOOST_REQUIRE(error == 0);
BOOST_CHECK(is_valid(file_handle) == true);
error = close_file(file_handle);
BOOST_REQUIRE(error == 0);
delete_file_manager(file_handle);
}
struct Fixture{
Fixture() {
error = 0;
file_handle = NULL;
file_handle = create_file_manager();
open_file(file_handle, NULL, "wt");
}
~Fixture() {
close_file(file_handle);
delete_file_manager(file_handle);
}
int error;
file_handle_t *file_handle;
};
BOOST_FIXTURE_TEST_CASE(test_temp_file, Fixture)
{
char *filename;
size_t size;
printf_file(file_handle, "%s", "This is a test.");
get_filename(file_handle, &filename, &size);
BOOST_CHECK(is_valid(file_handle) == true);
BOOST_CHECK(boost::filesystem::exists(filename) == true);
free(filename);
}
BOOST_AUTO_TEST_SUITE_END()