star-mesh

Define and load a binary data format for meshes
git clone git://git.meso-star.fr/star-mesh.git
Log | Files | Refs | README | LICENSE

vtk-data.c (6680B)


      1 /* Copyright (C) 2020-2023, 2025 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #define _POSIX_C_SOURCE 200112L /* getopt support */
     17 
     18 #include <rsys/cstr.h>
     19 #include <rsys/mem_allocator.h>
     20 #include <rsys/str.h>
     21 #include <rsys/text_reader.h>
     22 
     23 #include <errno.h>
     24 #include <string.h>
     25 #include <unistd.h> /* getopt */
     26 
     27 #define MAX_DATA 8
     28 
     29 /* Input arguments */
     30 struct args {
     31   const char* output;
     32   const char* data;
     33   unsigned long nitems;
     34   const char* names[MAX_DATA];
     35   unsigned ndata;
     36 };
     37 static const struct args ARGS_DEFAULT = {0};
     38 
     39 /* Command data */
     40 struct cmd {
     41   const char* names[MAX_DATA];
     42   const char* data_name;
     43   FILE* output;
     44   FILE* data;
     45   size_t nitems;
     46 };
     47 static const struct cmd CMD_NULL = {0};
     48 
     49 /*******************************************************************************
     50  * Helper functions
     51  ******************************************************************************/
     52 static INLINE void
     53 usage(FILE* stream)
     54 {
     55   fprintf(stream,
     56     "usage: vtk-data [-n name ...] [-o output] -c cell_count [data]\n");
     57 }
     58 
     59 static res_T
     60 parse_name(struct args* args, const char* name)
     61 {
     62   unsigned i;
     63   ASSERT(name);
     64 
     65   if(args->ndata >= MAX_DATA) {
     66     fprintf(stderr, "too many names\n");
     67     return RES_BAD_ARG;
     68   }
     69 
     70   /* Names cannot contain white spaces */
     71   if(strcspn(name, " \t") != strlen(name)) {
     72     fprintf(stderr, "name \"%s\" cannot contain white spaces \n", name);
     73     return RES_BAD_ARG;
     74   }
     75 
     76   /* Names must be unique */
     77   FOR_EACH(i, 0, args->ndata) {
     78     if(!strcmp(args->names[i], name)) {
     79       fprintf(stderr, "name \"%s\" already defined\n", name);
     80       return RES_BAD_ARG;
     81     }
     82   }
     83 
     84   args->names[args->ndata++] = name;
     85   return RES_OK;
     86 }
     87 
     88 static res_T
     89 args_init(struct args* args, const int argc, char** argv)
     90 {
     91   int opt = 0;
     92   res_T res = RES_OK;
     93 
     94   *args = ARGS_DEFAULT;
     95 
     96   while((opt = getopt(argc, argv, "o:c:n:")) != -1) {
     97     switch(opt) {
     98       case 'n': res = parse_name(args, optarg); break;
     99       case 'o': args->output = optarg; break;
    100       case 'c':
    101         res = cstr_to_ulong(optarg, &args->nitems);
    102         if(res == RES_OK && args->nitems == 0) res = RES_BAD_ARG;
    103         break;
    104       default: res = RES_BAD_ARG; goto error;
    105     }
    106     if(res != RES_OK) goto error;
    107   }
    108 
    109   if(optind < argc) args->data = argv[optind];
    110 
    111   if(!args->nitems) {
    112     fprintf(stderr, "missing item count -- option '-c'\n");
    113     res = RES_BAD_ARG;
    114     goto error;
    115   }
    116 
    117 exit:
    118   return res;
    119 error:
    120   usage(stderr);
    121   goto exit;
    122 }
    123 
    124 static void
    125 cmd_release(struct cmd* cmd)
    126 {
    127   if(cmd->data && cmd->data != stdin) CHK(!fclose(cmd->data));
    128   if(cmd->output && cmd->output != stdout) CHK(!fclose(cmd->output));
    129 }
    130 
    131 static res_T
    132 cmd_init(struct cmd* cmd, const struct args* args)
    133 {
    134   res_T res = RES_OK;
    135   ASSERT(cmd && args);
    136 
    137   if(!(cmd->output = args->output ? fopen(args->output, "w") : stdout)) {
    138     perror(args->output);
    139     res = RES_IO_ERR;
    140     goto error;
    141   }
    142 
    143   if(!(cmd->data = args->data ? fopen(args->data, "r") : stdin)) {
    144     perror(args->data);
    145     res = RES_IO_ERR;
    146     goto error;
    147   }
    148 
    149   cmd->data_name = args->data ? args->data : "stdin";
    150   memcpy(cmd->names, args->names, sizeof(char*[MAX_DATA]));
    151   cmd->nitems = args->nitems;
    152 
    153 exit:
    154   return res;
    155 error:
    156   cmd_release(cmd);
    157   goto exit;
    158 }
    159 
    160 static res_T
    161 write_data(struct cmd* cmd, const int idata, struct txtrdr* txtrdr)
    162 {
    163   size_t i = 0;
    164   int res = RES_OK;
    165 
    166   /* Pre-conditions */
    167   ASSERT(cmd && idata < MAX_DATA && txtrdr);
    168   ASSERT(txtrdr_get_line(txtrdr));
    169 
    170   if(cmd->names[idata]) {
    171     res = fprintf(cmd->output, "SCALARS %s double 1\n", cmd->names[idata]);
    172   } else {
    173     /* Make default name unique */
    174     res = fprintf(cmd->output, "SCALARS data%d double 1\n", idata);
    175   }
    176   if(res < 0) {
    177     perror(NULL);
    178     res = RES_IO_ERR;
    179     goto error;
    180   }
    181 
    182   if(fprintf(cmd->output, "LOOKUP_TABLE default\n") < 0) {
    183     perror(NULL);
    184     res = RES_IO_ERR;
    185     goto error;
    186   }
    187 
    188   FOR_EACH(i, 0, cmd->nitems) {
    189     const char* line = NULL;
    190     double f = 0;
    191 
    192     if(!(line = txtrdr_get_line(txtrdr))) {
    193       fprintf(stderr, "missing data\n");
    194       res = RES_BAD_ARG;
    195       goto error;
    196     }
    197 
    198     if((sscanf(line, "%lf\n", &f)) != 1) {
    199       fprintf(stderr, "%s:%lu: unable to read double\n",
    200         txtrdr_get_name(txtrdr), txtrdr_get_line_num(txtrdr));
    201       res = RES_IO_ERR;
    202       goto error;
    203     }
    204 
    205     if(fprintf(cmd->output, "%lf\n", f) < 0) {
    206       perror(NULL);
    207       res = RES_IO_ERR;
    208       goto error;
    209     }
    210 
    211     if((res = txtrdr_read_line(txtrdr)) != RES_OK) {
    212       fprintf(stderr, "%s\n", res_to_cstr(res));
    213       goto error;
    214     }
    215   }
    216 
    217 exit:
    218   return res;
    219 error:
    220   goto exit;
    221 }
    222 
    223 static res_T
    224 cmd_run(struct cmd* cmd)
    225 {
    226   struct txtrdr* txtrdr = NULL;
    227   int i = 0;
    228   res_T res = RES_OK;
    229   ASSERT(cmd);
    230 
    231   res = txtrdr_stream(NULL, cmd->data, cmd->data_name, '#', &txtrdr);
    232   if(res != RES_OK) {
    233     fprintf(stderr, "%s\n", res_to_cstr(res));
    234     goto error;
    235   }
    236 
    237   if((res = txtrdr_read_line(txtrdr)) != RES_OK) {
    238     fprintf(stderr, "%s\n", res_to_cstr(res));
    239     goto error;
    240   }
    241 
    242   if(!txtrdr_get_line(txtrdr)) goto exit; /* No data  */
    243 
    244   if(fprintf(cmd->output, "CELL_DATA %zu\n", cmd->nitems) < 0) {
    245     fprintf(stderr, "%s\n", strerror(errno));
    246     res = RES_IO_ERR;
    247     goto error;
    248   }
    249 
    250   FOR_EACH(i, 0, MAX_DATA) {
    251     if((res = write_data(cmd, i, txtrdr)) != RES_OK) goto error;
    252     if(!txtrdr_get_line(txtrdr)) break; /* No more data */
    253   }
    254 
    255 exit:
    256   if(txtrdr) txtrdr_ref_put(txtrdr);
    257   return res;
    258 error:
    259   goto exit;
    260 }
    261 
    262 /*******************************************************************************
    263  * Main function
    264  ******************************************************************************/
    265 int
    266 main(int argc, char** argv)
    267 {
    268   struct args args = ARGS_DEFAULT;
    269   struct cmd cmd = CMD_NULL;
    270   int err = 0;
    271   res_T res = RES_OK;
    272 
    273   if((res = args_init(&args, argc, argv)) != RES_OK) goto error;
    274   if((res = cmd_init(&cmd, &args)) != RES_OK) goto error;
    275   if((res = cmd_run(&cmd)) != RES_OK) goto error;
    276 
    277 exit:
    278   cmd_release(&cmd);
    279   CHK(mem_allocated_size() == 0);
    280   return err;
    281 error:
    282   err = 1;
    283   goto exit;
    284 }