epanet-plus 0.0.1__cp312-cp312-macosx_10_13_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of epanet-plus might be problematic. Click here for more details.
- docs/conf.py +67 -0
- epanet-msx-src/dispersion.h +27 -0
- epanet-msx-src/hash.c +107 -0
- epanet-msx-src/hash.h +28 -0
- epanet-msx-src/include/epanetmsx.h +104 -0
- epanet-msx-src/include/epanetmsx_export.h +42 -0
- epanet-msx-src/mathexpr.c +937 -0
- epanet-msx-src/mathexpr.h +39 -0
- epanet-msx-src/mempool.c +204 -0
- epanet-msx-src/mempool.h +24 -0
- epanet-msx-src/msxchem.c +1285 -0
- epanet-msx-src/msxcompiler.c +368 -0
- epanet-msx-src/msxdict.h +42 -0
- epanet-msx-src/msxdispersion.c +586 -0
- epanet-msx-src/msxerr.c +116 -0
- epanet-msx-src/msxfile.c +260 -0
- epanet-msx-src/msxfuncs.c +175 -0
- epanet-msx-src/msxfuncs.h +35 -0
- epanet-msx-src/msxinp.c +1504 -0
- epanet-msx-src/msxout.c +398 -0
- epanet-msx-src/msxproj.c +791 -0
- epanet-msx-src/msxqual.c +2011 -0
- epanet-msx-src/msxrpt.c +400 -0
- epanet-msx-src/msxtank.c +422 -0
- epanet-msx-src/msxtoolkit.c +1164 -0
- epanet-msx-src/msxtypes.h +551 -0
- epanet-msx-src/msxutils.c +524 -0
- epanet-msx-src/msxutils.h +56 -0
- epanet-msx-src/newton.c +158 -0
- epanet-msx-src/newton.h +34 -0
- epanet-msx-src/rk5.c +287 -0
- epanet-msx-src/rk5.h +39 -0
- epanet-msx-src/ros2.c +293 -0
- epanet-msx-src/ros2.h +35 -0
- epanet-msx-src/smatrix.c +816 -0
- epanet-msx-src/smatrix.h +29 -0
- epanet-src/AUTHORS +60 -0
- epanet-src/LICENSE +21 -0
- epanet-src/enumstxt.h +151 -0
- epanet-src/epanet.c +5937 -0
- epanet-src/epanet2.c +961 -0
- epanet-src/epanet2.def +131 -0
- epanet-src/errors.dat +79 -0
- epanet-src/flowbalance.c +186 -0
- epanet-src/funcs.h +219 -0
- epanet-src/genmmd.c +1000 -0
- epanet-src/hash.c +177 -0
- epanet-src/hash.h +28 -0
- epanet-src/hydcoeffs.c +1303 -0
- epanet-src/hydraul.c +1164 -0
- epanet-src/hydsolver.c +781 -0
- epanet-src/hydstatus.c +442 -0
- epanet-src/include/epanet2.h +466 -0
- epanet-src/include/epanet2_2.h +1962 -0
- epanet-src/include/epanet2_enums.h +518 -0
- epanet-src/inpfile.c +884 -0
- epanet-src/input1.c +672 -0
- epanet-src/input2.c +970 -0
- epanet-src/input3.c +2265 -0
- epanet-src/leakage.c +527 -0
- epanet-src/mempool.c +146 -0
- epanet-src/mempool.h +24 -0
- epanet-src/output.c +853 -0
- epanet-src/project.c +1691 -0
- epanet-src/quality.c +695 -0
- epanet-src/qualreact.c +800 -0
- epanet-src/qualroute.c +696 -0
- epanet-src/report.c +1559 -0
- epanet-src/rules.c +1500 -0
- epanet-src/smatrix.c +871 -0
- epanet-src/text.h +508 -0
- epanet-src/types.h +928 -0
- epanet-src/util/cstr_helper.c +59 -0
- epanet-src/util/cstr_helper.h +38 -0
- epanet-src/util/errormanager.c +92 -0
- epanet-src/util/errormanager.h +39 -0
- epanet-src/util/filemanager.c +212 -0
- epanet-src/util/filemanager.h +81 -0
- epanet-src/validate.c +408 -0
- epanet.cpython-312-darwin.so +0 -0
- epanet_plus/VERSION +1 -0
- epanet_plus/__init__.py +8 -0
- epanet_plus/epanet_plus.c +118 -0
- epanet_plus/epanet_toolkit.py +2730 -0
- epanet_plus/epanet_wrapper.py +2414 -0
- epanet_plus/include/epanet_plus.h +9 -0
- epanet_plus-0.0.1.dist-info/METADATA +152 -0
- epanet_plus-0.0.1.dist-info/RECORD +105 -0
- epanet_plus-0.0.1.dist-info/WHEEL +6 -0
- epanet_plus-0.0.1.dist-info/licenses/LICENSE +21 -0
- epanet_plus-0.0.1.dist-info/top_level.txt +11 -0
- examples/basic_usage.py +35 -0
- python-extension/ext.c +344 -0
- python-extension/pyepanet.c +2133 -0
- python-extension/pyepanet.h +143 -0
- python-extension/pyepanet2.c +1823 -0
- python-extension/pyepanet2.h +141 -0
- python-extension/pyepanet_plus.c +37 -0
- python-extension/pyepanet_plus.h +4 -0
- python-extension/pyepanetmsx.c +388 -0
- python-extension/pyepanetmsx.h +35 -0
- tests/test_epanet.py +16 -0
- tests/test_epanetmsx.py +36 -0
- tests/test_epyt.py +114 -0
- tests/test_load_inp_from_buffer.py +18 -0
epanet-src/input2.c
ADDED
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
/*
|
|
2
|
+
******************************************************************************
|
|
3
|
+
Project: OWA EPANET
|
|
4
|
+
Version: 2.3
|
|
5
|
+
Module: input2.c
|
|
6
|
+
Description: reads and interprets network data from an EPANET input file
|
|
7
|
+
Authors: see AUTHORS
|
|
8
|
+
Copyright: see AUTHORS
|
|
9
|
+
License: see LICENSE
|
|
10
|
+
Last Updated: 02/19/2025
|
|
11
|
+
******************************************************************************
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#include <stdlib.h>
|
|
15
|
+
#include <stdio.h>
|
|
16
|
+
#include <string.h>
|
|
17
|
+
#include <math.h>
|
|
18
|
+
|
|
19
|
+
#include "types.h"
|
|
20
|
+
#include "funcs.h"
|
|
21
|
+
#include "hash.h"
|
|
22
|
+
#include "text.h"
|
|
23
|
+
|
|
24
|
+
extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H)
|
|
25
|
+
|
|
26
|
+
// Exported functions
|
|
27
|
+
int addnodeID(Network *, int, char *);
|
|
28
|
+
int addlinkID(Network *, int, char *);
|
|
29
|
+
int getunitsoption(Project *, char *);
|
|
30
|
+
int getheadlossoption(Project *, char *);
|
|
31
|
+
|
|
32
|
+
// Local functions
|
|
33
|
+
static int newline(Project *, int, char *);
|
|
34
|
+
static int addpattern(Network *, char *);
|
|
35
|
+
static int addcurve(Network *, char *);
|
|
36
|
+
static void inperrmsg(Project *, int, int, char *);
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
int netsize(Project *pr)
|
|
40
|
+
/*
|
|
41
|
+
**--------------------------------------------------------------
|
|
42
|
+
** Input: none
|
|
43
|
+
** Output: returns error code
|
|
44
|
+
** Purpose: determines number of network objects
|
|
45
|
+
**--------------------------------------------------------------
|
|
46
|
+
*/
|
|
47
|
+
{
|
|
48
|
+
Parser *parser = &pr->parser;
|
|
49
|
+
|
|
50
|
+
char line[MAXLINE + 1]; // Line from input data file
|
|
51
|
+
char *tok; // First token of line
|
|
52
|
+
int sect, newsect; // Input data sections
|
|
53
|
+
int errcode = 0; // Error code
|
|
54
|
+
Spattern *pattern;
|
|
55
|
+
|
|
56
|
+
// Initialize object counts
|
|
57
|
+
parser->MaxJuncs = 0;
|
|
58
|
+
parser->MaxTanks = 0;
|
|
59
|
+
parser->MaxPipes = 0;
|
|
60
|
+
parser->MaxPumps = 0;
|
|
61
|
+
parser->MaxValves = 0;
|
|
62
|
+
parser->MaxControls = 0;
|
|
63
|
+
parser->MaxRules = 0;
|
|
64
|
+
parser->MaxCurves = 0;
|
|
65
|
+
sect = -1;
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
// Add a "dummy" time pattern with index of 0 and a single multiplier
|
|
69
|
+
// of 1.0 to be used by all demands not assigned a pattern
|
|
70
|
+
pr->network.Npats = -1;
|
|
71
|
+
errcode = addpattern(&pr->network, "");
|
|
72
|
+
if (errcode) return errcode;
|
|
73
|
+
pattern = &pr->network.Pattern[0];
|
|
74
|
+
pattern->Length = 1;
|
|
75
|
+
pattern[0].F = (double *)calloc(1, sizeof(double));
|
|
76
|
+
pattern[0].F[0] = 1.0;
|
|
77
|
+
parser->MaxPats = pr->network.Npats;
|
|
78
|
+
|
|
79
|
+
// Make a pass through input file counting number of each object
|
|
80
|
+
if (parser->InFile == NULL) return 0;
|
|
81
|
+
while (fgets(line, MAXLINE, parser->InFile) != NULL)
|
|
82
|
+
{
|
|
83
|
+
// Skip blank lines & those beginning with a comment
|
|
84
|
+
tok = strtok(line, SEPSTR);
|
|
85
|
+
if (tok == NULL) continue;
|
|
86
|
+
if (*tok == ';') continue;
|
|
87
|
+
|
|
88
|
+
// Check if line begins with a new section heading
|
|
89
|
+
if (tok[0] == '[')
|
|
90
|
+
{
|
|
91
|
+
newsect = findmatch(tok, SectTxt);
|
|
92
|
+
if (newsect >= 0)
|
|
93
|
+
{
|
|
94
|
+
sect = newsect;
|
|
95
|
+
if (sect == _END) break;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
else
|
|
99
|
+
{
|
|
100
|
+
sect = -1;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Add to count of current object
|
|
106
|
+
switch (sect)
|
|
107
|
+
{
|
|
108
|
+
case _JUNCTIONS: parser->MaxJuncs++; break;
|
|
109
|
+
case _RESERVOIRS:
|
|
110
|
+
case _TANKS: parser->MaxTanks++; break;
|
|
111
|
+
case _PIPES: parser->MaxPipes++; break;
|
|
112
|
+
case _PUMPS: parser->MaxPumps++; break;
|
|
113
|
+
case _VALVES: parser->MaxValves++; break;
|
|
114
|
+
case _CONTROLS: parser->MaxControls++; break;
|
|
115
|
+
case _RULES: addrule(parser,tok); break;
|
|
116
|
+
case _PATTERNS:
|
|
117
|
+
errcode = addpattern(&pr->network, tok);
|
|
118
|
+
parser->MaxPats = pr->network.Npats;
|
|
119
|
+
break;
|
|
120
|
+
case _CURVES:
|
|
121
|
+
errcode = addcurve(&pr->network, tok);
|
|
122
|
+
parser->MaxCurves = pr->network.Ncurves;
|
|
123
|
+
break;
|
|
124
|
+
case _OPTIONS:
|
|
125
|
+
if (match(tok, w_UNITS))
|
|
126
|
+
getunitsoption(pr, strtok(line, SEPSTR));
|
|
127
|
+
else if (match(tok, w_HEADLOSS))
|
|
128
|
+
getheadlossoption(pr, strtok(line, SEPSTR));
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
if (errcode) break;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
parser->MaxNodes = parser->MaxJuncs + parser->MaxTanks;
|
|
135
|
+
parser->MaxLinks = parser->MaxPipes + parser->MaxPumps + parser->MaxValves;
|
|
136
|
+
if (parser->MaxPats < 1) parser->MaxPats = 1;
|
|
137
|
+
return errcode;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
int readdata(Project *pr)
|
|
141
|
+
/*
|
|
142
|
+
**--------------------------------------------------------------
|
|
143
|
+
** Input: none
|
|
144
|
+
** Output: returns error code
|
|
145
|
+
** Purpose: reads contents of input data file
|
|
146
|
+
**--------------------------------------------------------------
|
|
147
|
+
*/
|
|
148
|
+
{
|
|
149
|
+
Network *net = &pr->network;
|
|
150
|
+
Parser *parser = &pr->parser;
|
|
151
|
+
|
|
152
|
+
char line[MAXLINE + 1], // Line from input data file
|
|
153
|
+
wline[MAXLINE + 1]; // Working copy of input line
|
|
154
|
+
char errmsg[MAXMSG + 1] = "";
|
|
155
|
+
int sect, newsect, // Data sections
|
|
156
|
+
errcode = 0, // Error code
|
|
157
|
+
inperr, errsum; // Error code & total error count
|
|
158
|
+
|
|
159
|
+
// Allocate input buffer
|
|
160
|
+
parser->X = (double *)calloc(MAXTOKS, sizeof(double));
|
|
161
|
+
ERRCODE(MEMCHECK(parser->X));
|
|
162
|
+
if (errcode) return errcode;
|
|
163
|
+
|
|
164
|
+
// Initialize actual number of network components
|
|
165
|
+
parser->Ntitle = 0;
|
|
166
|
+
net->Nnodes = 0;
|
|
167
|
+
net->Njuncs = 0;
|
|
168
|
+
net->Ntanks = 0;
|
|
169
|
+
net->Nlinks = 0;
|
|
170
|
+
net->Npipes = 0;
|
|
171
|
+
net->Npumps = 0;
|
|
172
|
+
net->Nvalves = 0;
|
|
173
|
+
net->Ncontrols = 0;
|
|
174
|
+
net->Nrules = 0;
|
|
175
|
+
|
|
176
|
+
// Patterns & Curves were created previously in netsize()
|
|
177
|
+
parser->MaxPats = net->Npats;
|
|
178
|
+
parser->MaxCurves = net->Ncurves;
|
|
179
|
+
parser->PrevPat = NULL;
|
|
180
|
+
parser->PrevCurve = NULL;
|
|
181
|
+
|
|
182
|
+
// Initialize full line comment, input data section and error count
|
|
183
|
+
parser->LineComment[0] = '\0';
|
|
184
|
+
sect = -1;
|
|
185
|
+
errsum = 0;
|
|
186
|
+
|
|
187
|
+
// Read each line from input file
|
|
188
|
+
while (fgets(line, MAXLINE, parser->InFile) != NULL)
|
|
189
|
+
{
|
|
190
|
+
// Make copy of line and scan for tokens
|
|
191
|
+
strcpy(wline, line);
|
|
192
|
+
parser->Ntokens = gettokens(wline, parser->Tok, MAXTOKS, parser->Comment);
|
|
193
|
+
|
|
194
|
+
// Skip blank lines and those filled with a comment
|
|
195
|
+
parser->ErrTok = -1;
|
|
196
|
+
if (parser->Ntokens == 0)
|
|
197
|
+
{
|
|
198
|
+
// Store full line comment for Patterns and Curves
|
|
199
|
+
if (sect == _PATTERNS || sect == _CURVES)
|
|
200
|
+
{
|
|
201
|
+
strncpy(parser->LineComment, parser->Comment, MAXMSG);
|
|
202
|
+
}
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Apply full line comment for Patterns and Curves
|
|
207
|
+
if (sect == _PATTERNS || sect == _CURVES)
|
|
208
|
+
{
|
|
209
|
+
strcpy(parser->Comment, parser->LineComment);
|
|
210
|
+
}
|
|
211
|
+
parser->LineComment[0] = '\0';
|
|
212
|
+
|
|
213
|
+
// Check if max. line length exceeded
|
|
214
|
+
if (strlen(line) >= MAXLINE)
|
|
215
|
+
{
|
|
216
|
+
sprintf(pr->Msg, "%s section: %s", geterrmsg(214, errmsg), SectTxt[sect]);
|
|
217
|
+
writeline(pr, pr->Msg);
|
|
218
|
+
writeline(pr, line);
|
|
219
|
+
errsum++;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Check if at start of a new input section
|
|
223
|
+
if (parser->Tok[0][0] == '[')
|
|
224
|
+
{
|
|
225
|
+
newsect = findmatch(parser->Tok[0], SectTxt);
|
|
226
|
+
if (newsect >= 0)
|
|
227
|
+
{
|
|
228
|
+
sect = newsect;
|
|
229
|
+
if (sect == _END) break;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
else
|
|
233
|
+
{
|
|
234
|
+
sect = -1;
|
|
235
|
+
parser->ErrTok = 0;
|
|
236
|
+
errsum++;
|
|
237
|
+
inperrmsg(pr, 299, sect, line);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Otherwise process next line of input in current section
|
|
243
|
+
else
|
|
244
|
+
{
|
|
245
|
+
if (sect >= 0)
|
|
246
|
+
{
|
|
247
|
+
inperr = newline(pr, sect, line);
|
|
248
|
+
if (inperr > 0)
|
|
249
|
+
{
|
|
250
|
+
inperrmsg(pr, inperr, sect, line);
|
|
251
|
+
errsum++;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else continue;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Check for errors
|
|
259
|
+
if (errsum > 0) errcode = 200;
|
|
260
|
+
|
|
261
|
+
// Free input buffer
|
|
262
|
+
free(parser->X);
|
|
263
|
+
return errcode;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
int newline(Project *pr, int sect, char *line)
|
|
267
|
+
/*
|
|
268
|
+
**--------------------------------------------------------------
|
|
269
|
+
** Input: sect = current section of input file
|
|
270
|
+
** *line = line read from input file
|
|
271
|
+
** Output: returns error code or 0 if no error found
|
|
272
|
+
** Purpose: processes a new line of data from input file
|
|
273
|
+
**
|
|
274
|
+
** Note: The xxxdata() functions appear in INPUT3.c.
|
|
275
|
+
**--------------------------------------------------------------
|
|
276
|
+
*/
|
|
277
|
+
{
|
|
278
|
+
Parser *parser = &pr->parser;
|
|
279
|
+
int n;
|
|
280
|
+
|
|
281
|
+
switch (sect)
|
|
282
|
+
{
|
|
283
|
+
case _TITLE:
|
|
284
|
+
if (parser->Ntitle < 3)
|
|
285
|
+
{
|
|
286
|
+
n = (int)strlen(line);
|
|
287
|
+
if (line[n - 1] == 10)
|
|
288
|
+
line[n - 1] = '\0';
|
|
289
|
+
strncpy(pr->Title[parser->Ntitle], line, TITLELEN);
|
|
290
|
+
parser->Ntitle++;
|
|
291
|
+
}
|
|
292
|
+
return 0;
|
|
293
|
+
case _JUNCTIONS: return (juncdata(pr));
|
|
294
|
+
case _RESERVOIRS:
|
|
295
|
+
case _TANKS: return (tankdata(pr));
|
|
296
|
+
case _PIPES: return (pipedata(pr));
|
|
297
|
+
case _PUMPS: return (pumpdata(pr));
|
|
298
|
+
case _VALVES: return (valvedata(pr));
|
|
299
|
+
case _PATTERNS: return (patterndata(pr));
|
|
300
|
+
case _CURVES: return (curvedata(pr));
|
|
301
|
+
case _DEMANDS: return (demanddata(pr));
|
|
302
|
+
case _CONTROLS: return (controldata(pr));
|
|
303
|
+
case _RULES:
|
|
304
|
+
if (ruledata(pr) > 0)
|
|
305
|
+
{
|
|
306
|
+
ruleerrmsg(pr);
|
|
307
|
+
deleterule(pr, pr->network.Nrules);
|
|
308
|
+
return 200;
|
|
309
|
+
}
|
|
310
|
+
else return 0;
|
|
311
|
+
case _SOURCES: return (sourcedata(pr));
|
|
312
|
+
case _EMITTERS: return (emitterdata(pr));
|
|
313
|
+
case _LEAKAGE: return (leakagedata(pr));
|
|
314
|
+
case _QUALITY: return (qualdata(pr));
|
|
315
|
+
case _STATUS: return (statusdata(pr));
|
|
316
|
+
case _ROUGHNESS: return (0);
|
|
317
|
+
case _ENERGY: return (energydata(pr));
|
|
318
|
+
case _REACTIONS: return (reactdata(pr));
|
|
319
|
+
case _MIXING: return (mixingdata(pr));
|
|
320
|
+
case _REPORT: return (reportdata(pr));
|
|
321
|
+
case _TIMES: return (timedata(pr));
|
|
322
|
+
case _OPTIONS: return (optiondata(pr));
|
|
323
|
+
case _TAGS: return (tagdata(pr));
|
|
324
|
+
case _COORDS: return (coordata(pr));
|
|
325
|
+
case _VERTICES: return (vertexdata(pr));
|
|
326
|
+
|
|
327
|
+
// Data in these sections are not used for any computations
|
|
328
|
+
case _LABELS:
|
|
329
|
+
case _BACKDROP:
|
|
330
|
+
return (0);
|
|
331
|
+
}
|
|
332
|
+
return 201;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
int addnodeID(Network *net, int n, char *id)
|
|
336
|
+
/*
|
|
337
|
+
**-------------------------------------------------------------
|
|
338
|
+
** Input: n = node index
|
|
339
|
+
** id = ID label
|
|
340
|
+
** Output: returns 0 if ID already in use, 1 if not
|
|
341
|
+
** Purpose: adds a node ID to the Node Hash Table
|
|
342
|
+
**--------------------------------------------------------------
|
|
343
|
+
*/
|
|
344
|
+
{
|
|
345
|
+
if (findnode(net,id))
|
|
346
|
+
return 215; // duplicate id
|
|
347
|
+
if (strlen(id) > MAXID)
|
|
348
|
+
return 252; // invalid format (too long)
|
|
349
|
+
strncpy(net->Node[n].ID, id, MAXID);
|
|
350
|
+
hashtable_insert(net->NodeHashTable, net->Node[n].ID, n);
|
|
351
|
+
return 0;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
int addlinkID(Network *net, int n, char *id)
|
|
355
|
+
/*
|
|
356
|
+
**-------------------------------------------------------------
|
|
357
|
+
** Input: n = link index
|
|
358
|
+
** id = ID label
|
|
359
|
+
** Output: returns 0 if ID already in use, 1 if not
|
|
360
|
+
** Purpose: adds a link ID to the Link Hash Table
|
|
361
|
+
**--------------------------------------------------------------
|
|
362
|
+
*/
|
|
363
|
+
{
|
|
364
|
+
if (findlink(net,id))
|
|
365
|
+
return 215; // duplicate id
|
|
366
|
+
if (strlen(id) > MAXID)
|
|
367
|
+
return 252; // invalid formt (too long);
|
|
368
|
+
strncpy(net->Link[n].ID, id, MAXID);
|
|
369
|
+
hashtable_insert(net->LinkHashTable, net->Link[n].ID, n);
|
|
370
|
+
return 0;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
int addpattern(Network *network, char *id)
|
|
374
|
+
/*
|
|
375
|
+
**-------------------------------------------------------------
|
|
376
|
+
** Input: id = pattern ID label
|
|
377
|
+
** Output: returns error code
|
|
378
|
+
** Purpose: adds a new pattern to the database
|
|
379
|
+
**--------------------------------------------------------------
|
|
380
|
+
*/
|
|
381
|
+
{
|
|
382
|
+
int n = network->Npats;
|
|
383
|
+
Spattern *pattern;
|
|
384
|
+
|
|
385
|
+
// Check if pattern was already created
|
|
386
|
+
if (n > 0)
|
|
387
|
+
{
|
|
388
|
+
if (strcmp(id, network->Pattern[n].ID) == 0) return 0;
|
|
389
|
+
if (findpattern(network, id) > 0) return 0;
|
|
390
|
+
}
|
|
391
|
+
if (strlen(id) > MAXID) return 252;
|
|
392
|
+
|
|
393
|
+
// Update pattern count & add a new pattern to the database
|
|
394
|
+
n = n + 2;
|
|
395
|
+
network->Pattern = (Spattern *)realloc(network->Pattern, n * sizeof(Spattern));
|
|
396
|
+
if (network->Pattern == NULL) return 101;
|
|
397
|
+
(network->Npats)++;
|
|
398
|
+
|
|
399
|
+
// Initialize the pattern
|
|
400
|
+
pattern = &network->Pattern[network->Npats];
|
|
401
|
+
strncpy(pattern->ID, id, MAXID);
|
|
402
|
+
pattern->Comment = NULL;
|
|
403
|
+
pattern->Length = 0;
|
|
404
|
+
pattern->F = NULL;
|
|
405
|
+
return 0;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
int addcurve(Network *network, char *id)
|
|
409
|
+
/*
|
|
410
|
+
**-------------------------------------------------------------
|
|
411
|
+
** Input: id = curve ID label
|
|
412
|
+
** Output: returns error code
|
|
413
|
+
** Purpose: adds a new curve to the database
|
|
414
|
+
**--------------------------------------------------------------
|
|
415
|
+
*/
|
|
416
|
+
{
|
|
417
|
+
int n = network->Ncurves;
|
|
418
|
+
Scurve *curve;
|
|
419
|
+
|
|
420
|
+
// Check if was already created
|
|
421
|
+
if (n > 0)
|
|
422
|
+
{
|
|
423
|
+
if (strcmp(id, network->Curve[n].ID) == 0) return 0;
|
|
424
|
+
if (findcurve(network, id) > 0) return 0;
|
|
425
|
+
}
|
|
426
|
+
if (strlen(id) > MAXID) return 252;
|
|
427
|
+
|
|
428
|
+
n = n + 2;
|
|
429
|
+
network->Curve = (Scurve *)realloc(network->Curve, n * sizeof(Scurve));
|
|
430
|
+
if (network->Curve == NULL) return 101;
|
|
431
|
+
(network->Ncurves)++;
|
|
432
|
+
|
|
433
|
+
// Initialize the curve
|
|
434
|
+
curve = &network->Curve[network->Ncurves];
|
|
435
|
+
strncpy(curve->ID, id, MAXID);
|
|
436
|
+
curve->Type = GENERIC_CURVE;
|
|
437
|
+
curve->Comment = NULL;
|
|
438
|
+
curve->Capacity = 0;
|
|
439
|
+
curve->Npts = 0;
|
|
440
|
+
curve->X = NULL;
|
|
441
|
+
curve->Y = NULL;
|
|
442
|
+
return 0;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
int getunitsoption(Project *pr, char *units)
|
|
446
|
+
/*
|
|
447
|
+
**-------------------------------------------------------------
|
|
448
|
+
** Input: units = name of flow units to be used
|
|
449
|
+
** Output: returns 1 if successful, 0 if not
|
|
450
|
+
** Purpose: sets the flows units to be used by a project.
|
|
451
|
+
**--------------------------------------------------------------
|
|
452
|
+
*/
|
|
453
|
+
{
|
|
454
|
+
Parser *parser = &pr->parser;
|
|
455
|
+
if (match(units, w_CFS)) parser->Flowflag = CFS;
|
|
456
|
+
else if (match(units, w_GPM)) parser->Flowflag = GPM;
|
|
457
|
+
else if (match(units, w_AFD)) parser->Flowflag = AFD;
|
|
458
|
+
else if (match(units, w_MGD)) parser->Flowflag = MGD;
|
|
459
|
+
else if (match(units, w_IMGD)) parser->Flowflag = IMGD;
|
|
460
|
+
else if (match(units, w_LPS)) parser->Flowflag = LPS;
|
|
461
|
+
else if (match(units, w_LPM)) parser->Flowflag = LPM;
|
|
462
|
+
else if (match(units, w_CMH)) parser->Flowflag = CMH;
|
|
463
|
+
else if (match(units, w_CMD)) parser->Flowflag = CMD;
|
|
464
|
+
else if (match(units, w_MLD)) parser->Flowflag = MLD;
|
|
465
|
+
else if (match(units, w_CMS)) parser->Flowflag = CMS;
|
|
466
|
+
else if (match(units, w_SI)) parser->Flowflag = LPS;
|
|
467
|
+
else return 0;
|
|
468
|
+
if (parser->Flowflag >= LPS) parser->Unitsflag = SI;
|
|
469
|
+
else parser->Unitsflag = US;
|
|
470
|
+
return 1;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
int getheadlossoption(Project *pr, char *formula)
|
|
474
|
+
/*
|
|
475
|
+
**-------------------------------------------------------------
|
|
476
|
+
** Input: formula = name of head loss formula to be used
|
|
477
|
+
** Output: returns 1 if successful, 0 if not
|
|
478
|
+
** Purpose: sets the head loss formula to be used by a project.
|
|
479
|
+
**--------------------------------------------------------------
|
|
480
|
+
*/
|
|
481
|
+
{
|
|
482
|
+
Hydraul *hyd = &pr->hydraul;
|
|
483
|
+
if (match(formula, w_HW)) hyd->Formflag = HW;
|
|
484
|
+
else if (match(formula, w_DW)) hyd->Formflag = DW;
|
|
485
|
+
else if (match(formula, w_CM)) hyd->Formflag = CM;
|
|
486
|
+
else return 0;
|
|
487
|
+
return 1;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
int findmatch(char *line, char *keyword[])
|
|
491
|
+
/*
|
|
492
|
+
**--------------------------------------------------------------
|
|
493
|
+
** Input: *line = line from input file
|
|
494
|
+
** *keyword[] = list of NULL terminated keywords
|
|
495
|
+
** Output: returns index of matching keyword or
|
|
496
|
+
** -1 if no match found
|
|
497
|
+
** Purpose: determines which keyword appears on input line
|
|
498
|
+
**--------------------------------------------------------------
|
|
499
|
+
*/
|
|
500
|
+
{
|
|
501
|
+
int i = 0;
|
|
502
|
+
while (keyword[i] != NULL)
|
|
503
|
+
{
|
|
504
|
+
if (match(line, keyword[i])) return i;
|
|
505
|
+
i++;
|
|
506
|
+
}
|
|
507
|
+
return -1;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
int match(const char *str, const char *substr)
|
|
511
|
+
/*
|
|
512
|
+
**--------------------------------------------------------------
|
|
513
|
+
** Input: *str = string being searched
|
|
514
|
+
** *substr = substring being searched for
|
|
515
|
+
** Output: returns 1 if substr found in str, 0 if not
|
|
516
|
+
** Purpose: sees if substr matches any part of str
|
|
517
|
+
**
|
|
518
|
+
** (Not case sensitive)
|
|
519
|
+
**--------------------------------------------------------------
|
|
520
|
+
*/
|
|
521
|
+
{
|
|
522
|
+
int i, j;
|
|
523
|
+
|
|
524
|
+
// Fail if substring is empty
|
|
525
|
+
if (!substr[0]) return 0;
|
|
526
|
+
|
|
527
|
+
// Skip leading blanks of str
|
|
528
|
+
for (i = 0; str[i]; i++)
|
|
529
|
+
{
|
|
530
|
+
if (str[i] != ' ') break;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Check if substr matches remainder of str
|
|
534
|
+
for (j = 0; substr[j]; i++, j++)
|
|
535
|
+
{
|
|
536
|
+
if (!str[i] || UCHAR(str[i]) != UCHAR(substr[j])) return 0;
|
|
537
|
+
}
|
|
538
|
+
return 1;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
int gettokens(char *s, char** Tok, int maxToks, char *comment)
|
|
542
|
+
/*
|
|
543
|
+
**--------------------------------------------------------------
|
|
544
|
+
** Input: *s = string to be tokenized
|
|
545
|
+
** Output: returns number of tokens in s
|
|
546
|
+
** Purpose: scans string for tokens, saving pointers to them
|
|
547
|
+
** in module global variable Tok[]
|
|
548
|
+
**
|
|
549
|
+
** Tokens can be separated by the characters listed in SEPSTR
|
|
550
|
+
** (spaces, tabs, newline, carriage return) which is defined
|
|
551
|
+
** in TYPES.H. Text between quotes is treated as a single token.
|
|
552
|
+
**--------------------------------------------------------------
|
|
553
|
+
*/
|
|
554
|
+
{
|
|
555
|
+
int n;
|
|
556
|
+
int len, m;
|
|
557
|
+
char *c, *c2;
|
|
558
|
+
|
|
559
|
+
// clear comment
|
|
560
|
+
comment[0] = '\0';
|
|
561
|
+
|
|
562
|
+
// Begin with no tokens
|
|
563
|
+
for (n=0; n<maxToks; n++) Tok[n] = NULL;
|
|
564
|
+
n = 0;
|
|
565
|
+
|
|
566
|
+
// Truncate s at start of comment
|
|
567
|
+
c = strchr(s,';');
|
|
568
|
+
if (c)
|
|
569
|
+
{
|
|
570
|
+
c2 = c+1;
|
|
571
|
+
if (c2)
|
|
572
|
+
{
|
|
573
|
+
// there is a comment here, after the semi-colon.
|
|
574
|
+
len = (int)strlen(c2);
|
|
575
|
+
if (len > 0)
|
|
576
|
+
{
|
|
577
|
+
len = (int)strcspn(c2, "\n\r");
|
|
578
|
+
len = MIN(len, MAXMSG);
|
|
579
|
+
strncpy(comment, c2, len);
|
|
580
|
+
comment[MIN(len,MAXMSG)] = '\0';
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
*c = '\0';
|
|
584
|
+
}
|
|
585
|
+
len = (int)strlen(s);
|
|
586
|
+
|
|
587
|
+
// Scan s for tokens until nothing left
|
|
588
|
+
while (len > 0 && n < MAXTOKS)
|
|
589
|
+
{
|
|
590
|
+
m = (int)strcspn(s,SEPSTR); // Find token length
|
|
591
|
+
if (m == len) // s is last token
|
|
592
|
+
{
|
|
593
|
+
Tok[n] = s;
|
|
594
|
+
n++;
|
|
595
|
+
break;
|
|
596
|
+
}
|
|
597
|
+
len -= m+1; // Update length of s
|
|
598
|
+
if (m == 0) s++; // No token found
|
|
599
|
+
else
|
|
600
|
+
{
|
|
601
|
+
if (*s == '"') // Token begins with quote
|
|
602
|
+
{
|
|
603
|
+
s++; // Start token after quote
|
|
604
|
+
m = (int)strcspn(s,"\"\n\r"); // Find end quote (or EOL)
|
|
605
|
+
}
|
|
606
|
+
s[m] = '\0'; // Null-terminate the token
|
|
607
|
+
Tok[n] = s; // Save pointer to token
|
|
608
|
+
n++; // Update token count
|
|
609
|
+
s += m+1; // Begin next token
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return n;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
double hour(char *time, char *units)
|
|
616
|
+
/*
|
|
617
|
+
**---------------------------------------------------------
|
|
618
|
+
** Input: *time = string containing a time value
|
|
619
|
+
** *units = string containing time units
|
|
620
|
+
** Output: returns numerical value of time in hours,
|
|
621
|
+
** or -1 if an error occurs
|
|
622
|
+
** Purpose: converts time from units to hours
|
|
623
|
+
**---------------------------------------------------------
|
|
624
|
+
*/
|
|
625
|
+
{
|
|
626
|
+
int n;
|
|
627
|
+
double y[3];
|
|
628
|
+
char *s;
|
|
629
|
+
|
|
630
|
+
// Separate clock time into hrs, min, sec
|
|
631
|
+
for (n = 0; n < 3; n++) y[n] = 0.0;
|
|
632
|
+
n = 0;
|
|
633
|
+
s = strtok(time, ":");
|
|
634
|
+
while (s != NULL && n <= 3)
|
|
635
|
+
{
|
|
636
|
+
if (!getfloat(s, &y[n])) return -1.0;
|
|
637
|
+
s = strtok(NULL, ":");
|
|
638
|
+
n++;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// If decimal time with units attached then convert to hours
|
|
642
|
+
if (n == 1)
|
|
643
|
+
{
|
|
644
|
+
if (strlen(units) == 0) return (y[0]);
|
|
645
|
+
if (match(units, w_SECONDS)) return (y[0] / 3600.0);
|
|
646
|
+
if (match(units, w_MINUTES)) return (y[0] / 60.0);
|
|
647
|
+
if (match(units, w_HOURS)) return (y[0]);
|
|
648
|
+
if (match(units, w_DAYS)) return (y[0] * 24.0);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// Convert hh:mm:ss format to decimal hours
|
|
652
|
+
if (n > 1) y[0] = y[0] + y[1] / 60.0 + y[2] / 3600.0;
|
|
653
|
+
|
|
654
|
+
// If am/pm attached then adjust hour accordingly
|
|
655
|
+
// (12 am is midnight, 12 pm is noon)
|
|
656
|
+
if (units[0] == '\0') return y[0];
|
|
657
|
+
if (match(units, w_AM))
|
|
658
|
+
{
|
|
659
|
+
if (y[0] >= 13.0) return -1.0;
|
|
660
|
+
if (y[0] >= 12.0) return (y[0] - 12.0);
|
|
661
|
+
else return (y[0]);
|
|
662
|
+
}
|
|
663
|
+
if (match(units, w_PM))
|
|
664
|
+
{
|
|
665
|
+
if (y[0] >= 13.0) return -1.0;
|
|
666
|
+
if (y[0] >= 12.0) return y[0];
|
|
667
|
+
else return (y[0] + 12.0);
|
|
668
|
+
}
|
|
669
|
+
return -1.0;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
int getfloat(char *s, double *y)
|
|
673
|
+
/*
|
|
674
|
+
**-----------------------------------------------------------
|
|
675
|
+
** Input: *s = character string
|
|
676
|
+
** Output: *y = floating point number
|
|
677
|
+
** returns 1 if conversion successful, 0 if not
|
|
678
|
+
** Purpose: converts string to floating point number
|
|
679
|
+
**-----------------------------------------------------------
|
|
680
|
+
*/
|
|
681
|
+
{
|
|
682
|
+
char *endptr;
|
|
683
|
+
*y = (double)strtod(s, &endptr);
|
|
684
|
+
if (*endptr > 0) return 0;
|
|
685
|
+
return 1;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
int setreport(Project *pr, char *s)
|
|
689
|
+
/*
|
|
690
|
+
**-----------------------------------------------------------
|
|
691
|
+
** Input: *s = report format command
|
|
692
|
+
** Output: none
|
|
693
|
+
** Returns: error code
|
|
694
|
+
** Purpose: processes a report formatting command
|
|
695
|
+
** issued by the ENsetreport function
|
|
696
|
+
**-----------------------------------------------------------
|
|
697
|
+
*/
|
|
698
|
+
{
|
|
699
|
+
Parser *parser = &pr->parser;
|
|
700
|
+
parser->Ntokens = gettokens(s, parser->Tok, MAXTOKS, parser->Comment);
|
|
701
|
+
return reportdata(pr);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
void inperrmsg(Project *pr, int err, int sect, char *line)
|
|
705
|
+
/*
|
|
706
|
+
**-------------------------------------------------------------
|
|
707
|
+
** Input: err = error code
|
|
708
|
+
** sect = input data section
|
|
709
|
+
** *line = line from input file
|
|
710
|
+
** Output: none
|
|
711
|
+
** Purpose: displays input reader error message
|
|
712
|
+
**-------------------------------------------------------------
|
|
713
|
+
*/
|
|
714
|
+
{
|
|
715
|
+
Parser *parser = &pr->parser;
|
|
716
|
+
|
|
717
|
+
char errStr[MAXMSG + 1] = "";
|
|
718
|
+
char tok[MAXMSG + 1];
|
|
719
|
+
|
|
720
|
+
// Get token associated with input error
|
|
721
|
+
if (parser->ErrTok >= 0) strcpy(tok, parser->Tok[parser->ErrTok]);
|
|
722
|
+
else strcpy(tok, "");
|
|
723
|
+
|
|
724
|
+
// write error message to report file
|
|
725
|
+
if (err == 299)
|
|
726
|
+
sprintf(pr->Msg, "Error %d: %s %s: section contents ignored.",
|
|
727
|
+
err, geterrmsg(err, errStr), tok);
|
|
728
|
+
else
|
|
729
|
+
sprintf(pr->Msg, "Error %d: %s %s in %s section:",
|
|
730
|
+
err, geterrmsg(err, errStr), tok, SectTxt[sect]);
|
|
731
|
+
writeline(pr, pr->Msg);
|
|
732
|
+
|
|
733
|
+
// Echo input line
|
|
734
|
+
writeline(pr, line);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
char *read_line_from_buffer(char *line, const int maxLen, const char **buf)
|
|
738
|
+
{
|
|
739
|
+
if(**buf == '\0')
|
|
740
|
+
return NULL;
|
|
741
|
+
|
|
742
|
+
int i;
|
|
743
|
+
for(i=0; i <= maxLen - 1; ++(*buf))
|
|
744
|
+
{
|
|
745
|
+
if(**buf == '\0')
|
|
746
|
+
break;
|
|
747
|
+
if(**buf == '\n')
|
|
748
|
+
{
|
|
749
|
+
*(line++)='\0';
|
|
750
|
+
++(*buf);
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
*(line++) = **buf;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
if(i == maxLen - 1)
|
|
758
|
+
*(line++) = '\0';
|
|
759
|
+
|
|
760
|
+
return line;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
int netsize_from_buffer(Project *pr, const char* inpBuffer)
|
|
764
|
+
{
|
|
765
|
+
Parser *parser = &pr->parser;
|
|
766
|
+
|
|
767
|
+
char line[MAXLINE + 1]; // Line from input data file
|
|
768
|
+
char *tok; // First token of line
|
|
769
|
+
int sect, newsect; // Input data sections
|
|
770
|
+
int errcode = 0; // Error code
|
|
771
|
+
Spattern *pattern;
|
|
772
|
+
|
|
773
|
+
// Initialize object counts
|
|
774
|
+
parser->MaxJuncs = 0;
|
|
775
|
+
parser->MaxTanks = 0;
|
|
776
|
+
parser->MaxPipes = 0;
|
|
777
|
+
parser->MaxPumps = 0;
|
|
778
|
+
parser->MaxValves = 0;
|
|
779
|
+
parser->MaxControls = 0;
|
|
780
|
+
parser->MaxRules = 0;
|
|
781
|
+
parser->MaxCurves = 0;
|
|
782
|
+
sect = -1;
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
// Add a "dummy" time pattern with index of 0 and a single multiplier
|
|
786
|
+
// of 1.0 to be used by all demands not assigned a pattern
|
|
787
|
+
pr->network.Npats = -1;
|
|
788
|
+
errcode = addpattern(&pr->network, "");
|
|
789
|
+
if (errcode) return errcode;
|
|
790
|
+
pattern = &pr->network.Pattern[0];
|
|
791
|
+
pattern->Length = 1;
|
|
792
|
+
pattern[0].F = (double *)calloc(1, sizeof(double));
|
|
793
|
+
pattern[0].F[0] = 1.0;
|
|
794
|
+
parser->MaxPats = pr->network.Npats;
|
|
795
|
+
|
|
796
|
+
// Make a pass through input buffer counting number of each object
|
|
797
|
+
if (inpBuffer == NULL) return 0;
|
|
798
|
+
while(read_line_from_buffer(&line[0], MAXLINE, &inpBuffer) != NULL)
|
|
799
|
+
{
|
|
800
|
+
// Skip blank lines & those beginning with a comment
|
|
801
|
+
tok = strtok(line, SEPSTR);
|
|
802
|
+
if (tok == NULL) continue;
|
|
803
|
+
if (*tok == ';') continue;
|
|
804
|
+
|
|
805
|
+
// Check if line begins with a new section heading
|
|
806
|
+
if (tok[0] == '[')
|
|
807
|
+
{
|
|
808
|
+
newsect = findmatch(tok, SectTxt);
|
|
809
|
+
if (newsect >= 0)
|
|
810
|
+
{
|
|
811
|
+
sect = newsect;
|
|
812
|
+
if (sect == _END) break;
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
else continue;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Add to count of current object
|
|
819
|
+
switch (sect)
|
|
820
|
+
{
|
|
821
|
+
case _JUNCTIONS: parser->MaxJuncs++; break;
|
|
822
|
+
case _RESERVOIRS:
|
|
823
|
+
case _TANKS: parser->MaxTanks++; break;
|
|
824
|
+
case _PIPES: parser->MaxPipes++; break;
|
|
825
|
+
case _PUMPS: parser->MaxPumps++; break;
|
|
826
|
+
case _VALVES: parser->MaxValves++; break;
|
|
827
|
+
case _CONTROLS: parser->MaxControls++; break;
|
|
828
|
+
case _RULES: addrule(parser,tok); break;
|
|
829
|
+
case _PATTERNS:
|
|
830
|
+
errcode = addpattern(&pr->network, tok);
|
|
831
|
+
parser->MaxPats = pr->network.Npats;
|
|
832
|
+
break;
|
|
833
|
+
case _CURVES:
|
|
834
|
+
errcode = addcurve(&pr->network, tok);
|
|
835
|
+
parser->MaxCurves = pr->network.Ncurves;
|
|
836
|
+
break;
|
|
837
|
+
}
|
|
838
|
+
if (errcode) break;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
parser->MaxNodes = parser->MaxJuncs + parser->MaxTanks;
|
|
842
|
+
parser->MaxLinks = parser->MaxPipes + parser->MaxPumps + parser->MaxValves;
|
|
843
|
+
if (parser->MaxPats < 1) parser->MaxPats = 1;
|
|
844
|
+
if (!errcode)
|
|
845
|
+
{
|
|
846
|
+
if (parser->MaxJuncs < 1) errcode = 223; // Not enough nodes
|
|
847
|
+
else if (parser->MaxTanks == 0) errcode = 224; // No tanks
|
|
848
|
+
}
|
|
849
|
+
return errcode;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
int read_data_from_buffer(Project *pr, const char *inpBuffer)
|
|
853
|
+
{
|
|
854
|
+
Network *net = &pr->network;
|
|
855
|
+
Parser *parser = &pr->parser;
|
|
856
|
+
|
|
857
|
+
char line[MAXLINE + 1], // Line from input data file
|
|
858
|
+
wline[MAXLINE + 1]; // Working copy of input line
|
|
859
|
+
int sect, newsect, // Data sections
|
|
860
|
+
errcode = 0, // Error code
|
|
861
|
+
inperr, errsum; // Error code & total error count
|
|
862
|
+
|
|
863
|
+
// Allocate input buffer
|
|
864
|
+
parser->X = (double *)calloc(MAXTOKS, sizeof(double));
|
|
865
|
+
ERRCODE(MEMCHECK(parser->X));
|
|
866
|
+
if (errcode) return errcode;
|
|
867
|
+
|
|
868
|
+
// Initialize actual number of network components
|
|
869
|
+
parser->Ntitle = 0;
|
|
870
|
+
net->Nnodes = 0;
|
|
871
|
+
net->Njuncs = 0;
|
|
872
|
+
net->Ntanks = 0;
|
|
873
|
+
net->Nlinks = 0;
|
|
874
|
+
net->Npipes = 0;
|
|
875
|
+
net->Npumps = 0;
|
|
876
|
+
net->Nvalves = 0;
|
|
877
|
+
net->Ncontrols = 0;
|
|
878
|
+
net->Nrules = 0;
|
|
879
|
+
|
|
880
|
+
// Patterns & Curves were created previously in netsize()
|
|
881
|
+
parser->MaxPats = net->Npats;
|
|
882
|
+
parser->MaxCurves = net->Ncurves;
|
|
883
|
+
parser->PrevPat = NULL;
|
|
884
|
+
parser->PrevCurve = NULL;
|
|
885
|
+
|
|
886
|
+
// Initialize full line comment, input data section and error count
|
|
887
|
+
parser->LineComment[0] = '\0';
|
|
888
|
+
sect = -1;
|
|
889
|
+
errsum = 0;
|
|
890
|
+
|
|
891
|
+
// Read each line from input file
|
|
892
|
+
const char **pData = &inpBuffer;
|
|
893
|
+
while (read_line_from_buffer(&line[0], MAXLINE, pData) != NULL)
|
|
894
|
+
{
|
|
895
|
+
// Make copy of line and scan for tokens
|
|
896
|
+
strcpy(wline, line);
|
|
897
|
+
parser->Ntokens = gettokens(wline, parser->Tok, MAXTOKS, parser->Comment);
|
|
898
|
+
|
|
899
|
+
// Skip blank lines and those filled with a comment
|
|
900
|
+
parser->ErrTok = -1;
|
|
901
|
+
if (parser->Ntokens == 0)
|
|
902
|
+
{
|
|
903
|
+
// Store full line comment for Patterns and Curves
|
|
904
|
+
if (sect == _PATTERNS || sect == _CURVES)
|
|
905
|
+
{
|
|
906
|
+
strncpy(parser->LineComment, parser->Comment, MAXMSG);
|
|
907
|
+
}
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// Apply full line comment for Patterns and Curves
|
|
912
|
+
if (sect == _PATTERNS || sect == _CURVES)
|
|
913
|
+
{
|
|
914
|
+
strcpy(parser->Comment, parser->LineComment);
|
|
915
|
+
}
|
|
916
|
+
parser->LineComment[0] = '\0';
|
|
917
|
+
|
|
918
|
+
// Check if max. line length exceeded
|
|
919
|
+
if (strlen(line) >= MAXLINE)
|
|
920
|
+
{
|
|
921
|
+
char errStr[MAXMSG + 1] = "";
|
|
922
|
+
sprintf(pr->Msg, "%s section: %s", geterrmsg(214, errStr), SectTxt[sect]);
|
|
923
|
+
writeline(pr, pr->Msg);
|
|
924
|
+
writeline(pr, line);
|
|
925
|
+
errsum++;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// Check if at start of a new input section
|
|
929
|
+
if (parser->Tok[0][0] == '[')
|
|
930
|
+
{
|
|
931
|
+
newsect = findmatch(parser->Tok[0], SectTxt);
|
|
932
|
+
if (newsect >= 0)
|
|
933
|
+
{
|
|
934
|
+
sect = newsect;
|
|
935
|
+
if (sect == _END) break;
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
else
|
|
939
|
+
{
|
|
940
|
+
sect = -1;
|
|
941
|
+
parser->ErrTok = 0;
|
|
942
|
+
errsum++;
|
|
943
|
+
inperrmsg(pr, 299, sect, line);
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// Otherwise process next line of input in current section
|
|
949
|
+
else
|
|
950
|
+
{
|
|
951
|
+
if (sect >= 0)
|
|
952
|
+
{
|
|
953
|
+
inperr = newline(pr, sect, line);
|
|
954
|
+
if (inperr > 0)
|
|
955
|
+
{
|
|
956
|
+
inperrmsg(pr, inperr, sect, line);
|
|
957
|
+
errsum++;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
else continue;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// Check for errors
|
|
965
|
+
if (errsum > 0) errcode = 200;
|
|
966
|
+
|
|
967
|
+
// Free input buffer
|
|
968
|
+
free(parser->X);
|
|
969
|
+
return errcode;
|
|
970
|
+
}
|