(git:374b731)
Loading...
Searching...
No Matches
cp_parser_methods.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief Utility routines to read data from files.
10!> Kept as close as possible to the old parser because
11!> 1. string handling is a weak point of fortran compilers, and it is
12!> easy to write correct things that do not work
13!> 2. conversion of old code
14!> \par History
15!> 22.11.1999 first version of the old parser (called qs_parser)
16!> Matthias Krack
17!> 06.2004 removed module variables, cp_parser_type, new module [fawzi]
18!> \author Fawzi Mohamed, Matthias Krack
19! **************************************************************************************************
21
34 USE kinds, ONLY: default_path_length,&
36 dp,&
37 int_8,&
39 USE mathconstants, ONLY: radians
43#include "../base/base_uses.f90"
44
45 IMPLICIT NONE
46 PRIVATE
47
51
52 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_parser_methods'
53
55 MODULE PROCEDURE parser_get_integer, &
56 parser_get_logical, &
57 parser_get_real, &
58 parser_get_string
59 END INTERFACE
60
61CONTAINS
62
63! **************************************************************************************************
64!> \brief return a description of the part of the file actually parsed
65!> \param parser the parser
66!> \return ...
67!> \author fawzi
68! **************************************************************************************************
69 FUNCTION parser_location(parser) RESULT(res)
70
71 TYPE(cp_parser_type), INTENT(IN) :: parser
72 character&
74
75 res = ", File: '"//trim(parser%input_file_name)//"', Line: "// &
76 trim(adjustl(cp_to_string(parser%input_line_number)))// &
77 ", Column: "//trim(adjustl(cp_to_string(parser%icol)))
78 IF (parser%icol == -1) THEN
79 res(len_trim(res):) = " (EOF)"
80 ELSE IF (max(1, parser%icol1) <= parser%icol2) THEN
81 res(len_trim(res):) = ", Chunk: <"// &
82 parser%input_line(max(1, parser%icol1):parser%icol2)//">"
83 END IF
84
85 END FUNCTION parser_location
86
87! **************************************************************************************************
88!> \brief store the present status of the parser
89!> \param parser ...
90!> \date 08.2008
91!> \author Teodoro Laino [tlaino] - University of Zurich
92! **************************************************************************************************
93 SUBROUTINE parser_store_status(parser)
94
95 TYPE(cp_parser_type), INTENT(INOUT) :: parser
96
97 cpassert(ASSOCIATED(parser%status))
98 parser%status%in_use = .true.
99 parser%status%old_input_line = parser%input_line
100 parser%status%old_input_line_number = parser%input_line_number
101 parser%status%old_icol = parser%icol
102 parser%status%old_icol1 = parser%icol1
103 parser%status%old_icol2 = parser%icol2
104 ! Store buffer info
105 CALL copy_buffer_type(parser%buffer, parser%status%buffer)
106
107 END SUBROUTINE parser_store_status
108
109! **************************************************************************************************
110!> \brief retrieve the original status of the parser
111!> \param parser ...
112!> \date 08.2008
113!> \author Teodoro Laino [tlaino] - University of Zurich
114! **************************************************************************************************
115 SUBROUTINE parser_retrieve_status(parser)
116
117 TYPE(cp_parser_type), INTENT(INOUT) :: parser
118
119 ! Always store the new buffer (if it is really newly read)
120 IF (parser%buffer%buffer_id /= parser%status%buffer%buffer_id) THEN
121 CALL initialize_sub_buffer(parser%buffer%sub_buffer, parser%buffer)
122 END IF
123 parser%status%in_use = .false.
124 parser%input_line = parser%status%old_input_line
125 parser%input_line_number = parser%status%old_input_line_number
126 parser%icol = parser%status%old_icol
127 parser%icol1 = parser%status%old_icol1
128 parser%icol2 = parser%status%old_icol2
129
130 ! Retrieve buffer info
131 CALL copy_buffer_type(parser%status%buffer, parser%buffer)
132
133 END SUBROUTINE parser_retrieve_status
134
135! **************************************************************************************************
136!> \brief Read the next line from a logical unit "unit" (I/O node only).
137!> Skip (nline-1) lines and skip also all comment lines.
138!> \param parser ...
139!> \param nline ...
140!> \param at_end ...
141!> \date 22.11.1999
142!> \author Matthias Krack (MK)
143!> \version 1.0
144!> \note 08.2008 [tlaino] - Teodoro Laino UZH : updated for buffer
145! **************************************************************************************************
146 SUBROUTINE parser_read_line(parser, nline, at_end)
147
148 TYPE(cp_parser_type), INTENT(INOUT) :: parser
149 INTEGER, INTENT(IN) :: nline
150 LOGICAL, INTENT(out), OPTIONAL :: at_end
151
152 CHARACTER(LEN=*), PARAMETER :: routinen = 'parser_read_line'
153
154 INTEGER :: handle, iline, istat
155
156 CALL timeset(routinen, handle)
157
158 IF (PRESENT(at_end)) at_end = .false.
159
160 DO iline = 1, nline
161 ! Try to read the next line from the buffer
162 CALL parser_get_line_from_buffer(parser, istat)
163
164 ! Handle (persisting) read errors
165 IF (istat /= 0) THEN
166 IF (istat < 0) THEN ! EOF/EOR is negative other errors positive
167 IF (PRESENT(at_end)) THEN
168 at_end = .true.
169 ELSE
170 cpabort("Unexpected EOF"//trim(parser_location(parser)))
171 END IF
172 parser%icol = -1
173 parser%icol1 = 0
174 parser%icol2 = -1
175 ELSE
176 CALL cp_abort(__location__, &
177 "An I/O error occurred (IOSTAT = "// &
178 trim(adjustl(cp_to_string(istat)))//")"// &
179 trim(parser_location(parser)))
180 END IF
181 CALL timestop(handle)
182 RETURN
183 END IF
184 END DO
185
186 ! Reset column pointer, if a new line was read
187 IF (nline > 0) parser%icol = 0
188
189 CALL timestop(handle)
190 END SUBROUTINE parser_read_line
191
192! **************************************************************************************************
193!> \brief Retrieving lines from buffer
194!> \param parser ...
195!> \param istat ...
196!> \date 08.2008
197!> \author Teodoro Laino [tlaino] - University of Zurich
198! **************************************************************************************************
199 SUBROUTINE parser_get_line_from_buffer(parser, istat)
200
201 TYPE(cp_parser_type), INTENT(INOUT) :: parser
202 INTEGER, INTENT(OUT) :: istat
203
204 istat = 0
205 ! Check buffer
206 IF (parser%buffer%present_line_number == parser%buffer%size) THEN
207 IF (ASSOCIATED(parser%buffer%sub_buffer)) THEN
208 ! If the sub_buffer is initialized let's restore its buffer
209 CALL finalize_sub_buffer(parser%buffer%sub_buffer, parser%buffer)
210 ELSE
211 ! Rebuffer input file if required
212 CALL parser_read_line_low(parser)
213 END IF
214 END IF
215 parser%buffer%present_line_number = parser%buffer%present_line_number + 1
216 parser%input_line_number = parser%buffer%input_line_numbers(parser%buffer%present_line_number)
217 parser%input_line = parser%buffer%input_lines(parser%buffer%present_line_number)
218 IF ((parser%buffer%istat /= 0) .AND. &
219 (parser%buffer%last_line_number == parser%buffer%present_line_number)) THEN
220 istat = parser%buffer%istat
221 END IF
222
223 END SUBROUTINE parser_get_line_from_buffer
224
225! **************************************************************************************************
226!> \brief Low level reading subroutine with buffering
227!> \param parser ...
228!> \date 08.2008
229!> \author Teodoro Laino [tlaino] - University of Zurich
230! **************************************************************************************************
231 SUBROUTINE parser_read_line_low(parser)
232
233 TYPE(cp_parser_type), INTENT(INOUT) :: parser
234
235 CHARACTER(LEN=*), PARAMETER :: routinen = 'parser_read_line_low'
236
237 INTEGER :: handle, iline, imark, islen, istat, &
238 last_buffered_line_number
239 LOGICAL :: non_white_found, &
240 this_line_is_white_or_comment
241
242 CALL timeset(routinen, handle)
243
244 parser%buffer%input_lines = ""
245 IF (parser%para_env%is_source()) THEN
246 iline = 0
247 istat = 0
248 parser%buffer%buffer_id = parser%buffer%buffer_id + 1
249 parser%buffer%present_line_number = 0
250 parser%buffer%last_line_number = parser%buffer%size
251 last_buffered_line_number = parser%buffer%input_line_numbers(parser%buffer%size)
252 DO WHILE (iline /= parser%buffer%size)
253 ! Increment counters by 1
254 iline = iline + 1
255 last_buffered_line_number = last_buffered_line_number + 1
256
257 ! Try to read the next line from file
258 parser%buffer%input_line_numbers(iline) = last_buffered_line_number
259 READ (unit=parser%input_unit, fmt="(A)", iostat=istat) parser%buffer%input_lines(iline)
260
261 ! Pre-processing steps:
262 ! 1. Expand variables 2. Process directives and read next line.
263 ! On read failure try to go back from included file to previous i/o-stream.
264 IF (istat == 0) THEN
265 islen = len_trim(parser%buffer%input_lines(iline))
266 this_line_is_white_or_comment = is_comment_line(parser, parser%buffer%input_lines(iline))
267 IF (.NOT. this_line_is_white_or_comment .AND. parser%apply_preprocessing) THEN
268 imark = index(parser%buffer%input_lines(iline) (1:islen), "$")
269 IF (imark /= 0) THEN
270 CALL inpp_expand_variables(parser%inpp, parser%buffer%input_lines(iline), &
271 parser%input_file_name, parser%buffer%input_line_numbers(iline))
272 islen = len_trim(parser%buffer%input_lines(iline))
273 END IF
274 imark = index(parser%buffer%input_lines(iline) (1:islen), "@")
275 IF (imark /= 0) THEN
276 CALL inpp_process_directive(parser%inpp, parser%buffer%input_lines(iline), &
277 parser%input_file_name, parser%buffer%input_line_numbers(iline), &
278 parser%input_unit)
279 islen = len_trim(parser%buffer%input_lines(iline))
280 ! Handle index and cycle
281 last_buffered_line_number = 0
282 iline = iline - 1
283 cycle
284 END IF
285
286 ! after preprocessor parsing could the line be empty again
287 this_line_is_white_or_comment = is_comment_line(parser, parser%buffer%input_lines(iline))
288 END IF
289 ELSE IF (istat < 0) THEN ! handle EOF
290 IF (parser%inpp%io_stack_level > 0) THEN
291 ! We were reading from an included file. Go back one level.
292 CALL inpp_end_include(parser%inpp, parser%input_file_name, &
293 parser%buffer%input_line_numbers(iline), parser%input_unit)
294 ! Handle index and cycle
295 last_buffered_line_number = parser%buffer%input_line_numbers(iline)
296 iline = iline - 1
297 cycle
298 END IF
299 END IF
300
301 ! Saving persisting read errors
302 IF (istat /= 0) THEN
303 parser%buffer%istat = istat
304 parser%buffer%last_line_number = iline
305 parser%buffer%input_line_numbers(iline:) = 0
306 parser%buffer%input_lines(iline:) = ""
307 EXIT
308 END IF
309
310 ! Pre-processing and error checking done. Ready for parsing.
311 IF (.NOT. parser%parse_white_lines) THEN
312 non_white_found = .NOT. this_line_is_white_or_comment
313 ELSE
314 non_white_found = .true.
315 END IF
316 IF (.NOT. non_white_found) THEN
317 iline = iline - 1
318 last_buffered_line_number = last_buffered_line_number - 1
319 END IF
320 END DO
321 END IF
322 ! Broadcast buffer informations
323 CALL broadcast_input_information(parser)
324
325 CALL timestop(handle)
326
327 END SUBROUTINE parser_read_line_low
328
329! **************************************************************************************************
330!> \brief Broadcast the input information.
331!> \param parser ...
332!> \date 02.03.2001
333!> \author Matthias Krack (MK)
334!> \note 08.2008 [tlaino] - Teodoro Laino UZH : updated for buffer
335! **************************************************************************************************
336 SUBROUTINE broadcast_input_information(parser)
337
338 TYPE(cp_parser_type), INTENT(INOUT) :: parser
339
340 CHARACTER(len=*), PARAMETER :: routinen = 'broadcast_input_information'
341
342 INTEGER :: handle
343 TYPE(mp_para_env_type), POINTER :: para_env
344
345 CALL timeset(routinen, handle)
346
347 para_env => parser%para_env
348 IF (para_env%num_pe > 1) THEN
349 CALL para_env%bcast(parser%buffer%buffer_id)
350 CALL para_env%bcast(parser%buffer%present_line_number)
351 CALL para_env%bcast(parser%buffer%last_line_number)
352 CALL para_env%bcast(parser%buffer%istat)
353 CALL para_env%bcast(parser%buffer%input_line_numbers)
354 CALL para_env%bcast(parser%buffer%input_lines)
355 END IF
356
357 CALL timestop(handle)
358
359 END SUBROUTINE broadcast_input_information
360
361! **************************************************************************************************
362!> \brief returns .true. if the line is a comment line or an empty line
363!> \param parser ...
364!> \param line ...
365!> \return ...
366!> \par History
367!> 03.2009 [tlaino] - Teodoro Laino
368! **************************************************************************************************
369 ELEMENTAL FUNCTION is_comment_line(parser, line) RESULT(resval)
370
371 TYPE(cp_parser_type), INTENT(IN) :: parser
372 CHARACTER(LEN=*), INTENT(IN) :: line
373 LOGICAL :: resval
374
375 CHARACTER(LEN=1) :: thischar
376 INTEGER :: icol
377
378 resval = .true.
379 DO icol = 1, len(line)
380 thischar = line(icol:icol)
381 IF (.NOT. is_whitespace(thischar)) THEN
382 IF (.NOT. is_comment(parser, thischar)) resval = .false.
383 EXIT
384 END IF
385 END DO
386
387 END FUNCTION is_comment_line
388
389! **************************************************************************************************
390!> \brief returns .true. if the character passed is a comment character
391!> \param parser ...
392!> \param testchar ...
393!> \return ...
394!> \par History
395!> 02.2008 created, AK
396!> \author AK
397! **************************************************************************************************
398 ELEMENTAL FUNCTION is_comment(parser, testchar) RESULT(resval)
399
400 TYPE(cp_parser_type), INTENT(IN) :: parser
401 CHARACTER(LEN=1), INTENT(IN) :: testchar
402 LOGICAL :: resval
403
404 resval = .false.
405 ! We are in a private function, and parser has been tested before...
406 IF (any(parser%comment_character == testchar)) resval = .true.
407
408 END FUNCTION is_comment
409
410! **************************************************************************************************
411!> \brief Read the next input line and broadcast the input information.
412!> Skip (nline-1) lines and skip also all comment lines.
413!> \param parser ...
414!> \param nline ...
415!> \param at_end ...
416!> \date 22.11.1999
417!> \author Matthias Krack (MK)
418!> \version 1.0
419! **************************************************************************************************
420 SUBROUTINE parser_get_next_line(parser, nline, at_end)
421
422 TYPE(cp_parser_type), INTENT(INOUT) :: parser
423 INTEGER, INTENT(IN) :: nline
424 LOGICAL, INTENT(out), OPTIONAL :: at_end
425
426 LOGICAL :: my_at_end
427
428 IF (nline > 0) THEN
429 CALL parser_read_line(parser, nline, at_end=my_at_end)
430 IF (PRESENT(at_end)) THEN
431 at_end = my_at_end
432 ELSE
433 IF (my_at_end) THEN
434 cpabort("Unexpected EOF"//trim(parser_location(parser)))
435 END IF
436 END IF
437 ELSE IF (PRESENT(at_end)) THEN
438 at_end = .false.
439 END IF
440
441 END SUBROUTINE parser_get_next_line
442
443! **************************************************************************************************
444!> \brief Skips the whitespaces
445!> \param parser ...
446!> \date 02.03.2001
447!> \author Matthias Krack (MK)
448!> \version 1.0
449! **************************************************************************************************
450 SUBROUTINE parser_skip_space(parser)
451 TYPE(cp_parser_type), INTENT(INOUT) :: parser
452
453 INTEGER :: i
454 LOGICAL :: at_end
455
456 ! Variable input string length (automatic search)
457
458 ! Check for EOF
459 IF (parser%icol == -1) THEN
460 parser%icol1 = 1
461 parser%icol2 = -1
462 RETURN
463 END IF
464
465 ! Search for the beginning of the next input string
466 outer_loop: DO
467
468 ! Increment the column counter
469 parser%icol = parser%icol + 1
470
471 ! Quick return, if the end of line is found
472 IF ((parser%icol > len_trim(parser%input_line)) .OR. &
473 is_comment(parser, parser%input_line(parser%icol:parser%icol))) THEN
474 parser%icol1 = 1
475 parser%icol2 = -1
476 RETURN
477 END IF
478
479 ! Ignore all white space
480 IF (.NOT. is_whitespace(parser%input_line(parser%icol:parser%icol))) THEN
481 ! Check for input line continuation
482 IF (parser%input_line(parser%icol:parser%icol) == parser%continuation_character) THEN
483 inner_loop: DO i = parser%icol + 1, len_trim(parser%input_line)
484 IF (is_whitespace(parser%input_line(i:i))) cycle inner_loop
485 IF (is_comment(parser, parser%input_line(i:i))) THEN
486 EXIT inner_loop
487 ELSE
488 parser%icol1 = i
489 parser%icol2 = len_trim(parser%input_line)
490 CALL cp_abort(__location__, &
491 "Found a non-blank token which is not a comment after the line continuation character '"// &
492 parser%continuation_character//"'"//trim(parser_location(parser)))
493 END IF
494 END DO inner_loop
495 CALL parser_get_next_line(parser, 1, at_end=at_end)
496 IF (at_end) THEN
497 CALL cp_abort(__location__, &
498 "Unexpected end of file (EOF) found after line continuation"// &
499 trim(parser_location(parser)))
500 END IF
501 parser%icol = 0
502 cycle outer_loop
503 ELSE
504 parser%icol = parser%icol - 1
505 parser%icol1 = parser%icol
506 parser%icol2 = parser%icol
507 RETURN
508 END IF
509 END IF
510
511 END DO outer_loop
512
513 END SUBROUTINE parser_skip_space
514
515! **************************************************************************************************
516!> \brief Get the next input string from the input line.
517!> \param parser ...
518!> \param string_length ...
519!> \date 19.02.2001
520!> \author Matthias Krack (MK)
521!> \version 1.0
522!> \notes -) this function MUST be private in this module!
523! **************************************************************************************************
524 SUBROUTINE parser_next_token(parser, string_length)
525
526 TYPE(cp_parser_type), INTENT(INOUT) :: parser
527 INTEGER, INTENT(IN), OPTIONAL :: string_length
528
529 CHARACTER(LEN=1) :: token
530 INTEGER :: i, len_trim_inputline, length
531 LOGICAL :: at_end
532
533 IF (PRESENT(string_length)) THEN
534 IF (string_length > max_line_length) THEN
535 cpabort("string length > max_line_length")
536 ELSE
537 length = string_length
538 END IF
539 ELSE
540 length = 0
541 END IF
542
543 ! Precompute trimmed line length
544 len_trim_inputline = len_trim(parser%input_line)
545
546 IF (length > 0) THEN
547
548 ! Read input string of fixed length (single line)
549
550 ! Check for EOF
551 IF (parser%icol == -1) &
552 cpabort("Unexpectetly reached EOF"//trim(parser_location(parser)))
553
554 length = min(len_trim_inputline - parser%icol1 + 1, length)
555 parser%icol1 = parser%icol + 1
556 parser%icol2 = parser%icol + length
557 i = index(parser%input_line(parser%icol1:parser%icol2), parser%quote_character)
558 IF (i > 0) parser%icol2 = parser%icol + i
559 parser%icol = parser%icol2
560
561 ELSE
562
563 ! Variable input string length (automatic multi-line search)
564
565 ! Check for EOF
566 IF (parser%icol == -1) THEN
567 parser%icol1 = 1
568 parser%icol2 = -1
569 RETURN
570 END IF
571
572 ! Search for the beginning of the next input string
573 outer_loop1: DO
574
575 ! Increment the column counter
576 parser%icol = parser%icol + 1
577
578 ! Quick return, if the end of line is found
579 IF (parser%icol > len_trim_inputline) THEN
580 parser%icol1 = 1
581 parser%icol2 = -1
582 RETURN
583 END IF
584
585 token = parser%input_line(parser%icol:parser%icol)
586
587 IF (is_whitespace(token)) THEN
588 ! Ignore white space
589 cycle outer_loop1
590 ELSE IF (is_comment(parser, token)) THEN
591 parser%icol1 = 1
592 parser%icol2 = -1
593 parser%first_separator = .true.
594 RETURN
595 ELSE IF (token == parser%quote_character) THEN
596 ! Read quoted string
597 parser%icol1 = parser%icol + 1
598 parser%icol2 = parser%icol + index(parser%input_line(parser%icol1:), parser%quote_character)
599 IF (parser%icol2 == parser%icol) THEN
600 parser%icol1 = parser%icol
601 parser%icol2 = parser%icol
602 CALL cp_abort(__location__, &
603 "Unmatched quotation mark found"//trim(parser_location(parser)))
604 ELSE
605 parser%icol = parser%icol2
606 parser%icol2 = parser%icol2 - 1
607 parser%first_separator = .true.
608 RETURN
609 END IF
610 ELSE IF (token == parser%continuation_character) THEN
611 ! Check for input line continuation
612 inner_loop1: DO i = parser%icol + 1, len_trim_inputline
613 IF (is_whitespace(parser%input_line(i:i))) THEN
614 cycle inner_loop1
615 ELSE IF (is_comment(parser, parser%input_line(i:i))) THEN
616 EXIT inner_loop1
617 ELSE
618 parser%icol1 = i
619 parser%icol2 = len_trim_inputline
620 CALL cp_abort(__location__, &
621 "Found a non-blank token which is not a comment after the line continuation character '"// &
622 parser%continuation_character//"'"//trim(parser_location(parser)))
623 END IF
624 END DO inner_loop1
625 CALL parser_get_next_line(parser, 1, at_end=at_end)
626 IF (at_end) THEN
627 CALL cp_abort(__location__, &
628 "Unexpected end of file (EOF) found after line continuation"//trim(parser_location(parser)))
629 END IF
630 len_trim_inputline = len_trim(parser%input_line)
631 cycle outer_loop1
632 ELSE IF (index(parser%separators, token) > 0) THEN
633 IF (parser%first_separator) THEN
634 parser%first_separator = .false.
635 cycle outer_loop1
636 ELSE
637 parser%icol1 = parser%icol
638 parser%icol2 = parser%icol
639 CALL cp_abort(__location__, &
640 "Unexpected separator token '"//token// &
641 "' found"//trim(parser_location(parser)))
642 END IF
643 ELSE
644 parser%icol1 = parser%icol
645 parser%first_separator = .true.
646 EXIT outer_loop1
647 END IF
648
649 END DO outer_loop1
650
651 ! Search for the end of the next input string
652 outer_loop2: DO
653 parser%icol = parser%icol + 1
654 IF (parser%icol > len_trim_inputline) EXIT outer_loop2
655 token = parser%input_line(parser%icol:parser%icol)
656 IF (is_whitespace(token) .OR. is_comment(parser, token) .OR. &
657 (token == parser%continuation_character)) THEN
658 EXIT outer_loop2
659 ELSE IF (index(parser%separators, token) > 0) THEN
660 parser%first_separator = .false.
661 EXIT outer_loop2
662 END IF
663 END DO outer_loop2
664
665 parser%icol2 = parser%icol - 1
666
667 IF (parser%input_line(parser%icol:parser%icol) == &
668 parser%continuation_character) parser%icol = parser%icol2
669
670 END IF
671
672 END SUBROUTINE parser_next_token
673
674! **************************************************************************************************
675!> \brief Test next input object.
676!> - test_result : "EOL": End of line
677!> - test_result : "EOS": End of section
678!> - test_result : "FLT": Floating point number
679!> - test_result : "INT": Integer number
680!> - test_result : "STR": String
681!> \param parser ...
682!> \param string_length ...
683!> \return ...
684!> \date 23.11.1999
685!> \author Matthias Krack (MK)
686!> \note - 08.2008 [tlaino] - Teodoro Laino UZH : updated for buffer
687!> - Major rewrite to parse also (multiple) products of integer or
688!> floating point numbers (23.11.2012,MK)
689! **************************************************************************************************
690 FUNCTION parser_test_next_token(parser, string_length) RESULT(test_result)
691
692 TYPE(cp_parser_type), INTENT(INOUT) :: parser
693 INTEGER, INTENT(IN), OPTIONAL :: string_length
694 CHARACTER(LEN=3) :: test_result
695
696 CHARACTER(LEN=max_line_length) :: error_message, string
697 INTEGER :: iz, n
698 LOGICAL :: ilist_in_use
699 REAL(kind=dp) :: fz
700
701 test_result = ""
702
703 ! Store current status
704 CALL parser_store_status(parser)
705
706 ! Handle possible list of integers
707 ilist_in_use = parser%ilist%in_use .AND. (parser%ilist%ipresent < parser%ilist%iend)
708 IF (ilist_in_use) THEN
709 test_result = "INT"
710 CALL parser_retrieve_status(parser)
711 RETURN
712 END IF
713
714 ! Otherwise continue normally
715 IF (PRESENT(string_length)) THEN
716 CALL parser_next_token(parser, string_length=string_length)
717 ELSE
718 CALL parser_next_token(parser)
719 END IF
720
721 ! End of line
722 IF (parser%icol1 > parser%icol2) THEN
723 test_result = "EOL"
724 CALL parser_retrieve_status(parser)
725 RETURN
726 END IF
727
728 string = parser%input_line(parser%icol1:parser%icol2)
729 n = len_trim(string)
730
731 IF (n == 0) THEN
732 test_result = "STR"
733 CALL parser_retrieve_status(parser)
734 RETURN
735 END IF
736
737 ! Check for end section string
738 IF (string(1:n) == parser%end_section) THEN
739 test_result = "EOS"
740 CALL parser_retrieve_status(parser)
741 RETURN
742 END IF
743
744 ! Check for integer object
745 error_message = ""
746 CALL read_integer_object(string(1:n), iz, error_message)
747 IF (len_trim(error_message) == 0) THEN
748 test_result = "INT"
749 CALL parser_retrieve_status(parser)
750 RETURN
751 END IF
752
753 ! Check for floating point object
754 error_message = ""
755 CALL read_float_object(string(1:n), fz, error_message)
756 IF (len_trim(error_message) == 0) THEN
757 test_result = "FLT"
758 CALL parser_retrieve_status(parser)
759 RETURN
760 END IF
761
762 test_result = "STR"
763 CALL parser_retrieve_status(parser)
764
765 END FUNCTION parser_test_next_token
766
767! **************************************************************************************************
768!> \brief Search a string pattern in a file defined by its logical unit
769!> number "unit". A case sensitive search is performed, if
770!> ignore_case is .FALSE..
771!> begin_line: give back the parser at the beginning of the line
772!> matching the search
773!> \param parser ...
774!> \param string ...
775!> \param ignore_case ...
776!> \param found ...
777!> \param line ...
778!> \param begin_line ...
779!> \param search_from_begin_of_file ...
780!> \date 05.10.1999
781!> \author MK
782!> \note 08.2008 [tlaino] - Teodoro Laino UZH : updated for buffer
783! **************************************************************************************************
784 SUBROUTINE parser_search_string(parser, string, ignore_case, found, line, begin_line, &
785 search_from_begin_of_file)
786
787 TYPE(cp_parser_type), INTENT(INOUT) :: parser
788 CHARACTER(LEN=*), INTENT(IN) :: string
789 LOGICAL, INTENT(IN) :: ignore_case
790 LOGICAL, INTENT(OUT) :: found
791 CHARACTER(LEN=*), INTENT(OUT), OPTIONAL :: line
792 LOGICAL, INTENT(IN), OPTIONAL :: begin_line, search_from_begin_of_file
793
794 CHARACTER(LEN=LEN(string)) :: pattern
795 CHARACTER(LEN=max_line_length+1) :: current_line
796 INTEGER :: ipattern
797 LOGICAL :: at_end, begin, do_reset
798
799 found = .false.
800 begin = .false.
801 do_reset = .false.
802 IF (PRESENT(begin_line)) begin = begin_line
803 IF (PRESENT(search_from_begin_of_file)) do_reset = search_from_begin_of_file
804 IF (PRESENT(line)) line = ""
805
806 ! Search for string pattern
807 pattern = string
808 IF (ignore_case) CALL uppercase(pattern)
809 IF (do_reset) CALL parser_reset(parser)
810 DO
811 ! This call is buffered.. so should not represent any bottleneck
812 CALL parser_get_next_line(parser, 1, at_end=at_end)
813
814 ! Exit loop, if the end of file is reached
815 IF (at_end) EXIT
816
817 ! Check the current line for string pattern
818 current_line = parser%input_line
819 IF (ignore_case) CALL uppercase(current_line)
820 ipattern = index(current_line, trim(pattern))
821
822 IF (ipattern > 0) THEN
823 found = .true.
824 parser%icol = ipattern - 1
825 IF (PRESENT(line)) THEN
826 IF (len(line) < len_trim(parser%input_line)) THEN
827 CALL cp_warn(__location__, &
828 "The returned input line has more than "// &
829 trim(adjustl(cp_to_string(len(line))))// &
830 " characters and is therefore too long to fit in the "// &
831 "specified variable"// &
832 trim(parser_location(parser)))
833 END IF
834 END IF
835 EXIT
836 END IF
837
838 END DO
839
840 IF (found) THEN
841 IF (begin) parser%icol = 0
842 END IF
843
844 IF (found) THEN
845 IF (PRESENT(line)) line = parser%input_line
846 IF (.NOT. begin) CALL parser_next_token(parser)
847 END IF
848
849 END SUBROUTINE parser_search_string
850
851! **************************************************************************************************
852!> \brief Check, if the string object contains an object of type integer.
853!> \param string ...
854!> \return ...
855!> \date 22.11.1999
856!> \author Matthias Krack (MK)
857!> \version 1.0
858!> \note - Introducing the possibility to parse a range of integers INT1..INT2
859!> Teodoro Laino [tlaino] - University of Zurich - 08.2008
860!> - Parse also a product of integer numbers (23.11.2012,MK)
861! **************************************************************************************************
862 ELEMENTAL FUNCTION integer_object(string) RESULT(contains_integer_object)
863
864 CHARACTER(LEN=*), INTENT(IN) :: string
865 LOGICAL :: contains_integer_object
866
867 INTEGER :: i, idots, istar, n
868
869 contains_integer_object = .true.
870 n = len_trim(string)
871
872 IF (n == 0) THEN
873 contains_integer_object = .false.
874 RETURN
875 END IF
876
877 idots = index(string(1:n), "..")
878 istar = index(string(1:n), "*")
879
880 IF (idots /= 0) THEN
881 contains_integer_object = is_integer(string(1:idots - 1)) .AND. &
882 is_integer(string(idots + 2:n))
883 ELSE IF (istar /= 0) THEN
884 i = 1
885 DO WHILE (istar /= 0)
886 IF (.NOT. is_integer(string(i:i + istar - 2))) THEN
887 contains_integer_object = .false.
888 RETURN
889 END IF
890 i = i + istar
891 istar = index(string(i:n), "*")
892 END DO
893 contains_integer_object = is_integer(string(i:n))
894 ELSE
895 contains_integer_object = is_integer(string(1:n))
896 END IF
897
898 END FUNCTION integer_object
899
900! **************************************************************************************************
901!> \brief ...
902!> \param string ...
903!> \return ...
904! **************************************************************************************************
905 ELEMENTAL FUNCTION is_integer(string) RESULT(check)
906
907 CHARACTER(LEN=*), INTENT(IN) :: string
908 LOGICAL :: check
909
910 INTEGER :: i, n
911
912 check = .true.
913 n = len_trim(string)
914
915 IF (n == 0) THEN
916 check = .false.
917 RETURN
918 END IF
919
920 IF ((index("+-", string(1:1)) > 0) .AND. (n == 1)) THEN
921 check = .false.
922 RETURN
923 END IF
924
925 IF (index("+-0123456789", string(1:1)) == 0) THEN
926 check = .false.
927 RETURN
928 END IF
929
930 DO i = 2, n
931 IF (index("0123456789", string(i:i)) == 0) THEN
932 check = .false.
933 RETURN
934 END IF
935 END DO
936
937 END FUNCTION is_integer
938
939! **************************************************************************************************
940!> \brief Read an integer number.
941!> \param parser ...
942!> \param object ...
943!> \param newline ...
944!> \param skip_lines ...
945!> \param string_length ...
946!> \param at_end ...
947!> \date 22.11.1999
948!> \author Matthias Krack (MK)
949!> \version 1.0
950! **************************************************************************************************
951 SUBROUTINE parser_get_integer(parser, object, newline, skip_lines, &
952 string_length, at_end)
953
954 TYPE(cp_parser_type), INTENT(INOUT) :: parser
955 INTEGER, INTENT(OUT) :: object
956 LOGICAL, INTENT(IN), OPTIONAL :: newline
957 INTEGER, INTENT(IN), OPTIONAL :: skip_lines, string_length
958 LOGICAL, INTENT(out), OPTIONAL :: at_end
959
960 CHARACTER(LEN=max_line_length) :: error_message
961 INTEGER :: nline
962 LOGICAL :: my_at_end
963
964 IF (PRESENT(skip_lines)) THEN
965 nline = skip_lines
966 ELSE
967 nline = 0
968 END IF
969
970 IF (PRESENT(newline)) THEN
971 IF (newline) nline = nline + 1
972 END IF
973
974 CALL parser_get_next_line(parser, nline, at_end=my_at_end)
975 IF (PRESENT(at_end)) THEN
976 at_end = my_at_end
977 IF (my_at_end) RETURN
978 ELSE IF (my_at_end) THEN
979 cpabort("Unexpected EOF"//trim(parser_location(parser)))
980 END IF
981
982 IF (parser%ilist%in_use) THEN
983 CALL ilist_update(parser%ilist)
984 ELSE
985 IF (PRESENT(string_length)) THEN
986 CALL parser_next_token(parser, string_length=string_length)
987 ELSE
988 CALL parser_next_token(parser)
989 END IF
990 IF (parser%icol1 > parser%icol2) THEN
991 parser%icol1 = parser%icol
992 parser%icol2 = parser%icol
993 CALL cp_abort(__location__, &
994 "An integer type object was expected, found end of line"// &
995 trim(parser_location(parser)))
996 END IF
997 ! Checks for possible lists of integers
998 IF (index(parser%input_line(parser%icol1:parser%icol2), "..") /= 0) THEN
999 CALL ilist_setup(parser%ilist, parser%input_line(parser%icol1:parser%icol2))
1000 END IF
1001 END IF
1002
1003 IF (integer_object(parser%input_line(parser%icol1:parser%icol2))) THEN
1004 IF (parser%ilist%in_use) THEN
1005 object = parser%ilist%ipresent
1006 CALL ilist_reset(parser%ilist)
1007 ELSE
1008 CALL read_integer_object(parser%input_line(parser%icol1:parser%icol2), object, error_message)
1009 IF (len_trim(error_message) > 0) THEN
1010 cpabort(trim(error_message)//trim(parser_location(parser)))
1011 END IF
1012 END IF
1013 ELSE
1014 CALL cp_abort(__location__, &
1015 "An integer type object was expected, found <"// &
1016 parser%input_line(parser%icol1:parser%icol2)//">"// &
1017 trim(parser_location(parser)))
1018 END IF
1019
1020 END SUBROUTINE parser_get_integer
1021
1022! **************************************************************************************************
1023!> \brief Read a string representing logical object.
1024!> \param parser ...
1025!> \param object ...
1026!> \param newline ...
1027!> \param skip_lines ...
1028!> \param string_length ...
1029!> \param at_end ...
1030!> \date 01.04.2003
1031!> \par History
1032!> - New version (08.07.2003,MK)
1033!> \author FM
1034!> \version 1.0
1035! **************************************************************************************************
1036 SUBROUTINE parser_get_logical(parser, object, newline, skip_lines, &
1037 string_length, at_end)
1038
1039 TYPE(cp_parser_type), INTENT(INOUT) :: parser
1040 LOGICAL, INTENT(OUT) :: object
1041 LOGICAL, INTENT(IN), OPTIONAL :: newline
1042 INTEGER, INTENT(IN), OPTIONAL :: skip_lines, string_length
1043 LOGICAL, INTENT(out), OPTIONAL :: at_end
1044
1045 CHARACTER(LEN=max_line_length) :: input_string
1046 INTEGER :: input_string_length, nline
1047 LOGICAL :: my_at_end
1048
1049 cpassert(.NOT. parser%ilist%in_use)
1050 IF (PRESENT(skip_lines)) THEN
1051 nline = skip_lines
1052 ELSE
1053 nline = 0
1054 END IF
1055
1056 IF (PRESENT(newline)) THEN
1057 IF (newline) nline = nline + 1
1058 END IF
1059
1060 CALL parser_get_next_line(parser, nline, at_end=my_at_end)
1061 IF (PRESENT(at_end)) THEN
1062 at_end = my_at_end
1063 IF (my_at_end) RETURN
1064 ELSE IF (my_at_end) THEN
1065 cpabort("Unexpected EOF"//trim(parser_location(parser)))
1066 END IF
1067
1068 IF (PRESENT(string_length)) THEN
1069 CALL parser_next_token(parser, string_length=string_length)
1070 ELSE
1071 CALL parser_next_token(parser)
1072 END IF
1073
1074 input_string_length = parser%icol2 - parser%icol1 + 1
1075
1076 IF (input_string_length == 0) THEN
1077 parser%icol1 = parser%icol
1078 parser%icol2 = parser%icol
1079 CALL cp_abort(__location__, &
1080 "A string representing a logical object was expected, found end of line"// &
1081 trim(parser_location(parser)))
1082 ELSE
1083 input_string = ""
1084 input_string(:input_string_length) = parser%input_line(parser%icol1:parser%icol2)
1085 END IF
1086 CALL uppercase(input_string)
1087
1088 SELECT CASE (trim(input_string))
1089 CASE ("0", "F", ".F.", "FALSE", ".FALSE.", "N", "NO", "OFF")
1090 object = .false.
1091 CASE ("1", "T", ".T.", "TRUE", ".TRUE.", "Y", "YES", "ON")
1092 object = .true.
1093 CASE DEFAULT
1094 CALL cp_abort(__location__, &
1095 "A string representing a logical object was expected, found <"// &
1096 trim(input_string)//">"//trim(parser_location(parser)))
1097 END SELECT
1098
1099 END SUBROUTINE parser_get_logical
1100
1101! **************************************************************************************************
1102!> \brief Read a floating point number.
1103!> \param parser ...
1104!> \param object ...
1105!> \param newline ...
1106!> \param skip_lines ...
1107!> \param string_length ...
1108!> \param at_end ...
1109!> \date 22.11.1999
1110!> \author Matthias Krack (MK)
1111!> \version 1.0
1112! **************************************************************************************************
1113 SUBROUTINE parser_get_real(parser, object, newline, skip_lines, string_length, &
1114 at_end)
1115
1116 TYPE(cp_parser_type), INTENT(INOUT) :: parser
1117 REAL(KIND=dp), INTENT(OUT) :: object
1118 LOGICAL, INTENT(IN), OPTIONAL :: newline
1119 INTEGER, INTENT(IN), OPTIONAL :: skip_lines, string_length
1120 LOGICAL, INTENT(out), OPTIONAL :: at_end
1121
1122 CHARACTER(LEN=max_line_length) :: error_message
1123 INTEGER :: nline
1124 LOGICAL :: my_at_end
1125
1126 cpassert(.NOT. parser%ilist%in_use)
1127
1128 IF (PRESENT(skip_lines)) THEN
1129 nline = skip_lines
1130 ELSE
1131 nline = 0
1132 END IF
1133
1134 IF (PRESENT(newline)) THEN
1135 IF (newline) nline = nline + 1
1136 END IF
1137
1138 CALL parser_get_next_line(parser, nline, at_end=my_at_end)
1139 IF (PRESENT(at_end)) THEN
1140 at_end = my_at_end
1141 IF (my_at_end) RETURN
1142 ELSE IF (my_at_end) THEN
1143 cpabort("Unexpected EOF"//trim(parser_location(parser)))
1144 END IF
1145
1146 IF (PRESENT(string_length)) THEN
1147 CALL parser_next_token(parser, string_length=string_length)
1148 ELSE
1149 CALL parser_next_token(parser)
1150 END IF
1151
1152 IF (parser%icol1 > parser%icol2) THEN
1153 parser%icol1 = parser%icol
1154 parser%icol2 = parser%icol
1155 CALL cp_abort(__location__, &
1156 "A floating point type object was expected, found end of the line"// &
1157 trim(parser_location(parser)))
1158 END IF
1159
1160 ! Possibility to have real numbers described in the input as division between two numbers
1161 CALL read_float_object(parser%input_line(parser%icol1:parser%icol2), object, error_message)
1162 IF (len_trim(error_message) > 0) THEN
1163 cpabort(trim(error_message)//trim(parser_location(parser)))
1164 END IF
1165
1166 END SUBROUTINE parser_get_real
1167
1168! **************************************************************************************************
1169!> \brief Read a string.
1170!> \param parser ...
1171!> \param object ...
1172!> \param lower_to_upper ...
1173!> \param newline ...
1174!> \param skip_lines ...
1175!> \param string_length ...
1176!> \param at_end ...
1177!> \date 22.11.1999
1178!> \author Matthias Krack (MK)
1179!> \version 1.0
1180! **************************************************************************************************
1181 SUBROUTINE parser_get_string(parser, object, lower_to_upper, newline, skip_lines, &
1182 string_length, at_end)
1183
1184 TYPE(cp_parser_type), INTENT(INOUT) :: parser
1185 CHARACTER(LEN=*), INTENT(OUT) :: object
1186 LOGICAL, INTENT(IN), OPTIONAL :: lower_to_upper, newline
1187 INTEGER, INTENT(IN), OPTIONAL :: skip_lines, string_length
1188 LOGICAL, INTENT(out), OPTIONAL :: at_end
1189
1190 INTEGER :: input_string_length, nline
1191 LOGICAL :: my_at_end
1192
1193 object = ""
1194 cpassert(.NOT. parser%ilist%in_use)
1195 IF (PRESENT(skip_lines)) THEN
1196 nline = skip_lines
1197 ELSE
1198 nline = 0
1199 END IF
1200
1201 IF (PRESENT(newline)) THEN
1202 IF (newline) nline = nline + 1
1203 END IF
1204
1205 CALL parser_get_next_line(parser, nline, at_end=my_at_end)
1206 IF (PRESENT(at_end)) THEN
1207 at_end = my_at_end
1208 IF (my_at_end) RETURN
1209 ELSE IF (my_at_end) THEN
1210 CALL cp_abort(__location__, &
1211 "Unexpected EOF"//trim(parser_location(parser)))
1212 END IF
1213
1214 IF (PRESENT(string_length)) THEN
1215 CALL parser_next_token(parser, string_length=string_length)
1216 ELSE
1217 CALL parser_next_token(parser)
1218 END IF
1219
1220 input_string_length = parser%icol2 - parser%icol1 + 1
1221
1222 IF (input_string_length <= 0) THEN
1223 CALL cp_abort(__location__, &
1224 "A string type object was expected, found end of line"// &
1225 trim(parser_location(parser)))
1226 ELSE IF (input_string_length > len(object)) THEN
1227 CALL cp_abort(__location__, &
1228 "The input string <"//parser%input_line(parser%icol1:parser%icol2)// &
1229 "> has more than "//cp_to_string(len(object))// &
1230 " characters and is therefore too long to fit in the "// &
1231 "specified variable"//trim(parser_location(parser)))
1232 object = parser%input_line(parser%icol1:parser%icol1 + len(object) - 1)
1233 ELSE
1234 object(:input_string_length) = parser%input_line(parser%icol1:parser%icol2)
1235 END IF
1236
1237 ! Convert lowercase to uppercase, if requested
1238 IF (PRESENT(lower_to_upper)) THEN
1239 IF (lower_to_upper) CALL uppercase(object)
1240 END IF
1241
1242 END SUBROUTINE parser_get_string
1243
1244! **************************************************************************************************
1245!> \brief Returns a floating point number read from a string including
1246!> fraction like z1/z2.
1247!> \param string ...
1248!> \param object ...
1249!> \param error_message ...
1250!> \date 11.01.2011 (MK)
1251!> \par History
1252!> - Add simple function parsing (17.05.2023, MK)
1253!> \author Matthias Krack
1254!> \version 2.0
1255!> \note - Parse also multiple products and fractions of floating point numbers (23.11.2012,MK)
1256! **************************************************************************************************
1257 ELEMENTAL SUBROUTINE read_float_object(string, object, error_message)
1258
1259 CHARACTER(LEN=*), INTENT(IN) :: string
1260 REAL(kind=dp), INTENT(OUT) :: object
1261 CHARACTER(LEN=*), INTENT(OUT) :: error_message
1262
1263 INTEGER, PARAMETER :: maxlen = 5
1264
1265 CHARACTER(LEN=maxlen) :: func
1266 INTEGER :: i, ileft, iop, iright, is, islash, &
1267 istar, istat, n
1268 LOGICAL :: parsing_done
1269 REAL(kind=dp) :: fsign, z
1270
1271 error_message = ""
1272 func = ""
1273
1274 i = 1
1275 iop = 0
1276 n = len_trim(string)
1277
1278 parsing_done = .false.
1279
1280 DO WHILE (.NOT. parsing_done)
1281 i = i + iop
1282 islash = index(string(i:n), "/")
1283 istar = index(string(i:n), "*")
1284 IF ((islash == 0) .AND. (istar == 0)) THEN
1285 ! Last factor found: read it and then exit the loop
1286 iop = n - i + 2
1287 parsing_done = .true.
1288 ELSE IF ((islash > 0) .AND. (istar > 0)) THEN
1289 iop = min(islash, istar)
1290 ELSE IF (islash > 0) THEN
1291 iop = islash
1292 ELSE IF (istar > 0) THEN
1293 iop = istar
1294 END IF
1295 ileft = index(string(i:min(n, i + maxlen + 1)), "(")
1296 IF (ileft > 0) THEN
1297 ! Check for sign
1298 is = ichar(string(i:i))
1299 SELECT CASE (is)
1300 CASE (43)
1301 fsign = 1.0_dp
1302 func = string(i + 1:i + ileft - 2)
1303 CASE (45)
1304 fsign = -1.0_dp
1305 func = string(i + 1:i + ileft - 2)
1306 CASE DEFAULT
1307 fsign = 1.0_dp
1308 func = string(i:i + ileft - 2)
1309 END SELECT
1310 iright = index(string(i:n), ")")
1311 READ (unit=string(i + ileft:i + iright - 2), fmt=*, iostat=istat) z
1312 IF (istat /= 0) THEN
1313 error_message = "A floating point type object as argument for function <"// &
1314 trim(func)//"> is expected, found <"// &
1315 string(i + ileft:i + iright - 2)//">"
1316 RETURN
1317 END IF
1318 SELECT CASE (func)
1319 CASE ("COS")
1320 z = fsign*cos(z*radians)
1321 CASE ("EXP")
1322 z = fsign*exp(z)
1323 CASE ("LOG")
1324 z = fsign*log(z)
1325 CASE ("LOG10")
1326 z = fsign*log10(z)
1327 CASE ("SIN")
1328 z = fsign*sin(z*radians)
1329 CASE ("SQRT")
1330 z = fsign*sqrt(z)
1331 CASE ("TAN")
1332 z = fsign*tan(z*radians)
1333 CASE DEFAULT
1334 error_message = "Unknown function <"//trim(func)//"> found"
1335 RETURN
1336 END SELECT
1337 ELSE
1338 READ (unit=string(i:i + iop - 2), fmt=*, iostat=istat) z
1339 IF (istat /= 0) THEN
1340 error_message = "A floating point type object was expected, found <"// &
1341 string(i:i + iop - 2)//">"
1342 RETURN
1343 END IF
1344 END IF
1345 IF (i == 1) THEN
1346 object = z
1347 ELSE IF (string(i - 1:i - 1) == "*") THEN
1348 object = object*z
1349 ELSE
1350 IF (z == 0.0_dp) THEN
1351 error_message = "Division by zero found <"// &
1352 string(i:i + iop - 2)//">"
1353 RETURN
1354 ELSE
1355 object = object/z
1356 END IF
1357 END IF
1358 END DO
1359
1360 END SUBROUTINE read_float_object
1361
1362! **************************************************************************************************
1363!> \brief Returns an integer number read from a string including products of
1364!> integer numbers like iz1*iz2*iz3
1365!> \param string ...
1366!> \param object ...
1367!> \param error_message ...
1368!> \date 23.11.2012 (MK)
1369!> \author Matthias Krack
1370!> \version 1.0
1371!> \note - Parse also (multiple) products of integer numbers (23.11.2012,MK)
1372! **************************************************************************************************
1373 ELEMENTAL SUBROUTINE read_integer_object(string, object, error_message)
1374
1375 CHARACTER(LEN=*), INTENT(IN) :: string
1376 INTEGER, INTENT(OUT) :: object
1377 CHARACTER(LEN=*), INTENT(OUT) :: error_message
1378
1379 CHARACTER(LEN=20) :: fmtstr
1380 INTEGER :: i, iop, istat, n
1381 INTEGER(KIND=int_8) :: iz8, object8
1382 LOGICAL :: parsing_done
1383
1384 error_message = ""
1385
1386 i = 1
1387 iop = 0
1388 n = len_trim(string)
1389
1390 parsing_done = .false.
1391
1392 DO WHILE (.NOT. parsing_done)
1393 i = i + iop
1394 ! note that INDEX always starts counting from 1 if found. Thus iop
1395 ! will give the length of the integer number plus 1
1396 iop = index(string(i:n), "*")
1397 IF (iop == 0) THEN
1398 ! Last factor found: read it and then exit the loop
1399 ! note that iop will always be the length of one integer plus 1
1400 ! and we still need to calculate it here as it is need for fmtstr
1401 ! below to determine integer format length
1402 iop = n - i + 2
1403 parsing_done = .true.
1404 END IF
1405 istat = 1
1406 IF (iop - 1 > 0) THEN
1407 ! need an explicit fmtstr here. With 'FMT=*' compilers from intel and pgi will also
1408 ! read float numbers as integers, without setting istat non-zero, i.e. string="0.3", istat=0, iz8=0
1409 ! this leads to wrong CP2K results (e.g. parsing force fields).
1410 WRITE (fmtstr, fmt='(A,I0,A)') '(I', iop - 1, ')'
1411 READ (unit=string(i:i + iop - 2), fmt=fmtstr, iostat=istat) iz8
1412 END IF
1413 IF (istat /= 0) THEN
1414 error_message = "An integer type object was expected, found <"// &
1415 string(i:i + iop - 2)//">"
1416 RETURN
1417 END IF
1418 IF (i == 1) THEN
1419 object8 = iz8
1420 ELSE
1421 object8 = object8*iz8
1422 END IF
1423 IF (abs(object8) > huge(0)) THEN
1424 error_message = "The specified integer number <"//string(i:i + iop - 2)// &
1425 "> exceeds the allowed range of a 32-bit integer number."
1426 RETURN
1427 END IF
1428 END DO
1429
1430 object = int(object8)
1431
1432 END SUBROUTINE read_integer_object
1433
1434END MODULE cp_parser_methods
various routines to log and control the output. The idea is that decisions about where to log should ...
a module to allow simple buffering of read lines of a parser
recursive subroutine, public copy_buffer_type(buffer_in, buffer_out, force)
Copies buffer types.
subroutine, public initialize_sub_buffer(sub_buffer, buffer)
Initializes sub buffer structure.
subroutine, public finalize_sub_buffer(sub_buffer, buffer)
Finalizes sub buffer structure.
a module to allow simple internal preprocessing in input files.
subroutine, public ilist_update(ilist)
updates the integer listing type
subroutine, public ilist_setup(ilist, token)
setup the integer listing type
subroutine, public ilist_reset(ilist)
updates the integer listing type
a module to allow simple internal preprocessing in input files.
subroutine, public inpp_expand_variables(inpp, input_line, input_file_name, input_line_number)
expand all ${VAR} or $VAR variable entries on the input string (LTR, no nested vars)
subroutine, public inpp_end_include(inpp, input_file_name, input_line_number, input_unit)
Restore older file status from stack after EOF on include file.
subroutine, public inpp_process_directive(inpp, input_line, input_file_name, input_line_number, input_unit)
process internal preprocessor directives like @INCLUDE, @SET, @IF/@ENDIF
Utility routines to read data from files. Kept as close as possible to the old parser because.
subroutine, public parser_read_line(parser, nline, at_end)
Read the next line from a logical unit "unit" (I/O node only). Skip (nline-1) lines and skip also all...
elemental subroutine, public read_integer_object(string, object, error_message)
Returns an integer number read from a string including products of integer numbers like iz1*iz2*iz3.
subroutine, public parser_skip_space(parser)
Skips the whitespaces.
subroutine, public parser_get_next_line(parser, nline, at_end)
Read the next input line and broadcast the input information. Skip (nline-1) lines and skip also all ...
character(len=3) function, public parser_test_next_token(parser, string_length)
Test next input object.
character(len=default_path_length+default_string_length) function, public parser_location(parser)
return a description of the part of the file actually parsed
elemental subroutine, public read_float_object(string, object, error_message)
Returns a floating point number read from a string including fraction like z1/z2.
subroutine, public parser_search_string(parser, string, ignore_case, found, line, begin_line, search_from_begin_of_file)
Search a string pattern in a file defined by its logical unit number "unit". A case sensitive search ...
Utility routines to read data from files. Kept as close as possible to the old parser because.
subroutine, public parser_reset(parser)
Resets the parser: rewinding the unit and re-initializing all parser structures.
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public max_line_length
Definition kinds.F:59
integer, parameter, public int_8
Definition kinds.F:54
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_string_length
Definition kinds.F:57
integer, parameter, public default_path_length
Definition kinds.F:58
Definition of mathematical constants and functions.
real(kind=dp), parameter, public radians
Interface to the message passing library MPI.
Utilities for string manipulations.
elemental logical function, public is_whitespace(testchar)
returns .true. if the character passed is a whitespace char.
elemental subroutine, public uppercase(string)
Convert all lower case characters in a string to upper case.
stores all the informations relevant to an mpi environment