sphin_config.c (11518B)
1 /* Copyright (C) 2024-2026 Centre National de la Recherche Scientifique 2 * Copyright (C) 2024-2026 Clermont Auvergne INP 3 * Copyright (C) 2024-2026 INSA Lyon 4 * Copyright (C) 2024-2026 Institut Mines Télécom Albi-Carmaux 5 * Copyright (C) 2024-2026 Institut National Polytechnique de Toulouse 6 * Copyright (C) 2024-2026 |Méso|Star> (contact@meso-star.com) 7 * Copyright (C) 2024-2026 PhotonLyX (info@photonlyx.com) 8 * Copyright (C) 2024-2026 Université de Lorraine 9 * Copyright (C) 2024-2026 Université Paul Sabatier 10 * Copyright (C) 2024-2026 Université Toulouse - Jean Jaurès 11 * 12 * This program is free software: you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation, either version 3 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 24 #define _POSIX_C_SOURCE 200112L /* for strtok_r support */ 25 26 #include "sphin.h" 27 #include "sphin_c.h" 28 #include "sphin_config.h" 29 #include "sphin_surface.h" 30 #include "sphin_volume.h" 31 32 #include <rsys/cstr.h> /* res_to_cstr */ 33 #include <rsys/mem_allocator.h> 34 #include <rsys/ref_count.h> 35 #include <rsys/rsys.h> 36 #include <rsys/str.h> /* struct str */ 37 #include <rsys/text_reader.h> /* struct txtrdr */ 38 39 #include <errno.h> 40 #include <stdio.h> /* fopen, fclose */ 41 #include <string.h> /* strerror */ 42 43 /******************************************************************************* 44 * Helper functions 45 ******************************************************************************/ 46 static res_T 47 config_create 48 (struct sphin* sphin, 49 struct sphin_config** out_config) 50 { 51 struct sphin_config* config = NULL; 52 res_T res = RES_OK; 53 54 ASSERT(NULL != sphin); 55 ASSERT(NULL != out_config); 56 57 config = MEM_CALLOC(sphin->allocator, 1, sizeof(struct sphin_config)); 58 if (NULL == config) { 59 res = RES_MEM_ERR; 60 goto error; 61 } 62 63 ref_init(&config->ref); 64 darray_sphin_volume_ptr_init(sphin->allocator, &config->volumes); 65 darray_sphin_surface_ptr_init(sphin->allocator, &config->surfaces); 66 config->sphin = sphin; 67 SPHIN(ref_get(sphin)); 68 69 exit: 70 *out_config = config; 71 return res; 72 error: 73 if (NULL != config) { 74 SPHIN(config_ref_put(config)); 75 config = NULL; 76 } 77 goto exit; 78 } 79 80 static void 81 release_config 82 (ref_T* address) 83 { 84 struct sphin_config* config = NULL; 85 struct sphin* sphin = NULL; 86 size_t i, nvolumes, nsurfaces; 87 struct sphin_volume** volumes = NULL; 88 struct sphin_surface** surfaces = NULL; 89 ASSERT(NULL != address); 90 config = CONTAINER_OF(address, struct sphin_config, ref); 91 92 /* Retrieve the number of volumes in the config and the array of pointers to 93 * each one of the volumes */ 94 nvolumes = darray_sphin_volume_ptr_size_get(&config->volumes); 95 volumes = darray_sphin_volume_ptr_data_get(&config->volumes); 96 97 /* Put references for each one of the volumes */ 98 FOR_EACH(i, 0, nvolumes) { 99 SPHIN(volume_ref_put(volumes[i])); 100 }; 101 darray_sphin_volume_ptr_release(&config->volumes); 102 103 /* Retrieve the number of surfaces in the config and the array of pointers to 104 * each one of the surfaces */ 105 nsurfaces = darray_sphin_surface_ptr_size_get(&config->surfaces); 106 surfaces = darray_sphin_surface_ptr_data_get(&config->surfaces); 107 108 /* Put references for each one of the surfaces */ 109 FOR_EACH(i, 0, nsurfaces) { 110 SPHIN(surface_ref_put(surfaces[i])); 111 }; 112 darray_sphin_surface_ptr_release(&config->surfaces); 113 114 /* Release the memory for config */ 115 sphin = config->sphin; 116 MEM_RM(sphin->allocator, config); 117 118 /* Put the reference for sphin */ 119 SPHIN(ref_put(sphin)); 120 } 121 122 static res_T 123 load_stream 124 (struct sphin* sphin, 125 FILE* stream, 126 const char* streamname, 127 struct sphin_config** out_config) 128 { 129 struct sphin_config* config = NULL; 130 struct txtrdr* txtrdr = NULL; 131 struct str line; 132 char* keyword = NULL; 133 char* name = NULL; 134 char* token = NULL; 135 char* token_ptr = NULL; 136 res_T res = RES_OK; 137 138 ASSERT(NULL != sphin); 139 ASSERT(NULL != stream); 140 ASSERT(NULL != streamname); 141 ASSERT(NULL != out_config); 142 143 str_init(sphin->allocator, &line); 144 145 res = config_create(sphin, &config); 146 if (RES_OK != res) { goto error; } 147 148 res = txtrdr_stream(sphin->allocator, stream, streamname, '#', &txtrdr); 149 if (RES_OK != res) { goto error; } 150 151 res = txtrdr_read_line(txtrdr); 152 if (RES_OK != res) { goto error; } 153 154 while (NULL != txtrdr_get_line(txtrdr)) { 155 res = str_set(&line, txtrdr_get_cline(txtrdr)); 156 if (RES_OK != res) { goto error; } 157 /* parse keyword */ 158 token = strtok_r(str_get(&line), ":", &token_ptr); 159 keyword = trim_keyword(token); 160 if (NULL == keyword){ res = RES_BAD_ARG; goto error; } 161 /* parse value (name) */ 162 token = token_ptr; 163 if (NULL == token){ res = RES_BAD_ARG; goto error; } 164 name = trim_string(token); 165 if (NULL == name){ res = RES_BAD_ARG; goto error; } 166 if (0 == strcmp(keyword, "volume")){ 167 res = parse_volume(config, txtrdr, name); 168 } 169 else if (0 == strcmp(keyword, "surface")){ 170 res = parse_surface(config, txtrdr, name); 171 } 172 else { 173 res = RES_BAD_ARG; 174 ERROR 175 (sphin, 176 "%s: %lu: Bad keyword\n", 177 txtrdr_get_name(txtrdr), txtrdr_get_line_num(txtrdr)); 178 goto error; 179 } 180 if (RES_OK != res) { 181 ERROR 182 (sphin, 183 "%s: %lu: Parsing error\n", 184 txtrdr_get_name(txtrdr), txtrdr_get_line_num(txtrdr)); 185 goto error; 186 } 187 } 188 189 exit: 190 str_release(&line); 191 *out_config = config; 192 if (NULL != txtrdr) { 193 txtrdr_ref_put(txtrdr); 194 } 195 return res; 196 error: 197 if (NULL != config) { 198 SPHIN(config_ref_put(config)); 199 config = NULL; 200 } 201 ERROR 202 (sphin, 203 "%s: %s: Error while loading stream -- %s\n", 204 __FILE__, FUNC_NAME, res_to_cstr(res)); 205 goto exit; 206 } 207 208 /******************************************************************************* 209 * Local functions 210 ******************************************************************************/ 211 char* /* 'volume' */ 212 trim_keyword 213 (char* str) /* ' volume ' */ 214 { 215 char* token_ptr = NULL; 216 char* token = NULL; 217 char* remaining_token = NULL; 218 219 ASSERT(NULL != str); 220 221 token = strtok_r(str, " \t", &token_ptr); 222 /* If no token was found (empty string or invalid input) */ 223 if (NULL == token) return NULL; 224 225 /* Check for any remaining tokens to ensure there's only one word in the 226 * string. */ 227 remaining_token = strtok_r(NULL, " \t", &token_ptr); 228 if (NULL != remaining_token) return NULL; 229 230 return token; 231 } 232 233 char* 234 trim_string 235 (char* str) 236 { 237 char* a = NULL; 238 char* b = NULL; 239 size_t len = 0; 240 241 ASSERT(NULL != str); 242 243 a = strchr(str, '"'); /* find the first occurrence of " */ 244 b = strrchr(str, '"'); /* find the last occurrence of " */ 245 246 if (a == b) { 247 /* Either there is only one " or both are NULL (no ") */ 248 return NULL; 249 } 250 251 if (a+1 == b) { 252 /* The string between quotes is empty */ 253 return NULL; 254 } 255 256 len = strspn(str, " \t"); 257 if (str + len != a) { 258 /* There are characters before the first " other than spaces and tabs */ 259 return NULL; 260 } 261 262 len = strspn(b+1, " \t"); /* Analyzes the part of str after b */ 263 if (b[1+len] != '\0') { 264 /* There are characters after the second " other than spaces and tabs */ 265 return NULL; 266 } 267 /* '"mon volume\0 \0' 268 * ^ ^ 269 * a b */ 270 *b = '\0'; 271 return a+1; 272 } 273 274 /******************************************************************************* 275 * Exported functions 276 ******************************************************************************/ 277 res_T 278 sphin_load 279 (struct sphin* sphin, 280 const char* filename, 281 struct sphin_config** config) 282 { 283 FILE* stream = NULL; 284 res_T res = RES_OK; 285 286 if (sphin == NULL || filename == NULL || config == NULL) { 287 res = RES_BAD_ARG; 288 goto error; 289 } 290 291 stream = fopen(filename, "r"); 292 if (NULL == stream) { 293 ERROR(sphin, "Not possible to open file %s -- %s\n", 294 filename, strerror(errno)); 295 res = RES_IO_ERR; 296 goto error; 297 } 298 299 res = load_stream(sphin, stream, filename, config); 300 if (RES_OK != res) { 301 goto error; 302 } 303 304 exit: 305 if (NULL != stream) { 306 fclose(stream); 307 } 308 return res; 309 310 error: 311 goto exit; 312 } 313 314 res_T 315 sphin_load_stream 316 (struct sphin* sphin, 317 FILE* stream, 318 const char* streamname, 319 struct sphin_config** config) 320 { 321 if (NULL == sphin 322 || NULL == stream 323 || NULL == streamname 324 || NULL == config) { 325 return RES_BAD_ARG; 326 } 327 return load_stream(sphin, stream, streamname, config); 328 } 329 330 res_T 331 sphin_config_ref_get 332 (struct sphin_config* config) 333 { 334 if (NULL == config) { 335 return RES_BAD_ARG; 336 } 337 ref_get(&config->ref); 338 return RES_OK; 339 } 340 341 res_T 342 sphin_config_ref_put 343 (struct sphin_config* config) 344 { 345 if (NULL == config) { 346 return RES_BAD_ARG; 347 } 348 ref_put(&config->ref, release_config); 349 return RES_OK; 350 } 351 352 res_T 353 sphin_config_get_volume_count 354 (struct sphin_config* config, 355 size_t* nvolumes) 356 { 357 res_T res = RES_OK; 358 if (NULL == config || NULL == nvolumes) { 359 return RES_BAD_ARG; 360 } 361 *nvolumes = darray_sphin_volume_ptr_size_get(&config->volumes); 362 return res; 363 } 364 365 res_T 366 sphin_config_get_volume 367 (struct sphin_config* config, 368 size_t ivolume, 369 struct sphin_volume** volume) 370 { 371 res_T res = RES_OK; 372 size_t nvolumes; 373 374 if (NULL == config || NULL == volume) { 375 return RES_BAD_ARG; 376 } 377 378 nvolumes = darray_sphin_volume_ptr_size_get(&config->volumes); 379 if (ivolume > nvolumes) { 380 return RES_BAD_ARG; 381 } 382 383 *volume = darray_sphin_volume_ptr_data_get(&config->volumes)[ivolume]; 384 return res; 385 } 386 387 res_T 388 sphin_config_get_surface_count 389 (struct sphin_config* config, 390 size_t* nsurfaces) 391 { 392 res_T res = RES_OK; 393 if (NULL == config || NULL == nsurfaces) { 394 return RES_BAD_ARG; 395 } 396 *nsurfaces = darray_sphin_surface_ptr_size_get(&config->surfaces); 397 return res; 398 } 399 400 res_T 401 sphin_config_get_surface 402 (struct sphin_config* config, 403 size_t isurface, 404 struct sphin_surface** surface) 405 { 406 res_T res = RES_OK; 407 size_t nsurfaces; 408 409 if (NULL == config || NULL == surface) { 410 return RES_BAD_ARG; 411 } 412 413 nsurfaces = darray_sphin_surface_ptr_size_get(&config->surfaces); 414 if (isurface > nsurfaces) { 415 return RES_BAD_ARG; 416 } 417 418 *surface = darray_sphin_surface_ptr_data_get(&config->surfaces)[isurface]; 419 return res; 420 } 421 422 res_T 423 sphin_config_get_total_surface_power 424 (struct sphin_config* config, 425 double* total_power) 426 { 427 double source_pow = 0; 428 struct sphin_surface* surface = NULL; 429 struct sphin_source_surface* source = NULL; 430 size_t surface_count = 0; 431 size_t i = 0; 432 res_T res = RES_OK; 433 434 if (NULL == config) { res = RES_BAD_ARG; goto error; } 435 if (NULL == total_power) { res = RES_BAD_ARG; goto error; } 436 437 res = sphin_config_get_surface_count(config, &surface_count); 438 if (RES_OK != res) { goto error; } 439 440 FOR_EACH(i, 0, surface_count) { 441 res = sphin_config_get_surface(config, i, &surface); 442 if (RES_OK != res) { goto error; } 443 444 res = sphin_surface_get_source(surface, &source); 445 if (RES_OK != res) { goto error; } 446 447 if (NULL != source) { 448 res = sphin_surface_source_get_power(surface, &source_pow); 449 if (RES_OK != res) { goto error; } 450 451 *total_power += source_pow; 452 } 453 } 454 455 exit: 456 return res; 457 error: 458 goto exit; 459 }