diff --git a/CMakeLists.txt b/CMakeLists.txt index 59e1356..466e964 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ cmake_minimum_required (VERSION 2.8.8) project(EPANET) +add_subdirectory(run) add_subdirectory(tools/epanet-output) IF (BUILD_TESTS) @@ -51,6 +52,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + # Sets the position independent code property for all targets SET(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -66,40 +68,25 @@ IF (MSVC) ENDIF (MSVC) -#include_directories(include src) - - # configure file groups -file(GLOB EPANET_SOURCES src/*.c) -#set(EPANET_API_HEADER include/epanet2.h) -set(EPANET_CLI_SOURCES run/main.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}) -source_group("CLI" REGULAR_EXPRESSION "run/.*") # the shared library add_library(epanet SHARED ${EPANET_SOURCES}) #${EPANET_API_HEADER}) target_include_directories(epanet PUBLIC ${PROJECT_SOURCE_DIR}/include) + # create export lib so we can link against dll using Visual Studio -#include(GenerateExportHeader) -#GENERATE_EXPORT_HEADER(epanet -# BASE_NAME epanet -# EXPORT_MACRO_NAME DLLEXPORT -# EXPORT_FILE_NAME epanet_export.h -# STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC) -# -#file(COPY ${CMAKE_CURRENT_BINARY_DIR}/epanet_export.h -# DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/include) +add_definitions(-D WITH_GENX) +include(GenerateExportHeader) +GENERATE_EXPORT_HEADER(epanet + BASE_NAME epanet + EXPORT_MACRO_NAME DLLEXPORT + EXPORT_FILE_NAME epanet_export.h + STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC) - -# the standalone executable -add_executable(runepanet ${EPANET_CLI_SOURCES}) - -if(NOT MSVC) - target_link_libraries(runepanet LINK_PUBLIC epanet m) -else(NOT MSVC) - target_link_libraries(runepanet LINK_PUBLIC epanet) -endif(NOT MSVC) +file(COPY ${CMAKE_CURRENT_BINARY_DIR}/epanet_export.h + DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/include/epanet2.h b/include/epanet2.h index a709d2f..e6d91c6 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -30,37 +30,40 @@ #define EN_API_FLOAT_TYPE float #endif -// --- define WINDOWS -#undef WINDOWS -#ifdef _WIN32 - #define WINDOWS -#endif -#ifdef __WIN32__ - #define WINDOWS -#endif +#ifdef WITH_GENX + #include "epanet_export.h" +#else + // --- define WINDOWS + #undef WINDOWS + #ifdef _WIN32 + #define WINDOWS + #endif + #ifdef __WIN32__ + #define WINDOWS + #endif -// --- define DLLEXPORT -#ifndef DLLEXPORT - #ifdef WINDOWS - #ifdef __cplusplus - #define DLLEXPORT extern "C" __declspec(dllexport) - #else - #define DLLEXPORT __declspec(dllexport) __stdcall - #endif // __cplusplus - #elif defined(CYGWIN) - #define DLLEXPORT __stdcall - #elif defined(__APPLE__) - #ifdef __cplusplus - #define DLLEXPORT + // --- define DLLEXPORT + #ifndef DLLEXPORT + #ifdef WINDOWS + #ifdef __cplusplus + #define DLLEXPORT __declspec(dllexport) + #else + #define DLLEXPORT __declspec(dllexport) __stdcall + #endif // __cplusplus + #elif defined(CYGWIN) + #define DLLEXPORT __stdcall + #elif defined(__APPLE__) + #ifdef __cplusplus + #define DLLEXPORT + #else + #define DLLEXPORT + #endif #else #define DLLEXPORT #endif - #else - #define DLLEXPORT #endif #endif -//#include "epanet_export.h" // --- Define the EPANET toolkit constants @@ -276,7 +279,10 @@ extern "C" { /** @brief The EPANET Project wrapper object */ - typedef struct EN_Project EN_Project; + typedef void *EN_ProjectHandle; + + typedef struct EN_Pattern EN_Pattern; + typedef struct EN_Curve EN_Curve; /** @brief runs a complete EPANET simulation @@ -291,7 +297,8 @@ extern "C" { as it carries out its computations. If this feature is not needed then the argument should be NULL. */ - int DLLEXPORT ENepanet(char *inpFile, char *rptFile, char *binOutFile, void (*callback) (char *)); + int DLLEXPORT ENepanet(const char *inpFile, const char *rptFile, + const char *binOutFile, void (*callback) (char *)); /** @brief Initializes an EPANET session @@ -1161,108 +1168,126 @@ extern "C" { Threadsafe versions of all epanet functions ***************************************************/ - int DLLEXPORT EN_createproject(EN_Project **p); - int DLLEXPORT EN_deleteproject(EN_Project *p); + int DLLEXPORT EN_createproject(EN_ProjectHandle *ph); + int DLLEXPORT EN_deleteproject(EN_ProjectHandle *ph); - int DLLEXPORT EN_epanet(char *inpFile, char *rptFile, char *binOutFile, void (*callback) (char *)); - int DLLEXPORT EN_init(EN_Project *p, char *rptFile, char *binOutFile, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula); - int DLLEXPORT EN_open(EN_Project *p, char *inpFile, char *rptFile, char *binOutFile); - int DLLEXPORT EN_saveinpfile(EN_Project *p, char *filename); - int DLLEXPORT EN_close(EN_Project *p); - int DLLEXPORT EN_solveH(EN_Project *p); - int DLLEXPORT EN_saveH(EN_Project *p); - int DLLEXPORT EN_openH(EN_Project *p); - int DLLEXPORT EN_initH(EN_Project *p, int EN_SaveOption); - int DLLEXPORT EN_runH(EN_Project *p, long *currentTime); - int DLLEXPORT EN_nextH(EN_Project *p, long *tStep); - int DLLEXPORT EN_closeH(EN_Project *p); - int DLLEXPORT EN_savehydfile(EN_Project *p, char *filename); - int DLLEXPORT EN_usehydfile(EN_Project *p, char *filename); - int DLLEXPORT EN_solveQ(EN_Project *p); - int DLLEXPORT EN_openQ(EN_Project *p); - int DLLEXPORT EN_initQ(EN_Project *p, int saveFlag); - int DLLEXPORT EN_runQ(EN_Project *p, long *currentTime); - int DLLEXPORT EN_nextQ(EN_Project *p, long *tStep); - int DLLEXPORT EN_stepQ(EN_Project *p, long *timeLeft); - int DLLEXPORT EN_closeQ(EN_Project *p); - int DLLEXPORT EN_writeline(EN_Project *p, char *line); - int DLLEXPORT EN_report(EN_Project *p); - int DLLEXPORT EN_resetreport(EN_Project *p); - int DLLEXPORT EN_setreport(EN_Project *p, char *reportFormat); - int DLLEXPORT EN_getcontrol(EN_Project *p, int controlIndex, int *controlType, int *linkIndex, EN_API_FLOAT_TYPE *setting, int *nodeIndex, EN_API_FLOAT_TYPE *level); - int DLLEXPORT EN_getcount(EN_Project *p, EN_CountType code, int *count); - int DLLEXPORT EN_getoption(EN_Project *p, EN_Option opt, EN_API_FLOAT_TYPE *value); - int DLLEXPORT EN_gettimeparam(EN_Project *p, int code, long *value); - int DLLEXPORT EN_getflowunits(EN_Project *p, int *code); - int DLLEXPORT EN_setflowunits(EN_Project *p, int code); - int DLLEXPORT EN_getdemandmodel(EN_Project *p, int *type, EN_API_FLOAT_TYPE *pmin, EN_API_FLOAT_TYPE *preq, - EN_API_FLOAT_TYPE *pexp); - int DLLEXPORT EN_setdemandmodel(EN_Project *p, int type, EN_API_FLOAT_TYPE pmin, EN_API_FLOAT_TYPE preq, - EN_API_FLOAT_TYPE pexp); - int DLLEXPORT EN_getpatternindex(EN_Project *p, char *id, int *index); - int DLLEXPORT EN_getpatternid(EN_Project *p, int index, char *id); - int DLLEXPORT EN_getpatternlen(EN_Project *p, int index, int *len); - int DLLEXPORT EN_getpatternvalue(EN_Project *p, int index, int period, EN_API_FLOAT_TYPE *value); - int DLLEXPORT EN_getaveragepatternvalue(EN_Project *p, int index, EN_API_FLOAT_TYPE *value); - int DLLEXPORT EN_getqualtype(EN_Project *p, int *qualcode, int *tracenode); + void DLLEXPORT EN_clearError(EN_ProjectHandle ph); + int DLLEXPORT EN_checkError(EN_ProjectHandle ph, char** msg_buffer); + + //int DLLEXPORT EN_epanet(EN_ProjectHandle ph, const char *f1, const char *f2, + // const char *f3, void(*pviewprog)(char *)); + int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *rptFile, char *binOutFile, + EN_FlowUnits UnitsType, EN_FormType HeadlossFormula); + + int DLLEXPORT EN_open(EN_ProjectHandle ph, const char *inpFile, + const char *rptFile, const char *binOutFile); + + int DLLEXPORT EN_saveinpfile(EN_ProjectHandle ph, char *filename); + + int DLLEXPORT EN_close(EN_ProjectHandle ph); + int DLLEXPORT EN_solveH(EN_ProjectHandle ph); + + int DLLEXPORT EN_saveH(EN_ProjectHandle ph); + int DLLEXPORT EN_openH(EN_ProjectHandle ph); + int DLLEXPORT EN_initH(EN_ProjectHandle ph, int EN_SaveOption); + int DLLEXPORT EN_runH(EN_ProjectHandle ph, long *currentTime); + int DLLEXPORT EN_nextH(EN_ProjectHandle ph, long *tStep); + int DLLEXPORT EN_closeH(EN_ProjectHandle ph); + int DLLEXPORT EN_savehydfile(EN_ProjectHandle ph, char *filename); + int DLLEXPORT EN_usehydfile(EN_ProjectHandle ph, char *filename); + + int DLLEXPORT EN_solveQ(EN_ProjectHandle ph); + int DLLEXPORT EN_openQ(EN_ProjectHandle ph); + int DLLEXPORT EN_initQ(EN_ProjectHandle ph, int saveFlag); + int DLLEXPORT EN_runQ(EN_ProjectHandle ph, long *currentTime); + int DLLEXPORT EN_nextQ(EN_ProjectHandle ph, long *tStep); + int DLLEXPORT EN_stepQ(EN_ProjectHandle ph, long *timeLeft); + int DLLEXPORT EN_closeQ(EN_ProjectHandle ph); + int DLLEXPORT EN_writeline(EN_ProjectHandle ph, char *line); + + int DLLEXPORT EN_report(EN_ProjectHandle ph); + int DLLEXPORT EN_resetreport(EN_ProjectHandle ph); + int DLLEXPORT EN_setreport(EN_ProjectHandle ph, char *reportFormat); + + int DLLEXPORT EN_getcontrol(EN_ProjectHandle ph, int controlIndex, int *controlType, int *linkIndex, EN_API_FLOAT_TYPE *setting, int *nodeIndex, EN_API_FLOAT_TYPE *level); + int DLLEXPORT EN_getcount(EN_ProjectHandle ph, EN_CountType code, int *count); + int DLLEXPORT EN_getoption(EN_ProjectHandle ph, EN_Option opt, EN_API_FLOAT_TYPE *value); + int DLLEXPORT EN_gettimeparam(EN_ProjectHandle ph, int code, long *value); + int DLLEXPORT EN_getflowunits(EN_ProjectHandle ph, int *code); + int DLLEXPORT EN_setflowunits(EN_ProjectHandle ph, int code); + int DLLEXPORT EN_getpatternindex(EN_ProjectHandle ph, char *id, int *index); + int DLLEXPORT EN_getpatternid(EN_ProjectHandle ph, int index, char *id); + int DLLEXPORT EN_getpatternlen(EN_ProjectHandle ph, int index, int *len); + int DLLEXPORT EN_getpatternvalue(EN_ProjectHandle ph, int index, int period, EN_API_FLOAT_TYPE *value); + int DLLEXPORT EN_getaveragepatternvalue(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *value); + int DLLEXPORT EN_getqualtype(EN_ProjectHandle ph, int *qualcode, int *tracenode); int DLLEXPORT EN_geterror(int errcode, char *errmsg, int maxLen); - int DLLEXPORT EN_getstatistic(EN_Project *p, int code, EN_API_FLOAT_TYPE* value); - int DLLEXPORT EN_getnodeindex(EN_Project *p, char *id, int *index); - int DLLEXPORT EN_getnodeid(EN_Project *p, int index, char *id); - int DLLEXPORT EN_getnodetype(EN_Project *p, int index, int *code); - int DLLEXPORT EN_getnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_TYPE *value); - int DLLEXPORT EN_getcoord(EN_Project *p, int index, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y); - int DLLEXPORT EN_setcoord(EN_Project *p, int index, EN_API_FLOAT_TYPE x, EN_API_FLOAT_TYPE y); - int DLLEXPORT EN_getnumdemands(EN_Project *p, int nodeIndex, int *numDemands); - int DLLEXPORT EN_getbasedemand(EN_Project *p, int nodeIndex, int demandIndex, EN_API_FLOAT_TYPE *baseDemand); - int DLLEXPORT EN_getdemandpattern(EN_Project *p, int nodeIndex, int demandIndex, int *pattIndex); - int DLLEXPORT EN_getlinkindex(EN_Project *p, char *id, int *index); - int DLLEXPORT EN_getlinkid(EN_Project *p, int index, char *id); - int DLLEXPORT EN_getlinktype(EN_Project *p, int index, EN_LinkType *code); - int DLLEXPORT EN_setlinktype(EN_Project *p, char *id, EN_LinkType type); - int DLLEXPORT EN_getlinknodes(EN_Project *p, int index, int *node1, int *node2); - int DLLEXPORT EN_getlinkvalue(EN_Project *p, int index, EN_LinkProperty code, EN_API_FLOAT_TYPE *value); - int DLLEXPORT EN_getcurve(EN_Project *p, int curveIndex, char* id, int *nValues, EN_API_FLOAT_TYPE **xValues, EN_API_FLOAT_TYPE **yValues); - int DLLEXPORT EN_getheadcurveindex(EN_Project *p, int pumpIndex, int *curveIndex); - int DLLEXPORT EN_setheadcurveindex(EN_Project *p, int pumpIndex, int curveIndex); - int DLLEXPORT EN_getpumptype(EN_Project *p, int linkIndex, int *outType); - int DLLEXPORT EN_getcurvetype(EN_Project *p, int curveIndex, int *outType); + + int DLLEXPORT EN_getstatistic(EN_ProjectHandle ph, int code, EN_API_FLOAT_TYPE* value); + int DLLEXPORT EN_getnodeindex(EN_ProjectHandle ph, char *id, int *index); + int DLLEXPORT EN_getnodeid(EN_ProjectHandle ph, int index, char *id); + int DLLEXPORT EN_getnodetype(EN_ProjectHandle ph, int index, int *code); + int DLLEXPORT EN_getnodevalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE *value); + int DLLEXPORT EN_getcoord(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y); + int DLLEXPORT EN_setcoord(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE x, EN_API_FLOAT_TYPE y); + int DLLEXPORT EN_getnumdemands(EN_ProjectHandle ph, int nodeIndex, int *numDemands); + int DLLEXPORT EN_getbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIndex, EN_API_FLOAT_TYPE *baseDemand); + int DLLEXPORT EN_getdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demandIndex, int *pattIndex); + int DLLEXPORT EN_getlinkindex(EN_ProjectHandle ph, char *id, int *index); + int DLLEXPORT EN_getlinkid(EN_ProjectHandle ph, int index, char *id); + int DLLEXPORT EN_getlinktype(EN_ProjectHandle ph, int index, EN_LinkType *code); + int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, char *id, EN_LinkType type); + int DLLEXPORT EN_getlinknodes(EN_ProjectHandle ph, int index, int *node1, int *node2); + int DLLEXPORT EN_getlinkvalue(EN_ProjectHandle ph, int index, EN_LinkProperty code, EN_API_FLOAT_TYPE *value); + int DLLEXPORT EN_getcurve(EN_ProjectHandle ph, int curveIndex, char* id, int *nValues, EN_API_FLOAT_TYPE **xValues, EN_API_FLOAT_TYPE **yValues); + int DLLEXPORT EN_getheadcurveindex(EN_ProjectHandle ph, int pumpIndex, int *curveIndex); + int DLLEXPORT EN_setheadcurveindex(EN_ProjectHandle ph, int pumpIndex, int curveIndex); + int DLLEXPORT EN_getpumptype(EN_ProjectHandle ph, int linkIndex, int *outType); + int DLLEXPORT EN_getcurvetype(EN_ProjectHandle ph, int curveIndex, int *outType); + int DLLEXPORT EN_getversion(int *version); - int DLLEXPORT EN_setcontrol(EN_Project *p, int cindex, int ctype, int lindex, EN_API_FLOAT_TYPE setting, int nindex, EN_API_FLOAT_TYPE level); - int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_TYPE v); - int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, EN_API_FLOAT_TYPE v); - int DLLEXPORT EN_addpattern(EN_Project *p, char *id); - int DLLEXPORT EN_setpattern(EN_Project *p, int index, EN_API_FLOAT_TYPE *f, int len); - int DLLEXPORT EN_setpatternvalue(EN_Project *p, int index, int period, EN_API_FLOAT_TYPE value); - int DLLEXPORT EN_settimeparam(EN_Project *p, int code, long value); - int DLLEXPORT EN_setoption(EN_Project *p, int code, EN_API_FLOAT_TYPE v); - int DLLEXPORT EN_setstatusreport(EN_Project *p, int code); - int DLLEXPORT EN_setqualtype(EN_Project *p, int qualcode, char *chemname, char *chemunits, char *tracenode); - int DLLEXPORT EN_getqualinfo(EN_Project *p, int *qualcode, char *chemname, char *chemunits, int *tracenode); - int DLLEXPORT EN_setbasedemand(EN_Project *p, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE baseDemand); - int DLLEXPORT EN_getcurveindex(EN_Project *p, char *id, int *index); - int DLLEXPORT EN_getcurveid(EN_Project *p, int index, char *id); - int DLLEXPORT EN_getcurvelen(EN_Project *p, int index, int *len); - int DLLEXPORT EN_getcurvevalue(EN_Project *p, int curveIndex, int pointIndex, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y); - int DLLEXPORT EN_setcurvevalue(EN_Project *p, int curveIndex, int pointIndex, EN_API_FLOAT_TYPE x, EN_API_FLOAT_TYPE y); - int DLLEXPORT EN_setcurve(EN_Project *p, int index, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y, int len); - int DLLEXPORT EN_addcurve(EN_Project *p, char *id); - int DLLEXPORT EN_getrule(EN_Project *p, int index, int *nPremises, int *nTrueActions, int *nFalseActions, EN_API_FLOAT_TYPE *priority); - int DLLEXPORT EN_setrulepriority(EN_Project *p, int index, EN_API_FLOAT_TYPE priority); - int DLLEXPORT EN_getpremise(EN_Project *p, int indexRule, int indexPremise, int *logop, int *object, int *indexObj, int *variable, int *relop, int *status, EN_API_FLOAT_TYPE *value); - int DLLEXPORT EN_setpremise(EN_Project *p, int indexRule, int indexPremise, int logop, int object, int indexObj, int variable, int relop, int status, EN_API_FLOAT_TYPE value); - int DLLEXPORT EN_setpremiseindex(EN_Project *p, int indexRule, int indexPremise, int indexObj); - int DLLEXPORT EN_setpremisestatus(EN_Project *p, int indexRule, int indexPremise, int status); - int DLLEXPORT EN_setpremisevalue(EN_Project *p, int indexRule, int indexPremise, EN_API_FLOAT_TYPE value); - int DLLEXPORT EN_gettrueaction(EN_Project *p, int indexRule, int indexAction, int *indexLink, int *status, EN_API_FLOAT_TYPE *setting); - int DLLEXPORT EN_settrueaction(EN_Project *p, int indexRule, int indexAction, int indexLink, int status, EN_API_FLOAT_TYPE setting); - int DLLEXPORT EN_getfalseaction(EN_Project *p, int indexRule, int indexAction, int *indexLink, int *status, EN_API_FLOAT_TYPE *setting); - int DLLEXPORT EN_setfalseaction(EN_Project *p, int indexRule, int indexAction, int indexLink, int status, EN_API_FLOAT_TYPE setting); - int DLLEXPORT EN_getruleID(EN_Project *p, int indexRule, char* id); - int DLLEXPORT EN_addnode(EN_Project *p, char *id, EN_NodeType nodeType); - int DLLEXPORT EN_addlink(EN_Project *p, char *id, EN_LinkType linkType, char *fromNode, char *toNode); - int DLLEXPORT EN_deletenode(EN_Project *p, int nodeIndex); - int DLLEXPORT EN_deletelink(EN_Project *p, int linkIndex); + + int DLLEXPORT EN_setcontrol(EN_ProjectHandle ph, int cindex, int ctype, int lindex, EN_API_FLOAT_TYPE setting, int nindex, EN_API_FLOAT_TYPE level); + int DLLEXPORT EN_setnodevalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE v); + int DLLEXPORT EN_setlinkvalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE v); + int DLLEXPORT EN_addpattern(EN_ProjectHandle ph, char *id); + int DLLEXPORT EN_setpattern(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *f, int len); + int DLLEXPORT EN_setpatternvalue(EN_ProjectHandle ph, int index, int period, EN_API_FLOAT_TYPE value); + int DLLEXPORT EN_settimeparam(EN_ProjectHandle ph, int code, long value); + int DLLEXPORT EN_setoption(EN_ProjectHandle ph, int code, EN_API_FLOAT_TYPE v); + int DLLEXPORT EN_setstatusreport(EN_ProjectHandle ph, int code); + int DLLEXPORT EN_setqualtype(EN_ProjectHandle ph, int qualcode, char *chemname, char *chemunits, char *tracenode); + + int DLLEXPORT EN_getdemandmodel(EN_ProjectHandle ph, int *type, EN_API_FLOAT_TYPE *pmin, + EN_API_FLOAT_TYPE *preq, EN_API_FLOAT_TYPE *pexp); + int DLLEXPORT EN_setdemandmodel(EN_ProjectHandle ph, int type, EN_API_FLOAT_TYPE pmin, + EN_API_FLOAT_TYPE preq, EN_API_FLOAT_TYPE pexp); + + int DLLEXPORT EN_getqualinfo(EN_ProjectHandle ph, int *qualcode, char *chemname, char *chemunits, int *tracenode); + int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE baseDemand); + int DLLEXPORT EN_getcurveindex(EN_ProjectHandle ph, char *id, int *index); + int DLLEXPORT EN_getcurveid(EN_ProjectHandle ph, int index, char *id); + int DLLEXPORT EN_getcurvelen(EN_ProjectHandle ph, int index, int *len); + int DLLEXPORT EN_getcurvevalue(EN_ProjectHandle ph, int curveIndex, int pointIndex, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y); + int DLLEXPORT EN_setcurvevalue(EN_ProjectHandle ph, int curveIndex, int pointIndex, EN_API_FLOAT_TYPE x, EN_API_FLOAT_TYPE y); + int DLLEXPORT EN_setcurve(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y, int len); + int DLLEXPORT EN_addcurve(EN_ProjectHandle ph, char *id); + int DLLEXPORT EN_getrule(EN_ProjectHandle ph, int index, int *nPremises, int *nTrueActions, int *nFalseActions, EN_API_FLOAT_TYPE *priority); + int DLLEXPORT EN_setrulepriority(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE priority); + int DLLEXPORT EN_getpremise(EN_ProjectHandle ph, int indexRule, int indexPremise, int *logop, int *object, int *indexObj, int *variable, int *relop, int *status, EN_API_FLOAT_TYPE *value); + int DLLEXPORT EN_setpremise(EN_ProjectHandle ph, int indexRule, int indexPremise, int logop, int object, int indexObj, int variable, int relop, int status, EN_API_FLOAT_TYPE value); + int DLLEXPORT EN_setpremiseindex(EN_ProjectHandle ph, int indexRule, int indexPremise, int indexObj); + int DLLEXPORT EN_setpremisestatus(EN_ProjectHandle ph, int indexRule, int indexPremise, int status); + int DLLEXPORT EN_setpremisevalue(EN_ProjectHandle ph, int indexRule, int indexPremise, EN_API_FLOAT_TYPE value); + int DLLEXPORT EN_gettrueaction(EN_ProjectHandle ph, int indexRule, int indexAction, int *indexLink, int *status, EN_API_FLOAT_TYPE *setting); + int DLLEXPORT EN_settrueaction(EN_ProjectHandle ph, int indexRule, int indexAction, int indexLink, int status, EN_API_FLOAT_TYPE setting); + int DLLEXPORT EN_getfalseaction(EN_ProjectHandle ph, int indexRule, int indexAction, int *indexLink, int *status, EN_API_FLOAT_TYPE *setting); + int DLLEXPORT EN_setfalseaction(EN_ProjectHandle ph, int indexRule, int indexAction, int indexLink, int status, EN_API_FLOAT_TYPE setting); + int DLLEXPORT EN_getruleID(EN_ProjectHandle ph, int indexRule, char* id); + int DLLEXPORT EN_addnode(EN_ProjectHandle ph, char *id, EN_NodeType nodeType); + int DLLEXPORT EN_addlink(EN_ProjectHandle ph, char *id, EN_LinkType linkType, char *fromNode, char *toNode); + int DLLEXPORT EN_deletenode(EN_ProjectHandle ph, int nodeIndex); + int DLLEXPORT EN_deletelink(EN_ProjectHandle ph, int linkIndex); #if defined(__cplusplus) } diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt new file mode 100644 index 0000000..53e792b --- /dev/null +++ b/run/CMakeLists.txt @@ -0,0 +1,28 @@ +# EPANET COMMAND LINE EXECUTABLE +cmake_minimum_required (VERSION 3.0.2) + + +# Sets for output directory for executables and libraries. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + +# Sets the position independent code property for all targets. +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + + +# Set up file groups for exe target +set(EPANET_CLI_SOURCES main.c) +include_directories(include) + +source_group("CLI" FILES ${EPANET_CLI_SOURCES}) + + +# Creates the EPANET command line executable +add_definitions(-D WITH_GENX) +add_executable(runepanet ${EPANET_CLI_SOURCES}) +if(NOT WIN32) + target_link_libraries(runepanet LINK_PUBLIC epanet m) +else(NOT WIN32) + target_link_libraries(runepanet LINK_PUBLIC epanet) +endif(NOT WIN32) diff --git a/src/epanet.c b/src/epanet.c index a0ab719..6463c08 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -134,6 +134,10 @@ execute function x and set the error code equal to its return value. // in "legacy mode" with the 2.1-style API. EN_Project *_defaultModel; + +// Local functions +void errorLookup(int errcode, char *errmsg, int len); + /**************************************************************** LEGACY (v <= 2.1) API: uses global project variable @@ -157,19 +161,24 @@ EN_Project *_defaultModel; ** needed then the argument should be NULL. **------------------------------------------------------------------------- */ -int DLLEXPORT ENepanet(char *f1, char *f2, char *f3, - void (*pviewprog)(char *)) { +int DLLEXPORT ENepanet(const char *f1, const char *f2, const char *f3, void (*pviewprog)(char *)) +{ int errcode = 0; + ERRCODE(EN_createproject(&_defaultModel)); ERRCODE(EN_open(_defaultModel, f1, f2, f3)); _defaultModel->viewprog = pviewprog; + if (_defaultModel->out_files.Hydflag != USE) { ERRCODE(EN_solveH(_defaultModel)); } + ERRCODE(EN_solveQ(_defaultModel)); ERRCODE(EN_report(_defaultModel)); + EN_close(_defaultModel); - EN_deleteproject(_defaultModel); + EN_deleteproject(&_defaultModel); + return (errcode); } @@ -184,10 +193,7 @@ int DLLEXPORT ENsaveinpfile(char *filename) { return EN_saveinpfile(_defaultModel, filename); } -int DLLEXPORT ENclose() { - EN_close(_defaultModel); - return EN_deleteproject(_defaultModel); -} +int DLLEXPORT ENclose() { return EN_close(_defaultModel); } int DLLEXPORT ENsolveH() { return EN_solveH(_defaultModel); } @@ -550,36 +556,50 @@ int DLLEXPORT ENdeletenode(int index) { return EN_deletenode(_defaultModel, index); } - -int DLLEXPORT EN_epanet(char *inpFile, char *rptFile, char *binOutFile, void(*callback) (char *)) -{ - return ENepanet(inpFile, rptFile, binOutFile, callback); -} - /* ---------------------------------------------------------------- Functions for opening & closing the EPANET system ---------------------------------------------------------------- */ -/// Create an EPANET project -int DLLEXPORT EN_createproject(EN_Project **p) +/// allocate a project pointer +int DLLEXPORT EN_createproject(EN_ProjectHandle *ph) +// Note: No error handling available until project allocation { - EN_Project *project = calloc(1, sizeof(EN_Project)); - if (project == NULL) return 101; - *p = project; + int errorcode = 0; + EN_Project *project = calloc(1, sizeof(EN_Project)); + + if (project != NULL){ + project->error_handle = new_errormanager(&errorLookup); + *ph = project; + } + else + errorcode = -1; + + return errorcode; +} + +int DLLEXPORT EN_deleteproject(EN_ProjectHandle *ph) +// Note: No error handling available after project deallocation +{ + int errorcode = 0; + EN_Project *p = (EN_Project*)(*ph); + + if (p == NULL) + errorcode = -1; + else + { + dst_errormanager(p->error_handle); + free(p); + + *ph = NULL; + } + return 0; } -/// Delete an EPANET project -int DLLEXPORT EN_deleteproject(EN_Project *p) -{ - if (p) free(p); - p = NULL; - return 0; -} -int DLLEXPORT EN_init(EN_Project *pr, char *f2, char *f3, +int DLLEXPORT EN_init(EN_ProjectHandle *ph, char *f2, char *f3, EN_FlowUnits UnitsType, EN_FormType HeadlossFormula) /*---------------------------------------------------------------- ** Input: @@ -600,6 +620,8 @@ int DLLEXPORT EN_init(EN_Project *pr, char *f2, char *f3, _fpreset(); #endif + EN_Project *pr = (EN_Project*)*ph; + /* Set system flags */ pr->Openflag = TRUE; pr->hydraulics.OpenHflag = FALSE; @@ -634,10 +656,10 @@ int DLLEXPORT EN_init(EN_Project *pr, char *f2, char *f3, // initialize default pattern getpatterns(pr); - return (errcode); + return set_error(pr->error_handle, errcode); } -int DLLEXPORT EN_open(EN_Project *p, char *f1, char *f2, char *f3) +int DLLEXPORT EN_open(EN_ProjectHandle ph, const char *f1, const char *f2, const char *f3) /*---------------------------------------------------------------- ** Input: f1 = pointer to name of input file ** f2 = pointer to name of report file @@ -656,6 +678,8 @@ int DLLEXPORT EN_open(EN_Project *p, char *f1, char *f2, char *f3) _fpreset(); #endif + EN_Project *p = (EN_Project*)ph; + /* Set system flags */ p->Openflag = FALSE; p->hydraulics.OpenHflag = FALSE; @@ -676,7 +700,7 @@ int DLLEXPORT EN_open(EN_Project *p, char *f1, char *f2, char *f3) ERRCODE(openfiles(p, f1, f2, f3)); if (errcode > 0) { errmsg(p, errcode); - return (errcode); + return set_error(p->error_handle, errcode); } writelogo(p); @@ -707,10 +731,10 @@ int DLLEXPORT EN_open(EN_Project *p, char *f1, char *f2, char *f3) p->Openflag = TRUE; } else errmsg(p, errcode); - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_saveinpfile(EN_Project *p, char *filename) +int DLLEXPORT EN_saveinpfile(EN_ProjectHandle ph, char *filename) /*---------------------------------------------------------------- ** Input: filename = name of INP file ** Output: none @@ -719,12 +743,15 @@ int DLLEXPORT EN_saveinpfile(EN_Project *p, char *filename) **---------------------------------------------------------------- */ { + EN_Project *p = (EN_Project*)ph; + if (!p->Openflag) - return (102); - return (saveinpfile(p, filename)); + return set_error(p->error_handle, 102); + + return set_error(p->error_handle, saveinpfile(p, filename)); } -int DLLEXPORT EN_close(EN_Project *p) +int DLLEXPORT EN_close(EN_ProjectHandle ph) /*---------------------------------------------------------------- ** Input: none ** Output: none @@ -734,6 +761,8 @@ int DLLEXPORT EN_close(EN_Project *p) */ { out_file_t *out; + + EN_Project *p = (EN_Project*)ph; if (p->Openflag) { writetime(p, FMT105); @@ -777,7 +806,8 @@ int DLLEXPORT EN_close(EN_Project *p) p->save_options.SaveHflag = FALSE; p->quality.OpenQflag = FALSE; p->save_options.SaveQflag = FALSE; - return (0); + + return set_error(p->error_handle, 0); } /* @@ -786,7 +816,7 @@ int DLLEXPORT EN_close(EN_Project *p) ---------------------------------------------------------------- */ -int DLLEXPORT EN_solveH(EN_Project *p) +int DLLEXPORT EN_solveH(EN_ProjectHandle ph) /*---------------------------------------------------------------- ** Input: none ** Output: none @@ -798,11 +828,13 @@ int DLLEXPORT EN_solveH(EN_Project *p) int errcode; long t, tstep; + EN_Project *p = (EN_Project*)ph; + /* Open hydraulics solver */ - errcode = EN_openH(p); + errcode = EN_openH(ph); if (!errcode) { /* Initialize hydraulics */ - errcode = EN_initH(p, EN_SAVE); + errcode = EN_initH(ph, EN_SAVE); writecon(FMT14); /* Analyze each hydraulic period */ @@ -821,8 +853,8 @@ int DLLEXPORT EN_solveH(EN_Project *p) /* Solve for hydraulics & advance to next time period */ tstep = 0; - ERRCODE(EN_runH(p, &t)); - ERRCODE(EN_nextH(p, &tstep)); + ERRCODE(EN_runH(ph, &t)); + ERRCODE(EN_nextH(ph, &tstep)); /*** Updated 6/24/02 ***/ writecon("\b\b\b\b\b\b\b\b\b\b"); } while (tstep > 0); @@ -833,12 +865,13 @@ int DLLEXPORT EN_solveH(EN_Project *p) /*** Updated 6/24/02 ***/ writecon("\b\b\b\b\b\b\b\b "); - EN_closeH(p); + EN_closeH(ph); errcode = MAX(errcode, p->Warnflag); - return (errcode); + + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_saveH(EN_Project *p) +int DLLEXPORT EN_saveH(EN_ProjectHandle ph) /*---------------------------------------------------------------- ** Input: none ** Output: none @@ -853,9 +886,11 @@ int DLLEXPORT EN_saveH(EN_Project *p) char tmpflag; int errcode; + EN_Project *p = (EN_Project*)ph; + /* Check if hydraulic results exist */ if (!p->save_options.SaveHflag) - return (104); + return set_error(p->error_handle, 104); /* Temporarily turn off WQ analysis */ tmpflag = p->quality.Qualflag; @@ -871,10 +906,10 @@ int DLLEXPORT EN_saveH(EN_Project *p) if (errcode) { errmsg(p, errcode); } - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_openH(EN_Project *p) +int DLLEXPORT EN_openH(EN_ProjectHandle ph) /*---------------------------------------------------------------- ** Input: none ** Output: none @@ -885,16 +920,18 @@ int DLLEXPORT EN_openH(EN_Project *p) { int errcode = 0; + EN_Project *p = (EN_Project*)ph; + /* Check that input data exists */ p->hydraulics.OpenHflag = FALSE; p->save_options.SaveHflag = FALSE; if (!p->Openflag) { - return (102); + return set_error(p->error_handle, 102); } /* Check that previously saved hydraulics file not in use */ if (p->out_files.Hydflag == USE) { - return (107); + return set_error(p->error_handle, 107); } /* Open hydraulics solver */ @@ -903,11 +940,12 @@ int DLLEXPORT EN_openH(EN_Project *p) p->hydraulics.OpenHflag = TRUE; else errmsg(p, errcode); - return (errcode); + + return set_error(p->error_handle, errcode); } /*** Updated 3/1/01 ***/ -int DLLEXPORT EN_initH(EN_Project *p, int flag) +int DLLEXPORT EN_initH(EN_ProjectHandle ph, int flag) /*---------------------------------------------------------------- ** Input: flag = 2-digit flag where 1st (left) digit indicates ** if link flows should be re-initialized (1) or @@ -922,6 +960,8 @@ int DLLEXPORT EN_initH(EN_Project *p, int flag) int errcode = 0; int sflag, fflag; + EN_Project *p = (EN_Project*)ph; + /* Reset status flags */ p->save_options.SaveHflag = FALSE; p->Warnflag = FALSE; @@ -932,7 +972,7 @@ int DLLEXPORT EN_initH(EN_Project *p, int flag) /* Check that hydraulics solver was opened */ if (!p->hydraulics.OpenHflag) - return (103); + return set_error(p->error_handle, 103); /* Open hydraulics file */ p->save_options.Saveflag = FALSE; @@ -942,7 +982,7 @@ int DLLEXPORT EN_initH(EN_Project *p, int flag) p->save_options.Saveflag = TRUE; else { errmsg(p, errcode); - return errcode; + return set_error(p->error_handle, errcode); } } @@ -950,57 +990,67 @@ int DLLEXPORT EN_initH(EN_Project *p, int flag) inithyd(p, fflag); if (p->report.Statflag > 0) writeheader(p, STATHDR, 0); - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_runH(EN_Project *p, long *t) { +int DLLEXPORT EN_runH(EN_ProjectHandle ph, long *t) { int errcode; + + EN_Project *p = (EN_Project*)ph; + *t = 0; if (!p->hydraulics.OpenHflag) - return (103); + return set_error(p->error_handle, 103); errcode = runhyd(p, t); if (errcode) errmsg(p, errcode); - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_nextH(EN_Project *p, long *tstep) { +int DLLEXPORT EN_nextH(EN_ProjectHandle ph, long *tstep) { int errcode; + + EN_Project *p = (EN_Project*)ph; + *tstep = 0; if (!p->hydraulics.OpenHflag) - return (103); + return set_error(p->error_handle, 103); errcode = nexthyd(p, tstep); if (errcode) errmsg(p, errcode); else if (p->save_options.Saveflag && *tstep == 0) p->save_options.SaveHflag = TRUE; - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_closeH(EN_Project *p) +int DLLEXPORT EN_closeH(EN_ProjectHandle ph) { + EN_Project *p = (EN_Project*)ph; + if (!p->Openflag) { - return (102); + return set_error(p->error_handle, 102); } if (p->hydraulics.OpenHflag) { closehyd(p); } p->hydraulics.OpenHflag = FALSE; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_savehydfile(EN_Project *p, char *filename) { +int DLLEXPORT EN_savehydfile(EN_ProjectHandle ph, char *filename) { FILE *f; int c; FILE *HydFile; + EN_Project *p = (EN_Project*)ph; + /* Check that hydraulics results exist */ if (p->out_files.HydFile == NULL || !p->save_options.SaveHflag) - return (104); + return set_error(p->error_handle, 104); /* Open file */ if ((f = fopen(filename, "w+b")) == NULL) - return (305); + return set_error(p->error_handle, 305); /* Copy from HydFile to f */ HydFile = p->out_files.HydFile; @@ -1009,17 +1059,19 @@ int DLLEXPORT EN_savehydfile(EN_Project *p, char *filename) { fputc(c, f); } fclose(f); - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_usehydfile(EN_Project *p, char *filename) { +int DLLEXPORT EN_usehydfile(EN_ProjectHandle ph, char *filename) { int errcode; + EN_Project *p = (EN_Project*)ph; + /* Check that input data exists & hydraulics system closed */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (p->hydraulics.OpenHflag) - return (108); + return set_error(p->error_handle, 108); /* Try to open hydraulics file */ strncpy(p->out_files.HydFname, filename, MAXFNAME); @@ -1033,7 +1085,7 @@ int DLLEXPORT EN_usehydfile(EN_Project *p, char *filename) { p->out_files.Hydflag = SCRATCH; p->save_options.SaveHflag = FALSE; } - return (errcode); + return set_error(p->error_handle, errcode); } /* @@ -1042,15 +1094,17 @@ int DLLEXPORT EN_usehydfile(EN_Project *p, char *filename) { ---------------------------------------------------------------- */ -int DLLEXPORT EN_solveQ(EN_Project *p) { +int DLLEXPORT EN_solveQ(EN_ProjectHandle ph) { int errcode; long t, tstep; + EN_Project *p = (EN_Project*)ph; + /* Open WQ solver */ - errcode = EN_openQ(p); + errcode = EN_openQ(ph); if (!errcode) { /* Initialize WQ */ - errcode = EN_initQ(p, EN_SAVE); + errcode = EN_initQ(ph, EN_SAVE); if (p->quality.Qualflag) writecon(FMT15); else { @@ -1076,8 +1130,8 @@ int DLLEXPORT EN_solveQ(EN_Project *p) { /* Retrieve current network solution & update WQ to next time period */ tstep = 0; - ERRCODE(EN_runQ(p, &t)); - ERRCODE(EN_nextQ(p, &tstep)); + ERRCODE(EN_runQ(ph, &t)); + ERRCODE(EN_nextQ(ph, &tstep)); /*** Updated 6/24/02 ***/ writecon("\b\b\b\b\b\b\b\b\b\b"); @@ -1089,18 +1143,20 @@ int DLLEXPORT EN_solveQ(EN_Project *p) { /*** Updated 6/24/02 ***/ writecon("\b\b\b\b\b\b\b\b "); - EN_closeQ(p); - return (errcode); + EN_closeQ(ph); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_openQ(EN_Project *p) { +int DLLEXPORT EN_openQ(EN_ProjectHandle ph) { int errcode = 0; + EN_Project *p = (EN_Project*)ph; + /* Check that hydraulics results exist */ p->quality.OpenQflag = FALSE; p->save_options.SaveQflag = FALSE; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); // !LT! todo - check for p->save_options.SaveHflag / set sequential/step mode // if (!p->save_options.SaveHflag) return(104); @@ -1110,13 +1166,16 @@ int DLLEXPORT EN_openQ(EN_Project *p) { p->quality.OpenQflag = TRUE; else errmsg(p, errcode); - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_initQ(EN_Project *p, int saveflag) { +int DLLEXPORT EN_initQ(EN_ProjectHandle ph, int saveflag) { int errcode = 0; + + EN_Project *p = (EN_Project*)ph; + if (!p->quality.OpenQflag) - return (105); + return set_error(p->error_handle, 105); initqual(p); p->save_options.SaveQflag = FALSE; p->save_options.Saveflag = FALSE; @@ -1125,56 +1184,66 @@ int DLLEXPORT EN_initQ(EN_Project *p, int saveflag) { if (!errcode) p->save_options.Saveflag = TRUE; } - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_runQ(EN_Project *p, long *t) { +int DLLEXPORT EN_runQ(EN_ProjectHandle ph, long *t) { int errcode; + + EN_Project *p = (EN_Project*)ph; + *t = 0; if (!p->quality.OpenQflag) - return (105); + return set_error(p->error_handle, 105); errcode = runqual(p, t); if (errcode) errmsg(p, errcode); - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_nextQ(EN_Project *p, long *tstep) { +int DLLEXPORT EN_nextQ(EN_ProjectHandle ph, long *tstep) { int errcode; + + EN_Project *p = (EN_Project*)ph; + *tstep = 0; if (!p->quality.OpenQflag) - return (105); + return set_error(p->error_handle, 105); errcode = nextqual(p, tstep); if (!errcode && p->save_options.Saveflag && *tstep == 0) { p->save_options.SaveQflag = TRUE; } if (errcode) errmsg(p, errcode); - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_stepQ(EN_Project *p, long *tleft) { +int DLLEXPORT EN_stepQ(EN_ProjectHandle ph, long *tleft) { int errcode; + + EN_Project *p = (EN_Project*)ph; + *tleft = 0; if (!p->quality.OpenQflag) - return (105); + return set_error(p->error_handle, 105); errcode = stepqual(p, tleft); if (!errcode && p->save_options.Saveflag && *tleft == 0) { p->save_options.SaveQflag = TRUE; } if (errcode) errmsg(p, errcode); - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_closeQ(EN_Project *p) +int DLLEXPORT EN_closeQ(EN_ProjectHandle ph) { + + EN_Project *p = (EN_Project*)ph; -{ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); closequal(p); p->quality.OpenQflag = FALSE; - return (0); + return set_error(p->error_handle, 0); } /* @@ -1183,48 +1252,59 @@ int DLLEXPORT EN_closeQ(EN_Project *p) ---------------------------------------------------------------- */ -int DLLEXPORT EN_writeline(EN_Project *p, char *line) { +int DLLEXPORT EN_writeline(EN_ProjectHandle ph, char *line) { + + EN_Project *p = (EN_Project*)ph; + if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); writeline(p, line); - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_report(EN_Project *p) { +int DLLEXPORT EN_report(EN_ProjectHandle ph) { int errcode; + EN_Project *p = (EN_Project*)ph; + /* Check if results saved to binary output file */ if (!p->save_options.SaveQflag) - return (106); + return set_error(p->error_handle, 106); errcode = writereport(p); if (errcode) errmsg(p, errcode); - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_resetreport(EN_Project *p) { +int DLLEXPORT EN_resetreport(EN_ProjectHandle ph) { int i; + + EN_Project *p = (EN_Project*)ph; + if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); initreport(&p->report); for (i = 1; i <= p->network.Nnodes; i++) p->network.Node[i].Rpt = 0; for (i = 1; i <= p->network.Nlinks; i++) p->network.Link[i].Rpt = 0; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setreport(EN_Project *p, char *s) { +int DLLEXPORT EN_setreport(EN_ProjectHandle ph, char *s) { char s1[MAXLINE + 1]; + + EN_Project *p = (EN_Project*)ph; + if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (strlen(s) > MAXLINE) - return (250); + return set_error(p->error_handle, 250); strcpy(s1, s); if (setreport(p, s1) > 0) - return (250); + return set_error(p->error_handle, 250); else - return (0); + return set_error(p->error_handle, 0); } /* @@ -1247,14 +1327,16 @@ int DLLEXPORT EN_getversion(int *v) */ { *v = CODEVERSION; - return (0); + return 0; } -int DLLEXPORT EN_getcontrol(EN_Project *pr, int cindex, int *ctype, int *lindex, +int DLLEXPORT EN_getcontrol(EN_ProjectHandle ph, int cindex, int *ctype, int *lindex, EN_API_FLOAT_TYPE *setting, int *nindex, EN_API_FLOAT_TYPE *level) { double s, lvl; + EN_Project *pr = (EN_Project*)ph; + EN_Network *net = &pr->network; Scontrol *Control = net->Control; @@ -1263,16 +1345,16 @@ int DLLEXPORT EN_getcontrol(EN_Project *pr, int cindex, int *ctype, int *lindex, const int Njuncs = net->Njuncs; double *Ucf = pr->Ucf; - + s = 0.0; lvl = 0.0; *ctype = 0; *lindex = 0; *nindex = 0; if (!pr->Openflag) - return (102); + return set_error(pr->error_handle, 102); if (cindex < 1 || cindex > net->Ncontrols) - return (241); + return set_error(pr->error_handle, 241); *ctype = Control[cindex].Type; *lindex = Control[cindex].Link; s = Control[cindex].Setting; @@ -1305,15 +1387,18 @@ int DLLEXPORT EN_getcontrol(EN_Project *pr, int cindex, int *ctype, int *lindex, lvl = (EN_API_FLOAT_TYPE)Control[cindex].Time; *setting = (EN_API_FLOAT_TYPE)s; *level = (EN_API_FLOAT_TYPE)lvl; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_getcount(EN_Project *pr, EN_CountType code, int *count) { +int DLLEXPORT EN_getcount(EN_ProjectHandle ph, EN_CountType code, int *count) { + + EN_Project *pr = (EN_Project*)ph; + EN_Network *net = &pr->network; *count = 0; if (!pr->Openflag) - return (102); + return set_error(pr->error_handle, 102); switch (code) { case EN_NODECOUNT: *count = net->Nnodes; @@ -1337,13 +1422,16 @@ int DLLEXPORT EN_getcount(EN_Project *pr, EN_CountType code, int *count) { *count = net->Nrules; break; default: - return (251); + return set_error(pr->error_handle, 251); } - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_getoption(EN_Project *pr, EN_Option code, +int DLLEXPORT EN_getoption(EN_ProjectHandle ph, EN_Option code, EN_API_FLOAT_TYPE *value) { + + EN_Project *pr = (EN_Project*)ph; + hydraulics_t *hyd = &pr->hydraulics; quality_t *qu = &pr->quality; double *Ucf = pr->Ucf; @@ -1351,7 +1439,7 @@ int DLLEXPORT EN_getoption(EN_Project *pr, EN_Option code, double v = 0.0; *value = 0.0; if (!pr->Openflag) - return (102); + return set_error(pr->error_handle, 102); switch (code) { case EN_TRIALS: v = (double)hyd->MaxIter; @@ -1378,15 +1466,17 @@ int DLLEXPORT EN_getoption(EN_Project *pr, EN_Option code, break; default: - return (251); + return set_error(pr->error_handle, 251); } *value = (EN_API_FLOAT_TYPE)v; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_gettimeparam(EN_Project *pr, int code, long *value) { - +int DLLEXPORT EN_gettimeparam(EN_ProjectHandle ph, int code, long *value) { int i; + + EN_Project *pr = (EN_Project*)ph; + report_options_t *rep = &pr->report; quality_t *qu = &pr->quality; time_options_t *time = &pr->time_options; @@ -1394,9 +1484,9 @@ int DLLEXPORT EN_gettimeparam(EN_Project *pr, int code, long *value) { *value = 0; if (!pr->Openflag) - return (102); + return set_error(pr->error_handle, 102); if (code < EN_DURATION || code > EN_NEXTEVENTIDX) - return (251); + return set_error(pr->error_handle, 251); switch (code) { case EN_DURATION: *value = time->Dur; @@ -1445,25 +1535,31 @@ int DLLEXPORT EN_gettimeparam(EN_Project *pr, int code, long *value) { *value = i; break; } - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_getflowunits(EN_Project *p, int *code) { +int DLLEXPORT EN_getflowunits(EN_ProjectHandle ph, int *code) { + + EN_Project *p = (EN_Project*)ph; + *code = -1; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); *code = p->parser.Flowflag; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setflowunits(EN_Project *p, int code) { +int DLLEXPORT EN_setflowunits(EN_ProjectHandle ph, int code) { int i, j; double qfactor, vfactor, hfactor, efactor, xfactor, yfactor; + + EN_Project *p = (EN_Project*)ph; + double *Ucf = p->Ucf; EN_Network *net = &p->network; if (!p->Openflag) { - return(102); + return set_error(p->error_handle, 102); } /* Determine unit system based on flow units */ @@ -1527,141 +1623,179 @@ int DLLEXPORT EN_setflowunits(EN_Project *p, int code) { } } - return(0); + return set_error(p->error_handle, 0); } - -int DLLEXPORT EN_getdemandmodel(EN_Project *p, int *type, EN_API_FLOAT_TYPE *pmin, +int DLLEXPORT EN_getdemandmodel(EN_ProjectHandle ph, int *type, EN_API_FLOAT_TYPE *pmin, EN_API_FLOAT_TYPE *preq, EN_API_FLOAT_TYPE *pexp) { + EN_Project *p = (EN_Project*)ph; + *type = p->hydraulics.DemandModel; *pmin = (EN_API_FLOAT_TYPE)(p->hydraulics.Pmin * p->Ucf[PRESSURE]); *preq = (EN_API_FLOAT_TYPE)(p->hydraulics.Preq * p->Ucf[PRESSURE]); *pexp = (EN_API_FLOAT_TYPE)(p->hydraulics.Pexp); - return 0; + + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setdemandmodel(EN_Project *p, int type, EN_API_FLOAT_TYPE pmin, +int DLLEXPORT EN_setdemandmodel(EN_ProjectHandle ph, int type, EN_API_FLOAT_TYPE pmin, EN_API_FLOAT_TYPE preq, EN_API_FLOAT_TYPE pexp) { - if (type < 0 || type > EN_PDA) return 251; - if (pmin > preq || pexp <= 0.0) return 202; + EN_Project *p = (EN_Project*)ph; + + if (type < 0 || type > EN_PDA) return set_error(p->error_handle, 251); + if (pmin > preq || pexp <= 0.0) return set_error(p->error_handle, 202); p->hydraulics.DemandModel = type; p->hydraulics.Pmin = pmin / p->Ucf[PRESSURE]; p->hydraulics.Preq = preq / p->Ucf[PRESSURE]; p->hydraulics.Pexp = pexp; - return 0; + + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getpatternindex(EN_Project *p, char *id, int *index) { +int DLLEXPORT EN_getpatternindex(EN_ProjectHandle ph, char *id, int *index) { int i; + + EN_Project *p = (EN_Project*)ph; + *index = 0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); for (i = 1; i <= p->network.Npats; i++) { if (strcmp(id, p->network.Pattern[i].ID) == 0) { *index = i; - return (0); + return set_error(p->error_handle, 0); } } *index = 0; - return (205); + return set_error(p->error_handle, 205); } -int DLLEXPORT EN_getpatternid(EN_Project *p, int index, char *id) { +int DLLEXPORT EN_getpatternid(EN_ProjectHandle ph, int index, char *id) { + + EN_Project *p = (EN_Project*)ph; + strcpy(id, ""); if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Npats) - return (205); + return set_error(p->error_handle, 205); strcpy(id, p->network.Pattern[index].ID); - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getpatternlen(EN_Project *p, int index, int *len) { +int DLLEXPORT EN_getpatternlen(EN_ProjectHandle ph, int index, int *len) { + + EN_Project *p = (EN_Project*)ph; + if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Npats) - return (205); + return set_error(p->error_handle, 205); *len = p->network.Pattern[index].Length; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getpatternvalue(EN_Project *p, int index, int period, +int DLLEXPORT EN_getpatternvalue(EN_ProjectHandle ph, int index, int period, EN_API_FLOAT_TYPE *value) { + + EN_Project *p = (EN_Project*)ph; + *value = 0.0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Npats) - return (205); + return set_error(p->error_handle, 205); if (period < 1 || period > p->network.Pattern[index].Length) - return (251); + return set_error(p->error_handle, 251); *value = (EN_API_FLOAT_TYPE)p->network.Pattern[index].F[period - 1]; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getcurveindex(EN_Project *p, char *id, int *index) { +int DLLEXPORT EN_getcurveindex(EN_ProjectHandle ph, char *id, int *index) { int i; + + EN_Project *p = (EN_Project*)ph; + *index = 0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); for (i = 1; i <= p->network.Ncurves; i++) { if (strcmp(id, p->network.Curve[i].ID) == 0) { *index = i; - return (0); + return set_error(p->error_handle, 0); } } *index = 0; - return (206); + return set_error(p->error_handle, 206); } -int DLLEXPORT EN_getcurveid(EN_Project *p, int index, char *id) { +int DLLEXPORT EN_getcurveid(EN_ProjectHandle ph, int index, char *id) { + + EN_Project *p = (EN_Project*)ph; + strcpy(id, ""); if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Ncurves) - return (206); + return set_error(p->error_handle, 206); strcpy(id, p->network.Curve[index].ID); - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getcurvelen(EN_Project *p, int index, int *len) { +int DLLEXPORT EN_getcurvelen(EN_ProjectHandle ph, int index, int *len) { + + EN_Project *p = (EN_Project*)ph; + if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Ncurves) - return (206); + return set_error(p->error_handle, 206); *len = p->network.Curve[index].Npts; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getcurvevalue(EN_Project *p, int index, int pnt, +int DLLEXPORT EN_getcurvevalue(EN_ProjectHandle ph, int index, int pnt, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y) { + + EN_Project *p = (EN_Project*)ph; + *x = 0.0; *y = 0.0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Ncurves) - return (206); + return set_error(p->error_handle, 206); if (pnt < 1 || pnt > p->network.Curve[index].Npts) - return (251); + return set_error(p->error_handle, 251); *x = (EN_API_FLOAT_TYPE)p->network.Curve[index].X[pnt - 1]; *y = (EN_API_FLOAT_TYPE)p->network.Curve[index].Y[pnt - 1]; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getqualtype(EN_Project *p, int *qualcode, int *tracenode) { +int DLLEXPORT EN_getqualtype(EN_ProjectHandle ph, int *qualcode, int *tracenode) { + + EN_Project *p = (EN_Project*)ph; + *tracenode = 0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); *qualcode = p->quality.Qualflag; if (p->quality.Qualflag == TRACE) *tracenode = p->quality.TraceNode; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getqualinfo(EN_Project *p, int *qualcode, char *chemname, char *chemunits, int *tracenode) { - EN_getqualtype(p, qualcode, tracenode); + +int DLLEXPORT EN_getqualinfo(EN_ProjectHandle ph, int *qualcode, char *chemname, + char *chemunits, int *tracenode) { + + EN_Project *p = (EN_Project*)ph; + + EN_getqualtype(ph, qualcode, tracenode); + if (p->quality.Qualflag == TRACE) { strncpy(chemname, "", MAXID); strncpy(chemunits, "dimensionless", MAXID); @@ -1669,10 +1803,68 @@ int DLLEXPORT EN_getqualinfo(EN_Project *p, int *qualcode, char *chemname, char strncpy(chemname, p->quality.ChemName, MAXID); strncpy(chemunits, p->quality.ChemUnits, MAXID); } - return 0; + return set_error(p->error_handle, 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) { + // Deprecate? char newMsg[MAXMSG+1]; switch (errcode) { @@ -1699,12 +1891,15 @@ int DLLEXPORT EN_geterror(int errcode, char *errmsg, int n) { strncpy(errmsg, newMsg, n); } if (strlen(errmsg) == 0) - return (251); + return 251; else - return (0); + return 0; } -int DLLEXPORT EN_getstatistic(EN_Project *p, int code, EN_API_FLOAT_TYPE *value) { +int DLLEXPORT EN_getstatistic(EN_ProjectHandle ph, int code, EN_API_FLOAT_TYPE *value) { + + EN_Project *p = (EN_Project*)ph; + switch (code) { case EN_ITERATIONS: *value = (EN_API_FLOAT_TYPE)p->hydraulics.Iterations; @@ -1721,7 +1916,7 @@ int DLLEXPORT EN_getstatistic(EN_Project *p, int code, EN_API_FLOAT_TYPE *value) default: break; } - return 0; + return set_error(p->error_handle, 0); } /* @@ -1730,33 +1925,42 @@ int DLLEXPORT EN_getstatistic(EN_Project *p, int code, EN_API_FLOAT_TYPE *value) ---------------------------------------------------------------- */ -int DLLEXPORT EN_getnodeindex(EN_Project *p, char *id, int *index) { +int DLLEXPORT EN_getnodeindex(EN_ProjectHandle ph, char *id, int *index) { + + EN_Project *p = (EN_Project*)ph; + *index = 0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); *index = findnode(&p->network,id); if (*index == 0) - return (203); + return set_error(p->error_handle, 203); else - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getnodeid(EN_Project *p, int index, char *id) { +int DLLEXPORT EN_getnodeid(EN_ProjectHandle ph, int index, char *id) { + + EN_Project *p = (EN_Project*)ph; + strcpy(id, ""); if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Nnodes) - return (203); + return set_error(p->error_handle, 203); strcpy(id, p->network.Node[index].ID); - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getnodetype(EN_Project *p, int index, int *code) { +int DLLEXPORT EN_getnodetype(EN_ProjectHandle ph, int index, int *code) { + + EN_Project *p = (EN_Project*)ph; + *code = -1; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Nnodes) - return (203); + return set_error(p->error_handle, 203); if (index <= p->network.Njuncs) *code = EN_JUNCTION; else { @@ -1765,48 +1969,56 @@ int DLLEXPORT EN_getnodetype(EN_Project *p, int index, int *code) { else *code = EN_TANK; } - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getcoord(EN_Project *p, int index, EN_API_FLOAT_TYPE *x, +int DLLEXPORT EN_getcoord(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y) { + + EN_Project *p = (EN_Project*)ph; + if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Nnodes) - return (203); + return set_error(p->error_handle, 203); if (!p->parser.Coordflag) - return (255); + return set_error(p->error_handle, 255); // check if node have coords if (p->network.Coord[index].HaveCoords == FALSE) - return (254); + return set_error(p->error_handle, 254); *x = (EN_API_FLOAT_TYPE)p->network.Coord[index].X; *y = (EN_API_FLOAT_TYPE)p->network.Coord[index].Y; - return 0; + + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setcoord(EN_Project *p, int index, EN_API_FLOAT_TYPE x, +int DLLEXPORT EN_setcoord(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE x, EN_API_FLOAT_TYPE y) { + + EN_Project *p = (EN_Project*)ph; + if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Nnodes) - return (203); + return set_error(p->error_handle, 203); if (!p->parser.Coordflag) - return (255); + return set_error(p->error_handle, 255); p->network.Coord[index].X = x; p->network.Coord[index].Y = y; p->network.Coord[index].HaveCoords = TRUE; - return 0; + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getnodevalue(EN_Project *p, int index, int code, +int DLLEXPORT EN_getnodevalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE *value) { double v = 0.0; Pdemand demand; Psource source; + EN_Project *p = (EN_Project*)ph; EN_Network *net = &p->network; hydraulics_t *hyd = &p->hydraulics; @@ -1826,9 +2038,9 @@ int DLLEXPORT EN_getnodevalue(EN_Project *p, int index, int code, /* Check for valid arguments */ *value = 0.0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > Nnodes) - return (203); + return set_error(p->error_handle, 203); /* Retrieve called-for parameter */ switch (code) { @@ -1872,7 +2084,7 @@ int DLLEXPORT EN_getnodevalue(EN_Project *p, int index, int code, case EN_SOURCEPAT: source = Node[index].S; if (source == NULL) - return (240); + return set_error(p->error_handle, 240); if (code == EN_SOURCEQUAL) v = source->C0; else if (code == EN_SOURCEMASS) @@ -1885,7 +2097,7 @@ int DLLEXPORT EN_getnodevalue(EN_Project *p, int index, int code, case EN_TANKLEVEL: if (index <= Njuncs) - return (251); + return set_error(p->error_handle, 251); v = (Tank[index - Njuncs].H0 - Node[index].El) * Ucf[ELEV]; break; @@ -1986,15 +2198,15 @@ int DLLEXPORT EN_getnodevalue(EN_Project *p, int index, int code, case EN_TANKVOLUME: if (index <= Njuncs) - return (251); + return set_error(p->error_handle, 251); v = tankvolume(p, index - Njuncs, hyd->NodeHead[index]) * Ucf[VOLUME]; break; default: - return (251); + return set_error(p->error_handle, 251); } *value = (EN_API_FLOAT_TYPE)v; - return (0); + return set_error(p->error_handle, 0); } /* @@ -2003,55 +2215,70 @@ int DLLEXPORT EN_getnodevalue(EN_Project *p, int index, int code, ---------------------------------------------------------------- */ -int DLLEXPORT EN_getlinkindex(EN_Project *p, char *id, int *index) { +int DLLEXPORT EN_getlinkindex(EN_ProjectHandle ph, char *id, int *index) { + + EN_Project *p = (EN_Project*)ph; + *index = 0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); *index = findlink(&p->network,id); if (*index == 0) - return (204); + return set_error(p->error_handle, 204); else - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getlinkid(EN_Project *p, int index, char *id) { +int DLLEXPORT EN_getlinkid(EN_ProjectHandle ph, int index, char *id) { + + EN_Project *p = (EN_Project*)ph; + strcpy(id, ""); if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Nlinks) - return (204); + return set_error(p->error_handle, 204); strcpy(id, p->network.Link[index].ID); - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getlinktype(EN_Project *p, int index, EN_LinkType *code) { +int DLLEXPORT EN_getlinktype(EN_ProjectHandle ph, int index, EN_LinkType *code) { + + EN_Project *p = (EN_Project*)ph; + *code = -1; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Nlinks) - return (204); + return set_error(p->error_handle, 204); *code = p->network.Link[index].Type; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getlinknodes(EN_Project *p, int index, int *node1, +int DLLEXPORT EN_getlinknodes(EN_ProjectHandle ph, int index, int *node1, int *node2) { + + EN_Project *p = (EN_Project*)ph; + *node1 = 0; *node2 = 0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > p->network.Nlinks) - return (204); + return set_error(p->error_handle, 204); *node1 = p->network.Link[index].N1; *node2 = p->network.Link[index].N2; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getlinkvalue(EN_Project *p, int index, EN_LinkProperty code, EN_API_FLOAT_TYPE *value) { +int DLLEXPORT EN_getlinkvalue(EN_ProjectHandle ph, int index, EN_LinkProperty code, + EN_API_FLOAT_TYPE *value) { double a, h, q, v = 0.0; int returnValue = 0; int pmp; + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; hydraulics_t *hyd = &p->hydraulics; @@ -2067,9 +2294,9 @@ int DLLEXPORT EN_getlinkvalue(EN_Project *p, int index, EN_LinkProperty code, EN /* Check for valid arguments */ *value = 0.0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > Nlinks) - return (204); + return set_error(p->error_handle, 204); /* Retrieve called-for parameter */ switch (code) { @@ -2111,7 +2338,7 @@ int DLLEXPORT EN_getlinkvalue(EN_Project *p, int index, EN_LinkProperty code, EN case EN_INITSETTING: if (Link[index].Type == EN_PIPE || Link[index].Type == EN_CVPIPE) - return (ENgetlinkvalue(index, EN_ROUGHNESS, value)); + return set_error(p->error_handle, ENgetlinkvalue(index, EN_ROUGHNESS, value)); v = Link[index].Kc; switch (Link[index].Type) { case EN_PRV: @@ -2214,7 +2441,7 @@ int DLLEXPORT EN_getlinkvalue(EN_Project *p, int index, EN_LinkProperty code, EN case EN_SETTING: if (Link[index].Type == EN_PIPE || Link[index].Type == EN_CVPIPE) { - return (ENgetlinkvalue(index, EN_ROUGHNESS, value)); + return set_error(p->error_handle, ENgetlinkvalue(index, EN_ROUGHNESS, value)); } if (LinkSetting[index] == MISSING) { v = 0.0; @@ -2286,19 +2513,21 @@ int DLLEXPORT EN_getlinkvalue(EN_Project *p, int index, EN_LinkProperty code, EN returnValue = 251; } *value = (EN_API_FLOAT_TYPE)v; - return returnValue; + return set_error(p->error_handle, returnValue); } -int DLLEXPORT EN_getcurve(EN_Project *p, int curveIndex, char *id, int *nValues, +int DLLEXPORT EN_getcurve(EN_ProjectHandle ph, int curveIndex, char *id, int *nValues, EN_API_FLOAT_TYPE **xValues, EN_API_FLOAT_TYPE **yValues) { int iPoint, nPoints; Scurve curve; EN_API_FLOAT_TYPE *pointX, *pointY; + EN_Project *p = (EN_Project*)ph; + /* Check that input file opened */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); curve = p->network.Curve[curveIndex]; nPoints = curve.Npts; @@ -2319,7 +2548,7 @@ int DLLEXPORT EN_getcurve(EN_Project *p, int curveIndex, char *id, int *nValues, *xValues = pointX; *yValues = pointY; - return (0); + return set_error(p->error_handle, 0); } /* @@ -2328,7 +2557,7 @@ int DLLEXPORT EN_getcurve(EN_Project *p, int curveIndex, char *id, int *nValues, ---------------------------------------------------------------- */ -int DLLEXPORT EN_setcontrol(EN_Project *p, int cindex, int ctype, int lindex, +int DLLEXPORT EN_setcontrol(EN_ProjectHandle ph, int cindex, int ctype, int lindex, EN_API_FLOAT_TYPE setting, int nindex, EN_API_FLOAT_TYPE level) { char status = ACTIVE; @@ -2344,13 +2573,15 @@ int DLLEXPORT EN_setcontrol(EN_Project *p, int cindex, int ctype, int lindex, int Nlinks; double *Ucf; + EN_Project *p = (EN_Project*)ph; + /* Check that input file opened */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); /* Check that control exists */ if (cindex < 1 || cindex > p->network.Ncontrols) - return (241); + return set_error(p->error_handle, 241); net = &p->network; @@ -2368,25 +2599,25 @@ int DLLEXPORT EN_setcontrol(EN_Project *p, int cindex, int ctype, int lindex, /* Check that controlled link exists */ if (lindex == 0) { Control[cindex].Link = 0; - return (0); + return set_error(p->error_handle, 0); } if (lindex < 0 || lindex > Nlinks) - return (204); + return set_error(p->error_handle, 204); /* Cannot control check valve. */ if (Link[lindex].Type == EN_CVPIPE) - return (207); + return set_error(p->error_handle, 207); /* Check for valid parameters */ if (ctype < 0 || ctype > EN_TIMEOFDAY) - return (251); + return set_error(p->error_handle, 251); if (ctype == EN_LOWLEVEL || ctype == EN_HILEVEL) { if (nindex < 1 || nindex > Nnodes) - return (203); + return set_error(p->error_handle, 203); } else nindex = 0; if (s < 0.0 || lvl < 0.0) - return (202); + return set_error(p->error_handle, 202); /* Adjust units of control parameters */ switch (Link[lindex].Type) { @@ -2406,7 +2637,7 @@ int DLLEXPORT EN_setcontrol(EN_Project *p, int cindex, int ctype, int lindex, else if (s == 1.0) status = OPEN; else - return (202); + return set_error(p->error_handle, 202); s = Link[lindex].Kc; break; @@ -2437,10 +2668,10 @@ int DLLEXPORT EN_setcontrol(EN_Project *p, int cindex, int ctype, int lindex, Control[cindex].Setting = s; Control[cindex].Grade = lvl; Control[cindex].Time = t; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_TYPE v) +int DLLEXPORT EN_setnodevalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE v) /*---------------------------------------------------------------- ** Input: index = node index ** code = node parameter code (see EPANET2.H) @@ -2451,6 +2682,8 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T **---------------------------------------------------------------- */ { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; hydraulics_t *hyd = &p->hydraulics; quality_t *qu = &p->quality; @@ -2471,9 +2704,9 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T double value = v; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > Nnodes) - return (203); + return set_error(p->error_handle, 203); switch (code) { case EN_ELEVATION: if (index <= Njuncs) @@ -2503,7 +2736,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T /* NOTE: primary demand category is last on demand list */ j = ROUND(value); if (j < 0 || j > Npats) - return (205); + return set_error(p->error_handle, 205); if (index <= Njuncs) { for (demand = Node[index].D; demand != NULL; demand = demand->next) { if (demand->next == NULL) @@ -2515,9 +2748,9 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T case EN_EMITTER: if (index > Njuncs) - return (203); + return set_error(p->error_handle, 203); if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); if (value > 0.0) value = pow((Ucf[FLOW] / value), hyd->Qexp) / Ucf[PRESSURE]; Node[index].Ke = value; @@ -2525,7 +2758,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T case EN_INITQUAL: if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); Node[index].C0 = value / Ucf[QUALITY]; if (index > Njuncs) Tank[index - Njuncs].C = Node[index].C0; @@ -2535,12 +2768,12 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T case EN_SOURCETYPE: case EN_SOURCEPAT: if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); source = Node[index].S; if (source == NULL) { source = (struct Ssource *)malloc(sizeof(struct Ssource)); if (source == NULL) - return (101); + return set_error(p->error_handle, 101); source->Type = CONCEN; source->C0 = 0.0; source->Pat = 0; @@ -2551,21 +2784,21 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T } else if (code == EN_SOURCEPAT) { j = ROUND(value); if (j < 0 || j > Npats) - return (205); + return set_error(p->error_handle, 205); source->Pat = j; } else // code == EN_SOURCETYPE { j = ROUND(value); if (j < CONCEN || j > FLOWPACED) - return (251); + return set_error(p->error_handle, 251); else source->Type = (char)j; } - return (0); + return set_error(p->error_handle, 0); case EN_TANKLEVEL: if (index <= Njuncs) - return (251); + return set_error(p->error_handle, 251); j = index - Njuncs; if (Tank[j].A == 0.0) /* Tank is a reservoir */ { @@ -2577,7 +2810,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T } else { value = Node[index].El + value / Ucf[ELEV]; if (value > Tank[j].Hmax || value < Tank[j].Hmin) - return (202); + return set_error(p->error_handle, 202); Tank[j].H0 = value; Tank[j].V0 = tankvolume(p, j, Tank[j].H0); // Resetting Volume in addition to initial volume @@ -2592,9 +2825,9 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T case EN_TANKDIAM: if (value <= 0.0) - return (202); + return set_error(p->error_handle, 202); if (index <= Njuncs) - return (251); + return set_error(p->error_handle, 251); j = index - Njuncs; if (j > 0 && Tank[j].A > 0.0) { value /= Ucf[ELEV]; @@ -2603,81 +2836,81 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T Tank[j].V0 = tankvolume(p, j, Tank[j].H0); Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); } else { - return (251); + return set_error(p->error_handle, 251); } break; case EN_MINVOLUME: if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); if (index <= Njuncs) - return (251); + return set_error(p->error_handle, 251); j = index - Njuncs; if (j > 0 && Tank[j].A > 0.0) { Tank[j].Vmin = value / Ucf[VOLUME]; Tank[j].V0 = tankvolume(p, j, Tank[j].H0); Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); } else { - return (251); + return set_error(p->error_handle, 251); } break; case EN_MINLEVEL: if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); if (index <= Njuncs) - return (251); // not a tank or reservoir + return set_error(p->error_handle, 251); // not a tank or reservoir j = index - Njuncs; if (Tank[j].A == 0.0) - return (251); // node is a reservoir + return set_error(p->error_handle, 251); // node is a reservoir Htmp = value / Ucf[ELEV] + Node[index].El; if (Htmp < Tank[j].Hmax && Htmp <= Tank[j].H0) { if (Tank[j].Vcurve > 0) - return (202); + return set_error(p->error_handle, 202); Tank[j].Hmin = Htmp; Tank[j].Vmin = tankvolume(p, j, Tank[j].Hmin); } else { - return (251); + return set_error(p->error_handle, 251); } break; case EN_MAXLEVEL: if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); if (index <= Njuncs) - return (251); // not a tank or reservoir + return set_error(p->error_handle, 251); // not a tank or reservoir j = index - Njuncs; if (Tank[j].A == 0.0) - return (251); // node is a reservoir + return set_error(p->error_handle, 251); // node is a reservoir Htmp = value / Ucf[ELEV] + Node[index].El; if (Htmp > Tank[j].Hmin && Htmp >= Tank[j].H0) { if (Tank[j].Vcurve > 0) - return (202); + return set_error(p->error_handle, 202); Tank[j].Hmax = Htmp; Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); } else { - return (251); + return set_error(p->error_handle, 251); } break; case EN_MIXMODEL: j = ROUND(value); if (index <= Njuncs) - return (251); + return set_error(p->error_handle, 251); if (j < MIX1 || j > LIFO) - return (202); + return set_error(p->error_handle, 202); if (index > Njuncs && Tank[index - Njuncs].A > 0.0) { Tank[index - Njuncs].MixModel = (char)j; } else { - return (251); + return set_error(p->error_handle, 251); } break; case EN_MIXFRACTION: if (value < 0.0 || value > 1.0) - return (202); + return set_error(p->error_handle, 202); if (index <= Njuncs) - return (251); + return set_error(p->error_handle, 251); j = index - Njuncs; if (j > 0 && Tank[j].A > 0.0) { Tank[j].V1max = value * Tank[j].Vmax; @@ -2686,25 +2919,25 @@ int DLLEXPORT EN_setnodevalue(EN_Project *p, int index, int code, EN_API_FLOAT_T case EN_TANK_KBULK: if (index <= Njuncs) - return (251); + return set_error(p->error_handle, 251); j = index - Njuncs; if (j > 0 && Tank[j].A > 0.0) { Tank[j].Kb = value / SECperDAY; qu->Reactflag = 1; } else { - return (251); + return set_error(p->error_handle, 251); } break; /*** New parameter additions ends here. ***/ default: - return (251); + return set_error(p->error_handle, 251); } - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, +int DLLEXPORT EN_setlinkvalue(EN_ProjectHandle ph, int index, int code, EN_API_FLOAT_TYPE v) /*---------------------------------------------------------------- @@ -2717,7 +2950,8 @@ int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, **---------------------------------------------------------------- */ { - + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; hydraulics_t *hyd = &p->hydraulics; quality_t *qu = &p->quality; @@ -2733,14 +2967,14 @@ int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, double r, value = v; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > Nlinks) - return (204); + return set_error(p->error_handle, 204); switch (code) { case EN_DIAMETER: if (Link[index].Type != EN_PUMP) { if (value <= 0.0) - return (202); + return set_error(p->error_handle, 202); value /= Ucf[DIAM]; /* Convert to feet */ r = Link[index].Diam / value; /* Ratio of old to new diam */ Link[index].Km *= SQR(r) * SQR(r); /* Adjust minor loss factor */ @@ -2752,7 +2986,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, case EN_LENGTH: if (Link[index].Type <= EN_PIPE) { if (value <= 0.0) - return (202); + return set_error(p->error_handle, 202); Link[index].Len = value / Ucf[ELEV]; resistcoeff(p, index); } @@ -2761,7 +2995,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, case EN_ROUGHNESS: if (Link[index].Type <= EN_PIPE) { if (value <= 0.0) - return (202); + return set_error(p->error_handle, 202); Link[index].Kc = value; if (hyd->Formflag == DW) Link[index].Kc /= (1000.0 * Ucf[ELEV]); @@ -2772,7 +3006,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, case EN_MINORLOSS: if (Link[index].Type != EN_PUMP) { if (value <= 0.0) - return (202); + return set_error(p->error_handle, 202); Link[index].Km = 0.02517 * value / SQR(Link[index].Diam) / SQR(Link[index].Diam); } @@ -2782,10 +3016,10 @@ int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, case EN_STATUS: /* Cannot set status for a check valve */ if (Link[index].Type == EN_CVPIPE) - return (207); + return set_error(p->error_handle, 207); s = (char)ROUND(value); if (s < 0 || s > 1) - return (251); + return set_error(p->error_handle, 251); if (code == EN_INITSTATUS) setlinkstatus(p, index, s, &Link[index].Stat, &Link[index].Kc); else @@ -2795,9 +3029,9 @@ int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, case EN_INITSETTING: case EN_SETTING: if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); if (Link[index].Type == EN_PIPE || Link[index].Type == EN_CVPIPE) - return (ENsetlinkvalue(index, EN_ROUGHNESS, v)); + return set_error(p->error_handle, ENsetlinkvalue(index, EN_ROUGHNESS, v)); else { switch (Link[index].Type) { case EN_PUMP: @@ -2815,10 +3049,10 @@ int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, /*** Updated 9/7/00 ***/ case EN_GPV: - return (202); /* Cannot modify setting for GPV */ + return set_error(p->error_handle, 202); /* Cannot modify setting for GPV */ default: - return (251); + return set_error(p->error_handle, 251); } if (code == EN_INITSETTING) setlinksetting(p, index, value, &Link[index].Stat, &Link[index].Kc); @@ -2843,15 +3077,17 @@ int DLLEXPORT EN_setlinkvalue(EN_Project *p, int index, int code, break; default: - return (251); + return set_error(p->error_handle, 251); } - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_addpattern(EN_Project *p, char *id) { +int DLLEXPORT EN_addpattern(EN_ProjectHandle ph, char *id) { int i, j, n, err = 0; Spattern *tmpPat; + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; parser_data_t *par = &p->parser; @@ -2863,21 +3099,21 @@ int DLLEXPORT EN_addpattern(EN_Project *p, char *id) { /* Check if a pattern with same id already exists */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (ENgetpatternindex(id, &i) == 0) - return (215); + return set_error(p->error_handle, 215); /* Check that id name is not too long */ if (strlen(id) > MAXID) - return (250); + return set_error(p->error_handle, 250); /* Allocate memory for a new array of patterns */ n = Npats + 1; tmpPat = (Spattern *)calloc(n + 1, sizeof(Spattern)); if (tmpPat == NULL) - return (101); + return set_error(p->error_handle, 101); /* Copy contents of old pattern array to new one */ @@ -2909,7 +3145,7 @@ int DLLEXPORT EN_addpattern(EN_Project *p, char *id) { if (tmpPat[i].F) free(tmpPat[i].F); free(tmpPat); - return (101); + return set_error(p->error_handle, 101); } // Replace old pattern array with new one @@ -2920,12 +3156,14 @@ int DLLEXPORT EN_addpattern(EN_Project *p, char *id) { Pattern = tmpPat; net->Npats = n; par->MaxPats = n; - return 0; + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setpattern(EN_Project *p, int index, EN_API_FLOAT_TYPE *f, int n) { +int DLLEXPORT EN_setpattern(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *f, int n) { int j; + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Spattern *Pattern = net->Pattern; const int Npats = net->Npats; @@ -2933,26 +3171,28 @@ int DLLEXPORT EN_setpattern(EN_Project *p, int index, EN_API_FLOAT_TYPE *f, int /* Check for valid arguments */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > Npats) - return (205); + return set_error(p->error_handle, 205); if (n <= 0) - return (202); + return set_error(p->error_handle, 202); /* Re-set number of time periods & reallocate memory for multipliers */ Pattern[index].Length = n; Pattern[index].F = (double *)realloc(Pattern[index].F, n * sizeof(double)); if (Pattern[index].F == NULL) - return (101); + return set_error(p->error_handle, 101); /* Load multipliers into pattern */ for (j = 0; j < n; j++) Pattern[index].F[j] = f[j]; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setpatternvalue(EN_Project *p, int index, int period, EN_API_FLOAT_TYPE value) { +int DLLEXPORT EN_setpatternvalue(EN_ProjectHandle ph, int index, int period, EN_API_FLOAT_TYPE value) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Spattern *Pattern = net->Pattern; @@ -2961,17 +3201,19 @@ int DLLEXPORT EN_setpatternvalue(EN_Project *p, int index, int period, EN_API_FL if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > Npats) - return (205); + return set_error(p->error_handle, 205); if (period <= 0 || period > Pattern[index].Length) - return (251); + return set_error(p->error_handle, 251); Pattern[index].F[period - 1] = value; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_addcurve(EN_Project *p, char *id) { +int DLLEXPORT EN_addcurve(EN_ProjectHandle ph, char *id) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; parser_data_t *par = &p->parser; Scurve *Curve = net->Curve; @@ -2982,21 +3224,21 @@ int DLLEXPORT EN_addcurve(EN_Project *p, char *id) { /* Check if a curve with same id already exists */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (ENgetcurveindex(id, &i) == 0) - return (215); + return set_error(p->error_handle, 215); /* Check that id name is not too long */ if (strlen(id) > MAXID) - return (250); + return set_error(p->error_handle, 250); /* Allocate memory for a new array of curves */ n = net->Ncurves + 1; tmpCur = (Scurve *)calloc(n + 1, sizeof(Scurve)); if (tmpCur == NULL) - return (101); + return set_error(p->error_handle, 101); /* Copy contents of old curve array to new one */ @@ -3042,7 +3284,7 @@ int DLLEXPORT EN_addcurve(EN_Project *p, char *id) { free(tmpCur[i].Y); } free(tmpCur); - return (101); + return set_error(p->error_handle, 101); } // Replace old curves array with new one @@ -3055,65 +3297,71 @@ int DLLEXPORT EN_addcurve(EN_Project *p, char *id) { net->Curve = tmpCur; net->Ncurves = n; par->MaxCurves = n; - return 0; + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setcurve(EN_Project *p, int index, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y, int n) { +int DLLEXPORT EN_setcurve(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y, int n) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Scurve *Curve = net->Curve; int j; /* Check for valid arguments */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > net->Ncurves) - return (206); + return set_error(p->error_handle, 206); if (n <= 0) - return (202); + return set_error(p->error_handle, 202); /* Re-set number of points & reallocate memory for values */ Curve[index].Npts = n; Curve[index].X = (double *)realloc(Curve[index].X, n * sizeof(double)); Curve[index].Y = (double *)realloc(Curve[index].Y, n * sizeof(double)); if (Curve[index].X == NULL) - return (101); + return set_error(p->error_handle, 101); if (Curve[index].Y == NULL) - return (101); + return set_error(p->error_handle, 101); /* Load values into curve */ for (j = 0; j < n; j++) { Curve[index].X[j] = x[j]; Curve[index].Y[j] = y[j]; } - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setcurvevalue(EN_Project *p, int index, int pnt, EN_API_FLOAT_TYPE x, EN_API_FLOAT_TYPE y) { - +int DLLEXPORT EN_setcurvevalue(EN_ProjectHandle ph, int index, int pnt, EN_API_FLOAT_TYPE x, EN_API_FLOAT_TYPE y) { + + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Scurve *Curve = net->Curve; const int Ncurves = net->Ncurves; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > Ncurves) - return (206); + return set_error(p->error_handle, 206); if (pnt <= 0 || pnt > Curve[index].Npts) - return (251); + return set_error(p->error_handle, 251); Curve[index].X[pnt - 1] = x; Curve[index].Y[pnt - 1] = y; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_settimeparam(EN_Project *p, int code, long value) +int DLLEXPORT EN_settimeparam(EN_ProjectHandle ph, int code, long value) { + EN_Project *p = (EN_Project*)ph; + report_options_t *rep = &p->report; quality_t *qu = &p->quality; time_options_t *time = &p->time_options; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (p->hydraulics.OpenHflag || p->quality.OpenQflag) { // --> there's nothing wrong with changing certain time parameters during a // simulation run, or before the run has started. @@ -3129,7 +3377,7 @@ int DLLEXPORT EN_settimeparam(EN_Project *p, int code, long value) */ } if (value < 0) - return (202); + return set_error(p->error_handle, 202); switch (code) { case EN_DURATION: time->Dur = value; @@ -3139,7 +3387,7 @@ int DLLEXPORT EN_settimeparam(EN_Project *p, int code, long value) case EN_HYDSTEP: if (value == 0) - return (202); + return set_error(p->error_handle, 202); time->Hstep = value; time->Hstep = MIN(time->Pstep, time->Hstep); time->Hstep = MIN(time->Rstep, time->Hstep); @@ -3148,14 +3396,14 @@ int DLLEXPORT EN_settimeparam(EN_Project *p, int code, long value) case EN_QUALSTEP: if (value == 0) - return (202); + return set_error(p->error_handle, 202); qu->Qstep = value; qu->Qstep = MIN(qu->Qstep, time->Hstep); break; case EN_PATTERNSTEP: if (value == 0) - return (202); + return set_error(p->error_handle, 202); time->Pstep = value; if (time->Hstep > time->Pstep) time->Hstep = time->Pstep; @@ -3167,7 +3415,7 @@ int DLLEXPORT EN_settimeparam(EN_Project *p, int code, long value) case EN_REPORTSTEP: if (value == 0) - return (202); + return set_error(p->error_handle, 202); time->Rstep = value; if (time->Hstep > time->Rstep) time->Hstep = time->Rstep; @@ -3175,20 +3423,20 @@ int DLLEXPORT EN_settimeparam(EN_Project *p, int code, long value) case EN_REPORTSTART: if (time->Rstart > time->Dur) - return (202); + return set_error(p->error_handle, 202); time->Rstart = value; break; case EN_RULESTEP: if (value == 0) - return (202); + return set_error(p->error_handle, 202); time->Rulestep = value; time->Rulestep = MIN(time->Rulestep, time->Hstep); break; case EN_STATISTIC: if (value > RANGE) - return (202); + return set_error(p->error_handle, 202); rep->Tstatflag = (char)value; break; @@ -3201,12 +3449,12 @@ int DLLEXPORT EN_settimeparam(EN_Project *p, int code, long value) break; default: - return (251); + return set_error(p->error_handle, 251); } - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setoption(EN_Project *p, int code, EN_API_FLOAT_TYPE v) +int DLLEXPORT EN_setoption(EN_ProjectHandle ph, int code, EN_API_FLOAT_TYPE v) /*---------------------------------------------------------------- ** Input: code = option code (see EPANET2.H) ** v = option value @@ -3216,6 +3464,8 @@ int DLLEXPORT EN_setoption(EN_Project *p, int code, EN_API_FLOAT_TYPE v) **---------------------------------------------------------------- */ { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; hydraulics_t *hyd = &p->hydraulics; quality_t *qu = &p->quality; @@ -3228,26 +3478,26 @@ int DLLEXPORT EN_setoption(EN_Project *p, int code, EN_API_FLOAT_TYPE v) int i, j; double Ke, n, ucf, value = v; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); switch (code) { case EN_TRIALS: if (value < 1.0) - return (202); + return set_error(p->error_handle, 202); hyd->MaxIter = (int)value; break; case EN_ACCURACY: if (value < 1.e-5 || value > 1.e-1) - return (202); + return set_error(p->error_handle, 202); hyd->Hacc = value; break; case EN_TOLERANCE: if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); qu->Ctol = value / Ucf[QUALITY]; break; case EN_EMITEXPON: if (value <= 0.0) - return (202); + return set_error(p->error_handle, 202); n = 1.0 / value; ucf = pow(Ucf[FLOW], n) / Ucf[PRESSURE]; for (i = 1; i <= Njuncs; i++) { @@ -3260,38 +3510,43 @@ int DLLEXPORT EN_setoption(EN_Project *p, int code, EN_API_FLOAT_TYPE v) break; case EN_DEMANDMULT: if (value <= 0.0) - return (202); + return set_error(p->error_handle, 202); hyd->Dmult = value; break; case EN_HEADERROR: if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); hyd->HeadErrorLimit = value / Ucf[HEAD]; break; case EN_FLOWCHANGE: if (value < 0.0) - return (202); + return set_error(p->error_handle, 202); hyd->FlowChangeLimit = value / Ucf[FLOW]; break; default: - return (251); + return set_error(p->error_handle, 251); } - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setstatusreport(EN_Project *p, int code) { +int DLLEXPORT EN_setstatusreport(EN_ProjectHandle ph, int code) { int errcode = 0; + + EN_Project *p = (EN_Project*)ph; + if (code >= 0 && code <= 2) p->report.Statflag = (char)code; else errcode = 202; - return (errcode); + return set_error(p->error_handle, errcode); } -int DLLEXPORT EN_setqualtype(EN_Project *p, int qualcode, char *chemname, char *chemunits, char *tracenode) { +int DLLEXPORT EN_setqualtype(EN_ProjectHandle ph, int qualcode, char *chemname, char *chemunits, char *tracenode) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; report_options_t *rep = &p->report; quality_t *qu = &p->quality; @@ -3303,9 +3558,9 @@ int DLLEXPORT EN_setqualtype(EN_Project *p, int qualcode, char *chemname, char * double ccf = 1.0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (qualcode < EN_NONE || qualcode > EN_TRACE) - return (251); + return set_error(p->error_handle, 251); qu->Qualflag = (char)qualcode; qu->Ctol *= Ucf[QUALITY]; if (qu->Qualflag == CHEM) /* Chemical constituent */ @@ -3323,7 +3578,7 @@ int DLLEXPORT EN_setqualtype(EN_Project *p, int qualcode, char *chemname, char * { qu->TraceNode = findnode(net,tracenode); if (qu->TraceNode == 0) - return (203); + return set_error(p->error_handle, 203); strncpy(qu->ChemName, u_PERCENT, MAXID); strncpy(qu->ChemUnits, tracenode, MAXID); @@ -3352,26 +3607,30 @@ int DLLEXPORT EN_setqualtype(EN_Project *p, int qualcode, char *chemname, char * Ucf[REACTRATE] = ccf; qu->Ctol /= Ucf[QUALITY]; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getheadcurveindex(EN_Project *p, int index, int *curveindex) { +int DLLEXPORT EN_getheadcurveindex(EN_ProjectHandle ph, int index, int *curveindex) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Slink *Link = net->Link; Spump *Pump = net->Pump; const int Nlinks = net->Nlinks; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > Nlinks || EN_PUMP != Link[index].Type) - return (204); + return set_error(p->error_handle, 204); *curveindex = Pump[findpump(net, index)].Hcurve; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setheadcurveindex(EN_Project *p, int index, int curveindex) { +int DLLEXPORT EN_setheadcurveindex(EN_ProjectHandle ph, int index, int curveindex) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Slink *Link = net->Link; @@ -3383,12 +3642,12 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project *p, int index, int curveindex) { Spump *pump; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > Nlinks || EN_PUMP != Link[index].Type) { - return (204); + return set_error(p->error_handle, 204); } if (curveindex <= 0 || curveindex > Ncurves) { - return (206); + return set_error(p->error_handle, 206); } pIdx = findpump(net, index); pump = &p->network.Pump[pIdx]; @@ -3407,11 +3666,13 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project *p, int index, int curveindex) { pump->Hmax /= Ucf[HEAD]; p->network.Curve[curveindex].Type = P_CURVE; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getpumptype(EN_Project *p, int index, int *type) { +int DLLEXPORT EN_getpumptype(EN_ProjectHandle ph, int index, int *type) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Slink *Link = net->Link; @@ -3420,23 +3681,25 @@ int DLLEXPORT EN_getpumptype(EN_Project *p, int index, int *type) { *type = -1; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > Nlinks || EN_PUMP != Link[index].Type) - return (204); + return set_error(p->error_handle, 204); *type = Pump[findpump(&p->network, index)].Ptype; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getcurvetype(EN_Project *p, int curveindex, int *type) { +int DLLEXPORT EN_getcurvetype(EN_ProjectHandle ph, int curveindex, int *type) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (curveindex < 1 || curveindex > net->Ncurves) - return (206); + return set_error(p->error_handle, 206); *type = net->Curve[curveindex].Type; - return (0); + return set_error(p->error_handle, 0); } /* @@ -3445,7 +3708,7 @@ int DLLEXPORT EN_getcurvetype(EN_Project *p, int curveindex, int *type) { ---------------------------------------------------------------- */ -int openfiles(EN_Project *p, char *f1, char *f2, char *f3) +int openfiles(EN_Project *p, const char *f1, const char *f2, const char *f3) /*---------------------------------------------------------------- ** Input: f1 = pointer to name of input file ** f2 = pointer to name of report file @@ -3480,23 +3743,23 @@ int openfiles(EN_Project *p, char *f1, char *f2, char *f3) if (strcomp(f1, f2) || strcomp(f1, f3) || (strcomp(f2, f3) && (strlen(f2) > 0 || strlen(f3) > 0))) { writecon(FMT04); - return (301); + return set_error(p->error_handle, 301); } /* Attempt to open input and report files */ if ((par->InFile = fopen(f1, "rt")) == NULL) { writecon(FMT05); writecon(f1); - return (302); + return set_error(p->error_handle, 302); } if (strlen(f2) == 0) rep->RptFile = stdout; else if ((rep->RptFile = fopen(f2, "wt")) == NULL) { writecon(FMT06); - return (303); + return set_error(p->error_handle, 303); } - return (0); + return set_error(p->error_handle, 0); } /* End of openfiles */ int openhydfile(EN_Project *p) @@ -3527,7 +3790,7 @@ int openhydfile(EN_Project *p) /* If HydFile currently open, then close it if its not a scratch file */ if (out->HydFile != NULL) { if (out->Hydflag == SCRATCH) - return (0); + return set_error(p->error_handle, 0); fclose(out->HydFile); } @@ -3547,7 +3810,7 @@ int openhydfile(EN_Project *p) break; } if (out->HydFile == NULL) - return (305); + return set_error(p->error_handle, 305); /* If a previous hydraulics solution is not being used, then */ /* save the current network size parameters to the file. */ @@ -3571,22 +3834,22 @@ int openhydfile(EN_Project *p) if (out->Hydflag == USE) { fread(&magic, sizeof(INT4), 1, out->HydFile); if (magic != MAGICNUMBER) - return (306); + return set_error(p->error_handle, 306); fread(&version, sizeof(INT4), 1, out->HydFile); if (version != ENGINE_VERSION) - return (306); + return set_error(p->error_handle, 306); if (fread(nsize, sizeof(INT4), 6, out->HydFile) < 6) - return (306); + return set_error(p->error_handle, 306); if (nsize[0] != Nnodes || nsize[1] != Nlinks || nsize[2] != Ntanks || nsize[3] != Npumps || nsize[4] != Nvalves || nsize[5] != time->Dur) - return (306); + return set_error(p->error_handle, 306); p->save_options.SaveHflag = TRUE; } /* Save current position in hydraulics file */ /* where storage of hydraulic results begins */ out->HydOffset = ftell(out->HydFile); - return (errcode); + return set_error(p->error_handle, errcode); } int openoutfile(EN_Project *p) @@ -3654,7 +3917,7 @@ int openoutfile(EN_Project *p) } else out->TmpOutFile = out->OutFile; } - return (errcode); + return set_error(p->error_handle, errcode); } /* @@ -3828,7 +4091,7 @@ int allocdata(EN_Project *p) /* Allocate memory for rule base (see RULES.C) */ if (!errcode) errcode = allocrules(p); - return (errcode); + return set_error(p->error_handle, errcode); } /* End of allocdata */ void freeTmplist(STmplist *t) @@ -3978,35 +4241,6 @@ char *getTmpName(EN_Project *p, char *fname) // --- free the pointer returned by _tempnam if (name) free(name); -/* -/////////////////// DEPRECATED ///////////////////////////////////// -// --- for Windows systems: -#ifdef WINDOWS - // --- use system function tmpnam() to create a temporary file name - char name[MAXFNAME + 1]; - int n; - - tmpnam(name); - - // --- if user supplied the name of a temporary directory, - // then make it be the prefix of the full file name - n = (int)strlen(out->TmpDir); - if (n > 0) { - strcpy(fname, out->TmpDir); - if (fname[n - 1] != '\\') - strcat(fname, "\\"); - } - - // --- otherwise, use the relative path notation as the file name - // prefix so that the file will be placed in the current directory - else { - strcpy(fname, ".\\"); - } - - // --- now add the prefix to the file name - strcat(fname, name); -*/ - // --- for non-Windows systems: #else // --- use system function mkstemp() to create a temporary file name @@ -4016,7 +4250,7 @@ char *getTmpName(EN_Project *p, char *fname) return fname; } -int strcomp(char *s1, char *s2) +int strcomp(const char *s1, const char *s2) /*--------------------------------------------------------------- ** Input: s1 = character string ** s2 = character string @@ -4156,11 +4390,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); } @@ -4182,7 +4416,7 @@ void errmsg(EN_Project *p, int errcode) } } -void writecon(char *s) +void writecon(const char *s) /*---------------------------------------------------------------- ** Input: text string ** Output: none @@ -4211,44 +4445,52 @@ void writewin(void (*vp)(char *), char *s) } } -int DLLEXPORT EN_getnumdemands(EN_Project *p, int nodeIndex, int *numDemands) { +int DLLEXPORT EN_getnumdemands(EN_ProjectHandle ph, int nodeIndex, int *numDemands) { Pdemand d; int n = 0; + + EN_Project *p = (EN_Project*)ph; + /* Check for valid arguments */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) - return (203); + return set_error(p->error_handle, 203); for (d = p->network.Node[nodeIndex].D; d != NULL; d = d->next) n++; *numDemands = n; - return 0; + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getbasedemand(EN_Project *p, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE *baseDemand) { +int DLLEXPORT EN_getbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE *baseDemand) { Pdemand d; int n = 1; + + EN_Project *p = (EN_Project*)ph; + /* Check for valid arguments */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) - return (203); + return set_error(p->error_handle, 203); if (nodeIndex <= p->network.Njuncs) { for (d = p->network.Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) { n++; } if (n != demandIdx) { - return (253); + return set_error(p->error_handle, 253); } *baseDemand = (EN_API_FLOAT_TYPE)(d->Base * p->Ucf[FLOW]); } else { *baseDemand = (EN_API_FLOAT_TYPE)(0.0); } - return 0; + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setbasedemand(EN_Project *pr, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE baseDemand) { +int DLLEXPORT EN_setbasedemand(EN_ProjectHandle ph, int nodeIndex, int demandIdx, EN_API_FLOAT_TYPE baseDemand) { + EN_Project *pr = (EN_Project*)ph; + EN_Network *net = &pr->network; Snode *Node = net->Node; @@ -4261,21 +4503,23 @@ int DLLEXPORT EN_setbasedemand(EN_Project *pr, int nodeIndex, int demandIdx, EN_ int n = 1; /* Check for valid arguments */ if (!pr->Openflag) - return (102); + return set_error(pr->error_handle, 102); if (nodeIndex <= 0 || nodeIndex > Nnodes) - return (203); + return set_error(pr->error_handle, 203); if (nodeIndex <= Njuncs) { for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) n++; if (n != demandIdx) - return (253); + return set_error(pr->error_handle, 253); d->Base = baseDemand / Ucf[FLOW]; } - return 0; + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_getdemandpattern(EN_Project *p, int nodeIndex, int demandIdx, int *pattIdx) { +int DLLEXPORT EN_getdemandpattern(EN_ProjectHandle ph, int nodeIndex, int demandIdx, int *pattIdx) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Snode *Node = net->Node; const int Nnodes = net->Nnodes; @@ -4284,19 +4528,21 @@ int DLLEXPORT EN_getdemandpattern(EN_Project *p, int nodeIndex, int demandIdx, i int n = 1; /* Check for valid arguments */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (nodeIndex <= 0 || nodeIndex > Nnodes) - return (203); + return set_error(p->error_handle, 203); for (d = Node[nodeIndex].D; n < demandIdx && d != NULL; d = d->next) n++; if (n != demandIdx) - return (253); + return set_error(p->error_handle, 253); *pattIdx = d->Pat; - return 0; + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getaveragepatternvalue(EN_Project *p, int index, EN_API_FLOAT_TYPE *value) { +int DLLEXPORT EN_getaveragepatternvalue(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE *value) { + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Spattern *Pattern = net->Pattern; @@ -4305,34 +4551,36 @@ int DLLEXPORT EN_getaveragepatternvalue(EN_Project *p, int index, EN_API_FLOAT_T int i; *value = 0.0; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index < 1 || index > Npats) - return (205); + return set_error(p->error_handle, 205); // if (period < 1 || period > Pattern[index].Length) return(251); for (i = 0; i < Pattern[index].Length; i++) { *value += (EN_API_FLOAT_TYPE)Pattern[index].F[i]; } *value /= (EN_API_FLOAT_TYPE)Pattern[index].Length; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_setlinktype(EN_Project *p, char *id, EN_LinkType toType) { +int DLLEXPORT EN_setlinktype(EN_ProjectHandle ph, char *id, EN_LinkType toType) { int i; EN_LinkType fromType; + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); /* Check if a link with the id exists */ if (EN_getlinkindex(p, id, &i) != 0) - return (215); + return set_error(p->error_handle, 215); /* Get the current type of the link */ ENgetlinktype(i, &fromType); if (fromType == toType) - return (0); + return set_error(p->error_handle, 0); /* Change link from Pipe */ if (toType <= EN_PIPE) { @@ -4350,13 +4598,16 @@ int DLLEXPORT EN_setlinktype(EN_Project *p, char *id, EN_LinkType toType) { } else if (fromType == EN_PUMP) { net->Npumps--; } - return 0; + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_addnode(EN_Project *p, char *id, EN_NodeType nodeType) { +int DLLEXPORT EN_addnode(EN_ProjectHandle ph, char *id, EN_NodeType nodeType) { int i, nIdx; int index; struct Sdemand *demand; + + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; hydraulics_t *hyd = &p->hydraulics; quality_t *qu = &p->quality; @@ -4366,13 +4617,13 @@ int DLLEXPORT EN_addnode(EN_Project *p, char *id, EN_NodeType nodeType) { /* Check if a node with same id already exists */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (ENgetnodeindex(id, &i) == 0) - return (215); + return set_error(p->error_handle, 215); /* Check that id name is not too long */ if (strlen(id) > MAXID) - return (250); + return set_error(p->error_handle, 250); /* Grow arrays to accomodate the new values */ net->Node = (Snode *)realloc(net->Node, (net->Nnodes + 2) * sizeof(Snode)); @@ -4464,13 +4715,16 @@ int DLLEXPORT EN_addnode(EN_Project *p, char *id, EN_NodeType nodeType) { /* Insert new node into hash table */ ENHashTableInsert(net->NodeHashTable, node->ID, nIdx); /* see HASH.C */ - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_addlink(EN_Project *p, char *id, EN_LinkType linkType, char *fromNode, +int DLLEXPORT EN_addlink(EN_ProjectHandle ph, char *id, EN_LinkType linkType, char *fromNode, char *toNode) { int i, n; int N1, N2; + + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; hydraulics_t *hyd = &p->hydraulics; Slink *link; @@ -4478,21 +4732,21 @@ int DLLEXPORT EN_addlink(EN_Project *p, char *id, EN_LinkType linkType, char *fr /* Check if a link with same id already exists */ if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (ENgetlinkindex(id, &i) == 0) - return (215); + return set_error(p->error_handle, 215); /* Lookup the from and to nodes */ N1 = ENHashTableFind(net->NodeHashTable, fromNode); N2 = ENHashTableFind(net->NodeHashTable, toNode); if (N1 == 0 || N2 == 0) { - return (203); + return set_error(p->error_handle, 203); } /* Check that id name is not too long */ if (strlen(id) > MAXID) - return (250); + return set_error(p->error_handle, 250); net->Nlinks++; n = net->Nlinks; @@ -4574,19 +4828,22 @@ int DLLEXPORT EN_addlink(EN_Project *p, char *id, EN_LinkType linkType, char *fr } ENHashTableInsert(net->LinkHashTable, link->ID, n); - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_deletelink(EN_Project *p, int index) { +int DLLEXPORT EN_deletelink(EN_ProjectHandle ph, int index) { int i; EN_LinkType linkType; + + EN_Project *p = (EN_Project*)ph; + EN_Network *net = &p->network; Slink *link; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > net->Nlinks) - return (203); + return set_error(p->error_handle, 203); EN_getlinktype(p, index, &linkType); @@ -4633,19 +4890,21 @@ int DLLEXPORT EN_deletelink(EN_Project *p, int index) { net->Nvalves--; } - return 0; + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_deletenode(EN_Project *p, int index) { +int DLLEXPORT EN_deletenode(EN_ProjectHandle ph, int index) { + + EN_Project *p = (EN_Project*)ph; EN_Network *net = &p->network; int i, nodeType; if (!p->Openflag) - return (102); + return set_error(p->error_handle, 102); if (index <= 0 || index > net->Nnodes) - return (203); + return set_error(p->error_handle, 203); EN_getnodetype(p, index, &nodeType); @@ -4701,10 +4960,10 @@ int DLLEXPORT EN_deletenode(EN_Project *p, int index) { net->Nnodes--; - return (0); + return set_error(p->error_handle, 0); } -int DLLEXPORT EN_getrule(EN_Project *pr, int index, int *nPremises, int *nTrueActions, int *nFalseActions, EN_API_FLOAT_TYPE *priority) +int DLLEXPORT EN_getrule(EN_ProjectHandle ph, int index, int *nPremises, int *nTrueActions, int *nFalseActions, EN_API_FLOAT_TYPE *priority) /*---------------------------------------------------------------- ** Input: index = index of the rule ** nPremises = number of conditions (IF AND OR) @@ -4720,10 +4979,12 @@ int DLLEXPORT EN_getrule(EN_Project *pr, int index, int *nPremises, int *nTrueAc Premise *p; Action *c; + EN_Project *pr = (EN_Project*)ph; + EN_Network *net = &pr->network; if (index > net->Nrules) - return (257); + return set_error(pr->error_handle, 257); *priority = (EN_API_FLOAT_TYPE)pr->rules.Rule[index].priority; count = 1; p = pr->rules.Rule[index].Pchain; @@ -4750,24 +5011,24 @@ int DLLEXPORT EN_getrule(EN_Project *pr, int index, int *nPremises, int *nTrueAc } } *nFalseActions = count; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_getpremise(EN_Project *pr, int indexRule, int idxPremise, int *logop, +int DLLEXPORT EN_getpremise(EN_ProjectHandle ph, int indexRule, int idxPremise, int *logop, int *object, int *indexObj, int *variable, int *relop, int *status, EN_API_FLOAT_TYPE *value) { int count = 1, error = 0, nPremises, a, b; EN_API_FLOAT_TYPE priority; Premise *p; - + EN_Project *pr = (EN_Project*)ph; if (indexRule > pr->network.Nrules) { - return (257); + return set_error(pr->error_handle, 257); } error = EN_getrule(pr, indexRule, &nPremises, &a, &b, &priority); if (idxPremise > nPremises) { - return (258); + return set_error(pr->error_handle, 258); } p = pr->rules.Rule[indexRule].Pchain; @@ -4782,10 +5043,10 @@ int DLLEXPORT EN_getpremise(EN_Project *pr, int indexRule, int idxPremise, int * *relop = p->relop; *status = p->status; *value = (EN_API_FLOAT_TYPE)p[0].value; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_setrulepriority(EN_Project *pr, int index, EN_API_FLOAT_TYPE priority) +int DLLEXPORT EN_setrulepriority(EN_ProjectHandle ph, int index, EN_API_FLOAT_TYPE priority) /*---------------------------------------------------------------- ** Input: index = index of the rule ** priority = rule priority @@ -4794,29 +5055,32 @@ int DLLEXPORT EN_setrulepriority(EN_Project *pr, int index, EN_API_FLOAT_TYPE pr **---------------------------------------------------------------- */ { + EN_Project *pr = (EN_Project*)ph; + if (index > pr->network.Nrules) { - return (257); + return set_error(pr->error_handle, 257); } pr->rules.Rule[index].priority = priority; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_setpremise(EN_Project *pr, int indexRule, int indexPremise, int logop, +int DLLEXPORT EN_setpremise(EN_ProjectHandle ph, int indexRule, int indexPremise, int logop, int object, int indexObj, int variable, int relop, int status, EN_API_FLOAT_TYPE value) { int count = 1, error = 0, nPremises, a, b; EN_API_FLOAT_TYPE priority; Premise *p; - + EN_Project *pr; + pr = (EN_Project*)ph; if (indexRule > pr->network.Nrules) { - return (257); + return set_error(pr->error_handle, 257); } error = EN_getrule(pr, indexRule, &nPremises, &a, &b, &priority); if (indexPremise > nPremises) { - return (258); + return set_error(pr->error_handle, 258); } p = pr->rules.Rule[indexRule].Pchain; while (count < indexPremise) { @@ -4830,19 +5094,21 @@ int DLLEXPORT EN_setpremise(EN_Project *pr, int indexRule, int indexPremise, int p->relop = relop; p->status = status; p->value = value; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_setpremiseindex(EN_Project *pr, int indexRule, int indexPremise, int indexObj) { +int DLLEXPORT EN_setpremiseindex(EN_ProjectHandle ph, int indexRule, int indexPremise, int indexObj) { int count = 1, error = 0, nPremises, a, b; EN_API_FLOAT_TYPE priority; Premise *p; + EN_Project *pr = (EN_Project*)ph; + if (indexRule > pr->network.Nrules) - return (257); + return set_error(pr->error_handle, 257); error = EN_getrule(pr, indexRule, &nPremises, &a, &b, &priority); if (indexPremise > nPremises) { - return (258); + return set_error(pr->error_handle, 258); } p = pr->rules.Rule[indexRule].Pchain; while (count < indexPremise) { @@ -4850,20 +5116,22 @@ int DLLEXPORT EN_setpremiseindex(EN_Project *pr, int indexRule, int indexPremise p = p->next; } p->index = indexObj; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_setpremisestatus(EN_Project *pr, int indexRule, int indexPremise, int status) { +int DLLEXPORT EN_setpremisestatus(EN_ProjectHandle ph, int indexRule, int indexPremise, int status) { int count = 1, error = 0, nPremises, a, b; EN_API_FLOAT_TYPE priority; Premise *p; + EN_Project *pr = (EN_Project*)ph; + if (indexRule > pr->network.Nrules) { - return (257); + return set_error(pr->error_handle, 257); } error = EN_getrule(pr, indexRule, &nPremises, &a, &b, &priority); if (indexPremise > nPremises) { - return (258); + return set_error(pr->error_handle, 258); } p = pr->rules.Rule[indexRule].Pchain; while (count < indexPremise) { @@ -4871,20 +5139,22 @@ int DLLEXPORT EN_setpremisestatus(EN_Project *pr, int indexRule, int indexPremis p = p->next; } p->status = status; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_setpremisevalue(EN_Project *pr, int indexRule, int indexPremise, +int DLLEXPORT EN_setpremisevalue(EN_ProjectHandle ph, int indexRule, int indexPremise, EN_API_FLOAT_TYPE value) { int count = 1, error = 0, nPremises, a, b; EN_API_FLOAT_TYPE priority; Premise *p; + EN_Project *pr = (EN_Project*)ph; + if (indexRule > pr->network.Nrules) - return (257); + return set_error(pr->error_handle, 257); error = EN_getrule(pr, indexRule, &nPremises, &a, &b, &priority); if (indexPremise > nPremises) { - return (258); + return set_error(pr->error_handle, 258); } p = pr->rules.Rule[indexRule].Pchain; while (count < indexPremise) { @@ -4892,21 +5162,23 @@ int DLLEXPORT EN_setpremisevalue(EN_Project *pr, int indexRule, int indexPremise p = p->next; } p->value = value; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_gettrueaction(EN_Project *pr, int indexRule, int indexAction, int *indexLink, +int DLLEXPORT EN_gettrueaction(EN_ProjectHandle ph, int indexRule, int indexAction, int *indexLink, int *status, EN_API_FLOAT_TYPE *setting) { int count = 1, error = 0, nTrueAction, c, b; EN_API_FLOAT_TYPE priority; Action *a; + EN_Project *pr = (EN_Project*)ph; + if (indexRule > pr->network.Nrules) { - return (252); + return set_error(pr->error_handle, 252); } error = EN_getrule(pr, indexRule, &c, &nTrueAction, &b, &priority); if (indexAction > nTrueAction) { - return (253); + return set_error(pr->error_handle, 253); } a = pr->rules.Rule[indexRule].Tchain; while (count < indexAction) { @@ -4916,21 +5188,23 @@ int DLLEXPORT EN_gettrueaction(EN_Project *pr, int indexRule, int indexAction, i *indexLink = a->link; *status = a->status; *setting = (EN_API_FLOAT_TYPE)a->setting; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_settrueaction(EN_Project *pr, int indexRule, int indexAction, int indexLink, +int DLLEXPORT EN_settrueaction(EN_ProjectHandle ph, int indexRule, int indexAction, int indexLink, int status, EN_API_FLOAT_TYPE setting) { int count = 1, error = 0, nTrueAction, c, b; EN_API_FLOAT_TYPE priority; Action *a; + EN_Project *pr = (EN_Project*)ph; + if (indexRule > pr->network.Nrules) { - return (257); + return set_error(pr->error_handle, 257); } error = EN_getrule(pr, indexRule, &c, &nTrueAction, &b, &priority); if (indexAction > nTrueAction) { - return (258); + return set_error(pr->error_handle, 258); } a = pr->rules.Rule[indexRule].Tchain; while (count < indexAction) { @@ -4940,21 +5214,23 @@ int DLLEXPORT EN_settrueaction(EN_Project *pr, int indexRule, int indexAction, i a->link = indexLink; a->status = status; a->setting = setting; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_getfalseaction(EN_Project *pr, int indexRule, int indexAction, int *indexLink, +int DLLEXPORT EN_getfalseaction(EN_ProjectHandle ph, int indexRule, int indexAction, int *indexLink, int *status, EN_API_FLOAT_TYPE *setting) { int count = 1, error = 0, nFalseAction, c, b; EN_API_FLOAT_TYPE priority; Action *a; + EN_Project *pr = (EN_Project*)ph; + if (indexRule > pr->network.Nrules) { - return (257); + return set_error(pr->error_handle, 257); } error = EN_getrule(pr, indexRule, &c, &b, &nFalseAction, &priority); if (indexAction > nFalseAction) { - return (258); + return set_error(pr->error_handle, 258); } a = pr->rules.Rule[indexRule].Fchain; while (count < indexAction) { @@ -4964,21 +5240,23 @@ int DLLEXPORT EN_getfalseaction(EN_Project *pr, int indexRule, int indexAction, *indexLink = a->link; *status = a->status; *setting = (EN_API_FLOAT_TYPE)a->setting; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_setfalseaction(EN_Project *pr, int indexRule, int indexAction, int indexLink, +int DLLEXPORT EN_setfalseaction(EN_ProjectHandle ph, int indexRule, int indexAction, int indexLink, int status, EN_API_FLOAT_TYPE setting) { int count = 1, error = 0, nFalseAction, c, b; EN_API_FLOAT_TYPE priority; Action *a; + EN_Project *pr = (EN_Project*)ph; + if (indexRule > pr->network.Nrules) { - return (257); + return set_error(pr->error_handle, 257); } error = EN_getrule(pr, indexRule, &c, &b, &nFalseAction, &priority); if (indexAction > nFalseAction) { - return (258); + return set_error(pr->error_handle, 258); } a = pr->rules.Rule[indexRule].Fchain; while (count < indexAction) { @@ -4989,17 +5267,20 @@ int DLLEXPORT EN_setfalseaction(EN_Project *pr, int indexRule, int indexAction, a->status = status; a->setting = setting; - return (0); + return set_error(pr->error_handle, 0); } -int DLLEXPORT EN_getruleID(EN_Project *pr, int indexRule, char *id) { +int DLLEXPORT EN_getruleID(EN_ProjectHandle ph, int indexRule, char *id) { + + EN_Project *pr = (EN_Project*)ph; + strcpy(id, ""); if (!pr->Openflag) - return (102); + return set_error(pr->error_handle, 102); if (indexRule < 1 || indexRule > pr->network.Nrules) - return (257); + return set_error(pr->error_handle, 257); strcpy(id, pr->rules.Rule[indexRule].label); - return (0); + return set_error(pr->error_handle, 0); } /*************************** END OF EPANET.C ***************************/ diff --git a/src/funcs.h b/src/funcs.h index e274ded..b961a82 100755 --- a/src/funcs.h +++ b/src/funcs.h @@ -36,10 +36,11 @@ int allocdata(EN_Project *pr); /* Allocates memory void freeTmplist(STmplist *); /* Frees items in linked list */ void freeFloatlist(SFloatlist *); /* Frees list of floats */ void freedata(EN_Project *pr); /* Frees allocated memory */ -int openfiles(EN_Project *pr, char *,char *,char *); /* Opens input & report files */ +int openfiles(EN_Project *pr, const char *, + const char *,const char *); /* Opens input & report files */ int openhydfile(EN_Project *pr); /* Opens hydraulics file */ int openoutfile(EN_Project *pr); /* Opens binary output file */ -int strcomp(char *, char *); /* Compares two strings */ +int strcomp(const char *, const char *); /* Compares two strings */ char* getTmpName(EN_Project *p, char* fname); /* Gets temporary file name */ double interp(int n, double x[], double y[], double xx); /* Interpolates a data curve */ @@ -51,7 +52,7 @@ int findvalve(EN_Network *n, int); /* Find valve index from node int findpump(EN_Network *n, int); /* Find pump index from node index */ // (AH) char *geterrmsg(int errcode, char *msg); /* Gets text of error message */ void errmsg(EN_Project *p, int); /* Reports program error */ -void writecon(char *); /* Writes text to console */ +void writecon(const char *); /* Writes text to console */ void writewin(void (*vp)(char *), char *); /* Passes text to calling app */ /* ------- INPUT1.C --------------------*/ @@ -126,6 +127,8 @@ void freerules(EN_Project *pr); /* Frees rule base memory int writeRuleinInp(EN_Project *pr, FILE *f, /* Writes rule to an INP file */ int RuleIdx); +int writeRuleinInp(EN_Project *pr, FILE *f, int RuleIdx); + /* ------------- REPORT.C --------------*/ int writereport(EN_Project *pr); /* Writes formatted report */ void writelogo(EN_Project *pr); /* Writes program logo */ diff --git a/src/input2.c b/src/input2.c index e4836b5..c40d029 100644 --- a/src/input2.c +++ b/src/input2.c @@ -820,9 +820,10 @@ int match(const char *str, const char *substr) break; /* Check if substr matches remainder of str. */ - for (i = i, j = 0; substr[j]; i++, j++) + for (j = 0; substr[j]; i++, j++) if (!str[i] || UCHAR(str[i]) != UCHAR(substr[j])) return (0); + return (1); } /* end of match */ diff --git a/src/rules.c b/src/rules.c index d5da392..b8d0518 100644 --- a/src/rules.c +++ b/src/rules.c @@ -112,7 +112,7 @@ int takeactions(EN_Project *pr); void clearactlist(rules_t *rules); void clearrules(EN_Project *pr); void ruleerrmsg(EN_Project *pr, int); -int writeRuleinInp(EN_Project *pr, FILE *f, int RuleIdx); +//int writeRuleinInp(EN_Project *pr, FILE *f, int RuleIdx); void initrules(rules_t *rules) /* diff --git a/src/types.h b/src/types.h index c520280..d887c96 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). */ @@ -861,7 +863,7 @@ typedef struct { /* project wrapper */ -struct EN_Project { +typedef struct EN_Project { EN_Network network; /// the network description struct hydraulics_t hydraulics; @@ -883,8 +885,10 @@ 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; #endif 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/src/vars.h b/src/vars.h index 04f540c..9c4c08f 100755 --- a/src/vars.h +++ b/src/vars.h @@ -11,6 +11,6 @@ // this single global variable is used only when the library is called in "legacy mode" // with the 2.1-style API. -EXTERN EN_Project *_defaultModel; +EXTERN void *_defaultModel; #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 609d0b4..be6dc5a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,8 +37,7 @@ foreach(testSrc ${TEST_SRCS}) #link to Boost libraries AND your targets and dependencies target_link_libraries(${testName} ${Boost_LIBRARIES} epanet epanet-output) - - #Finally add it to test execution - + #Finally add it to test execution #Notice the WORKING_DIRECTORY and COMMAND add_test(NAME ${testName} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${testName} diff --git a/tests/data/example1.out b/tests/data/example1.out new file mode 100644 index 0000000..416c98b Binary files /dev/null and b/tests/data/example1.out differ diff --git a/tests/data/net1.inp b/tests/data/net1.inp new file mode 100644 index 0000000..4df5bbf --- /dev/null +++ b/tests/data/net1.inp @@ -0,0 +1,178 @@ +[TITLE] + EPANET Example Network 1 +A simple example of modeling chlorine decay. Both bulk and +wall reactions are included. + +[JUNCTIONS] +;ID Elev Demand Pattern + 10 710 0 ; + 11 710 150 ; + 12 700 150 ; + 13 695 100 ; + 21 700 150 ; + 22 695 200 ; + 23 690 150 ; + 31 700 100 ; + 32 710 100 ; + +[RESERVOIRS] +;ID Head Pattern + 9 800 ; + +[TANKS] +;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve + 2 850 120 100 150 50.5 0 ; + +[PIPES] +;ID Node1 Node2 Length Diameter Roughness MinorLoss Status + 10 10 11 10530 18 100 0 Open ; + 11 11 12 5280 14 100 0 Open ; + 12 12 13 5280 10 100 0 Open ; + 21 21 22 5280 10 100 0 Open ; + 22 22 23 5280 12 100 0 Open ; + 31 31 32 5280 6 100 0 Open ; + 110 2 12 200 18 100 0 Open ; + 111 11 21 5280 10 100 0 Open ; + 112 12 22 5280 12 100 0 Open ; + 113 13 23 5280 8 100 0 Open ; + 121 21 31 5280 8 100 0 Open ; + 122 22 32 5280 6 100 0 Open ; + +[PUMPS] +;ID Node1 Node2 Parameters + 9 9 10 HEAD 1 ; + +[VALVES] +;ID Node1 Node2 Diameter Type Setting MinorLoss + +[TAGS] + +[DEMANDS] +;Junction Demand Pattern Category + +[STATUS] +;ID Status/Setting + +[PATTERNS] +;ID Multipliers +;Demand Pattern + 1 1.0 1.2 1.4 1.6 1.4 1.2 + 1 1.0 0.8 0.6 0.4 0.6 0.8 + +[CURVES] +;ID X-Value Y-Value +;PUMP: Pump Curve for Pump 9 + 1 1500 250 + +[CONTROLS] + LINK 9 OPEN IF NODE 2 BELOW 110 + LINK 9 CLOSED IF NODE 2 ABOVE 140 + + +[RULES] + +[ENERGY] + Global Efficiency 75 + Global Price 0.0 + Demand Charge 0.0 + +[EMITTERS] +;Junction Coefficient + +[QUALITY] +;Node InitQual + 10 0.5 + 11 0.5 + 12 0.5 + 13 0.5 + 21 0.5 + 22 0.5 + 23 0.5 + 31 0.5 + 32 0.5 + 9 1.0 + 2 1.0 + +[SOURCES] +;Node Type Quality Pattern + +[REACTIONS] +;Type Pipe/Tank Coefficient + + +[REACTIONS] + Order Bulk 1 + Order Tank 1 + Order Wall 1 + Global Bulk -.5 + Global Wall -1 + Limiting Potential 0.0 + Roughness Correlation 0.0 + +[MIXING] +;Tank Model + +[TIMES] + Duration 24:00 + Hydraulic Timestep 1:00 + Quality Timestep 0:05 + Pattern Timestep 2:00 + Pattern Start 0:00 + Report Timestep 1:00 + Report Start 0:00 + Start ClockTime 12 am + Statistic None + +[REPORT] + Status Yes + Summary No + Page 0 + +[OPTIONS] + Units GPM + Headloss H-W + Specific Gravity 1.0 + Viscosity 1.0 + Trials 40 + Accuracy 0.001 + CHECKFREQ 2 + MAXCHECK 10 + DAMPLIMIT 0 + Unbalanced Continue 10 + Pattern 1 + Demand Multiplier 1.0 + Emitter Exponent 0.5 + Quality Chlorine mg/L + Diffusivity 1.0 + Tolerance 0.01 + +[COORDINATES] +;Node X-Coord Y-Coord + 10 20.00 70.00 + 11 30.00 70.00 + 12 50.00 70.00 + 13 70.00 70.00 + 21 30.00 40.00 + 22 50.00 40.00 + 23 70.00 40.00 + 31 30.00 10.00 + 32 50.00 10.00 + 9 10.00 70.00 + 2 50.00 90.00 + +[VERTICES] +;Link X-Coord Y-Coord + +[LABELS] +;X-Coord Y-Coord Label & Anchor Node + 6.99 73.63 "Source" + 13.48 68.13 "Pump" + 43.85 91.21 "Tank" + +[BACKDROP] + DIMENSIONS 7.00 6.00 73.00 94.00 + UNITS None + FILE + OFFSET 0.00 0.00 + +[END] diff --git a/tests/test_output.cpp b/tests/test_output.cpp index cd55f4f..78f55ed 100644 --- a/tests/test_output.cpp +++ b/tests/test_output.cpp @@ -22,8 +22,7 @@ #include "epanet_output.h" - -#define DATA_PATH "./net1.out" +#define DATA_PATH "./example1.out" using namespace std; @@ -117,7 +116,6 @@ struct Fixture{ float* array; int array_dim; - }; BOOST_AUTO_TEST_SUITE(test_output_fixture) @@ -144,6 +142,15 @@ BOOST_FIXTURE_TEST_CASE(test_getNetSize, Fixture) ENR_free((void**)&i_array); } +BOOST_FIXTURE_TEST_CASE(test_getUnits, Fixture) { + int flag; + + error = ENR_getUnits(p_handle, ENR_qualUnits, &flag); + BOOST_REQUIRE(error == 0); + + BOOST_CHECK_EQUAL(flag, ENR_MGL); +} + BOOST_FIXTURE_TEST_CASE(test_getElementName, Fixture) { char* name = new char[MAXID]; int length, index = 1; @@ -179,7 +186,6 @@ BOOST_FIXTURE_TEST_CASE(test_getNodeAttribute, Fixture) { std::vector ref_vec; ref_vec.assign(ref_array, ref_array + ref_dim); - std::vector test_vec; test_vec.assign(array, array + array_dim); diff --git a/tests/test_toolkit.cpp b/tests/test_toolkit.cpp new file mode 100644 index 0000000..6ca6322 --- /dev/null +++ b/tests/test_toolkit.cpp @@ -0,0 +1,207 @@ +// +// test_epanet_toolkit.cpp +// +// Date Created: January 24, 2018 +// +// Author: Michael E. Tryby +// US EPA - ORD/NRMRL +// + +//#define BOOST_TEST_DYN_LINK + +#define BOOST_TEST_MODULE "toolkit" +#include + +#include +#include "epanet2.h" + +// NOTE: Project Home needs to be updated to run unit test +#define DATA_PATH_INP "./net1.inp" +#define DATA_PATH_RPT "./test.rpt" +#define DATA_PATH_OUT "./test.out" + +using namespace std; + + +BOOST_AUTO_TEST_SUITE (test_toolkit) + +BOOST_AUTO_TEST_CASE (test_alloc_free) +{ + int error = 0; + EN_ProjectHandle ph = NULL; + + error = EN_createproject(&ph); + + BOOST_REQUIRE(error == 0); + BOOST_CHECK(ph != NULL); + + error = EN_deleteproject(&ph); + + BOOST_REQUIRE(error == 0); + BOOST_CHECK(ph == NULL); +} + +BOOST_AUTO_TEST_CASE (test_open_close) +{ + EN_ProjectHandle ph = NULL; + EN_createproject(&ph); + + 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_OUT); + + int error = EN_open(ph, path_inp.c_str(), path_rpt.c_str(), path_out.c_str()); + BOOST_REQUIRE(error == 0); + + error = EN_close(ph); + BOOST_REQUIRE(error == 0); + + EN_deleteproject(&ph); +} + +BOOST_AUTO_TEST_CASE(test_epanet) +{ + 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_OUT); + + int error = ENepanet(path_inp.c_str(), path_rpt.c_str(), path_out.c_str(), NULL); + BOOST_REQUIRE(error == 0); +} + +BOOST_AUTO_TEST_SUITE_END() + + +struct Fixture{ + Fixture() { + path_inp = std::string(DATA_PATH_INP); + path_rpt = std::string(DATA_PATH_RPT); + path_out = std::string(DATA_PATH_OUT); + + EN_createproject(&ph); + error = EN_open(ph, path_inp.c_str(), path_rpt.c_str(), path_out.c_str()); + + } + + ~Fixture() { + error = EN_close(ph); + EN_deleteproject(&ph); + } + + std::string path_inp; + std::string path_rpt; + std::string path_out; + + int error; + EN_ProjectHandle ph; + +}; + +BOOST_AUTO_TEST_SUITE(test_epanet_fixture) + +BOOST_FIXTURE_TEST_CASE(test_epanet, Fixture) +{ + error = EN_solveH(ph); + BOOST_REQUIRE(error == 0); + + error = EN_solveQ(ph); + BOOST_REQUIRE(error == 0); + + error = EN_report(ph); + BOOST_REQUIRE(error == 0); +} + +BOOST_FIXTURE_TEST_CASE(test_hyd_step, Fixture) +{ + int flag = 00; + long t, tstep; + + error = EN_openH(ph); + BOOST_REQUIRE(error == 0); + + error = EN_initH(ph, flag); + BOOST_REQUIRE(error == 0); + + do { + error = EN_runH(ph, &t); + BOOST_REQUIRE(error == 0); + + error = EN_nextH(ph, &tstep); + BOOST_REQUIRE(error == 0); + + } while (tstep > 0); + + error = EN_closeH(ph); + BOOST_REQUIRE(error == 0); +} + +BOOST_FIXTURE_TEST_CASE(test_qual_step, Fixture) +{ + int flag = 0; + long t, tstep; + + error = EN_solveH(ph); + BOOST_REQUIRE(error == 0); + + error = EN_openQ(ph); + BOOST_REQUIRE(error == 0); + + error = EN_initQ(ph, flag); + BOOST_REQUIRE(error == 0); + + do { + error = EN_runQ(ph, &t); + BOOST_REQUIRE(error == 0); + + error = EN_nextQ(ph, &tstep); + BOOST_REQUIRE(error == 0); + + } while (tstep > 0); + + error = EN_closeQ(ph); + BOOST_REQUIRE(error == 0); +} + +BOOST_FIXTURE_TEST_CASE(test_progressive_stepping, Fixture) +{ + int flag = EN_NOSAVE; + long t, tstep_h, tstep_q; + + error = EN_openH(ph); + BOOST_REQUIRE(error == 0); + + error = EN_initH(ph, flag); + BOOST_REQUIRE(error == 0); + + error = EN_openQ(ph); + BOOST_REQUIRE(error == 0); + + error = EN_initQ(ph, flag); + BOOST_REQUIRE(error == 0); + + do { + + + error = EN_runH(ph, &t); + BOOST_REQUIRE(error == 0); + + error = EN_runQ(ph, &t); + BOOST_REQUIRE(error == 0); + + error = EN_nextH(ph, &tstep_h); + BOOST_REQUIRE(error == 0); + + error = EN_nextQ(ph, &tstep_q); + BOOST_REQUIRE(error == 0); + + } while (tstep_h > 0); + + error = EN_closeH(ph); + BOOST_REQUIRE(error == 0); + + error = EN_closeQ(ph); + BOOST_REQUIRE(error == 0); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/epanet-output/include/epanet_output.h b/tools/epanet-output/include/epanet_output.h index 0066d16..93a8425 100644 --- a/tools/epanet-output/include/epanet_output.h +++ b/tools/epanet-output/include/epanet_output.h @@ -18,22 +18,42 @@ typedef void* ENR_Handle; typedef enum { - ENR_node = 1, - ENR_link = 2 + ENR_node = 1, + ENR_link = 2 } ENR_ElementType; typedef enum { - ENR_getSeries = 1, - ENR_getAttribute = 2, - ENR_getResult = 3, - ENR_getReacts = 4, - ENR_getEnergy = 5 -} ENR_ApiFunction; + ENR_flowUnits = 1, + ENR_pressUnits = 2, + ENR_qualUnits = 3 +} ENR_Units; typedef enum { - ENR_flowUnits = 1, - ENR_pressUnits = 2 -} ENR_Units; + ENR_CFS = 0, + ENR_GPM = 1, + ENR_MGD = 2, + ENR_IMGD = 3, + ENR_AFD = 4, + ENR_LPS = 5, + ENR_LPM = 6, + ENR_MLD = 7, + ENR_CMH = 8, + ENR_CMD = 9 +} ENR_FlowUnits; + +typedef enum { + ENR_PSI = 0, + ENR_MTR = 1, + ENR_KPA = 2 +} ENR_PressUnits; + +typedef enum { + ENR_NONE = 0, + ENR_MGL = 1, + ENR_UGL = 2, + ENR_HOURS = 3, + ENR_PRCNT = 4 +} ENR_QualUnits; typedef enum { ENR_reportStart = 1, @@ -43,21 +63,21 @@ typedef enum { }ENR_Time; typedef enum { - ENR_demand = 1, - ENR_head = 2, - ENR_pressure = 3, - ENR_quality = 4 + ENR_demand = 1, + ENR_head = 2, + ENR_pressure = 3, + ENR_quality = 4 } ENR_NodeAttribute; typedef enum { - ENR_flow = 1, - ENR_velocity = 2, - ENR_headloss = 3, - ENR_avgQuality = 4, - ENR_status = 5, - ENR_setting = 6, - ENR_rxRate = 7, - ENR_frctnFctr = 8 + ENR_flow = 1, + ENR_velocity = 2, + ENR_headloss = 3, + ENR_avgQuality = 4, + ENR_status = 5, + ENR_setting = 6, + ENR_rxRate = 7, + ENR_frctnFctr = 8 } ENR_LinkAttribute; diff --git a/tools/epanet-output/src/epanet_output.c b/tools/epanet-output/src/epanet_output.c index 486ef81..741304f 100644 --- a/tools/epanet-output/src/epanet_output.c +++ b/tools/epanet-output/src/epanet_output.c @@ -57,7 +57,8 @@ #define MINNREC 14 // Minimum allowable number of records #define PROLOGUE 884 // Preliminary fixed length section of header -#define MAXID_P1 32 // Max. # characters in ID name +#define MAXID_P1 32 // EPANET max characters in ID name PLUS 1 +#define MAXMSG_P1 80 // EPANET max characters in message text PLUS 1 #define NELEMENTTYPES 5 // Number of element types #define NENERGYRESULTS 6 // Number of energy results @@ -303,6 +304,8 @@ int DLLEXPORT ENR_getUnits(ENR_Handle p_handle, ENR_Units code, int* unitFlag) */ { int errorcode = 0; + F_OFF offset; + char temp[MAXID_P1]; data_t* p_data; *unitFlag = -1; @@ -315,15 +318,37 @@ int DLLEXPORT ENR_getUnits(ENR_Handle p_handle, ENR_Units code, int* unitFlag) switch (code) { case ENR_flowUnits: - fseek(p_data->file, 9*WORDSIZE, SEEK_SET); + _fseek(p_data->file, 9*WORDSIZE, SEEK_SET); fread(unitFlag, WORDSIZE, 1, p_data->file); break; case ENR_pressUnits: - fseek(p_data->file, 10*WORDSIZE, SEEK_SET); + _fseek(p_data->file, 10*WORDSIZE, SEEK_SET); fread(unitFlag, WORDSIZE, 1, p_data->file); break; + case ENR_qualUnits: + offset = 7*WORDSIZE; + _fseek(p_data->file, offset, SEEK_SET); + fread(unitFlag, WORDSIZE, 1, p_data->file); + + 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); + + if (!strcmp(temp, "mg/L")) *unitFlag = ENR_MGL; + else *unitFlag = ENR_UGL; + } + + else if (*unitFlag == 2) *unitFlag = ENR_HOURS; + + else *unitFlag = ENR_PRCNT; + + break; + default: errorcode = 421; } } @@ -378,6 +403,12 @@ int DLLEXPORT ENR_getTimes(ENR_Handle p_handle, ENR_Time code, int* time) return set_error(p_data->error_handle, errorcode); } +int DLLEXPORT ENR_getChemData(ENR_Handle p_handle, char** name, int* length) + +{ + return 0; +} + int DLLEXPORT ENR_getElementName(ENR_Handle p_handle, ENR_ElementType type, int elementIndex, char** name, int* length) /*------------------------------------------------------------------------ @@ -815,7 +846,7 @@ void errorLookup(int errcode, char* dest_msg, int dest_len) default: msg = ERRERR; } - strncpy(dest_msg, msg, MAXMSG); + strncpy(dest_msg, msg, MSG_MAXLEN); } int validateFile(ENR_Handle p_handle) diff --git a/tools/epanet-output/src/messages.h b/tools/epanet-output/src/messages.h index 78725a1..bc04a7d 100644 --- a/tools/epanet-output/src/messages.h +++ b/tools/epanet-output/src/messages.h @@ -10,7 +10,7 @@ #ifndef MESSAGES_H_ #define MESSAGES_H_ /*------------------- Error Messages --------------------*/ -#define MAXMSG 53 +#define MSG_MAXLEN 53 #define WARN10 "Warning: model run issued warnings" diff --git a/tools/epanet-output/test/epanet_output_test.py b/tools/epanet-output/test/epanet_output_test.py deleted file mode 100644 index fa23d62..0000000 --- a/tools/epanet-output/test/epanet_output_test.py +++ /dev/null @@ -1,102 +0,0 @@ -# -# epanet_output_test.py -# -# Created: 11/8/2017 -# Author: Michael E. Tryby -# US EPA - ORD/NRMRL -# -# Unit testing for EPANET Output API using pytest. -# - -import pytest -import numpy as np - -import epanet_output as oapi - -from data import OUTPUT_FILE_EXAMPLE1 - -@pytest.fixture() -def enr_handle(request): - _handle = oapi.enr_init() - oapi.enr_open(_handle, OUTPUT_FILE_EXAMPLE1) - - def enr_close(): - oapi.enr_close() - - request.addfinalizer(enr_close) - return _handle - - -def test_get_times(enr_handle): - num_periods = oapi.enr_get_times(enr_handle, oapi.Time.NUM_PERIODS) - assert num_periods == 25 - - -# def test_get_size(file_path): -# handle = oapi.enr_init() -# oapi.enr_open(handle, file_path) -# -# size = oapi.enr_get_net_size(handle) -# -# print(size) -# -# handle = oapi.enr_close() -# -# def test_get_names(file_path): -# handle = oapi.enr_init() -# oapi.enr_open(handle, file_path) -# -# name = oapi.enr_get_element_name(handle, oapi.ElementType.NODE, 10) -# -# print(name) -# -# handle = oapi.enr_close() -# -# def test_get_energy(file_path): -# handle = oapi.enr_init() -# oapi.enr_open(handle, file_path) -# -# result = oapi.enr_get_energy_usage(handle, 1) -# -# print(result) -# -# handle = oapi.enr_close() -# -# def test_get_react(file_path): -# handle = oapi.enr_init() -# oapi.enr_open(handle, file_path) -# -# result = oapi.enr_get_net_reacts(handle) -# -# print(result) -# -# handle = oapi.enr_close() -# -def test_get_node_attribute(enr_handle): - ref_array = np.array([ 1., 0.44407997, 0.43766347, 0.42827705, 0.41342604, - 0.42804748, 0.44152543, 0.40502965, 0.38635802, 1., 0.96745253]) - - array = oapi.enr_get_node_attribute(enr_handle, 1, oapi.NodeAttribute.QUALITY) - assert len(array) == 11 - assert np.allclose(array, ref_array) - -def test_get_link_attribute(enr_handle): - ref_array = np.array([ 1848.58117676, 1220.42736816, 130.11161804, - 187.68930054, 119.88839722, 40.46448898, -748.58111572, 478.15377808, - 191.73458862, 30.11160851, 140.4644928, 59.53551483, 1848.58117676]) - - array = oapi.enr_get_link_attribute(enr_handle, 1, oapi.LinkAttribute.FLOW) - assert len(array) == 13 - assert np.allclose(array, ref_array) - -# if __name__ == "__main__": -# -# file_path = "M:\\net mydocuments\\EPA Projects\\EPAnet Examples\\net1.out" -# test_get_times(file_path) -# test_get_size(file_path) -# test_get_names(file_path) -# test_get_energy(file_path) -# test_get_react(file_path) -# test_get_node_attribute(file_path) -# test_get_link_attribute(file_path) -# \ No newline at end of file diff --git a/win_build/WinSDK/Makefile.bat b/win_build/WinSDK/Makefile.bat index ee5b030..66bf58f 100644 --- a/win_build/WinSDK/Makefile.bat +++ b/win_build/WinSDK/Makefile.bat @@ -21,9 +21,9 @@ Find /i "x86" < checkOS.tmp > StringCheck.tmp If %ERRORLEVEL% == 1 ( CALL "%SDK_PATH%bin\"SetEnv.cmd /x64 /release rem : create EPANET2.DLL - cl -o epanet2.dll epanet.c hash.c hydraul.c hydcoeffs.c hydsolver.c hydstatus.c genmmd.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c /I ..\include /I ..\run /link /DLL + cl -o epanet2.dll epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL rem : create EPANET2.EXE - cl -o epanet2.exe epanet.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydsolver.c hydstatus.c genmmd.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c /I ..\include /I ..\run /I ..\src /link + cl -o epanet2.exe epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link md "%Build_PATH%"\64bit move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\64bit move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\64bit @@ -35,9 +35,9 @@ rem : 32 bit with DEF CALL "%SDK_PATH%bin\"SetEnv.cmd /x86 /release echo "32 bit with epanet2.def mapping" rem : create EPANET2.DLL -cl -o epanet2.dll epanet.c hash.c hydraul.c hydcoeffs.c hydsolver.c hydstatus.c genmmd.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c /I ..\include /I ..\run /link /DLL /def:..\win_build\WinSDK\epanet2.def /MAP +cl -o epanet2.dll epanet.c util\errormanager.c hash.c hydraul.c hydcoeffs.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /link /DLL /def:..\win_build\WinSDK\epanet2.def /MAP rem : create EPANET2.EXE -cl -o epanet2.exe epanet.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydstatus.c genmmd.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c /I ..\include /I ..\run /I ..\src /link +cl -o epanet2.exe epanet.c util\errormanager.c ..\run\main.c hash.c hydraul.c hydcoeffs.c hydsolver.c inpfile.c input1.c input2.c input3.c mempool.c output.c quality.c report.c rules.c smatrix.c genmmd.c /I ..\include /I ..\run /I ..\src /link md "%Build_PATH%"\32bit move /y "%SRC_PATH%"\*.dll "%Build_PATH%"\32bit move /y "%SRC_PATH%"\*.exe "%Build_PATH%"\32bit @@ -51,4 +51,3 @@ del "%SRC_PATH%"\*.map del "%SRC_PATH%"\*.tmp cd "%Build_PATH%" -