FMS  2025.04
Flexible Modeling System
yaml_parser.F90
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 !> @defgroup yaml_parser_mod yaml_parser_mod
20 !> @ingroup parser
21 !> @brief Routines to use for parsing yaml files
22 
23 !> @file
24 !> @brief File for @ref yaml_parser_mod
25 
26 !> @addtogroup yaml_parser_mod
27 !> @{
28 module yaml_parser_mod
29 
30 #ifdef use_yaml
31 use fms_mod, only: fms_c2f_string
32 use fms_string_utils_mod, only: string_copy
33 use platform_mod
34 use mpp_mod
35 use iso_c_binding
36 
37 implicit none
38 private
39 
40 public :: open_and_parse_file
41 public :: missing_file_error_code
42 public :: get_num_unique_blocks
43 public :: get_unique_block_ids
44 public :: get_block_name
45 public :: get_num_blocks
46 public :: get_block_ids
47 public :: get_value_from_key
48 public :: get_nkeys
49 public :: get_key_ids
50 public :: get_key_name
51 public :: get_key_value
52 !public :: clean_up
53 !> @}
54 
55 integer, parameter :: missing_file_error_code = 999
56 
57 !> @brief Dermine the value of a key from a keyname
58 !> @ingroup yaml_parser_mod
60  module procedure get_value_from_key_0d
61  module procedure get_value_from_key_1d
62 end interface get_value_from_key
63 
64 !! Error codes from open_and_parse_file_wrap
65 integer, parameter :: MISSING_FILE = -1 !< Error code if the yaml file is missing
66 integer, parameter :: PARSER_INIT_ERROR = -2 !< Error code if unable to create a parser object
67 integer, parameter :: INVALID_YAML = -3 !< Error code if unable to parse a yaml file
68 integer, parameter :: INVALID_ALIAS = -4 !< Error code if an invalid alias was passed in
69 integer, parameter :: MAX_LEVELS_REACH = -5 !< Error code if the MAX_LEVELS is reach
70 integer, parameter :: SUCCESSFUL = 1 !< "Error" code if the parsing was successful
71 
72 !> @brief c functions binding
73 !> @ingroup yaml_parser_mod
74 interface
75 
76 !> @brief Private c function that opens and parses a yaml file (see yaml_parser_binding.c)
77 !! @return Flag indicating if the read was successful
78 function open_and_parse_file_wrap(filename, file_id) bind(c) &
79  result(error_code)
80  use iso_c_binding, only: c_char, c_int, c_bool
81  character(kind=c_char), intent(in) :: filename(*) !< Filename of the yaml file
82  integer(kind=c_int), intent(out) :: file_id !< File id corresponding to the yaml file that was opened
83  integer(kind=c_int) :: error_code !< Flag indicating the error message (1 if sucessful)
84 end function open_and_parse_file_wrap
85 
86 !> @brief Private c function that checks if a file_id is valid (see yaml_parser_binding.c)
87 !! @return Flag indicating if the file_id is valid
88 function is_valid_file_id(file_id) bind(c) &
89  result(is_valid)
90  use iso_c_binding, only: c_char, c_int, c_bool
91  integer(kind=c_int), intent(in) :: file_id !< File id corresponding to the yaml file that was opened
92  logical(kind=c_bool) :: is_valid !< Flag indicating if the file_id is valid
93 end function is_valid_file_id
94 
95 !> @brief Private c function that gets the number of key-value pairs in a block (see yaml_parser_binding.c)
96 !! @return Number of key-value pairs in this block
97 function get_nkeys_binding(file_id, block_id) bind(c) &
98  result(nkeys)
99  use iso_c_binding, only: c_char, c_int, c_bool
100  integer(kind=c_int), intent(in) :: file_id !< File id corresponding to the yaml file that was opened
101  integer(kind=c_int), intent(in) :: block_id !< Id of the parent_block
102  integer(kind=c_int) :: nkeys
103 end function get_nkeys_binding
104 
105 !> @brief Private c function that gets the ids of the key-value pairs in a block (see yaml_parser_binding.c)
106 subroutine get_key_ids_binding(file_id, block_id, key_ids) bind(c)
107  use iso_c_binding, only: c_char, c_int, c_bool
108  integer(kind=c_int), intent(in) :: file_id !< File id corresponding to the yaml file that was opened
109  integer(kind=c_int), intent(in) :: block_id !< Id of the parent_block
110  integer(kind=c_int), intent(inout) :: key_ids(*) !< Ids of the key-value pairs
111 end subroutine get_key_ids_binding
112 
113 !> @brief Private c function that checks if a key_id is valid (see yaml_parser_binding.c)
114 !! @return Flag indicating if the key_id is valid
115 function is_valid_key_id(file_id, key_id) bind(c) &
116  result(is_valid)
117  use iso_c_binding, only: c_char, c_int, c_bool
118  integer(kind=c_int), intent(in) :: file_id !< File id corresponding to the yaml file that was opened
119  integer(kind=c_int), intent(in) :: key_id !< Key id to check if valid
120  logical(kind=c_bool) :: is_valid !< Flag indicating if the file_id is valid
121 end function is_valid_key_id
122 
123 !> @brief Private c function that get the key from a key_id in a yaml file
124 !! @return Name of the key obtained
125 function get_key(file_id, key_id) bind(c) &
126  result(key_name)
127  use iso_c_binding, only: c_ptr, c_int, c_bool
128  integer(kind=c_int), intent(in) :: file_id !< File id corresponding to the yaml file that was opened
129  integer(kind=c_int), intent(in) :: key_id !< Id of the key-value pair of interest
130  type(c_ptr) :: key_name
131 end function get_key
132 
133 !> @brief Private c function that get the value from a key_id in a yaml file
134 !! @return String containing the value obtained
135 function get_value(file_id, key_id) bind(c) &
136  result(key_value)
137  use iso_c_binding, only: c_ptr, c_int, c_bool
138  integer(kind=c_int), intent(in) :: file_id !< File id corresponding to the yaml file that was opened
139  integer(kind=c_int), intent(in) :: key_id !< Id of the key-value pair of interest
140  type(c_ptr) :: key_value
141 end function get_value
142 
143 !> @brief Private c function that get the block name from a block_id in a yaml file
144 !! @return String containing the value obtained
145 function get_block(file_id, block_id) bind(c) &
146  result(block_name)
147  use iso_c_binding, only: c_ptr, c_int, c_bool
148  integer(kind=c_int), intent(in) :: file_id !< File id corresponding to the yaml file that was opened
149  integer(kind=c_int), intent(in) :: block_id !< Block_id to get the block name for
150 
151  type(c_ptr) :: block_name
152 end function get_block
153 
154 !> @brief Private c function that determines the value of a key in yaml_file (see yaml_parser_binding.c)
155 !! @return c pointer with the value obtained
156 function get_value_from_key_wrap(file_id, block_id, key_name, success) bind(c) &
157  result(key_value2)
158 
159  use iso_c_binding, only: c_ptr, c_char, c_int, c_bool
160  integer(kind=c_int), intent(in) :: file_id !< File id of the yaml file to search
161  integer(kind=c_int), intent(in) :: block_id !< ID corresponding to the block you want the key for
162  character(kind=c_char), intent(in) :: key_name(*) !< Name of the key you want the value for
163  integer(kind=c_int), intent(out) :: success !< Flag indicating if the call was successful
164  type(c_ptr) :: key_value2
165 end function get_value_from_key_wrap
166 
167 !> @brief Private c function that determines the number of blocks with block_name in the yaml file
168 !! (see yaml_parser_binding.c)
169 !! @return Number of blocks with block_name
170 function get_num_blocks_all(file_id, block_name) bind(c) &
171  result(nblocks)
172  use iso_c_binding, only: c_char, c_int, c_bool
173  integer(kind=c_int), intent(in) :: file_id !< File id of the yaml file to search
174  character(kind=c_char), intent(in) :: block_name(*) !< The name of the block you are looking for
175 
176  integer(kind=c_int) :: nblocks
177 end function get_num_blocks_all
178 
179 !> @brief Private c function that determines the number of blocks with block_name that belong to
180 !! a parent block with parent_block_id in the yaml file (see yaml_parser_binding.c)
181 !! @return Number of blocks with block_name
182 function get_num_blocks_child(file_id, block_name, parent_block_id) bind(c) &
183  result(nblocks)
184  use iso_c_binding, only: c_char, c_int, c_bool
185  integer(kind=c_int), intent(in) :: file_id !< File id of the yaml file to search
186  character(kind=c_char), intent(in) :: block_name(*) !< The name of the block you are looking for
187  integer(kind=c_int) :: parent_block_id !< Id of the parent block
188 
189  integer(kind=c_int) :: nblocks
190 end function get_num_blocks_child
191 
192 !> @brief Private c function that gets the ids of the blocks with block_name in the yaml file
193 !! (see yaml_parser_binding.c)
194 subroutine get_block_ids_all(file_id, block_name, block_ids) bind(c)
195  use iso_c_binding, only: c_char, c_int, c_bool
196  integer(kind=c_int), intent(in) :: file_id !< File id of the yaml file to search
197  character(kind=c_char), intent(in) :: block_name(*) !< The name of the block you are looking for
198  integer(kind=c_int), intent(inout) :: block_ids(*) !< Id of the parent_block
199 end subroutine get_block_ids_all
200 
201 !> @brief Private c function that gets the ids of the blocks with block_name and that
202 !! belong to a parent block id in the yaml file (see yaml_parser_binding.c)
203 subroutine get_block_ids_child(file_id, block_name, block_ids, parent_block_id) bind(c)
204  use iso_c_binding, only: c_char, c_int, c_bool
205  integer(kind=c_int), intent(in) :: file_id !< File id of the yaml file to search
206  character(kind=c_char), intent(in) :: block_name(*) !< The name of the block you are looking for
207  integer(kind=c_int), intent(inout) :: block_ids(*) !< Id of the parent_block
208  integer(kind=c_int) :: parent_block_id !< Id of the parent block
209 end subroutine get_block_ids_child
210 
211 !> @brief Private c function that checks if a block_id is valid (see yaml_parser_binding.c)
212 !! @return Flag indicating if the block_id is valid
213 function is_valid_block_id(file_id, block_id) bind(c) &
214  result(is_valid)
215  use iso_c_binding, only: c_char, c_int, c_bool
216  integer(kind=c_int), intent(in) :: file_id !< File id corresponding to the yaml file that was opened
217  integer(kind=c_int), intent(in) :: block_id !< Block id to check if valid
218  logical(kind=c_bool) :: is_valid !< Flag indicating if the file_id is valid
219 end function is_valid_block_id
220 
221 !> @brief Private c function that determines the number of unique blocks that belong to
222 !! a parent block with parent_block_id in the yaml file (see yaml_parser_binding.c)
223 !! @return Number of unique blocks
224 function get_num_unique_blocks_bind(file_id, parent_block_id) bind(c) &
225  result(nblocks)
226  use iso_c_binding, only: c_char, c_int, c_bool
227  integer(kind=c_int), intent(in) :: file_id !< File id of the yaml file to search
228  integer(kind=c_int) :: parent_block_id !< Id of the parent block
229 
230  integer(kind=c_int) :: nblocks
231 end function get_num_unique_blocks_bind
232 
233 !> @brief Private c function that gets the ids of the unique blocks in the yaml file
234 !! (see yaml_parser_binding.c)
235 subroutine get_unique_block_ids_bind(file_id, block_ids, parent_block_id) bind(c)
236  use iso_c_binding, only: c_char, c_int, c_bool, c_ptr
237  integer(kind=c_int), intent(in) :: file_id !< File id corresponding to the yaml file that was opened
238  integer(kind=c_int), intent(inout) :: block_ids(*) !< Id of the parent_block
239  integer(kind=c_int) :: parent_block_id !< Id of the parent block
240 end subroutine get_unique_block_ids_bind
241 end interface
242 
243 !> @addtogroup yaml_parser_mod
244 !> @{
245 contains
246 
247 !> @brief Opens and parses a yaml file
248 !! @return A file id corresponding to the file that was opened
249 function open_and_parse_file(filename) &
250  result(file_id)
251 
252  character(len=*), intent(in) :: filename !< Filename of the yaml file
253  integer :: error_code !< Flag indicating any errors in the parsing or 1 if sucessful
254  logical :: yaml_exists !< Flag indicating whether the yaml exists
255 
256  integer :: file_id
257 
258  inquire(file=trim(filename), exist=yaml_exists)
259  if (.not. yaml_exists) then
260  file_id = missing_file_error_code
261  call mpp_error(note, "The yaml file:"//trim(filename)//" does not exist, hopefully this is your intent!")
262  return
263  end if
264  error_code = open_and_parse_file_wrap(trim(filename)//c_null_char, file_id)
265  call check_error_code(error_code, filename)
266 
267 end function open_and_parse_file
268 
269 !> @brief Checks the error code from a open_and_parse_file_wrap function call
270 subroutine check_error_code(error_code, filename)
271  integer, intent(in) :: error_code
272  character(len=*), intent(in) :: filename
273 
274  select case (error_code)
275  case (successful)
276  return
277  case (missing_file)
278  call mpp_error(fatal, "Error opening the yaml file:"//trim(filename))
279  case (parser_init_error)
280  call mpp_error(fatal, "Error initializing the parser for the file:"//trim(filename))
281  case (invalid_yaml)
282  call mpp_error(fatal, "Error parsing the file:"//trim(filename)//". Check that your yaml file is valid")
283  case (invalid_alias)
284  call mpp_error(fatal, "An alias (*alias_name) in your file:"//trim(filename)//" is invalid."//&
285  "Make sure that all aliases correspond to an anchor (&anchor_name)!")
286  case (max_levels_reach)
287  call mpp_error(fatal, "The file:"//trim(filename)//" has reached the maximum number of level!"//&
288  "Try setting -DMAX_LEVELS to a number greater than the current limit and recompile")
289  end select
290 end subroutine check_error_code
291 
292 !> @brief Gets the key from a file id
293 subroutine get_key_name(file_id, key_id, key_name)
294  integer, intent(in) :: key_id !< Id of the key-value pair of interest
295  integer, intent(in) :: file_id !< File id of the yaml file to search
296  character(len=*), intent(out) :: key_name
297 
298  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
299  & "The file id in your get_key_name call is invalid! Check your call.")
300  if (.not. is_valid_key_id(file_id, key_id)) call mpp_error(fatal, &
301  & "The key id in your get_key_name call is invalid! Check your call.")
302 
303  key_name = fms_c2f_string(get_key(file_id, key_id))
304 
305 end subroutine get_key_name
306 
307 !> @brief Gets the value from a file id
308 subroutine get_key_value(file_id, key_id, key_value)
309  integer, intent(in) :: key_id !< Id of the key-value pair of interest
310  integer, intent(in) :: file_id !< File id of the yaml file to search
311  character(len=*), intent(out) :: key_value
312 
313  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
314  & "The file id in your get_key_value call is invalid! Check your call.")
315  if (.not. is_valid_key_id(file_id, key_id)) call mpp_error(fatal, &
316  & "The key id in your get_key_value call is invalid! Check your call.")
317 
318  key_value = fms_c2f_string(get_value(file_id, key_id))
319 
320 end subroutine get_key_value
321 
322 !> @brief Used to dermine the value of a key from a keyname
323 subroutine get_value_from_key_0d(file_id, block_id, key_name, key_value, is_optional)
324  integer, intent(in) :: file_id !< File id of the yaml file to search
325  integer, intent(in) :: block_id !< ID corresponding to the block you want the key for
326  character(len=*), intent(in) :: key_name !< Name of the key you want the value for
327  class(*), intent(inout):: key_value !< Value of the key
328  logical, intent(in), optional :: is_optional !< Flag indicating if it is okay for the key to not exist.
329  !! If the key does not exist key_value will not be set, so it
330  !! is the user's responsibility to initialize it before the call
331 
332  character(len=255) :: buffer !< String buffer with the value
333 
334  type(c_ptr) :: c_buffer !< c pointer with the value
335  integer(kind=c_int) :: success !< Flag indicating if the value was obtained successfully
336  logical :: optional_flag !< Flag indicating that the key was optional
337  integer :: err_unit !< integer with io error
338 
339  optional_flag = .false.
340  if (present(is_optional)) optional_flag = is_optional
341 
342  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
343  & "The file id in your get_value_from_key call is invalid! Check your call.")
344  if (.not. is_valid_block_id(file_id, block_id)) call mpp_error(fatal, &
345  & "The block id in your get_value_from_key call is invalid! Check your call.")
346 
347  c_buffer = get_value_from_key_wrap(file_id, block_id, trim(key_name)//c_null_char, success)
348  if (success == 1) then
349  buffer = fms_c2f_string(c_buffer)
350 
351  select type (key_value)
352  type is (integer(kind=i4_kind))
353  read(buffer,*, iostat=err_unit) key_value
354  if (err_unit .ne. 0) call mpp_error(fatal, "Key:"// &
355  & trim(key_name)//" Error converting '"//trim(buffer)//"' to i4")
356  type is (integer(kind=i8_kind))
357  read(buffer,*, iostat=err_unit) key_value
358  if (err_unit .ne. 0) call mpp_error(fatal, "Key:"// &
359  & trim(key_name)//" Error converting '"//trim(buffer)//"' to i8")
360  type is (real(kind=r4_kind))
361  read(buffer,*, iostat=err_unit) key_value
362  if (err_unit .ne. 0) call mpp_error(fatal, "Key:"// &
363  & trim(key_name)//" Error converting '"//trim(buffer)//"' to r4")
364  type is (real(kind=r8_kind))
365  read(buffer,*, iostat=err_unit) key_value
366  if (err_unit .ne. 0) call mpp_error(fatal, "Key:"// &
367  & trim(key_name)//" Error converting '"//trim(buffer)//"' to r8")
368  type is (character(len=*))
369  call string_copy(key_value, buffer)
370  type is (logical)
371  if (lowercase(trim(buffer)) == "false") then
372  key_value = .false.
373  elseif (lowercase(trim(buffer)) == "true") then
374  key_value = .true.
375  else
376  call mpp_error(fatal, "Key:"//trim(key_name)//" Error converting '"//trim(buffer)//"' to logical")
377  endif
378  class default
379  call mpp_error(fatal, "The type of your buffer in your get_value_from_key call for key "//trim(key_name)//&
380  &" is not supported. Only i4, i8, r4, r8 and strings are supported.")
381  end select
382  else
383  if(.not. optional_flag) call mpp_error(fatal, "Error getting the value for key:"//trim(key_name))
384  endif
385 
386 end subroutine get_value_from_key_0d
387 
388 !> @brief Used' to dermine the 1D value of a key from a keyname
389 subroutine get_value_from_key_1d(file_id, block_id, key_name, key_value, is_optional)
390  integer, intent(in) :: file_id !< File id of the yaml file to search
391  integer, intent(in) :: block_id !< ID corresponding to the block you want the key for
392  character(len=*), intent(in) :: key_name !< Name of the key you want the value for
393  class(*), intent(inout):: key_value(:) !< Value of the key
394  logical, intent(in), optional :: is_optional !< Flag indicating if it is okay for the key' to not exist.
395  !! If the key does not exist key_value will not be set, so it
396  !! is the user's responsibility to initialize it before the call
397 
398  character(len=255) :: buffer !< String buffer with the value
399 
400  type(c_ptr) :: c_buffer !< c pointer with the value
401  integer(kind=c_int) :: success !< Flag indicating if the value was obtained successfully
402  logical :: optional_flag !< Flag indicating that the key was optional
403  integer :: err_unit !< integer with io error
404 
405  optional_flag=.false.
406  if (present(is_optional)) optional_flag = is_optional
407 
408  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
409  & "The file id in your get_value_from_key call is invalid! Check your call.")
410  if (.not. is_valid_block_id(file_id, block_id)) call mpp_error(fatal, &
411  & "The block id in your get_value_from_key call is invalid! Check your call.")
412 
413  c_buffer = get_value_from_key_wrap(file_id, block_id, trim(key_name)//c_null_char, success)
414  if (success == 1) then
415  buffer = fms_c2f_string(c_buffer)
416 
417  select type (key_value)
418  type is (integer(kind=i4_kind))
419  read(buffer,*, iostat=err_unit) key_value
420  if (err_unit .ne. 0) call mpp_error(fatal, "Key:"// &
421  & trim(key_name)//" Error converting '"//trim(buffer)//"' to i4")
422  type is (integer(kind=i8_kind))
423  read(buffer,*, iostat=err_unit) key_value
424  if (err_unit .ne. 0) call mpp_error(fatal, "Key:"// &
425  & trim(key_name)//" Error converting '"//trim(buffer)//"' to i8")
426  type is (real(kind=r4_kind))
427  read(buffer,*, iostat=err_unit) key_value
428  if (err_unit .ne. 0) call mpp_error(fatal, "Key:"// &
429  & trim(key_name)//" Error converting '"//trim(buffer)//"' to r4")
430  type is (real(kind=r8_kind))
431  read(buffer,*, iostat=err_unit) key_value
432  if (err_unit .ne. 0) call mpp_error(fatal, "Key:"// &
433  & trim(key_name)//" Error converting '"//trim(buffer)//"' to r8")
434  type is (character(len=*))
435  call mpp_error(fatal, "get_value_from_key 1d string variables are not supported. Contact developers")
436  class default
437  call mpp_error(fatal, "The type of your buffer in your get_value_from_key call for key "//trim(key_name)//&
438  &" is not supported. Only i4, i8, r4, r8 and strings are supported.")
439  end select
440  else
441  if(.not. optional_flag) call mpp_error(fatal, "Error getting the value for key:"//trim(key_name))
442  endif
443 end subroutine get_value_from_key_1d
444 
445 !> @brief Determines the number of blocks with block_name in the yaml file
446 !! If parent_block_id is present, it only counts those that belong to that block
447 !! @return Number of blocks with block_name
448 function get_num_blocks(file_id, block_name, parent_block_id) &
449  result(nblocks)
450 
451  integer, intent(in) :: file_id !< File id of the yaml file to search
452  character(len=*), intent(in) :: block_name !< The name of the block you are looking for
453  integer, intent(in), optional :: parent_block_id !< Id of the parent block
454  integer :: nblocks
455 
456  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
457  & "The file id in your get_num_blocks call is invalid! Check your call.")
458 
459  if (.not. present(parent_block_id)) then
460  nblocks=get_num_blocks_all(file_id, trim(block_name)//c_null_char)
461  else
462  if (.not. is_valid_block_id(file_id, parent_block_id)) call mpp_error(fatal, &
463  & "The parent_block id in your get_num_blocks call is invalid! Check your call.")
464  nblocks=get_num_blocks_child(file_id, trim(block_name)//c_null_char, parent_block_id)
465  endif
466 end function get_num_blocks
467 
468 !> @brief Gets the ids of the blocks with block_name in the yaml file
469 !! If parent_block_id is present, it only gets those that belong to that block
470 subroutine get_block_ids(file_id, block_name, block_ids, parent_block_id)
471 
472  integer, intent(in) :: file_id !< File id of the yaml file to search
473  character(len=*), intent(in) :: block_name !< The name of the block you are looking for
474  integer, intent(inout) :: block_ids(:) !< Id of blocks with block_name
475  integer, intent(in), optional :: parent_block_id !< Id of the parent_block
476  integer :: nblocks_id
477  integer :: nblocks
478 
479  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
480  & "The file id in your get_block_ids call is invalid! Check your call.")
481 
482  nblocks_id = size(block_ids)
483  nblocks = get_num_blocks(file_id, block_name, parent_block_id)
484  if (nblocks .ne. nblocks_id) call mpp_error(fatal, "The size of your block_ids array is not correct")
485 
486  if (.not. present(parent_block_id)) then
487  call get_block_ids_all(file_id, trim(block_name)//c_null_char, block_ids)
488  else
489  if (.not. is_valid_block_id(file_id, parent_block_id)) call mpp_error(fatal, &
490  & "The parent_block id in your get_block_ids call is invalid! Check your call.")
491  call get_block_ids_child(file_id, trim(block_name)//c_null_char, block_ids, parent_block_id)
492  endif
493 end subroutine get_block_ids
494 
495 !> @brief Gets the number of key-value pairs in a block
496 !! @return Number of key-value pairs in this block
497 function get_nkeys(file_id, block_id) &
498  result(nkeys)
499  integer, intent(in) :: file_id !< File id corresponding to the yaml file that was opened
500  integer, intent(in) :: block_id !< Id of the parent_block
501  integer :: nkeys
502 
503  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
504  & "The file id in your get_nkeys call is invalid! Check your call.")
505  if (.not. is_valid_block_id(file_id, block_id)) call mpp_error(fatal, &
506  & "The block id in your get_nkeys call is invalid! Check your call.")
507 
508  nkeys = get_nkeys_binding(file_id, block_id)
509 end function get_nkeys
510 
511 !> @brief Gets the ids of the key-value pairs in a block
512 subroutine get_key_ids (file_id, block_id, key_ids)
513  integer, intent(in) :: file_id !< File id corresponding to the yaml file that was opened
514  integer, intent(in) :: block_id !< Id of the parent_block
515  integer, intent(inout) :: key_ids(:) !< Ids of the key-value pairs
516 
517  integer :: nkey_ids !< Size of key_ids
518  integer :: nkeys !< Actual number of keys
519 
520  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
521  & "The file id in your get_key_ids call is invalid! Check your call.")
522  if (.not. is_valid_block_id(file_id, block_id)) call mpp_error(fatal, &
523  & "The block id in your get_key_ids call is invalid! Check your call.")
524 
525  nkey_ids = size(key_ids)
526  nkeys = get_nkeys(file_id, block_id)
527 
528  if (nkeys .ne. nkey_ids) call mpp_error(fatal, "The size of your key_ids array is not correct.")
529 
530  call get_key_ids_binding (file_id, block_id, key_ids)
531 end subroutine get_key_ids
532 
533 !> @brief Gets the number of unique blocks
534 !! @return The number of unique blocks
535 function get_num_unique_blocks(file_id, parent_block_id) &
536  result(nblocks)
537  integer, intent(in) :: file_id !< File id corresponding to the yaml file that was opened
538  integer, intent(in), optional :: parent_block_id !< Id of the parent_block
539  integer :: nblocks
540 
541  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
542  & "The file id in your get_num_unique_blocks call is invalid! Check your call.")
543 
544  if (.not. present(parent_block_id)) then
545  nblocks = get_num_unique_blocks_bind(file_id, 0)
546  else
547  if (.not. is_valid_block_id(file_id, parent_block_id)) call mpp_error(fatal, &
548  & "The parent_block id in your get_block_ids call is invalid! Check your call.")
549  nblocks = get_num_unique_blocks_bind(file_id, parent_block_id)
550  endif
551 end function
552 
553 !> @brief Gets the ids of the unique block ids
554 subroutine get_unique_block_ids(file_id, block_ids, parent_block_id)
555  integer, intent(in) :: file_id !< File id corresponding to the yaml file that was opened
556  integer, intent(inout) :: block_ids(:) !< Ids of each unique block
557  integer, intent(in), optional :: parent_block_id !< Id of the parent_block
558 
559  if (.not. is_valid_file_id(file_id)) call mpp_error(fatal, &
560  & "The file id in your get_num_unique_blocks_ids call is invalid! Check your call.")
561 
562  if (.not. present(parent_block_id)) then
563  call get_unique_block_ids_bind(file_id, block_ids, 0)
564  else
565  if (.not. is_valid_block_id(file_id, parent_block_id)) call mpp_error(fatal, &
566  & "The parent_block id in your get_block_ids call is invalid! Check your call.")
567  call get_unique_block_ids_bind(file_id, block_ids, parent_block_id)
568  endif
569 end subroutine get_unique_block_ids
570 
571 !> @brief Gets the block name form the block id
572 subroutine get_block_name(file_id, block_id, block_name)
573  integer, intent(in) :: file_id !< File id corresponding to the yaml file that was opened
574  integer, intent(in) :: block_id !< Id of the block to get the name from
575  character(len=*), intent(out) :: block_name !< Name of the block
576 
577  block_name = fms_c2f_string(get_block(file_id, block_id))
578 end subroutine
579 #endif
580 end module yaml_parser_mod
581 !> @}
582 ! close documentation grouping
Converts a C string to a Fortran string.
subroutine, public string_copy(dest, source, check_for_null)
Safely copy a string from one buffer to another.
Error handler.
Definition: mpp.F90:381
subroutine get_value_from_key_0d(file_id, block_id, key_name, key_value, is_optional)
Used to dermine the value of a key from a keyname.
integer function, public get_nkeys(file_id, block_id)
Gets the number of key-value pairs in a block.
subroutine, public get_key_name(file_id, key_id, key_name)
Gets the key from a file id.
integer function, public open_and_parse_file(filename)
Opens and parses a yaml file.
subroutine check_error_code(error_code, filename)
Checks the error code from a open_and_parse_file_wrap function call.
subroutine, public get_key_ids(file_id, block_id, key_ids)
Gets the ids of the key-value pairs in a block.
subroutine get_value_from_key_1d(file_id, block_id, key_name, key_value, is_optional)
Used' to dermine the 1D value of a key from a keyname.
subroutine, public get_block_ids(file_id, block_name, block_ids, parent_block_id)
Gets the ids of the blocks with block_name in the yaml file If parent_block_id is present,...
integer function, public get_num_unique_blocks(file_id, parent_block_id)
Gets the number of unique blocks.
integer function, public get_num_blocks(file_id, block_name, parent_block_id)
Determines the number of blocks with block_name in the yaml file If parent_block_id is present,...
subroutine, public get_unique_block_ids(file_id, block_ids, parent_block_id)
Gets the ids of the unique block ids.
subroutine, public get_block_name(file_id, block_id, block_name)
Gets the block name form the block id.
subroutine, public get_key_value(file_id, key_id, key_value)
Gets the value from a file id.
Dermine the value of a key from a keyname.
Definition: yaml_parser.F90:59
Private c function that gets the ids of the blocks with block_name in the yaml file (see yaml_parser_...
Private c function that gets the ids of the blocks with block_name and that belong to a parent block ...
Private c function that get the block name from a block_id in a yaml file.
Private c function that gets the ids of the key-value pairs in a block (see yaml_parser_binding....
Private c function that get the key from a key_id in a yaml file.
Private c function that gets the number of key-value pairs in a block (see yaml_parser_binding....
Definition: yaml_parser.F90:97
Private c function that determines the number of blocks with block_name in the yaml file (see yaml_pa...
Private c function that determines the number of blocks with block_name that belong to a parent block...
Private c function that determines the number of unique blocks that belong to a parent block with par...
Private c function that gets the ids of the unique blocks in the yaml file (see yaml_parser_binding....
Private c function that determines the value of a key in yaml_file (see yaml_parser_binding....
Private c function that get the value from a key_id in a yaml file.
Private c function that checks if a block_id is valid (see yaml_parser_binding.c)
Private c function that checks if a file_id is valid (see yaml_parser_binding.c)
Definition: yaml_parser.F90:88
Private c function that checks if a key_id is valid (see yaml_parser_binding.c)