From 4723336726bca146d9f7529e313b27e6ef261a8d Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 13 Jul 2018 11:47:47 -0400 Subject: [PATCH] Adding errormanager to toolkit api --- CMakeLists.txt | 4 +- include/epanet2.h | 7 ++- src/epanet.c | 135 +++++++++++++++++++++++++++++++++------- src/types.h | 4 ++ src/util/errormanager.c | 73 ++++++++++++++++++++++ src/util/errormanager.h | 30 +++++++++ tests/test_toolkit.cpp | 21 +++++++ 7 files changed, 246 insertions(+), 28 deletions(-) create mode 100644 src/util/errormanager.c create mode 100644 src/util/errormanager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e82365..acb522c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,8 +69,8 @@ ENDIF (MSVC) # configure file groups -file(GLOB EPANET_SOURCES src/*.c) -file(GLOB EPANET_LIB_ALL src/*) +file(GLOB EPANET_SOURCES src/*.c src/util/*.c) +file(GLOB EPANET_LIB_ALL src/* src/util/*) source_group("Library" FILES ${EPANET_LIB_ALL}) diff --git a/include/epanet2.h b/include/epanet2.h index ef6f9d2..726678c 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -294,8 +294,9 @@ typedef struct EN_Curve EN_Curve; needed then the argument should be NULL. */ int DLLEXPORT ENepanet(const char *inpFile, const char *rptFile, - const char *binOutFile, void (*callback) (char *)); - + const char *binOutFile, void (*callback) (char *)); +int DLLEXPORT EN_epanet(EN_ProjectHandle ph, const char *inpFile, + const char *rptFile, const char *binOutFile, void(*callback) (char *)); // OPENING A CLOSING THE EPANET TOOLKIT SYSTEM /** @@ -1261,6 +1262,8 @@ int DLLEXPORT EN_deletelink(EN_ProjectHandle ph, int linkIndex); int DLLEXPORT EN_alloc(EN_ProjectHandle *ph); int DLLEXPORT EN_free(EN_ProjectHandle *ph); +void DLLEXPORT EN_clearError(EN_ProjectHandle ph); +int DLLEXPORT EN_checkError(EN_ProjectHandle ph, char **msg_buffer); int DLLEXPORT EN_getqualtype(EN_ProjectHandle ph, int *qualcode, int *tracenode); diff --git a/src/epanet.c b/src/epanet.c index 568b3c8..90b790f 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -133,6 +133,10 @@ execute function x and set the error code equal to its return value. ////////////////////////////////////////////#include "epanet2.h" #include "vars.h" + +// Local functions +void errorLookup(int errcode, char *errmsg, int len); + /**************************************************************** LEGACY (v <= 2.1) API: uses global project variable @@ -159,24 +163,14 @@ execute function x and set the error code equal to its return value. int DLLEXPORT ENepanet(const char *f1, const char *f2, const char *f3, void (*pviewprog)(char *)) { int errcode = 0; - EN_Project *_p; ERRCODE(EN_alloc(&_defaultModel)); - ERRCODE(EN_open(_defaultModel, f1, f2, f3)); - _p = (EN_Project*)_defaultModel; + ERRCODE(EN_epanet(_defaultModel, f1, f2, f3, pviewprog)); + + ERRCODE(EN_free(&_defaultModel)); - _p->viewprog = pviewprog; - if (_p->out_files.Hydflag != USE) { - ERRCODE(EN_solveH(_defaultModel)); - } - - ERRCODE(EN_solveQ(_defaultModel)); - ERRCODE(EN_report(_defaultModel)); - EN_close(_defaultModel); - EN_free(&_defaultModel); - - return (errcode); + return errcode; } int DLLEXPORT ENopen(char *f1, char *f2, char *f3) { @@ -548,21 +542,55 @@ int DLLEXPORT ENdeletenode(int index) { /// allocate a project pointer int DLLEXPORT EN_alloc(EN_ProjectHandle *ph) { + int errorcode = 0; EN_Project *project = calloc(1, sizeof(EN_Project)); - *ph = project; - return 0; + if (project != NULL){ + project->error_handle = new_errormanager(&errorLookup); + *ph = project; + } + else + errorcode = -1; + + return errorcode; } int DLLEXPORT EN_free(EN_ProjectHandle *ph) { - EN_Project *p = (EN_Project*)(*ph); + int errorcode = 0; + EN_Project *p = (EN_Project*)(*ph); - free(p); + if (p == NULL) + errorcode = -1; + else + { + dst_errormanager(p->error_handle); + free(p); - *ph = NULL; + *ph = NULL; + } - return 0; + return 0; +} + +int DLLEXPORT EN_epanet(EN_ProjectHandle ph, const char *f1, const char *f2, + const char *f3, void(*pviewprog)(char *)) +{ + int errcode = 0; + EN_Project *_p = (EN_Project*)ph; + + ERRCODE(EN_open(ph, f1, f2, f3)); + + _p->viewprog = pviewprog; + if (_p->out_files.Hydflag != USE) { + ERRCODE(EN_solveH(ph)); + } + + ERRCODE(EN_solveQ(ph)); + ERRCODE(EN_report(ph)); + EN_close(ph); + + return set_error(_p->error_handle, errcode); } int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *f2, char *f3, @@ -1724,10 +1752,12 @@ int DLLEXPORT EN_getqualtype(EN_ProjectHandle ph, int *qualcode, int *tracenode) } -int DLLEXPORT EN_getqualinfo(EN_Project *p, int *qualcode, char *chemname, +int DLLEXPORT EN_getqualinfo(EN_ProjectHandle ph, int *qualcode, char *chemname, char *chemunits, int *tracenode) { - EN_getqualtype(p, qualcode, tracenode); + EN_Project *p = (EN_Project*)ph; + + EN_getqualtype(ph, qualcode, tracenode); if (p->quality.Qualflag == TRACE) { strncpy(chemname, "", MAXID); @@ -1739,6 +1769,63 @@ int DLLEXPORT EN_getqualinfo(EN_Project *p, int *qualcode, char *chemname, return 0; } +void errorLookup(int errcode, char *dest_msg, int dest_len) +// Purpose: takes error code returns error message +{ + char *msg = NULL; + + switch (errcode) + { + case 1: msg = WARN1; + break; + case 2: msg = WARN2; + break; + case 3: msg = WARN3; + break; + case 4: msg = WARN4; + break; + case 5: msg = WARN5; + break; + case 6: msg = WARN6; + break; + default: + msg = geterrmsg(errcode, msg); + } + strncpy(dest_msg, msg, MAXMSG); +} + +void DLLEXPORT EN_clearError(EN_ProjectHandle ph) +{ + EN_Project *p = (EN_Project*)ph; + + clear_error(p->error_handle); +} + +int DLLEXPORT EN_checkError(EN_ProjectHandle ph, char** msg_buffer) +// +// Purpose: Returns the error message or NULL. +// +// Note: Caller must free memory allocated by EN_check_error +// +{ + int errorcode = 0; + char *temp = NULL; + EN_Project *p = (EN_Project*)ph; + + + if (p == NULL) return -1; + else + { + errorcode = p->error_handle->error_status; + if (errorcode) + temp = check_error(p->error_handle); + + *msg_buffer = temp; + } + + return errorcode; +} + int DLLEXPORT EN_geterror(int errcode, char *errmsg, int n) { char newMsg[MAXMSG+1]; @@ -4247,11 +4334,11 @@ char *geterrmsg(int errcode, char *msg) */ { switch (errcode) { /* Warnings */ -#define DAT(code,enumer,string) case code: strcpy(msg, string); break; +#define DAT(code,enumer,string) case code: msg = string; break; #include "errors.dat" #undef DAT default: - strcpy(msg, ""); + msg = ""; } return (msg); } diff --git a/src/types.h b/src/types.h index cd64eb5..cd3fdf7 100755 --- a/src/types.h +++ b/src/types.h @@ -23,6 +23,8 @@ AUTHOR: L. Rossman #include "epanet2.h" #include "hash.h" #include "mempool.h" +#include "util/errormanager.h" + /*********************************************************/ /* All floats have been re-declared as doubles (7/3/07). */ @@ -870,6 +872,8 @@ typedef struct EN_Project { Title[MAXTITLE][MAXMSG+1], /// Problem title MapFname[MAXFNAME+1]; /// Map file name + error_handle_t* error_handle; //Simple error manager + void (* viewprog) (char *); /* Pointer to progress viewing function */ } EN_Project; diff --git a/src/util/errormanager.c b/src/util/errormanager.c new file mode 100644 index 0000000..abba233 --- /dev/null +++ b/src/util/errormanager.c @@ -0,0 +1,73 @@ +//----------------------------------------------------------------------------- +// +// errormanager.c +// +// Purpose: Provides a simple interface for managing runtime error messages. +// +// Date: 08/25/2017 +// +// Author: Michael E. Tryby +// US EPA - ORD/NRMRL +//----------------------------------------------------------------------------- +#include "errormanager.h" + +error_handle_t* new_errormanager(void (*p_error_message)(int, char*, int)) +// +// Purpose: Constructs a new error handle. +// +{ + error_handle_t* error_handle; + error_handle = (error_handle_t*)calloc(1, sizeof(error_handle_t)); + + if (error_handle != NULL) + error_handle->p_msg_lookup = p_error_message; + + return error_handle; +} + +void dst_errormanager(error_handle_t* error_handle) +// +// Purpose: Destroys the error handle. +// +{ + free(error_handle); +} + +int set_error(error_handle_t* error_handle, int errorcode) +// +// Purpose: Sets an error code in the handle. +// +{ + // If the error code is 0 no action is taken and 0 is returned. + // This is a feature not a bug. + if (errorcode) + error_handle->error_status = errorcode; + + return errorcode; +} + +char* check_error(error_handle_t* error_handle) +// +// Purpose: Returns the error message or NULL. +// +// Note: Caller must free memory allocated by check_error +// +{ + char* temp = NULL; + + if (error_handle->error_status != 0) { + temp = (char*) calloc(ERR_MAXMSG, sizeof(char)); + + if (temp) + error_handle->p_msg_lookup(error_handle->error_status, temp, ERR_MAXMSG); + } + return temp; +} + +void clear_error(error_handle_t* error_handle) +// +// Purpose: Clears the error from the handle. +// +{ + error_handle->error_status = 0; +} diff --git a/src/util/errormanager.h b/src/util/errormanager.h new file mode 100644 index 0000000..36ee969 --- /dev/null +++ b/src/util/errormanager.h @@ -0,0 +1,30 @@ +/* + * errormanager.h + * + * Created on: Aug 25, 2017 + * + * Author: Michael E. Tryby + * US EPA - ORD/NRMRL + */ + +#ifndef ERRORMANAGER_H_ +#define ERRORMANAGER_H_ + +#include +#include + +#define ERR_MAXMSG 256 + +typedef struct error_s { + int error_status; + void (*p_msg_lookup)(int, char*, int); +} error_handle_t; + +error_handle_t* new_errormanager(void (*p_error_message)(int, char*, int)); +void dst_errormanager(error_handle_t* error_handle); + +int set_error(error_handle_t* error_handle, int errorcode); +char* check_error(error_handle_t* error_handle); +void clear_error(error_handle_t* error_handle); + +#endif /* ERRORMANAGER_H_ */ diff --git a/tests/test_toolkit.cpp b/tests/test_toolkit.cpp index d01d53a..efb144c 100644 --- a/tests/test_toolkit.cpp +++ b/tests/test_toolkit.cpp @@ -69,6 +69,27 @@ BOOST_AUTO_TEST_CASE(test_epanet) BOOST_REQUIRE(error == 0); } +BOOST_AUTO_TEST_CASE(test_errormanager) +{ + char *error_msg; + EN_ProjectHandle ph = NULL; + + std::string path_inp = std::string(DATA_PATH_INP); + std::string path_rpt = std::string(DATA_PATH_RPT); + std::string path_out = std::string(DATA_PATH_RPT); + + + EN_alloc(&ph); + + EN_clearError(ph); + int error = EN_epanet(ph, path_inp.c_str(), path_rpt.c_str(), path_out.c_str(), NULL); + EN_checkError(ph, &error_msg); + + EN_free(&ph); + + free(error_msg); +} + BOOST_AUTO_TEST_SUITE_END()