afivo-streamer 1.1
1D/2D/3D streamer simulations with AMR
Loading...
Searching...
No Matches
m_config.f90
Go to the documentation of this file.
1!> Module that allows working with a configuration file
2!>
3!> Author: Jannis Teunissen and others
4!> Repository: https://github.com/jannisteunissen/config_fortran
5module m_config
6
7 implicit none
8 private
9
10 !> The double precision kind-parameter
11 integer, parameter :: dp = kind(0.0d0)
12
13 integer, parameter :: CFG_num_types = 4 !< Number of variable types
14 integer, parameter :: cfg_integer_type = 1 !< Integer type
15 integer, parameter :: cfg_real_type = 2 !< Real number type
16 integer, parameter :: cfg_string_type = 3 !< String type
17 integer, parameter :: cfg_logic_type = 4 !< Boolean/logical type
18 integer, parameter :: cfg_unknown_type = 0 !< Used before a variable is created
19
20 !> Indicates a variable has its default value
21 integer, parameter :: cfg_set_by_default = 1
22 !> Indicates a variable was set by a command line argument
23 integer, parameter :: cfg_set_by_arg = 2
24 !> Indicates a variable was set by reading a file
25 integer, parameter :: cfg_set_by_file = 3
26
27 !> Names of the types
28 character(len=10), parameter :: cfg_type_names(0:cfg_num_types) = &
29 [character(len=10) :: "storage", "integer", "real", "string ", "logical"]
30
31 integer, parameter :: cfg_name_len = 80 !< Maximum length of variable names
32 integer, parameter :: cfg_string_len = 200 !< Fixed length of string type
33 !> Maximum length of line containing multiple arguments/values
34 integer, parameter :: cfg_max_line_len = 1000
35
36 !> Maximum number of entries in a variable (if it's an array)
37 integer, parameter :: cfg_max_array_size = 1000
38
39 character, parameter :: tab_char = char(9)
40
41 !> The separator(s) for array-like variables (space, comma, ', ", and tab)
42 character(len=*), parameter :: cfg_separators = " ,'"""//tab_char
43
44 !> The separator for categories (stored in var_name)
45 character(len=*), parameter :: cfg_category_separator = "%"
46
47 !> The default string for data that is not yet stored
48 character(len=*), parameter :: unstored_data_string = "__UNSTORED_DATA_STRING"
49
50 !> The type of a configuration variable
51 type cfg_var_t
52 private
53 !> Name of the variable
54 character(len=CFG_name_len) :: var_name
55 !> Description of variable
56 character(len=CFG_string_len) :: description
57 !> Type of variable
58 integer :: var_type
59 !> Size of variable, 1 means scalar, > 1 means array
60 integer :: var_size
61 !> Whether the variable size is flexible
62 logical :: dynamic_size
63 !> Whether the variable's value has been requested
64 logical :: used
65 !> How the variable has been set (default, command line, file)
66 integer :: set_by = cfg_set_by_default
67 !> Data that has been read in for this variable
68 character(len=CFG_max_line_len) :: stored_data
69
70 ! These are the arrays used for storage. In the future, a "pointer" based
71 ! approach could be used.
72 real(dp), allocatable :: real_data(:)
73 integer, allocatable :: int_data(:)
74 character(len=CFG_string_len), allocatable :: char_data(:)
75 logical, allocatable :: logic_data(:)
76 end type cfg_var_t
77
78 !> The configuration that contains all the variables
79 type cfg_t
80 logical :: sorted = .false.
81 integer :: num_vars = 0
82 type(cfg_var_t), allocatable :: vars(:)
83 end type cfg_t
84
85 !> Interface to add variables to the configuration
86 interface cfg_add
87 module procedure add_real, add_real_array
88 module procedure add_int, add_int_array
89 module procedure add_string, add_string_array
90 module procedure add_logic, add_logic_array
91 end interface cfg_add
92
93 !> Interface to get variables from the configuration
94 interface cfg_get
95 module procedure get_real, get_real_array
96 module procedure get_int, get_int_array
97 module procedure get_logic, get_logic_array
98 module procedure get_string, get_string_array
99 end interface cfg_get
100
101 !> Interface to get variables from the configuration
102 interface cfg_add_get
103 module procedure add_get_real, add_get_real_array
104 module procedure add_get_int, add_get_int_array
105 module procedure add_get_logic, add_get_logic_array
106 module procedure add_get_string, add_get_string_array
107 end interface cfg_add_get
108
109 ! Public types
110 public :: cfg_t
111 public :: cfg_integer_type
112 public :: cfg_real_type
113 public :: cfg_string_type
114 public :: cfg_logic_type
115 public :: cfg_type_names
116
117 ! Constants
118 public :: cfg_name_len
119 public :: cfg_string_len
120 public :: cfg_max_line_len
121 public :: cfg_max_array_size
122
123 ! Public methods
124 public :: cfg_add
125 public :: cfg_get
126 public :: cfg_add_get
127 public :: cfg_get_size
128 public :: cfg_get_type
129 public :: cfg_check
130 public :: cfg_sort
131 public :: cfg_write
132 public :: cfg_write_markdown
133 public :: cfg_read_file
135 public :: cfg_update_from_line
136 public :: cfg_clear
137
138contains
139
140 !> Read command line arguments. Both files and variables can be specified, for
141 !> example as: ./my_program config.cfg -n_runs=3
142 !>
143 !> config files should have an extension .cfg or .txt
144 !> command line arguments should be preceded by a single dash
145 subroutine cfg_update_from_arguments(cfg, ignore_unknown)
146 type(cfg_t),intent(inout) :: cfg
147 !> Ignore unknown arguments (default: false)
148 logical, intent(in), optional :: ignore_unknown
149 character(len=CFG_max_line_len) :: arg
150 integer :: ix, n, arg_status
151 logical :: valid_syntax, strict
152 character(len=4) :: extension
153
154 strict = .true.; if (present(ignore_unknown)) strict = .not. ignore_unknown
155
156 do ix = 1, command_argument_count()
157 call get_command_argument(ix, arg, status=arg_status)
158
159 if (arg_status > 0) then
160 call handle_error("Error in get_command_argument (status > 0)")
161 else if (arg_status == -1) then
162 call handle_error("Argument too long, increase CFG_max_line_len")
163 end if
164
165 n = len_trim(arg)
166 if (n > 3) extension = arg(n-3:)
167
168 ! Look for arguments starting with a single dash
169 if (arg(1:1) == '-' .and. arg(2:2) /= '-') then
170 ! This sets a variable
171 call parse_line(cfg, cfg_set_by_arg, arg(2:), valid_syntax)
172
173 if (.not. valid_syntax) then
174 call handle_error("Invalid syntax on command line: " // trim(arg))
175 end if
176 else if (arg(1:1) /= '-' .and. &
177 (extension == ".cfg" .or. extension == ".txt")) then
178 ! Read a configuration file
179 call cfg_read_file(cfg, trim(arg))
180 else if (strict) then
181 print *, "This error message can be disabled by setting"
182 print *, "ignore_unknown = .true. for CFG_update_from_arguments"
183 call handle_error("Unknown argument: " // trim(arg))
184 end if
185 end do
186 end subroutine cfg_update_from_arguments
187
188 !> Update the configuration by parsing a line
189 subroutine cfg_update_from_line(cfg, line)
190 type(cfg_t), intent(inout) :: cfg
191 character(len=*), intent(in) :: line
192 logical :: valid_syntax
193
194 ! This sets a variable
195 call parse_line(cfg, cfg_set_by_arg, line, valid_syntax)
196
197 if (.not. valid_syntax) then
198 call handle_error("CFG_set: invalid syntax")
199 end if
200 end subroutine cfg_update_from_line
201
202 !> This routine will be called if an error occurs in one of the subroutines of
203 !> this module.
204 subroutine handle_error(err_string)
205 character(len=*), intent(in) :: err_string
206
207 print *, "The following error occured in m_config:"
208 print *, trim(err_string)
209
210 ! It is usually best to quit after an error, to make sure the error message
211 ! is not overlooked in the program's output
212 error stop
213 end subroutine handle_error
214
215 !> Return the index of the variable with name 'var_name', or -1 if not found.
216 subroutine get_var_index(cfg, var_name, ix)
217 type(cfg_t), intent(in) :: cfg
218 character(len=*), intent(in) :: var_name
219 integer, intent(out) :: ix
220 integer :: i
221
222 if (cfg%sorted) then
223 call binary_search_variable(cfg, var_name, ix)
224 else
225 ! Linear search
226 do i = 1, cfg%num_vars
227 if (cfg%vars(i)%var_name == var_name) exit
228 end do
229
230 ! If not found, set i to -1
231 if (i == cfg%num_vars + 1) i = -1
232 ix = i
233 end if
234
235 end subroutine get_var_index
236
237 !> Update the variables in the configartion with the values found in 'filename'
238 subroutine cfg_read_file(cfg, filename)
239 type(cfg_t), intent(inout) :: cfg
240 character(len=*), intent(in) :: filename
241
242 integer, parameter :: my_unit = 123
243 integer :: io_state
244 integer :: line_number
245 logical :: valid_syntax
246 character(len=CFG_name_len) :: line_fmt
247 character(len=CFG_string_len) :: err_string
248 character(len=CFG_max_line_len) :: line
249 character(len=CFG_name_len) :: category
250
251 open(my_unit, file=trim(filename), status="old", action="read")
252 write(line_fmt, "(A,I0,A)") "(A", cfg_max_line_len, ")"
253
254 category = "" ! Default category is empty
255 line_number = 0
256
257 do
258 read(my_unit, fmt=trim(line_fmt), err=998, end=999) line
259 line_number = line_number + 1
260
261 if (len_trim(line) > cfg_max_line_len - 2) then
262 write(err_string, *) "Possible truncation in line ", line_number, &
263 " from ", trim(filename)
264 call handle_error(err_string)
265 end if
266
267 call parse_line(cfg, cfg_set_by_file, line, valid_syntax, category)
268
269 if (.not. valid_syntax) then
270 write(err_string, *) "Cannot read line ", line_number, &
271 " from ", trim(filename)
272 call handle_error(err_string)
273 end if
274 end do
275
276 ! Error handling
277998 write(err_string, "(A,I0,A,I0)") " IOSTAT = ", io_state, &
278 " while reading from " // trim(filename) // " at line ", &
279 line_number
280 call handle_error("CFG_read_file:" // err_string)
281
282 ! Routine ends here if the end of "filename" is reached
283999 close(my_unit, iostat=io_state)
284
285 end subroutine cfg_read_file
286
287 !> Update the cfg by parsing one line
288 subroutine parse_line(cfg, set_by, line_arg, valid_syntax, category_arg)
289 type(cfg_t), intent(inout) :: cfg
290 integer, intent(in) :: set_by !< Where the line came from
291 character(len=*), intent(in) :: line_arg !< Line to parse
292 logical, intent(out) :: valid_syntax
293 character(len=CFG_name_len), intent(inout), optional :: category_arg !< The category
294 character(len=CFG_name_len) :: var_name, category
295 integer :: ix, equal_sign_ix
296 logical :: append
297 character(len=CFG_max_line_len) :: line
298
299 valid_syntax = .true.
300
301 ! Work on a copy
302 line = line_arg
303 category = ""
304 if (present(category_arg)) category = category_arg
305
306 call trim_comment(line, '#;')
307
308 ! Skip empty lines
309 if (line == "") return
310
311 ! Locate the '=' sign
312 equal_sign_ix = scan(line, '=')
313
314 ! if there is no '='-sign then a category is indicated
315 if (equal_sign_ix == 0) then
316 line = adjustl(line)
317
318 ! The category name should appear like this: [category_name]
319 ix = scan(line, ']')
320 if (line(1:1) /= '[' .or. ix == 0) then
321 valid_syntax = .false.
322 return
323 else
324 if (present(category_arg)) category_arg = line(2:ix-1)
325 return
326 end if
327 end if
328
329 if (line(equal_sign_ix-1:equal_sign_ix) == '+=') then
330 append = .true.
331 var_name = line(1 : equal_sign_ix - 2) ! Set variable name
332 else
333 append = .false.
334 var_name = line(1 : equal_sign_ix - 1) ! Set variable name
335 end if
336
337 ! If there are less than two spaces or a tab, reset to no category
338 if (var_name(1:2) /= " " .and. var_name(1:1) /= tab_char) then
339 category = ""
340 end if
341
342 ! Replace leading tabs by spaces
343 ix = verify(var_name, tab_char) ! Find first non-tab character
344 var_name(1:ix-1) = ""
345
346 ! Remove leading blanks
347 var_name = adjustl(var_name)
348
349 ! Add category if it is defined
350 if (category /= "") then
351 var_name = trim(category) // cfg_category_separator // var_name
352 end if
353
354 line = line(equal_sign_ix + 1:) ! Set line to the values behind the '=' sign
355
356 ! Find variable corresponding to name in file
357 call get_var_index(cfg, var_name, ix)
358
359 if (ix <= 0) then
360 ! Variable still needs to be created, for now store data as a string
361 call prepare_store_var(cfg, trim(var_name), cfg_unknown_type, 1, &
362 "Not yet created", ix, .false.)
363 cfg%vars(ix)%stored_data = line
364 else
365 if (append) then
366 cfg%vars(ix)%stored_data = &
367 trim(cfg%vars(ix)%stored_data) // trim(line)
368 else
369 cfg%vars(ix)%stored_data = line
370 end if
371
372 ! If type is known, read in values
373 if (cfg%vars(ix)%var_type /= cfg_unknown_type) then
374 call read_variable(cfg%vars(ix))
375 end if
376 end if
377
378 ! Store how the variable was set
379 cfg%vars(ix)%set_by = set_by
380
381 end subroutine parse_line
382
383 subroutine read_variable(var)
384 type(cfg_var_t), intent(inout) :: var
385 integer :: n, n_entries
386 integer :: ix_start(cfg_max_array_size)
387 integer :: ix_end(cfg_max_array_size), stat
388
389 ! Get the start and end positions of the line content, and the number of entries
390 call get_fields_string(var%stored_data, cfg_separators, &
391 cfg_max_array_size, n_entries, ix_start, ix_end)
392
393 if (var%var_size /= n_entries) then
394
395 if (.not. var%dynamic_size) then
396 ! Allow strings of length 1 to be automatically concatenated
397 if (var%var_type == cfg_string_type .and. var%var_size == 1) then
398 var%char_data(1) = trim(var%stored_data(ix_start(1):ix_end(n_entries)))
399 return ! Leave routine
400 else
401 call handle_error("read_variable: variable [" // &
402 & trim(var%var_name) // "] has the wrong size")
403 end if
404 else
405 var%var_size = n_entries
406 call resize_storage(var)
407 end if
408 end if
409
410 do n = 1, n_entries
411 stat = 0
412 select case (var%var_type)
413 case (cfg_integer_type)
414 read(var%stored_data(ix_start(n):ix_end(n)), *, iostat=stat) var%int_data(n)
415 case (cfg_real_type)
416 read(var%stored_data(ix_start(n):ix_end(n)), *, iostat=stat) var%real_data(n)
417 case (cfg_string_type)
418 var%char_data(n) = trim(var%stored_data(ix_start(n):ix_end(n)))
419 case (cfg_logic_type)
420 read(var%stored_data(ix_start(n):ix_end(n)), *, iostat=stat) var%logic_data(n)
421 end select
422
423 if(stat /= 0) then
424 write (*, *) "** m_config error **"
425 write (*, *) "reading variable: ", trim(var%var_name)
426 write (*, *) "variable type: ", trim(cfg_type_names(var%var_type))
427 write (*, *) "parsing value: ", var%stored_data(ix_start(n):ix_end(n))
428 write (*, "(A,I0)") " iostat value: ", stat
429 stop
430 endif
431 end do
432 end subroutine read_variable
433
434 subroutine trim_comment(line, comment_chars)
435 character(len=*), intent(inout) :: line
436 character(len=*), intent(in) :: comment_chars
437 character :: current_char, need_char
438 integer :: n
439
440 ! Strip comments, but only outside quoted strings (so that var = '#yolo' is
441 ! valid when # is a comment char)
442 need_char = ""
443
444 do n = 1, len(line)
445 current_char = line(n:n)
446
447 if (need_char == "") then
448 if (current_char == "'") then
449 need_char = "'" ! Open string
450 else if (current_char == '"') then
451 need_char = '"' ! Open string
452 else if (index(comment_chars, current_char) /= 0) then
453 line = line(1:n-1) ! Trim line up to comment character
454 exit
455 end if
456 else if (current_char == need_char) then
457 need_char = "" ! Close string
458 end if
459
460 end do
461
462 end subroutine trim_comment
463
464 subroutine cfg_check(cfg)
465 type(cfg_t), intent(in) :: cfg
466 integer :: n
467 character(len=CFG_string_len) :: err_string
468
469 do n = 1, cfg%num_vars
470 if (cfg%vars(n)%var_type == cfg_unknown_type) then
471 write(err_string, *) "CFG_check: unknown variable ", &
472 trim(cfg%vars(n)%var_name), " specified"
473 call handle_error(err_string)
474 end if
475 end do
476 end subroutine cfg_check
477
478 !> This routine writes the current configuration to a file with descriptions
479 subroutine cfg_write(cfg_in, filename, hide_unused, custom_first)
480 use iso_fortran_env
481 type(cfg_t), intent(in) :: cfg_in
482 character(len=*), intent(in) :: filename
483 !> Hide variables whose value was not requested
484 logical, intent(in), optional :: hide_unused
485 !> Show user-set variables first (default: false)
486 logical, intent(in), optional :: custom_first
487 logical :: hide_not_used, sort_set_by
488 type(cfg_t) :: cfg
489 integer :: i, j, n, io_state, myunit
490 integer :: n_custom_set
491 integer, allocatable :: cfg_order(:)
492 character(len=CFG_name_len) :: name_format, var_name
493 character(len=CFG_name_len) :: category, prev_category
494 character(len=CFG_string_len) :: err_string
495
496 hide_not_used = .false.
497 if (present(hide_unused)) hide_not_used = hide_unused
498
499 sort_set_by = .false.
500 if (present(custom_first)) sort_set_by = custom_first
501
502 ! Always print a sorted configuration
503 cfg = cfg_in
504 if (.not. cfg%sorted) call cfg_sort(cfg)
505
506 write(name_format, fmt="(A,I0,A)") "(A,A", cfg_name_len, ",A)"
507
508 if (filename == "stdout") then
509 myunit = output_unit
510 else
511 open(newunit=myunit, file=filename, action="WRITE")
512 end if
513
514 category = ""
515 prev_category = ""
516
517 allocate(cfg_order(cfg%num_vars))
518 if (sort_set_by) then
519 n = 0
520 do i = 1, cfg%num_vars
521 if (cfg%vars(i)%set_by /= cfg_set_by_default) then
522 n = n + 1
523 cfg_order(n) = i
524 end if
525 end do
526 n_custom_set = n
527
528 do i = 1, cfg%num_vars
529 if (cfg%vars(i)%set_by == cfg_set_by_default) then
530 n = n + 1
531 cfg_order(n) = i
532 end if
533 end do
534 else
535 n_custom_set = -1 ! To prevent undefined warning
536 cfg_order(:) = [(i, i = 1, cfg%num_vars)]
537 end if
538
539 do n = 1, cfg%num_vars
540 i = cfg_order(n)
541
542 if (.not. cfg%vars(i)%used .and. hide_not_used) cycle
543 if (cfg%vars(i)%var_type == cfg_unknown_type) cycle
544
545 if (sort_set_by .and. n == n_custom_set + 1) then
546 write(myunit, err=998, fmt="(A)") '# Variables below have default values'
547 write(myunit, err=998, fmt="(A)") ''
548 end if
549
550 ! Write category when it changes
551 call split_category(cfg%vars(i), category, var_name)
552
553 if (category /= prev_category .and. category /= '') then
554 write(myunit, err=998, fmt="(A)") '[' // trim(category) // ']'
555 prev_category = category
556 end if
557
558 ! Indent if inside category
559 if (category /= "") then
560 write(myunit, err=998, fmt="(A,A,A)") " # ", &
561 trim(cfg%vars(i)%description), ":"
562 write(myunit, advance="NO", err=998, fmt="(A)") &
563 " " // trim(var_name) // " ="
564 else
565 write(myunit, err=998, fmt="(A,A,A)") "# ", &
566 trim(cfg%vars(i)%description), ":"
567 write(myunit, advance="NO", err=998, fmt="(A)") &
568 trim(var_name) // " ="
569 end if
570
571 select case(cfg%vars(i)%var_type)
572 case (cfg_integer_type)
573 do j = 1, cfg%vars(i)%var_size
574 write(myunit, advance="NO", err=998, fmt="(A,I0)") &
575 " ", cfg%vars(i)%int_data(j)
576 end do
577 case (cfg_real_type)
578 do j = 1, cfg%vars(i)%var_size
579 write(myunit, advance="NO", err=998, fmt="(A,ES11.4)") &
580 " ", cfg%vars(i)%real_data(j)
581 end do
582 case (cfg_string_type)
583 do j = 1, cfg%vars(i)%var_size
584 write(myunit, advance="NO", err=998, fmt="(A)") &
585 " '" // trim(cfg%vars(i)%char_data(j)) // "'"
586 end do
587 case (cfg_logic_type)
588 do j = 1, cfg%vars(i)%var_size
589 write(myunit, advance="NO", err=998, fmt="(A,L1)") &
590 " ", cfg%vars(i)%logic_data(j)
591 end do
592 end select
593 write(myunit, err=998, fmt="(A)") ""
594 write(myunit, err=998, fmt="(A)") ""
595 end do
596
597 if (myunit /= output_unit) close(myunit, err=999, iostat=io_state)
598 call cfg_check(cfg_in)
599 return
600
601998 continue
602 write(err_string, *) "CFG_write error: io_state = ", io_state, &
603 " while writing ", trim(var_name), " to ", filename
604 call handle_error(err_string)
605
606999 continue ! If there was an error, the routine will end here
607 write(err_string, *) "CFG_write error: io_state = ", io_state, &
608 " while writing to ", filename
609 call handle_error(err_string)
610
611 end subroutine cfg_write
612
613 !> This routine writes the current configuration to a markdown file
614 subroutine cfg_write_markdown(cfg_in, filename, hide_unused)
615 use iso_fortran_env
616 type(cfg_t), intent(in) :: cfg_in
617 character(len=*), intent(in) :: filename
618 logical, intent(in), optional :: hide_unused
619 logical :: hide_not_used
620 integer :: i, j, io_state, myunit
621 type(cfg_t) :: cfg
622 character(len=CFG_name_len) :: name_format, var_name
623 character(len=CFG_name_len) :: category, prev_category
624 character(len=CFG_string_len) :: err_string
625
626 hide_not_used = .false.
627 if (present(hide_unused)) hide_not_used = hide_unused
628
629 ! Always print a sorted configuration
630 cfg = cfg_in
631 if (.not. cfg%sorted) call cfg_sort(cfg)
632
633 write(name_format, fmt="(A,I0,A)") "(A,A", cfg_name_len, ",A)"
634
635 if (filename == "stdout") then
636 myunit = output_unit
637 else
638 myunit = 333
639 open(myunit, file=filename, action="WRITE")
640 end if
641
642 category = ""
643 prev_category = "X"
644 write(myunit, err=998, fmt="(A)") "# Configuration file (markdown format)"
645 write(myunit, err=998, fmt="(A)") ""
646
647 do i = 1, cfg%num_vars
648
649 if (.not. cfg%vars(i)%used .and. hide_not_used) cycle
650 if (cfg%vars(i)%var_type == cfg_unknown_type) cycle
651
652 ! Write category when it changes
653 call split_category(cfg%vars(i), category, var_name)
654
655 if (category /= prev_category) then
656 if (category == "") category = "No category"
657 write(myunit, err=998, fmt="(A)") '## ' // trim(category)
658 write(myunit, err=998, fmt="(A)") ""
659 prev_category = category
660 end if
661
662 write(myunit, err=998, fmt="(A)") "* " // trim(cfg%vars(i)%description)
663 write(myunit, err=998, fmt="(A)") ""
664 write(myunit, advance="NO", err=998, fmt="(A)") &
665 ' ' // trim(var_name) // " ="
666
667 select case(cfg%vars(i)%var_type)
668 case (cfg_integer_type)
669 do j = 1, cfg%vars(i)%var_size
670 write(myunit, advance="NO", err=998, fmt="(A,I0)") &
671 " ", cfg%vars(i)%int_data(j)
672 end do
673 case (cfg_real_type)
674 do j = 1, cfg%vars(i)%var_size
675 write(myunit, advance="NO", err=998, fmt="(A,E11.4)") &
676 " ", cfg%vars(i)%real_data(j)
677 end do
678 case (cfg_string_type)
679 do j = 1, cfg%vars(i)%var_size
680 write(myunit, advance="NO", err=998, fmt="(A)") &
681 " '" // trim(cfg%vars(i)%char_data(j)) // "'"
682 end do
683 case (cfg_logic_type)
684 do j = 1, cfg%vars(i)%var_size
685 write(myunit, advance="NO", err=998, fmt="(A,L1)") &
686 " ", cfg%vars(i)%logic_data(j)
687 end do
688 end select
689 write(myunit, err=998, fmt="(A)") ""
690 write(myunit, err=998, fmt="(A)") ""
691 end do
692
693 if (myunit /= output_unit) close(myunit, err=999, iostat=io_state)
694 call cfg_check(cfg_in)
695 return
696
697998 continue
698 write(err_string, *) "CFG_write_markdown error: io_state = ", io_state, &
699 " while writing ", trim(var_name), " to ", filename
700 call handle_error(err_string)
701
702999 continue ! If there was an error, the routine will end here
703 write(err_string, *) "CFG_write_markdown error: io_state = ", io_state, &
704 " while writing to ", filename
705 call handle_error(err_string)
706
707 end subroutine cfg_write_markdown
708
709 subroutine split_category(variable, category, var_name)
710 type(cfg_var_t), intent(in) :: variable
711 character(CFG_name_len), intent(out) :: category
712 character(CFG_name_len), intent(out) :: var_name
713 integer :: ix
714
715 ix = index(variable%var_name, cfg_category_separator)
716
717 if (ix == 0) then
718 category = ""
719 var_name = variable%var_name
720 else
721 category = variable%var_name(1:ix-1)
722 var_name = variable%var_name(ix+1:)
723 end if
724
725 end subroutine split_category
726
727 !> Resize the storage size of variable, which can be of type integer, logical,
728 !> real or character
729 subroutine resize_storage(variable)
730 type(cfg_var_t), intent(inout) :: variable
731
732 select case (variable%var_type)
733 case (cfg_integer_type)
734 deallocate( variable%int_data )
735 allocate( variable%int_data(variable%var_size) )
736 case (cfg_logic_type)
737 deallocate( variable%logic_data )
738 allocate( variable%logic_data(variable%var_size) )
739 case (cfg_real_type)
740 deallocate( variable%real_data )
741 allocate( variable%real_data(variable%var_size) )
742 case (cfg_string_type)
743 deallocate( variable%char_data )
744 allocate( variable%char_data(variable%var_size) )
745 end select
746 end subroutine resize_storage
747
748 !> Helper routine to store variables. This is useful because a lot of the same
749 !> code is executed for the different types of variables.
750 subroutine prepare_store_var(cfg, var_name, var_type, var_size, &
751 description, ix, dynamic_size)
752 type(cfg_t), intent(inout) :: cfg
753 character(len=*), intent(in) :: var_name, description
754 integer, intent(in) :: var_type, var_size
755 integer, intent(out) :: ix !< Index of variable
756 logical, intent(in), optional :: dynamic_size
757
758 ! Check if variable already exists
759 call get_var_index(cfg, var_name, ix)
760
761 if (ix == -1) then ! Create a new variable
762 call ensure_free_storage(cfg)
763 cfg%sorted = .false.
764 ix = cfg%num_vars + 1
765 cfg%num_vars = cfg%num_vars + 1
766 cfg%vars(ix)%used = .false.
767 cfg%vars(ix)%stored_data = unstored_data_string
768 else
769 ! Only allowed when the variable is not yet created
770 if (cfg%vars(ix)%var_type /= cfg_unknown_type) then
771 call handle_error("prepare_store_var: variable [" // &
772 & trim(var_name) // "] already exists")
773 end if
774 end if
775
776 cfg%vars(ix)%var_name = var_name
777 cfg%vars(ix)%description = description
778 cfg%vars(ix)%var_type = var_type
779 cfg%vars(ix)%var_size = var_size
780
781 if (present(dynamic_size)) then
782 cfg%vars(ix)%dynamic_size = dynamic_size
783 else
784 cfg%vars(ix)%dynamic_size = .false.
785 end if
786
787 select case (var_type)
788 case (cfg_integer_type)
789 allocate( cfg%vars(ix)%int_data(var_size) )
790 case (cfg_real_type)
791 allocate( cfg%vars(ix)%real_data(var_size) )
792 case (cfg_string_type)
793 allocate( cfg%vars(ix)%char_data(var_size) )
794 case (cfg_logic_type)
795 allocate( cfg%vars(ix)%logic_data(var_size) )
796 end select
797
798 end subroutine prepare_store_var
799
800 !> Helper routine to get variables. This is useful because a lot of the same
801 !> code is executed for the different types of variables.
802 subroutine prepare_get_var(cfg, var_name, var_type, var_size, ix)
803 type(cfg_t), intent(inout) :: cfg
804 character(len=*), intent(in) :: var_name
805 integer, intent(in) :: var_type, var_size
806 integer, intent(out) :: ix
807 character(len=CFG_string_len) :: err_string
808
809 call get_var_index(cfg, var_name, ix)
810
811 if (ix == -1) then
812 call handle_error("CFG_get: variable ["//var_name//"] not found")
813 else if (cfg%vars(ix)%var_type /= var_type) then
814 write(err_string, fmt="(A)") "CFG_get: variable [" &
815 // var_name // "] has different type (" // &
816 trim(cfg_type_names(cfg%vars(ix)%var_type)) // &
817 ") than requested (" // trim(cfg_type_names(var_type)) // ")"
818 call handle_error(err_string)
819 else if (cfg%vars(ix)%var_size /= var_size) then
820 write(err_string, fmt="(A,I0,A,I0,A)") "CFG_get: variable [" &
821 // var_name // "] has different size (", cfg%vars(ix)%var_size, &
822 ") than requested (", var_size, ")"
823 call handle_error(err_string)
824 else ! All good, variable will be used
825 cfg%vars(ix)%used = .true.
826 end if
827 end subroutine prepare_get_var
828
829 !> Add a configuration variable with a real value
830 subroutine add_real(cfg, var_name, real_data, comment)
831 type(cfg_t), intent(inout) :: cfg
832 character(len=*), intent(in) :: var_name, comment
833 real(dp), intent(in) :: real_data
834 integer :: ix
835
836 call prepare_store_var(cfg, var_name, cfg_real_type, 1, comment, ix)
837
838 if (cfg%vars(ix)%stored_data /= unstored_data_string) then
839 call read_variable(cfg%vars(ix))
840 else
841 cfg%vars(ix)%real_data(1) = real_data
842 end if
843 end subroutine add_real
844
845 !> Add a configuration variable with an array of type
846 ! real
847 subroutine add_real_array(cfg, var_name, real_data, comment, dynamic_size)
848 type(cfg_t), intent(inout) :: cfg
849 character(len=*), intent(in) :: var_name, comment
850 real(dp), intent(in) :: real_data(:)
851 logical, intent(in), optional :: dynamic_size
852 integer :: ix
853
854 call prepare_store_var(cfg, var_name, cfg_real_type, &
855 size(real_data), comment, ix, dynamic_size)
856
857 if (cfg%vars(ix)%stored_data /= unstored_data_string) then
858 call read_variable(cfg%vars(ix))
859 else
860 cfg%vars(ix)%real_data = real_data
861 end if
862 end subroutine add_real_array
863
864 !> Add a configuration variable with an integer value
865 subroutine add_int(cfg, var_name, int_data, comment)
866 type(cfg_t), intent(inout) :: cfg
867 character(len=*), intent(in) :: var_name, comment
868 integer, intent(in) :: int_data
869 integer :: ix
870
871 call prepare_store_var(cfg, var_name, cfg_integer_type, 1, comment, ix)
872
873 if (cfg%vars(ix)%stored_data /= unstored_data_string) then
874 call read_variable(cfg%vars(ix))
875 else
876 cfg%vars(ix)%int_data(1) = int_data
877 end if
878 end subroutine add_int
879
880 !> Add a configuration variable with an array of type integer
881 subroutine add_int_array(cfg, var_name, int_data, comment, dynamic_size)
882 type(cfg_t), intent(inout) :: cfg
883 character(len=*), intent(in) :: var_name, comment
884 integer, intent(in) :: int_data(:)
885 logical, intent(in), optional :: dynamic_size
886 integer :: ix
887
888 call prepare_store_var(cfg, var_name, cfg_integer_type, &
889 size(int_data), comment, ix, dynamic_size)
890
891 if (cfg%vars(ix)%stored_data /= unstored_data_string) then
892 call read_variable(cfg%vars(ix))
893 else
894 cfg%vars(ix)%int_data = int_data
895 end if
896 end subroutine add_int_array
897
898 !> Add a configuration variable with an character value
899 subroutine add_string(cfg, var_name, char_data, comment)
900 type(cfg_t), intent(inout) :: cfg
901 character(len=*), intent(in) :: var_name, comment, char_data
902 integer :: ix
903
904 call prepare_store_var(cfg, var_name, cfg_string_type, 1, comment, ix)
905 if (cfg%vars(ix)%stored_data /= unstored_data_string) then
906 call read_variable(cfg%vars(ix))
907 else
908 cfg%vars(ix)%char_data(1) = char_data
909 end if
910 end subroutine add_string
911
912 !> Add a configuration variable with an array of type character
913 subroutine add_string_array(cfg, var_name, char_data, &
914 comment, dynamic_size)
915 type(cfg_t), intent(inout) :: cfg
916 character(len=*), intent(in) :: var_name, comment, char_data(:)
917 logical, intent(in), optional :: dynamic_size
918 integer :: ix
919
920 call prepare_store_var(cfg, var_name, cfg_string_type, &
921 size(char_data), comment, ix, dynamic_size)
922
923 if (cfg%vars(ix)%stored_data /= unstored_data_string) then
924 call read_variable(cfg%vars(ix))
925 else
926 cfg%vars(ix)%char_data = char_data
927 end if
928 end subroutine add_string_array
929
930 !> Add a configuration variable with an logical value
931 subroutine add_logic(cfg, var_name, logic_data, comment)
932 type(cfg_t), intent(inout) :: cfg
933 character(len=*), intent(in) :: var_name, comment
934 logical, intent(in) :: logic_data
935 integer :: ix
936
937 call prepare_store_var(cfg, var_name, cfg_logic_type, 1, comment, ix)
938
939 if (cfg%vars(ix)%stored_data /= unstored_data_string) then
940 call read_variable(cfg%vars(ix))
941 else
942 cfg%vars(ix)%logic_data(1) = logic_data
943 end if
944 end subroutine add_logic
945
946 !> Add a configuration variable with an array of type logical
947 subroutine add_logic_array(cfg, var_name, logic_data, &
948 comment, dynamic_size)
949 type(cfg_t), intent(inout) :: cfg
950 character(len=*), intent(in) :: var_name, comment
951 logical, intent(in) :: logic_data(:)
952 logical, intent(in), optional :: dynamic_size
953 integer :: ix
954
955 call prepare_store_var(cfg, var_name, cfg_logic_type, &
956 size(logic_data), comment, ix, dynamic_size)
957
958 if (cfg%vars(ix)%stored_data /= unstored_data_string) then
959 call read_variable(cfg%vars(ix))
960 else
961 cfg%vars(ix)%logic_data = logic_data
962 end if
963 end subroutine add_logic_array
964
965 !> Get a real array of a given name
966 subroutine get_real_array(cfg, var_name, real_data)
967 type(cfg_t), intent(inout) :: cfg
968 character(len=*), intent(in) :: var_name
969 real(dp), intent(inout) :: real_data(:)
970 integer :: ix
971
972 call prepare_get_var(cfg, var_name, cfg_real_type, &
973 size(real_data), ix)
974 real_data = cfg%vars(ix)%real_data
975 end subroutine get_real_array
976
977 !> Get a integer array of a given name
978 subroutine get_int_array(cfg, var_name, int_data)
979 type(cfg_t), intent(inout) :: cfg
980 character(len=*), intent(in) :: var_name
981 integer, intent(inout) :: int_data(:)
982 integer :: ix
983
984 call prepare_get_var(cfg, var_name, cfg_integer_type, &
985 size(int_data), ix)
986 int_data = cfg%vars(ix)%int_data
987 end subroutine get_int_array
988
989 !> Get a character array of a given name
990 subroutine get_string_array(cfg, var_name, char_data)
991 type(cfg_t), intent(inout) :: cfg
992 character(len=*), intent(in) :: var_name
993 character(len=*), intent(inout) :: char_data(:)
994 integer :: ix
995
996 call prepare_get_var(cfg, var_name, cfg_string_type, &
997 size(char_data), ix)
998 char_data = cfg%vars(ix)%char_data
999 end subroutine get_string_array
1000
1001 !> Get a logical array of a given name
1002 subroutine get_logic_array(cfg, var_name, logic_data)
1003 type(cfg_t), intent(inout) :: cfg
1004 character(len=*), intent(in) :: var_name
1005 logical, intent(inout) :: logic_data(:)
1006 integer :: ix
1007
1008 call prepare_get_var(cfg, var_name, cfg_logic_type, &
1009 size(logic_data), ix)
1010 logic_data = cfg%vars(ix)%logic_data
1011 end subroutine get_logic_array
1012
1013 !> Get a real value of a given name
1014 subroutine get_real(cfg, var_name, res)
1015 type(cfg_t), intent(inout) :: cfg
1016 character(len=*), intent(in) :: var_name
1017 real(dp), intent(out) :: res
1018 integer :: ix
1019
1020 call prepare_get_var(cfg, var_name, cfg_real_type, 1, ix)
1021 res = cfg%vars(ix)%real_data(1)
1022 end subroutine get_real
1023
1024 !> Get a integer value of a given name
1025 subroutine get_int(cfg, var_name, res)
1026 type(cfg_t), intent(inout) :: cfg
1027 character(len=*), intent(in) :: var_name
1028 integer, intent(inout) :: res
1029 integer :: ix
1030
1031 call prepare_get_var(cfg, var_name, cfg_integer_type, 1, ix)
1032 res = cfg%vars(ix)%int_data(1)
1033 end subroutine get_int
1034
1035 !> Get a logical value of a given name
1036 subroutine get_logic(cfg, var_name, res)
1037 type(cfg_t), intent(inout) :: cfg
1038 character(len=*), intent(in) :: var_name
1039 logical, intent(out) :: res
1040 integer :: ix
1041
1042 call prepare_get_var(cfg, var_name, cfg_logic_type, 1, ix)
1043 res = cfg%vars(ix)%logic_data(1)
1044 end subroutine get_logic
1045
1046 !> Get a character value of a given name
1047 subroutine get_string(cfg, var_name, res)
1048 type(cfg_t), intent(inout) :: cfg
1049 character(len=*), intent(in) :: var_name
1050 character(len=*), intent(out) :: res
1051 integer :: ix
1052
1053 call prepare_get_var(cfg, var_name, cfg_string_type, 1, ix)
1054 res = cfg%vars(ix)%char_data(1)
1055 end subroutine get_string
1056
1057 !> Get or add a real array of a given name
1058 subroutine add_get_real_array(cfg, var_name, real_data, &
1059 comment, dynamic_size)
1060 type(cfg_t), intent(inout) :: cfg
1061 character(len=*), intent(in) :: var_name, comment
1062 real(dp), intent(inout) :: real_data(:)
1063 logical, intent(in), optional :: dynamic_size
1064
1065 call add_real_array(cfg, var_name, real_data, comment, dynamic_size)
1066 call get_real_array(cfg, var_name, real_data)
1067 end subroutine add_get_real_array
1068
1069 !> Get or add a integer array of a given name
1070 subroutine add_get_int_array(cfg, var_name, int_data, &
1071 comment, dynamic_size)
1072 type(cfg_t), intent(inout) :: cfg
1073 character(len=*), intent(in) :: var_name, comment
1074 integer, intent(inout) :: int_data(:)
1075 logical, intent(in), optional :: dynamic_size
1076
1077 call add_int_array(cfg, var_name, int_data, comment, dynamic_size)
1078 call get_int_array(cfg, var_name, int_data)
1079 end subroutine add_get_int_array
1080
1081 !> Get or add a character array of a given name
1082 subroutine add_get_string_array(cfg, var_name, char_data, &
1083 comment, dynamic_size)
1084 type(cfg_t), intent(inout) :: cfg
1085 character(len=*), intent(in) :: var_name, comment
1086 character(len=*), intent(inout) :: char_data(:)
1087 logical, intent(in), optional :: dynamic_size
1088
1089 call add_string_array(cfg, var_name, char_data, comment, dynamic_size)
1090 call get_string_array(cfg, var_name, char_data)
1091 end subroutine add_get_string_array
1092
1093 !> Get or add a logical array of a given name
1094 subroutine add_get_logic_array(cfg, var_name, logic_data, &
1095 comment, dynamic_size)
1096 type(cfg_t), intent(inout) :: cfg
1097 character(len=*), intent(in) :: var_name, comment
1098 logical, intent(inout) :: logic_data(:)
1099 logical, intent(in), optional :: dynamic_size
1100
1101 call add_logic_array(cfg, var_name, logic_data, comment, dynamic_size)
1102 call get_logic_array(cfg, var_name, logic_data)
1103 end subroutine add_get_logic_array
1104
1105 !> Get or add a real value of a given name
1106 subroutine add_get_real(cfg, var_name, real_data, comment)
1107 type(cfg_t), intent(inout) :: cfg
1108 character(len=*), intent(in) :: var_name, comment
1109 real(dp), intent(inout) :: real_data
1110
1111 call add_real(cfg, var_name, real_data, comment)
1112 call get_real(cfg, var_name, real_data)
1113 end subroutine add_get_real
1114
1115 !> Get or add a integer value of a given name
1116 subroutine add_get_int(cfg, var_name, int_data, comment)
1117 type(cfg_t), intent(inout) :: cfg
1118 character(len=*), intent(in) :: var_name, comment
1119 integer, intent(inout) :: int_data
1120
1121 call add_int(cfg, var_name, int_data, comment)
1122 call get_int(cfg, var_name, int_data)
1123 end subroutine add_get_int
1124
1125 !> Get or add a logical value of a given name
1126 subroutine add_get_logic(cfg, var_name, logical_data, comment)
1127 type(cfg_t), intent(inout) :: cfg
1128 character(len=*), intent(in) :: var_name, comment
1129 logical, intent(inout) :: logical_data
1130
1131 call add_logic(cfg, var_name, logical_data, comment)
1132 call get_logic(cfg, var_name, logical_data)
1133 end subroutine add_get_logic
1134
1135 !> Get a character value of a given name
1136 subroutine add_get_string(cfg, var_name, string_data, comment)
1137 type(cfg_t), intent(inout) :: cfg
1138 character(len=*), intent(in) :: var_name, comment
1139 character(len=*), intent(inout) :: string_data
1140
1141 call add_string(cfg, var_name, string_data, comment)
1142 call get_string(cfg, var_name, string_data)
1143 end subroutine add_get_string
1144
1145 !> Get the size of a variable
1146 subroutine cfg_get_size(cfg, var_name, res)
1147 type(cfg_t), intent(in) :: cfg
1148 character(len=*), intent(in) :: var_name
1149 integer, intent(out) :: res
1150 integer :: ix
1151
1152 call get_var_index(cfg, var_name, ix)
1153 if (ix /= -1) then
1154 res = cfg%vars(ix)%var_size
1155 else
1156 res = -1
1157 call handle_error("CFG_get_size: variable ["//var_name//"] not found")
1158 end if
1159 end subroutine cfg_get_size
1160
1161 !> Get the type of a given variable of a configuration type
1162 subroutine cfg_get_type(cfg, var_name, res)
1163 type(cfg_t), intent(in) :: cfg
1164 character(len=*), intent(in) :: var_name
1165 integer, intent(out) :: res
1166 integer :: ix
1167
1168 call get_var_index(cfg, var_name, ix)
1169
1170 if (ix /= -1) then
1171 res = cfg%vars(ix)%var_type
1172 else
1173 res = -1
1174 call handle_error("CFG_get_type: variable ["//var_name//"] not found")
1175 end if
1176 end subroutine cfg_get_type
1177
1178 !> Routine to ensure that enough storage is allocated for the configuration
1179 !> type. If not the new size will be twice as much as the current size. If no
1180 !> storage is allocated yet a minumum amount of starage is allocated.
1181 subroutine ensure_free_storage(cfg)
1182 type(cfg_t), intent(inout) :: cfg
1183 type(cfg_var_t), allocatable :: cfg_copy(:)
1184 integer, parameter :: min_dyn_size = 100
1185 integer :: cur_size, new_size
1186
1187 if (allocated(cfg%vars)) then
1188 cur_size = size(cfg%vars)
1189
1190 if (cur_size < cfg%num_vars + 1) then
1191 new_size = 2 * cur_size
1192 allocate(cfg_copy(cur_size))
1193 cfg_copy = cfg%vars
1194 deallocate(cfg%vars)
1195 allocate(cfg%vars(new_size))
1196 cfg%vars(1:cur_size) = cfg_copy
1197 end if
1198 else
1199 allocate(cfg%vars(min_dyn_size))
1200 end if
1201
1202 end subroutine ensure_free_storage
1203
1204 !> Routine to find the indices of entries in a string
1205 subroutine get_fields_string(line, delims, n_max, n_found, ixs_start, ixs_end)
1206 !> The line from which we want to read
1207 character(len=*), intent(in) :: line
1208 !> A string with delimiters. For example delims = " ,'"""//tab_char
1209 character(len=*), intent(in) :: delims
1210 !> Maximum number of entries to read in
1211 integer, intent(in) :: n_max
1212 !> Number of entries found
1213 integer, intent(inout) :: n_found
1214 !> On return, ix_start(i) holds the starting point of entry i
1215 integer, intent(inout) :: ixs_start(n_max)
1216 !> On return, ix_end(i) holds the end point of entry i
1217 integer, intent(inout) :: ixs_end(n_max)
1218
1219 integer :: ix, ix_prev
1220
1221 ix_prev = 0
1222 n_found = 0
1223
1224 do while (n_found < n_max)
1225
1226 ! Find the starting point of the next entry (a non-delimiter value)
1227 ix = verify(line(ix_prev+1:), delims)
1228 if (ix == 0) exit
1229
1230 n_found = n_found + 1
1231 ixs_start(n_found) = ix_prev + ix ! This is the absolute position in 'line'
1232
1233 ! Get the end point of the current entry (next delimiter index minus one)
1234 ix = scan(line(ixs_start(n_found)+1:), delims) - 1
1235
1236 if (ix == -1) then ! If there is no last delimiter,
1237 ixs_end(n_found) = len(line) ! the end of the line is the endpoint
1238 else
1239 ixs_end(n_found) = ixs_start(n_found) + ix
1240 end if
1241
1242 ix_prev = ixs_end(n_found) ! We continue to search from here
1243 end do
1244
1245 end subroutine get_fields_string
1246
1247 !> Performa a binary search for the variable 'var_name'
1248 subroutine binary_search_variable(cfg, var_name, ix)
1249 type(cfg_t), intent(in) :: cfg
1250 character(len=*), intent(in) :: var_name
1251 integer, intent(out) :: ix
1252 integer :: i_min, i_max, i_mid
1253
1254 i_min = 1
1255 i_max = cfg%num_vars
1256 ix = - 1
1257
1258 do while (i_min < i_max)
1259 i_mid = i_min + (i_max - i_min) / 2
1260 if ( llt(cfg%vars(i_mid)%var_name, var_name) ) then
1261 i_min = i_mid + 1
1262 else
1263 i_max = i_mid
1264 end if
1265 end do
1266
1267 ! If not found, binary_search_variable is not set here, and stays -1
1268 if (i_max == i_min .and. cfg%vars(i_min)%var_name == var_name) then
1269 ix = i_min
1270 else
1271 ix = -1
1272 end if
1273 end subroutine binary_search_variable
1274
1275 !> Sort the variables for faster lookup
1276 subroutine cfg_sort(cfg)
1277 type(cfg_t), intent(inout) :: cfg
1278
1279 call qsort_config(cfg%vars(1:cfg%num_vars))
1280 cfg%sorted = .true.
1281 end subroutine cfg_sort
1282
1283 !> Simple implementation of quicksort algorithm to sort the variable list alphabetically.
1284 recursive subroutine qsort_config(list)
1285 type(cfg_var_t), intent(inout) :: list(:)
1286 integer :: split_pos
1287
1288 if (size(list) > 1) then
1289 call parition_var_list(list, split_pos)
1290 call qsort_config( list(:split_pos-1) )
1291 call qsort_config( list(split_pos:) )
1292 end if
1293 end subroutine qsort_config
1294
1295 !> Helper routine for quicksort, to perform partitioning
1296 subroutine parition_var_list(list, marker)
1297 type(cfg_var_t), intent(inout) :: list(:)
1298 integer, intent(out) :: marker
1299 integer :: left, right, pivot_ix
1300 type(cfg_var_t) :: temp
1301 character(len=CFG_name_len) :: pivot_value
1302
1303 left = 0
1304 right = size(list) + 1
1305
1306 ! Take the middle element as pivot
1307 pivot_ix = size(list) / 2
1308 pivot_value = list(pivot_ix)%var_name
1309
1310 do while (left < right)
1311
1312 right = right - 1
1313 do while (lgt(list(right)%var_name, pivot_value))
1314 right = right - 1
1315 end do
1316
1317 left = left + 1
1318 do while (lgt(pivot_value, list(left)%var_name))
1319 left = left + 1
1320 end do
1321
1322 if (left < right) then
1323 temp = list(left)
1324 list(left) = list(right)
1325 list(right) = temp
1326 end if
1327 end do
1328
1329 if (left == right) then
1330 marker = left + 1
1331 else
1332 marker = left
1333 end if
1334 end subroutine parition_var_list
1335
1336 !> Clear all data from a CFG_t object, so that it can be reused. Note that
1337 !> this also happens automatically when such an object goes out of scope.
1338 subroutine cfg_clear(cfg)
1339 implicit none
1340 type(cfg_t) :: cfg
1341
1342 cfg%sorted = .false.
1343 cfg%num_vars = 0
1344 if(allocated(cfg%vars)) then
1345 deallocate(cfg%vars)
1346 endif
1347 end subroutine cfg_clear
1348
1349end module m_config
Interface to get variables from the configuration.
Definition m_config.f90:102
Interface to add variables to the configuration.
Definition m_config.f90:86
Interface to get variables from the configuration.
Definition m_config.f90:94
Module that allows working with a configuration file.
Definition m_config.f90:5
integer, parameter, public cfg_real_type
Real number type.
Definition m_config.f90:15
subroutine, public cfg_write(cfg_in, filename, hide_unused, custom_first)
This routine writes the current configuration to a file with descriptions.
Definition m_config.f90:480
character(len=10), dimension(0:cfg_num_types), parameter, public cfg_type_names
Names of the types.
Definition m_config.f90:28
subroutine, public cfg_get_size(cfg, var_name, res)
Get the size of a variable.
integer, parameter, public cfg_max_array_size
Maximum number of entries in a variable (if it's an array)
Definition m_config.f90:37
integer, parameter, public cfg_string_len
Fixed length of string type.
Definition m_config.f90:32
integer, parameter, public cfg_logic_type
Boolean/logical type.
Definition m_config.f90:17
subroutine, public cfg_update_from_line(cfg, line)
Update the configuration by parsing a line.
Definition m_config.f90:190
integer, parameter, public cfg_name_len
Maximum length of variable names.
Definition m_config.f90:31
integer, parameter, public cfg_integer_type
Integer type.
Definition m_config.f90:14
subroutine, public cfg_write_markdown(cfg_in, filename, hide_unused)
This routine writes the current configuration to a markdown file.
Definition m_config.f90:615
subroutine, public cfg_sort(cfg)
Sort the variables for faster lookup.
subroutine, public cfg_clear(cfg)
Clear all data from a CFG_t object, so that it can be reused. Note that this also happens automatical...
subroutine, public cfg_update_from_arguments(cfg, ignore_unknown)
Read command line arguments. Both files and variables can be specified, for example as: ....
Definition m_config.f90:146
subroutine, public cfg_get_type(cfg, var_name, res)
Get the type of a given variable of a configuration type.
integer, parameter, public cfg_max_line_len
Maximum length of line containing multiple arguments/values.
Definition m_config.f90:34
integer, parameter, public cfg_string_type
String type.
Definition m_config.f90:16
subroutine, public cfg_read_file(cfg, filename)
Update the variables in the configartion with the values found in 'filename'.
Definition m_config.f90:239
subroutine, public cfg_check(cfg)
Definition m_config.f90:465
The configuration that contains all the variables.
Definition m_config.f90:79