Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 55.3% 83 / 0 / 150
Functions: 66.7% 8 / 0 / 12
Branches: 45.3% 39 / 0 / 86

OMCompiler/SimulationRuntime/c/util/read_csv.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 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include "read_csv.h"
32 #include "read_matlab4.h"
33 #include "libcsv.h"
34 #include "omc_file.h"
35 #include "omc_numbers.h"
36 #include "omc_strdup.h"
37
38 struct cell_row_count
39 {
40 int cell_count;
41 int row_count;
42 };
43
44 struct csv_head
45 {
46 char **variables;
47 int size;
48 int buffer_size;
49 int found_row;
50 };
51
52 struct csv_body
53 {
54 double *res;
55 int size;
56 int buffer_size;
57 int found_first_row;
58 int cur_size;
59 int row_length;
60 int error;
61 };
62
63 ✗ static void do_nothing(void *data, size_t len, void *t)
64 {
65 ✗ }
66
67 305 static void found_first_row(int c, void *t)
68 {
69 struct csv_head *head = (struct csv_head*) t;
70 305 head->found_row++;
71 305 }
72
73 4302 static void add_variable(void *data, size_t len, void *t)
74 {
75 struct csv_head *head = (struct csv_head*) t;
76
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 4130 times.
4302 if (head->found_row) {
77 return;
78 }
79
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 166 times.
172 if (head->size+1 >= head->buffer_size) {
80
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 head->buffer_size = head->buffer_size ? 2*head->buffer_size : 512;
81 6 head->variables = (char**) realloc(head->variables, sizeof(char*)*head->buffer_size);
82 }
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 172 times.
172 head->variables[head->size++] = omc_strdup(data ? (char*) data : "");
84 }
85
86 ✗ static void row_count(int c, void *t)
87 {
88 struct cell_row_count *s = (struct cell_row_count *) t;
89 ✗ s->row_count++;
90 ✗ }
91
92 ✗ int read_csv_dataset_size(const char* filename)
93 {
94 const int buf_size = 4096;
95 char buf[4096];
96 FILE *f;
97 struct csv_parser p;
98 ✗ struct cell_row_count count = {0};
99 size_t offset=0;
100 ✗ unsigned char delim = CSV_COMMA;
101 ✗ f = omc_fopen(filename,"r");
102 ✗ if (f == NULL) {
103 return -1;
104 }
105
106 /* determine delim */
107 ✗ omc_fread(buf, 1, 5, f, 0);
108 ✗ if (0 == strcmp(buf, "\"sep="))
109 {
110 ✗ omc_fread(&delim, 1, 1, f, 0);
111 offset = 8;
112 }
113 ✗ fseek(f, offset, SEEK_SET);
114
115 ✗ csv_init(&p, CSV_STRICT | CSV_REPALL_NL | CSV_STRICT_FINI | CSV_APPEND_NULL | CSV_EMPTY_IS_NULL, delim);
116 ✗ csv_set_realloc_func(&p, realloc);
117 ✗ csv_set_free_func(&p, free);
118 do {
119 ✗ size_t len = omc_fread(buf, 1, buf_size, f, 1);
120 ✗ if (len != buf_size && !feof(f)) {
121 ✗ csv_free(&p);
122 ✗ fclose(f);
123 ✗ return -1;
124 }
125 ✗ csv_parse(&p,buf,len,do_nothing,row_count,&count);
126 ✗ } while (!feof(f));
127 ✗ csv_fini(&p,do_nothing,row_count,&count);
128 ✗ csv_free(&p);
129 ✗ fclose(f);
130 ✗ return count.row_count - 1; /* The header is excluded */
131 }
132
133 6 char** read_csv_variables(FILE *fin, int *length, unsigned char delim)
134 {
135 const int buf_size = 4096;
136 char buf[4096];
137 char **res;
138 struct csv_parser p;
139 6 struct csv_head head = {0};
140 6 csv_init(&p, CSV_STRICT | CSV_REPALL_NL | CSV_STRICT_FINI | CSV_APPEND_NULL | CSV_EMPTY_IS_NULL, delim);
141 6 csv_set_realloc_func(&p, realloc);
142 6 csv_set_free_func(&p, free);
143 do {
144 6 size_t len = omc_fread(buf, 1, buf_size, fin, 1);
145
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 if (len != buf_size && !feof(fin)) {
146 ✗ csv_free(&p);
147 ✗ return NULL;
148 }
149 6 csv_parse(&p,buf,len,add_variable,found_first_row,&head);
150
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 } while (!head.found_row && !feof(fin));
151 6 csv_free(&p);
152
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!head.found_row) {
153 return NULL;
154 }
155 6 *length = head.size-1;
156 6 return head.variables;
157 }
158
159 866595 static void add_cell(void *data, size_t len, void *t)
160 {
161 struct csv_body *body = (struct csv_body*) t;
162 866595 char *endptr = "";
163
1/2
✓ Branch 0 taken 866595 times.
✗ Branch 1 not taken.
866595 if (body->error) {
164 172 return;
165 }
166
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 866423 times.
866595 if (!body->found_first_row) {
167 172 body->cur_size++;
168 172 body->row_length++;
169 172 return;
170 }
171
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 866408 times.
866423 if (body->size+1 >= body->buffer_size) {
172
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
15 body->buffer_size = body->res ? 2*body->buffer_size : body->row_length*1024; /* Guess it's 1024 time points; we could also take the size of the file or something, but this is cool too */
173
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 body->buffer_size = body->buffer_size > 0 ? body->buffer_size : 1024;
174
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
15 body->res = body->res ? (double*)realloc(body->res, sizeof(double)*body->buffer_size) : (double*) malloc(sizeof(double)*body->buffer_size);
175 }
176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 866423 times.
866423 if (data == NULL) {
177 ✗ body->res[body->size++] = 0.0;
178 ✗ return;
179 }
180 866423 body->res[body->size++] = data ? om_strtod((const char*)data,&endptr) : 0;
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 866423 times.
866423 if (*endptr) {
182 ✗ fprintf(stderr,"Found non-double data in csv result-file: %s\n", (char*) data);
183 ✗ body->error = 1;
184 }
185 }
186
187 19075 static void add_row(int c, void *t)
188 {
189 struct csv_body *body = (struct csv_body*) t;
190 19075 body->found_first_row++;
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19075 times.
19075 if (body->cur_size != body->row_length) {
192 ✗ fprintf(stderr,"Did not find time points for all variables for row: %d\n", body->found_first_row);
193 ✗ body->error = 1;
194 ✗ return;
195 }
196 }
197
198 ✗ double* read_csv_dataset_var(const char *filename, const char *var, int dimsize)
199 {
200 const int buf_size = 4096;
201 char buf[4096];
202 char **res;
203 struct csv_parser p;
204 ✗ struct csv_body body = {0};
205 ✗ FILE *fin = omc_fopen(filename, "r");
206 size_t offset = 0;
207 ✗ unsigned char delim = CSV_COMMA;
208 ✗ if (!fin) {
209 return NULL;
210 }
211
212 /* determine delim */
213 ✗ omc_fread(buf, 1, 5, fin, 0);
214 ✗ if (0 == strcmp(buf, "\"sep="))
215 {
216 ✗ omc_fread(&delim, 1, 1, fin, 0);
217 offset = 8;
218 }
219 ✗ fseek(fin, offset, SEEK_SET);
220
221 ✗ csv_init(&p, CSV_STRICT | CSV_REPALL_NL | CSV_STRICT_FINI | CSV_APPEND_NULL | CSV_EMPTY_IS_NULL, delim);
222 ✗ csv_set_realloc_func(&p, realloc);
223 ✗ csv_set_free_func(&p, free);
224 do {
225 ✗ size_t len = omc_fread(buf, 1, buf_size, fin, 1);
226 ✗ if (len != buf_size && !feof(fin)) {
227 ✗ csv_free(&p);
228 ✗ fclose(fin);
229 ✗ return NULL;
230 }
231 ✗ csv_parse(&p,buf,len,add_cell,add_row,&body);
232 ✗ } while (!body.error && !feof(fin));
233 ✗ csv_fini(&p,add_cell,add_row,&body);
234 ✗ csv_free(&p);
235 ✗ fclose(fin);
236 ✗ if (body.error) {
237 return NULL;
238 }
239 ✗ return body.res;
240 }
241
242 6 struct csv_data* read_csv(const char *filename)
243 {
244 const int buf_size = 4096;
245 char buf[4096];
246 char **variables;
247 int dummy;
248 struct csv_parser p;
249 6 struct csv_body body = {0};
250 struct csv_data *res;
251 size_t offset = 0;
252 6 unsigned char delim = CSV_COMMA;
253 size_t len;
254
255 6 FILE *fin = omc_fopen(filename, "r");
256
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!fin) {
257 return NULL;
258 }
259
260 /* determine delim */
261 6 len = omc_fread(buf, 1, 5, fin, 0);
262 // Terminate the string in the buffer to make sure strcmp works as expected.
263 6 buf[len] = '\0';
264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (0 == strcmp(buf, "\"sep="))
265 {
266 ✗ omc_fread(&delim, 1, 1, fin, 0);
267 offset = 8;
268 }
269 6 fseek(fin, offset, SEEK_SET);
270
271 6 variables = read_csv_variables(fin, &dummy, delim);
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!variables) {
273 ✗ fclose(fin);
274 ✗ return NULL;
275 }
276 6 fseek(fin,offset,SEEK_SET);
277
278 6 csv_init(&p, CSV_STRICT | CSV_REPALL_NL | CSV_STRICT_FINI | CSV_APPEND_NULL | CSV_EMPTY_IS_NULL, delim);
279 6 csv_set_realloc_func(&p, realloc);
280 6 csv_set_free_func(&p, free);
281 do {
282 3229 len = omc_fread(buf, 1, buf_size, fin, 1);
283
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3223 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
3229 if (len != buf_size && !feof(fin)) {
284 ✗ csv_free(&p);
285 ✗ fclose(fin);
286 ✗ return NULL;
287 }
288 3229 csv_parse(&p,buf,len,add_cell,add_row,&body);
289
3/4
✓ Branch 0 taken 3229 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 3223 times.
✓ Branch 4 taken 6 times.
3229 } while (!body.error && !feof(fin));
290 6 csv_fini(&p,add_cell,add_row,&body);
291 6 csv_free(&p);
292 6 fclose(fin);
293
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (body.error) {
294 return NULL;
295 }
296 6 res = (struct csv_data*) malloc(sizeof(struct csv_data));
297
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!res) {
298 return NULL;
299 }
300 6 res->variables = variables;
301 6 res->data = body.res;
302 6 res->numvars = body.row_length;
303 6 res->numsteps = body.size / body.row_length;
304 6 matrix_transpose(res->data,res->numvars,res->numsteps);
305 /* printf("num vars %d in %s num steps %d\n", body.row_length, filename, res->numsteps); */
306 6 return res;
307 }
308
309 15 double* read_csv_dataset(struct csv_data *data, const char *var)
310 {
311 int i,found=-1;
312
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
92 for (i=0; i<data->numvars; i++) {
313
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 15 times.
92 if (0==strcmp(data->variables[i],var)) {
314 found=i;
315 break;
316 }
317 }
318
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (found == -1) {
319 return NULL;
320 }
321 15 return data->data + i*data->numsteps;
322 }
323
324 5 void omc_free_csv_reader(struct csv_data *data)
325 {
326 int i;
327
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 5 times.
160 for (i=0; i<data->numvars; i++) {
328 155 free(data->variables[i]);
329 }
330 5 free(data->variables);
331 5 free(data->data);
332 data->variables = 0;
333 data->data = 0;
334 5 free(data);
335 5 }
336