Return object index from EN_addnode and EN_addlink (issue #432)

Adds an output argument to EN_addnode and EN_addlink that returns the index of the newly added object.
Also refactors the validity check on object ID names.
This commit is contained in:
Lew Rossman
2019-04-18 07:00:07 -04:00
parent 4494db8f56
commit 1583bea154
18 changed files with 149 additions and 154 deletions

View File

@@ -83,8 +83,8 @@ ENDIF (MSVC)
# configure file groups
file(GLOB EPANET_SOURCES RELATIVE ${PROJECT_SOURCE_DIR} src/*.c src/util/cstr_helper.c)
file(GLOB EPANET_LIB_ALL RELATIVE ${PROJECT_SOURCE_DIR} src/* src/util/cstr_helper.*)
file(GLOB EPANET_SOURCES RELATIVE ${PROJECT_SOURCE_DIR} src/*.c)
file(GLOB EPANET_LIB_ALL RELATIVE ${PROJECT_SOURCE_DIR} src/*)
# exclude epanet python API from the default build
list(REMOVE_ITEM EPANET_LIB_ALL "src/epanet_py.c")
source_group("Library" FILES ${EPANET_LIB_ALL})

View File

@@ -141,7 +141,7 @@ These are symbolic constants used as function arguments.
/**
@addtogroup Nodes
@{
@fn int EN_addnode(EN_Project ph, char *id, int nodeType)
@fn int EN_addnode(EN_Project ph, char *id, int nodeType, int *index)
@fn int EN_deletenode(EN_Project ph, int index, int actionCode)
@fn int EN_getnodeindex(EN_Project ph, char *id, int *index)
@fn int EN_getnodeid(EN_Project ph, int index, char *id)
@@ -175,7 +175,7 @@ These are symbolic constants used as function arguments.
/**
@addtogroup Links
@{
@fn int EN_addlink(EN_Project ph, char *id, int linkType, char *fromNode, char *toNode)
@fn int EN_addlink(EN_Project ph, char *id, int linkType, char *fromNode, char *toNode, int *index)
@fn int EN_deletelink(EN_Project ph, int index, int actionCode)
@fn int EN_getlinkindex(EN_Project ph, char *id, int *index)
@fn int EN_getlinkid(EN_Project ph, int index, char *id)

View File

@@ -53,51 +53,52 @@ void netbuilder()
{
// Create a project that uses gpm for flow units and
// the Hazen-Williams formula for head loss
int index;
EN_Project ph;
EN_createproject(&ph);
EN_init(ph, "", "", EN_GPM, EN_HW);
// Add the first junction node to the project with
// an elevation of 700 ft and a demand of 0
EN_addnode(ph, "J1", EN_JUNCTION);
EN_setjuncdata(ph, 1, 700, 0, "");
EN_addnode(ph, "J1", EN_JUNCTION, &index);
EN_setjuncdata(ph, index, 700, 0, "");
// Add the remaining two junctions with elevations of
// 710 ft and demands of 250 and 500 gpm, respectively
EN_addnode(ph, "J2", EN_JUNCTION);
EN_setjuncdata(ph, 2, 710, 250, "");
EN_addnode(ph, "J3", EN_JUNCTION);
EN_setjuncdata(ph, 3, 710, 500, "");
EN_addnode(ph, "J2", EN_JUNCTION, &index);
EN_setjuncdata(ph, index, 710, 250, "");
EN_addnode(ph, "J3", EN_JUNCTION, &index);
EN_setjuncdata(ph, index, 710, 500, "");
// Add the reservoir at an elevation of 650 ft
EN_addnode(ph, "R1", EN_RESERVOIR);
EN_setnodevalue(ph, 4, EN_ELEVATION, 650);
EN_addnode(ph, "R1", EN_RESERVOIR, &index);
EN_setnodevalue(ph, index, EN_ELEVATION, 650);
// Add the tank node at elevation of 850 ft, initial water level
// at 120 ft, minimum level at 100 ft, maximum level at 150 ft
// and a diameter of 50.5 ft
EN_addnode(ph, "T1", EN_TANK);
EN_settankdata(ph, 5, 850, 120, 100, 150, 50.5, 0, "");
EN_addnode(ph, "T1", EN_TANK, &index);
EN_settankdata(ph, index, 850, 120, 100, 150, 50.5, 0, "");
// Add the pipes to the project, setting their length,
// diameter, and roughness values
EN_addlink(ph, "P1", EN_PIPE, "J1", "J2");
EN_setpipedata(ph, 1, 10560, 12, 100, 0);
EN_addlink(ph, "P2", EN_PIPE, "J1", "T1");
EN_setpipedata(ph, 2, 5280, 14, 100, 0);
EN_addlink(ph, "P3", EN_PIPE, "J1", "J3");
EN_setpipedata(ph, 3, 5280, 14, 100, 0);
EN_addlink(ph, "P4", EN_PIPE, "J2", "J3");
EN_setpipedata(ph, 4, 5280, 14, 100, 0);
EN_addlink(ph, "P1", EN_PIPE, "J1", "J2", &index);
EN_setpipedata(ph, index, 10560, 12, 100, 0);
EN_addlink(ph, "P2", EN_PIPE, "J1", "T1", &index);
EN_setpipedata(ph, index, 5280, 14, 100, 0);
EN_addlink(ph, "P3", EN_PIPE, "J1", "J3", &index);
EN_setpipedata(ph, index, 5280, 14, 100, 0);
EN_addlink(ph, "P4", EN_PIPE, "J2", "J3", &index);
EN_setpipedata(ph, index, 5280, 14, 100, 0);
// Add a pump to the project
EN_addlink(ph, "PUMP", EN_PUMP, "R1", "J1");
EN_addlink(ph, "PUMP", EN_PUMP, "R1", "J1", &index);
// Create a single point head curve (index = 1) and
// assign it to the pump (index = 5)
// assign it to the pump
EN_addcurve(ph, "C1");
EN_setcurvevalue(ph, 1, 1, 1500, 250);
EN_setlinkvalue(ph, 5, EN_PUMP_HCURVE, 1);
EN_setlinkvalue(ph, index, EN_PUMP_HCURVE, 1);
// Save the project for future use
EN_saveinpfile(ph, "example2.inp");

View File

@@ -55,27 +55,28 @@ if (errcode == 0)
EN_deleteproject(&ph);
\endcode
Note that after an input file has been loaded in this fashion the resulting network can have objects added or deleted, and their properties set using various Toolkit functions .
After an input file has been loaded in this fashion the resulting network can have objects added or deleted, and their properties set using the various Toolkit functions .
The second method for supplying network data to a project is to use the Toolkit's functions to add objects and to set their properties via code. In this case the @ref EN_init function should be called immediately after creating a project, passing in the names of a report and binary output files (both optional) as well as the choices of flow units and head loss formulas to use. After that the various `EN_add` functions, such as @ref EN_addnode, @ref EN_addlink, @ref EN_addpattern, @ref EN_addcontrol, etc., can be called to add new objects to the network. Here is a partial example:
The second method for supplying network data to a project is to use the Toolkit's functions to add objects and to set their properties via code. In this case the @ref EN_init function should be called immediately after creating a project, passing in the names of a report and binary output files (both optional) as well as the choices of flow units and head loss formulas to use. After that the various `EN_add` functions, such as @ref EN_addnode, @ref EN_addlink, @ref EN_addpattern, @ref EN_addcontrol, etc., can be called to add new objects to the network. Here is a partial example of constructing a network from code:
\code {.c}
int index;
EN_Project ph;
EN_createproject(&ph);
EN_init(ph, "net1.rpt", "", EN_GPM, EN_HW);
EN_addnode(ph, "J1", EN_JUNCTION);
EN_addnode(ph, "J2", EN_JUNCTION);
EN_addlink(ph, "P1", EN_PIPE, "J1", "J2");
EN_addnode(ph, "J1", EN_JUNCTION, &index);
EN_addnode(ph, "J2", EN_JUNCTION, &index);
EN_addlink(ph, "P1", EN_PIPE, "J1", "J2", &index);
// additional function calls to complete building the network
\endcode
See the @ref Example2 for a more complete example. While adding objects their properties can be set as described in the next section. Attemtping to change a network's structure by adding or deleting nodes and links while the Toolkit's hydraulic or water quality solvers are open will result in an error condition.
See the @ref Example2 for a more complete example. The labels used to name objects cannot contain spaces, semi-colons, or double quotes nor exceed @ref EN_MAXID characters in length. While adding objects their properties can be set as described in the next section. Attemtping to change a network's structure by adding or deleting nodes and links while the Toolkit's hydraulic or water quality solvers are open will result in an error condition.
@section Properties Setting Object Properties
The Toolkit contains several functions for retrieving and setting the properties of a network's objects and its analysis options. The names of retrieval functions all begin with `EN_get` (e.g., @ref EN_getnodevalue, @ref EN_getoption, etc.) while the functions used for setting parameter values begin with `EN_set` (e.g., @ref EN_setnodevalue, @ref EN_setoption, etc.).
Most of these functions use an index number to refer to a specific network component (such as a node, link, time pattern or data curve). This number is simply the position of the component in the list of all components of similar type (e.g., node 10 is the tenth node, starting from 1, in the network) and is not the same as the ID label assigned to the component. A series of functions exist to determine a component's index number given its ID label (see @ref EN_getnodeindex, @ref EN_getlinkindex, @ref EN_getpatternindex, and @ref EN_getcurveindex). Likewise, functions exist to retrieve a component's ID label given its index number (see @ref EN_getlinkid, @ref EN_getnodeid, @ref EN_getpatternid, and @ref EN_getcurveid). The @ref EN_getcount function can be used to determine the number of different components in the network. Be aware that a component's index can change as elements are added or deleted from the network.
Most of these functions use an index number to refer to a specific network component (such as a node, link, time pattern or data curve). This number is simply the position of the component in the list of all components of similar type (e.g., node 10 is the tenth node, starting from 1, in the network) and is not the same as the ID label assigned to the component. A series of functions exist to determine a component's index number given its ID label (see @ref EN_getnodeindex, @ref EN_getlinkindex, @ref EN_getpatternindex, and @ref EN_getcurveindex). Likewise, functions exist to retrieve a component's ID label given its index number (see @ref EN_getlinkid, @ref EN_getnodeid, @ref EN_getpatternid, and @ref EN_getcurveid). The @ref EN_getcount function can be used to determine the number of different components in the network. Be aware that a component's index can change as elements are added or deleted from the network. The @ref EN_addnode and @ref EN_addlink functions return the index of the newly added node or link as a convenience for immediately setting their properties.
The code below is an example of using the property retrieval and setting functions. It changes all links with diameter of 10 inches to 12 inches.

View File

@@ -291,7 +291,7 @@ Public Const EN_R_IS_ACTIVE = 3
Declare Function ENsetqualtype Lib "epanet2.dll" (ByVal qualType As Long, ByVal chemName As String, ByVal chemUnits As String, ByVal traceNode As String) As Long
'Node Functions
Declare Function ENaddnode Lib "epanet2.dll" (ByVal id As String, ByVal nodeType As Long) As Long
Declare Function ENaddnode Lib "epanet2.dll" (ByVal id As String, ByVal nodeType As Long, index As Long) As Long
Declare Function ENdeletenode Lib "epanet2.dll" (ByVal index As Long, ByVal actionCode As Long) As Long
Declare Function ENgetnodeindex Lib "epanet2.dll" (ByVal id As String, index As Long) As Long
Declare Function ENgetnodeid Lib "epanet2.dll" (ByVal index As Long, ByVal id As String) As Long
@@ -316,7 +316,7 @@ Public Const EN_R_IS_ACTIVE = 3
Declare Function ENsetdemandname Lib "epanet2.dll" (ByVal nodeIndex As Long, ByVal demandIndex As Long, ByVal demandName As String) As Long
'Link Functions
Declare Function ENaddlink Lib "epanet2.dll" (ByVal id As String, ByVal linkType As Long, ByVal fromNode As String, ByVal toNode As String) As Long
Declare Function ENaddlink Lib "epanet2.dll" (ByVal id As String, ByVal linkType As Long, ByVal fromNode As String, ByVal toNode As String, index As Long) As Long
Declare Function ENdeletelink Lib "epanet2.dll" (ByVal index As Long, ByVal actionCode As Long) As Long
Declare Function ENgetlinkindex Lib "epanet2.dll" (ByVal id As String, index As Long) As Long
Declare Function ENgetlinkid Lib "epanet2.dll" (ByVal index As Long, ByVal id As String) As Long

View File

@@ -3,8 +3,8 @@ LIBRARY EPANET2.DLL
EXPORTS
ENaddcontrol = _ENaddcontrol@24
ENaddcurve = _ENaddcurve@4
ENaddlink = _ENaddlink@16
ENaddnode = _ENaddnode@8
ENaddlink = _ENaddlink@20
ENaddnode = _ENaddnode@12
ENaddpattern = _ENaddpattern@4
ENaddrule = _ENaddrule@4
ENclearreport = _ENclearreport@0

View File

@@ -190,7 +190,7 @@ extern "C" {
********************************************************************/
int DLLEXPORT ENaddnode(char *id, int nodeType);
int DLLEXPORT ENaddnode(char *id, int nodeType, int *index);
int DLLEXPORT ENdeletenode(int index, int actionCode);
@@ -252,7 +252,7 @@ extern "C" {
********************************************************************/
int DLLEXPORT ENaddlink(char *id, int linkType, char *fromNode, char *toNode);
int DLLEXPORT ENaddlink(char *id, int linkType, char *fromNode, char *toNode, int *index);
int DLLEXPORT ENdeletelink(int index, int actionCode);

View File

@@ -296,7 +296,7 @@ Public Const EN_R_IS_ACTIVE = 3
Declare Function ENsetqualtype Lib "epanet2.dll" (ByVal qualType As Int32, ByVal chemName As String, ByVal chemUnits As String, ByVal traceNode As String) As Int32
'Node Functions
Declare Function ENaddnode Lib "epanet2.dll" (ByVal id As String, ByVal nodeType As Int32) As Int32
Declare Function ENaddnode Lib "epanet2.dll" (ByVal id As String, ByVal nodeType As Int32, Index As Int32) As Int32
Declare Function ENdeletenode Lib "epanet2.dll" (ByVal index As Int32, ByVal actionCode As Int32) As Int32
Declare Function ENgetnodeindex Lib "epanet2.dll" (ByVal id As String, index As Int32) As Int32
Declare Function ENgetnodeid Lib "epanet2.dll" (ByVal index As Int32, ByVal id As String) As Int32
@@ -321,7 +321,7 @@ Public Const EN_R_IS_ACTIVE = 3
Declare Function ENsetdemandname Lib "epanet2.dll" (ByVal nodeIndex As Int32, ByVal demandIndex As Int32, ByVal demandName As String) As Int32
'Link Functions
Declare Function ENaddlink Lib "epanet2.dll" (ByVal id As String, ByVal linkType As Int32, ByVal fromNode As String, ByVal toNode As String) As Int32
Declare Function ENaddlink Lib "epanet2.dll" (ByVal id As String, ByVal linkType As Int32, ByVal fromNode As String, ByVal toNode As String, Index As Int32) As Int32
Declare Function ENdeletelink Lib "epanet2.dll" (ByVal index As Int32, ByVal actionCode As Int32) As Int32
Declare Function ENgetlinkindex Lib "epanet2.dll" (ByVal id As String, index As Int32) As Int32
Declare Function ENgetlinkid Lib "epanet2.dll" (ByVal index As Int32, ByVal id As String) As Int32

View File

@@ -752,11 +752,12 @@ typedef struct Project *EN_Project;
@param ph an EPANET project handle.
@param id the ID name of the node to be added.
@param nodeType the type of node being added (see @ref EN_NodeType)
@param[out] index the index of the newly added node
@return an error code.
When a new node is created all of it's properties (see @ref EN_NodeProperty) are set to 0.
*/
int DLLEXPORT EN_addnode(EN_Project ph, char *id, int nodeType);
int DLLEXPORT EN_addnode(EN_Project ph, char *id, int nodeType, int *index);
/**
@brief Deletes a node from a project.
@@ -1027,6 +1028,7 @@ typedef struct Project *EN_Project;
@param linkType The type of link being added (see @ref EN_LinkType)
@param fromNode The ID name of the link's starting node.
@param toNode The ID name of the link's ending node.
@param[out] index the index of the newly added link.
@return an error code.
A new pipe is assigned a diameter of 10 inches (or 254 mm), a length of 100
@@ -1039,7 +1041,8 @@ typedef struct Project *EN_Project;
See @ref EN_LinkProperty.
*/
int DLLEXPORT EN_addlink(EN_Project ph, char *id, int linkType, char *fromNode, char *toNode);
int DLLEXPORT EN_addlink(EN_Project ph, char *id, int linkType, char *fromNode,
char *toNode, int *index);
/**
@brief Deletes a link from the project.

View File

@@ -81,7 +81,7 @@ int EXPORT_PY_API anlys_getqualtype(Handle ph, int *qualcode, int *tracenode);
int EXPORT_PY_API anlys_setqualtype(Handle ph, EN_QualityType qualcode, char *chemname, char *chemunits, char *tracenode);
int EXPORT_PY_API node_add(Handle ph, char *id, EN_NodeType nodeType);
int EXPORT_PY_API node_add(Handle ph, char *id, EN_NodeType nodeType, int *index);
int EXPORT_PY_API node_delete(Handle ph, int index, int actionCode);
int EXPORT_PY_API node_getindex(Handle ph, char *id, int *index);
int EXPORT_PY_API node_getid(Handle ph, int index, char *id);
@@ -104,7 +104,7 @@ int EXPORT_PY_API dmnd_getname(Handle ph, int nodeIndex, int demandIdx, char *de
int EXPORT_PY_API dmnd_setname(Handle ph, int nodeIndex, int demandIdx, char *demandName);
int EXPORT_PY_API link_add(Handle ph, char *id, EN_LinkType linkType, char *fromNode, char *toNode);
int EXPORT_PY_API link_add(Handle ph, char *id, EN_LinkType linkType, char *fromNode, char *toNode, int *index);
int EXPORT_PY_API link_delete(Handle ph, int index, int actionCode);
int EXPORT_PY_API link_getindex(Handle ph, char *id, int *index);
int EXPORT_PY_API link_getid(Handle ph, int index, char *id);

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/03/2019
Last Updated: 04/18/2019
******************************************************************************
*/
@@ -30,8 +30,6 @@
#include "text.h"
#include "enumstxt.h"
#include "util/cstr_helper.h"
#ifdef _WIN32
#define snprintf _snprintf
#endif
@@ -1707,11 +1705,11 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, char *chemName,
********************************************************************/
int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType)
int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
/*----------------------------------------------------------------
** Input: id = node ID name
** nodeType = type of node (see EN_NodeType)
** Output: none
** Output: index = index of newly added node
** Returns: error code
** Purpose: adds a new node to a project
**----------------------------------------------------------------
@@ -1721,27 +1719,23 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType)
Hydraul *hyd = &p->hydraul;
Quality *qual = &p->quality;
int i, nIdx;
int index;
int size;
int i, nIdx, size;
struct Sdemand *demand;
Stank *tank;
Snode *node;
Scontrol *control;
// Cannot modify network structure while solvers are active
*index = 0;
if (!p->Openflag) return 102;
if (hyd->OpenHflag || qual->OpenQflag) return 262;
// Check if id contains invalid characters
if (!cstr_isvalid(id)) return 252;
// Check if id name contains invalid characters
if (!namevalid(id)) return 252;
// Check if a node with same id already exists
if (EN_getnodeindex(p, id, &i) == 0) return 215;
// Check that id name is not too long
if (strlen(id) > MAXID) return 250;
// Grow node-related arrays to accomodate the new node
size = (net->Nnodes + 2) * sizeof(Snode);
net->Node = (Snode *)realloc(net->Node, size);
@@ -1765,28 +1759,28 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType)
node->D = demand;
// shift rest of Node array
for (index = net->Nnodes; index >= net->Njuncs; index--)
for (i = net->Nnodes; i >= net->Njuncs; i--)
{
hashtable_update(net->NodeHashTable, net->Node[index].ID, index + 1);
net->Node[index + 1] = net->Node[index];
hashtable_update(net->NodeHashTable, net->Node[i].ID, i + 1);
net->Node[i + 1] = net->Node[i];
}
// shift indices of Tank array
for (index = 1; index <= net->Ntanks; index++)
for (i = 1; i <= net->Ntanks; i++)
{
net->Tank[index].Node += 1;
net->Tank[i].Node += 1;
}
// shift indices of Links, if necessary
for (index = 1; index <= net->Nlinks; index++)
for (i = 1; i <= net->Nlinks; i++)
{
if (net->Link[index].N1 > net->Njuncs - 1) net->Link[index].N1 += 1;
if (net->Link[index].N2 > net->Njuncs - 1) net->Link[index].N2 += 1;
if (net->Link[i].N1 > net->Njuncs - 1) net->Link[i].N1 += 1;
if (net->Link[i].N2 > net->Njuncs - 1) net->Link[i].N2 += 1;
}
// shift indices of tanks/reservoir nodes in controls
for (index = 1; index <= net->Ncontrols; ++index)
for (i = 1; i <= net->Ncontrols; ++i)
{
control = &net->Control[index];
control = &net->Control[i];
if (control->Node > net->Njuncs - 1) control->Node += 1;
}
@@ -1841,6 +1835,7 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType)
// Insert new node into hash table
hashtable_insert(net->NodeHashTable, node->ID, nIdx);
*index = nIdx;
return 0;
}
@@ -2015,13 +2010,10 @@ int DLLEXPORT EN_setnodeid(EN_Project p, int index, char *newid)
*/
{
Network *net = &p->network;
size_t n;
// Check for valid arguments
if (index <= 0 || index > net->Nnodes) return 203;
n = strlen(newid);
if (n < 1 || n > MAXID) return 209;
if (!cstr_isvalid(newid)) return 252;
if (!namevalid(newid)) return 252;
// Check if another node with same name exists
if (hashtable_find(net->NodeHashTable, newid) > 0) return 215;
@@ -2845,7 +2837,7 @@ int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex,
if (nodeIndex <= 0 || nodeIndex > p->network.Njuncs) return 203;
// Check that demandName is not too long
if (strlen(demandName) > MAXID) return 250;
if (strlen(demandName) > MAXID) return 252;
// Locate demand category record and assign demandName to it
for (d = p->network.Node[nodeIndex].D;
@@ -2920,13 +2912,13 @@ int DLLEXPORT EN_setdemandpattern(EN_Project p, int nodeIndex, int demandIndex,
********************************************************************/
int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
char *fromNode, char *toNode)
char *fromNode, char *toNode, int *index)
/*----------------------------------------------------------------
** Input: id = link ID name
** type = link type (see EN_LinkType)
** fromNode = name of link's starting node
** toNode = name of link's ending node
** Output: none
** Output: index = position of new link in Link array
** Returns: error code
** Purpose: adds a new link to a project
**----------------------------------------------------------------
@@ -2941,11 +2933,12 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
Spump *pump;
// Cannot modify network structure while solvers are active
*index = 0;
if (!p->Openflag) return 102;
if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262;
// Check if id contains invalid characters
if (!cstr_isvalid(id)) return 252;
// Check if id name contains invalid characters
if (!namevalid(id)) return 252;
// Check if a link with same id already exists
if (EN_getlinkindex(p, id, &i) == 0) return 215;
@@ -2958,9 +2951,6 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
n2 = hashtable_find(net->NodeHashTable, toNode);
if (n1 == 0 || n2 == 0) return 203;
// Check that id name is not too long
if (strlen(id) > MAXID) return 250;
// Check that valve link has legal connections
if (linkType > PUMP)
{
@@ -2970,6 +2960,7 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
// Grow link-related arrays to accomodate the new link
net->Nlinks++;
p->parser.MaxLinks = net->Nlinks;
n = net->Nlinks;
size = (n + 1) * sizeof(Slink);
net->Link = (Slink *)realloc(net->Link, size);
@@ -3049,6 +3040,7 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
link->Comment = NULL;
hashtable_insert(net->LinkHashTable, link->ID, n);
*index = n;
return 0;
}
@@ -3202,13 +3194,10 @@ int DLLEXPORT EN_setlinkid(EN_Project p, int index, char *newid)
*/
{
Network *net = &p->network;
size_t n;
// Check for valid arguments
if (index <= 0 || index > net->Nlinks) return 204;
n = strlen(newid);
if (n < 1 || n > MAXID) return 211;
if (!cstr_isvalid(newid)) return 252;
if (!namevalid(newid)) return 252;
// Check if another link with same name exists
if (hashtable_find(net->LinkHashTable, newid) > 0) return 215;
@@ -3306,10 +3295,7 @@ int DLLEXPORT EN_setlinktype(EN_Project p, int *index, int linkType, int actionC
EN_deletelink(p, i, actionCode);
// Create a new link of new type and old id
errcode = EN_addlink(p, id, linkType, id1, id2);
// Find the index of this new link
EN_getlinkindex(p, id, index);
errcode = EN_addlink(p, id, linkType, id1, id2, index);
return errcode;
}
@@ -3959,11 +3945,8 @@ int DLLEXPORT EN_addpattern(EN_Project p, char *id)
if (!p->Openflag) return 102;
if (EN_getpatternindex(p, id, &i) == 0) return 215;
// Check is id name contains invalid characters
if (!cstr_isvalid(id)) return 252;
// Check that id name is not too long
if (strlen(id) > MAXID) return 250;
// Check if id name contains invalid characters
if (!namevalid(id)) return 252;
// Expand the project's array of patterns
n = net->Npats + 1;
@@ -4086,10 +4069,8 @@ int DLLEXPORT EN_setpatternid(EN_Project p, int index, char *id)
if (!p->Openflag) return 102;
if (index < 1 || index > p->network.Npats) return 205;
// Check is id name contains invalid characters
if (!cstr_isvalid(id)) return 252;
if (strlen(id) > MAXID) return 250;
// Check if id name contains invalid characters
if (!namevalid(id)) return 252;
for (i = 1; i <= p->network.Npats; i++)
{
@@ -4235,11 +4216,8 @@ int DLLEXPORT EN_addcurve(EN_Project p, char *id)
if (!p->Openflag) return 102;
if (EN_getcurveindex(p, id, &i) == 0) return 215;
// Check is id name contains invalid characters
if (!cstr_isvalid(id)) return 252;
// Check that id name is not too long
if (strlen(id) > MAXID) return 250;
// Check if id name contains invalid characters
if (!namevalid(id)) return 252;
// Expand the array of curves
n = net->Ncurves + 1;
@@ -4358,10 +4336,9 @@ int DLLEXPORT EN_setcurveid(EN_Project p, int index, char *id)
if (!p->Openflag) return 102;
if (index < 1 || index > p->network.Ncurves) return 205;
// Check is id name contains invalid characters
if (!cstr_isvalid(id)) return 252;
// Check if id name contains invalid characters
if (!namevalid(id)) return 252;
if (strlen(id) > MAXID) return 250;
for (i = 1; i <= p->network.Ncurves; i++)
{
if (i != index && strcmp(id, p->network.Curve[i].ID) == 0) return 215;

View File

@@ -294,9 +294,9 @@ int DLLEXPORT ENsetqualtype(int qualType, char *chemName, char *chemUnits,
********************************************************************/
int DLLEXPORT ENaddnode(char *id, int nodeType)
int DLLEXPORT ENaddnode(char *id, int nodeType, int *index)
{
return EN_addnode(_defaultProject, id, nodeType);
return EN_addnode(_defaultProject, id, nodeType, index);
}
int DLLEXPORT ENdeletenode(int index, int actionCode)
@@ -431,9 +431,9 @@ int DLLEXPORT ENsetdemandname(int nodeIndex, int demandIndex, char *demandName)
********************************************************************/
int DLLEXPORT ENaddlink(char *id, int linkType, char *fromNode, char *toNode)
int DLLEXPORT ENaddlink(char *id, int linkType, char *fromNode, char *toNode, int *index)
{
return EN_addlink(_defaultProject, id, linkType, fromNode, toNode);
return EN_addlink(_defaultProject, id, linkType, fromNode, toNode, index);
}
int DLLEXPORT ENdeletelink(int index, int actionCode)

View File

@@ -326,10 +326,10 @@ int EXPORT_PY_API anlys_setqualtype(Handle ph, EN_QualityType qualcode, char *ch
int EXPORT_PY_API node_add(Handle ph, char *id, EN_NodeType nodeType)
int EXPORT_PY_API node_add(Handle ph, char *id, EN_NodeType nodeType, int *index)
{
handle_t *pr = (handle_t *)ph;
return set_error(pr->error, EN_addnode(pr->project, id, nodeType));
return set_error(pr->error, EN_addnode(pr->project, id, nodeType, index));
}
int EXPORT_PY_API node_delete(Handle ph, int index, int actionCode)
@@ -446,10 +446,10 @@ int EXPORT_PY_API dmnd_setname(Handle ph, int nodeIndex, int demandIdx, char *de
int EXPORT_PY_API link_add(Handle ph, char *id, EN_LinkType linkType, char *fromNode, char *toNode)
int EXPORT_PY_API link_add(Handle ph, char *id, EN_LinkType linkType, char *fromNode, char *toNode, int *index)
{
handle_t *pr = (handle_t *)ph;
return set_error(pr->error, EN_addlink(pr->project, id, linkType, fromNode, toNode));
return set_error(pr->error, EN_addlink(pr->project, id, linkType, fromNode, toNode, index));
}
int EXPORT_PY_API link_delete(Handle ph, int index, int actionCode)

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/03/2019
Last Updated: 04/18/2019
******************************************************************************
*/
#ifndef FUNCS_H
@@ -44,6 +44,7 @@ int resizecurve(Scurve *, int);
int getcomment(Network *, int, int, char *);
int setcomment(Network *, int, int, const char *);
int namevalid(const char *);
char *getTmpName(char *);
char *xstrcpy(char **, const char *, const size_t n);
int strcomp(const char *, const char *);

View File

@@ -7,7 +7,7 @@
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 04/03/2019
Last Updated: 04/18/2019
******************************************************************************
*/
@@ -988,6 +988,18 @@ int setcomment(Network *network, int object, int index, const char *newcomment)
}
}
int namevalid(const char *name)
//----------------------------------------------------------------
// Input: name = name used to ID an object
// Output: returns TRUE if name is valid, FALSE if not
// Purpose: checks that an object's ID name is valid.
//----------------------------------------------------------------
{
size_t n = strlen(name);
if (n < 1 || n > MAXID || strpbrk(name, " \";")) return FALSE;
return TRUE;
}
char *getTmpName(char *fname)
//----------------------------------------------------------------
// Input: fname = file name string

View File

@@ -26,14 +26,14 @@ BOOST_FIXTURE_TEST_CASE(test_adddelete_link, FixtureInitClose)
int index;
// Build a network
EN_addnode(ph, (char *)"N1", EN_JUNCTION);
EN_addnode(ph, (char *)"N2", EN_JUNCTION);
EN_addnode(ph, (char *)"N3", EN_RESERVOIR);
EN_addnode(ph, (char *)"N1", EN_JUNCTION, &index);
EN_addnode(ph, (char *)"N2", EN_JUNCTION, &index);
EN_addnode(ph, (char *)"N3", EN_RESERVOIR, &index);
error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N3", (char *)"N1");
error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N3", (char *)"N1", &index);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"L2", EN_PIPE, (char *)"N1", (char *)"N3");
error = EN_addlink(ph, (char *)"L2", EN_PIPE, (char *)"N1", (char *)"N3", &index);
BOOST_REQUIRE(error == 0);
error = EN_getlinkindex(ph, (char *)"L2", &index);
@@ -41,7 +41,7 @@ BOOST_FIXTURE_TEST_CASE(test_adddelete_link, FixtureInitClose)
error = EN_deletelink(ph, index, EN_UNCONDITIONAL);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"L3", EN_PIPE, (char *)"N1", (char *)"N2");
error = EN_addlink(ph, (char *)"L3", EN_PIPE, (char *)"N1", (char *)"N2", &index);
BOOST_REQUIRE(error == 0);
error = EN_getlinkindex(ph, (char *)"L1", &index);
@@ -60,20 +60,20 @@ BOOST_FIXTURE_TEST_CASE(test_link_id_isvalid, FixtureInitClose)
int index;
// Build a network
EN_addnode(ph, (char *)"N1", EN_JUNCTION);
EN_addnode(ph, (char *)"N2", EN_JUNCTION);
EN_addnode(ph, (char *)"N3", EN_RESERVOIR);
EN_addnode(ph, (char *)"N1", EN_JUNCTION, &index);
EN_addnode(ph, (char *)"N2", EN_JUNCTION, &index);
EN_addnode(ph, (char *)"N3", EN_RESERVOIR, &index);
error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N1", (char *)"N2");
error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N1", (char *)"N2", &index);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"L 2", EN_PIPE, (char *)"N1", (char *)"N2");
error = EN_addlink(ph, (char *)"L 2", EN_PIPE, (char *)"N1", (char *)"N2", &index);
BOOST_REQUIRE(error == 252);
error = EN_addlink(ph, (char *)"L\"2", EN_PIPE, (char *)"N1", (char *)"N2");
error = EN_addlink(ph, (char *)"L\"2", EN_PIPE, (char *)"N1", (char *)"N2", &index);
BOOST_REQUIRE(error == 252);
error = EN_addlink(ph, (char *)"L;2", EN_PIPE, (char *)"N1", (char *)"N2");
error = EN_addlink(ph, (char *)"L;2", EN_PIPE, (char *)"N1", (char *)"N2", &index);
BOOST_REQUIRE(error == 252);
EN_getlinkindex(ph, (char *)"L1", &index);

View File

@@ -128,7 +128,7 @@ BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose)
//BOOST_REQUIRE(error == 0);
for (i = 0; i < 9; i++)
{
error = EN_addnode(ph, juncs[i], EN_JUNCTION);
error = EN_addnode(ph, juncs[i], EN_JUNCTION, &ind);
BOOST_REQUIRE(error == 0);
error = EN_setnodevalue(ph, i + 1, EN_ELEVATION, e[i]);
BOOST_REQUIRE(error == 0);
@@ -141,14 +141,14 @@ BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose)
//error = EN_setdemandpattern(ph, i + 1, 1, 1);
//BOOST_REQUIRE(error == 0);
}
error = EN_addnode(ph, (char *)"9", EN_RESERVOIR);
error = EN_addnode(ph, (char *)"9", EN_RESERVOIR, &ind);
BOOST_REQUIRE(error == 0);
error = EN_setcoord(ph, 10, 10, 70);
BOOST_REQUIRE(error == 0);
error = EN_setnodevalue(ph, 10, EN_ELEVATION, 800);
BOOST_REQUIRE(error == 0);
error = EN_addnode(ph, (char *)"2", EN_TANK);
error = EN_addnode(ph, (char *)"2", EN_TANK, &ind);
BOOST_REQUIRE(error == 0);
error = EN_setcoord(ph, 11, 50, 90);
BOOST_REQUIRE(error == 0);
@@ -165,29 +165,29 @@ BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose)
error = EN_setnodevalue(ph, 11, EN_MIXFRACTION, 1);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"10", EN_PIPE, (char *)"10", (char *)"11");
error = EN_addlink(ph, (char *)"10", EN_PIPE, (char *)"10", (char *)"11", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"11", EN_PIPE, (char *)"11", (char *)"12");
error = EN_addlink(ph, (char *)"11", EN_PIPE, (char *)"11", (char *)"12", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"12", EN_PIPE, (char *)"12", (char *)"13");
error = EN_addlink(ph, (char *)"12", EN_PIPE, (char *)"12", (char *)"13", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"21", EN_PIPE, (char *)"21", (char *)"22");
error = EN_addlink(ph, (char *)"21", EN_PIPE, (char *)"21", (char *)"22", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"22", EN_PIPE, (char *)"22", (char *)"23");
error = EN_addlink(ph, (char *)"22", EN_PIPE, (char *)"22", (char *)"23", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"31", EN_PIPE, (char *)"31", (char *)"32");
error = EN_addlink(ph, (char *)"31", EN_PIPE, (char *)"31", (char *)"32", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"110", EN_PIPE, (char *)"2", (char *)"12");
error = EN_addlink(ph, (char *)"110", EN_PIPE, (char *)"2", (char *)"12", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"111", EN_PIPE, (char *)"11", (char *)"21");
error = EN_addlink(ph, (char *)"111", EN_PIPE, (char *)"11", (char *)"21", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"112", EN_PIPE, (char *)"12", (char *)"22");
error = EN_addlink(ph, (char *)"112", EN_PIPE, (char *)"12", (char *)"22", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"113", EN_PIPE, (char *)"13", (char *)"23");
error = EN_addlink(ph, (char *)"113", EN_PIPE, (char *)"13", (char *)"23", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"121", EN_PIPE, (char *)"21", (char *)"31");
error = EN_addlink(ph, (char *)"121", EN_PIPE, (char *)"21", (char *)"31", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"122", EN_PIPE, (char *)"22", (char *)"32");
error = EN_addlink(ph, (char *)"122", EN_PIPE, (char *)"22", (char *)"32", &ind);
BOOST_REQUIRE(error == 0);
for (i = 0; i < 12; i++)
{
@@ -197,7 +197,7 @@ BOOST_FIXTURE_TEST_CASE(test_build_net1, FixtureInitClose)
BOOST_REQUIRE(error == 0);
}
error = EN_addlink(ph, (char *)"9", EN_PUMP, (char *)"9", (char *)"10");
error = EN_addlink(ph, (char *)"9", EN_PUMP, (char *)"9", (char *)"10", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addcurve(ph, (char *)"1");
BOOST_REQUIRE(error == 0);
@@ -306,19 +306,19 @@ BOOST_FIXTURE_TEST_CASE(test_save_net2, FixtureInitClose)
double q1_1, q2_1; // q1_2, q2_2;
// Build a network
error = EN_addnode(ph, (char *)"N1", EN_JUNCTION);
error = EN_addnode(ph, (char *)"N1", EN_JUNCTION, &ind);
BOOST_REQUIRE(error == 0);
error = EN_addnode(ph, (char *)"N2", EN_JUNCTION);
error = EN_addnode(ph, (char *)"N2", EN_JUNCTION, &ind);
BOOST_REQUIRE(error == 0);
error = EN_addnode(ph, (char *)"N3", EN_RESERVOIR);
error = EN_addnode(ph, (char *)"N3", EN_RESERVOIR, &ind);
BOOST_REQUIRE(error == 0);
error = EN_addnode(ph, (char *)"N4", EN_TANK);
error = EN_addnode(ph, (char *)"N4", EN_TANK, &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N3", (char *)"N1");
error = EN_addlink(ph, (char *)"L1", EN_PUMP, (char *)"N3", (char *)"N1", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"L2", EN_PIPE, (char *)"N1", (char *)"N3");
error = EN_addlink(ph, (char *)"L2", EN_PIPE, (char *)"N1", (char *)"N3", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"L3", EN_PIPE, (char *)"N1", (char *)"N2");
error = EN_addlink(ph, (char *)"L3", EN_PIPE, (char *)"N1", (char *)"N2", &ind);
BOOST_REQUIRE(error == 0);
error = EN_addcurve(ph, (char *)"C1");
BOOST_REQUIRE(error == 0);

View File

@@ -3,8 +3,8 @@ LIBRARY EPANET2.DLL
EXPORTS
ENaddcontrol = _ENaddcontrol@24
ENaddcurve = _ENaddcurve@4
ENaddlink = _ENaddlink@16
ENaddnode = _ENaddnode@8
ENaddlink = _ENaddlink@20
ENaddnode = _ENaddnode@12
ENaddpattern = _ENaddpattern@4
ENaddrule = _ENaddrule@4
ENclearreport = _ENclearreport@0