FMS 2025.01.02-dev
Flexible Modeling System
Loading...
Searching...
No Matches
yaml_parser_binding.c
1/***********************************************************************
2 * GNU Lesser General Public License
3 *
4 * This file is part of the GFDL Flexible Modeling System (FMS).
5 *
6 * FMS is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or (at
9 * your option) any later version.
10 *
11 * FMS is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 **********************************************************************/
19
20#ifdef use_yaml
21
22#include <stdio.h>
23#include <yaml.h>
24#include <stdbool.h>
25
26/* Type to store info about key */
27typedef struct {
28 int key_number; /* Id of this key */
29 char key[255]; /* Name of the key */
30 char value[255]; /* Value of the key */
31 char parent_name[255]; /* Name of the block the key belongs to */
32 int parent_key; /* Id of the block the key belongs to */
33}key_value_pairs;
34
35/* Type to store all of the keys */
36typedef struct {
37 int nkeys;
38 key_value_pairs *keys;
39}yaml_file;
40
41/* Type to store all the yaml files that are opened */
42typedef struct {
43 yaml_file *files;
44}file_type;
45
46file_type my_files; /* Array of opened yaml files */
47int nfiles = 0; /* Number of files in the yaml file */
48
49/* @brief Private c function that gets the number of key-value pairs in a block
50 @return Number of key-value pairs in this block */
51int get_nkeys_binding(int *file_id, int *block_id)
52{
53 int nkeys = 0; /* Number of key-value pairs */
54 int i; /* For loops */
55 int j = *file_id; /* To minimize the typing :) */
56
57 for ( i = 1; i <= my_files.files[j].nkeys; i++ )
58 {
59 if(my_files.files[j].keys[i].parent_key == *block_id && !strcmp(my_files.files[j].keys[i].parent_name, "") ) nkeys = nkeys + 1;
60 }
61
62 return nkeys;
63
64}
65
66/* @brief Private c function that gets the ids of the key-value pairs in a block */
67void get_key_ids_binding(int *file_id, int *block_id, int *key_ids)
68{
69 int i; /* For loops */
70 int key_count = -1; /* Number of key-value pairs */
71 int j = *file_id; /* To minimize the typing :) */
72
73 for ( i = 1; i <= my_files.files[j].nkeys; i++ )
74 {
75 if(my_files.files[j].keys[i].parent_key == *block_id && !strcmp(my_files.files[j].keys[i].parent_name, "") ){
76 key_count = key_count + 1;
77 key_ids[key_count] = i;
78 }
79 }
80
81 return;
82}
83
84/* @brief Private c function that get the key from a key_id in a yaml file
85 @return Name of the key obtained */
86char *get_key(int *file_id, int *key_id)
87{
88 int j = *file_id; /* To minimize the typing :) */
89 return my_files.files[j].keys[*key_id].key;
90}
91
92/* @brief Private c function that get the value from a key_id in a yaml file
93 @return String containing the value obtained */
94char *get_value(int *file_id, int *key_id)
95{
96 int j = *file_id; /* To minimize the typing :) */
97 return my_files.files[j].keys[*key_id].value;
98}
99
100/* @brief Private c functions get gets the block name from a block id
101 @return String containing the value obtained */
102char *get_block(int *file_id, int *block_id)
103{
104 int j = *file_id; /* To minimize the typing :) */
105 return my_files.files[j].keys[*block_id].parent_name;
106}
107
108/* @brief Private c function that determines they value of a key in yaml_file
109 @return c pointer with the value obtained */
110char *get_value_from_key_wrap(int *file_id, int *block_id, char *key_name, int *sucess) /*, char *key_name) */
111{
112 int i; /* For loops */
113 int j = *file_id; /* To minimize the typing :) */
114
115 *sucess = 0; /* Flag indicating if the search was sucessful */
116
117 for ( i = 1; i <= my_files.files[j].nkeys; i++ )
118 {
119 if (my_files.files[j].keys[i].parent_key == *block_id)
120 {
121 if( strcmp(my_files.files[j].keys[i].key, key_name) == 0)
122 {
123 *sucess = 1;
124 break;
125 }
126 }
127 }
128 if (*sucess == 1) {return my_files.files[j].keys[i].value;} else {return "";}
129}
130
131/* @brief Private c function that determines the number of blocks with block_name in the yaml file
132 @return Number of blocks with block_name */
133int get_num_blocks_all(int *file_id, char *block_name)
134{
135 int nblocks = 0; /* Number of blocks */
136 int i; /* For loops */
137 int j = *file_id; /* To minimize the typing :) */
138
139 for ( i = 1; i <= my_files.files[j].nkeys; i++ )
140 {
141 if(strcmp(my_files.files[j].keys[i].parent_name, block_name) == 0) nblocks = nblocks + 1;
142 }
143
144 return nblocks;
145}
146
147/* @brief Private c function that determines the number of unique blocks (i.e diag_files, varlist, etc)
148 @return The number of unique blocks */
149int get_num_unique_blocks_bind(int *file_id, int *parent_block_id)
150{
151 int nblocks = 0; /* Number of blocks */
152 int i; /* For loops */
153 int j = *file_id; /* To minimize the typing :) */
154 char block_names[my_files.files[j].nkeys][255]; /* Array that stores the names of the unique blocks*/
155 bool found; /* True if the block name was already found (i.e it not unqiue)*/
156 int k; /* For loops */
157
158 for ( i = 1; i <= my_files.files[j].nkeys; i++ )
159 {
160 if (my_files.files[j].keys[i].parent_key == *parent_block_id )
161 {
162 if (strcmp(my_files.files[j].keys[i].parent_name, "") == 0){
163 continue;
164 }
165 found = false;
166 for (k = 1; k <= nblocks; k++)
167 {
168 if (strcmp(block_names[k], my_files.files[j].keys[i].parent_name) == 0)
169 {
170 found = true;
171 break;
172 }
173 }
174
175 if (found) continue;
176
177 nblocks = nblocks + 1;
178 strcpy(block_names[nblocks], my_files.files[j].keys[i].parent_name);
179 // printf("Block names: %s \n", block_names[nblocks]);
180 }
181 }
182 return nblocks;
183}
184
185/* @brief Private c function that determines the ids of the unique blocks (i.e diag_files, varlist, etc)
186 @return The ids of the unique blocks */
187void get_unique_block_ids_bind(int *file_id, int *block_ids, int *parent_block_id)
188{
189 int nblocks = 0; /* Number of blocks */
190 int i; /* For loops */
191 int j = *file_id; /* To minimize the typing :) */
192 char block_names[my_files.files[j].nkeys][255]; /* Array that stores the names of the unique blocks*/
193 bool found; /* True if the block name was already found (i.e it not unqiue)*/
194 int k; /* For loops */
195
196 for ( i = 1; i <= my_files.files[j].nkeys; i++ )
197 {
198 if (my_files.files[j].keys[i].parent_key == *parent_block_id )
199 {
200 if (strcmp(my_files.files[j].keys[i].parent_name, "") == 0){
201 continue;
202 }
203 found = false;
204 for (k = 1; k <= nblocks; k++)
205 {
206 if (strcmp(block_names[k], my_files.files[j].keys[i].parent_name) == 0)
207 {
208 found = true;
209 break;
210 }
211 }
212
213 if (found) continue;
214
215 nblocks = nblocks + 1;
216 block_ids[nblocks - 1] = my_files.files[j].keys[i].key_number;
217 strcpy(block_names[nblocks], my_files.files[j].keys[i].parent_name);
218 //printf("Block names: %s \n", block_names[nblocks]);
219 }
220 }
221 return;
222}
223/* @brief Private c function that determines the number of blocks with block_name that belong to
224 a parent block with parent_block_id in the yaml file
225 @return Number of blocks with block_name */
226int get_num_blocks_child(int *file_id, char *block_name, int *parent_block_id)
227{
228 int nblocks = 0; /* Number of blocks */
229 int i; /* For loops */
230 int j = *file_id; /* To minimize the typing :) */
231
232 for ( i = 1; i <= my_files.files[j].nkeys; i++ )
233 {
234 if(strcmp(my_files.files[j].keys[i].parent_name, block_name) == 0 && my_files.files[j].keys[i].parent_key == *parent_block_id) nblocks = nblocks + 1;
235 }
236
237 return nblocks;
238}
239
240
241/* @brief Private c function that gets the the ids of the blocks with block_name in the yaml file */
242void get_block_ids_all(int *file_id, char *block_name, int *block_ids)
243{
244 int i; /* For loops */
245 int nblocks = -1; /* Number of blocks */
246 int j = *file_id; /* To minimize the typing :) */
247
248 for ( i = 1; i <= my_files.files[j].nkeys; i++ )
249 {
250 if(strcmp(my_files.files[j].keys[i].parent_name, block_name) == 0) {
251 nblocks = nblocks + 1;
252 block_ids[nblocks] = my_files.files[j].keys[i].key_number;
253 }
254 }
255 return;
256}
257
258/* @brief Private c function that gets the the ids of the blocks with block_name and that
259 belong to a parent block id in the yaml file */
260void get_block_ids_child(int *file_id, char *block_name, int *block_ids, int *parent_key_id )
261{
262 int i; /* For loops */
263 int nblocks = -1; /* Number of blocks */
264 int j = *file_id; /* To minimize the typing :) */
265
266 for ( i = 1; i <= my_files.files[j].nkeys; i++ )
267 {
268 if(strcmp(my_files.files[j].keys[i].parent_name, block_name) == 0 && my_files.files[j].keys[i].parent_key == *parent_key_id) {
269 nblocks = nblocks + 1;
270 block_ids[nblocks] = my_files.files[j].keys[i].key_number;
271 }
272 }
273 return;
274}
275
276/* @brief Private c function to determine if a block_id is valid */
277bool is_valid_block_id(int *file_id, int *block_id)
278{
279 /* If the block id it not in the allowed range is not a valid block id */
280 if (*block_id <= -1 || *block_id > my_files.files[*file_id].nkeys) {return false;}
281
282 /* If the block id has an empty parent name then it is not a valid block id */
283 if (*block_id != 0 && strcmp(my_files.files[*file_id].keys[*block_id].parent_name, "") == 0) {return false;}
284 return true;
285}
286
287/* @brief Private c function to determine if a key_id is valid */
288bool is_valid_key_id(int *file_id, int *key_id)
289{
290 if (*key_id > -1 && *key_id <= my_files.files[*file_id].nkeys) {return true;}
291 else { return false;}
292}
293
294/* @brief Private c function to determine if a file_id is valid */
295bool is_valid_file_id(int *file_id)
296{
297 if (*file_id > -1 && *file_id < nfiles) {return true;}
298 else { return false;}
299}
300
301/* @brief Private c function that opens and parses a yaml file and saves it in a struct
302 @return Flag indicating if the read was sucessful */
303int open_and_parse_file_wrap(char *filename, int *file_id)
304{
305 yaml_parser_t parser;
306 yaml_token_t token;
307 FILE *file;
308
309 bool is_key = false; /* Flag indicating if the current token in a key */
310 char key_value[255]; /* Value of a key */
311 int layer = 0; /* Current layer (block level) */
312 int key_count=0; /* Current number of keys */
313 int parent[10]; /* Ids of blocks */
314 int current_parent; /* Id of the current block */
315 char layer_name[10][255]; /* Array of block names */
316 char current_layername[255]; /* Name of the current block */
317 int i; /* To minimize the typing :) */
318 int j; /* To minimize the typing :) */
319
320 if (nfiles == 0 )
321 {
322 my_files.files = (yaml_file*)calloc(1, sizeof(yaml_file));
323 } else
324 {
325 my_files.files = realloc(my_files.files, (nfiles+1)*sizeof(yaml_file));
326 }
327
328 j = nfiles;
329 *file_id =j;
330
331/* printf("Opening file: %s.\nThere are %i files opened.\n", filename, j); */
332 file = fopen(filename, "r");
333 if (file == NULL) return -1;
334
335 if(!yaml_parser_initialize(&parser)) return -2;
336
337 my_files.files[j].keys = (key_value_pairs*)calloc(1, sizeof(key_value_pairs));
338
339 parent[0]=0;
340 strcpy(layer_name[0], "TOP");
341 /* Set input file */
342 yaml_parser_set_input_file(&parser, file);
343 do {
344 if (!yaml_parser_scan(&parser, &token)) {
345 return -3;
346 }
347 switch(token.type)
348 {
349 case YAML_KEY_TOKEN:
350 {
351 is_key = true;
352 break;
353 }
354 case YAML_VALUE_TOKEN:
355 {
356 is_key = false;
357 break;
358 }
359 case YAML_BLOCK_ENTRY_TOKEN:
360 {
361 layer = layer + 1;
362
363 if (strcmp(key_value, ""))
364 {
365 strcpy(layer_name[layer], key_value);
366 }
367 key_count = key_count + 1;
368 i = key_count;
369 my_files.files[j].keys = realloc(my_files.files[j].keys, (i+1)*sizeof(key_value_pairs));
370 my_files.files[j].keys[i].key_number=i;
371 my_files.files[j].keys[i].parent_key = parent[layer-1];
372 strcpy(my_files.files[j].keys[i].parent_name, layer_name[layer]);
373 strcpy(my_files.files[j].keys[i].key, "");
374 strcpy(my_files.files[j].keys[i].value, "");
375 parent[layer]=key_count;
376 /*printf("KEY:%i LAYER:%i NAME:%s for %s=%i\n", key_count, layer, layer_name[layer], layer_name[layer-1], parent[layer-1]); */
377
378 break;
379 }
380 case YAML_BLOCK_END_TOKEN:
381 {
382 layer = layer - 1;
383 break;
384 }
385 case YAML_SCALAR_TOKEN:
386 {
387 if ( ! is_key)
388 {
389 current_parent = parent[layer];
390 strcpy(current_layername, "");
391 key_count = key_count + 1;
392 i = key_count;
393 my_files.files[j].keys = realloc(my_files.files[j].keys, (i+1)*sizeof(key_value_pairs));
394 my_files.files[j].keys[i].key_number=i;
395 my_files.files[j].keys[i].parent_key = current_parent;
396 strcpy(my_files.files[j].keys[i].parent_name, current_layername);
397 strcpy(my_files.files[j].keys[i].key, key_value);
398 strcpy(my_files.files[j].keys[i].value, token.data.scalar.value);
399 my_files.files[j].nkeys = key_count;
400 /* printf("----> LAYER:%i LAYER_NAME=%s PARENT:%i, KEYCOUNT:%i KEY: %s VALUE: %s \n", layer, current_layername, current_parent, key_count, key_value, token.data.scalar.value); */
401 strcpy(key_value,"");
402 }
403 else
404 {strcpy(key_value,token.data.scalar.value);}
405 }
406 break;
407 }
408 if(token.type != YAML_STREAM_END_TOKEN)
409 yaml_token_delete(&token);
410 } while(token.type != YAML_STREAM_END_TOKEN);
411 yaml_token_delete(&token);
412 yaml_parser_delete(&parser);
413
414 /*
415 for ( i = 1; i <= my_files.files[j].nkeys; i++ ) {
416 printf("Key_number:%i Parent_key:%i Parent_name:%s Key:%s Value:%s \n", my_files.files[j].keys[i].key_number, my_files.files[j].keys[i].parent_key, my_files.files[j].keys[i].parent_name, my_files.files[j].keys[i].key, my_files.files[j].keys[i].value);
417 }
418 printf("/\n");
419 */
420
421 nfiles = nfiles + 1;
422/* printf("closing file: %s\n", filename); */
423 fclose(file);
424
425 return 1;
426}
427
428#endif