star-phor-input

File format for describing photoreactor configurations
git clone https://www.edstar.cnrs.fr/git/star-phor-input.git
Log | Files | Refs | README | LICENSE

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 }