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, comment_point
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
65  ! and errors will occur. See has_multiple_values.
67  comment_point=index(raw_line,'#')
68  if (comment_point .eq. 0) comment_point=index(raw_line,'!')
69  if (comment_point .ne. 0) raw_line = raw_line(:comment_point - 1)
70 
72  raw_line=adjustl(raw_line)
73  if (len_trim(raw_line) .gt. 0) then
74  call process_configuration_line(options_database, raw_line, is_user_file, &
75  found_global)
76  end if
77  end if
78  end do
79  close(file_id)
80  end subroutine process_configuration_file
81 
89  recursive subroutine process_configuration_line(options_database, raw_line, is_user_file, &
90  found_global)
91  type(hashmap_type), intent(inout) :: options_database
92  character(*), intent(in) :: raw_line
93  logical, intent(in) :: is_user_file
94  logical, intent(inout) :: found_global
95 
96  integer :: mode, start_split, end_split
97  character(len=10000) :: config_key, config_value
98 
99  call get_mode_and_split_points_from_line(raw_line, mode, start_split, end_split)
100 
101  if (mode .ge. 1 .and. raw_line(1:1) .ne. '#' .and. raw_line(1:1) .ne. '!') then
102  config_key=raw_line(1:start_split)
103  config_value=adjustl(raw_line(end_split:))
105  ! The key already exists with multiple values, treat as an array.
106  ! The second case is important if, for instance, the global_config defaults
107  ! to an array with multiple values, but the option may be acceptably entered
108  ! as a single value. This ensures the full key will be removed.
109  if (has_multiple_values(config_value) .or. &
110  options_has_key(options_database, trim(config_key)//"a_size")) then
111  call process_configuration_array(options_database, config_key, config_value, mode)
112  else
113  if (is_key_array_index_specifier(config_key) .or. mode .eq. 2) then
114  call handle_array_element_set(options_database, config_key, config_value, mode)
115  else
116  call store_configuration(options_database, config_key, config_value)
117  if (is_user_file .and. .not. found_global) &
118  found_global=parse_global_configuration_if_available(options_database)
119  end if
120  end if
121  end if
122  end subroutine process_configuration_line
123 
128  logical function parse_global_configuration_if_available(options_database)
129  type(hashmap_type), intent(inout) :: options_database
130 
131  if (options_has_key(options_database, "global_configuration")) then
133  call process_configuration_file(options_database, &
134  trim(options_get_string(options_database, "global_configuration")), .false., &
136  else
138  end if
140 
144  logical function has_multiple_values(configuration_value)
145  character(*), intent(in) :: configuration_value
146 
147  has_multiple_values=scan(configuration_value, ",") .ne. 0
148  end function has_multiple_values
149 
157  subroutine get_mode_and_split_points_from_line(raw_line, mode, start_split, end_split)
158  character(*), intent(in) :: raw_line
159  integer, intent(out) :: mode, start_split, end_split
160 
161  integer :: split_point
162 
163  split_point=index(raw_line, "+=")
164  if (split_point .eq. 0) split_point=index(raw_line, "=+")
165  if (split_point .ne. 0) then
166  mode=2
167  start_split=split_point-1
168  end_split=split_point+2
169  else
170  split_point=index(raw_line, "=")
171  if (split_point .ne. 0) then
172  mode=1
173  start_split=split_point-1
174  end_split=split_point+1
175  else
176  mode=0
177  end if
178  end if
180 
187  subroutine handle_array_element_set(options_database, config_key, config_value, mode)
188  type(hashmap_type), intent(inout) :: options_database
189  character(*), intent(in) :: config_key, config_value
190  integer, intent(in) :: mode
191 
192  integer :: array_index, key_end_index
193 
194  if (mode .eq. 2) then
195  array_index=options_get_array_size(options_database, config_key)+1
196  key_end_index=len(config_key)
197  else
198  array_index=get_key_array_index(config_key)
199  key_end_index=scan(config_key,"(")-1
200  end if
201 
202  call store_configuration(options_database, config_key(:key_end_index), &
203  trim(adjustl(config_value)), array_index)
204  end subroutine handle_array_element_set
205 
209  integer function get_key_array_index(config_key)
210  character(*), intent(in) :: config_key
211 
212  integer :: open_brace_index, close_brace_index
213 
214  open_brace_index=scan(config_key,"(")
215  close_brace_index=scan(config_key,")")
216 
217  if (close_brace_index - open_brace_index .lt. 2) then
218  call log_master_log(log_error, "Array element format for key "//&
219  trim(config_key)//" but no element provided")
220  end if
221 
222  get_key_array_index=conv_to_integer(config_key(open_brace_index+1:close_brace_index-1))
223  end function get_key_array_index
224 
229  logical function is_key_array_index_specifier(config_key)
230  character(*), intent(in) :: config_key
231 
232  integer :: loc
233 
234  loc=scan(config_key,"(")
235  if (loc .ne. 0) then
236  loc=scan(config_key,")")
237  if (loc .ne. 0) then
239  return
240  end if
241  end if
243  end function is_key_array_index_specifier
244 
250  subroutine process_configuration_array(options_database, config_key, config_value, mode)
251  type(hashmap_type), intent(inout) :: options_database
252  character(*), intent(in) :: config_key, config_value
253  integer, intent(in) :: mode
254 
255  character(len=len(config_value)) :: raw_value
256  character(len=len(config_key)) :: parsed_config_key
257 
258  integer :: comma_posn, index
259 
260  if (mode == 1) then
261  call options_remove_key(options_database, config_key)
262  if (is_key_array_index_specifier(config_key)) then
263  index=get_key_array_index(config_key)
264  parsed_config_key=config_key(:scan(config_key,"(")-1)
265  else
266  parsed_config_key=config_key
267  index=1
268  end if
269  else if (mode==2) then
270  index=options_get_array_size(options_database, config_key)+1
271  end if
272 
273  raw_value=config_value
274  comma_posn=scan(raw_value, ",")
275  do while (comma_posn .gt. 0)
276  call store_configuration(options_database, parsed_config_key, &
277  trim(adjustl(raw_value(1:comma_posn-1))), index)
278  raw_value=raw_value(comma_posn+1:)
279  comma_posn=scan(raw_value, ",")
280  index=index+1
281  end do
282  call store_configuration(options_database, parsed_config_key, &
283  trim(adjustl(raw_value(1:))), index)
284  end subroutine process_configuration_array
285 
292  subroutine store_configuration(options_database, config_key, config_value, array_index)
293  type(hashmap_type), intent(inout) :: options_database
294  character(*), intent(in) :: config_key, config_value
295  integer, intent(in), optional :: array_index
296 
297  integer :: comment_location
298  character(len=len(config_value)) :: parsed_value
299 
300  comment_location=scan(config_value,"#")
301  if (comment_location == 0) comment_location=scan(config_value,"!")
302  if (comment_location .gt. 0) then
303  parsed_value=config_value(:comment_location-1)
304  else
305  parsed_value=config_value
306  end if
307 
308  if (conv_is_logical(trim(parsed_value))) then
309  if (present(array_index)) then
310  call options_add(options_database, trim(config_key), &
311  conv_to_logical(trim(parsed_value)), &
312  array_index=array_index)
313  else
314  call options_add(options_database, trim(config_key), &
315  conv_to_logical(trim(parsed_value)))
316  end if
317  else if (conv_is_integer(parsed_value)) then
318  if (present(array_index)) then
319  call options_add(options_database, trim(config_key), &
320  conv_to_integer(trim(parsed_value)), &
321  array_index=array_index)
322  else
323  call options_add(options_database, trim(config_key), &
324  conv_to_integer(trim(parsed_value)))
325  end if
326  else if (conv_is_real(parsed_value)) then
327  if (present(array_index)) then
328  call options_add(options_database, trim(config_key), &
329  conv_single_real_to_double(conv_to_real(trim(parsed_value))), array_index=array_index)
330  else
331  call options_add(options_database, trim(config_key), conv_single_real_to_double(conv_to_real(trim(parsed_value))))
332  end if
333  else
334  if (present(array_index)) then
335  call options_add(options_database, trim(config_key), &
336  trim(remove_string_quotation(parsed_value)), array_index=array_index)
337  else
338  call options_add(options_database, trim(config_key), &
339  trim(remove_string_quotation(parsed_value)))
340  end if
341  end if
342  end subroutine store_configuration
343 
349  function remove_string_quotation(string_value)
350  character(len=*), intent(in) :: string_value
351  character(len=len(string_value)) :: remove_string_quotation
352 
353  integer :: quotation_index_start, quotation_index_end
354 
355  quotation_index_start=scan(string_value, """")
356  if (quotation_index_start .gt. 0) then
357  quotation_index_end=scan(string_value(quotation_index_start+1:), """")+&
358  quotation_index_start
359  if (quotation_index_end .gt. 0) then
360  remove_string_quotation=string_value(quotation_index_start+1:quotation_index_end-1)
361  else
362  remove_string_quotation=string_value
363  end if
364  else
365  remove_string_quotation=string_value
366  end if
367  end function remove_string_quotation
logging_mod::log_error
integer, parameter, public log_error
Only log ERROR messages.
Definition: logging.F90:11
conversions_mod
Conversion between common inbuilt FORTRAN data types.
Definition: conversions.F90:5
conversions_mod::conv_is_logical
Determines whether a data item can be represented as a logical or not.
Definition: conversions.F90:100
optionsdatabase_mod::options_get_array_size
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.
Definition: optionsdatabase.F90:342
configuration_file_parser_mod::parse_configuration_file
subroutine, public parse_configuration_file(options_database, user_configuration_file)
Parses a specific configuration and adds the contents into the options database.
Definition: configurationfileparser.F90:27
conversions_mod::conv_to_integer
Converts data types to integers.
Definition: conversions.F90:49
collections_mod
Collection data structures.
Definition: collections.F90:7
configuration_file_parser_mod::handle_array_element_set
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...
Definition: configurationfileparser.F90:188
collections_mod::hashmap_type
A hashmap structure, the same as a map but uses hashing for greatly improved performance when storing...
Definition: collections.F90:94
configuration_file_parser_mod::get_mode_and_split_points_from_line
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...
Definition: configurationfileparser.F90:158
conversions_mod::conv_to_logical
Converts data types to logical.
Definition: conversions.F90:71
configuration_file_parser_mod::get_key_array_index
integer function get_key_array_index(config_key)
Given a configuration key of the form k(n), this returns the n.
Definition: configurationfileparser.F90:210
configuration_file_parser_mod::global_file_id
integer, parameter global_file_id
Definition: configurationfileparser.F90:17
optionsdatabase_mod::options_add
Generic add interface for adding different types of data to the databases.
Definition: optionsdatabase.F90:28
optionsdatabase_mod::options_get_string
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.
Definition: optionsdatabase.F90:280
configuration_file_parser_mod
Parses a configuration file and loads the contents into the options database which can then be intero...
Definition: configurationfileparser.F90:3
optionsdatabase_mod::options_has_key
logical function, public options_has_key(options_database, key)
Determines whether a specific key is in the database.
Definition: optionsdatabase.F90:76
configuration_file_parser_mod::remove_string_quotation
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...
Definition: configurationfileparser.F90:350
conversions_mod::conv_is_real
Determines whether a data item can be represented as a real or not.
Definition: conversions.F90:91
configuration_file_parser_mod::store_configuration
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...
Definition: configurationfileparser.F90:293
conversions_mod::conv_is_integer
Determines whether a data item can be represented as an integer or not.
Definition: conversions.F90:81
configuration_file_parser_mod::is_key_array_index_specifier
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)
Definition: configurationfileparser.F90:230
configuration_file_parser_mod::parse_global_configuration_if_available
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...
Definition: configurationfileparser.F90:129
logging_mod
Logging utility.
Definition: logging.F90:2
configuration_file_parser_mod::user_file_id
integer, parameter user_file_id
Definition: configurationfileparser.F90:17
logging_mod::log_master_log
subroutine, public log_master_log(level, message)
Will log just from the master process.
Definition: logging.F90:47
configuration_file_parser_mod::has_multiple_values
logical function has_multiple_values(configuration_value)
Determines if a specific string contains multiple values such as str1, str2, str3.
Definition: configurationfileparser.F90:145
conversions_mod::conv_to_real
Converts data types to real.
Definition: conversions.F90:60
optionsdatabase_mod
Manages the options database. Contains administration functions and deduce runtime options from the c...
Definition: optionsdatabase.F90:7
optionsdatabase_mod::options_remove_key
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.
Definition: optionsdatabase.F90:384
configuration_file_parser_mod::process_configuration_line
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 ...
Definition: configurationfileparser.F90:91
configuration_file_parser_mod::process_configuration_array
subroutine process_configuration_array(options_database, config_key, config_value, mode)
Will process a configuration array of values such as v1,v2,v3,v4.
Definition: configurationfileparser.F90:251
configuration_file_parser_mod::process_configuration_file
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...
Definition: configurationfileparser.F90:42
conversions_mod::conv_single_real_to_double
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...
Definition: conversions.F90:114