From f1175b1f92629f7a53e4f6cd15e4d39b3f4fcffd Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Sat, 15 Dec 2018 15:13:19 -0500 Subject: [PATCH] Error reporting fixes and re-formatting (issue #358) --- src/epanet.c | 205 +++++++++++++++-------------- src/errors.dat | 137 ++++++++++--------- src/input1.c | 22 ++-- src/input2.c | 63 ++++----- src/input3.c | 349 +++++++++++++++++++++++++++---------------------- src/project.c | 17 ++- src/types.h | 5 +- 7 files changed, 415 insertions(+), 383 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 9540a7b..9f2d13b 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 11/27/2018 + Last Updated: 12/15/2018 ****************************************************************************** */ @@ -26,7 +26,9 @@ #include "text.h" #include "enumstxt.h" - +#ifdef WINDOWS +#define snprintf _snprintf +#endif /******************************************************************** @@ -841,7 +843,7 @@ int DLLEXPORT EN_setstatusreport(EN_Project p, int code) { p->report.Statflag = (char)code; } - else errcode = 202; + else errcode = 251; return errcode; } @@ -915,7 +917,8 @@ int DLLEXPORT EN_geterror(int errcode, char *errmsg, int n) **---------------------------------------------------------------- */ { - char newMsg[MAXMSG + 1]; + char msg1[MAXMSG+1] = ""; + char msg2[MAXMSG+1] = ""; switch (errcode) { @@ -938,8 +941,10 @@ int DLLEXPORT EN_geterror(int errcode, char *errmsg, int n) strncpy(errmsg, WARN6, n); break; default: - geterrmsg(errcode, newMsg); - strncpy(errmsg, newMsg, n); + sprintf(msg1, "Error %d: ", errcode); + if ((errcode >= 202 && errcode <= 222) || + (errcode >= 240 && errcode <= 261)) strcat(msg1, "function call contains "); + snprintf(errmsg, n, "%s%s", msg1, geterrmsg(errcode, msg2)); } if (strlen(errmsg) == 0) return 251; @@ -974,6 +979,7 @@ int DLLEXPORT EN_getstatistic(EN_Project p, int code, EN_API_FLOAT_TYPE *value) *value = (EN_API_FLOAT_TYPE)(p->quality.MassBalance.ratio); break; default: + *value = 0.0; break; } return 0; @@ -1067,22 +1073,22 @@ int DLLEXPORT EN_setoption(EN_Project p, int code, EN_API_FLOAT_TYPE v) switch (code) { case EN_TRIALS: - if (value < 1.0) return 202; + if (value < 1.0) return 213; hyd->MaxIter = (int)value; break; case EN_ACCURACY: - if (value < 1.e-5 || value > 1.e-1) return 202; + if (value < 1.e-5 || value > 1.e-1) return 213; hyd->Hacc = value; break; case EN_TOLERANCE: - if (value < 0.0) return 202; + if (value < 0.0) return 213; qual->Ctol = value / Ucf[QUALITY]; break; case EN_EMITEXPON: - if (value <= 0.0) return 202; + if (value <= 0.0) return 213; n = 1.0 / value; ucf = pow(Ucf[FLOW], n) / Ucf[PRESSURE]; for (i = 1; i <= Njuncs; i++) @@ -1095,17 +1101,17 @@ int DLLEXPORT EN_setoption(EN_Project p, int code, EN_API_FLOAT_TYPE v) break; case EN_DEMANDMULT: - if (value <= 0.0) return 202; + if (value <= 0.0) return 213; hyd->Dmult = value; break; case EN_HEADERROR: - if (value < 0.0) return 202; + if (value < 0.0) return 213; hyd->HeadErrorLimit = value / Ucf[HEAD]; break; case EN_FLOWCHANGE: - if (value < 0.0) return 202; + if (value < 0.0) return 213; hyd->FlowChangeLimit = value / Ucf[FLOW]; break; @@ -1319,7 +1325,7 @@ int DLLEXPORT EN_settimeparam(EN_Project p, int code, long value) Times *time = &p->times; if (!p->Openflag) return 102; - if (value < 0) return 202; + if (value < 0) return 213; switch (code) { case EN_DURATION: @@ -1328,7 +1334,7 @@ int DLLEXPORT EN_settimeparam(EN_Project p, int code, long value) break; case EN_HYDSTEP: - if (value == 0) return 202; + if (value == 0) return 213; time->Hstep = value; time->Hstep = MIN(time->Pstep, time->Hstep); time->Hstep = MIN(time->Rstep, time->Hstep); @@ -1336,13 +1342,13 @@ int DLLEXPORT EN_settimeparam(EN_Project p, int code, long value) break; case EN_QUALSTEP: - if (value == 0) return 202; + if (value == 0) return 213; time->Qstep = value; time->Qstep = MIN(time->Qstep, time->Hstep); break; case EN_PATTERNSTEP: - if (value == 0) return 202; + if (value == 0) return 213; time->Pstep = value; if (time->Hstep > time->Pstep) time->Hstep = time->Pstep; break; @@ -1352,24 +1358,24 @@ int DLLEXPORT EN_settimeparam(EN_Project p, int code, long value) break; case EN_REPORTSTEP: - if (value == 0) return 202; + if (value == 0) return 213; time->Rstep = value; if (time->Hstep > time->Rstep) time->Hstep = time->Rstep; break; case EN_REPORTSTART: - if (time->Rstart > time->Dur) return 202; + if (time->Rstart > time->Dur) return 213; time->Rstart = value; break; case EN_RULESTEP: - if (value == 0) return 202; + if (value == 0) return 213; time->Rulestep = value; time->Rulestep = MIN(time->Rulestep, time->Hstep); break; case EN_STATISTIC: - if (value > RANGE) return 202; + if (value > RANGE) return 213; rpt->Tstatflag = (char)value; break; @@ -1401,16 +1407,26 @@ int DLLEXPORT EN_getqualinfo(EN_Project p, int *qualcode, char *chemname, */ { EN_getqualtype(p, qualcode, tracenode); - if (p->quality.Qualflag == TRACE) - { - strncpy(chemname, "", MAXID); - strncpy(chemunits, "dimensionless", MAXID); - } - else + if (p->quality.Qualflag == CHEM) { strncpy(chemname, p->quality.ChemName, MAXID); strncpy(chemunits, p->quality.ChemUnits, MAXID); } + else if (p->quality.Qualflag == TRACE) + { + strncpy(chemname, w_TRACE, MAXID); + strncpy(chemunits, u_PERCENT, MAXID); + } + else if (p->quality.Qualflag == AGE) + { + strncpy(chemname, w_AGE, MAXID); + strncpy(chemunits, u_HOURS, MAXID); + } + else + { + strncpy(chemname, "", MAXID); + strncpy(chemunits, "", MAXID); + } return 0; } @@ -1469,9 +1485,9 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualcode, char *chemname, if (qual->Qualflag == TRACE) // Source trace analysis { qual->TraceNode = findnode(net, tracenode); - if (qual->TraceNode == 0) return 203; - strncpy(qual->ChemName, u_PERCENT, MAXID); - strncpy(qual->ChemUnits, tracenode, MAXID); + if (qual->TraceNode == 0) return 212; + strncpy(qual->ChemName, w_TRACE, MAXID); + strncpy(qual->ChemUnits, u_PERCENT, MAXID); strcpy(rpt->Field[QUALITY].Units, u_PERCENT); } if (qual->Qualflag == AGE) // Water age analysis @@ -1656,7 +1672,7 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode) // Check that node exists if (!p->Openflag) return 102; - if (index <= 0 || index > net->Nnodes) return 204; + if (index <= 0 || index > net->Nnodes) return 203; if (actionCode < EN_UNCONDITIONAL || actionCode > EN_CONDITIONAL) return 251; // Can't delete a water quality trace node @@ -1930,7 +1946,7 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int code, EN_API_FLOAT_TY break; case EN_TANKLEVEL: - if (index <= nJuncs) return 251; + if (index <= nJuncs) return 0; v = (Tank[index - nJuncs].H0 - Node[index].El) * Ucf[ELEV]; break; @@ -2018,7 +2034,7 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int code, EN_API_FLOAT_TY break; case EN_TANKVOLUME: - if (index <= nJuncs) return 251; + if (index <= nJuncs) return 0; v = tankvolume(p, index - nJuncs, NodeHead[index]) * Ucf[VOLUME]; break; @@ -2103,14 +2119,14 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int code, EN_API_FLOAT_TY break; case EN_EMITTER: - if (index > nJuncs) return 203; - if (value < 0.0) return 202; + if (index > nJuncs) return 0; + if (value < 0.0) return 209; if (value > 0.0) value = pow((Ucf[FLOW] / value), hyd->Qexp) / Ucf[PRESSURE]; Node[index].Ke = value; break; case EN_INITQUAL: - if (value < 0.0) return 202; + if (value < 0.0) return 209; Node[index].C0 = value / Ucf[QUALITY]; if (index > nJuncs) Tank[index - nJuncs].C = Node[index].C0; break; @@ -2118,7 +2134,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int code, EN_API_FLOAT_TY case EN_SOURCEQUAL: case EN_SOURCETYPE: case EN_SOURCEPAT: - if (value < 0.0) return 202; + if (value < 0.0) return 209; source = Node[index].S; if (source == NULL) { @@ -2142,10 +2158,10 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int code, EN_API_FLOAT_TY if (j < CONCEN || j > FLOWPACED) return 251; else source->Type = (char)j; } - return 0; + break; case EN_TANKLEVEL: - if (index <= nJuncs) return 251; + if (index <= nJuncs) return 0; j = index - nJuncs; if (Tank[j].A == 0.0) /* Tank is a reservoir */ { @@ -2158,7 +2174,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int code, EN_API_FLOAT_TY else { value = Node[index].El + value / Ucf[ELEV]; - if (value > Tank[j].Hmax || value < Tank[j].Hmin) return 202; + if (value > Tank[j].Hmax || value < Tank[j].Hmin) return 209; Tank[j].H0 = value; Tank[j].V0 = tankvolume(p, j, Tank[j].H0); // Resetting Volume in addition to initial volume @@ -2168,10 +2184,10 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int code, EN_API_FLOAT_TY break; case EN_TANKDIAM: - if (value <= 0.0) return 202; - if (index <= nJuncs) return 251; + if (value <= 0.0) return 209; + if (index <= nJuncs) return 0; j = index - nJuncs; - if (j > 0 && Tank[j].A > 0.0) + if (Tank[j].A > 0.0) { value /= Ucf[ELEV]; Tank[j].A = PI * SQR(value) / 4.0; @@ -2179,82 +2195,78 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int code, EN_API_FLOAT_TY Tank[j].V0 = tankvolume(p, j, Tank[j].H0); Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); } - else return 251; break; case EN_MINVOLUME: - if (value < 0.0) return 202; - if (index <= nJuncs) return 251; + if (value < 0.0) return 209; + if (index <= nJuncs) return 0; j = index - nJuncs; - if (j > 0 && Tank[j].A > 0.0) + if (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; break; case EN_MINLEVEL: - if (value < 0.0) return 202; - if (index <= nJuncs) return 251; // not a tank or reservoir + if (value < 0.0) return 209; + if (index <= nJuncs) return 0; // not a tank or reservoir j = index - nJuncs; - if (Tank[j].A == 0.0) return 251; // node is a reservoir + if (Tank[j].A == 0.0) return 0; // 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; + if (Tank[j].Vcurve > 0) return 0; Tank[j].Hmin = hTmp; Tank[j].Vmin = (Tank[j].Hmin - Node[index].El) * Tank[j].A; } - else return 251; + else return 209; break; case EN_MAXLEVEL: - if (value < 0.0) return 202; - if (index <= nJuncs) return 251; // not a tank or reservoir + if (value < 0.0) return 209; + if (index <= nJuncs) return 0; // not a tank or reservoir j = index - nJuncs; - if (Tank[j].A == 0.0) return 251; // node is a reservoir + if (Tank[j].A == 0.0) return 0; // 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; + if (Tank[j].Vcurve > 0) return 0; Tank[j].Hmax = hTmp; Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); } - else return 251; + else return 209; break; case EN_MIXMODEL: j = ROUND(value); - if (index <= nJuncs) return 251; - if (j < MIX1 || j > LIFO) return 202; - if (index > nJuncs && Tank[index - nJuncs].A > 0.0) + if (index <= nJuncs) return 0; + if (j < MIX1 || j > LIFO) return 251; + if (Tank[index - nJuncs].A > 0.0) { Tank[index - nJuncs].MixModel = (char)j; } - else return 251; break; case EN_MIXFRACTION: - if (value < 0.0 || value > 1.0) return 202; - if (index <= nJuncs) return 251; + if (index <= nJuncs) return 0; + if (value < 0.0 || value > 1.0) return 209; j = index - nJuncs; - if (j > 0 && Tank[j].A > 0.0) + if (Tank[j].A > 0.0) { Tank[j].V1max = value * Tank[j].Vmax; } break; case EN_TANK_KBULK: - if (index <= nJuncs) return 251; + if (index <= nJuncs) return 0; j = index - nJuncs; - if (j > 0 && Tank[j].A > 0.0) + if (Tank[j].A > 0.0) { Tank[j].Kb = value / SECperDAY; qual->Reactflag = 1; } - else return 251; break; default: @@ -2280,7 +2292,7 @@ int DLLEXPORT EN_getcoord(EN_Project p, int index, EN_API_FLOAT_TYPE *x, if (!p->Openflag) return 102; if (index < 1 || index > p->network.Nnodes) return 203; - // check if node have coords + // check if node has coords node = &net->Node[index]; if (node->X == MISSING || node->Y == MISSING) return 254; @@ -2353,7 +2365,7 @@ int DLLEXPORT EN_setdemandmodel(EN_Project p, int type, EN_API_FLOAT_TYPE pmin, */ { if (type < 0 || type > EN_PDA) return 251; - if (pmin > preq || pexp <= 0.0) return 202; + if (pmin > preq || pexp <= 0.0) return 209; p->hydraul.DemandModel = type; p->hydraul.Pmin = pmin / p->Ucf[PRESSURE]; p->hydraul.Preq = preq / p->Ucf[PRESSURE]; @@ -2958,6 +2970,9 @@ int DLLEXPORT EN_setlinknodes(EN_Project p, int index, int node1, int node2) if (node1 < 0 || node1 > net->Nnodes) return 203; if (node2 < 0 || node2 > net->Nnodes) return 203; + // Check that nodes are not the same + if (node1 == node2) return 222; + // Check for illegal valve connection type = net->Link[index].Type; if (type == EN_PRV || type == EN_PSV || type == EN_FCV) @@ -2991,7 +3006,6 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, EN_LinkProperty code, Hydraul *hyd = &p->hydraul; double a, h, q, v = 0.0; - int returnValue = 0; int pmp; Slink *Link = net->Link; Spump *Pump = net->Pump; @@ -3184,12 +3198,6 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, EN_LinkProperty code, if (Link[index].Type == EN_PUMP) { v = (double)Pump[findpump(&p->network, index)].Hcurve; - if (v == 0) returnValue = 226; - } - else - { - v = 0; - returnValue = 211; } break; @@ -3197,20 +3205,14 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, EN_LinkProperty code, if (Link[index].Type == EN_PUMP) { v = (double)Pump[findpump(&p->network, index)].Ecurve; - if (v == 0) returnValue = 268; - } - else - { - v = 0; - returnValue = 211; } + break; default: - v = 0; - returnValue = 251; + return 251; } *value = (EN_API_FLOAT_TYPE)v; - return returnValue; + return 0; } int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int code, EN_API_FLOAT_TYPE v) @@ -3241,7 +3243,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int code, EN_API_FLOAT_TY case EN_DIAMETER: if (Link[index].Type != EN_PUMP) { - if (value <= 0.0) return 202; + if (value <= 0.0) return 211; 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 @@ -3253,7 +3255,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int code, EN_API_FLOAT_TY case EN_LENGTH: if (Link[index].Type <= EN_PIPE) { - if (value <= 0.0) return 202; + if (value <= 0.0) return 211; Link[index].Len = value / Ucf[ELEV]; resistcoeff(p, index); } @@ -3262,7 +3264,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int code, EN_API_FLOAT_TY case EN_ROUGHNESS: if (Link[index].Type <= EN_PIPE) { - if (value <= 0.0) return 202; + if (value <= 0.0) return 211; Link[index].Kc = value; if (hyd->Formflag == DW) Link[index].Kc /= (1000.0 * Ucf[ELEV]); resistcoeff(p, index); @@ -3272,7 +3274,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int code, EN_API_FLOAT_TY case EN_MINORLOSS: if (Link[index].Type != EN_PUMP) { - if (value <= 0.0) return 202; + if (value <= 0.0) return 211; Link[index].Km = 0.02517 * value / SQR(Link[index].Diam) / SQR(Link[index].Diam); } @@ -3283,7 +3285,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int code, EN_API_FLOAT_TY // Cannot set status for a check valve if (Link[index].Type == EN_CVPIPE) return 207; s = (char)ROUND(value); - if (s < 0 || s > 1) return 251; + if (s < 0 || s > 1) return 211; if (code == EN_INITSTATUS) { setlinkstatus(p, index, s, &Link[index].Status, &Link[index].Kc); @@ -3296,7 +3298,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int code, EN_API_FLOAT_TY case EN_INITSETTING: case EN_SETTING: - if (value < 0.0) return 202; + if (value < 0.0) return 211; if (Link[index].Type == EN_PIPE || Link[index].Type == EN_CVPIPE) { return EN_setlinkvalue(p, index, EN_ROUGHNESS, v); @@ -3318,9 +3320,9 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int code, EN_API_FLOAT_TY case EN_TCV: break; case EN_GPV: - return 202; // Cannot modify setting for GPV + return 207; // Cannot modify setting for GPV default: - return 251; + return 0; } if (code == EN_INITSETTING) { @@ -3379,7 +3381,8 @@ int DLLEXPORT EN_getpumptype(EN_Project p, int index, int *type) *type = -1; if (!p->Openflag) return 102; - if (index < 1 || index > Nlinks || EN_PUMP != Link[index].Type) return 204; + if (index < 1 || index > Nlinks) return 204; + if (EN_PUMP != Link[index].Type) return 216; *type = Pump[findpump(&p->network, index)].Ptype; return 0; } @@ -3399,8 +3402,10 @@ int DLLEXPORT EN_getheadcurveindex(EN_Project p, int index, int *curveindex) Spump *Pump = net->Pump; const int Nlinks = net->Nlinks; + *curveindex = 0; if (!p->Openflag) return 102; - if (index < 1 || index > Nlinks || EN_PUMP != Link[index].Type) return 204; + if (index < 1 || index > Nlinks) return 204; + if (EN_PUMP != Link[index].Type) return 216; *curveindex = Pump[findpump(net, index)].Hcurve; return 0; } @@ -3426,7 +3431,8 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project p, int index, int curveindex) // Check for valid parameters if (!p->Openflag) return 102; - if (index < 1 || index > net->Nlinks || EN_PUMP != net->Link[index].Type) return 204; + if (index < 1 || index > net->Nlinks) return 204; + if (EN_PUMP != net->Link[index].Type) return 0; if (curveindex <= 0 || curveindex > net->Ncurves) return 206; // Assign the new curve to the pump @@ -3649,7 +3655,7 @@ int DLLEXPORT EN_setpattern(EN_Project p, int index, EN_API_FLOAT_TYPE *f, int n // Check for valid arguments if (!p->Openflag) return 102; if (index <= 0 || index > net->Npats) return 205; - if (n <= 0) return 202; + if (n <= 0) return 251; // Re-set number of time periods & reallocate memory for multipliers Pattern[index].Length = n; @@ -3892,6 +3898,9 @@ int DLLEXPORT EN_setcurve(EN_Project p, int index, EN_API_FLOAT_TYPE *x, if (!p->Openflag) return 102; if (index <= 0 || index > net->Ncurves) return 206; if (n <= 0) return 202; + + // Check that x values are increasing + for (j = 1; j < n; j++) if (x[j-1] >= x[j]) return 230; // Re-set number of points & reallocate memory for values curve = &net->Curve[index]; diff --git a/src/errors.dat b/src/errors.dat index 13a788f..3e8b448 100644 --- a/src/errors.dat +++ b/src/errors.dat @@ -1,76 +1,71 @@ +//EPANET 2 Error Messages +DAT(0,"ok") +DAT(101,"insufficient memory available") +DAT(102,"no network data available") +DAT(103,"hydraulic solver not opened") +DAT(104,"no hydraulics for water quality analysis") +DAT(105,"water quality solver not opened") +DAT(106,"no results saved to report on") +DAT(107,"hydraulics supplied from external file") +DAT(108,"cannot use external file while hydraulics solver is active") +DAT(109,"cannot change time parameter when solver is active") +DAT(110,"cannot solve network hydraulic equations") +DAT(120,"cannot solve water quality transport equations") -DAT(0,EN_OK,"ok") -DAT(101,ENERR_INSUF_MEM,"insufficient memory available") -DAT(102,ENERR_NO_NET_DATA,"no network data available") -DAT(103,ENERR_HYD_NOT_INIT,"hydraulics not initialized") -DAT(104,ENERR_NO_HYD,"no hydraulics for water quality analysis") -DAT(105,ENERR_WQ_NOT_INIT,"water quality not initialized") -DAT(106,ENERR_NO_RESULT,"no results saved to report on") -DAT(107,ENERR_HYD_EXT_FILE,"hydraulics supplied from external file") -DAT(108,ENERR_CANT_USE_EXT_FILE,"cannot use external file while hydraulics solver is active") -DAT(109,ENERR_CANT_CHANGE_TIME_PARAM,"cannot change time parameter when solver is active") -DAT(110,ENERR_CANT_SOLVE_HYD,"cannot solve network hydraulic equations") -DAT(120,ENERR_CANT_SOLVE_WQ,"cannot solve water quality transport equations") +// These errors apply only to an input file +DAT(200,"one or more errors in input file") +DAT(201,"syntax error") -DAT(200,ENERR_INP_ERR,"one or more errors in input file") -DAT(201,ENERR_SYNTAX_LINE,"syntax error in following line of section") -DAT(202,ENERR_ILLEGAL_NUM,"function call contains illegal numeric value") -DAT(203,ENERR_UNDEF_NODE,"function call refers to undefined node") -DAT(204,ENERR_UNDEF_LINK,"function call refers to undefined link") -DAT(205,ENERR_UNDEF_PAT,"function call refers to undefined time pattern") -DAT(206,ENERR_UNDEF_CURVE,"function call refers to undefined curve") -DAT(207,ENERR_CANT_CONTROL_CV,"function call attempts to control a CV") +// These errors apply to both an input file and to API functions +DAT(202,"illegal numeric value") +DAT(203,"undefined node") +DAT(204,"undefined link") +DAT(205,"undefined time pattern") +DAT(206,"undefined curve") +DAT(207,"attempt to control CV/GPV link") +DAT(208,"reference to undefined node") +DAT(209,"illegal node property value") +DAT(210,"reference to undefined link") +DAT(211,"illegal link property value") +DAT(212,"undefined trace node") +DAT(213,"invalid option value") +DAT(214,"too many characters in input line") +DAT(215,"duplicate ID label") +DAT(216,"reference to undefined pump") +DAT(217,"invalid pump energy data") +DAT(219,"illegal valve connection to tank node") +DAT(220,"illegal valve connection to another valve") +DAT(221,"mis-placed rule clause in rule-based control") +DAT(222,"same start and end nodes for link") -DAT(208,ENERR_SPEC_UNDEF_NODE,"undefined Node") -DAT(209,ENERR_ILLEGAL_VAL_NODE,"illegal value for Node") -DAT(210,ENERR_SPEC_UNDEF_LINK,"specified for undefined Link") -DAT(211,ENERR_ILLEGAL_VAL_LINK,"illegal value for Link") -DAT(212,ENERR_TRACE_NODE,"invalid trace node") -DAT(213,ENERR_ILLEGAL_OPT,"illegal option value in section") -DAT(214,ENERR_TOO_MANY_CHAR,"following line of section contains too many characters") -DAT(215,ENERR_DUPLICATE_ID,"duplicate ID") -DAT(216,ENERR_UNDEF_PUMP,"data specified for undefined Pump") -DAT(217,ENERR_INVALID_DATA_PUMP,"invalid data for Pump") -DAT(219,ENERR_ILLEGAL_CON_TANK,"illegally connected to a tank") -DAT(220,ENERR_ILLEGAL_CON_VALVE,"illegally connected to another valve") -DAT(221,ENERR_RULE_CLAUSE, "mis-placed rule clause") - -DAT(222,ENERR_SAME_START_END,"same start and end nodes") - -DAT(223,ENERR_NOT_ENOUGH_NODES,"not enough nodes in network") -DAT(224,ENERR_NO_TANKS_RES,"no tanks or reservoirs in network") -DAT(225,ENERR_INVALID_LEVELS,"invalid lower/upper levels for Tank") -DAT(226,ENERR_NO_HEAD_CURVE,"no head curve supplied for Pump") -DAT(227,ENERR_INVALID_HEAD_CURVE,"invalid head curve for Pump") -DAT(230,ENERR_X_NONINCREASING,"Curve has nonincreasing x-values") -DAT(233,ENERR_NODE_UNCONNECTED,"Node is unconnected") -DAT(240,ENERR_UNDEF_SOURCE,"undefined source") -DAT(241,ENERR_UNDEF_CONTROL,"refers to undefined control") -DAT(250,ENERR_INVALID_FORMAT,"function call contains invalid format") -DAT(251,ENERR_INVALID_CODE,"function call contains invalid parameter code") - -DAT(253,ENERR_NO_DEMAND_CAT,"function applied to nonexistent demand category") -DAT(254,ENERR_NO_COORDS,"function applied to node with no coordinates") -DAT(255,ENERR_COORDS_NOT_LOADED,"function fails because no node coordinates were supplied") - -DAT(257,ENERR_NO_RULE,"function applied to nonexistent rule") -DAT(258,ENERR_NO_CONDITION_ACTION,"function applied to nonexistent rule clause") - -DAT(260,ENERR_DEL_TRACE_NODE,"cannot delete node assigned as a Trace Node") -DAT(261,ENERR_DEL_NODE_LINK, "cannot delete a node or link contained in a control") - -DAT(301,ENERR_FILES_ARE_SAME,"identical file names") -DAT(302,ENERR_CANT_OPEN_INP,"cannot open input file") -DAT(303,ENERR_CANT_OPEN_RPT,"cannot open report file") -DAT(304,ENERR_CANT_OPEN_BIN,"cannot open binary output file") -DAT(305,ENERR_CANT_OPEN_HYD,"cannot open hydraulics file") -DAT(306,ENERR_HYD_FILE_NOMATCH,"hydraulics file does not match network data") -DAT(307,ENERR_CANT_READ_HYD,"cannot read hydraulics file") -DAT(308,ENERR_CANT_SAVE_RES,"cannot save results to file") -DAT(309,ENERR_CANT_SAVE_RPT,"cannot save results to report file") - -DAT(411,ENERR_NO_MEM_ALLOC,"no memory allocated for results") -DAT(412,ENERR_NO_RESULTS_NO_FILE,"no results; binary file hasn't been opened") -DAT(435,ENERR_RUN_TERMINATED,"run terminated; no results in binary file") +// These errors apply to network consistency check +DAT(223,"not enough nodes in network") +DAT(224,"no tanks or reservoirs in network") +DAT(225,"invalid lower/upper levels for tank") +DAT(226,"no head curve or power rating for pump") +DAT(227,"invalid head curve for pump") +DAT(230,"nonincreasing x-values for curve") +DAT(233,"network has unconnected node") +// These errors apply only to API functions +DAT(240,"nonexistent source") +DAT(241,"nonexistent control") +DAT(250,"invalid format") +DAT(251,"invalid parameter code") +DAT(253,"nonexistent demand category") +DAT(254,"node with no coordinates") +DAT(257,"nonexistent rule") +DAT(258,"nonexistent rule clause") +DAT(260,"attempt to delete node assigned as a Trace Node") +DAT(261,"attempt to delete a node or link contained in a control") +// File errors +DAT(301,"identical file names") +DAT(302,"cannot open input file") +DAT(303,"cannot open report file") +DAT(304,"cannot open binary output file") +DAT(305,"cannot open hydraulics file") +DAT(306,"hydraulics file does not match network data") +DAT(307,"cannot read hydraulics file") +DAT(308,"cannot save results to file") +DAT(309,"cannot save results to report file") diff --git a/src/input1.c b/src/input1.c index 3f7879b..11cbce4 100644 --- a/src/input1.c +++ b/src/input1.c @@ -7,7 +7,7 @@ Description: retrieves network data from an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE -Last Updated: 11/10/2018 +Last Updated: 12/15/2018 ****************************************************************************** */ @@ -353,10 +353,11 @@ int inittanks(Project *pr) */ { Network *net = &pr->network; - + int i, j, n = 0; double a; int errcode = 0, levelerr; + char errmsg[MAXMSG+1] = ""; Stank *tank; Scurve *curve; @@ -383,14 +384,6 @@ int inittanks(Project *pr) levelerr = 1; } - // Report error in levels if found - if (levelerr) - { - sprintf(pr->Msg, "%s node: %s", geterrmsg(225, pr->Msg), - net->Node[tank->Node].ID); - writeline(pr, pr->Msg); - errcode = 200; - } else { // Find min., max., and initial volumes from curve @@ -403,6 +396,15 @@ int inittanks(Project *pr) tank->A = sqrt(4.0 * a / PI); } } + + // Report error in levels if found + if (levelerr) + { + sprintf(pr->Msg, "Error 225: %s node %s", geterrmsg(225, errmsg), + net->Node[tank->Node].ID); + writeline(pr, pr->Msg); + errcode = 200; + } } return errcode; } diff --git a/src/input2.c b/src/input2.c index 02470d8..180b35b 100644 --- a/src/input2.c +++ b/src/input2.c @@ -7,7 +7,7 @@ Description: reads and interprets network data from an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE -Last Updated: 11/10/2018 +Last Updated: 12/15/2018 ****************************************************************************** */ @@ -179,6 +179,7 @@ int readdata(Project *pr) parser->Comment); // Skip blank lines and comments + parser->ErrTok = -1; if (parser->Ntokens == 0) continue; if (*parser->Tok[0] == ';') continue; @@ -218,7 +219,7 @@ int readdata(Project *pr) inperr = newline(pr, sect, line); if (inperr > 0) { - inperrmsg(pr,inperr, sect, line); + inperrmsg(pr, inperr, sect, line); errsum++; } } @@ -326,7 +327,8 @@ int getpumpparams(Project *pr) */ { Network *net = &pr->network; - int i, k, errcode = 0; + int i, k, errcode = 0; + char errmsg[MAXMSG+1]; for (i = 1; i <= net->Npumps; i++) { @@ -334,8 +336,8 @@ int getpumpparams(Project *pr) if (errcode) { k = net->Pump[i].Link; - sprintf(pr->Msg, "%s link: %s", geterrmsg(errcode, pr->Msg), - net->Link[k].ID); + sprintf(pr->Msg, "Error %d: %s %s", + errcode, geterrmsg(errcode, errmsg), net->Link[k].ID); writeline(pr, pr->Msg); return 200; } @@ -596,8 +598,7 @@ int unlinked(Project *pr) if (marked[i] == 0) { err++; - sprintf(pr->Msg, "%s link: %s", geterrmsg(233, pr->Msg), - net->Node[i].ID); + sprintf(pr->Msg, "Error 233: %s %s", geterrmsg(233, pr->Msg), net->Node[i].ID); writeline(pr, pr->Msg); } if (err >= MAXERRS) break; @@ -685,6 +686,7 @@ int getcurves(Project *pr) int i, j; double x; + char errmsg[MAXMSG+1]; SFloatlist *fx, *fy; STmplist *tmpcurve; Scurve *curve; @@ -705,10 +707,9 @@ int getcurves(Project *pr) // Check that network curve has data points if (curve->Npts <= 0) { - sprintf(pr->Msg, "%s link: %s", geterrmsg(230, pr->Msg), - curve->ID); + sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg), curve->ID); writeline(pr, pr->Msg); - return (200); + return 200; } // Allocate memory for network's curve data @@ -726,10 +727,9 @@ int getcurves(Project *pr) // Check that x data is in ascending order if (fx->value >= x) { - sprintf(pr->Msg, "%s link: %s", geterrmsg(230, pr->Msg), - curve->ID); + sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg), curve->ID); writeline(pr, pr->Msg); - return (200); + return 200; } x = fx->value; @@ -967,33 +967,18 @@ void inperrmsg(Project *pr, int err, int sect, char *line) { Parser *parser = &pr->parser; - char errStr[MAXMSG + 1]; - char id[MAXMSG + 1]; + char errStr[MAXMSG + 1] = ""; + char tok[MAXMSG + 1]; + + // Get token associated with input error + if (parser->ErrTok >= 0) strcpy(tok, parser->Tok[parser->ErrTok]); + else strcpy(tok, ""); - // get text for error message - sprintf(pr->Msg, "%s - section: %s", geterrmsg(err, errStr), SectTxt[sect]); - - // Retrieve ID label of object with input error - // (No ID used for CONTROLS or REPORT sections) - switch (sect) - { - case _CONTROLS: - case _REPORT: - // don't append - break; - case _ENERGY: - sprintf(id, " id: %s", parser->Tok[1]); - break; - default: - sprintf(id, " id: %s", parser->Tok[0]); - break; - } - - strcat(pr->Msg, id); + // write error message to report file + sprintf(pr->Msg, "Error %d: %s %s in %s section:", + err, geterrmsg(err, errStr), tok, SectTxt[sect]); writeline(pr, pr->Msg); - // Echo input line for syntax errors, and - // errors in CONTROLS and OPTIONS sections - if (sect == _CONTROLS || err == 201 || err == 213) writeline(pr, line); - else writeline(pr, ""); + // Echo input line + writeline(pr, line); } diff --git a/src/input3.c b/src/input3.c index 9e4de54..3e43494 100644 --- a/src/input3.c +++ b/src/input3.c @@ -7,7 +7,7 @@ Description: parses network data from a line of an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE -Last Updated: 11/10/2018 +Last Updated: 12/15/2018 ****************************************************************************** */ @@ -43,7 +43,23 @@ static int optionchoice(Project *, int); static int optionvalue(Project *, int); static int getpumpcurve(Project *, int); static void changestatus(Network *, int, StatusType, double); +static int setError(Parser *, int, int); + +int setError(Parser *parser, int tokindex, int errcode) +/* +**-------------------------------------------------------------- +** Input: tokindex = index of input line token +** errcode = an error code +** Output: returns error code +** Purpose: records index of token from line of input associated +** with an error +**-------------------------------------------------------------- +*/ +{ + parser->ErrTok = tokindex; + return errcode; +} int juncdata(Project *pr) /* @@ -76,16 +92,16 @@ int juncdata(Project *pr) net->Njuncs++; net->Nnodes++; njuncs = net->Njuncs; - if (!addnodeID(net, net->Njuncs, parser->Tok[0])) return 215; + if (!addnodeID(net, net->Njuncs, parser->Tok[0])) return setError(parser, 0, 215); // Check for valid data if (n < 2) return 201; - if (!getfloat(parser->Tok[1], &el)) return 202; - if (n >= 3 && !getfloat(parser->Tok[2], &y)) return 202; + if (!getfloat(parser->Tok[1], &el)) return setError(parser, 1, 202); + if (n >= 3 && !getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202); if (n >= 4) { patlist = getlistitem(parser->Tok[3], parser->Patlist); - if (patlist == NULL) return 205; + if (patlist == NULL) return setError(parser, 3, 205); p = patlist->i; } @@ -155,11 +171,11 @@ int tankdata(Project *pr) net->Nnodes++; i = parser->MaxJuncs + net->Ntanks; - if (!addnodeID(net, i, parser->Tok[0])) return 215; + if (!addnodeID(net, i, parser->Tok[0])) return setError(parser, 0, 215); // Check for valid data - if (n < 2) return (201); - if (!getfloat(parser->Tok[1], &el)) return 202; + if (n < 2) return 201; + if (!getfloat(parser->Tok[1], &el)) return setError(parser, 1, 202); // Tank is reservoir if (n <= 3) @@ -168,7 +184,7 @@ int tankdata(Project *pr) if (n == 3) { tmplist = getlistitem(parser->Tok[2], parser->Patlist); - if (tmplist == NULL) return 205; + if (tmplist == NULL) return setError(parser, 2, 205); pattern = tmplist->i; } } @@ -177,21 +193,25 @@ int tankdata(Project *pr) // Tank is a storage tank else { - if (!getfloat(parser->Tok[2], &initlevel)) return 202; - if (!getfloat(parser->Tok[3], &minlevel)) return 202; - if (!getfloat(parser->Tok[4], &maxlevel)) return 202; - if (!getfloat(parser->Tok[5], &diam)) return 202; - if (diam < 0.0) return 202; - if (n >= 7 && !getfloat(parser->Tok[6], &minvol)) return 202; + if (!getfloat(parser->Tok[2], &initlevel)) return setError(parser, 2, 202); + if (!getfloat(parser->Tok[3], &minlevel)) return setError(parser, 3, 202); + if (!getfloat(parser->Tok[4], &maxlevel)) return setError(parser, 4, 202); + if (!getfloat(parser->Tok[5], &diam)) return setError(parser, 5, 202); + if (n >= 7 && !getfloat(parser->Tok[6], &minvol)) return setError(parser, 6, 202); // If volume curve supplied check it exists if (n == 8) { tmplist = getlistitem(parser->Tok[7], parser->Curvelist); - if (tmplist == NULL) return 202; + if (tmplist == NULL) return setError(parser, 7, 206); curve = tmplist->i; net->Curve[curve].Type = V_CURVE; } + if (initlevel < 0.0) return setError(parser, 2, 209); + if (minlevel < 0.0) return setError(parser, 3, 209); + if (maxlevel < 0.0) return setError(parser, 4, 209); + if (diam < 0.0) return setError(parser, 5, 209); + if (minvol < 0.0) return setError(parser, 6, 209); } node = &net->Node[i]; tank = &net->Tank[net->Ntanks]; @@ -261,18 +281,20 @@ int pipedata(Project *pr) if (net->Nlinks == parser->MaxLinks) return 200; net->Npipes++; net->Nlinks++; - if (!addlinkID(net, net->Nlinks, parser->Tok[0])) return 215; + if (!addlinkID(net, net->Nlinks, parser->Tok[0])) return setError(parser, 0, 215); // Check for valid data if (n < 6) return 201; - if ((j1 = findnode(net, parser->Tok[1])) == 0 || - (j2 = findnode(net, parser->Tok[2])) == 0) return 203; - if (j1 == j2) return 222; + if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203); + if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203); + if (j1 == j2) return setError(parser, 0, 222); - if (!getfloat(parser->Tok[3], &length) || - !getfloat(parser->Tok[4], &diam) || - !getfloat(parser->Tok[5], &rcoeff)) return 202; - if (length <= 0.0 || diam <= 0.0 || rcoeff <= 0.0) return 202; + if (!getfloat(parser->Tok[3], &length)) return setError(parser, 3, 202); + if (length <= 0.0) return setError(parser, 3, 211); + if (!getfloat(parser->Tok[4], &diam)) return setError(parser, 4, 202); + if (diam <= 0.0) return setError(parser, 4, 211); + if (!getfloat(parser->Tok[5], &rcoeff)) return setError(parser, 5, 202); + if (rcoeff <= 0.0) setError(parser, 5, 211); // Either a loss coeff. or a status is supplied if (n == 7) @@ -280,19 +302,19 @@ int pipedata(Project *pr) if (match(parser->Tok[6], w_CV)) type = CVPIPE; else if (match(parser->Tok[6], w_CLOSED)) status = CLOSED; else if (match(parser->Tok[6], w_OPEN)) status = OPEN; - else if (!getfloat(parser->Tok[6], &lcoeff)) return (202); + else if (!getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202); } // Both a loss coeff. and a status is supplied if (n == 8) { - if (!getfloat(parser->Tok[6], &lcoeff)) return 202; + if (!getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202); if (match(parser->Tok[7], w_CV)) type = CVPIPE; else if (match(parser->Tok[7], w_CLOSED)) status = CLOSED; else if (match(parser->Tok[7], w_OPEN)) status = OPEN; - else return 202; + else return setError(parser, 7, 213); } - if (lcoeff < 0.0) return 202; + if (lcoeff < 0.0) return setError(parser, 6, 211); // Save pipe data link = &net->Link[net->Nlinks]; @@ -347,13 +369,13 @@ int pumpdata(Project *pr) net->Npumps == parser->MaxPumps) return 200; net->Nlinks++; net->Npumps++; - if (!addlinkID(net, net->Nlinks, parser->Tok[0])) return 215; + if (!addlinkID(net, net->Nlinks, parser->Tok[0])) return setError(parser, 0, 215); // Check for valid data - if (n < 4) return 201; - if ((j1 = findnode(net, parser->Tok[1])) == 0 || - (j2 = findnode(net, parser->Tok[2])) == 0) return 203; - if (j1 == j2) return 222; + if (n < 3) return 201; + if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203); + if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203); + if (j1 == j2) return setError(parser, 0, 222); // Save pump data link = &net->Link[net->Nlinks]; @@ -378,6 +400,7 @@ int pumpdata(Project *pr) pump->Upat = 0; pump->Ecost = 0.0; pump->Epat = 0; + if (n < 4) return 0; // If 4-th token is a number then input follows Version 1.x format // so retrieve pump curve parameters @@ -386,10 +409,10 @@ int pumpdata(Project *pr) m = 1; for (j = 4; j < n; j++) { - if (!getfloat(parser->Tok[j], &parser->X[m])) return 202; + if (!getfloat(parser->Tok[j], &parser->X[m])) return setError(parser, j, 202); m++; } - return (getpumpcurve(pr,m)); + return (getpumpcurve(pr, m)); } // Otherwise input follows Version 2 format @@ -400,26 +423,26 @@ int pumpdata(Project *pr) if (match(parser->Tok[m - 1], w_POWER)) // Const. HP curve { y = atof(parser->Tok[m]); - if (y <= 0.0) return (202); + if (y <= 0.0) return setError(parser, m, 202); pump->Ptype = CONST_HP; link->Km = y; } else if (match(parser->Tok[m - 1], w_HEAD)) // Custom pump curve { tmplist = getlistitem(parser->Tok[m], parser->Curvelist); - if (tmplist == NULL) return 206; + if (tmplist == NULL) return setError(parser, m, 206); pump->Hcurve = tmplist->i; } else if (match(parser->Tok[m - 1], w_PATTERN)) // Speed/status pattern { tmplist = getlistitem(parser->Tok[m], parser->Patlist); - if (tmplist == NULL) return 205; + if (tmplist == NULL) return setError(parser, m, 205); pump->Upat = tmplist->i; } else if (match(parser->Tok[m - 1], w_SPEED)) // Speed setting { - if (!getfloat(parser->Tok[m], &y)) return 202; - if (y < 0.0) return 202; + if (!getfloat(parser->Tok[m], &y)) return setError(parser, m, 202); + if (y < 0.0) return setError(parser, m, 211); link->Kc = y; } else return 201; @@ -460,13 +483,13 @@ int valvedata(Project *pr) net->Nvalves == parser->MaxValves) return 200; net->Nvalves++; net->Nlinks++; - if (!addlinkID(net, net->Nlinks, parser->Tok[0])) return 215; + if (!addlinkID(net, net->Nlinks, parser->Tok[0])) return setError(parser, 0, 215); // Check for valid data if (n < 6) return 201; - if ((j1 = findnode(net, parser->Tok[1])) == 0 || - (j2 = findnode(net, parser->Tok[2])) == 0) return (203); - if (j1 == j2) return 222; + if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203); + if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203); + if (j1 == j2) return setError(parser, 0, 222); if (match(parser->Tok[4], w_PRV)) type = PRV; else if (match(parser->Tok[4], w_PSV)) type = PSV; @@ -474,28 +497,31 @@ int valvedata(Project *pr) else if (match(parser->Tok[4], w_FCV)) type = FCV; else if (match(parser->Tok[4], w_TCV)) type = TCV; else if (match(parser->Tok[4], w_GPV)) type = GPV; - else return 201; + else return setError(parser, 4, 213); - if (!getfloat(parser->Tok[3], &diam)) return 202; - if (diam <= 0.0) return 202; + if (!getfloat(parser->Tok[3], &diam)) return setError(parser, 3, 202); 202; + if (diam <= 0.0) return setError(parser, 3, 211); // Find headloss curve for GPV if (type == GPV) { tmplist = getlistitem(parser->Tok[5], parser->Curvelist); - if (tmplist == NULL) return 206; + if (tmplist == NULL) return setError(parser, 5, 206); setting = tmplist->i; net->Curve[tmplist->i].Type = H_CURVE; status = OPEN; } - else if (!getfloat(parser->Tok[5], &setting)) return 202; - if (n >= 7 && !getfloat(parser->Tok[6], &lcoeff)) return 202; + else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202); + if (n >= 7 && !getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202); // Check that PRV, PSV, or FCV not connected to a tank & // check for illegal connections between pairs of valves - if ((j1 > net->Njuncs || j2 > net->Njuncs) && - (type == PRV || type == PSV || type == FCV)) return 219; - if (!valvecheck(pr, type, j1, j2)) return 220; + if (type == PRV || type == PSV || type == FCV) + { + if (j1 > net->Njuncs) return setError(parser, 1, 219); + if (j2 > net->Njuncs) return setError(parser, 2, 219); + } + if (!valvecheck(pr, type, j1, j2)) return setError(parser, -1, 220); // Save valve data link = &net->Link[net->Nlinks]; @@ -542,12 +568,12 @@ int patterndata(Project *pr) if (parser->PrevPat != NULL && strcmp(parser->Tok[0], parser->PrevPat->ID) == 0) p = parser->PrevPat; else p = getlistitem(parser->Tok[0], parser->Patlist); - if (p == NULL) return 205; + if (p == NULL) return setError(parser, 0, 205); // Add parsed multipliers to the pattern for (i = 1; i <= n; i++) { - if (!getfloat(parser->Tok[i], &x)) return 202; + if (!getfloat(parser->Tok[i], &x)) return setError(parser, i, 202); f = (SFloatlist *)malloc(sizeof(SFloatlist)); if (f == NULL) return 101; f->value = x; @@ -587,11 +613,11 @@ int curvedata(Project *pr) if (parser->PrevCurve != NULL && strcmp(parser->Tok[0], parser->PrevCurve->ID) == 0) c = parser->PrevCurve; else c = getlistitem(parser->Tok[0], parser->Curvelist); - if (c == NULL) return 205; + if (c == NULL) return setError(parser, 0, 206); // Check for valid data - if (!getfloat(parser->Tok[1], &x)) return 202; - if (!getfloat(parser->Tok[2], &y)) return 202; + if (!getfloat(parser->Tok[1], &x)) return setError(parser, 1, 202); + if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202); // Add new data point to curve fx = (SFloatlist *)malloc(sizeof(SFloatlist)); @@ -636,11 +662,11 @@ int coordata(Project *pr) // Check for valid node ID if (parser->Ntokens < 3) return 201; - if ((j = findnode(net, parser->Tok[0])) == 0) return 203; + if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203); // Check for valid data - if (!getfloat(parser->Tok[1], &x)) return 202; - if (!getfloat(parser->Tok[2], &y)) return 202; + if (!getfloat(parser->Tok[1], &x)) return setError(parser, 1, 202); + if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202); // Save coord data node = &net->Node[j]; @@ -678,23 +704,23 @@ int demanddata(Project *pr) // Extract data from tokens n = parser->Ntokens; if (n < 2) return 201; - if (!getfloat(parser->Tok[1], &y)) return 202; + if (!getfloat(parser->Tok[1], &y)) return setError(parser, 1, 202); // If MULTIPLY command, save multiplier if (match(parser->Tok[0], w_MULTIPLY)) { - if (y <= 0.0) return 202; + if (y <= 0.0) return setError(parser, 1, 213); else hyd->Dmult = y; return 0; } // Otherwise find node (and pattern) being referenced - if ((j = findnode(net, parser->Tok[0])) == 0) return 208; - if (j > net->Njuncs) return 208; + if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203); + if (j > net->Njuncs) return 0; if (n >= 3) { patlist = getlistitem(parser->Tok[2], parser->Patlist); - if (patlist == NULL) return 205; + if (patlist == NULL) return setError(parser, 2, 205); p = patlist->i; } @@ -761,11 +787,11 @@ int controldata(Project *pr) // Check that controlled link exists k = findlink(net, parser->Tok[1]); - if (k == 0) return 204; + if (k == 0) return setError(parser, 1, 204); // Cannot control a check valve linktype = net->Link[k].Type; - if (linktype == CVPIPE) return 207; + if (linktype == CVPIPE) return setError(parser, 1, 207); // Parse control setting into a status level or numerical setting if (match(parser->Tok[2], w_OPEN)) @@ -780,8 +806,8 @@ int controldata(Project *pr) if (linktype == PUMP) setting = 0.0; if (linktype == GPV) setting = net->Link[k].Kc; } - else if (linktype == GPV) return 206; - else if (!getfloat(parser->Tok[2], &setting)) return 202; + else if (linktype == GPV) return setError(parser, 1, 207); + else if (!getfloat(parser->Tok[2], &setting)) return setError(parser, 2, 202); // Set status for pump in case speed setting was supplied // or for pipe if numerical setting was supplied @@ -789,7 +815,7 @@ int controldata(Project *pr) { if (setting != MISSING) { - if (setting < 0.0) return 202; + if (setting < 0.0) return setError(parser, 2, 211); else if (setting == 0.0) status = CLOSED; else status = OPEN; } @@ -801,10 +827,10 @@ int controldata(Project *pr) else { if (n < 8) return 201; - if ((i = findnode(net, parser->Tok[5])) == 0) return 203; + if ((i = findnode(net, parser->Tok[5])) == 0) return setError(parser, 5, 203); if (match(parser->Tok[6], w_BELOW)) ctltype = LOWLEVEL; else if (match(parser->Tok[6], w_ABOVE)) ctltype = HILEVEL; - else return 201; + else return setError(parser, 6, 213); } // Parse control level or time @@ -814,11 +840,11 @@ int controldata(Project *pr) case TIMEOFDAY: if (n == 6) time = hour(parser->Tok[5], ""); if (n == 7) time = hour(parser->Tok[5], parser->Tok[6]); - if (time < 0.0) return 201; + if (time < 0.0) return setError(parser, 5, 213); break; case LOWLEVEL: case HILEVEL: - if (!getfloat(parser->Tok[7], &level)) return 202; + if (!getfloat(parser->Tok[7], &level)) return setError(parser, 7, 202); break; } @@ -866,7 +892,7 @@ int sourcedata(Project *pr) // Check for enough tokens & that source node exists n = parser->Ntokens; if (n < 2) return 201; - if ((j = findnode(net, parser->Tok[0])) == 0) return 203; + if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203); // Parse source type // NOTE: Under old 1.1 format, SourceType not supplied so @@ -879,14 +905,18 @@ int sourcedata(Project *pr) else i = 1; // Parse source quality - if (!getfloat(parser->Tok[i], &c0)) return 202; + if (!getfloat(parser->Tok[i], &c0)) + { + if (i == 1) return setError(parser, i, 213); + else return setError(parser, i, 202); + } // Parse optional source time pattern if (n > i + 1 && strlen(parser->Tok[i + 1]) > 0 && strcmp(parser->Tok[i + 1], "*") != 0) { patlist = getlistitem(parser->Tok[i + 1], parser->Patlist); - if (patlist == NULL) return (205); + if (patlist == NULL) return setError(parser, i+1, 205); p = patlist->i; } @@ -925,12 +955,12 @@ int emitterdata(Project *pr) // Check that node exists & is a junction n = parser->Ntokens; if (n < 2) return 201; - if ((j = findnode(net, parser->Tok[0])) == 0) return 203; - if (j > net->Njuncs) return 209; + if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203); + if (j > net->Njuncs) return 0; // Parse emitter flow coeff. - if (!getfloat(parser->Tok[1], &k)) return 202; - if (k < 0.0) return 202; + if (!getfloat(parser->Tok[1], &k)) return setError(parser, 1, 202); + if (k < 0.0) return setError(parser, 1, 209); net->Node[j].Ke = k; return 0; } @@ -956,15 +986,16 @@ int qualdata(Project *pr) double c0; Snode *Node = net->Node; - if (net->Nnodes == 0) return 208; // No nodes defined yet + if (net->Nnodes == 0) return setError(parser, 0, 203); // No nodes defined yet n = parser->Ntokens; if (n < 2) return 0; // Single node name supplied if (n == 2) { - if ((j = findnode(net,parser->Tok[0])) == 0) return 0; - if (!getfloat(parser->Tok[1], &c0)) return 209; + if ((j = findnode(net,parser->Tok[0])) == 0) return setError(parser, 0, 203); + if (!getfloat(parser->Tok[1], &c0)) return setError(parser, 1, 202); + if (c0 < 0.0) return setError(parser, 1, 209); Node[j].C0 = c0; } @@ -972,7 +1003,8 @@ int qualdata(Project *pr) else { // Parse quality value - if (!getfloat(parser->Tok[2], &c0)) return 209; + if (!getfloat(parser->Tok[2], &c0)) return setError(parser, 2, 202); + if (c0 < 0.0) return setError(parser, 2, 209); // If numerical node names supplied, then use numerical comparison // to find which nodes are assigned the quality value @@ -1034,23 +1066,23 @@ int reactdata(Project *pr) // Keyword is ORDER if (match(parser->Tok[0], w_ORDER)) { - if (!getfloat(parser->Tok[n - 1], &y)) return 213; + if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202); if (match(parser->Tok[1], w_BULK)) qual->BulkOrder = y; else if (match(parser->Tok[1], w_TANK)) qual->TankOrder = y; else if (match(parser->Tok[1], w_WALL)) { if (y == 0.0) qual->WallOrder = 0.0; else if (y == 1.0) qual->WallOrder = 1.0; - else return 213; + else return setError(parser, n-1, 213); } - else return 213; + else return setError(parser, 1, 213); return 0; } // Keyword is ROUGHNESS if (match(parser->Tok[0], w_ROUGHNESS)) { - if (!getfloat(parser->Tok[n - 1], &y)) return 213; + if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202); qual->Rfactor = y; return 0; } @@ -1058,7 +1090,7 @@ int reactdata(Project *pr) // Keyword is LIMITING if (match(parser->Tok[0], w_LIMITING)) { - if (!getfloat(parser->Tok[n - 1], &y)) return 213; + if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202); qual->Climit = y; return 0; } @@ -1066,10 +1098,10 @@ int reactdata(Project *pr) // Keyword is GLOBAL if (match(parser->Tok[0], w_GLOBAL)) { - if (!getfloat(parser->Tok[n - 1], &y)) return 213; + if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202); if (match(parser->Tok[1], w_BULK)) qual->Kbulk = y; else if (match(parser->Tok[1], w_WALL)) qual->Kwall = y; - else return 201; + else return setError(parser, 1, 213); return 0; } @@ -1077,7 +1109,7 @@ int reactdata(Project *pr) if (match(parser->Tok[0], w_BULK)) item = 1; else if (match(parser->Tok[0], w_WALL)) item = 2; else if (match(parser->Tok[0], w_TANK)) item = 3; - else return 201; + else return setError(parser, 0, 213); // Save the first link/node ID in the first token strcpy(parser->Tok[0], parser->Tok[1]); @@ -1086,7 +1118,7 @@ int reactdata(Project *pr) if (item == 3) { // Get the rate coeff. value - if (!getfloat(parser->Tok[n - 1], &y)) return 209; + if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202); // Case where just a single tank is specified if (n == 3) @@ -1119,7 +1151,7 @@ int reactdata(Project *pr) else { // Get the rate coeff. value - if (!getfloat(parser->Tok[n - 1], &y)) return 211; /* Rate coeff. */ + if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202); if (net->Nlinks == 0) return 0; // Case where just a single link is specified @@ -1181,15 +1213,18 @@ int mixingdata(Project *pr) double v; // Mixing zone volume fraction // Check for valid data - if (net->Nnodes == 0) return 208; + if (net->Nnodes == 0) return setError(parser, 0, 203); n = parser->Ntokens; if (n < 2) return 0; - if ((j = findnode(net, parser->Tok[0])) <= net->Njuncs) return 0; - if ((m = findmatch(parser->Tok[1], MixTxt)) < 0) return 201; + j = findnode(net, parser->Tok[0]); + if (j == 0) return setError(parser, 0, 203); + if (j <= net->Njuncs) return 0; + if ((m = findmatch(parser->Tok[1], MixTxt)) < 0) return setError(parser, 1, 213); // Find mixing zone volume fraction (which can't be 0) v = 1.0; - if ((m == MIX2) && (n == 3) && (!getfloat(parser->Tok[2], &v))) return 209; + if ((m == MIX2) && (n == 3) && + (!getfloat(parser->Tok[2], &v))) return setError(parser, 2, 202); if (v == 0.0) v = 1.0; // Assign mixing data to tank (return if tank is a reservoir) @@ -1221,26 +1256,29 @@ int statusdata(Project *pr) double y = 0.0; char status = ACTIVE; - if (net->Nlinks == 0) return 210; + if (net->Nlinks == 0) return setError(parser, 0, 204); n = parser->Ntokens - 1; if (n < 1) return 201; // Check for legal status setting if (match(parser->Tok[n], w_OPEN)) status = OPEN; else if (match(parser->Tok[n], w_CLOSED)) status = CLOSED; - else if (!getfloat(parser->Tok[n], &y)) return 211; - if (y < 0.0) return 211; + else + { + if (!getfloat(parser->Tok[n], &y)) return setError(parser, n, 202); + if (y < 0.0) return setError(parser, n, 211); + } // A single link ID was supplied if (n == 1) { - if ((j = findlink(net, parser->Tok[0])) == 0) return 0; + if ((j = findlink(net, parser->Tok[0])) == 0) return setError(parser, 0, 204); // Cannot change status of a Check Valve - if (net->Link[j].Type == CVPIPE) return 211; + if (net->Link[j].Type == CVPIPE) return setError(parser, 0, 207); // Cannot change setting for a GPV - if (net->Link[j].Type == GPV && status == ACTIVE) return 211; + if (net->Link[j].Type == GPV && status == ACTIVE) return setError(parser, 0, 207); changestatus(net, j, status, y); } @@ -1297,7 +1335,8 @@ int energydata(Project *pr) // First keyword is DEMAND if (match(parser->Tok[0], w_DMNDCHARGE)) { - if (!getfloat(parser->Tok[2], &y)) return 213; + if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202); + if (y < 0.0) return setError(parser, 2, 213); hyd->Dcost = y; return 0; } @@ -1313,20 +1352,17 @@ int energydata(Project *pr) { if (n < 4) return 201; k = findlink(net,parser->Tok[1]); - if (k == 0) return 216; - if (Link[k].Type != PUMP) return 216; + if (k == 0) return setError(parser, 1, 216); + if (Link[k].Type != PUMP) return setError(parser, 1, 216); j = findpump(net, k); } - else return 201; + else return setError(parser, 0, 213); // PRICE parameter being set if (match(parser->Tok[n - 2], w_PRICE)) { - if (!getfloat(parser->Tok[n - 1], &y)) - { - if (j == 0) return 213; - else return 217; - } + if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n-1, 202); + if (y < 0.0) return setError(parser, n-1, 217); if (j == 0) hyd->Ecost = y; else Pump[j].Ecost = y; return 0; @@ -1336,11 +1372,7 @@ int energydata(Project *pr) else if (match(parser->Tok[n - 2], w_PATTERN)) { listitem = getlistitem(parser->Tok[n - 1], parser->Patlist); - if (listitem == NULL) - { - if (j == 0) return 213; - else return 217; - } + if (listitem == NULL) return setError(parser, n - 1, 205); if (j == 0) hyd->Epat = listitem->i; else Pump[j].Epat = listitem->i; return 0; @@ -1351,14 +1383,14 @@ int energydata(Project *pr) { if (j == 0) { - if (!getfloat(parser->Tok[n - 1], &y)) return 213; - if (y <= 0.0) return 213; + if (!getfloat(parser->Tok[n - 1], &y)) return setError(parser, n - 1, 202); + if (y <= 0.0) return setError(parser, n - 1, 217); hyd->Epump = y; } else { listitem = getlistitem(parser->Tok[n - 1], parser->Curvelist); - if (listitem == NULL) return 217; + if (listitem == NULL) return setError(parser, n - 1, 206); Pump[j].Ecurve = listitem->i; net->Curve[listitem->i].Type = E_CURVE; } @@ -1402,8 +1434,8 @@ int reportdata(Project *pr) // Value for page size if (match(parser->Tok[0], w_PAGE)) { - if (!getfloat(parser->Tok[n], &y)) return 213; - if (y < 0.0 || y > 255.0) return 213; + if (!getfloat(parser->Tok[n], &y)) return setError(parser, n, 202); + if (y < 0.0 || y > 255.0) return setError(parser, n, 213); rpt->PageSize = (int)y; return 0; } @@ -1448,10 +1480,10 @@ int reportdata(Project *pr) else if (match(parser->Tok[n], w_ALL)) rpt->Nodeflag = 1; // All nodes else { - if (net->Nnodes == 0) return 208; + if (net->Nnodes == 0) return setError(parser, 1, 208); for (i = 1; i <= n; i++) { - if ((j = findnode(net, parser->Tok[i])) == 0) return 208; + if ((j = findnode(net, parser->Tok[i])) == 0) return setError(parser, i, 208); net->Node[j].Rpt = 1; } rpt->Nodeflag = 2; @@ -1466,10 +1498,10 @@ int reportdata(Project *pr) else if (match(parser->Tok[n], w_ALL)) rpt->Linkflag = 1; else { - if (net->Nlinks == 0) return 210; + if (net->Nlinks == 0) return setError(parser, 1, 210); for (i = 1; i <= n; i++) { - if ((j = findlink(net, parser->Tok[i])) == 0) return 210; + if ((j = findlink(net, parser->Tok[i])) == 0) return setError(parser, i, 210); net->Link[j].Rpt = 1; } rpt->Linkflag = 2; @@ -1483,7 +1515,7 @@ int reportdata(Project *pr) else i = findmatch(parser->Tok[0], Fldname); if (i >= 0) { - if (i > FRICTION) return 201; + if (i > FRICTION) return setError(parser, 0, 213); if (parser->Ntokens == 1 || match(parser->Tok[1], w_YES)) { rpt->Field[i].Enabled = TRUE; @@ -1497,14 +1529,14 @@ int reportdata(Project *pr) } // Get field qualifier type - if (parser->Ntokens < 3) return (201); + if (parser->Ntokens < 3) return 201; if (match(parser->Tok[1], w_BELOW)) j = LOW; else if (match(parser->Tok[1], w_ABOVE)) j = HI; else if (match(parser->Tok[1], w_PRECISION)) j = PREC; - else return 201; + else return setError(parser, 1, 213); // Get field qualifier value - if (!getfloat(parser->Tok[2], &y)) return 201; + if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202); if (j == PREC) { rpt->Field[i].Enabled = TRUE; @@ -1566,7 +1598,7 @@ int timedata(Project *pr) else if (match(parser->Tok[n], w_MIN)) rpt->Tstatflag = MIN; else if (match(parser->Tok[n], w_MAX)) rpt->Tstatflag = MAX; else if (match(parser->Tok[n], w_RANGE)) rpt->Tstatflag = RANGE; - else return 201; + else return setError(parser, n, 213); return 0; } @@ -1581,7 +1613,10 @@ int timedata(Project *pr) { if ((y = hour(parser->Tok[n], "")) < 0.0) { - if ((y = hour(parser->Tok[n - 1], parser->Tok[n])) < 0.0) return 213; + if ((y = hour(parser->Tok[n - 1], parser->Tok[n])) < 0.0) + { + return setError(parser, n-1, 213); + } } } t = (long)(3600.0 * y + 0.5); @@ -1596,16 +1631,16 @@ int timedata(Project *pr) { if (match(parser->Tok[1], w_TIME)) time->Pstep = t; else if (match(parser->Tok[1], w_START)) time->Pstart = t; - else return 201; + else return setError(parser, 1, 213); } else if (match(parser->Tok[0], w_REPORT)) { if (match(parser->Tok[1], w_TIME)) time->Rstep = t; else if (match(parser->Tok[1], w_START)) time->Rstart = t; - else return 201; + else return setError(parser, 1, 213); } else if (match(parser->Tok[0], w_START)) time->Tstart = t % SECperDAY; - else return 201; + else return setError(parser, 0, 213); return 0; } @@ -1633,7 +1668,7 @@ int optiondata(Project *pr) int optionchoice(Project *pr, int n) /* **-------------------------------------------------------------- -** Input: n = index of last input token saved in par->Tok[] +** Input: n = index of last input token ** Output: returns error code or 0 if option belongs to ** those listed below, or -1 otherwise ** Purpose: processes fixed choice [OPTIONS] data @@ -1678,7 +1713,7 @@ int optionchoice(Project *pr, int n) else if (match(parser->Tok[1], w_CMD)) parser->Flowflag = CMD; else if (match(parser->Tok[1], w_MLD)) parser->Flowflag = MLD; else if (match(parser->Tok[1], w_SI)) parser->Flowflag = LPS; - else return 201; + else return setError(parser, 1, 213); } // PRESSURE units @@ -1689,7 +1724,7 @@ int optionchoice(Project *pr, int n) else if (match(parser->Tok[1], w_PSI)) parser->Pressflag = PSI; else if (match(parser->Tok[1], w_KPA)) parser->Pressflag = KPA; else if (match(parser->Tok[1], w_METERS)) parser->Pressflag = METERS; - else return 201; + else return setError(parser, 1, 213); } // HEADLOSS formula @@ -1699,7 +1734,7 @@ int optionchoice(Project *pr, int n) else if (match(parser->Tok[1], w_HW)) hyd->Formflag = HW; else if (match(parser->Tok[1], w_DW)) hyd->Formflag = DW; else if (match(parser->Tok[1], w_CM)) hyd->Formflag = CM; - else return 201; + else return setError(parser, 1, 213); } // HYDRUALICS USE/SAVE file option @@ -1708,14 +1743,14 @@ int optionchoice(Project *pr, int n) if (n < 2) return 0; else if (match(parser->Tok[1], w_USE)) out->Hydflag = USE; else if (match(parser->Tok[1], w_SAVE)) out->Hydflag = SAVE; - else return 201; + else return setError(parser, 1, 213); strncpy(out->HydFname, parser->Tok[2], MAXFNAME); } // Water QUALITY option else if (match(parser->Tok[0], w_QUALITY)) { - if (n < 1) return (0); + if (n < 1) return 0; else if (match(parser->Tok[1], w_NONE)) qual->Qualflag = NONE; else if (match(parser->Tok[1], w_CHEM)) qual->Qualflag = CHEM; else if (match(parser->Tok[1], w_AGE)) qual->Qualflag = AGE; @@ -1730,10 +1765,10 @@ int optionchoice(Project *pr, int n) { // Copy Trace Node ID to parser->Tok[0] for error reporting strcpy(parser->Tok[0], ""); - if (n < 2) return 212; + if (n < 2) return 201; strcpy(parser->Tok[0], parser->Tok[2]); qual->TraceNode = findnode(net, parser->Tok[2]); - if (qual->TraceNode == 0) return 212; + if (qual->TraceNode == 0) return setError(parser, 2, 212); strncpy(qual->ChemName, u_PERCENT, MAXID); strncpy(qual->ChemUnits, parser->Tok[2], MAXID); } @@ -1766,7 +1801,7 @@ int optionchoice(Project *pr, int n) if (n >= 2) hyd->ExtraIter = atoi(parser->Tok[2]); else hyd->ExtraIter = 0; } - else return 201; + else return setError(parser, 1, 213); } // Default demand PATTERN @@ -1782,7 +1817,7 @@ int optionchoice(Project *pr, int n) if (n < 2) return 0; if (!match(parser->Tok[1], w_MODEL)) return -1; choice = findmatch(parser->Tok[2], DemandModelTxt); - if (choice < 0) return 201; + if (choice < 0) return setError(parser, 2, 213); hyd->DemandModel = choice; } @@ -1844,12 +1879,12 @@ int optionvalue(Project *pr, int n) if (n < nvalue) return 0; // Check for valid numerical input - if (!getfloat(parser->Tok[nvalue], &y)) return 213; + if (!getfloat(parser->Tok[nvalue], &y)) return setError(parser, nvalue, 202); // Quality tolerance option (which can be 0) if (match(tok0, w_TOLERANCE)) { - if (y < 0.0) return 213; + if (y < 0.0) return setError(parser, nvalue, 213); qual->Ctol = y; return 0; } @@ -1857,7 +1892,7 @@ int optionvalue(Project *pr, int n) // Diffusivity if (match(tok0, w_DIFFUSIVITY)) { - if (y < 0.0) return 213; + if (y < 0.0) return setError(parser, nvalue, 213); qual->Diffus = y; return 0; } @@ -1872,7 +1907,7 @@ int optionvalue(Project *pr, int n) // Flow change limit else if (match(tok0, w_FLOWCHANGE)) { - if (y < 0.0) return 213; + if (y < 0.0) return setError(parser, nvalue, 213); hyd->FlowChangeLimit = y; return 0; } @@ -1880,7 +1915,7 @@ int optionvalue(Project *pr, int n) // Head loss error limit else if (match(tok0, w_HEADERROR)) { - if (y < 0.0) return 213; + if (y < 0.0) return setError(parser, nvalue, 213); hyd->HeadErrorLimit = y; return 0; } @@ -1888,25 +1923,25 @@ int optionvalue(Project *pr, int n) // Pressure dependent demand parameters else if (match(tok0, w_MINIMUM)) { - if (y < 0.0) return 213; + if (y < 0.0) return setError(parser, nvalue, 213); hyd->Pmin = y; return 0; } else if (match(tok0, w_REQUIRED)) { - if (y < 0.0) return 213; + if (y < 0.0) return setError(parser, nvalue, 213); hyd->Preq = y; return 0; } else if (match(tok0, w_PRESSURE)) { - if (y < 0.0) return 213; + if (y < 0.0) return setError(parser, nvalue, 213); hyd->Pexp = y; return 0; } // All other options must be > 0 - if (y <= 0.0) return 213; + if (y <= 0.0) return setError(parser, nvalue, 213); // Assign value to all other options if (match(tok0, w_VISCOSITY)) hyd->Viscos = y; diff --git a/src/project.c b/src/project.c index 54bf669..afdfd43 100644 --- a/src/project.c +++ b/src/project.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 11/27/2018 + Last Updated: 12/15/2018 ****************************************************************************** */ @@ -791,11 +791,14 @@ 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: sprintf(msg, "Error %d: %s", code, string); break; + switch (errcode) + { + +//#define DAT(code,string) case code: sprintf(msg, "%s", string); break; +#define DAT(code,string) case code: strcpy(msg, string); break; #include "errors.dat" #undef DAT + default: strcpy(msg, ""); } @@ -810,13 +813,15 @@ void errmsg(Project *pr, int errcode) **---------------------------------------------------------------- */ { + char errmsg[MAXMSG + 1] = ""; if (errcode == 309) /* Report file write error - */ { /* Do not write msg to file. */ } - else if (pr->report.RptFile != NULL && pr->report.Messageflag) + else if (pr->report.RptFile != NULL && pr->report.Messageflag && errcode > 100) { - writeline(pr, geterrmsg(errcode, pr->Msg)); + sprintf(pr->Msg, "Error %d: %s", errcode, geterrmsg(errcode, errmsg)); + writeline(pr, pr->Msg); } } diff --git a/src/types.h b/src/types.h index f27fd4e..55355e9 100755 --- a/src/types.h +++ b/src/types.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 11/27/2018 + Last Updated: 12/15/2018 ****************************************************************************** */ @@ -565,7 +565,8 @@ typedef struct { MaxPats, // Pattern count " " " MaxCurves, // Curve count " " " Ntokens, // Number of tokens in line of input - Ntitle; // Number of title lines + Ntitle, // Number of title lines + ErrTok; // Index of error-producing token STmplist *Patlist, // Temporary time pattern list