]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMILibrary/src/XML/src/FMI1/fmi1_xml_variable.c
Add FMILibrary-2.0.3 to org.simantics.fmil.core\native.
[simantics/fmil.git] / org.simantics.fmil.core / native / FMILibrary / src / XML / src / FMI1 / fmi1_xml_variable.c
1 /*
2     Copyright (C) 2012 Modelon AB
3
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the BSD style license.
6
7      This program is distributed in the hope that it will be useful,
8     but WITHOUT ANY WARRANTY; without even the implied warranty of
9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10     FMILIB_License.txt file for more details.
11
12     You should have received a copy of the FMILIB_License.txt file
13     along with this program. If not, contact Modelon AB <http://www.modelon.com>.
14 */
15
16 #include <string.h>
17 #include <stdio.h>
18
19 #include <JM/jm_vector.h>
20
21 #include "fmi1_xml_parser.h"
22 #include "fmi1_xml_type_impl.h"
23 #include "fmi1_xml_model_description_impl.h"
24
25 #include "fmi1_xml_variable_impl.h"
26
27 static const char* module = "FMI1XML";
28
29 const char* fmi1_xml_get_variable_name(fmi1_xml_variable_t* v) {
30     return v->name;
31 }
32
33 const char* fmi1_xml_get_variable_description(fmi1_xml_variable_t* v) {
34     return v->description;
35 }
36
37 size_t fmi1_xml_get_variable_original_order(fmi1_xml_variable_t* v) {
38         return v->originalIndex;
39 }
40
41 fmi1_value_reference_t fmi1_xml_get_variable_vr(fmi1_xml_variable_t* v) {
42     return v->vr;
43 }
44
45 fmi1_variable_alias_kind_enu_t fmi1_xml_get_variable_alias_kind(fmi1_xml_variable_t* v) {
46     return (fmi1_variable_alias_kind_enu_t)v->aliasKind;
47 }
48
49 fmi1_xml_variable_t* fmi1_xml_get_variable_alias_base(fmi1_xml_model_description_t* md, fmi1_xml_variable_t* v) {
50     fmi1_xml_variable_t key;
51     fmi1_xml_variable_t *pkey = &key, *base;
52     void ** found;
53     if(!md->variablesByVR) return 0;
54     if(v->aliasKind == fmi1_variable_is_not_alias) return v;
55     key = *v;
56     key.aliasKind = fmi1_variable_is_not_alias;
57
58     found = jm_vector_bsearch(jm_voidp)(md->variablesByVR,(void**)&pkey, fmi1_xml_compare_vr);
59     assert(found);
60     base = *found;
61     return base;
62 }
63
64 /*
65     Return the list of all the variables aliased to the given one (including the base one.
66     The list is ordered: base variable, aliases, negated aliases.
67 */
68 jm_status_enu_t fmi1_xml_get_variable_aliases(fmi1_xml_model_description_t* md,fmi1_xml_variable_t* v, jm_vector(jm_voidp)* list) {
69     fmi1_xml_variable_t key, *cur;
70     fmi1_value_reference_t vr = fmi1_xml_get_variable_vr(v);
71     size_t baseIndex, i, num = jm_vector_get_size(jm_voidp)(md->variablesByVR);
72     key = *v;
73     key.aliasKind = 0;
74     cur = &key;
75     baseIndex = jm_vector_bsearch_index(jm_voidp)(md->variablesByVR,(void**)&cur, fmi1_xml_compare_vr);
76     cur = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesByVR, baseIndex);
77     assert(cur);
78     i = baseIndex + 1;
79     while(fmi1_xml_get_variable_vr(cur) == vr) {
80         if(!jm_vector_push_back(jm_voidp)(list, cur)) {
81                         jm_log_fatal(md->callbacks,module,"Could not allocate memory");
82             return jm_status_error;
83         };
84         if(i >= num) break;
85         cur = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesByVR, i);
86         assert(cur);
87         i++;
88     }
89     if(baseIndex) {
90         i = baseIndex - 1;
91         cur = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesByVR, i);
92         while(fmi1_xml_get_variable_vr(cur) == vr) {
93             if(!jm_vector_push_back(jm_voidp)(list, cur)) {
94                 jm_log_fatal(md->callbacks,module,"Could not allocate memory");
95                 return jm_status_error;
96             };
97             i--;
98             if(!i) break;
99             cur = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesByVR, i - 1);
100             assert(cur);
101         }
102     }
103     return jm_status_success;
104 }
105
106
107 fmi1_xml_variable_typedef_t* fmi1_xml_get_variable_declared_type(fmi1_xml_variable_t* v) {
108     return (fmi1_xml_variable_typedef_t*)(fmi1_xml_find_type_struct(v->typeBase, fmi1_xml_type_struct_enu_typedef));
109 }
110
111 fmi1_base_type_enu_t fmi1_xml_get_variable_base_type(fmi1_xml_variable_t* v) {
112     fmi1_xml_variable_type_base_t* type = v->typeBase;
113     type = fmi1_xml_find_type_struct(type, fmi1_xml_type_struct_enu_base);
114     return (type->baseType);
115 }
116
117 int fmi1_xml_get_variable_has_start(fmi1_xml_variable_t* v) {
118     return (v->typeBase->structKind == fmi1_xml_type_struct_enu_start);
119 }
120
121 int   fmi1_xml_get_variable_is_fixed(fmi1_xml_variable_t* v) {
122     fmi1_xml_variable_type_base_t* type = v->typeBase;
123     return ((type->structKind == fmi1_xml_type_struct_enu_start) && (type->isFixed));
124 }
125
126 fmi1_variability_enu_t fmi1_xml_get_variability(fmi1_xml_variable_t* v) {
127     return (fmi1_variability_enu_t)v->variability;
128 }
129
130 fmi1_causality_enu_t fmi1_xml_get_causality(fmi1_xml_variable_t* v) {
131     return (fmi1_causality_enu_t)v->causality;
132 }
133
134 double fmi1_xml_get_real_variable_start(fmi1_xml_real_variable_t* v) {
135     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
136     if(fmi1_xml_get_variable_has_start(vv)) {
137         fmi1_xml_variable_start_real_t* start = (fmi1_xml_variable_start_real_t*)(vv->typeBase);
138         return start->start;
139     }
140         return fmi1_xml_get_real_variable_nominal(v);
141 }
142
143 fmi1_xml_unit_t* fmi1_xml_get_real_variable_unit(fmi1_xml_real_variable_t* v) {
144     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
145     fmi1_xml_real_type_props_t* props = (fmi1_xml_real_type_props_t*)(fmi1_xml_find_type_struct(vv->typeBase, fmi1_xml_type_struct_enu_props));
146     if(!props || !props->displayUnit) return 0;
147     return props->displayUnit->baseUnit;
148 }
149
150 fmi1_xml_display_unit_t* fmi1_xml_get_real_variable_display_unit(fmi1_xml_real_variable_t* v) {
151     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
152     fmi1_xml_real_type_props_t* props = (fmi1_xml_real_type_props_t*)(fmi1_xml_find_type_struct(vv->typeBase, fmi1_xml_type_struct_enu_props));
153     if(!props || !props->displayUnit || !props->displayUnit->displayUnit[0]) return 0;
154     return props->displayUnit;
155 }
156
157 double fmi1_xml_get_real_variable_max(fmi1_xml_real_variable_t* v) {
158     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
159     fmi1_xml_real_type_props_t* props = (fmi1_xml_real_type_props_t*)(fmi1_xml_find_type_props(vv->typeBase));
160         assert(props);
161         return props->typeMax;
162 }
163
164 double fmi1_xml_get_real_variable_min(fmi1_xml_real_variable_t* v) {
165     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
166     fmi1_xml_real_type_props_t* props = (fmi1_xml_real_type_props_t*)(fmi1_xml_find_type_props(vv->typeBase));
167         assert(props);
168         return props->typeMin;
169 }
170
171 double fmi1_xml_get_real_variable_nominal(fmi1_xml_real_variable_t* v){
172     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
173     fmi1_xml_real_type_props_t* props = (fmi1_xml_real_type_props_t*)(fmi1_xml_find_type_props(vv->typeBase));
174         assert(props);
175         return props->typeNominal;
176 }
177
178 int fmi1_xml_get_integer_variable_start(fmi1_xml_integer_variable_t* v){
179     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
180     if(fmi1_xml_get_variable_has_start(vv)) {
181         fmi1_xml_variable_start_integer_t* start = (fmi1_xml_variable_start_integer_t*)(vv->typeBase);
182         return start->start;
183     }
184         return 0;
185 }
186
187 int fmi1_xml_get_integer_variable_min(fmi1_xml_integer_variable_t* v){
188     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
189     fmi1_xml_integer_type_props_t* props = (fmi1_xml_integer_type_props_t*)(fmi1_xml_find_type_props(vv->typeBase));
190         assert(props);
191         return props->typeMin;
192 }
193
194 int fmi1_xml_get_integer_variable_max(fmi1_xml_integer_variable_t* v){
195     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
196     fmi1_xml_integer_type_props_t* props = (fmi1_xml_integer_type_props_t*)(fmi1_xml_find_type_props(vv->typeBase));
197         assert(props);
198         return props->typeMax;
199 }
200
201 int fmi1_xml_get_enum_variable_min(fmi1_xml_enum_variable_t* v){
202     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
203     fmi1_xml_enum_type_props_t* props = (fmi1_xml_enum_type_props_t*)(fmi1_xml_find_type_props(vv->typeBase));
204         assert(props);
205         return props->typeMin;
206 }
207
208 int fmi1_xml_get_enum_variable_max(fmi1_xml_enum_variable_t* v){
209     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
210     fmi1_xml_enum_type_props_t* props = (fmi1_xml_enum_type_props_t*)(fmi1_xml_find_type_props(vv->typeBase));
211         assert(props);
212         return props->typeMax;
213 }
214
215 const char* fmi1_xml_get_string_variable_start(fmi1_xml_string_variable_t* v){
216     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
217     if(fmi1_xml_get_variable_has_start(vv)) {
218         fmi1_xml_variable_start_string_t* start = (fmi1_xml_variable_start_string_t*)(vv->typeBase);
219         return start->start;
220     }
221     return 0;
222 }
223
224 int fmi1_xml_get_enum_variable_start(fmi1_xml_enum_variable_t* v) {
225     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
226     if(fmi1_xml_get_variable_has_start(vv)) {
227         fmi1_xml_variable_start_integer_t* start = (fmi1_xml_variable_start_integer_t*)(vv->typeBase);
228         return start->start;
229     }
230         return 0;
231 }
232
233 fmi1_boolean_t fmi1_xml_get_boolean_variable_start(fmi1_xml_bool_variable_t* v) {
234     fmi1_xml_variable_t* vv = (fmi1_xml_variable_t*)v;
235     if(fmi1_xml_get_variable_has_start(vv)) {
236         fmi1_xml_variable_start_integer_t* start = (fmi1_xml_variable_start_integer_t*)(vv->typeBase);
237         return start->start;
238     }
239         return 0;
240 }
241
242 size_t fmi1_xml_get_direct_dependency_size(fmi1_xml_model_description_t* md,fmi1_xml_variable_t*v) {
243         if(v->directDependency) {
244                 return jm_vector_get_size(jm_voidp)(v->directDependency);
245         }
246         else{
247                 return jm_vector_get_size(jm_voidp)(md->inputVariables);
248         }
249 }
250
251 /* DirectDependency is returned for variables with causality Output. Null pointer for others. */
252 jm_status_enu_t fmi1_xml_get_direct_dependency(fmi1_xml_model_description_t* md, fmi1_xml_variable_t* v, jm_vector(jm_voidp)* list) {
253         size_t size = 0;
254         if(fmi1_xml_get_causality(v) != fmi1_causality_enu_output) return jm_status_error;
255         jm_vector_resize(jm_voidp)(list, 0);
256         if(v->directDependency) {
257                 size = jm_vector_get_size(jm_voidp)(v->directDependency);
258                 if(jm_vector_reserve(jm_voidp)(list, size) < size) return jm_status_error;
259                 jm_vector_copy(jm_voidp)(list,v->directDependency);
260         }
261         /*no direct dependency defined, deliver all inputs, see FMI for ME spec. p 38.*/
262         else{
263                 if (md->inputVariables){
264                         jm_vector_copy(jm_voidp)(list,md->inputVariables);
265                 }
266                 else {
267                         jm_log_error(md->callbacks,module, "List of input variables not found.");
268                 }
269         }
270         return jm_status_success;
271 }
272
273 fmi1_xml_real_variable_t* fmi1_xml_get_variable_as_real(fmi1_xml_variable_t* v) {
274     if(fmi1_xml_get_variable_base_type(v) == fmi1_base_type_real)  return (void*)v;
275     return 0;
276 }
277
278 fmi1_xml_integer_variable_t* fmi1_xml_get_variable_as_integer(fmi1_xml_variable_t*v){
279     if(fmi1_xml_get_variable_base_type(v) == fmi1_base_type_int)  return (void*)v;
280     return 0;
281 }
282 fmi1_xml_enum_variable_t* fmi1_xml_get_variable_as_enum(fmi1_xml_variable_t* v){
283     if(fmi1_xml_get_variable_base_type(v) == fmi1_base_type_enum)  return (void*)v;
284     return 0;
285 }
286 fmi1_xml_string_variable_t* fmi1_xml_get_variable_as_string(fmi1_xml_variable_t* v){
287     if(fmi1_xml_get_variable_base_type(v) == fmi1_base_type_str)  return (void*)v;
288     return 0;
289 }
290 fmi1_xml_bool_variable_t* fmi1_xml_get_variable_as_boolean(fmi1_xml_variable_t* v){
291     if(fmi1_xml_get_variable_base_type(v) == fmi1_base_type_bool)  return (void*)v;
292     return 0;
293 }
294
295 void fmi1_xml_free_direct_dependencies(jm_named_ptr named) {
296         fmi1_xml_variable_t* v = named.ptr;
297         if(v->directDependency) {
298                 jm_vector_free(jm_voidp)(v->directDependency);
299                 v->directDependency = 0;
300         }
301 }
302
303 int fmi1_xml_handle_ScalarVariable(fmi1_xml_parser_context_t *context, const char* data) {
304     if(!data) {
305             fmi1_xml_model_description_t* md = context->modelDescription;
306             fmi1_xml_variable_t* variable;
307             fmi1_xml_variable_t dummyV;
308             const char* description = 0;
309             jm_named_ptr named, *pnamed;
310             jm_vector(char)* bufName = fmi1_xml_reserve_parse_buffer(context,1,100);
311             jm_vector(char)* bufDescr = fmi1_xml_reserve_parse_buffer(context,2,100);
312             unsigned int vr;
313
314             if(!bufName || !bufDescr) return -1;
315
316             /*   <xs:attribute name="valueReference" type="xs:unsignedInt" use="required"> */
317             if(fmi1_xml_set_attr_uint(context, fmi1_xml_elmID_ScalarVariable, fmi_attr_id_valueReference, 1, &vr, 0)) return -1;
318
319             if(vr == fmi1_undefined_value_reference) {
320                 context->skipOneVariableFlag = 1;
321             }
322
323             if(
324             /*  <xs:attribute name="name" type="xs:normalizedString" use="required"/> */
325                 fmi1_xml_set_attr_string(context, fmi1_xml_elmID_ScalarVariable, fmi_attr_id_name, 1, bufName) ||
326             /* <xs:attribute name="description" type="xs:string"/> */
327                 fmi1_xml_set_attr_string(context, fmi1_xml_elmID_ScalarVariable, fmi_attr_id_description, 0, bufDescr)
328             ) return -1;
329
330             if(context->skipOneVariableFlag) {
331                                 jm_log_error(context->callbacks,module, "Ignoring variable with undefined vr '%s'", jm_vector_get_itemp(char)(bufName,0));
332                 return 0;
333             }
334             if(jm_vector_get_size(char)(bufDescr)) {
335                 description = jm_string_set_put(&md->descriptions, jm_vector_get_itemp(char)(bufDescr,0));
336             }
337
338             named.ptr = 0;
339                         named.name = 0;
340             pnamed = jm_vector_push_back(jm_named_ptr)(&md->variablesByName, named);
341
342             if(pnamed) *pnamed = named = jm_named_alloc_v(bufName,sizeof(fmi1_xml_variable_t), dummyV.name - (char*)&dummyV, context->callbacks);
343             variable = named.ptr;
344             if( !pnamed || !variable ) {
345                 fmi1_xml_parse_fatal(context, "Could not allocate memory");
346                 return -1;
347             }
348             variable->vr = vr;
349             variable->description = description;
350             variable->typeBase = 0;
351             variable->directDependency = 0;
352                         variable->originalIndex = jm_vector_get_size(jm_named_ptr)(&md->variablesByName) - 1;
353
354               {
355                 jm_name_ID_map_t variabilityConventionMap[] = {{"continuous",fmi1_variability_enu_continuous},
356                                                                {"constant", fmi1_variability_enu_constant},
357                                                                {"parameter", fmi1_variability_enu_parameter},
358                                                                {"discrete", fmi1_variability_enu_discrete},{0,0}};
359                 unsigned int variability;
360                 /*  <xs:attribute name="variability" default="continuous"> */
361                 if(fmi1_xml_set_attr_enum(context, fmi1_xml_elmID_ScalarVariable, fmi_attr_id_variability,0,&variability,fmi1_variability_enu_continuous,variabilityConventionMap))
362                     return -1;
363                 variable->variability = variability;
364             }
365             {
366                 jm_name_ID_map_t causalityConventionMap[] = {{"internal",fmi1_causality_enu_internal},
367                                                              {"input",fmi1_causality_enu_input},
368                                                              {"output",fmi1_causality_enu_output},
369                                                              {"none",fmi1_causality_enu_none},{0,0}};
370                 /* <xs:attribute name="causality" default="internal"> */
371                 unsigned int causality;
372                 if(fmi1_xml_set_attr_enum(context, fmi1_xml_elmID_ScalarVariable, fmi_attr_id_causality,0,&causality,fmi1_causality_enu_internal,causalityConventionMap))
373                     return -1;
374                 variable->causality = causality;
375             }
376             {
377                 jm_name_ID_map_t aliasConventionMap[] = {{"alias", 1},
378                                                          {"negatedAlias", 2},
379                                                          {"noAlias", 0}, {0,0}};
380                 unsigned int alias;
381                 /* <xs:attribute name="alias" default="noAlias"> */
382                 if(fmi1_xml_set_attr_enum(context, fmi1_xml_elmID_ScalarVariable, fmi_attr_id_alias ,0,&alias,0,aliasConventionMap))
383                     return -1;
384                 if(alias == 0) variable->aliasKind = fmi1_variable_is_not_alias;
385                 else if (alias == 1) variable->aliasKind = fmi1_variable_is_alias;
386                 else if (alias == 2) variable->aliasKind = fmi1_variable_is_negated_alias;
387                 else assert(0);
388             }
389     }
390     else {
391         if(context->skipOneVariableFlag) {
392             context->skipOneVariableFlag = 0;
393         }
394         else {
395             /* check that the type for the variable is set */
396             fmi1_xml_model_description_t* md = context->modelDescription;
397             fmi1_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
398             if(!variable->typeBase) {
399                                 jm_log_error(context->callbacks, module, "No variable type element for variable %s. Assuming Real.", variable->name);
400
401                                 return fmi1_xml_handle_Real(context, data);
402             }
403         }
404         /* might give out a warning if(data[0] != 0) */
405     }
406     return 0;
407 }
408
409
410 int fmi1_xml_handle_DirectDependency(fmi1_xml_parser_context_t *context, const char* data) {
411     if(context->skipOneVariableFlag) return 0;
412     if(!data) {
413         fmi1_xml_model_description_t* md = context->modelDescription;
414         fmi1_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
415         if(variable->causality != fmi1_causality_enu_output) {
416                         jm_log_error(context->callbacks,module,
417                                 "DirectDependency XML element cannot be defined for '%s' since causality is not output. Skipping.", variable->name);
418                         context->skipElementCnt = 1;
419             return 0;
420         }
421     }
422     else {
423         fmi1_xml_model_description_t* md = context->modelDescription;
424         fmi1_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
425         /*
426         - always create the list to be able to differentiate no depedendencies from all dependencies (no DirectDependency element present)
427         if(jm_vector_get_size(jm_voidp)(&context->directDependencyBuf))
428         */
429         {
430             variable->directDependency = jm_vector_clone(jm_voidp)(&context->directDependencyBuf);
431             if(!variable->directDependency) {
432                 fmi1_xml_parse_fatal(context, "Could not allocate memory");
433                 return -1;
434             }
435         }
436         jm_vector_resize(jm_voidp)(&context->directDependencyBuf,0);
437     }
438     return 0;
439 }
440
441 int fmi1_xml_handle_Name(fmi1_xml_parser_context_t *context, const char* data) {
442     if(context->skipOneVariableFlag) return 0;
443
444     if(!data) {
445                 return 0;
446     }
447     else {
448         fmi1_xml_model_description_t* md = context->modelDescription;
449         fmi1_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
450         size_t namelen = strlen(data), i = 0, j;
451         char* name = 0;
452         jm_voidp* itemp;
453         jm_string* namep;
454 #define TRIM_SPACE " \n\r\t"
455                 if(namelen) {
456                         while(strchr(TRIM_SPACE, data[i])) i++;
457                         while(strchr(TRIM_SPACE, data[namelen-1])) namelen--;
458                 }
459         if(i>=namelen) {
460                         jm_log_error(context->callbacks, module,
461                                 "Unexpected empty Name element for DirectDependency of variable %s. Ignoring.", variable->name);
462             return 0;
463         }
464         namep = jm_vector_push_back(jm_string)(&context->directDependencyStringsStore, name);
465         if(namep) *namep = name = context->callbacks->malloc(namelen + 1);
466         itemp = jm_vector_push_back(jm_voidp)(&context->directDependencyBuf, name);
467         if(!namep || !itemp || !name)  {
468             fmi1_xml_parse_fatal(context, "Could not allocate memory");
469             return -1;
470         }
471                 for(j = 0; i<namelen;i++) {
472                         name[j++] = data[i];
473                 }
474                 name[j] = 0;
475     }
476     return 0;
477 }
478
479 static void fmi1_log_error_if_start_required(
480     fmi1_xml_parser_context_t *context,
481     fmi1_xml_variable_t *variable)
482 {
483     if (fmi1_xml_is_attr_defined(context, fmi_attr_id_fixed)) {
484         jm_log_error(context->callbacks, module,
485                        "Error: variable %s: 'fixed' attributed is only allowed when start is defined",
486                        variable->name);
487
488     } else if (variable->causality == fmi1_causality_enu_input) {
489         jm_log_error(context->callbacks, module,
490                        "Error: variable %s: start value required for input variables",
491                        variable->name);
492     }
493 }
494
495 int fmi1_xml_handle_Real(fmi1_xml_parser_context_t *context, const char* data) {
496     fmi1_xml_model_description_t* md = context->modelDescription;
497     fmi1_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
498     fmi1_xml_type_definitions_t* td = &md->typeDefinitions;
499     fmi1_xml_variable_type_base_t * declaredType = 0;
500     fmi1_xml_real_type_props_t * type = 0;
501     int hasStart;
502
503     if(context->skipOneVariableFlag){
504         return 0;
505     } else if(data) {
506         /* don't do anything. might give out a warning if(data[0] != 0) */
507         return 0;
508     }
509     assert(!variable->typeBase);
510
511     declaredType = fmi1_get_declared_type(context, fmi1_xml_elmID_Real, &td->defaultRealType.typeBase);
512
513     if(!declaredType) return -1;
514
515     {
516         int hasUnit = fmi1_xml_is_attr_defined(context, fmi_attr_id_unit) ||
517                 fmi1_xml_is_attr_defined(context, fmi_attr_id_displayUnit);
518         int hasMin =  fmi1_xml_is_attr_defined(context, fmi_attr_id_min);
519         int hasMax = fmi1_xml_is_attr_defined(context, fmi_attr_id_max);
520         int hasNom = fmi1_xml_is_attr_defined(context, fmi_attr_id_nominal);
521         int hasQuan = fmi1_xml_is_attr_defined(context, fmi_attr_id_quantity);
522         int hasRelQ = fmi1_xml_is_attr_defined(context, fmi_attr_id_relativeQuantity);
523
524
525         if(hasUnit || hasMin || hasMax || hasNom || hasQuan || hasRelQ) {
526             fmi1_xml_real_type_props_t* props = 0;
527
528             if(declaredType->structKind == fmi1_xml_type_struct_enu_typedef)
529                 props = (fmi1_xml_real_type_props_t*)(declaredType->baseTypeStruct);
530             else
531                 props = (fmi1_xml_real_type_props_t* )declaredType;
532
533             fmi1_xml_reserve_parse_buffer(context, 1, 0);
534             fmi1_xml_reserve_parse_buffer(context, 2, 0);
535
536             type = fmi1_xml_parse_real_type_properties(context, fmi1_xml_elmID_Real);
537
538             if(!type) return -1;
539             type->typeBase.baseTypeStruct = declaredType;
540             if( !hasUnit) type->displayUnit = props->displayUnit;
541             if( !hasMin)  type->typeMin = props->typeMin;
542             if( !hasMax) type->typeMax = props->typeMax;
543             if( !hasNom) type->typeNominal = props->typeNominal;
544             if( !hasQuan) type->quantity = props->quantity;
545             if( !hasRelQ) type->typeBase.relativeQuantity = props->typeBase.relativeQuantity;
546         }
547         else
548             type = (fmi1_xml_real_type_props_t*)declaredType;
549     }
550     variable->typeBase = &type->typeBase;
551
552     hasStart = fmi1_xml_is_attr_defined(context, fmi_attr_id_start);
553     if(hasStart) {
554         fmi1_xml_variable_start_real_t * start = (fmi1_xml_variable_start_real_t*)fmi1_xml_alloc_variable_type_start(td, &type->typeBase, sizeof(fmi1_xml_variable_start_real_t));
555         int isFixedBuf;
556         if(!start) {
557             fmi1_xml_parse_fatal(context, "Could not allocate memory");
558             return -1;
559         }
560         if(
561             /*  <xs:attribute name="start" type="xs:double"/> */
562                 fmi1_xml_set_attr_double(context, fmi1_xml_elmID_Real, fmi_attr_id_start, 0, &start->start, 0) ||
563             /*  <xs:attribute name="fixed" type="xs:boolean"> */
564                 fmi1_xml_set_attr_boolean(context, fmi1_xml_elmID_Real, fmi_attr_id_fixed, 0, &(isFixedBuf), 1)
565             )
566                 return -1;
567         start->typeBase.isFixed = isFixedBuf;
568         variable->typeBase = &start->typeBase;
569     } else {
570         fmi1_log_error_if_start_required(context, variable);
571     }
572
573     return 0;
574 }
575
576 int fmi1_xml_handle_Integer(fmi1_xml_parser_context_t *context, const char* data) {
577     fmi1_xml_model_description_t* md = context->modelDescription;
578     fmi1_xml_type_definitions_t* td = &md->typeDefinitions;
579     fmi1_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
580     fmi1_xml_variable_type_base_t * declaredType = 0;
581     fmi1_xml_integer_type_props_t * type = 0;
582     int hasStart;
583
584     if (context->skipOneVariableFlag) {
585         return 0;
586     } else if (data) {
587         /* don't do anything. might give out a warning if(data[0] != 0) */
588         return 0;
589     }
590
591     declaredType = fmi1_get_declared_type(context, fmi1_xml_elmID_Integer,&td->defaultIntegerType.typeBase) ;
592
593     if(!declaredType) return -1;
594
595     {
596         int hasQuan = fmi1_xml_is_attr_defined(context, fmi_attr_id_quantity);
597         int hasMin =  fmi1_xml_is_attr_defined(context, fmi_attr_id_min);
598         int hasMax = fmi1_xml_is_attr_defined(context, fmi_attr_id_max);
599
600         if(hasQuan ||hasMin || hasMax) {
601                 fmi1_xml_integer_type_props_t* props = 0;
602
603                 if(declaredType->structKind != fmi1_xml_type_struct_enu_typedef)
604                     props = (fmi1_xml_integer_type_props_t*)declaredType;
605                 else
606                     props = (fmi1_xml_integer_type_props_t*)(declaredType->baseTypeStruct);
607                 assert((props->typeBase.structKind == fmi1_xml_type_struct_enu_props) || (props->typeBase.structKind == fmi1_xml_type_struct_enu_base));
608                 fmi1_xml_reserve_parse_buffer(context, 1, 0);
609                 fmi1_xml_reserve_parse_buffer(context, 2, 0);
610                 type = fmi1_xml_parse_integer_type_properties(context, fmi1_xml_elmID_Integer);
611                 if(!type) return -1;
612                 type->typeBase.baseTypeStruct = declaredType;
613                 if(!hasMin) type->typeMin = props->typeMin;
614                 if(!hasMax) type->typeMax = props->typeMax;
615                 if(!hasQuan) type->quantity = props->quantity;
616         }
617         else
618             type = (fmi1_xml_integer_type_props_t*)declaredType;
619     }
620     variable->typeBase = &type->typeBase;
621
622     hasStart = fmi1_xml_is_attr_defined(context,fmi_attr_id_start);
623     if(hasStart) {
624         fmi1_xml_variable_start_integer_t * start = (fmi1_xml_variable_start_integer_t*)fmi1_xml_alloc_variable_type_start(td, &type->typeBase, sizeof(fmi1_xml_variable_start_integer_t));
625         int isFixedBuf;
626         if(!start) {
627             fmi1_xml_parse_fatal(context, "Could not allocate memory");
628             return -1;
629         }
630
631             /*  <xs:attribute name="start" type="xs:integer"/> */
632                 fmi1_xml_set_attr_int(context, fmi1_xml_elmID_Integer, fmi_attr_id_start, 0, &start->start, 0);
633             /*  <xs:attribute name="fixed" type="xs:boolean"> */
634                 fmi1_xml_set_attr_boolean(context, fmi1_xml_elmID_Integer, fmi_attr_id_fixed, 0, &isFixedBuf, 1);
635
636         start->typeBase.isFixed = isFixedBuf;
637         variable->typeBase = &start->typeBase;
638     } else {
639         fmi1_log_error_if_start_required(context, variable);
640     }
641
642     return 0;
643 }
644
645 int fmi1_xml_handle_Boolean(fmi1_xml_parser_context_t *context, const char* data) {
646     fmi1_xml_model_description_t* md = context->modelDescription;
647     fmi1_xml_type_definitions_t* td = &md->typeDefinitions;
648     fmi1_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
649     int hasStart;
650
651     if (context->skipOneVariableFlag) {
652         return 0;
653     } else if (data) {
654         /* don't do anything. might give out a warning if(data[0] != 0) */
655         return 0;
656     }
657
658         assert(!variable->typeBase);
659
660     variable->typeBase = fmi1_get_declared_type(context, fmi1_xml_elmID_Boolean, &td->defaultBooleanType) ;
661
662     if(!variable->typeBase) return -1;
663
664     hasStart = fmi1_xml_is_attr_defined(context,fmi_attr_id_start);
665     if(hasStart) {
666         int isFixedBuf;
667         fmi1_xml_variable_start_integer_t * start = (fmi1_xml_variable_start_integer_t*)fmi1_xml_alloc_variable_type_start(td, variable->typeBase, sizeof(fmi1_xml_variable_start_integer_t ));
668         if(!start) {
669             fmi1_xml_parse_fatal(context, "Could not allocate memory");
670             return -1;
671         }
672         if(
673               /*  <xs:attribute name="start" type="xs:boolean"/> */
674                 fmi1_xml_set_attr_boolean(context, fmi1_xml_elmID_Boolean, fmi_attr_id_start, 0, (int*)&start->start, 0) ||
675             /*  <xs:attribute name="fixed" type="xs:boolean"> */
676                 fmi1_xml_set_attr_boolean(context, fmi1_xml_elmID_Boolean, fmi_attr_id_fixed, 0, &isFixedBuf, 1)
677             )
678                 return -1;
679         start->typeBase.isFixed = isFixedBuf;
680         variable->typeBase = &start->typeBase;
681     } else {
682         fmi1_log_error_if_start_required(context, variable);
683     }
684
685     return 0;
686 }
687
688 int fmi1_xml_handle_String(fmi1_xml_parser_context_t *context, const char* data) {
689     fmi1_xml_model_description_t* md = context->modelDescription;
690     fmi1_xml_type_definitions_t* td = &md->typeDefinitions;
691     fmi1_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
692     int hasStart;
693
694     if (context->skipOneVariableFlag) {
695         return 0;
696     } else if (data) {
697         /* don't do anything. might give out a warning if(data[0] != 0) */
698         return 0;
699     }
700
701         assert(!variable->typeBase);
702
703     variable->typeBase = fmi1_get_declared_type(context, fmi1_xml_elmID_String,&td->defaultStringType) ;
704
705     if(!variable->typeBase) return -1;
706
707     hasStart = fmi1_xml_is_attr_defined(context,fmi_attr_id_start);
708     if(hasStart) {
709         jm_vector(char)* bufStartStr = fmi1_xml_reserve_parse_buffer(context,1, 100);
710         size_t strlen;
711         int isFixed;
712         fmi1_xml_variable_start_string_t * start;
713         if(
714              /*   <xs:attribute name="start" type="xs:string"/> */
715                 fmi1_xml_set_attr_string(context, fmi1_xml_elmID_String, fmi_attr_id_start, 0, bufStartStr) ||
716             /*  <xs:attribute name="fixed" type="xs:boolean"> */
717                 fmi1_xml_set_attr_boolean(context, fmi1_xml_elmID_Boolean, fmi_attr_id_fixed, 0, &isFixed, 1)
718             )
719                 return -1;
720         strlen = jm_vector_get_size_char(bufStartStr);
721
722         start = (fmi1_xml_variable_start_string_t*)fmi1_xml_alloc_variable_type_start(td, variable->typeBase, sizeof(fmi1_xml_variable_start_string_t) + strlen);
723
724         if(!start) {
725             fmi1_xml_parse_fatal(context, "Could not allocate memory");
726             return -1;
727         }
728         if (strlen != 0) { /* No need to memcpy empty strings (gives assetion error) */
729             memcpy(start->start, jm_vector_get_itemp_char(bufStartStr,0), strlen);
730         }
731         start->start[strlen] = 0;
732         variable->typeBase = &start->typeBase;
733     } else {
734         fmi1_log_error_if_start_required(context, variable);
735     }
736
737     return 0;
738 }
739
740 int fmi1_xml_handle_Enumeration(fmi1_xml_parser_context_t *context, const char* data) {
741
742     fmi1_xml_model_description_t* md = context->modelDescription;
743     fmi1_xml_type_definitions_t* td = &md->typeDefinitions;
744     fmi1_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
745     fmi1_xml_variable_type_base_t * declaredType = 0;
746     fmi1_xml_integer_type_props_t * type = 0;
747     int hasStart;
748
749     if (context->skipOneVariableFlag) {
750         return 0;
751     } else if (data) {
752         /* don't do anything. might give out a warning if(data[0] != 0) */
753         return 0;
754     }
755
756         assert(!variable->typeBase);
757
758     declaredType = fmi1_get_declared_type(context, fmi1_xml_elmID_Enumeration,&td->defaultEnumType.typeBase);
759
760     if(!declaredType) return -1;
761
762     {
763         int hasQuan = fmi1_xml_is_attr_defined(context, fmi_attr_id_quantity);
764         int hasMin =  fmi1_xml_is_attr_defined(context, fmi_attr_id_min);
765         int hasMax = fmi1_xml_is_attr_defined(context, fmi_attr_id_max);
766
767         if(hasQuan || hasMin || hasMax) {
768             fmi1_xml_integer_type_props_t* props = 0;
769
770             if(declaredType->structKind != fmi1_xml_type_struct_enu_typedef)
771                 props = (fmi1_xml_integer_type_props_t*)declaredType;
772             else
773                 props = (fmi1_xml_integer_type_props_t*)declaredType->baseTypeStruct;
774             assert(props->typeBase.structKind == fmi1_xml_type_struct_enu_props);
775             fmi1_xml_reserve_parse_buffer(context, 1, 0);
776             fmi1_xml_reserve_parse_buffer(context, 2, 0);
777             type = fmi1_xml_parse_integer_type_properties(context, fmi1_xml_elmID_Enumeration);
778             if(!type) return -1;
779             type->typeBase.baseTypeStruct = declaredType;
780             if(!hasMin) type->typeMin = props->typeMin;
781             if(!hasMax) type->typeMax = props->typeMax;
782             if(!hasQuan) type->quantity = props->quantity;
783         }
784         else
785             type = (fmi1_xml_integer_type_props_t*)declaredType;
786     }
787
788     variable->typeBase = &type->typeBase;
789
790     hasStart = fmi1_xml_is_attr_defined(context,fmi_attr_id_start);
791     if(hasStart) {
792         fmi1_xml_variable_start_integer_t * start = (fmi1_xml_variable_start_integer_t*)fmi1_xml_alloc_variable_type_start(td, &type->typeBase, sizeof(fmi1_xml_variable_start_integer_t ));
793         int isFixedBuf;
794         if(!start) {
795             fmi1_xml_parse_fatal(context, "Could not allocate memory");
796             return -1;
797         }
798         if(
799             /*  <xs:attribute name="start" type="xs:integer"/> */
800                 fmi1_xml_set_attr_int(context, fmi1_xml_elmID_Enumeration, fmi_attr_id_start, 0, &start->start, 0) ||
801             /*  <xs:attribute name="fixed" type="xs:boolean"> */
802                 fmi1_xml_set_attr_boolean(context, fmi1_xml_elmID_Enumeration, fmi_attr_id_fixed, 0, &isFixedBuf, 1)
803             )
804                 return -1;
805         start->typeBase.isFixed = isFixedBuf;
806         variable->typeBase = &start->typeBase;
807     } else {
808         fmi1_log_error_if_start_required(context, variable);
809     }
810     return 0;
811 }
812
813 static int fmi1_xml_compare_variable_original_index (const void* first, const void* second) {
814         size_t a = (*(fmi1_xml_variable_t**)first)->originalIndex;
815         size_t b = (*(fmi1_xml_variable_t**)second)->originalIndex;
816     if(a < b) return -1;
817     if(a > b) return 1;
818         return 0;
819 }
820
821 void fmi1_xml_eliminate_bad_alias(fmi1_xml_parser_context_t *context, jm_vector(jm_voidp)* varByVR, size_t indexVR) {
822     size_t n, index;
823     
824     fmi1_xml_variable_t* v = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, indexVR);
825     fmi1_value_reference_t vr = v->vr;
826     fmi1_base_type_enu_t vt = fmi1_xml_get_variable_base_type(v);
827     jm_named_ptr key;
828
829     n = jm_vector_get_size(jm_voidp)(varByVR);
830     v = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, indexVR);
831         
832     jm_vector_remove_item_jm_voidp(varByVR, indexVR);
833     key.name = v->name;
834     index = jm_vector_bsearch_index(jm_named_ptr)(&context->modelDescription->variablesByName, &key, jm_compare_named);
835     assert(index <= n);
836     jm_vector_remove_item(jm_named_ptr)(&context->modelDescription->variablesByName, index);
837
838     index = jm_vector_bsearch_index(jm_voidp)(context->modelDescription->variablesOrigOrder, (jm_voidp*)&v, fmi1_xml_compare_variable_original_index);
839     assert(index <= n);
840
841         jm_vector_remove_item(jm_voidp)(context->modelDescription->variablesOrigOrder,index);
842
843     jm_log_error(context->callbacks, module,"Removing incorrect alias variable '%s'", v->name);
844     context->callbacks->free(v);
845 }
846
847 static size_t fmi1_xml_eliminate_bad_alias_set(fmi1_xml_parser_context_t *context, size_t indexVR) {\r
848     size_t i, n, removed_aliases;\r
849     \r
850     jm_vector(jm_voidp)* varByVR = context->modelDescription->variablesByVR;\r
851     fmi1_xml_variable_t* v = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, indexVR);\r
852     fmi1_value_reference_t vr = v->vr;\r
853     fmi1_base_type_enu_t vt = fmi1_xml_get_variable_base_type(v);\r
854 \r
855     jm_log_error(context->callbacks, module, "Alias set with vr=%u "
856                 "(type=%s) do not have a 'noAlias' variable.", v->vr,
857                 fmi1_base_type_to_string(fmi1_xml_get_variable_base_type(v)));\r
858 \r
859     removed_aliases = 0;\r
860     n = jm_vector_get_size(jm_voidp)(varByVR);\r
861     for(i = 0; i< n; i++) {\r
862         v = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, i);\r
863         if ((v->vr == vr) && (vt == fmi1_xml_get_variable_base_type(v))) {\r
864             fmi1_xml_eliminate_bad_alias(context, varByVR, i);\r
865             n--; i--; removed_aliases++;\r
866         }\r
867     }
868
869     return removed_aliases;
870 }
871
872 static int fmi1_xml_compare_vr_and_original_index (const void* first, const void* second) {
873         int ret = fmi1_xml_compare_vr(first, second);
874         if(ret == 0) {
875             fmi1_xml_variable_t* a = *(fmi1_xml_variable_t**)first;
876                 fmi1_xml_variable_t* b = *(fmi1_xml_variable_t**)second;
877                 size_t ai = a->originalIndex;
878                 size_t bi = b->originalIndex;
879                 if(ai > bi) ret = 1;
880                 if(ai < bi) ret = -1;
881         }
882
883         return ret;
884 }
885
886 static int fmi1_same_vr_and_base_type(
887     fmi1_xml_variable_t* a,
888     fmi1_xml_variable_t* b)
889 {
890     return (a->vr == b->vr) && \r
891         (fmi1_xml_get_variable_base_type(a) == fmi1_xml_get_variable_base_type(b));
892 }
893
894 static fmi1_xml_variable_t* findNextBaseAliasIdx(
895     fmi1_xml_parser_context_t *context,
896     jm_vector(jm_voidp)* varByVR,
897     size_t cur_list_idx)
898 {
899     size_t n, i;
900     fmi1_xml_variable_t* a;
901
902     n = jm_vector_get_size(jm_voidp)(varByVR);
903     a = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, cur_list_idx);
904     if (a->aliasKind == fmi1_variable_is_not_alias) {
905         return a;
906     }
907
908     for (i = cur_list_idx + 1; i < n; i++) {
909         fmi1_xml_variable_t* b =
910             (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, i);
911
912         if (!fmi1_same_vr_and_base_type(a, b)) {
913             size_t aliases_removed;
914
915             /* End of alias set, did not find base in current so remove it */
916             aliases_removed = fmi1_xml_eliminate_bad_alias_set(context, i - 1);
917
918             /* Setup for iterating through the next alias set */
919             n -= aliases_removed; i -= aliases_removed;
920             a = b;
921         }
922         if (b->aliasKind == fmi1_variable_is_not_alias) {
923             return b;
924         }
925     }
926
927     /* Did not find a next base alias */
928     fmi1_xml_eliminate_bad_alias_set(context, i - 1);
929     return NULL;
930 }
931
932 static int fmi1_alias_check_sign(
933     fmi1_xml_variable_t* a,
934     fmi1_xml_variable_t* b)
935 {
936     if ((a->aliasKind == fmi1_variable_is_negated_alias) != 
937         (b->aliasKind == fmi1_variable_is_negated_alias))
938     {
939         return -1;
940     } else {
941         return 1;
942     }
943 }
944
945 static const char* fmi1_alias_negated_string(fmi1_xml_variable_t* a) {
946     return  a->aliasKind == fmi1_variable_is_negated_alias ?
947         "(negated alias)" : "";
948 }
949
950 #define FMIL_ABS(X) (((X) > 0) ? (X) : -(X))
951 #define FMIL_MAX(X, Y) ((X) > (Y) ? (X) : (Y))
952
953 static int fmi1_real_alias_consistent_start_values(
954     jm_callbacks* cb,
955     fmi1_xml_variable_t* a,
956     fmi1_xml_variable_t* b)
957 {
958     double a_start = fmi1_xml_get_real_variable_start(fmi1_xml_get_variable_as_real(a));
959     double b_start = fmi1_xml_get_real_variable_start(fmi1_xml_get_variable_as_real(b));
960     double scaling;
961     int check_sign = fmi1_alias_check_sign(a, b);
962     int consistent;
963
964     scaling = FMIL_MAX(FMIL_ABS(a_start), 1.0);
965     consistent = FMIL_ABS(a_start - check_sign*b_start) < 1e-14 * scaling;
966     if (!consistent) {
967         jm_log_error(cb, module, "Inconsistent start values in alias set, "
968             "start value '%16.16f' of '%s'%s does not match "
969             "start value '%16.16f' of '%s'%s.",
970             a_start, a->name, fmi1_alias_negated_string(a),
971             b_start, b->name, fmi1_alias_negated_string(b));
972     }
973
974     return consistent;
975 }
976
977 static int fmi1_int_alias_consistent_start_values(
978     jm_callbacks* cb,
979     fmi1_xml_variable_t* a,
980     fmi1_xml_variable_t* b)
981 {
982     int a_start = fmi1_xml_get_integer_variable_start(fmi1_xml_get_variable_as_integer(a));
983     int b_start = fmi1_xml_get_integer_variable_start(fmi1_xml_get_variable_as_integer(b));
984     int check_sign = fmi1_alias_check_sign(a, b);
985     int consistent;
986
987     consistent = (a_start == check_sign*b_start);
988     if (!consistent) {
989         jm_log_error(cb, module, "Inconsistent start values in alias set, "
990             "start value '%d' of '%s'%s does not match "
991             "start value '%d' of '%s'%s.",
992             a_start, a->name, fmi1_alias_negated_string(a),
993             b_start, b->name, fmi1_alias_negated_string(b));
994     }
995
996     return consistent;
997 }
998
999 static int fmi1_enum_alias_consistent_start_values(
1000     jm_callbacks* cb,
1001     fmi1_xml_variable_t* a,
1002     fmi1_xml_variable_t* b)
1003 {
1004     int a_start = fmi1_xml_get_enum_variable_start(fmi1_xml_get_variable_as_enum(a));
1005     int b_start = fmi1_xml_get_enum_variable_start(fmi1_xml_get_variable_as_enum(b));
1006     int check_sign = fmi1_alias_check_sign(a, b);
1007     int consistent;
1008
1009     consistent = (check_sign > 0) && (a_start == b_start);
1010     if (!consistent) {
1011         jm_log_error(cb, module, "Inconsistent start values in alias set, "
1012             "start value '%d' of '%s'%s does not match "
1013             "start value '%d' of '%s'%s.",
1014             a_start, a->name, fmi1_alias_negated_string(a),
1015             b_start, b->name, fmi1_alias_negated_string(b));
1016     }
1017
1018     return consistent;
1019 }
1020
1021 static int fmi1_bool_alias_consistent_start_values(
1022     jm_callbacks* cb,
1023     fmi1_xml_variable_t* a,
1024     fmi1_xml_variable_t* b)
1025 {
1026     fmi1_boolean_t a_start = fmi1_xml_get_boolean_variable_start(fmi1_xml_get_variable_as_boolean(a));
1027     fmi1_boolean_t b_start = fmi1_xml_get_boolean_variable_start(fmi1_xml_get_variable_as_boolean(b));
1028     int check_sign = fmi1_alias_check_sign(a, b);
1029     int consistent;
1030
1031     if (check_sign > 0) {
1032         consistent = ((!a_start) == (!b_start));
1033     } else {
1034         consistent = ((!a_start) != (!b_start));
1035     }
1036     if (!consistent) {
1037         jm_log_error(cb, module, "Inconsistent start values in alias set, "
1038             "start value '%s' of '%s'%s does not match "
1039             "start value '%s' of '%s'%s.",
1040             a_start ? "true" : "false", a->name, fmi1_alias_negated_string(a),
1041             b_start ? "true" : "false", b->name, fmi1_alias_negated_string(b));
1042     }
1043
1044     return consistent;
1045 }
1046
1047 static int fmi1_str_alias_consistent_start_values(
1048     jm_callbacks* cb,
1049     fmi1_xml_variable_t* a,
1050     fmi1_xml_variable_t* b)
1051 {
1052     const char* a_start = fmi1_xml_get_string_variable_start(fmi1_xml_get_variable_as_string(a));
1053     const char* b_start = fmi1_xml_get_string_variable_start(fmi1_xml_get_variable_as_string(b));
1054     int check_sign = fmi1_alias_check_sign(a, b);
1055     int consistent;
1056
1057     consistent = check_sign > 0 && strcmp(a_start, b_start) == 0;
1058     if (!consistent) {
1059         jm_log_error(cb, module, "Inconsistent start values in alias set, "
1060             "start value '%s' of '%s'%s does not match "
1061             "start value '%s' of '%s'%s.",
1062             a_start, a->name, fmi1_alias_negated_string(a),
1063             b_start, b->name, fmi1_alias_negated_string(b));
1064     }
1065
1066     return consistent;
1067 }
1068
1069 static int fmi1_alias_consistent_start_values(
1070     jm_callbacks* cb,
1071     fmi1_xml_variable_t* a,
1072     fmi1_xml_variable_t* b)
1073 {
1074     fmi1_base_type_enu_t type = fmi1_xml_get_variable_base_type(a);
1075     assert(fmi1_same_vr_and_base_type(a, b));
1076
1077     switch (type) {
1078         case fmi1_base_type_real:
1079             return fmi1_real_alias_consistent_start_values(cb, a, b);
1080         case fmi1_base_type_int:
1081             return fmi1_int_alias_consistent_start_values(cb, a, b);
1082         case fmi1_base_type_bool:
1083             return fmi1_bool_alias_consistent_start_values(cb, a, b);
1084         case fmi1_base_type_str:
1085             return fmi1_str_alias_consistent_start_values(cb, a, b);
1086         case fmi1_base_type_enum:
1087             return fmi1_enum_alias_consistent_start_values(cb, a, b);
1088         default: assert(0); return 0;
1089     }
1090 }
1091
1092 static size_t handleAliasSet(
1093     fmi1_xml_parser_context_t *context,
1094     jm_vector(jm_voidp)* varByVR,
1095     fmi1_xml_variable_t* base_alias,
1096     size_t start_idx)
1097 {
1098     size_t numvar, cur_list_idx;
1099     fmi1_xml_variable_t* v_with_start = NULL;
1100
1101     numvar = jm_vector_get_size(jm_voidp)(varByVR);
1102     if (numvar <= start_idx) {
1103         /* Nothing to do if past the end of the list */
1104         return start_idx + 1;
1105     }
1106
1107     assert(base_alias->aliasKind == fmi1_variable_is_not_alias);
1108     if (fmi1_xml_get_variable_has_start(base_alias)) {
1109         /* If base alias have start, use it as the correct value
1110          * when comparing against other vars so we don'r remove
1111          * it from the alias set */
1112         v_with_start = base_alias;
1113     }
1114     for(cur_list_idx = start_idx; cur_list_idx < numvar; cur_list_idx++) {
1115         fmi1_xml_variable_t* v = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, cur_list_idx);
1116         
1117         if (v == base_alias) {
1118             /* The base alias, nothing to do */
1119             continue;
1120         }
1121         if (!fmi1_same_vr_and_base_type(base_alias, v)) {
1122             /* Not the same vr and type, end of the alias set */
1123             break;
1124         } else {
1125             /* Next variable in list have same type and valueRef */
1126             if (v->aliasKind == fmi1_variable_is_not_alias) {
1127                 /* But is for some reason marked as 'noAlias' => make it an alias */
1128                 fmi1_xml_variable_t* c;
1129                 size_t i, j;
1130
1131                 jm_log_error(context->callbacks, module, "Variables %s and %s reference the "
1132                     "same vr %u. Marking '%s' as alias.",
1133                      base_alias->name, v->name, v->vr, v->name);
1134                 v->aliasKind = fmi1_variable_is_alias;
1135
1136                 /* Ok, now we sort b into a later position in the var list
1137                  * which is consistent with the lists sorting */
1138                 i = cur_list_idx;
1139                 j = cur_list_idx + 1;
1140                 while(j < numvar) {
1141                     c = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, j);
1142                     if(fmi1_xml_compare_vr(&v,&c) <= 0) break;
1143                     j++;
1144                 }
1145                 j--;
1146                 if(i != j) {
1147                     c = (fmi1_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, j);
1148                     jm_vector_set_item(jm_voidp)(varByVR, j, v);
1149                     jm_vector_set_item(jm_voidp)(varByVR, i, c);
1150                 }
1151
1152                 /* Now that this inconsistency is taken care of we repeat
1153                  * current loop iteration: */
1154                 cur_list_idx--;
1155                 continue;
1156             } else if (fmi1_xml_get_variable_has_start(v)) {
1157                 if (v_with_start == NULL) {
1158                     v_with_start = v;
1159                 } else if (!fmi1_alias_consistent_start_values(
1160                                 context->callbacks, v_with_start, v))
1161                 {
1162                     fmi1_xml_eliminate_bad_alias(context, varByVR, cur_list_idx);
1163                     cur_list_idx--; numvar--;
1164                 }
1165             }
1166         }
1167     }
1168
1169     return cur_list_idx;
1170 }
1171
1172 static void fmi1_checking_alias_info(
1173     fmi1_xml_parser_context_t *context,
1174     jm_vector(jm_voidp)* varByVR)
1175 {
1176     size_t cur_list_idx = 0;
1177
1178     jm_log_verbose(context->callbacks, module,"Checking alias information");
1179     while (cur_list_idx < jm_vector_get_size(jm_voidp)(varByVR)) {
1180         fmi1_xml_variable_t* base_alias = findNextBaseAliasIdx(context, varByVR, cur_list_idx);
1181         if (base_alias == NULL) break;
1182         cur_list_idx = handleAliasSet(context, varByVR, base_alias, cur_list_idx);
1183     }
1184 }
1185
1186 int fmi1_xml_handle_ModelVariables(fmi1_xml_parser_context_t *context, const char* data) {
1187     if(!data) {
1188                 jm_log_verbose(context->callbacks, module,"Parsing XML element ModelVariables");
1189     }
1190     else {
1191          /* postprocess variable list */
1192
1193         fmi1_xml_model_description_t* md = context->modelDescription;
1194         jm_vector(jm_voidp)* varByVR;
1195                 jm_vector(jm_voidp)* inputVars;
1196                 jm_vector(jm_voidp)* outputVars;
1197         size_t i, numvar;
1198                 size_t num_in = 0;
1199                 size_t num_out = 0;
1200                 numvar = jm_vector_get_size(jm_named_ptr)(&md->variablesByName);
1201                 inputVars = jm_vector_alloc(jm_voidp)(numvar,numvar,md->callbacks);
1202                 outputVars = jm_vector_alloc(jm_voidp)(numvar,numvar,md->callbacks);
1203                 if (!inputVars || !outputVars) {
1204                         fmi1_xml_parse_fatal(context, "Could not allocate memory");
1205                 }
1206                 /* vars with  vr = fmiUndefinedValueReference were already skipped. Just sanity: */
1207         /* remove any variable with vr = fmiUndefinedValueReference */
1208         for(i = 0; i< numvar; i++) {
1209             jm_named_ptr named = jm_vector_get_item(jm_named_ptr)(&md->variablesByName, i);
1210             fmi1_xml_variable_t* v = named.ptr;
1211             if(v->vr == fmi1_undefined_value_reference) {
1212                 jm_vector_remove_item(jm_named_ptr)(&md->variablesByName,i);
1213                 numvar--; i--;
1214                 fmi1_xml_free_direct_dependencies(named);
1215                 md->callbacks->free(v);
1216                 assert(0);
1217             }
1218                         if (v->causality == fmi1_causality_enu_input){
1219                                 jm_vector_set_item(jm_voidp)(inputVars, num_in, jm_vector_get_item(jm_named_ptr)(&md->variablesByName,i).ptr);
1220                                 num_in++;
1221                         }
1222                         if (v->causality == fmi1_causality_enu_output){
1223                                 jm_vector_set_item(jm_voidp)(outputVars, num_out, jm_vector_get_item(jm_named_ptr)(&md->variablesByName,i).ptr);
1224                                 num_out++;
1225                         }
1226
1227         }
1228
1229         /* store the list of vars in origianl order */
1230                 {
1231                         size_t size = jm_vector_get_size(jm_named_ptr)(&md->variablesByName);
1232                         md->variablesOrigOrder = jm_vector_alloc(jm_voidp)(size,size,md->callbacks);
1233                         if(md->variablesOrigOrder) {
1234                                 size_t i;
1235                                 for(i= 0; i < size; ++i) {
1236                                         jm_vector_set_item(jm_voidp)(md->variablesOrigOrder, i, jm_vector_get_item(jm_named_ptr)(&md->variablesByName,i).ptr);
1237                                 }
1238                         }
1239
1240                 }
1241
1242                 /* store the list of input vars */
1243                 md->inputVariables = jm_vector_alloc(jm_voidp)(num_in,num_in,md->callbacks);
1244                 md->outputVariables = jm_vector_alloc(jm_voidp)(num_out,num_out,md->callbacks);
1245                 if(md->inputVariables) {
1246                                 size_t i;
1247                                 for(i= 0; i < num_in; ++i) {
1248                                         jm_vector_set_item(jm_voidp)(md->inputVariables, i, jm_vector_get_item(jm_voidp)(inputVars,i));
1249                                 }
1250                         }
1251                 else {
1252                         fmi1_xml_parse_fatal(context, "Could not allocate memory");
1253                 }
1254                 if(md->outputVariables) {
1255                                 size_t i;
1256                                 for(i= 0; i < num_out; ++i) {
1257                                         jm_vector_set_item(jm_voidp)(md->outputVariables, i, jm_vector_get_item(jm_voidp)(outputVars,i));
1258                                 }
1259                         }
1260                 else {
1261                         fmi1_xml_parse_fatal(context, "Could not allocate memory");
1262                 }
1263                 jm_vector_free(jm_voidp)(inputVars);
1264                 jm_vector_free(jm_voidp)(outputVars);
1265
1266                 /* sort the variables by names */
1267         jm_vector_qsort(jm_named_ptr)(&md->variablesByName,jm_compare_named);
1268
1269         /* create VR index */
1270         md->status = fmi1_xml_model_description_enu_ok;
1271                 {
1272                         size_t size = jm_vector_get_size(jm_named_ptr)(&md->variablesByName);
1273                         md->variablesByVR = jm_vector_alloc(jm_voidp)(size,size,md->callbacks);
1274                         if(md->variablesByVR) {
1275                                 size_t i;
1276                                 for(i= 0; i < size; ++i) {
1277                                         jm_vector_set_item(jm_voidp)(md->variablesByVR, i, jm_vector_get_item(jm_named_ptr)(&md->variablesByName,i).ptr);
1278
1279                                 }
1280                         }
1281                 }
1282
1283         md->status = fmi1_xml_model_description_enu_empty;
1284                 if(!md->variablesByVR || !md->variablesOrigOrder || !md->inputVariables || !md->outputVariables) {
1285             fmi1_xml_parse_fatal(context, "Could not allocate memory");
1286             return -1;
1287         }
1288         varByVR = md->variablesByVR;
1289         jm_vector_qsort(jm_voidp)(varByVR, fmi1_xml_compare_vr_and_original_index);
1290         
1291         fmi1_checking_alias_info(context, varByVR);
1292
1293         numvar = jm_vector_get_size(jm_named_ptr)(&md->variablesByName);
1294                 jm_log_verbose(context->callbacks, module,"Setting up direct dependencies cross-references");
1295         /* postprocess direct dependencies */
1296         for(i = 0; i< numvar; i++) {
1297             size_t numdep, j, var_i = 0;
1298             jm_vector(jm_voidp)* dep;
1299             fmi1_xml_variable_t* variable = (fmi1_xml_variable_t*)jm_vector_get_item(jm_named_ptr)(&md->variablesByName, i).ptr;
1300
1301             if(!variable->directDependency) continue;
1302             dep = variable->directDependency;
1303             numdep = jm_vector_get_size(jm_voidp)(dep);
1304             for(j = 0; j < numdep; j++) {
1305                 jm_string name = jm_vector_get_item(jm_voidp)(dep, j);
1306                 jm_named_ptr key, *found;
1307                 fmi1_xml_variable_t* depvar;
1308                 key.name = name;
1309                                 key.ptr = 0;
1310                                 found = jm_vector_bsearch(jm_named_ptr)(&md->variablesByName, &key, jm_compare_named);
1311                                 if(found)
1312                                         depvar = found->ptr;
1313                                 else
1314                                         depvar = 0;
1315                 if(!depvar) {
1316                     jm_log_error(context->callbacks,module, "Could not find variable %s mentioned in dependecies of %s. Ignoring", name, variable->name);
1317                     continue;
1318                 }
1319                 if(depvar->causality != fmi1_causality_enu_input) {
1320                     jm_log_error(context->callbacks,module, "Only input variables are allowed in DirectDependecies, but %s is not input. Ignoring", name);
1321                     continue;
1322                 }
1323                 jm_vector_set_item(jm_voidp)(dep,var_i++, depvar);
1324             }
1325             jm_vector_resize(jm_voidp)(dep,var_i);
1326         }
1327         jm_vector_foreach(jm_string)(&context->directDependencyStringsStore, (void(*)(jm_string))context->callbacks->free);
1328         jm_vector_free_data(jm_string)(&context->directDependencyStringsStore);
1329
1330         /* might give out a warning if(data[0] != 0) */
1331     }
1332     return 0;
1333 }