MONC
configurationfileparser.F90
Go to the documentation of this file.
1 
4  use collections_mod, only : hashmap_type
10  implicit none
11 
12 #ifndef TEST_MODE
13  private
14 #endif
15 
16  ! Ids used in the opening and reading in of configuration files
17  integer, parameter :: user_file_id=15, global_file_id=16
18 
20 contains
21 
26  subroutine parse_configuration_file(options_database, user_configuration_file)
27  type(hashmap_type), intent(inout) :: options_database
28  character(*), intent(in) :: user_configuration_file
29 
30  call process_configuration_file(options_database, user_configuration_file, .true., &
32  end subroutine parse_configuration_file
33 
40  recursive subroutine process_configuration_file(options_database, filename, is_user_file,&
41  file_id)
42  type(hashmap_type), intent(inout) :: options_database
43  character(*), intent(in) :: filename
44  integer, intent(in) :: file_id
45  logical, intent(in) :: is_user_file
46 
47  integer :: file_status
48  logical :: continue_parsing, found_global
49  character(len=10000) :: raw_line
50 
51  found_global=.false.
52  continue_parsing=.true.
53  open(unit=file_id, file=filename, status='old', access='sequential', form='formatted',&
54  action='read', iostat=file_status)
55  if (file_status .ne. 0) then
56  call log_master_log(log_error, "Configuration file "//trim(filename)//" does not exist")
57  end if
58 
59  do while (continue_parsing)
60  read(file_id, '(A)', iostat=file_status) raw_line
61  if (is_iostat_end(file_status)) then
62  continue_parsing=.false.
63  else
64  raw_line=adjustl(raw_line)
65  if (len_trim(raw_line) .gt. 0) then
66  call process_configuration_line(options_database, raw_line, is_user_file, &
67  found_global)
68  end if
69  end if
70  end do
71  close(file_id)
72  end subroutine process_configuration_file
73 
81  recursive subroutine process_configuration_line(options_database, raw_line, is_user_file, &
82  found_global)
83  type(hashmap_type), intent(inout) :: options_database
84  character(*), intent(in) :: raw_line
85  logical, intent(in) :: is_user_file
86  logical, intent(inout) :: found_global
87 
88  integer :: mode, start_split, end_split
89  character(len=10000) :: config_key, config_value
90 
91  call get_mode_and_split_points_from_line(raw_line, mode, start_split, end_split)
92 
93  if (mode .ge. 1 .and. raw_line(1:1) .ne. '#' .and. raw_line(1:1) .ne. '!') then
94  config_key=raw_line(1:start_split)
95  config_value=adjustl(raw_line(end_split:))
96 
97  if (has_multiple_values(config_value)) then
98  call process_configuration_array(options_database, config_key, config_value, mode)
99  else
100  if (is_key_array_index_specifier(config_key) .or. mode .eq. 2) then
101  call handle_array_element_set(options_database, config_key, config_value, mode)
102  else
103  call store_configuration(options_database, config_key, config_value)
104  if (is_user_file .and. .not. found_global) &
105  found_global=parse_global_configuration_if_available(options_database)
106  end if
107  end if
108  end if
109  end subroutine process_configuration_line
110 
115  logical function parse_global_configuration_if_available(options_database)
116  type(hashmap_type), intent(inout) :: options_database
117 
118  if (options_has_key(options_database, "global_configuration")) then
120  call process_configuration_file(options_database, &
121  trim(options_get_string(options_database, "global_configuration")), .false., &
123  else
125  end if
127 
131  logical function has_multiple_values(configuration_value)
132  character(*), intent(in) :: configuration_value
133 
134  has_multiple_values=scan(configuration_value, ",") .ne. 0
135  end function has_multiple_values
136 
144  subroutine get_mode_and_split_points_from_line(raw_line, mode, start_split, end_split)
145  character(*), intent(in) :: raw_line
146  integer, intent(out) :: mode, start_split, end_split
147 
148  integer :: split_point
149 
150  split_point=index(raw_line, "+=")
151  if (split_point .eq. 0) split_point=index(raw_line, "=+")
152  if (split_point .ne. 0) then
153  mode=2
154  start_split=split_point-1
155  end_split=split_point+2
156  else
157  split_point=index(raw_line, "=")
158  if (split_point .ne. 0) then
159  mode=1
160  start_split=split_point-1
161  end_split=split_point+1
162  else
163  mode=0
164  end if
165  end if
167 
174  subroutine handle_array_element_set(options_database, config_key, config_value, mode)
175  type(hashmap_type), intent(inout) :: options_database
176  character(*), intent(in) :: config_key, config_value
177  integer, intent(in) :: mode
178 
179  integer :: array_index, key_end_index
180 
181  if (mode .eq. 2) then
182  array_index=options_get_array_size(options_database, config_key)+1
183  key_end_index=len(config_key)
184  else
185  array_index=get_key_array_index(config_key)
186  key_end_index=scan(config_key,"(")-1
187  end if
188 
189  call store_configuration(options_database, config_key(:key_end_index), &
190  trim(adjustl(config_value)), array_index)
191  end subroutine handle_array_element_set
192 
196  integer function get_key_array_index(config_key)
197  character(*), intent(in) :: config_key
198 
199  integer :: open_brace_index, close_brace_index
200 
201  open_brace_index=scan(config_key,"(")
202  close_brace_index=scan(config_key,")")
203 
204  if (close_brace_index - open_brace_index .lt. 2) then
205  call log_master_log(log_error, "Array element format for key "//&
206  trim(config_key)//" but no element provided")
207  end if
208 
209  get_key_array_index=conv_to_integer(config_key(open_brace_index+1:close_brace_index-1))
210  end function get_key_array_index
211 
216  logical function is_key_array_index_specifier(config_key)
217  character(*), intent(in) :: config_key
218 
219  integer :: loc
220 
221  loc=scan(config_key,"(")
222  if (loc .ne. 0) then
223  loc=scan(config_key,")")
224  if (loc .ne. 0) then
226  return
227  end if
228  end if
230  end function is_key_array_index_specifier
231 
237  subroutine process_configuration_array(options_database, config_key, config_value, mode)
238  type(hashmap_type), intent(inout) :: options_database
239  character(*), intent(in) :: config_key, config_value
240  integer, intent(in) :: mode
241 
242  character(len=len(config_value)) :: raw_value
243  character(len=len(config_key)) :: parsed_config_key
244 
245  integer :: comma_posn, index
246 
247  if (mode == 1) then
248  call options_remove_key(options_database, config_key)
249  if (is_key_array_index_specifier(config_key)) then
250  index=get_key_array_index(config_key)
251  parsed_config_key=config_key(:scan(config_key,"(")-1)
252  else
253  parsed_config_key=config_key
254  index=1
255  end if
256  else if (mode==2) then
257  index=options_get_array_size(options_database, config_key)+1
258  end if
259 
260  raw_value=config_value
261  comma_posn=scan(raw_value, ",")
262  do while (comma_posn .gt. 0)
263  call store_configuration(options_database, parsed_config_key, &
264  trim(adjustl(raw_value(1:comma_posn-1))), index)
265  raw_value=raw_value(comma_posn+1:)
266  comma_posn=scan(raw_value, ",")
267  index=index+1
268  end do
269  call store_configuration(options_database, parsed_config_key, &
270  trim(adjustl(raw_value(1:))), index)
271  end subroutine process_configuration_array
272 
279  subroutine store_configuration(options_database, config_key, config_value, array_index)
280  type(hashmap_type), intent(inout) :: options_database
281  character(*), intent(in) :: config_key, config_value
282  integer, intent(in), optional :: array_index
283 
284  integer :: comment_location
285  character(len=len(config_value)) :: parsed_value
286 
287  comment_location=scan(config_value,"#")
288  if (comment_location == 0) comment_location=scan(config_value,"!")
289  if (comment_location .gt. 0) then
290  parsed_value=config_value(:comment_location-1)
291  else
292  parsed_value=config_value
293  end if
294 
295  if (conv_is_logical(trim(parsed_value))) then
296  if (present(array_index)) then
297  call options_add(options_database, trim(config_key), &
298  conv_to_logical(trim(parsed_value)), &
299  array_index=array_index)
300  else
301  call options_add(options_database, trim(config_key), &
302  conv_to_logical(trim(parsed_value)))
303  end if
304  else if (conv_is_integer(parsed_value)) then
305  if (present(array_index)) then
306  call options_add(options_database, trim(config_key), &
307  conv_to_integer(trim(parsed_value)), &
308  array_index=array_index)
309  else
310  call options_add(options_database, trim(config_key), &
311  conv_to_integer(trim(parsed_value)))
312  end if
313  else if (conv_is_real(parsed_value)) then
314  if (present(array_index)) then
315  call options_add(options_database, trim(config_key), &
316  conv_single_real_to_double(conv_to_real(trim(parsed_value))), array_index=array_index)
317  else
318  call options_add(options_database, trim(config_key), conv_single_real_to_double(conv_to_real(trim(parsed_value))))
319  end if
320  else
321  if (present(array_index)) then
322  call options_add(options_database, trim(config_key), &
323  trim(remove_string_quotation(parsed_value)), array_index=array_index)
324  else
325  call options_add(options_database, trim(config_key), &
326  trim(remove_string_quotation(parsed_value)))
327  end if
328  end if
329  end subroutine store_configuration
330 
336  function remove_string_quotation(string_value)
337  character(len=*), intent(in) :: string_value
338  character(len=len(string_value)) :: remove_string_quotation
339 
340  integer :: quotation_index_start, quotation_index_end
341 
342  quotation_index_start=scan(string_value, """")
343  if (quotation_index_start .gt. 0) then
344  quotation_index_end=scan(string_value(quotation_index_start+1:), """")+&
345  quotation_index_start
346  if (quotation_index_end .gt. 0) then
347  remove_string_quotation=string_value(quotation_index_start+1:quotation_index_end-1)
348  else
349  remove_string_quotation=string_value
350  end if
351  else
352  remove_string_quotation=string_value
353  end if
354  end function remove_string_quotation
Generic add interface for adding different types of data to the databases.
logical function parse_global_configuration_if_available(options_database)
Parses the global configuration file if it is available and calls on to add all of this to the option...
subroutine process_configuration_array(options_database, config_key, config_value, mode)
Will process a configuration array of values such as v1,v2,v3,v4.
integer function, public options_get_array_size(options_database, key)
Gets the size of the array held in the options database corresponding to a specific key...
logical function is_key_array_index_specifier(config_key)
Determines whether a configuration key represents a specific array element, i.e. is of the form k(n) ...
integer, parameter, public log_error
Only log ERROR messages.
Definition: logging.F90:11
character(len=string_length) function, public options_get_string(options_database, key, index)
Retrieves a string value from the database that matches the provided key.
Logging utility.
Definition: logging.F90:2
subroutine, public log_master_log(level, message)
Will log just from the master process.
Definition: logging.F90:47
A hashmap structure, the same as a map but uses hashing for greatly improved performance when storing...
Definition: collections.F90:94
Conversion between common inbuilt FORTRAN data types.
Definition: conversions.F90:5
subroutine, public options_remove_key(options_database, key)
Removes a specific key from the options database, if it is an array then the entire array is removed...
recursive subroutine process_configuration_line(options_database, raw_line, is_user_file, found_global)
Processes a line from the configuration file, breaks it up into its key and value and depending upon ...
Converts data types to logical.
Definition: conversions.F90:69
character(len=len(string_value)) function remove_string_quotation(string_value)
Removes quotations from a string if these are included, regardless of before it will return the conte...
Determines whether a data item can be represented as a logical or not.
Definition: conversions.F90:98
subroutine get_mode_and_split_points_from_line(raw_line, mode, start_split, end_split)
Processes a line to determine the mode (replace or additive) and where the split point is between the...
Collection data structures.
Definition: collections.F90:7
Determines whether a data item can be represented as an integer or not.
Definition: conversions.F90:79
Converts data types to real.
Definition: conversions.F90:58
subroutine handle_array_element_set(options_database, config_key, config_value, mode)
Handles setting a specific array element, when the key has something like k(n) - n being the index to...
recursive subroutine process_configuration_file(options_database, filename, is_user_file, file_id)
Will actually open a specific file and read it in line by line, parsing this and storing the configur...
logical function has_multiple_values(configuration_value)
Determines if a specific string contains multiple values such as str1, str2, str3.
Determines whether a data item can be represented as a real or not.
Definition: conversions.F90:89
Manages the options database. Contains administration functions and deduce runtime options from the c...
subroutine, public parse_configuration_file(options_database, user_configuration_file)
Parses a specific configuration and adds the contents into the options database.
Parses a configuration file and loads the contents into the options database which can then be intero...
integer function get_key_array_index(config_key)
Given a configuration key of the form k(n), this returns the n.
Converts data types to integers.
Definition: conversions.F90:47
subroutine store_configuration(options_database, config_key, config_value, array_index)
Stores a specific configuration by determining the type of a value and calling on to the options data...
logical function, public options_has_key(options_database, key)
Determines whether a specific key is in the database.
real(kind=double_precision) function, public conv_single_real_to_double(input_real)
Converts from a single to double precision real. This applies some rounding to a certain number of de...