Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 50.6% 383 / 0 / 757
Functions: 73.3% 33 / 0 / 45
Branches: 33.0% 233 / 0 / 707

OMCompiler/SimulationRuntime/c/simulation/simulation_input_xml.c
Line Branch Exec Source
1 /*
2 * This file belongs to the OpenModelica Run-Time System
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), c/o Linköpings
5 * universitet, Department of Computer and Information Science, SE-58183 Linköping, Sweden. All rights
6 * reserved.
7 *
8 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE
9 * AGPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. ANY
10 * USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S
11 * ACCEPTANCE OF THE BSD NEW LICENSE OR THE OSMC PUBLIC LICENSE OR THE AGPL
12 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
13 *
14 * The OpenModelica software and the OSMC (Open Source Modelica Consortium) Public License
15 * (OSMC-PL) are obtained from OSMC, either from the above address, from the URLs:
16 * http://www.openmodelica.org or https://github.com/OpenModelica/ or
17 * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica distribution. GNU
18 * AGPL version 3 is obtained from: https://www.gnu.org/licenses/licenses.html#GPL. The BSD NEW
19 * License is obtained from: http://www.opensource.org/licenses/BSD-3-Clause.
20 *
21 * This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY
23 * SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF
24 * OSMC-PL.
25 *
26 */
27
28 /*
29 * file simulation_input_xml.c
30 * this file reads the model input from Model_init.xml
31 * file using the Expat XML parser.
32 * basically a structure with maps is created (see omc_ModelInput)
33 * and populated during the XML parser. after, the values from it
34 * are used to populate the outputs of the read_input_xml function.
35 */
36
37
38 #include "arrayIndex.h"
39 #include "simulation_input_xml.h"
40 #include <errno.h>
41 #include "simulation_runtime.h"
42 #include "options.h"
43 #include "../util/omc_error.h"
44 #include "../util/omc_file.h"
45 #include "../util/omc_strdup.h"
46 #include "../util/modelica_string.h"
47 #include "solver/model_help.h"
48
49 #include <limits.h>
50 #include "../util/uthash.h"
51 #include <string.h>
52 #include <ctype.h>
53 #include <expat.h>
54 #include <inttypes.h>
55
56 typedef struct hash_string_string
57 {
58 const char *id;
59 const char *val;
60 UT_hash_handle hh;
61 } hash_string_string;
62
63 typedef hash_string_string omc_ModelDescription;
64 typedef hash_string_string omc_DefaultExperiment;
65 typedef hash_string_string omc_ModelVariable; // ScalarVariable or ArrayVariable
66
67 typedef struct hash_long_var
68 {
69 long id;
70 omc_ModelVariable *val;
71 UT_hash_handle hh;
72 } hash_long_var;
73
74 typedef hash_long_var omc_ModelVariables;
75
76 typedef struct hash_string_long
77 {
78 const char *id;
79 long val;
80 UT_hash_handle hh;
81 } hash_string_long;
82
83 101 static inline const char* findHashStringStringNull(hash_string_string *ht, const char *key)
84 {
85 hash_string_string *res;
86
25/26
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 101 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 8 times.
✓ Branch 11 taken 10 times.
✓ Branch 12 taken 6 times.
✓ Branch 13 taken 10 times.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 6 times.
✓ Branch 16 taken 90 times.
✓ Branch 17 taken 11 times.
✓ Branch 18 taken 83 times.
✓ Branch 19 taken 29 times.
✓ Branch 20 taken 7 times.
✓ Branch 21 taken 76 times.
✓ Branch 22 taken 22 times.
✓ Branch 23 taken 14 times.
✓ Branch 24 taken 112 times.
✓ Branch 25 taken 11 times.
269 HASH_FIND_STR( ht, key, res );
87
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 25 times.
101 return res ? res->val : NULL;
88 }
89
90 static inline const char* findHashStringStringEmpty(hash_string_string *ht, const char *key)
91 {
92 16 const char *res = findHashStringStringNull(ht,key);
93
15/38
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 time.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 time.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 time.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 time.
✓ Branch 17 taken 1 time.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 2 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 2 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 3 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 3 times.
✓ Branch 34 taken 3 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 3 times.
✗ Branch 37 not taken.
29 return res ? res : "";
94 }
95
96 68 static inline const char* findHashStringString(hash_string_string *ht, const char *key)
97 {
98 68 const char *res = findHashStringStringNull(ht,key);
99
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (0==res) {
100 hash_string_string *c, *tmp;
101 ✗ HASH_ITER(hh, ht, c, tmp) {
102 ✗ fprintf(stderr, "HashMap contained: %s->%s\n", c->id, c->val);
103 }
104 ✗ throwStreamPrint(NULL, "Failed to lookup %s in hashmap %p", key, (void*)ht);
105 }
106 68 return res;
107 }
108
109 129 static inline void addHashStringString(hash_string_string **ht, const char *key, const char *val)
110 {
111 129 hash_string_string *v = (hash_string_string*) calloc(1, sizeof(hash_string_string)); /* FIXME this isn't always freed correctly */
112 129 v->id=omc_strdup(key);
113 129 v->val=omc_strdup(val);
114
21/42
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✓ Branch 8 taken 100 times.
✓ Branch 9 taken 129 times.
✓ Branch 10 taken 20 times.
✓ Branch 11 taken 16 times.
✓ Branch 12 taken 21 times.
✓ Branch 13 taken 7 times.
✓ Branch 14 taken 3 times.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 15 times.
✓ Branch 17 taken 8 times.
✓ Branch 18 taken 5 times.
✓ Branch 19 taken 13 times.
✓ Branch 20 taken 7 times.
✓ Branch 21 taken 11 times.
✓ Branch 22 taken 42 times.
✓ Branch 23 taken 87 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 129 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
229 HASH_ADD_KEYPTR( hh, *ht, v->id, strlen(v->id), v );
115 129 }
116
117 static inline long findHashStringLongOrZero(hash_string_long *ht, const char *key)
118 {
119 hash_string_long *res;
120 HASH_FIND_STR( ht, key, res );
121 return res ? res->val : 0;
122 }
123
124 ✗ static inline long* findHashStringLongPtr(hash_string_long *ht, const char *key)
125 {
126 hash_string_long *res;
127 ✗ HASH_FIND_STR( ht, key, res );
128 ✗ return res ? &res->val : 0;
129 }
130
131 3 static inline void addHashStringLong(hash_string_long **ht, const char *key, long val)
132 {
133 hash_string_long *v2;
134
7/26
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 time.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 2 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 2 times.
5 HASH_FIND_STR( *ht, key, v2 );
135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (v2) {
136 ✗ v2->val = val;
137 } else {
138 3 hash_string_long *v = (hash_string_long*) calloc(1, sizeof(hash_string_long));
139 3 v->id=omc_strdup(key);
140 3 v->val=val;
141
9/42
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 time.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 2 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 3 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
3 HASH_ADD_KEYPTR( hh, *ht, v->id, strlen(v->id), v );
142 }
143 3 }
144
145 15 static inline omc_ModelVariable** findHashLongVar(hash_long_var *ht, long key)
146 {
147 hash_long_var *res;
148
5/12
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
30 HASH_FIND_INT( ht, &key, res );
149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (0==res) {
150 hash_long_var *c, *tmp;
151 ✗ HASH_ITER(hh, ht, c, tmp) {
152 ✗ fprintf(stderr, "HashMap contained: %ld->*map*\n", c->id);
153 }
154 ✗ throwStreamPrint(NULL, "Failed to lookup %ld in hashmap %p", key, (void*)ht);
155 }
156 15 return &res->val;
157 }
158
159 3 static inline void addHashLongVar(hash_long_var **ht, long key, omc_ModelVariable *val)
160 {
161 3 hash_long_var *v = (hash_long_var*) calloc(1, sizeof(hash_long_var));
162 3 v->id=key;
163 3 v->val=val;
164
5/28
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
3 HASH_ADD_INT( *ht, id, v );
165 3 }
166
167 5 static inline void freeHashStringString(hash_string_string *ht)
168 {
169 hash_string_string *c, *tmp;
170
3/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 129 times.
✓ Branch 3 taken 5 times.
263 HASH_ITER(hh, ht, c, tmp) {
171
11/16
✓ Branch 0 taken 129 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 124 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 124 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 124 times.
✓ Branch 8 taken 124 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 82 times.
✓ Branch 11 taken 42 times.
✓ Branch 12 taken 42 times.
✓ Branch 13 taken 82 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 124 times.
129 HASH_DEL(ht, c);
172 129 free((void*)c->id);
173 129 free((void*)c->val);
174
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 5 times.
129 free(c);
175 }
176 5 }
177
178 15 static inline void freeHashLongVar(hash_long_var *ht)
179 {
180 hash_long_var *c, *tmp;
181
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 15 times.
33 HASH_ITER(hh, ht, c, tmp) {
182 3 freeHashStringString(c->val);
183
2/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
3 HASH_DEL(ht, c);
184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 free(c);
185 }
186 15 }
187
188 3 static inline void freeHashStringLong(hash_string_long *ht)
189 {
190 hash_string_long *c, *tmp;
191
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
11 HASH_ITER(hh, ht, c, tmp) {
192
9/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
3 HASH_DEL(ht, c);
193 3 free((void*)c->id);
194
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 free(c);
195 }
196 3 }
197
198 /* maybe use a map below {"rSta" -> omc_ModelVariables} */
199 /* typedef map < string, omc_ModelVariables > omc_ModelVariablesClassified; */
200
201 /* structure used to collect data from the xml input file */
202 typedef struct omc_ModelInput
203 {
204 omc_ModelDescription *md; /* model description */
205 omc_DefaultExperiment *de; /* default experiment */
206
207 omc_ModelVariables *rSta; /* states */
208 omc_ModelVariables *rDer; /* derivatives */
209 omc_ModelVariables *rAlg; /* algebraic */
210 omc_ModelVariables *rPar; /* parameters */
211 omc_ModelVariables *rAli; /* aliases */
212 omc_ModelVariables *rSen; /* sensitivities */
213
214 omc_ModelVariables *iAlg; /* int algebraic */
215 omc_ModelVariables *iPar; /* int parameters */
216 omc_ModelVariables *iAli; /* int aliases */
217
218 omc_ModelVariables *bAlg; /* bool algebraic */
219 omc_ModelVariables *bPar; /* bool parameters */
220 omc_ModelVariables *bAli; /* bool aliases */
221
222 omc_ModelVariables *sAlg; /* string algebraic */
223 omc_ModelVariables *sPar; /* string parameters */
224 omc_ModelVariables *sAli; /* string aliases */
225
226 /* these two we need to know to be able to add
227 the stuff in <Real ... />, <String ... /> to
228 the correct variable in the correct map */
229 mmc_sint_t lastCI; /* index */
230 omc_ModelVariables** lastCT; /* type (classification) */
231 } omc_ModelInput;
232
233 // a map for overrides
234 typedef hash_string_string omc_CommandLineOverrides;
235 // a map to find out which names were used
236 #define OMC_OVERRIDE_UNUSED 0
237 #define OMC_OVERRIDE_USED 1
238 typedef hash_string_long omc_CommandLineOverridesUses;
239
240 // function to handle command line settings override
241 void doOverride(omc_ModelInput *mi, MODEL_DATA *modelData, const char *override, const char *overrideFile);
242
243 /* Persistent map of all quantities given via -override/-overrideFile.
244 * Kept alive after doOverride() so that other parts of the runtime (e.g.
245 * importStartValues() for -iif) can tell which quantities the user explicitly
246 * overrode and must therefore not be clobbered by imported values. See #15807. */
247 static omc_CommandLineOverrides *gCommandLineOverrides = NULL;
248
249 static const double REAL_MIN = -DBL_MAX;
250 static const double REAL_MAX = DBL_MAX;
251 static const modelica_integer INTEGER_MIN = MODELICA_INT_MIN;
252 static const modelica_integer INTEGER_MAX = MODELICA_INT_MAX;
253
254 /* Private function prototypes */
255 static modelica_real read_value_real_default(const char *s, modelica_real default_value);
256 static inline modelica_real read_value_real(const char *s);
257 static modelica_integer read_value_long(const char *s, modelica_integer default_value);
258 static int read_value_int(const char *s, int default_value);
259 static modelica_boolean read_value_bool(const char *s);
260 static modelica_string read_value_string(const char *s);
261
262 12 static void XMLCALL startElement(void *userData, const char *name, const char **attr)
263 {
264 omc_ModelInput* mi = (omc_ModelInput*)userData;
265 mmc_sint_t i = 0;
266
267 /* handle fmiModelDescription */
268
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 11 times.
12 if(!strcmp(name, "fmiModelDescription")) {
269
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 1 time.
48 for(i = 0; attr[i]; i += 2) {
270 47 addHashStringString(&mi->md, attr[i], attr[i+1]);
271 }
272 return;
273 }
274 /* handle DefaultExperiment */
275
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 10 times.
11 if(!strcmp(name, "DefaultExperiment")) {
276
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 time.
8 for(i = 0; attr[i]; i += 2) {
277 7 addHashStringString(&mi->de, attr[i], attr[i+1]);
278 }
279 return;
280 }
281
282 /* handle ScalarVariable and ArrayVariable */
283
3/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 7 times.
10 if(!strcmp(name, "ScalarVariable") || !strcmp(name, "ArrayVariable"))
284 {
285 3 omc_ModelVariable *v = NULL, *vfind;
286 const char *ci, *ct;
287 int fail=0;
288 3 mi->lastCI = -1;
289 3 mi->lastCT = NULL;
290
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 3 times.
60 for(i = 0; attr[i]; i += 2) {
291 57 addHashStringString(&v, attr[i], attr[i+1]);
292 }
293 3 addHashStringString(&v, "num_dimensions", "0");
294
295 /* fetch the class index/type */
296 3 ci = findHashStringString(v, "classIndex");
297 3 ct = findHashStringString(v, "classType");
298 /* transform to mmc_sint_t */
299 3 mi->lastCI = atoi(ci);
300
301 /* which one of the classifications? */
302
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (strlen(ct) == 4) {
303
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 if (ct[0]=='r') {
304
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (0 == strcmp(ct+1,"Sta")) {
305 1 mi->lastCT = &mi->rSta;
306
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 } else if (0 == strcmp(ct+1,"Der")) {
307 1 mi->lastCT = &mi->rDer;
308 ✗ } else if (0 == strcmp(ct+1,"Alg")) {
309 ✗ mi->lastCT = &mi->rAlg;
310 ✗ } else if (0 == strcmp(ct+1,"Par")) {
311 ✗ mi->lastCT = &mi->rPar;
312 ✗ } else if (0 == strcmp(ct+1,"Ali")) {
313 ✗ mi->lastCT = &mi->rAli;
314 ✗ } else if (0 == strcmp(ct+1,"Sen")) {
315 ✗ mi->lastCT = &mi->rSen;
316 } else {
317 fail = 1;
318 }
319
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 } else if (ct[0]=='i') {
320
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (0 == strcmp(ct+1,"Alg")) {
321 1 mi->lastCT = &mi->iAlg;
322 ✗ } else if (0 == strcmp(ct+1,"Par")) {
323 ✗ mi->lastCT = &mi->iPar;
324 ✗ } else if (0 == strcmp(ct+1,"Ali")) {
325 ✗ mi->lastCT = &mi->iAli;
326 } else {
327 fail = 1;
328 }
329 ✗ } else if (ct[0]=='b') {
330 ✗ if (0 == strcmp(ct+1,"Alg")) {
331 ✗ mi->lastCT = &mi->bAlg;
332 ✗ } else if (0 == strcmp(ct+1,"Par")) {
333 ✗ mi->lastCT = &mi->bPar;
334 ✗ } else if (0 == strcmp(ct+1,"Ali")) {
335 ✗ mi->lastCT = &mi->bAli;
336 } else {
337 fail = 1;
338 }
339 ✗ } else if (ct[0]=='s') {
340 ✗ if (0 == strcmp(ct+1,"Alg")) {
341 ✗ mi->lastCT = &mi->sAlg;
342 ✗ } else if (0 == strcmp(ct+1,"Par")) {
343 ✗ mi->lastCT = &mi->sPar;
344 ✗ } else if (0 == strcmp(ct+1,"Ali")) {
345 ✗ mi->lastCT = &mi->sAli;
346 } else {
347 fail = 1;
348 }
349 } else {
350 fail = 1;
351 }
352 } else {
353 fail = 1;
354 }
355
356 if (fail) {
357 ✗ throwStreamPrint(NULL, "simulation_input_xml.c: error reading the xml file, found unknown class: %s for variable: %s",ct,findHashStringString(v,"name"));
358 }
359
360 /* add the ScalarVariable map to the correct map! */
361 3 addHashLongVar(mi->lastCT, mi->lastCI, v);
362
363 return;
364 }
365
366 /* handle Real/Integer/Boolean/String */
367
6/8
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
7 if(!strcmp(name, "Real") || !strcmp(name, "Integer") || !strcmp(name, "Boolean") || !strcmp(name, "String")) {
368 /* add keys/value to the last variable */
369
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 for(i = 0; attr[i]; i += 2) {
370 /* add more key/value pairs to the last variable */
371 6 addHashStringString(findHashLongVar(*mi->lastCT, mi->lastCI), attr[i], attr[i+1]);
372 }
373 3 addHashStringString(findHashLongVar(*mi->lastCT, mi->lastCI), "variableType", name);
374 3 return;
375 }
376
377 /* Handle Dimensions of ArrayVariable */
378
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 if(!strcmp(name, "Dimension")) {
379 char* key;
380 omc_ModelVariable** v;
381 const char* num_dimensions;
382 char* next_num_dimensions;
383 unsigned int dim_plus_1;
384 unsigned int size;
385 unsigned int len;
386
387 3 v = findHashLongVar(*mi->lastCT, mi->lastCI);
388 3 num_dimensions = findHashStringString(*v, "num_dimensions");
389 3 dim_plus_1 = atoi(num_dimensions) + 1;
390 3 size = strlen(num_dimensions) + 2; // add additional +1 for possible increase number of digits and one +1 '\0'
391 3 next_num_dimensions = calloc(sizeof(char), size);
392 sprintf(next_num_dimensions, "%u", dim_plus_1);
393 3 addHashStringString(v, "num_dimensions", next_num_dimensions);
394
395 3 len = snprintf(NULL, 0, "dim-%u-valueReference", dim_plus_1); // longest string we ever write into key
396 3 key = calloc(sizeof(char), len + 1);
397
398 /* add more key/value pairs to the last variable */
399
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for(i = 0; attr[i]; i += 2) {
400
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(!strcmp(attr[i], "start")) {
401 sprintf(key, "dim-%u-start", dim_plus_1);
402 3 addHashStringString(v, key, attr[i+1]);
403
404 ✗ } else if(!strcmp(attr[i], "valueReference")) {
405 sprintf(key, "dim-%u-valueReference", dim_plus_1);
406 ✗ addHashStringString(v, key, attr[i+1]);
407 }
408 }
409
410 3 free(key);
411 3 free(next_num_dimensions);
412 3 return;
413 }
414
415 /* anything else, we don't handle! */
416 }
417
418 12 static void XMLCALL endElement(void *userData, const char *name)
419 {
420 /* do nothing! */
421 12 }
422
423 /**
424 * @brief Fill variable info.
425 *
426 * Allocates memory for strings `name`, `comment`, `filename`.
427 * `VAR_INFO` needs to be freed with `freeVarInfo` to free that memory.
428 *
429 * @param var Model variable hash map containing variable info.
430 * @param info Variable info to fill.
431 */
432 3 static void read_var_info(omc_ModelVariable *var, VAR_INFO *info)
433 {
434 3 info->name = omc_strdup(findHashStringString(var,"name"));
435 3 info->inputIndex = read_value_long(findHashStringStringNull(var,"inputIndex"), -1);
436 3 info->id = read_value_int(findHashStringString(var,"valueReference"), -1);
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 assertStreamPrint(NULL, info->id != -1, "read_var_info: Missing valueReference!");
438 3 info->comment = omc_strdup(findHashStringStringEmpty(var,"description"));
439 3 info->info.filename = omc_strdup(findHashStringString(var,"fileName"));
440 3 info->info.lineStart = read_value_long(findHashStringString(var,"startLine"), 0);
441 3 info->info.colStart = read_value_long(findHashStringString(var,"startColumn"), 0);
442 3 info->info.lineEnd = read_value_long(findHashStringString(var,"endLine"), 0);
443 3 info->info.colEnd = read_value_long(findHashStringString(var,"endColumn"), 0);
444 3 info->info.readonly = read_value_long(findHashStringString(var,"fileWritable"), 0);
445
446 3 infoStreamPrint(OMC_LOG_DEBUG, 0, "read var %s from setup file", info->name);
447 3 }
448
449
450 /**
451 * @brief Read variable dimension information
452 *
453 * <ArrayVariable>
454 * <Dimension start="3"/>
455 * <Dimension valueReference="1001"/>
456 * </ArrayVariable>
457 *
458 * @param v Pointer to model variable hash map.
459 * @param dimension_info Pointer to dimension info structure to populate.
460 */
461 3 static void read_var_dimension(omc_ModelVariable *v, DIMENSION_INFO *dimension_info) {
462 char* key;
463 int len;
464 DIMENSION_ATTRIBUTE* dim;
465 modelica_integer numDimensions;
466 modelica_integer i;
467
468 3 numDimensions = read_value_long(findHashStringStringEmpty(v, "num_dimensions"), 0);
469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (numDimensions < 0) {
470 ✗ throwStreamPrint(NULL, "Illegal value while parsing 'num_dimensions'. Expected positive number.");
471 }
472 3 dimension_info->numberOfDimensions = (size_t) numDimensions;
473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (dimension_info->numberOfDimensions == 0) {
474 // No <dimension> tags
475 ✗ dimension_info->dimensions = NULL;
476 ✗ dimension_info->scalar_length = 1;
477 ✗ return;
478 }
479
480 3 dimension_info->dimensions = (DIMENSION_ATTRIBUTE*) calloc(dimension_info->numberOfDimensions, sizeof(DIMENSION_ATTRIBUTE));
481
482 len = snprintf(NULL, 0, "dim-%"PRIdPTR"-valueReference", (intptr_t)dimension_info->numberOfDimensions); // longest string we ever write into key
483 3 key = calloc(sizeof(char), len + 1);
484
485
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (i = 0; i < dimension_info->numberOfDimensions; i++) {
486 3 dim = &dimension_info->dimensions[i];
487
488 3 sprintf(key, "dim-%"PRIdPTR"-start", (intptr_t)(i + 1));
489 3 dim->start = read_value_long(findHashStringStringEmpty(v, key), -1);
490
491 sprintf(key, "dim-%"PRIdPTR"-valueReference", (intptr_t)(i + 1));
492 3 dim->valueReference = read_value_long(findHashStringStringEmpty(v, key), -1);
493
494
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (dim->start > 0 && dim->valueReference == -1) {
495 3 dim->type = DIMENSION_BY_START;
496 ✗ } else if (dim->start == -1 && dim->valueReference >= 0) {
497 ✗ dim->type = DIMENSION_BY_VALUE_REFERENCE;
498 ✗ } else if (dim->start == -1 && dim->valueReference == -1) {
499 ✗ throwStreamPrint(NULL, "simulation_input_xml.c: Error reading the xml file! " \
500 "Found neither 'start' or 'valueReference' element in <dimension> tag.");
501 } else {
502 ✗ throwStreamPrint(NULL, "simulation_input_xml.c: Error reading the xml file! " \
503 "Found 'start' and 'valueReference' element in <dimension> tag, " \
504 "but only one is allowed");
505 }
506 }
507
508 3 dimension_info->scalar_length = -1; // We might not know the values of structural parameters yet.
509
510 3 free(key);
511 }
512
513 /**
514 * @brief Write `token` as element `i` of `array`.
515 */
516 typedef void (*put_token_t)(const char *token, size_t i, base_array_t *array);
517
518 1 static void put_real_token(const char *token, size_t i, base_array_t *array)
519 {
520 1 put_real_element(read_value_real(token), i, array);
521 1 }
522
523 ✗ static void put_integer_token(const char *token, size_t i, base_array_t *array)
524 {
525 ✗ put_integer_element(read_value_long(token, 0), i, array);
526 ✗ }
527
528 ✗ static void put_boolean_token(const char *token, size_t i, base_array_t *array)
529 {
530 ✗ put_boolean_element(read_value_bool(token), i, array);
531 ✗ }
532
533 /**
534 * @brief Read string with multiple space separated values into `array`.
535 *
536 * @param str String to read values from.
537 * @param put Converts a single token and stores it in `array`.
538 * @param array Array to fill. Needs enough memory to store
539 * `num_elements` elements.
540 * If `NULL` only counts number of elements, but doesn't
541 * write into `array`.
542 * @param num_elements Number of elements to read from `str`.
543 * @return size_t Returns number of elements read.
544 */
545 12 static size_t read_tokens(const char* str, put_token_t put, base_array_t* array, size_t num_elements) {
546 const char* delimeter = " ";
547 size_t count = 0;
548
549 12 char* copy = omc_strdup(str);
550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assertStreamPrint(NULL, copy != NULL, "Out of memory!");
551 12 char* rest = copy;
552
553 12 char *token = strtok_r(rest, delimeter, &rest);
554
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 while (token != NULL) {
555 2 count++;
556
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (count <= num_elements && array != NULL) {
557 1 put(token, count-1, array);
558 }
559 2 token = strtok_r(rest, delimeter, &rest);
560 }
561
562 12 free(copy);
563
564 12 return count;
565 }
566
567 /**
568 * @brief Read string with multiple real values into `array`.
569 *
570 * @param str String to read values from.
571 * @param array Array to fill. Needs enough memory to store
572 * `num_elements` elements.
573 * If `NULL` only counts number of elements, but doesn't
574 * write into `array`.
575 * @param num_elements Number of elements to read from `str`.
576 * @return size_t Returns number of elements read.
577 */
578 9 size_t read_str(const char* str, real_array* array, size_t num_elements) {
579 9 return read_tokens(str, put_real_token, array, num_elements);
580 }
581
582 /**
583 * @brief Read string into array variable.
584 *
585 * @param array Array variable to populate.
586 * @param str String with numbers to be read into real array.
587 * Values delimited by space `" "`.
588 * @param default_value
589 */
590 8 void read_array_var_real(real_array* array, const char* str, modelica_real default_value) {
591 size_t length;
592
593 8 length = read_str(str, NULL, 0);
594
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 time.
8 if (length == 0) {
595 length = 1;
596 7 simple_alloc_1d_real_array(array, length);
597 7 put_real_element(default_value, 0, array);
598 } else {
599 1 simple_alloc_1d_real_array(array, length);
600 1 read_str(str, array, length);
601 }
602 8 }
603
604 /**
605 * @brief Read string into integer array variable.
606 *
607 * @param array Array variable to populate.
608 * @param str String with integers to be read into integer array.
609 * Values delimited by space `" "`.
610 * @param default_value Value to use if `str` is empty.
611 */
612 3 void read_array_var_integer(integer_array* array, const char* str, modelica_integer default_value) {
613 size_t length;
614
615 3 length = read_tokens(str, put_integer_token, NULL, 0);
616
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (length == 0) {
617 3 simple_alloc_1d_integer_array(array, 1);
618 3 put_integer_element(default_value, 0, array);
619 } else {
620 ✗ simple_alloc_1d_integer_array(array, length);
621 ✗ read_tokens(str, put_integer_token, array, length);
622 }
623 3 }
624
625 /**
626 * @brief Read string into boolean array variable.
627 *
628 * @param array Array variable to populate.
629 * @param str String with `true`/`false` values to be read into
630 * boolean array. Values delimited by space `" "`.
631 * @param default_value Value to use if `str` is empty.
632 */
633 ✗ void read_array_var_boolean(boolean_array* array, const char* str, modelica_boolean default_value) {
634 size_t length;
635
636 ✗ length = read_tokens(str, put_boolean_token, NULL, 0);
637 ✗ if (length == 0) {
638 ✗ simple_alloc_1d_boolean_array(array, 1);
639 ✗ put_boolean_element(default_value, 0, array);
640 } else {
641 ✗ simple_alloc_1d_boolean_array(array, length);
642 ✗ read_tokens(str, put_boolean_token, array, length);
643 }
644 ✗ }
645
646 /**
647 * @brief Read string with multiple quoted string values into `array`.
648 *
649 * Values are enclosed in double quotes and delimited by space, e.g.
650 * `"a" "b c" ""`. Inside a value `"` is not escaped, so a quote only closes
651 * the value if it is followed by the end of `str` or by spaces and the next
652 * opening quote.
653 *
654 * @param str String to read values from.
655 * @param array Array to fill. Needs enough memory to store
656 * `num_elements` elements.
657 * If `NULL` only counts number of elements, but doesn't
658 * write into `array`.
659 * @param num_elements Number of elements to read from `str`.
660 * @return size_t Returns number of elements read or 0 if `str` isn't a
661 * list of quoted values.
662 */
663 ✗ size_t read_quoted_str(const char* str, string_array* array, size_t num_elements) {
664 const char *pos = str;
665 const char *begin;
666 const char *end;
667 const char *next;
668 size_t count = 0;
669
670 ✗ while (*pos == ' ') pos++;
671 ✗ while (*pos != '\0') {
672 ✗ if (*pos != '"') {
673 return 0;
674 }
675 ✗ begin = pos + 1;
676
677 /* find closing quote */
678 end = NULL;
679 ✗ for (next = begin; *next != '\0'; next++) {
680 ✗ if (*next == '"') {
681 ✗ const char *after = next + 1;
682 ✗ while (*after == ' ') after++;
683 ✗ if (*after == '\0' || (*after == '"' && after > next + 1)) {
684 end = next;
685 break;
686 }
687 }
688 }
689 ✗ if (end == NULL) {
690 return 0;
691 }
692
693 ✗ count++;
694 ✗ if (count <= num_elements && array != NULL) {
695 ✗ modelica_string value = omc_string_new_len(begin, (mmc_uint_t)(end - begin));
696 ✗ put_string_element(value, count-1, array);
697 omc_string_release(value);
698 }
699
700 ✗ pos = end + 1;
701 ✗ while (*pos == ' ') pos++;
702 }
703
704 return count;
705 }
706
707 /**
708 * @brief Read string into string array variable.
709 *
710 * For scalar variables `str` is the value itself. For array variables `str`
711 * is a list of quoted values, see `read_quoted_str`. If it doesn't start with a
712 * quote it is a single value that is used for all array elements.
713 *
714 * @param array Array variable to populate.
715 * @param str String to read.
716 * @param isScalar If true `str` belongs to a scalar variable.
717 */
718 ✗ void read_array_var_string(string_array* array, const char* str, modelica_boolean isScalar) {
719 size_t length = 0;
720 modelica_string value;
721
722 ✗ if (!isScalar) {
723 ✗ length = read_quoted_str(str, NULL, 0);
724 }
725
726 ✗ if (length == 0) {
727 ✗ simple_alloc_1d_string_array(array, 1);
728 ✗ value = omc_string_new(str);
729 ✗ put_string_element(value, 0, array);
730 omc_string_release(value);
731 } else {
732 ✗ simple_alloc_1d_string_array(array, length);
733 ✗ read_quoted_str(str, array, length);
734 }
735 ✗ }
736
737 /**
738 * @brief Read attributes of real variable.
739 *
740 * @param var_map Hash map for variable with attributes as keys.
741 * @param attribute Attributes to write values into.
742 * @param isScalar If true real variable represents a scalar, otherwise an array.
743 */
744 2 static void read_var_attribute_real(omc_ModelVariable *var_map, REAL_ATTRIBUTE *attribute, modelica_boolean isScalar)
745 {
746 const size_t buff_size = 2048;
747 char *start_buffer;
748 char *nominal_buffer;
749 char *min_buffer;
750 char *max_buffer;
751
752 2 read_array_var_real(&attribute->start, findHashStringStringEmpty(var_map, "start"), 0.0);
753 2 attribute->fixed = read_value_bool(findHashStringString(var_map, "fixed"));
754 4 attribute->useNominal = read_value_bool(findHashStringString(var_map, "useNominal"));
755 2 read_array_var_real(&attribute->nominal, findHashStringStringEmpty(var_map, "nominal"), 1.0);
756 2 read_array_var_real(&attribute->min, findHashStringStringEmpty(var_map, "min"), REAL_MIN);
757 2 read_array_var_real(&attribute->max, findHashStringStringEmpty(var_map, "max"), REAL_MAX);
758 2 attribute->unit = read_value_string(findHashStringStringEmpty(var_map, "unit"));
759 2 attribute->displayUnit = read_value_string(findHashStringStringEmpty(var_map, "displayUnit"));
760 2 attribute->relativeQuantity = read_value_bool(findHashStringStringEmpty(var_map, "relativeQuantity"));
761
762 2 if (omc_useStream[OMC_LOG_DEBUG])
763 {
764 ✗ start_buffer = (char*) malloc(buff_size * sizeof(char));
765 ✗ assertStreamPrint(NULL, start_buffer != NULL, "Out of memory.");
766 ✗ nominal_buffer = (char*) malloc(buff_size * sizeof(char));
767 ✗ assertStreamPrint(NULL, nominal_buffer != NULL, "Out of memory.");
768 ✗ min_buffer = (char*) malloc(buff_size * sizeof(char));
769 ✗ assertStreamPrint(NULL, min_buffer != NULL, "Out of memory.");
770 ✗ max_buffer = (char*) malloc(buff_size * sizeof(char));
771 ✗ assertStreamPrint(NULL, max_buffer != NULL, "Out of memory.");
772
773 ✗ real_vector_to_string(&attribute->start, isScalar, start_buffer, buff_size);
774 ✗ real_vector_to_string(&attribute->nominal, isScalar, nominal_buffer, buff_size);
775 ✗ real_vector_to_string(&attribute->min, isScalar, min_buffer, buff_size);
776 ✗ real_vector_to_string(&attribute->max, isScalar, max_buffer, buff_size);
777
778 ✗ infoStreamPrint(OMC_LOG_DEBUG, 0,
779 "Real %s(start=%s, fixed=%s, useNominal=%s, nominal=%s, min=%s, max=%s)",
780 findHashStringString(var_map, "name"),
781 start_buffer,
782 ✗ (attribute->fixed) ? "true" : "false",
783 ✗ (attribute->useNominal) ? "true" : "false",
784 nominal_buffer,
785 min_buffer,
786 max_buffer);
787
788 ✗ free(start_buffer);
789 ✗ free(nominal_buffer);
790 ✗ free(min_buffer);
791 ✗ free(max_buffer);
792 }
793 2 }
794
795 /**
796 * @brief Read attributes of integer variable.
797 *
798 * @param var_map Hash map for variable with attributes as keys.
799 * @param attribute Attributes to write values into.
800 * @param isScalar If true integer variable represents a scalar, otherwise an array.
801 */
802 1 static void read_var_attribute_int(omc_ModelVariable *var_map, INTEGER_ATTRIBUTE *attribute, modelica_boolean isScalar)
803 {
804 const size_t buff_size = 2048;
805 char *start_buffer;
806 char *min_buffer;
807 char *max_buffer;
808
809 1 read_array_var_integer(&attribute->start, findHashStringStringEmpty(var_map, "start"), 0);
810 1 attribute->fixed = read_value_bool(findHashStringString(var_map, "fixed"));
811 1 read_array_var_integer(&attribute->min, findHashStringStringEmpty(var_map, "min"), INTEGER_MIN);
812 1 read_array_var_integer(&attribute->max, findHashStringStringEmpty(var_map, "max"), INTEGER_MAX);
813
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_useStream[OMC_LOG_DEBUG])
815 {
816 ✗ start_buffer = (char*) malloc(buff_size * sizeof(char));
817 ✗ assertStreamPrint(NULL, start_buffer != NULL, "Out of memory.");
818 ✗ min_buffer = (char*) malloc(buff_size * sizeof(char));
819 ✗ assertStreamPrint(NULL, min_buffer != NULL, "Out of memory.");
820 ✗ max_buffer = (char*) malloc(buff_size * sizeof(char));
821 ✗ assertStreamPrint(NULL, max_buffer != NULL, "Out of memory.");
822
823 ✗ integer_vector_to_string(&attribute->start, isScalar, start_buffer, buff_size);
824 ✗ integer_vector_to_string(&attribute->min, isScalar, min_buffer, buff_size);
825 ✗ integer_vector_to_string(&attribute->max, isScalar, max_buffer, buff_size);
826
827 ✗ infoStreamPrint(OMC_LOG_DEBUG, 0,
828 "Integer %s(start=%s, fixed=%s, min=%s, max=%s)",
829 findHashStringString(var_map, "name"),
830 start_buffer,
831 ✗ attribute->fixed ? "true" : "false",
832 min_buffer,
833 max_buffer);
834
835 ✗ free(start_buffer);
836 ✗ free(min_buffer);
837 ✗ free(max_buffer);
838 }
839 1 }
840
841 /**
842 * @brief Read attributes of boolean variable.
843 *
844 * @param var_map Hash map for variable with attributes as keys.
845 * @param attribute Attributes to write values into.
846 * @param isScalar If true boolean variable represents a scalar, otherwise an array.
847 */
848 ✗ static void read_var_attribute_bool(omc_ModelVariable *var_map, BOOLEAN_ATTRIBUTE *attribute, modelica_boolean isScalar)
849 {
850 const size_t buff_size = 2048;
851 char *start_buffer;
852
853 ✗ read_array_var_boolean(&attribute->start, findHashStringStringEmpty(var_map, "start"), 0);
854 ✗ attribute->fixed = read_value_bool(findHashStringString(var_map, "fixed"));
855
856 ✗ if (omc_useStream[OMC_LOG_DEBUG])
857 {
858 ✗ start_buffer = (char*) malloc(buff_size * sizeof(char));
859 ✗ assertStreamPrint(NULL, start_buffer != NULL, "Out of memory.");
860
861 ✗ boolean_vector_to_string(&attribute->start, isScalar, start_buffer, buff_size);
862
863 ✗ infoStreamPrint(OMC_LOG_DEBUG, 0,
864 "Boolean %s(start=%s, fixed=%s)",
865 findHashStringString(var_map, "name"),
866 start_buffer,
867 ✗ attribute->fixed ? "true" : "false");
868
869 ✗ free(start_buffer);
870 }
871 ✗ }
872
873 /**
874 * @brief Read attributes of string variable.
875 *
876 * @param var_map Hash map for variable with attributes as keys.
877 * @param attribute Attributes to write values into.
878 * @param isScalar If true string variable represents a scalar, otherwise an array.
879 */
880 ✗ static void read_var_attribute_string(omc_ModelVariable *var_map, STRING_ATTRIBUTE *attribute, modelica_boolean isScalar)
881 {
882 const size_t buff_size = 2048;
883 char *start_buffer;
884
885 ✗ read_array_var_string(&attribute->start, findHashStringStringEmpty(var_map, "start"), isScalar);
886
887 ✗ if (omc_useStream[OMC_LOG_DEBUG])
888 {
889 ✗ start_buffer = (char*) malloc(buff_size * sizeof(char));
890 ✗ assertStreamPrint(NULL, start_buffer != NULL, "Out of memory.");
891
892 ✗ string_vector_to_string(&attribute->start, isScalar, start_buffer, buff_size);
893
894 ✗ infoStreamPrint(OMC_LOG_DEBUG, 0,
895 "String %s(start=%s)",
896 findHashStringString(var_map, "name"),
897 start_buffer);
898
899 ✗ free(start_buffer);
900 }
901 ✗ }
902
903 /**
904 * @brief Check if a variable should be filtered from the output
905 *
906 * the check is like this:
907 * - we filter if isProtected (protected variables)
908 * - we filter if annotation(HideResult=true)
909 * - we emit (remove filtering) if !encrypted && emitProtected && isProtected
910 * - we emit (remove filtering) if ignoreHideResult && annotation(HideResult=true)
911 *
912 * @param variable Variable to check
913 * @param name Variable name
914 *
915 * @return TRUE if the variable should be filtered (not appear in the output)
916 */
917 3 int shouldFilterOutput(omc_ModelVariable *variable, const char *name)
918 {
919 3 int ep = omc_flag[FLAG_EMIT_PROTECTED];
920 3 int ihr = omc_flag[FLAG_IGNORE_HIDERESULT];
921 3 const char *ipstr = findHashStringString(variable, "isProtected");
922 3 const char *hrstr = findHashStringString(variable, "hideResult");
923 3 const char *iestr = findHashStringString(variable, "isEncrypted");
924 3 int ipcmptrue = (0 == strcmp(ipstr, "true"));
925 3 int hrcmptrue = (0 == strcmp(hrstr, "true"));
926 3 int iecmptrue = (0 == strcmp(iestr, "true"));
927
928 int shouldFilter = FALSE;
929
930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ipcmptrue) {
931 ✗ infoStreamPrint(OMC_LOG_DEBUG, 0, "filtering protected variable %s", name);
932 shouldFilter = TRUE;
933 }
934
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (hrcmptrue) {
935 ✗ infoStreamPrint(OMC_LOG_DEBUG, 0, "filtering variable %s due to HideResult annotation", name);
936 shouldFilter = TRUE;
937 }
938
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (!iecmptrue && ep && ipcmptrue) {
939 ✗ infoStreamPrint(OMC_LOG_DEBUG, 0, "emitting protected variable %s due to flag %s", name, omc_flagValue[FLAG_EMIT_PROTECTED]);
940 shouldFilter = FALSE;
941 }
942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ihr && hrcmptrue) {
943 ✗ infoStreamPrint(OMC_LOG_DEBUG, 0, "emitting variable %s with HideResult=true annotation due to flag %s", name, omc_flagValue[FLAG_IGNORE_HIDERESULT]);
944 shouldFilter = FALSE;
945 }
946
947 3 return shouldFilter;
948 }
949
950 /**
951 * @brief Read all static data from File for every variable
952 *
953 * @param simulationInfo
954 * @param type VAR_TYPE_REAL, VAR_TYPE_INTEGER, VAR_TYPE_BOOLEAN, VAR_TYPE_STRING
955 * @param out Write variable infos into.
956 * Must be of type STATIC_<type>_DATA
957 * @param in Model variable map
958 * @param debugName Name used in debug output
959 * @param start Start index in out
960 * @param numVariables Number of variables to read
961 * @param mapAlias Map of variable names to indices in out
962 * @param mapAliasParam Map of parameter names to indices in out
963 * @param sensitivityParIndex Index in sensitivityParList, will be incremented
964 * for each sensitivity parameter found
965 */
966 10 static void read_variables(SIMULATION_INFO* simulationInfo,
967 enum var_type type,
968 void *out,
969 omc_ModelVariables *in,
970 const char *debugName,
971 mmc_sint_t start,
972 mmc_sint_t numVariables,
973 hash_string_long **mapAlias,
974 hash_string_long **mapAliasParam,
975 int *sensitivityParIndex)
976 {
977 VAR_INFO *info;
978 DIMENSION_INFO* dimension;
979 modelica_boolean *filterOutput;
980 mmc_sint_t i, j;
981 omc_ModelVariable *v;
982
983 10 infoStreamPrint(OMC_LOG_DEBUG, 0, "read xml file for %s", debugName);
984
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 for (i = 0; i < numVariables; i++) {
985 3 j = start + i;
986 3 v = *findHashLongVar(in, i);
987
988 // Access real/int/bool/string attribute data
989 // Set info, dimension and filterOutput pointers
990
2/5
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 switch (type) {
991 2 case VAR_TYPE_REAL:
992 {
993 STATIC_REAL_DATA* realVarsData = (STATIC_REAL_DATA*) out;
994 2 REAL_ATTRIBUTE* attribute = &realVarsData[j].attribute;
995 2 dimension = &realVarsData[j].dimension;
996 2 info = &realVarsData[j].info;
997 filterOutput = &realVarsData[j].filterOutput;
998 2 read_var_dimension(v, dimension);
999 2 read_var_attribute_real(v, attribute, dimension->numberOfDimensions == 0);
1000 2 read_var_info(v, info);
1001 2 *filterOutput = shouldFilterOutput(v, info->name);
1002 }
1003 2 break;
1004 1 case VAR_TYPE_INTEGER:
1005 {
1006 STATIC_INTEGER_DATA* intVarsData = (STATIC_INTEGER_DATA*) out;
1007 1 INTEGER_ATTRIBUTE* attribute = &intVarsData[j].attribute;
1008 1 dimension = &intVarsData[j].dimension;
1009 1 info = &intVarsData[j].info;
1010 filterOutput = &intVarsData[j].filterOutput;
1011 1 read_var_dimension(v, dimension);
1012 1 read_var_attribute_int(v, attribute, dimension->numberOfDimensions == 0);
1013 1 read_var_info(v, info);
1014 1 *filterOutput = shouldFilterOutput(v, info->name);
1015 }
1016 1 break;
1017 ✗ case VAR_TYPE_BOOLEAN:
1018 {
1019 STATIC_BOOLEAN_DATA* boolVarsData = (STATIC_BOOLEAN_DATA*) out;
1020 ✗ BOOLEAN_ATTRIBUTE* attribute = &boolVarsData[j].attribute;
1021 ✗ dimension = &boolVarsData[j].dimension;
1022 ✗ info = &boolVarsData[j].info;
1023 filterOutput = &boolVarsData[j].filterOutput;
1024 ✗ read_var_dimension(v, dimension);
1025 ✗ read_var_attribute_bool(v, attribute, dimension->numberOfDimensions == 0);
1026 ✗ read_var_info(v, info);
1027 ✗ *filterOutput = shouldFilterOutput(v, info->name);
1028 }
1029 ✗ break;
1030 ✗ case VAR_TYPE_STRING:
1031 {
1032 STATIC_STRING_DATA* stringVarsData = (STATIC_STRING_DATA*) out;
1033 ✗ STRING_ATTRIBUTE* attribute = &stringVarsData[j].attribute;
1034 ✗ dimension = &stringVarsData[j].dimension;
1035 ✗ info = &stringVarsData[j].info;
1036 filterOutput = &stringVarsData[j].filterOutput;
1037 ✗ read_var_dimension(v, dimension);
1038 ✗ read_var_attribute_string(v, attribute, dimension->numberOfDimensions == 0);
1039 ✗ read_var_info(v, info);
1040 ✗ *filterOutput = shouldFilterOutput(v, info->name);
1041 }
1042 ✗ break;
1043 ✗ default:
1044 ✗ throwStreamPrint(NULL, "simulation_input_xml.c: Error: Unsupported type in read_variables.");
1045 break;
1046 }
1047
1048 /* create a mapping for Alias variable to get the correct index */
1049 3 addHashStringLong(mapAlias, info->name, j);
1050
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (omc_flag[FLAG_IDAS] && 0 == strcmp(debugName, "real sensitivities")) {
1051 ✗ if (0 == strcmp(findHashStringString(v, "isValueChangeable"), "true")) {
1052 ✗ long *it = findHashStringLongPtr(*mapAliasParam, info->name);
1053 // TODO: This should not be filled here. It's part of simulation info, not model data.
1054 ✗ simulationInfo->sensitivityParList[*sensitivityParIndex] = *it;
1055 ✗ infoStreamPrint(OMC_LOG_SOLVER, 0, "%d. sensitivity parameter %s at index %d", *sensitivityParIndex, info->name, simulationInfo->sensitivityParList[*sensitivityParIndex]);
1056 ✗ (*sensitivityParIndex)++;
1057 }
1058 }
1059 }
1060 10 }
1061
1062 /**
1063 * @brief Read XML file name from user supplied flags
1064 *
1065 * @return const char* Filename, needs to be freed.
1066 */
1067 1 char* getXMLfileName(const char* modelFilePrefix, threadData_t* threadData) {
1068 char *filename;
1069
1070
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_flag[FLAG_F]) { // Read the filename from the command line
1071 ✗ filename = omc_strdup(omc_flagValue[FLAG_F]);
1072 ✗ if(filename == NULL) {
1073 ✗ throwStreamPrint(threadData, "simulation_input_xml.c: Out of memory");
1074 }
1075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 } else if (omc_flag[FLAG_INPUT_PATH]) { // Read the input path from the command line
1076 ✗ filename = (char*) calloc(strlen(omc_flagValue[FLAG_INPUT_PATH]) + strlen(modelFilePrefix) + 10 + 1, sizeof(char));
1077 ✗ if(filename == NULL) {
1078 ✗ throwStreamPrint(threadData, "simulation_input_xml.c: Out of memory");
1079 }
1080 sprintf(filename, "%s/%s_init.xml", omc_flagValue[FLAG_INPUT_PATH], modelFilePrefix);
1081 } else { // Use default model_name
1082 1 filename = (char*) calloc(strlen(modelFilePrefix) + 9 + 1, sizeof(char));
1083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if(filename == NULL) {
1084 ✗ throwStreamPrint(threadData, "simulation_input_xml.c: Out of memory");
1085 }
1086 sprintf(filename, "%s_init.xml", modelFilePrefix);
1087 }
1088
1089 1 return filename;
1090 }
1091
1092 /**
1093 * @brief Parse input XML content.
1094 *
1095 * @param filename Name to init XML file. If no file is available set `initXMLData` with the content of the file instead.
1096 * @param initXMLData [Optional] Content of input XML file.
1097 * @param threadData For error handling, can be NULL.
1098 * @return omc_ModelInput* Hash map with all data read from XML. Needs to be freed by caller with `free`.
1099 */
1100 1 omc_ModelInput* parse_input_xml(const char *filename, const char* initXMLData, threadData_t* threadData) {
1101 XML_Parser parser = NULL;
1102 enum XML_Status status;
1103 FILE* file = NULL;
1104 1 omc_ModelInput* mi = (omc_ModelInput*) calloc(1, sizeof(omc_ModelInput));
1105
1106 /* create the XML parser */
1107 1 parser = XML_ParserCreate(NULL);
1108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if(!parser)
1109 {
1110 ✗ free(mi);
1111 ✗ throwStreamPrint(threadData, "simulation_input_xml.c: Error: couldn't allocate memory for the XML parser!");
1112 }
1113
1114 /* set our user data */
1115 1 XML_SetUserData(parser, mi);
1116
1117 /* set the handlers for start/end of element. */
1118 1 XML_SetElementHandler(parser, startElement, endElement);
1119
1120
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if(initXMLData == NULL) {
1121 1 file = omc_fopen(filename, "r");
1122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if(!file) {
1123 ✗ free(mi);
1124 ✗ XML_ParserFree(parser);
1125 ✗ throwStreamPrint(threadData, "simulation_input_xml.c: Error: can not read file %s as setup file to the generated simulation code.", filename);
1126 }
1127
1128 int done;
1129 1 char buf[BUFSIZ+1] = {0};
1130 do
1131 {
1132 1 size_t len = omc_fread(buf, 1, BUFSIZ, file, 1);
1133 1 done = len < BUFSIZ;
1134 1 status = XML_Parse(parser, buf, len, done);
1135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if(status == XML_STATUS_ERROR)
1136 {
1137 ✗ fclose(file);
1138 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "simulation_input_xml.c: Error: failed to read the XML file %s: %s at line %lu\n",
1139 filename,
1140 XML_ErrorString(XML_GetErrorCode(parser)),
1141 XML_GetCurrentLineNumber(parser));
1142 ✗ XML_ParserFree(parser);
1143 ✗ throwStreamPrint(threadData, "see last warning");
1144 }
1145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 } while(!done);
1146 1 fclose(file);
1147 } else {
1148 ✗ status = XML_Parse(parser, initXMLData, strlen(initXMLData), 1);
1149 ✗ if(status == XML_STATUS_ERROR) {
1150 ✗ fprintf(stderr, "%s, %s %lu\n", initXMLData, XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
1151 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "simulation_input_xml.c: Error: failed to read the XML data %s: %s at line %lu\n",
1152 initXMLData,
1153 XML_ErrorString(XML_GetErrorCode(parser)),
1154 XML_GetCurrentLineNumber(parser));
1155 ✗ XML_ParserFree(parser);
1156 ✗ throwStreamPrint(threadData, "see last warning");
1157 }
1158 }
1159
1160 1 XML_ParserFree(parser);
1161 1 return mi;
1162 }
1163
1164 /**
1165 * @brief Read experiment information from hash map and flags.
1166 *
1167 * Allocates memory for `solverMethod`, `outputFormat` and `variableFilter`
1168 * which needs to be freed by caller.
1169 *
1170 * @param simulationInfo Contains read values after return.
1171 * @param de Default experiment hash map.
1172 */
1173 1 void read_experiment(SIMULATION_INFO* simulationInfo, omc_DefaultExperiment *de)
1174 {
1175 modelica_boolean reCalcStepSize = FALSE; // If true step size is recalculated instead of read from hash map.
1176
1177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_flag[FLAG_START_TIME]) {
1178 ✗ simulationInfo->startTime = atof(omc_flagValue[FLAG_START_TIME]);
1179 reCalcStepSize = TRUE;
1180 } else {
1181 1 simulationInfo->startTime = read_value_real_default(findHashStringString(de,"startTime"), 0);
1182 }
1183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_flag[FLAG_STOP_TIME]) {
1184 ✗ simulationInfo->stopTime = atof(omc_flagValue[FLAG_STOP_TIME]);
1185 reCalcStepSize = TRUE;
1186 } else {
1187 1 simulationInfo->stopTime = read_value_real_default(findHashStringString(de,"stopTime"), 1.0);
1188 }
1189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_flag[FLAG_STEP_SIZE]) {
1190 ✗ simulationInfo->stepSize = atof(omc_flagValue[FLAG_STEP_SIZE]);
1191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 } else if (reCalcStepSize) {
1192 ✗ simulationInfo->stepSize = (simulationInfo->stopTime - simulationInfo->startTime) / 500;
1193 ✗ warningStreamPrint(OMC_LOG_STDOUT, 1, "Start or stop time was overwritten, but no new integrator step size was provided.");
1194 ✗ infoStreamPrint(OMC_LOG_STDOUT, 0, "Re-calculating step size for 500 intervals.");
1195 ✗ infoStreamPrint(OMC_LOG_STDOUT, 0, "Use `-stepSize=<value>` to silence this warning.");
1196 ✗ messageCloseWarning(OMC_LOG_STDOUT);
1197 } else {
1198 1 simulationInfo->stepSize = read_value_real_default(findHashStringString(de, "stepSize"), (simulationInfo->stopTime - simulationInfo->startTime) / 500);
1199 }
1200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_flag[FLAG_TOLERANCE]) {
1201 ✗ simulationInfo->tolerance = atof(omc_flagValue[FLAG_TOLERANCE]);
1202 } else {
1203 1 simulationInfo->tolerance = read_value_real_default(findHashStringString(de, "tolerance"), 1e-5);
1204 }
1205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_flag[FLAG_S]) {
1206 ✗ simulationInfo->solverMethod = GC_strdup(omc_flagValue[FLAG_S]);
1207 } else {
1208 1 simulationInfo->solverMethod = GC_strdup(findHashStringString(de, "solver"));
1209 }
1210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_flag[FLAG_OUTPUT_FORMAT]) {
1211 ✗ simulationInfo->outputFormat = GC_strdup(omc_flagValue[FLAG_OUTPUT_FORMAT]);
1212 } else {
1213 1 simulationInfo->outputFormat = GC_strdup(findHashStringString(de, "outputFormat"));
1214 }
1215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_flag[FLAG_VARIABLE_FILTER]) {
1216 ✗ simulationInfo->variableFilter = GC_strdup(omc_flagValue[FLAG_VARIABLE_FILTER]);
1217 } else {
1218 1 simulationInfo->variableFilter = GC_strdup(findHashStringString(de, "variableFilter"));
1219 }
1220
1221 1 infoStreamPrint(OMC_LOG_SIMULATION, 1, "Read all Experiment values:");
1222 1 infoStreamPrint(OMC_LOG_SIMULATION, 0, "startTime = %g", simulationInfo->startTime);
1223 1 infoStreamPrint(OMC_LOG_SIMULATION, 0, "stopTime = %g", simulationInfo->stopTime);
1224 1 infoStreamPrint(OMC_LOG_SIMULATION, 0, "stepSize = %g", simulationInfo->stepSize);
1225 1 infoStreamPrint(OMC_LOG_SIMULATION, 0, "tolerance = %g", simulationInfo->tolerance);
1226 1 infoStreamPrint(OMC_LOG_SIMULATION, 0, "solver method: %s", simulationInfo->solverMethod);
1227 1 infoStreamPrint(OMC_LOG_SIMULATION, 0, "output format: %s", simulationInfo->outputFormat);
1228 1 infoStreamPrint(OMC_LOG_SIMULATION, 0, "variable filter: %s", simulationInfo->variableFilter);
1229 1 messageClose(OMC_LOG_SIMULATION);
1230 1 }
1231
1232 /**
1233 * @brief Read number of scalar and array variables / parameters.
1234 *
1235 * Read number of scalar and array variables or parameters from model
1236 * description into `modelData`. Here one array variable of arbitrary size
1237 * counts as one variable.
1238 *
1239 * @param md Model description hash map.
1240 * @param modelData Model data to contain number of variables / parameters on
1241 * return.
1242 */
1243 1 void read_model_description_sizes(omc_ModelDescription *md, MODEL_DATA *modelData) {
1244 modelica_integer numRealAlgVars;
1245
1246 1 modelData->nStatesArray = read_value_long(findHashStringString(md, "numberOfContinuousStates"), 0);
1247 1 numRealAlgVars = read_value_long(findHashStringString(md, "numberOfRealAlgebraicVariables"), 0);
1248 1 modelData->nVariablesRealArray = 2*modelData->nStatesArray + numRealAlgVars;
1249 1 modelData->nAliasRealArray = read_value_long(findHashStringString(md, "numberOfRealAlgebraicAliasVariables"), 0);
1250 1 modelData->nParametersRealArray = read_value_long(findHashStringString(md, "numberOfRealParameters"), 0);
1251
1252 1 modelData->nParametersIntegerArray = read_value_long(findHashStringString(md, "numberOfIntegerParameters"), 0);
1253 1 modelData->nVariablesIntegerArray = read_value_long(findHashStringString(md, "numberOfIntegerAlgebraicVariables"), 0);
1254 1 modelData->nAliasIntegerArray = read_value_long(findHashStringString(md, "numberOfIntegerAliasVariables"), 0);
1255
1256 1 modelData->nParametersBooleanArray = read_value_long(findHashStringString(md, "numberOfBooleanParameters"), 0);
1257 1 modelData->nVariablesBooleanArray = read_value_long(findHashStringString(md, "numberOfBooleanAlgebraicVariables"), 0);
1258 1 modelData->nAliasBooleanArray = read_value_long(findHashStringString(md, "numberOfBooleanAliasVariables"), 0);
1259
1260 1 modelData->nParametersStringArray = read_value_long(findHashStringString(md, "numberOfStringParameters"), 0);
1261 1 modelData->nVariablesStringArray = read_value_long(findHashStringString(md, "numberOfStringAlgebraicVariables"), 0);
1262 1 modelData->nAliasStringArray = read_value_long(findHashStringString(md, "numberOfStringAliasVariables"), 0);
1263 1 }
1264
1265 /**
1266 * @brief Read all alias variables from hash map.
1267 *
1268 * Fill if parameter is negated, its ID, and alias type (variable, parameter, time).
1269 *
1270 * @param alias Alias variable to fill with values from hash map.
1271 * @param aliasHashMap Alias hash map.
1272 * @param nAliasVariables Number of alias variables in hash map.
1273 * @param mapAlias Hash map for alias variables.
1274 * @param mapAliasParam Hash map for alias parameters.
1275 */
1276 4 void read_alias_var(DATA_ALIAS* alias,
1277 omc_ModelVariables *aliasHashMap,
1278 unsigned long nAliasVariables,
1279 hash_string_long *mapAlias,
1280 hash_string_long *mapAliasParam)
1281 {
1282 // Assert nAliasVariables has correct size
1283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 size_t num_alias_vars_xml = HASH_COUNT(aliasHashMap);
1284
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 assertStreamPrint(NULL, nAliasVariables == num_alias_vars_xml, "Number of alias variables doesn't match up. Expected %lu but found %zu in XML!", nAliasVariables, num_alias_vars_xml);
1285
1286 long *it, *itParam;
1287 const char *aliasTmp = NULL;
1288
1289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 for(unsigned long i=0; i < nAliasVariables; i++)
1290 {
1291 ✗ read_var_info(*findHashLongVar(aliasHashMap, i), &alias[i].info);
1292
1293 /* Empty for the types that have no unit, and for an alias that declares none. */
1294 ✗ alias[i].unit = read_value_string(findHashStringStringEmpty(*findHashLongVar(aliasHashMap, i), "unit"));
1295 ✗ alias[i].displayUnit = read_value_string(findHashStringStringEmpty(*findHashLongVar(aliasHashMap, i), "displayUnit"));
1296 ✗ alias[i].relativeQuantity = read_value_bool(findHashStringStringEmpty(*findHashLongVar(aliasHashMap, i), "relativeQuantity"));
1297
1298 ✗ aliasTmp = omc_strdup(findHashStringStringNull(*findHashLongVar(aliasHashMap, i),"alias"));
1299 ✗ if (0 == strcmp(aliasTmp, "negatedAlias")) {
1300 ✗ alias[i].negate = 1;
1301 } else {
1302 ✗ alias[i].negate = 0;
1303 }
1304 ✗ infoStreamPrint(OMC_LOG_DEBUG, 0, "read for %s negated %d from setup file", alias[i].info.name, alias[i].negate);
1305
1306 ✗ alias[i].filterOutput = shouldFilterOutput(*findHashLongVar(aliasHashMap, i), alias[i].info.name);
1307
1308 ✗ free((char*)aliasTmp);
1309 aliasTmp = NULL;
1310
1311 ✗ aliasTmp = omc_strdup(findHashStringStringNull(*findHashLongVar(aliasHashMap, i),"aliasVariable"));
1312
1313 ✗ it = findHashStringLongPtr(mapAlias, aliasTmp);
1314 ✗ itParam = findHashStringLongPtr(mapAliasParam, aliasTmp);
1315
1316 ✗ if (NULL != it) {
1317 ✗ alias[i].nameID = *it;
1318 ✗ alias[i].aliasType = ALIAS_TYPE_VARIABLE;
1319 ✗ } else if (NULL != itParam) {
1320 ✗ alias[i].nameID = *itParam;
1321 ✗ alias[i].aliasType = ALIAS_TYPE_PARAMETER;
1322 ✗ } else if (0 == strcmp(aliasTmp, "time")) {
1323 ✗ alias[i].aliasType = ALIAS_TYPE_TIME;
1324 } else {
1325 ✗ throwStreamPrint(NULL, "Alias variable %s not found.", aliasTmp);
1326 }
1327 ✗ free((char*)aliasTmp);
1328 aliasTmp = NULL;
1329 }
1330 4 }
1331
1332 /**
1333 * @brief Reads initial values from init XML file.
1334 *
1335 * Can be FMI 1.0 modelDescription.xml or in a similar style.
1336 *
1337 * - Parse init XML file or content written in C with Expat.
1338 * - Checks GUID.
1339 * - Read number of variables / parameters from XML.
1340 * - Update initial values with overrides.
1341 * - Read default experiment.
1342 * - Read OPENMODELICAHOME.
1343 * - Allocates model data variables --> free with `freeModelDataVars`.
1344 * - Read all initial values into `modelData`.
1345 *
1346 * @param modelData Model data to update.
1347 * @param simulationInfo Simulation info to update.
1348 * @param threadData Thread data for error handling.
1349 */
1350 1 void read_input_xml(MODEL_DATA* modelData,
1351 SIMULATION_INFO* simulationInfo,
1352 threadData_t* threadData)
1353 {
1354 omc_ModelInput* mi;
1355
1356 const char *filename, *guid, *override, *overrideFile;
1357 1 hash_string_long *mapAlias = NULL, *mapAliasParam = NULL, *mapAliasSen = NULL;
1358 1 int sensitivityParIndex = 0;
1359
1360 1 filename = getXMLfileName(modelData->modelFilePrefix, threadData);
1361 1 mi = parse_input_xml(filename, modelData->initXMLData, threadData);
1362
1363 /* Check modelGUID */
1364 1 guid = findHashStringStringNull(mi->md, "guid");
1365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (NULL == guid) {
1366 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "The Model GUID: %s is not set in file: %s",
1367 modelData->modelGUID,
1368 filename);
1369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 } else if (strcmp(modelData->modelGUID, guid)) {
1370 ✗ throwStreamPrint(threadData, "GUID: %s from input data file: %s does not match the GUID compiled in the model: %s",
1371 guid,
1372 filename,
1373 modelData->modelGUID);
1374 }
1375
1376 // Read sizes before using them
1377 1 read_model_description_sizes(mi->md, modelData);
1378
1379 /* Update inital values from override flag */
1380 1 override = omc_flagValue[FLAG_OVERRIDE];
1381 1 overrideFile = omc_flagValue[FLAG_OVERRIDE_FILE];
1382 1 doOverride(mi, modelData, override, overrideFile);
1383
1384 /* Read initial values from hash map */
1385 1 read_experiment(simulationInfo, mi->de);
1386
1387 1 simulationInfo->OPENMODELICAHOME = GC_strdup(findHashStringString(mi->md,"OPENMODELICAHOME")); // Can be set by generated code
1388 1 infoStreamPrint(OMC_LOG_SIMULATION, 0, "OPENMODELICAHOME: %s", simulationInfo->OPENMODELICAHOME);
1389
1390 1 allocModelDataVars(modelData, TRUE, threadData);
1391
1392 1 read_variables(simulationInfo, VAR_TYPE_REAL, modelData->realVarsData, mi->rSta, "real states", 0, modelData->nStatesArray, &mapAlias, &mapAliasParam, &sensitivityParIndex);
1393 1 read_variables(simulationInfo, VAR_TYPE_REAL, modelData->realVarsData, mi->rDer, "real state derivatives", modelData->nStatesArray, modelData->nStatesArray, &mapAlias, &mapAliasParam, &sensitivityParIndex);
1394 1 read_variables(simulationInfo, VAR_TYPE_REAL, modelData->realVarsData, mi->rAlg, "real algebraics", 2*modelData->nStatesArray, modelData->nVariablesRealArray - 2*modelData->nStatesArray, &mapAlias, &mapAliasParam, &sensitivityParIndex);
1395
1396 1 read_variables(simulationInfo, VAR_TYPE_INTEGER, modelData->integerVarsData, mi->iAlg, "integer variables", 0, modelData->nVariablesIntegerArray, &mapAlias, &mapAliasParam, &sensitivityParIndex);
1397 1 read_variables(simulationInfo, VAR_TYPE_BOOLEAN, modelData->booleanVarsData, mi->bAlg, "boolean variables", 0, modelData->nVariablesBooleanArray, &mapAlias, &mapAliasParam, &sensitivityParIndex);
1398 1 read_variables(simulationInfo, VAR_TYPE_STRING, modelData->stringVarsData, mi->sAlg, "string variables", 0, modelData->nVariablesStringArray, &mapAlias, &mapAliasParam, &sensitivityParIndex);
1399
1400 1 read_variables(simulationInfo, VAR_TYPE_REAL, modelData->realParameterData, mi->rPar, "real parameters", 0, modelData->nParametersRealArray, &mapAliasParam, &mapAliasParam, &sensitivityParIndex);
1401 1 read_variables(simulationInfo, VAR_TYPE_INTEGER, modelData->integerParameterData, mi->iPar, "integer parameters", 0, modelData->nParametersIntegerArray, &mapAliasParam, &mapAliasParam, &sensitivityParIndex);
1402 1 read_variables(simulationInfo, VAR_TYPE_BOOLEAN, modelData->booleanParameterData, mi->bPar, "boolean parameters", 0, modelData->nParametersBooleanArray, &mapAliasParam, &mapAliasParam, &sensitivityParIndex);
1403 1 read_variables(simulationInfo, VAR_TYPE_STRING, modelData->stringParameterData, mi->sPar, "string parameters", 0, modelData->nParametersStringArray, &mapAliasParam, &mapAliasParam, &sensitivityParIndex);
1404
1405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (omc_flag[FLAG_IDAS]) {
1406 /* allocate memory for sensitivity analysis */
1407 ✗ simulationInfo->sensitivityParList = (int*) calloc(modelData->nSensitivityParamVars, sizeof(int));
1408 ✗ simulationInfo->sensitivityMatrix = (modelica_real*) calloc(modelData->nSensitivityVars - modelData->nSensitivityParamVars, sizeof(modelica_real));
1409
1410 // TODO: We also need nSensitivityVarsArray
1411 ✗ read_variables(simulationInfo, VAR_TYPE_REAL, modelData->realSensitivityData, mi->rSen, "real sensitivities", 0, modelData->nSensitivityVars, &mapAliasSen, &mapAliasParam, &sensitivityParIndex);
1412 }
1413
1414 /* Read all alias variables */
1415 1 infoStreamPrint(OMC_LOG_DEBUG, 0, "Read XML file for real alias vars");
1416 1 read_alias_var(modelData->realAlias, mi->rAli, modelData->nAliasRealArray, mapAlias, mapAliasParam);
1417 1 infoStreamPrint(OMC_LOG_DEBUG, 0, "Read XML file for integer alias vars");
1418 1 read_alias_var(modelData->integerAlias, mi->iAli, modelData->nAliasIntegerArray, mapAlias, mapAliasParam);
1419 1 infoStreamPrint(OMC_LOG_DEBUG, 0, "Read XML file for boolean alias vars");
1420 1 read_alias_var(modelData->booleanAlias, mi->bAli, modelData->nAliasBooleanArray, mapAlias, mapAliasParam);
1421 1 infoStreamPrint(OMC_LOG_DEBUG, 0, "Read XML file for string alias vars");
1422 1 read_alias_var(modelData->stringAlias, mi->sAli, modelData->nAliasStringArray, mapAlias, mapAliasParam);
1423
1424 1 calculateAllScalarLength(modelData);
1425
1426 1 free((char*)filename);
1427 1 freeHashStringString(mi->md);
1428 1 freeHashStringString(mi->de);
1429 1 freeHashLongVar(mi->rSta);
1430 1 freeHashLongVar(mi->rDer);
1431 1 freeHashLongVar(mi->rAlg);
1432 1 freeHashLongVar(mi->rPar);
1433 1 freeHashLongVar(mi->rAli);
1434 1 freeHashLongVar(mi->rSen);
1435 1 freeHashLongVar(mi->iAlg);
1436 1 freeHashLongVar(mi->iPar);
1437 1 freeHashLongVar(mi->iAli);
1438 1 freeHashLongVar(mi->bAlg);
1439 1 freeHashLongVar(mi->bPar);
1440 1 freeHashLongVar(mi->bAli);
1441 1 freeHashLongVar(mi->sAlg);
1442 1 freeHashLongVar(mi->sPar);
1443 1 freeHashLongVar(mi->sAli);
1444 1 freeHashStringLong(mapAlias);
1445 1 freeHashStringLong(mapAliasParam);
1446 1 freeHashStringLong(mapAliasSen);
1447 1 free(mi);
1448 1 }
1449
1450 /**
1451 * @brief Read double value from a string.
1452 *
1453 * @param s Null terminated string.
1454 * Treat string value `"true"` as `1.0` and `"false"`
1455 * as `0.0`.
1456 * @param default_value Default value to return if string is empty.
1457 * @return modelica_real Real value.
1458 */
1459 4 static inline modelica_real read_value_real_default(const char *s, modelica_real default_value)
1460 {
1461
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (*s == '\0') {
1462 return default_value;
1463
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (0 == strcmp(s, "true")) {
1464 return 1.0;
1465
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (0 == strcmp(s, "false")) {
1466 return 0.0;
1467 } else {
1468 4 return atof(s);
1469 }
1470 }
1471
1472 /**
1473 * @brief Read double value from a string.
1474 *
1475 * @param s Null terminated string.
1476 * Treat string value `"true"` as `1.0` and `"false"`
1477 * as `0.0`.
1478 * @return modelica_real Real value.
1479 */
1480 1 static inline modelica_real read_value_real(const char *s)
1481 {
1482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (*s == '\0') {
1483 ✗ throwStreamPrint(NULL, "read_value_real: Nothing to read!");
1484 }
1485
1486
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (0 == strcmp(s, "true")) {
1487 return 1.0;
1488
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 } else if (0 == strcmp(s, "false")) {
1489 return 0.0;
1490 } else {
1491 1 return atof(s);
1492 }
1493 }
1494
1495 /**
1496 * @brief Read long value from string.
1497 *
1498 * @param s Null terminated string to read.
1499 * Treat string value `"true"` as `1` and `"false"`
1500 * as `0`.
1501 * @param default_value Default value if string is empty.
1502 * @return modelica_integer Long integer.
1503 */
1504 40 static inline modelica_integer read_value_long(const char *s, modelica_integer default_value)
1505 {
1506
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 3 times.
40 if (s == NULL || *s == '\0') {
1507 return default_value;
1508
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 3 times.
34 } else if (0 == strcmp(s, "true")) {
1509 return 1;
1510
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 } else if (0 == strcmp(s, "false")) {
1511 return 0;
1512 } else {
1513 31 return atol(s);
1514 }
1515 }
1516
1517 /**
1518 * @brief Read int value from string.
1519 *
1520 * @param s Null terminated string to read.
1521 * Treat string value `"true"` as `1` and `"false"`
1522 * as `0`.
1523 * @param default_value Default value if string is empty.
1524 * @return modelica_integer Integer.
1525 */
1526 3 static inline int read_value_int(const char *s, int default_value)
1527 {
1528
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (s == NULL || *s == '\0') {
1529 return default_value;
1530
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 } else if (0 == strcmp(s, "true")) {
1531 return 1;
1532
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 } else if (0 == strcmp(s, "false")) {
1533 return 0;
1534 } else {
1535 3 return atoi(s);
1536 }
1537 }
1538
1539 /**
1540 * @brief Read boolean value from string.
1541 *
1542 * @param s Null terminated string to read.
1543 * @return modelica_boolean Return TRUE if string equals "true", FALSE otherwise.
1544 */
1545 static inline modelica_boolean read_value_bool(const char *s)
1546 {
1547
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
5 return 0 == strcmp(s, "true");
1548 }
1549
1550 /**
1551 * @brief Read modelica_string from a string
1552 *
1553 * @param s String
1554 * @return modelica_string Modelica string, owned by the slot it is stored in
1555 * and released by `freeModelDataVarArrays`.
1556 */
1557 static inline modelica_string read_value_string(const char *s)
1558 {
1559 4 return omc_string_new(s);
1560 }
1561
1562 ✗ static char* trim(char *str) {
1563 ✗ char *res=str,*end=str+strlen(str)-1;
1564 ✗ while (isspace(*res)) {
1565 ✗ res++;
1566 }
1567 ✗ while (isspace(*end)) {
1568 ✗ *end='\0';
1569 ✗ end--;
1570 }
1571 ✗ return res;
1572 }
1573
1574 static const char* getOverrideValue(omc_CommandLineOverrides *mOverrides, omc_CommandLineOverridesUses **mOverridesUses, const char *name)
1575 {
1576 ✗ addHashStringLong(mOverridesUses, name, OMC_OVERRIDE_USED);
1577 ✗ return findHashStringString(mOverrides, name);
1578 }
1579
1580 /**
1581 * @brief Check override and do override.
1582 *
1583 * Overwrite start value if variable is changeable. Otherwise add it to
1584 * `mOverridesUses`.
1585 *
1586 * @param mOverrides Command line overrides.
1587 * @param mOverridesUses
1588 * @param variables Hash map with variables to check override for.
1589 * @param index Index of variable in map `variables`.
1590 * @param warn_small_override Issue warning if overriding small value or zero if set to `1`.
1591 */
1592 ✗ static void singleOverride(omc_CommandLineOverrides *mOverrides,
1593 omc_CommandLineOverridesUses **mOverridesUses,
1594 omc_ModelVariables *variables,
1595 size_t index,
1596 int warn_small_override)
1597 {
1598 ✗ if (findHashStringStringNull(mOverrides, findHashStringString(*findHashLongVar(variables, index), "name")))
1599 {
1600 ✗ if (0 == strcmp(findHashStringString(*findHashLongVar(variables, index), "isValueChangeable"), "true"))
1601 {
1602 ✗ infoStreamPrint(OMC_LOG_SOLVER, 0,
1603 "override %s = %s",
1604 ✗ findHashStringString(*findHashLongVar(variables, index), "name"),
1605 ✗ getOverrideValue(mOverrides, mOverridesUses, findHashStringString(*findHashLongVar(variables, index), "name")));
1606 ✗ if (warn_small_override && fabs(atof(getOverrideValue(mOverrides, mOverridesUses, findHashStringString(*findHashLongVar(variables, index), "name")))) < 1e-6) {
1607 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0,
1608 "You are overriding %s with a small value or zero.\n"\
1609 "This could lead to numerically dirty solutions or divisions by zero if not tearingStrictness=veryStrict.",
1610 ✗ findHashStringString(*findHashLongVar(variables, index), "name"));
1611 }
1612 ✗ addHashStringString(
1613 ✗ findHashLongVar(variables, index),
1614 "start",
1615 ✗ getOverrideValue(mOverrides, mOverridesUses, findHashStringString(*findHashLongVar(variables, index), "name")));
1616 }
1617 else
1618 {
1619 ✗ addHashStringLong(
1620 mOverridesUses,
1621 ✗ findHashStringString(*findHashLongVar(variables, index), "name"), OMC_OVERRIDE_USED);
1622 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0,
1623 "It is not possible to override the following quantity: %s\n"\
1624 "It seems to be structural, final, protected or evaluated or has a non-constant binding.",
1625 ✗ findHashStringString(*findHashLongVar(variables, index), "name"));
1626 }
1627 }
1628 ✗ }
1629
1630 /**
1631 * @brief Read override values from simulation flags `-override` and `-overrideFile` and update variables.
1632 *
1633 * Return if step sizes needs to be re-calculated because start or stop time was changed, but step size wasn't changed.
1634 *
1635 * @param mi Model input from info XML file.
1636 * @param modelData Pointer to model data containing variable values to override.
1637 * @param overrideFile Path to override file given by `-overrideFile`.
1638 */
1639 1 void doOverride(omc_ModelInput *mi, MODEL_DATA *modelData, const char *override, const char *overrideFile)
1640 {
1641 1 omc_CommandLineOverrides *mOverrides = NULL;
1642 1 omc_CommandLineOverridesUses *mOverridesUses = NULL, *it = NULL, *ittmp = NULL;
1643 mmc_sint_t i;
1644 char* overrideStr1 = NULL, *overrideStr2 = NULL, *overrideStr = NULL;
1645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if((override != NULL) && (overrideFile != NULL)) {
1646 ✗ infoStreamPrint(OMC_LOG_SOLVER, 0, "using -override=%s and -overrideFile=%s", override, overrideFile);
1647 }
1648
1649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if(override != NULL) {
1650 ✗ overrideStr1 = omc_strdup(override);
1651 }
1652
1653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if(overrideFile != NULL) {
1654 FILE *infile = NULL;
1655 char *line=NULL, *tline=NULL, *tline2=NULL;
1656 char *overrideLine;
1657 size_t n=0;
1658
1659 /* read override values from file */
1660 ✗ infoStreamPrint(OMC_LOG_SOLVER, 0, "read override values from file: %s", overrideFile);
1661
1662 ✗ infile = omc_fopen(overrideFile, "rb");
1663 ✗ if (0==infile) {
1664 ✗ throwStreamPrint(NULL, "simulation_input_xml.c: could not open the file given to -overrideFile=%s", overrideFile);
1665 }
1666
1667 ✗ fseek(infile, 0L, SEEK_END);
1668 ✗ n = ftell(infile);
1669 ✗ line = (char*) malloc(n+1);
1670 ✗ line[0] = '\0';
1671 ✗ fseek(infile, 0L, SEEK_SET);
1672 ✗ errno = 0;
1673 ✗ if (1 != omc_fread(line, n, 1, infile, 0)) {
1674 ✗ free(line);
1675 ✗ throwStreamPrint(NULL, "simulation_input_xml.c: could not read overrideFile %s: %s", overrideFile, strerror(errno));
1676 }
1677 ✗ line[n] = '\0';
1678 ✗ overrideLine = (char*) malloc(n+1);
1679 ✗ overrideLine[0] = '\0';
1680 overrideStr2 = overrideLine;
1681 tline = line;
1682
1683 /* get the lines */
1684 ✗ while (0 != (tline2=strchr(tline,'\n'))) {
1685 ✗ *tline2 = '\0';
1686
1687 ✗ tline = trim(tline);
1688 // if is comment //, ignore line
1689 ✗ if (tline[0] && tline[0] != '/' && tline[1] != '/') {
1690 ✗ if (overrideLine != overrideStr2) {
1691 ✗ overrideLine[0] = ',';
1692 ✗ ++overrideLine;
1693 }
1694 ✗ overrideLine = strcpy(overrideLine,tline)+strlen(tline);
1695 }
1696 ✗ tline = tline2+1;
1697 }
1698 ✗ fclose(infile);
1699 ✗ free(line);
1700 }
1701
1702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (overrideStr1 != NULL || overrideStr2 != NULL) {
1703 char *value, *p, *ov;
1704 /* read override values */
1705 ✗ infoStreamPrint(OMC_LOG_SOLVER, 0, "-override=%s", overrideStr1 ? overrideStr1 : "[not given]");
1706 ✗ infoStreamPrint(OMC_LOG_SOLVER, 0, "-overrideFile=%s", overrideStr2 ? overrideStr2 : "[not given]");
1707 /* fix overrideStr to contain | instead of , for splitting */
1708 ✗ if (overrideStr1)
1709 {
1710 ✗ parseVariableStr(overrideStr1);
1711 ✗ p = strtok(overrideStr1, "!");
1712
1713 ✗ while (p) {
1714 // split it key = value => map[key]=value
1715 ✗ value = strchr(p, '=');
1716
1717 ✗ if (!value) {
1718 ✗ throwStreamPrint(NULL, "Invalid format for value of override flag: %s", override);
1719 }
1720
1721 ✗ if (*value == '\0') {
1722 ✗ warningStreamPrint(OMC_LOG_SOLVER, 0, "failed to parse override string %s", p);
1723 ✗ p = strtok(NULL, "!");
1724 }
1725 ✗ *value = '\0';
1726 ✗ value++;
1727 // map[key]=value
1728 // check if we already overrided this variable
1729 ✗ ov = (char*)findHashStringStringNull(mOverrides, p);
1730 ✗ if (ov)
1731 {
1732 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "You are overriding variable: %s=%s again with %s=%s.", p, ov, p, value);
1733 }
1734 ✗ addHashStringString(&mOverrides, p, value);
1735 ✗ addHashStringLong(&mOverridesUses, p, OMC_OVERRIDE_UNUSED);
1736
1737 // move to next
1738 ✗ p = strtok(NULL, "!");
1739 }
1740 ✗ free(overrideStr1);
1741 }
1742
1743 ✗ if (overrideStr2)
1744 {
1745 ✗ parseVariableStr(overrideStr2);
1746 ✗ p = strtok(overrideStr2, "!");
1747
1748 ✗ while (p) {
1749 // split it key = value => map[key]=value
1750 ✗ value = strchr(p, '=');
1751
1752 ✗ if (!value) {
1753 ✗ throwStreamPrint(NULL, "Invalid format for value of override flag: %s", override);
1754 }
1755
1756 ✗ if (*value == '\0') {
1757 ✗ warningStreamPrint(OMC_LOG_SOLVER, 0, "failed to parse override string %s", p);
1758 ✗ p = strtok(NULL, "!");
1759 }
1760 ✗ *value = '\0';
1761 ✗ value++;
1762 // map[key]=value
1763 ✗ ov = (char*)findHashStringStringNull(mOverrides, p);
1764 ✗ if (ov)
1765 {
1766 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "You are overriding variable: %s=%s again with %s=%s.", p, ov, p, value);
1767 }
1768 ✗ addHashStringString(&mOverrides, p, value);
1769 ✗ addHashStringLong(&mOverridesUses, p, OMC_OVERRIDE_UNUSED);
1770
1771 // move to next
1772 ✗ p = strtok(NULL, "!");
1773 }
1774 ✗ free(overrideStr2);
1775 }
1776
1777 /* remember the overridden quantities so importStartValues() (-iif) does not
1778 * clobber values the user explicitly set via -override/-overrideFile (#15807) */
1779 ✗ gCommandLineOverrides = mOverrides;
1780
1781 // override all found!
1782 ✗ for(i=0; i<modelData->nStatesArray; i++) {
1783 ✗ singleOverride(mOverrides, &mOverridesUses, mi->rSta, i, 0);
1784 ✗ singleOverride(mOverrides, &mOverridesUses, mi->rDer, i, 0);
1785 }
1786 ✗ for(i=0; i<(modelData->nVariablesRealArray - 2*modelData->nStatesArray); i++) {
1787 ✗ singleOverride(mOverrides, &mOverridesUses, mi->rAlg, i, 0);
1788 }
1789 ✗ for(i=0; i<modelData->nVariablesIntegerArray; i++) {
1790 ✗ singleOverride(mOverrides, &mOverridesUses, mi->iAlg, i, 0);
1791 }
1792 ✗ for(i=0; i<modelData->nVariablesBooleanArray; i++) {
1793 ✗ singleOverride(mOverrides, &mOverridesUses, mi->bAlg, i, 0);
1794 }
1795 ✗ for(i=0; i<modelData->nVariablesStringArray; i++) {
1796 ✗ singleOverride(mOverrides, &mOverridesUses, mi->sAlg, i, 0);
1797 }
1798 ✗ for(i=0; i<modelData->nParametersRealArray; i++) {
1799 // TODO: only allow to override primary parameters
1800 ✗ singleOverride(mOverrides, &mOverridesUses, mi->rPar, i, 1);
1801 }
1802 ✗ for(i=0; i<modelData->nParametersIntegerArray; i++) {
1803 // TODO: only allow to override primary parameters
1804 ✗ singleOverride(mOverrides, &mOverridesUses, mi->iPar, i, 1);
1805 }
1806 ✗ for(i=0; i<modelData->nParametersBooleanArray; i++) {
1807 // TODO: only allow to override primary parameters
1808 ✗ singleOverride(mOverrides, &mOverridesUses, mi->bPar, i, 0);
1809 }
1810 ✗ for(i=0; i<modelData->nParametersStringArray; i++) {
1811 // TODO: only allow to override primary parameters
1812 ✗ singleOverride(mOverrides, &mOverridesUses, mi->sPar, i, 0);
1813 }
1814 ✗ for(i=0; i<modelData->nAliasRealArray; i++) {
1815 ✗ singleOverride(mOverrides, &mOverridesUses, mi->rAli, i, 0);
1816 }
1817 ✗ for(i=0; i<modelData->nAliasIntegerArray; i++) {
1818 ✗ singleOverride(mOverrides, &mOverridesUses, mi->iAli, i, 0);
1819 }
1820 ✗ for(i=0; i<modelData->nAliasBooleanArray; i++) {
1821 ✗ singleOverride(mOverrides, &mOverridesUses, mi->bAli, i, 0);
1822 }
1823 ✗ for(i=0; i<modelData->nAliasStringArray; i++) {
1824 ✗ singleOverride(mOverrides, &mOverridesUses, mi->sAli, i, 0);
1825 }
1826
1827 // give a warning if an override is not used #3204
1828 ✗ HASH_ITER(hh, mOverridesUses, it, ittmp) {
1829 ✗ if (it->val == OMC_OVERRIDE_UNUSED) {
1830 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "simulation_input_xml.c: override variable name not found in model: %s\n", it->id);
1831 }
1832 }
1833 ✗ freeHashStringLong(mOverridesUses);
1834
1835 ✗ infoStreamPrint(OMC_LOG_SOLVER, 0, "override done!");
1836 } else {
1837 1 infoStreamPrint(OMC_LOG_SOLVER, 0, "NO override given on the command line.");
1838 }
1839 1 }
1840
1841 /**
1842 * @brief Check whether a quantity was overridden on the command line.
1843 *
1844 * Used to make sure that values explicitly set via -override/-overrideFile are
1845 * not clobbered when importing start values from a file given with -iif (#15807).
1846 *
1847 * @param name Fully qualified name of the variable or parameter.
1848 * @return int 1 if the quantity was given via -override/-overrideFile, 0 otherwise.
1849 */
1850 ✗ int isQuantityOverridden(const char *name)
1851 {
1852 ✗ return (gCommandLineOverrides != NULL) && (findHashStringStringNull(gCommandLineOverrides, name) != NULL);
1853 }
1854
1855 ✗ void parseVariableStr(char* variableStr)
1856 {
1857 /* TODO! FIXME!: support also quoted identifiers containing comma: , */
1858 unsigned int i = 0, insideArray = 0;
1859 ✗ for (i = 0; i < strlen(variableStr); i++)
1860 {
1861 ✗ if (variableStr[i] == '[') { insideArray = 1; }
1862 ✗ if (variableStr[i] == ']') { insideArray = 0; }
1863 ✗ if ((insideArray == 0) && (variableStr[i] == ',')) { variableStr[i] = '!'; }
1864 }
1865 ✗ }
1866