FMS  2025.04
Flexible Modeling System
yaml_parser_binding.c
1 /***********************************************************************
2  * Apache License 2.0
3  *
4  * This file is part of the GFDL Flexible Modeling System (FMS).
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * FMS is distributed in the hope that it will be useful, but WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
14  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15  * PARTICULAR PURPOSE. See the License for the specific language
16  * governing permissions and limitations under the License.
17  ***********************************************************************/
18 
19 #ifdef use_yaml
20 
21 #include <stdio.h>
22 #include <yaml.h>
23 #include <stdbool.h>
24 
25 // TODO: FMS_MAX_FILE_LEN is repeated from fms_platform.h.
26 // Consider consolidating constant definitions or using a shared header.
27 #ifndef FMS_MAX_FILE_LEN
28 #define FMS_MAX_FILE_LEN 255
29 #endif
30 
31 #define FMS_FILE_LEN FMS_MAX_FILE_LEN
32 
33 // TODO: These constants are also defined in yaml_parser.F90
34 // Consider consolidating constant definitions or using a shared header.
35 const int MISSING_FILE = -1;
36 const int PARSER_INIT_ERROR = -2;
37 const int INVALID_YAML = -3;
38 const int INVALID_ALIAS = -4;
39 const int MAX_LEVELS_REACH = -5;
40 const int SUCCESSFUL = 1;
41 
42 #ifndef MAX_LEVELS
43 #define MAX_LEVELS 10
44 #endif
45 
46 // DEBUG_FMS_YAML_PARSER is a hidden macro that may be useful when debugging parser issues
47 #ifdef DEBUG_FMS_YAML_PARSER
48  #define DEBUG_PRINT(...) printf(__VA_ARGS__)
49 #else
50  #define DEBUG_PRINT(...) // nothing
51 #endif
52 
53 /**
54  * @brief Represents a key-value pair within a YAML file.
55  *
56  * Includes metadata for tracking the key's structure and origin.
57  */
58 typedef struct {
59  int key_id; ///< ID of this key
60  char key[FMS_FILE_LEN]; ///< Name of the key
61  char value[FMS_FILE_LEN]; ///< Value associated with the key
62  char parent_name[FMS_FILE_LEN]; ///< Name of the parent block
63  int parent_key; ///< ID of the parent block
64 } KeyValuePairs;
65 
66 /**
67  * @brief Represents the contents of a YAML anchor as an array of key-value pairs.
68  */
69 typedef struct {
70  int nkeys; ///< Number of keys defined for the anchor
71  KeyValuePairs *keys; ///< Array of key-value pairs
72  char anchor_name[FMS_FILE_LEN]; ///< Name of the anchor
73  int nlevels;
74  int pid[MAX_LEVELS];
75  char parent_names[MAX_LEVELS][FMS_FILE_LEN];
76 } AnchorsType;
77 
78 /**
79  * @brief Represents the contents of a YAML file as an array of key-value pairs.
80  */
81 typedef struct {
82  int nkeys; ///< Number of keys defined in the YAML file
83  KeyValuePairs *keys; ///< Array of key-value pairs
84  AnchorsType *Anchors; ///< Array of anchors in the yaml file
85  int nanchors; ///< Number of anchors that have been defined in the file
86 } YamlFile;
87 
88 /**
89  * @brief Represents all YAML files that have been opened and parsed.
90  */
91 typedef struct {
92  YamlFile *files; ///< Array of parsed YAML files
93 } FileType;
94 
95 // Local Variables:
96 FileType my_files; // Struct holding parsed YAML files
97 int nfiles = 0; // Number of files opened and parsed so far
98 
99 /**
100  * @brief Private C function that gets the number of key-value pairs in a block.
101  *
102  * @param file_id Pointer to the file index.
103  * @param block_id Pointer to the block identifier.
104  * @return Number of key-value pairs in this block.
105  */
106 int get_nkeys_binding(const int *file_id, const int *block_id)
107 {
108  int nkeys = 0;
109  int j = *file_id;
110 
111  for (int i = 1; i <= my_files.files[j].nkeys; i++)
112  {
113  if (my_files.files[j].keys[i].parent_key == *block_id &&
114  my_files.files[j].keys[i].parent_name[0] == '\0')
115  nkeys++;
116  }
117 
118  return nkeys;
119 }
120 
121 /**
122  * @brief Private C function that gets the ids of the key-value pairs in a block.
123  *
124  * @param file_id Pointer to the file index.
125  * @param block_id Pointer to the block identifier.
126  * @param key_ids Output array to store the key ids.
127 */
128 void get_key_ids_binding(const int *file_id, const int *block_id, int *key_ids)
129 {
130  int j = *file_id;
131  int key_count = 0;
132 
133  for (int i = 1; i <= my_files.files[j].nkeys; i++)
134  {
135  if (my_files.files[j].keys[i].parent_key == *block_id &&
136  my_files.files[j].keys[i].parent_name[0] == '\0')
137  {
138  key_ids[key_count++] = i;
139  }
140  }
141 }
142 
143 /**
144  * @brief Gets the key name corresponding to a key ID in a YAML file.
145  *
146  * @param file_id Pointer to the index of the YAML file (read-only).
147  * @param key_id Pointer to the index of the key within that file (read-only).
148  * @return Pointer to the key name.
149  *
150  * @note Assumes file_id and key_id are valid and checked beforehand.
151  */
152 char *get_key(const int *file_id, const int *key_id)
153 {
154  return my_files.files[*file_id].keys[*key_id].key;
155 }
156 
157 /**
158  * @brief Gets the key value corresponding to a key ID in a YAML file.
159  *
160  * @param file_id Pointer to the index of the YAML file (read-only).
161  * @param key_id Pointer to the index of the key within that file (read-only).
162  * @return Pointer to the key value.
163  *
164  * @note Assumes file_id and key_id are valid and checked beforehand.
165  */
166 char *get_value(const int *file_id, const int *key_id)
167 {
168  return my_files.files[*file_id].keys[*key_id].value;
169 }
170 
171 /**
172  * @brief Gets the block name corresponding to a block id in a YAML file.
173  *
174  * @param file_id Pointer to the index of the YAML file (read-only).
175  * @param block_id Pointer to the index of the block within that file (read-only).
176  * @return Pointer to the block name.
177  *
178  * @note Assumes file_id and block_id are valid and checked beforehand.
179  */
180 char *get_block(const int *file_id, const int *block_id)
181 {
182  return my_files.files[*file_id].keys[*block_id].parent_name;
183 }
184 
185 /**
186  * @brief Searches for the value of a given key name within a specified block in a YAML file.
187  *
188  * @param file_id Pointer to the index of the YAML file (read-only).
189  * @param block_id Pointer to the ID of the block to search within (read-only).
190  * @param key_name The name of the key to search for (read-only).
191  * @param success Pointer to an int flag that will be set to 1 if found, 0 otherwise.
192  * @return Pointer to the value string if found, or NULL if not found.
193  *
194  * @note Assumes file_id and block_id are valid and checked beforehand.
195  */
196 char *get_value_from_key_wrap(const int *file_id, const int *block_id, const char *key_name, int *success)
197 {
198  int i;
199  int j = *file_id;
200 
201  *success = 0; // Initialize flag to failure
202 
203  for (i = 1; i <= my_files.files[j].nkeys; i++)
204  {
205  if (my_files.files[j].keys[i].parent_key == *block_id)
206  {
207  if (strcmp(my_files.files[j].keys[i].key, key_name) == 0)
208  {
209  *success = 1;
210  return my_files.files[j].keys[i].value;
211  }
212  }
213  }
214 
215  return ""; // Key not found
216 }
217 
218 /**
219  * @brief Counts the number of blocks with a given block name in a YAML file.
220  *
221  * @param file_id Pointer to the index of the YAML file (read-only).
222  * @param block_name Name of the block to count (read-only).
223  * @return Number of blocks matching the given block name.
224  *
225  * @note Assumes valid file_id and non-null block_name.
226  * The function skips the key at index 0 (if indexing starts at 1).
227  */
228 int get_num_blocks_all(const int *file_id, const char *block_name)
229 {
230  int nblocks = 0;
231  int i;
232  int fid = *file_id;
233 
234  /* Loop through keys, assuming keys are 1-based indexed */
235  for (i = 1; i <= my_files.files[fid].nkeys; i++)
236  {
237  if (strcmp(my_files.files[fid].keys[i].parent_name, block_name) == 0)
238  {
239  nblocks++;
240  }
241  }
242 
243  return nblocks;
244 }
245 
246 /**
247  * @brief Counts the number of unique blocks with a given parent block ID.
248  *
249  * @param file_id Pointer to the index of the YAML file (read-only).
250  * @param parent_block_id Pointer to the ID of the parent block (read-only).
251  * @return Number of unique blocks found.
252  */
253 int get_num_unique_blocks_bind(const int *file_id, const int *parent_block_id)
254 {
255  int nblocks = 0;
256  int i, k;
257  int fid = *file_id;
258  char block_names[my_files.files[fid].nkeys][FMS_FILE_LEN]; // Assuming 255 or defined length
259  bool found;
260 
261  for (i = 1; i <= my_files.files[fid].nkeys; i++)
262  {
263  if (my_files.files[fid].keys[i].parent_key == *parent_block_id)
264  {
265  if (strcmp(my_files.files[fid].keys[i].parent_name, "") == 0)
266  continue;
267 
268  found = false;
269  for (k = 0; k < nblocks; k++)
270  {
271  if (strcmp(block_names[k], my_files.files[fid].keys[i].parent_name) == 0)
272  {
273  found = true;
274  break;
275  }
276  }
277 
278  if (found)
279  continue;
280 
281  strcpy(block_names[nblocks], my_files.files[fid].keys[i].parent_name);
282  ++nblocks;
283  }
284  }
285 
286  return nblocks;
287 }
288 
289 /**
290  * @brief Gets the IDs of the unique blocks with a given parent block ID.
291  *
292  * @param file_id Pointer to the index of the YAML file (read-only).
293  * @param block_ids Array to store the unique block IDs (output).
294  * @param parent_block_id Pointer to the ID of the parent block (read-only).
295  */
296 void get_unique_block_ids_bind(const int *file_id, int *block_ids, const int *parent_block_id)
297 {
298  int nblocks = 0;
299  int i, k;
300  int fid = *file_id;
301  char block_names[my_files.files[fid].nkeys][FMS_FILE_LEN];
302  bool found;
303 
304  for (i = 1; i <= my_files.files[fid].nkeys; i++)
305  {
306  if (my_files.files[fid].keys[i].parent_key == *parent_block_id)
307  {
308  if (strcmp(my_files.files[fid].keys[i].parent_name, "") == 0)
309  continue;
310 
311  found = false;
312  for (k = 0; k < nblocks; k++)
313  {
314  if (strcmp(block_names[k], my_files.files[fid].keys[i].parent_name) == 0)
315  {
316  found = true;
317  break;
318  }
319  }
320 
321  if (found)
322  continue;
323 
324  block_ids[nblocks] = my_files.files[fid].keys[i].key_id;
325  strcpy(block_names[nblocks], my_files.files[fid].keys[i].parent_name);
326  ++nblocks;
327  }
328  }
329 }
330 
331 /**
332  * @brief Counts the number of blocks with a given name that belong to a specified parent block.
333  *
334  * @param file_id Pointer to the index of the YAML file (read-only).
335  * @param block_name Name of the blocks to count.
336  * @param parent_block_id Pointer to the ID of the parent block (read-only).
337  * @return Number of blocks with the specified block_name and parent_block_id.
338  */
339 int get_num_blocks_child(const int *file_id, const char *block_name, const int *parent_block_id)
340 {
341  int nblocks = 0; // Counter for matching blocks
342  int i;
343  int fid = *file_id; // Local copy for clarity
344 
345  for (i = 1; i <= my_files.files[fid].nkeys; i++)
346  {
347  if (strcmp(my_files.files[fid].keys[i].parent_name, block_name) == 0 &&
348  my_files.files[fid].keys[i].parent_key == *parent_block_id)
349  {
350  nblocks++;
351  }
352  }
353 
354  return nblocks;
355 }
356 
357 /**
358  * @brief Retrieves the IDs of all blocks with the specified block_name in a YAML file.
359  *
360  * @param file_id Pointer to the index of the YAML file (read-only).
361  * @param block_name Name of the block to search for.
362  * @param block_ids Output array to store the found block IDs.
363  *
364  * @note Assumes block_ids points to enough memory to hold all matching block IDs.
365  */
366 void get_block_ids_all(const int *file_id, const char *block_name, int *block_ids)
367 {
368  int i;
369  int nblocks = 0; // Number of matching blocks found
370  int fid = *file_id; // Local copy of file ID for convenience
371 
372  // Loop over keys; assuming keys index starts at 1
373  for (i = 1; i <= my_files.files[fid].nkeys; i++)
374  {
375  if (strcmp(my_files.files[fid].keys[i].parent_name, block_name) == 0)
376  {
377  block_ids[nblocks] = my_files.files[fid].keys[i].key_id;
378  nblocks++;
379  }
380  }
381 }
382 
383 /**
384  * @brief Finds the IDs of child blocks with a given name and parent block ID in a YAML file.
385  *
386  * @param file_id Pointer to the index of the YAML file (read-only).
387  * @param block_name Name of the block to search for (read-only).
388  * @param block_ids Output array to store matching block IDs.
389  * @param parent_key_id Pointer to the parent block ID (read-only).
390  *
391  * @note Assumes block_ids points to an array large enough to hold all matching IDs.
392  * Assumes valid file_id and non-null pointers.
393  */
394 void get_block_ids_child(const int *file_id, const char *block_name, int *block_ids, const int *parent_key_id)
395 {
396  int nblocks = 0; // Tracks number of matches found
397  int fid = *file_id;
398 
399  // no need to check i == 0
400  for ( int i = 1; i <= my_files.files[fid].nkeys; i++ )
401  {
402  if(strcmp(my_files.files[fid].keys[i].parent_name, block_name) == 0 &&
403  my_files.files[fid].keys[i].parent_key == *parent_key_id)
404  {
405  block_ids[nblocks++] = my_files.files[fid].keys[i].key_id;
406  }
407  }
408 }
409 
410 /**
411  * @brief Checks whether a given block ID is valid within a YAML file.
412  *
413  * @param file_id Pointer to the index of the YAML file (read-only).
414  * @param block_id Pointer to the block ID to validate (read-only).
415  * @return true if the block ID is valid, false otherwise.
416  *
417  * @note A block ID is invalid if:
418  * - It is less than zero or greater than the number of keys in the file.
419  * - Its associated parent name is empty (except for block ID 0).
420  */
421 bool is_valid_block_id(const int *file_id, const int *block_id)
422 {
423  int fid = *file_id;
424  int bid = *block_id;
425 
426  if (bid <= -1 || bid > my_files.files[fid].nkeys) {
427  return false;
428  }
429 
430  if (bid != 0 && strcmp(my_files.files[fid].keys[bid].parent_name, "") == 0) {
431  return false;
432  }
433 
434  return true;
435 }
436 
437 /**
438  * @brief Checks whether a given key ID is valid within a YAML file.
439  *
440  * @param file_id Pointer to the index of the YAML file (read-only).
441  * @param key_id Pointer to the key ID to validate (read-only).
442  * @return true if the key ID is valid, false otherwise.
443  *
444  * @note A key ID is valid if it is between 0 and the number of keys in the file (inclusive).
445  */
446 bool is_valid_key_id(const int *file_id, const int *key_id)
447 {
448  int fid = *file_id;
449  int kid = *key_id;
450 
451  return (kid > -1 && kid <= my_files.files[fid].nkeys);
452 }
453 
454 /**
455  * @brief Checks whether a given file ID is valid.
456  *
457  * @param file_id Pointer to the file ID to validate (read-only).
458  * @return true if the file ID is valid, false otherwise.
459  *
460  * @note A file ID is valid if it is between 0 (inclusive) and nfiles (exclusive).
461  */
462 bool is_valid_file_id(const int *file_id)
463 {
464  int fid = *file_id;
465 
466  return (fid > -1 && fid < nfiles);
467 }
468 
469 /**
470  * @brief Increments the number of levels, enforcing a maximum limit.
471  *
472  * Increments the value pointed to by `nlevels`. If the new value exceeds
473  * the maximum allowed (`MAX_LEVELS`), the function returns an error code.
474  *
475  * @param nlevels Pointer to the current number of levels to be incremented.
476  *
477  * @return SUCCESSFUL (typically 0) if increment is valid;
478  * MAX_LEVELS_REACH if the maximum level count is exceeded.
479  */
480 int increment_nlevels(int *nlevels) {
481  (*nlevels) ++;
482  if (*nlevels > MAX_LEVELS){
483  return MAX_LEVELS_REACH;
484  }
485  return SUCCESSFUL;
486 }
487 
488 /**
489  * @brief Initializes an AnchorsType instance.
490  *
491  * @param anchor Pointer to the AnchorsType to initialize.
492  * @param name Name of the anchor (null-terminated string).
493  */
494 void init_anchor(AnchorsType *anchor, const char *name, const char *parent_name)
495 {
496  if (anchor == NULL || name == NULL) return;
497 
498  anchor->nkeys = 0;
499  anchor->keys = (KeyValuePairs*)calloc(1, sizeof(KeyValuePairs));
500  strcpy(anchor->anchor_name, name);
501  anchor->nlevels = 0;
502  anchor->pid[0] = 0;
503  strcpy(anchor->parent_names[0], parent_name);
504 }
505 
506 /**
507  * @brief Populates a KeyValuePairs structure with provided key data.
508  *
509  * @param my_key Pointer to a KeyValuePairs structure to populate.
510  * @param key_id Integer identifier for the key.
511  * @param parent_key Integer identifier for the parent key.
512  * @param key String representing the key name (can be NULL).
513  * @param value String representing the key value (can be NULL).
514  * @param parent_name String representing the parent key's name (can be NULL).
515  */
516 void add_key(KeyValuePairs *my_key, const int key_id, const int parent_key,
517  const char *key, const char *value, const char *parent_name) {
518 
519  my_key->key_id = key_id;
520  my_key->parent_key = parent_key;
521 
522  if (key) {
523  strncpy(my_key->key, key, sizeof(my_key->key) - 1);
524  my_key->key[sizeof(my_key->key) - 1] = '\0';
525  } else {
526  my_key->key[0] = '\0';
527  }
528 
529  if (value) {
530  strncpy(my_key->value, value, sizeof(my_key->value) - 1);
531  my_key->value[sizeof(my_key->value) - 1] = '\0';
532  } else {
533  my_key->value[0] = '\0';
534  }
535 
536  if (parent_name) {
537  strncpy(my_key->parent_name, parent_name, sizeof(my_key->parent_name) - 1);
538  my_key->parent_name[sizeof(my_key->parent_name) - 1] = '\0';
539  } else {
540  my_key->parent_name[0] = '\0';
541  }
542 }
543 
544 /**
545  * @brief Populates a KeyValuePairs structure in anchor with a key/value
546  *
547  * @param anchor Pointer to the AnchorsType to populate
548  * @param key Key of the yaml key/value pair
549  * @param value Value of the yaml key/value pair
550  */
551 void add_anchor_key(AnchorsType *anchor, const char *key, const char *value)
552 {
553  anchor->nkeys++;
554  anchor->keys = realloc(anchor->keys, (anchor->nkeys+1)*sizeof(KeyValuePairs));
555 
556  KeyValuePairs *my_key = &anchor->keys[anchor->nkeys];
557  add_key(my_key, anchor->nkeys, anchor->pid[anchor->nlevels],
558  key, value, "");
559 
560  DEBUG_PRINT("ANCHOR :: Key_number: %i, parent_key: %i, %s:%s \n ", my_key->key_id, my_key->parent_key, my_key->key, my_key->value);
561 }
562 
563 /**
564  * @brief Populates a KeyValuePairs structure in anchor with a new block
565  *
566  * @param anchor Pointer to the AnchorsType to populate
567  * @param key Name of the block
568  * @return 1 if successful otherwise error code
569  */
570 int add_anchor_parent(AnchorsType *anchor, const char *key)
571 {
572  anchor->nkeys++;
573 
574  anchor->keys = realloc(anchor->keys, (anchor->nkeys+1)*sizeof(KeyValuePairs));
575  int err_code = increment_nlevels(&anchor->nlevels);
576  if (err_code =! SUCCESSFUL) return err_code;
577 
578  anchor->pid[anchor->nlevels] = anchor->nkeys;
579 
580  if (strcmp(key, "")) {
581  strcpy(anchor->parent_names[anchor->nlevels],key );
582  }
583  KeyValuePairs *my_key = &anchor->keys[anchor->nkeys];
584  add_key(my_key, anchor->nkeys, anchor->pid[anchor->nlevels -1],
585  "", "", anchor->parent_names[anchor->nlevels]);
586  DEBUG_PRINT("ANCHOR :: Key_number: %i, parent_key: %i, parent_name: %s \n ", my_key->key_id, my_key->parent_key, my_key->parent_name);
587 
588  return SUCCESSFUL;
589 }
590 /**
591  * @brief Retrieves the index of an anchor by its alias name.
592  *
593  * Searches the YamlFile's list of anchors for a matching alias name.
594  * If a match is found, returns the corresponding index (starting from 1).
595  *
596  * @param this Pointer to the YamlFile structure containing anchors.
597  * @param alias_name The alias name to search for.
598  *
599  * @return Index of the matching anchor if found; otherwise, returns INVALID_ALIAS.
600  */
601 int get_anchor_id(YamlFile *this, const char *alias_name)
602 {
603  for (int i = 1; i < this->nanchors + 1; i++) {
604  AnchorsType *my_anchor = &this->Anchors[i];
605  if (strcmp(my_anchor->anchor_name, alias_name) == 0) {
606  return i;
607  }
608  }
609  return INVALID_ALIAS;
610 }
611 
612 /**
613  * @brief Opens and parses a YAML file.
614  *
615  * @param filename Pointer to the name of the YAML file (read-only).
616  * @param file_id Pointer to an integer where the assigned file ID will be stored (output).
617  * @return 1 if the file was read successfully, or < 0 if there was an error.
618  */
619 int open_and_parse_file_wrap(const char *filename, int *file_id)
620 {
621  yaml_parser_t parser;
622  yaml_token_t token;
623 
624  int fid; /* To minimize the typing :) */
625 
626  // Allocate space to store all the yaml file's info
627  if (nfiles == 0 )
628  {
629  my_files.files = (YamlFile*)calloc(1, sizeof(YamlFile));
630  } else
631  {
632  my_files.files = realloc(my_files.files, (nfiles+1)*sizeof(YamlFile));
633  }
634 
635  // Assign the file id
636  fid = nfiles;
637  *file_id =fid;
638 
639  DEBUG_PRINT("Opening file: %s.\n There are %i files opened.\n", filename, nfiles);
640 
641  FILE *file;
642  file = fopen(filename, "r");
643  if (file == NULL) return MISSING_FILE;
644 
645  if(!yaml_parser_initialize(&parser)) return PARSER_INIT_ERROR;
646 
647  YamlFile *my_file = &my_files.files[fid];
648  my_file->keys = (KeyValuePairs*)calloc(1, sizeof(KeyValuePairs));
649 
650  int nlevels = 0;
651  int nkeys = 0;
652  int pid[MAX_LEVELS]; // parent_ids
653  char parent_names[MAX_LEVELS][FMS_FILE_LEN]; // the name of the parent at each level
654  char key_value[FMS_FILE_LEN];
655  bool defining_value;
656  bool defining_anchor;
657 
658  // Initialize some variables
659  defining_value = false;
660  defining_anchor = false;
661  pid[0]=0;
662  strcpy(parent_names[0], "TOP");
663 
664  yaml_parser_set_input_file(&parser, file);
665  do {
666  if (!yaml_parser_scan(&parser, &token)) {
667  return INVALID_YAML;
668  }
669  switch(token.type)
670  {
671  case YAML_KEY_TOKEN:
672  DEBUG_PRINT("YAML_KEY_TOKEN \n");
673  defining_value = false;
674  break;
675 
676  case YAML_VALUE_TOKEN:
677  DEBUG_PRINT("YAML_VALUE_TOKEN \n");
678  defining_value = true;
679  break;
680 
681  case YAML_SCALAR_TOKEN:
682  DEBUG_PRINT("YAML_SCALAR_TOKEN \n");
683  if (!defining_value) {
684  strcpy(key_value, token.data.scalar.value);
685  break;
686  }
687  if (defining_anchor) {
688  AnchorsType *my_anchor = &my_file->Anchors[my_file->nanchors];
689  add_anchor_key(my_anchor, key_value, token.data.scalar.value);
690  } else {
691  nkeys ++;
692  my_file->keys = realloc(my_file->keys, (nkeys+1)*sizeof(KeyValuePairs));
693  KeyValuePairs *my_key = &my_file->keys[nkeys];
694  add_key(my_key, nkeys, pid[nlevels],
695  key_value, token.data.scalar.value, "");
696  DEBUG_PRINT("Key_number: %i, parent_key: %i, ----- %s:%s \n ",
697  my_file->keys[nkeys].key_id, my_file->keys[nkeys].parent_key,
698  my_file->keys[nkeys].key, my_file->keys[nkeys].value);
699  }
700  defining_value = false;
701  strcpy(key_value, "" );
702  break;
703 
704  case YAML_BLOCK_ENTRY_TOKEN:
705  DEBUG_PRINT("YAML_BLOCK_ENTRY_TOKEN \n");
706  if (defining_anchor) {
707  AnchorsType *my_anchor = &my_file->Anchors[my_file->nanchors];
708 
709  int err_code = add_anchor_parent(my_anchor, key_value);
710  if (err_code != SUCCESSFUL) return err_code;
711 
712  } else {
713  int err_code = increment_nlevels(&nlevels);
714  if (err_code == MAX_LEVELS_REACH) return MAX_LEVELS_REACH;
715 
716  nkeys ++;
717  pid[nlevels] = nkeys;
718  if (strcmp(key_value, "")) {
719  strcpy(parent_names[nlevels], key_value);
720  }
721  my_file->keys = realloc(my_file->keys, (nkeys+1)*sizeof(KeyValuePairs));
722  KeyValuePairs *my_key = &my_file->keys[nkeys];
723  add_key(my_key, nkeys, pid[nlevels-1],
724  "", "", parent_names[nlevels]);
725  DEBUG_PRINT("Key_number: %i, parent_key: %i, parent_name: %s \n ", my_file->keys[nkeys].key_id, my_file->keys[nkeys].parent_key, my_file->keys[nkeys].parent_name);
726  }
727  defining_value = false;
728  strcpy(key_value, "" );
729  break;
730  case YAML_BLOCK_END_TOKEN:
731  DEBUG_PRINT("YAML_BLOCK_END_TOKEN \n");
732  if (defining_anchor) {
733  AnchorsType *my_anchor = &my_file->Anchors[my_file->nanchors];
734  my_anchor->nlevels--;
735  if (my_anchor->nlevels == -1) {
736  defining_anchor = false;
737  DEBUG_PRINT("FINISHED WITH ANCHOR :: ----------------------------- \n");
738  }
739  } else {
740  nlevels --;
741  }
742  defining_value = false;
743  strcpy(key_value, "" );
744  break;
745  case YAML_ANCHOR_TOKEN: {
746  DEBUG_PRINT("YAML_ANCHOR_TOKEN \n");
747  my_file->nanchors ++;
748  if (my_file->nanchors == 1) {
749  my_file->Anchors = (AnchorsType*)calloc(my_file->nanchors + 1, sizeof(AnchorsType));
750  } else {
751  my_file->Anchors = realloc(my_file->Anchors, (my_file->nanchors + 1)*sizeof(AnchorsType));
752  }
753  defining_anchor = true;
754  defining_value = false;
755  AnchorsType *my_anchor = &my_file->Anchors[my_file->nanchors];
756  init_anchor(my_anchor, token.data.anchor.value, key_value);
757  break;
758  }
759  case YAML_ALIAS_TOKEN: {
760  DEBUG_PRINT("YAML_ALIAS_TOKEN \n");
761  int top_key = nkeys;
762 
763  int aid = get_anchor_id(my_file, token.data.alias.value);
764  if (aid == INVALID_ALIAS) return INVALID_ALIAS;
765 
766  AnchorsType *my_anchor = &my_file->Anchors[aid];
767  for (int i = 2; i < my_anchor->nkeys + 1; i++) {
768  nkeys ++;
769  my_file->keys = realloc(my_file->keys, (nkeys+1)*sizeof(KeyValuePairs));
770  KeyValuePairs *my_key = &my_file->keys[nkeys];
771  int parent_key_id;
772  char parent_name[FMS_FILE_LEN];
773  if (my_anchor->keys[i].parent_key == 0){
774  strcpy(parent_name, parent_names[nlevels]);
775  parent_key_id = pid[nlevels-1];
776  } else {
777  strcpy(parent_name, my_anchor->keys[i].parent_name);
778  parent_key_id = top_key + my_anchor->keys[i].parent_key - 1;
779  }
780  add_key(my_key, nkeys, parent_key_id,
781  my_anchor->keys[i].key, my_anchor->keys[i].value, parent_name);
782  if (strcmp(my_file->keys[nkeys].key, "")) {
783  DEBUG_PRINT("**:: Key_number: %i, parent_key: %i, ----- %s:%s \n ",
784  my_file->keys[nkeys].key_id, my_file->keys[nkeys].parent_key,
785  my_file->keys[nkeys].key, my_file->keys[nkeys].value);
786  }else {
787  DEBUG_PRINT("**:: Key_number: %i, parent_key: %i, parent_name: %s \n ",
788  my_file->keys[nkeys].key_id, my_file->keys[nkeys].parent_key,
789  my_file->keys[nkeys].parent_name);
790  }
791  }
792  nlevels --;
793 
794  break;
795  }
796  } //end of switch
797  if(token.type != YAML_STREAM_END_TOKEN)
798  yaml_token_delete(&token);
799  } while(token.type != YAML_STREAM_END_TOKEN);
800  yaml_token_delete(&token);
801  yaml_parser_delete(&parser);
802 
803  my_file->nkeys = nkeys;
804  nfiles = nfiles + 1;
805  DEBUG_PRINT("closing file: %s\n", filename);
806  fclose(file);
807 
808  return SUCCESSFUL;
809 }
810 
811 #endif