LCOV - code coverage report
Current view: top level - src/input - cp_parser_inpp_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 79.9 % 274 219
Test Date: 2026-07-25 06:35:44 Functions: 83.3 % 6 5

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief a module to allow simple internal preprocessing in input files.
      10              : !> \par History
      11              : !>      - standalone proof-of-concept implementation (20.02.2008,AK)
      12              : !>      - integration into cp2k (22.02.2008,tlaino)
      13              : !>      - variables added (23.02.2008,AK)
      14              : !>      - @IF/@ENDIF added (25.02.2008,AK)
      15              : !>      - @PRINT and debug ifdefs added (26.02.2008,AK)
      16              : !> \author Axel Kohlmeyer [AK] - CMM/UPenn Philadelphia
      17              : !> \date 20.02.2008
      18              : ! **************************************************************************************************
      19              : MODULE cp_parser_inpp_methods
      20              :    USE cp_files, ONLY: close_file, &
      21              :                        open_file, file_exists
      22              :    USE cp_log_handling, ONLY: cp_logger_get_default_io_unit
      23              :    USE cp_parser_inpp_types, ONLY: inpp_type
      24              :    USE kinds, ONLY: default_path_length, &
      25              :                     default_string_length
      26              :    USE memory_utilities, ONLY: reallocate
      27              :    USE string_utilities, ONLY: is_whitespace, &
      28              :                                uppercase
      29              : #include "../base/base_uses.f90"
      30              : 
      31              :    IMPLICIT NONE
      32              : 
      33              :    PRIVATE
      34              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_parser_inpp_methods'
      35              :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .FALSE.
      36              :    INTEGER, PARAMETER, PRIVATE          :: max_message_length = 400
      37              : 
      38              :    PUBLIC  :: inpp_process_directive, inpp_end_include, inpp_expand_variables
      39              :    PRIVATE :: inpp_find_variable, inpp_list_variables
      40              : 
      41              : CONTAINS
      42              : 
      43              : ! **************************************************************************************************
      44              : !> \brief Validates whether the given string is a valid preprocessor variable name
      45              : !> \param str The input string (must be already trimmed if necessary)
      46              : !> \return .TRUE. if it is a valid variable name, .FALSE. otherwise
      47              : ! **************************************************************************************************
      48        11031 :    LOGICAL PURE FUNCTION is_valid_varname(str)
      49              :       CHARACTER(LEN=*), INTENT(IN) :: str
      50              :       CHARACTER(LEN=*), PARAMETER  :: alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
      51              :       CHARACTER(LEN=*), PARAMETER  :: alphanum = alpha//"0123456789"
      52              :       INTEGER                      :: idx
      53              : 
      54        11031 :       is_valid_varname = .FALSE.
      55              : 
      56        11031 :       IF (LEN(str) == 0) then
      57              :          RETURN
      58              :       end if
      59              : 
      60        11031 :       IF (INDEX(alpha, str(1:1)) == 0) then
      61              :          RETURN
      62              :       end if
      63              : 
      64       116478 :       DO idx = 2, LEN(str)
      65       116478 :          IF (INDEX(alphanum, str(idx:idx)) == 0) then
      66              :             RETURN
      67              :          end if
      68              :       END DO
      69              : 
      70        11031 :       is_valid_varname = .TRUE.
      71              :    END FUNCTION is_valid_varname
      72              : ! **************************************************************************************************
      73              : !> \brief process internal preprocessor directives like @INCLUDE, @SET, @IF/@ENDIF
      74              : !> \param inpp ...
      75              : !> \param input_line ...
      76              : !> \param input_file_name ...
      77              : !> \param input_line_number ...
      78              : !> \param input_unit ...
      79              : !> \par History
      80              : !>      - standalone proof-of-concept implementation (20.02.2008,AK)
      81              : !>      - integration into cp2k (22.02.2008,tlaino)
      82              : !>      - variables added (23.02.2008,AK)
      83              : !>      - @IF/@ENDIF added (25.02.2008,AK)
      84              : !> \author AK
      85              : ! **************************************************************************************************
      86         9976 :    SUBROUTINE inpp_process_directive(inpp, input_line, input_file_name, input_line_number, &
      87              :                                      input_unit)
      88              :       TYPE(inpp_type), POINTER                           :: inpp
      89              :       CHARACTER(LEN=*), INTENT(INOUT)                    :: input_line, input_file_name
      90              :       INTEGER, INTENT(INOUT)                             :: input_line_number, input_unit
      91              : 
      92              :       CHARACTER(LEN=default_path_length)                 :: cond1, cond2, filename, mytag, value, &
      93              :                                                             varname
      94              :       CHARACTER(LEN=max_message_length)                  :: message
      95              :       INTEGER                                            :: i, indf, indi, istat, output_unit, pos1, &
      96              :                                                             pos2, unit
      97              :       LOGICAL                                            :: check
      98              : 
      99        19952 :       output_unit = cp_logger_get_default_io_unit()
     100              : 
     101         9976 :       CPASSERT(ASSOCIATED(inpp))
     102              : 
     103              :       ! Find location of directive in line and check whether it is commented out
     104         9976 :       indi = INDEX(input_line, "@")
     105         9976 :       pos1 = INDEX(input_line, "!")
     106         9976 :       pos2 = INDEX(input_line, "#")
     107         9976 :       IF (((pos1 > 0) .AND. (pos1 < indi)) .OR. ((pos2 > 0) .AND. (pos2 < indi))) THEN
     108              :          ! Nothing to do
     109         2497 :          RETURN
     110              :       END IF
     111              : 
     112              :       ! Get the start of the instruction and find "@KEYWORD" (or "@")
     113              :       indf = indi
     114        60850 :       DO WHILE (.NOT. is_whitespace(input_line(indf:indf)))
     115        50874 :          indf = indf + 1
     116              :       END DO
     117         9976 :       mytag = input_line(indi:indf - 1)
     118         9976 :       CALL uppercase(mytag)
     119              : 
     120          513 :       SELECT CASE (mytag)
     121              : 
     122              :       CASE ("@INCLUDE")
     123              :          ! Get the file name, allow for " or ' or nothing
     124          513 :          filename = TRIM(input_line(indf:))
     125          513 :          IF (LEN_TRIM(filename) == 0) THEN
     126              :             WRITE (UNIT=message, FMT="(A,I0)") &
     127              :                "No filename argument found for "//TRIM(mytag)// &
     128              :                " directive in file <"//TRIM(input_file_name)// &
     129            0 :                ">  Line:", input_line_number
     130            0 :             CPABORT(TRIM(message))
     131              :          END IF
     132          513 :          indi = 1
     133         1027 :          DO WHILE (is_whitespace(filename(indi:indi)))
     134          514 :             indi = indi + 1
     135              :          END DO
     136          513 :          filename = TRIM(filename(indi:))
     137              : 
     138              :          ! Handle quoting of the filename
     139          513 :          pos1 = INDEX(filename, '"')
     140          513 :          pos2 = INDEX(filename(pos1 + 1:), '"')
     141          513 :          IF ((pos1 /= 0) .AND. (pos2 /= 0)) THEN
     142            8 :             filename = filename(pos1 + 1:pos1 + pos2 - 1)
     143              :          ELSE
     144          505 :             pos1 = INDEX(filename, "'")
     145          505 :             pos2 = INDEX(filename(pos1 + 1:), "'")
     146          505 :             IF ((pos1 /= 0) .AND. (pos2 /= 0)) THEN
     147           40 :                filename = filename(pos1 + 1:pos1 + pos2 - 1)
     148              :             ELSE
     149              :                ! Check quoting of the included file name
     150          465 :                pos2 = INDEX(filename, '"')
     151          465 :                IF ((pos1 /= 0) .OR. (pos2 /= 0)) THEN
     152              :                   WRITE (UNIT=message, FMT="(A,I0)") &
     153            0 :                      "Incorrect quoting of the included filename in file <", &
     154            0 :                      TRIM(input_file_name)//">  Line:", input_line_number
     155            0 :                   CPABORT(TRIM(message))
     156              :                END IF
     157              :             END IF
     158              :          END IF
     159              : 
     160              :          ! Let's check that files already opened won't be again opened
     161          656 :          DO i = 1, inpp%io_stack_level
     162          143 :             check = TRIM(filename) /= TRIM(inpp%io_stack_filename(i))
     163          656 :             CPASSERT(check)
     164              :          END DO
     165              : 
     166              :          CALL open_file(file_name=TRIM(filename), &
     167              :                         file_status="OLD", &
     168              :                         file_form="FORMATTED", &
     169              :                         file_action="READ", &
     170          513 :                         unit_number=unit)
     171              : 
     172              :          ! Make room, save status and position the parser at the beginning of new file.
     173          513 :          inpp%io_stack_level = inpp%io_stack_level + 1
     174          513 :          CALL reallocate(inpp%io_stack_channel, 1, inpp%io_stack_level)
     175          513 :          CALL reallocate(inpp%io_stack_lineno, 1, inpp%io_stack_level)
     176          513 :          CALL reallocate(inpp%io_stack_filename, 1, inpp%io_stack_level)
     177              : 
     178          513 :          inpp%io_stack_channel(inpp%io_stack_level) = input_unit
     179          513 :          inpp%io_stack_lineno(inpp%io_stack_level) = input_line_number
     180          513 :          inpp%io_stack_filename(inpp%io_stack_level) = input_file_name
     181              : 
     182          513 :          input_file_name = TRIM(filename)
     183          513 :          input_line_number = 0
     184          513 :          input_unit = unit
     185              : 
     186              :       CASE ("@FFTYPE", "@XCTYPE")
     187              :          ! Include a &XC section from the data/xc_section directory or include
     188              :          ! a &FORCEFIELD section from the data/forcefield_section directory
     189              :          ! Get the filename, allow for " or ' or nothing
     190           24 :          filename = TRIM(input_line(indf:))
     191           24 :          IF (LEN_TRIM(filename) == 0) THEN
     192              :             WRITE (UNIT=message, FMT="(A,I0)") &
     193              :                "No filename argument found for "//TRIM(mytag)// &
     194              :                " directive in file <"//TRIM(input_file_name)// &
     195            0 :                ">  Line:", input_line_number
     196            0 :             CPABORT(TRIM(message))
     197              :          END IF
     198           24 :          indi = 1
     199           48 :          DO WHILE (is_whitespace(filename(indi:indi)))
     200           24 :             indi = indi + 1
     201              :          END DO
     202           24 :          filename = TRIM(filename(indi:))
     203              : 
     204              :          ! Handle quoting of the filename
     205           24 :          pos1 = INDEX(filename, '"')
     206           24 :          pos2 = INDEX(filename(pos1 + 1:), '"')
     207           24 :          IF ((pos1 /= 0) .AND. (pos2 /= 0)) THEN
     208            0 :             filename = filename(pos1 + 1:pos1 + pos2 - 1)
     209              :          ELSE
     210           24 :             pos1 = INDEX(filename, "'")
     211           24 :             pos2 = INDEX(filename(pos1 + 1:), "'")
     212           24 :             IF ((pos1 /= 0) .AND. (pos2 /= 0)) THEN
     213            0 :                filename = filename(pos1 + 1:pos1 + pos2 - 1)
     214              :             ELSE
     215              :                ! Incorrect quotes (only one of ' or ").
     216           24 :                pos2 = INDEX(filename, '"')
     217           24 :                IF ((pos1 /= 0) .OR. (pos2 /= 0)) THEN
     218              :                   WRITE (UNIT=message, FMT="(A,I0)") &
     219            0 :                      "Incorrect quoting of the filename argument in file <", &
     220            0 :                      TRIM(input_file_name)//">  Line:", input_line_number
     221            0 :                   CPABORT(TRIM(message))
     222              :                END IF
     223              :             END IF
     224              :          END IF
     225              : 
     226              :          ! Add file extension ".sec"
     227           24 :          filename = TRIM(filename)//".sec"
     228              :          ! Check for file
     229           24 :          IF (.NOT. file_exists(TRIM(filename))) THEN
     230           24 :             IF (filename(1:1) == "/") THEN
     231              :                ! this is an absolute path filename, don't change
     232              :             ELSE
     233            5 :                SELECT CASE (mytag)
     234              :                CASE ("@FFTYPE")
     235            5 :                   filename = "forcefield_section/"//TRIM(filename)
     236              :                CASE ("@XCTYPE")
     237           24 :                   filename = "xc_section/"//TRIM(filename)
     238              :                END SELECT
     239              :             END IF
     240              :          END IF
     241           24 :          IF (.NOT. file_exists(TRIM(filename))) THEN
     242              :             WRITE (UNIT=message, FMT="(A,I0)") &
     243              :                TRIM(mytag)//": Could not find the file <"// &
     244              :                TRIM(filename)//"> with the input section given in the file <"// &
     245            0 :                TRIM(input_file_name)//">  Line: ", input_line_number
     246            0 :             CPABORT(TRIM(message))
     247              :          END IF
     248              : 
     249              :          ! Let's check that files already opened won't be again opened
     250           24 :          DO i = 1, inpp%io_stack_level
     251            0 :             check = TRIM(filename) /= TRIM(inpp%io_stack_filename(i))
     252           24 :             CPASSERT(check)
     253              :          END DO
     254              : 
     255              :          ! This stops on error so we can always assume success
     256              :          CALL open_file(file_name=TRIM(filename), &
     257              :                         file_status="OLD", &
     258              :                         file_form="FORMATTED", &
     259              :                         file_action="READ", &
     260           24 :                         unit_number=unit)
     261              : 
     262              :          ! make room, save status and position the parser at the beginning of new file.
     263           24 :          inpp%io_stack_level = inpp%io_stack_level + 1
     264           24 :          CALL reallocate(inpp%io_stack_channel, 1, inpp%io_stack_level)
     265           24 :          CALL reallocate(inpp%io_stack_lineno, 1, inpp%io_stack_level)
     266           24 :          CALL reallocate(inpp%io_stack_filename, 1, inpp%io_stack_level)
     267              : 
     268           24 :          inpp%io_stack_channel(inpp%io_stack_level) = input_unit
     269           24 :          inpp%io_stack_lineno(inpp%io_stack_level) = input_line_number
     270           24 :          inpp%io_stack_filename(inpp%io_stack_level) = input_file_name
     271              : 
     272           24 :          input_file_name = TRIM(filename)
     273           24 :          input_line_number = 0
     274           24 :          input_unit = unit
     275              : 
     276              :       CASE ("@SET")
     277              :          ! Split directive into variable name and value data.
     278         4184 :          varname = TRIM(input_line(indf:))
     279         4184 :          IF (LEN_TRIM(varname) == 0) THEN
     280              :             WRITE (UNIT=message, FMT="(A,I0)") &
     281              :                "No variable name found for "//TRIM(mytag)//" directive in file <"// &
     282            0 :                TRIM(input_file_name)//">  Line:", input_line_number
     283            0 :             CPABORT(TRIM(message))
     284              :          END IF
     285              : 
     286         4184 :          indi = 1
     287         8373 :          DO WHILE (is_whitespace(varname(indi:indi)))
     288         4189 :             indi = indi + 1
     289              :          END DO
     290              :          indf = indi
     291        51200 :          DO WHILE (.NOT. is_whitespace(varname(indf:indf)))
     292        47016 :             indf = indf + 1
     293              :          END DO
     294         4184 :          value = TRIM(varname(indf:))
     295         4184 :          varname = TRIM(varname(indi:indf - 1))
     296              : 
     297         4184 :          IF (.NOT. is_valid_varname(TRIM(varname))) THEN
     298              :             WRITE (UNIT=message, FMT="(A,I0)") &
     299              :                "Invalid variable name for "//TRIM(mytag)//" directive in file <"// &
     300            0 :                TRIM(input_file_name)//">  Line:", input_line_number
     301            0 :             CPABORT(TRIM(message))
     302              :          END IF
     303              : 
     304         4184 :          indi = 1
     305        30747 :          DO WHILE (is_whitespace(value(indi:indi)))
     306        26563 :             indi = indi + 1
     307              :          END DO
     308         4184 :          value = TRIM(value(indi:))
     309              : 
     310         4184 :          IF (LEN_TRIM(value) == 0) THEN
     311              :             WRITE (UNIT=message, FMT="(A,I0)") &
     312              :                "Incomplete "//TRIM(mytag)//" directive: "// &
     313              :                "No value found for variable <"//TRIM(varname)//"> in file <"// &
     314            0 :                TRIM(input_file_name)//">  Line:", input_line_number
     315            0 :             CPABORT(TRIM(message))
     316              :          END IF
     317              : 
     318              :          ! sort into table of variables.
     319         4184 :          indi = inpp_find_variable(inpp, varname)
     320         4184 :          IF (indi == 0) THEN
     321              :             ! create new variable
     322         3931 :             inpp%num_variables = inpp%num_variables + 1
     323         3931 :             CALL reallocate(inpp%variable_name, 1, inpp%num_variables)
     324         3931 :             CALL reallocate(inpp%variable_value, 1, inpp%num_variables)
     325         3931 :             inpp%variable_name(inpp%num_variables) = varname
     326         3931 :             inpp%variable_value(inpp%num_variables) = value
     327              :             IF (debug_this_module .AND. output_unit > 0) THEN
     328              :                WRITE (UNIT=message, FMT="(3A,I6,4A)") "INPP_@SET: in file: ", &
     329              :                   TRIM(input_file_name), "  Line:", input_line_number, &
     330              :                   " Set new variable ", TRIM(varname), " to value: ", TRIM(value)
     331              :                WRITE (output_unit, *) TRIM(message)
     332              :             END IF
     333              :          ELSE
     334              :             ! reassign variable
     335              :             IF (debug_this_module .AND. output_unit > 0) THEN
     336              :                WRITE (UNIT=message, FMT="(3A,I6,6A)") "INPP_@SET: in file: ", &
     337              :                   TRIM(input_file_name), "  Line:", input_line_number, &
     338              :                   " Change variable ", TRIM(varname), " from value: ", &
     339              :                   TRIM(inpp%variable_value(indi)), " to value: ", TRIM(value)
     340              :                WRITE (output_unit, *) TRIM(message)
     341              :             END IF
     342          253 :             inpp%variable_value(indi) = value
     343              :          END IF
     344              : 
     345         2497 :          IF (debug_this_module) CALL inpp_list_variables(inpp, 6)
     346              : 
     347              :       CASE ("@IF")
     348              :          ! detect IF expression.
     349              :          ! we recognize lexical equality or inequality, and presence of
     350              :          ! a string (true) vs. blank (false). in case the expression resolves
     351              :          ! to "false" we read lines here until we reach an @ENDIF or EOF.
     352         2497 :          indi = indf
     353         2497 :          pos1 = INDEX(input_line, "==")
     354         2497 :          pos2 = INDEX(input_line, "/=")
     355              :          ! shave off leading whitespace
     356         4993 :          DO WHILE (is_whitespace(input_line(indi:indi)))
     357         2497 :             indi = indi + 1
     358         4993 :             IF (indi > LEN_TRIM(input_line)) EXIT
     359              :          END DO
     360         2497 :          check = .FALSE.
     361         2497 :          IF (pos1 > 0) THEN
     362         2368 :             cond1 = input_line(indi:pos1 - 1)
     363         2368 :             cond2 = input_line(pos1 + 2:)
     364         2368 :             check = .TRUE.
     365         2368 :             IF ((pos2 > 0) .OR. (INDEX(cond2, "==") > 0)) THEN
     366              :                WRITE (UNIT=message, FMT="(A,I0)") &
     367            0 :                   "Incorrect "//TRIM(mytag)//" directive found in file <", &
     368            0 :                   TRIM(input_file_name)//">  Line:", input_line_number
     369            0 :                CPABORT(TRIM(message))
     370              :             END IF
     371          129 :          ELSE IF (pos2 > 0) THEN
     372            2 :             cond1 = input_line(indi:pos2 - 1)
     373            2 :             cond2 = input_line(pos2 + 2:)
     374            2 :             check = .FALSE.
     375            2 :             IF ((pos1 > 0) .OR. (INDEX(cond2, "/=") > 0)) THEN
     376              :                WRITE (UNIT=message, FMT="(A,I0)") &
     377            0 :                   "Incorrect "//TRIM(mytag)//" directive found in file <", &
     378            0 :                   TRIM(input_file_name)//">  Line:", input_line_number
     379            0 :                CPABORT(TRIM(message))
     380              :             END IF
     381              :          ELSE
     382          127 :             IF (LEN_TRIM(input_line(indi:)) > 0) THEN
     383          126 :                IF (TRIM(input_line(indi:)) == '0') THEN
     384           62 :                   cond1 = 'XXX'
     385           62 :                   cond2 = 'XXX'
     386           62 :                   check = .FALSE.
     387              :                ELSE
     388           64 :                   cond1 = 'XXX'
     389           64 :                   cond2 = 'XXX'
     390           64 :                   check = .TRUE.
     391              :                END IF
     392              :             ELSE
     393            1 :                cond1 = 'XXX'
     394            1 :                cond2 = 'XXX'
     395            1 :                check = .FALSE.
     396              :             END IF
     397              :          END IF
     398              : 
     399              :          ! Get rid of possible parentheses
     400         2497 :          IF (INDEX(cond1, "(") /= 0) cond1 = cond1(INDEX(cond1, "(") + 1:)
     401         2497 :          IF (INDEX(cond2, ")") /= 0) cond2 = cond2(1:INDEX(cond2, ")") - 1)
     402              : 
     403              :          ! Shave off leading whitespace from cond1
     404         2497 :          indi = 1
     405         4782 :          DO WHILE (is_whitespace(cond1(indi:indi)))
     406         2285 :             indi = indi + 1
     407              :          END DO
     408         2497 :          cond1 = cond1(indi:)
     409              : 
     410              :          ! Shave off leading whitespace from cond2
     411         2497 :          indi = 1
     412         4865 :          DO WHILE (is_whitespace(cond2(indi:indi)))
     413         2368 :             indi = indi + 1
     414              :          END DO
     415         2497 :          cond2 = cond2(indi:)
     416              : 
     417         2497 :          IF (LEN_TRIM(cond2) == 0) THEN
     418              :             WRITE (UNIT=message, FMT="(3A,I6)") &
     419            0 :                "INPP_@IF: Incorrect @IF directive in file: ", &
     420            0 :                TRIM(input_file_name), "  Line:", input_line_number
     421            0 :             CPABORT(TRIM(message))
     422              :          END IF
     423              : 
     424         2497 :          IF ((TRIM(cond1) == TRIM(cond2)) .EQV. check) THEN
     425              :             IF (debug_this_module .AND. output_unit > 0) THEN
     426              :                WRITE (UNIT=message, FMT="(3A,I6,A)") "INPP_@IF: in file: ", &
     427              :                   TRIM(input_file_name), "  Line:", input_line_number, &
     428              :                   " Conditional ("//TRIM(cond1)//","//TRIM(cond2)// &
     429              :                   ") resolves to true. Continuing parsing."
     430              :                WRITE (output_unit, *) TRIM(message)
     431              :             END IF
     432              :             ! resolves to true. keep on reading normally...
     433              :             RETURN
     434              :          ELSE
     435              :             IF (debug_this_module .AND. output_unit > 0) THEN
     436              :                WRITE (UNIT=message, FMT="(3A,I6,A)") "INPP_@IF: in file: ", &
     437              :                   TRIM(input_file_name), "  Line:", input_line_number, &
     438              :                   " Conditional ("//TRIM(cond1)//","//TRIM(cond2)// &
     439              :                   ") resolves to false. Skipping Lines."
     440              :                WRITE (output_unit, *) TRIM(message)
     441              :             END IF
     442         1199 :             istat = 0
     443         5545 :             DO WHILE (istat == 0)
     444         5545 :                input_line_number = input_line_number + 1
     445         5545 :                READ (UNIT=input_unit, FMT="(A)", IOSTAT=istat) input_line
     446              :                IF (debug_this_module .AND. output_unit > 0) THEN
     447              :                   WRITE (UNIT=message, FMT="(1A,I6,2A)") "INPP_@IF: skipping line ", &
     448              :                      input_line_number, ": ", TRIM(input_line)
     449              :                   WRITE (output_unit, *) TRIM(message)
     450              :                END IF
     451              : 
     452         5545 :                indi = INDEX(input_line, "@")
     453         5545 :                pos1 = INDEX(input_line, "!")
     454         5545 :                pos2 = INDEX(input_line, "#")
     455         5545 :                IF (((pos1 > 0) .AND. (pos1 < indi)) .OR. ((pos2 > 0) .AND. (pos2 < indi))) THEN
     456              :                   ! Nothing to do
     457              :                   CYCLE
     458              :                END IF
     459              : 
     460              :                ! Get the start of the instruction and find "@KEYWORD"
     461         5545 :                indi = MAX(1, indi)
     462         5545 :                indf = indi
     463        12911 :                DO WHILE (input_line(indf:indf) /= " ")
     464         7366 :                   indf = indf + 1
     465              :                END DO
     466         5545 :                CPASSERT((indf - indi) <= default_string_length)
     467         5545 :                mytag = input_line(indi:indf - 1)
     468         5545 :                CALL uppercase(mytag)
     469         5545 :                IF (INDEX(mytag, "@ENDIF") > 0) THEN
     470              :                   ! ok found it. go back to normal
     471              :                   IF (debug_this_module .AND. output_unit > 0) THEN
     472              :                      WRITE (output_unit, *) "INPP_@IF: found @ENDIF. End of skipping."
     473              :                   END IF
     474              :                   RETURN
     475              :                END IF
     476              :             END DO
     477              :             IF (istat /= 0) THEN
     478              :                WRITE (UNIT=message, FMT="(A,I0)") &
     479              :                   "Error while searching for matching @ENDIF directive in file <"// &
     480            0 :                   TRIM(input_file_name)//">  Line:", input_line_number
     481            0 :                CPABORT(TRIM(message))
     482              :             END IF
     483              :          END IF
     484              : 
     485              :       CASE ("@ENDIF")
     486              :          ! In normal mode, just skip line and continue
     487            1 :          IF (debug_this_module .AND. output_unit > 0) THEN
     488              :             WRITE (UNIT=message, FMT="(A,I0)") &
     489              :                TRIM(mytag)//" directive found and ignored in file <"// &
     490              :                TRIM(input_file_name)//">  Line: ", input_line_number
     491              :          END IF
     492              : 
     493              :       CASE ("@PRINT")
     494              :          ! For debugging of variables etc.
     495         9976 :          IF (output_unit > 0) THEN
     496              :             WRITE (UNIT=output_unit, FMT="(T2,A,I0,A)") &
     497              :                TRIM(mytag)//" directive in file <"// &
     498            1 :                TRIM(input_file_name)//">  Line: ", input_line_number, &
     499            2 :                " ->"//TRIM(input_line(indf:))
     500              :          END IF
     501              : 
     502              :       END SELECT
     503              : 
     504         9976 :    END SUBROUTINE inpp_process_directive
     505              : 
     506              : ! **************************************************************************************************
     507              : !> \brief Restore older file status from stack after EOF on include file.
     508              : !> \param inpp ...
     509              : !> \param input_file_name ...
     510              : !> \param input_line_number ...
     511              : !> \param input_unit ...
     512              : !> \par History
     513              : !>      - standalone proof-of-concept implementation (20.02.2008,AK)
     514              : !>      - integrated into cp2k (21.02.2008)
     515              : !> \author AK
     516              : ! **************************************************************************************************
     517          537 :    SUBROUTINE inpp_end_include(inpp, input_file_name, input_line_number, input_unit)
     518              :       TYPE(inpp_type), POINTER                           :: inpp
     519              :       CHARACTER(LEN=*), INTENT(INOUT)                    :: input_file_name
     520              :       INTEGER, INTENT(INOUT)                             :: input_line_number, input_unit
     521              : 
     522            0 :       CPASSERT(ASSOCIATED(inpp))
     523          537 :       IF (inpp%io_stack_level > 0) THEN
     524          537 :          CALL close_file(input_unit)
     525          537 :          input_unit = inpp%io_stack_channel(inpp%io_stack_level)
     526          537 :          input_line_number = inpp%io_stack_lineno(inpp%io_stack_level)
     527          537 :          input_file_name = TRIM(inpp%io_stack_filename(inpp%io_stack_level))
     528          537 :          inpp%io_stack_level = inpp%io_stack_level - 1
     529          537 :          CALL reallocate(inpp%io_stack_channel, 1, inpp%io_stack_level)
     530          537 :          CALL reallocate(inpp%io_stack_lineno, 1, inpp%io_stack_level)
     531          537 :          CALL reallocate(inpp%io_stack_filename, 1, inpp%io_stack_level)
     532              :       END IF
     533              : 
     534          537 :    END SUBROUTINE inpp_end_include
     535              : 
     536              : ! **************************************************************************************************
     537              : !> \brief expand all ${VAR} or $VAR variable entries on the input string (LTR, no nested vars)
     538              : !> \param inpp ...
     539              : !> \param input_line ...
     540              : !> \param input_file_name ...
     541              : !> \param input_line_number ...
     542              : !> \par History
     543              : !>      - standalone proof-of-concept implementation (22.02.2008,AK)
     544              : !>      - integrated into cp2k (23.02.2008)
     545              : !> \author AK
     546              : ! **************************************************************************************************
     547         5882 :    SUBROUTINE inpp_expand_variables(inpp, input_line, input_file_name, input_line_number)
     548              :       TYPE(inpp_type), POINTER                           :: inpp
     549              :       CHARACTER(LEN=*), INTENT(INOUT)                    :: input_line, input_file_name
     550              :       INTEGER, INTENT(IN)                                :: input_line_number
     551              : 
     552              :       CHARACTER(LEN=default_path_length)                 :: newline
     553              :       CHARACTER(LEN=max_message_length)                  :: message
     554         5882 :       CHARACTER(LEN=:), ALLOCATABLE                      :: var_value, var_name
     555              :       INTEGER                                            :: idx, pos1, pos2, default_val_sep_idx
     556              : 
     557            0 :       CPASSERT(ASSOCIATED(inpp))
     558              : 
     559              :       ! process line until all variables named with the convention ${VAR} are expanded
     560        12521 :       DO WHILE (INDEX(input_line, '${') > 0)
     561         6639 :          pos1 = INDEX(input_line, '${')
     562         6639 :          pos1 = pos1 + 2
     563         6639 :          pos2 = INDEX(input_line(pos1:), '}')
     564              : 
     565         6639 :          IF (pos2 == 0) THEN
     566              :             WRITE (UNIT=message, FMT="(3A,I6)") &
     567            0 :                "Missing '}' in file: ", &
     568            0 :                TRIM(input_file_name), "  Line:", input_line_number
     569            0 :             CPABORT(TRIM(message))
     570              :          END IF
     571              : 
     572         6639 :          pos2 = pos1 + pos2 - 2
     573         6639 :          var_name = input_line(pos1:pos2)
     574              : 
     575         6639 :          default_val_sep_idx = INDEX(var_name, '-')
     576              : 
     577         6639 :          IF (default_val_sep_idx > 0) THEN
     578            8 :             var_value = var_name(default_val_sep_idx + 1:)
     579            8 :             var_name = var_name(:default_val_sep_idx - 1)
     580              :          END IF
     581              : 
     582         6639 :          IF (.NOT. is_valid_varname(var_name)) THEN
     583              :             WRITE (UNIT=message, FMT="(5A,I6)") &
     584            0 :                "Invalid variable name ${", var_name, "} in file: ", &
     585            0 :                TRIM(input_file_name), "  Line:", input_line_number
     586            0 :             CPABORT(TRIM(message))
     587              :          END IF
     588              : 
     589         6639 :          idx = inpp_find_variable(inpp, var_name)
     590              : 
     591         6639 :          IF (idx == 0 .AND. default_val_sep_idx == 0) THEN
     592              :             WRITE (UNIT=message, FMT="(5A,I6)") &
     593            0 :                "Variable ${", var_name, "} not defined in file: ", &
     594            0 :                TRIM(input_file_name), "  Line:", input_line_number
     595            0 :             CPABORT(TRIM(message))
     596              :          END IF
     597              : 
     598         6639 :          IF (idx > 0) then
     599         6639 :             var_value = TRIM(inpp%variable_value(idx))
     600              :          end if
     601              : 
     602         6639 :          newline = input_line(1:pos1 - 3)//var_value//input_line(pos2 + 2:)
     603        12521 :          input_line = newline
     604              :       END DO
     605              : 
     606              :       ! process line until all variables named with the convention $VAR are expanded
     607         6090 :       DO WHILE (INDEX(input_line, '$') > 0)
     608          208 :          pos1 = INDEX(input_line, '$')
     609          208 :          pos1 = pos1 + 1 ! move to the start of the variable name
     610          208 :          pos2 = INDEX(input_line(pos1:), ' ')
     611              : 
     612          208 :          IF (pos2 == 0) then
     613            0 :             pos2 = LEN_TRIM(input_line(pos1:)) + 1
     614              :          end if
     615              : 
     616          208 :          pos2 = pos1 + pos2 - 2 ! end of the variable name, minus the separating whitespace
     617          208 :          var_name = input_line(pos1:pos2)
     618          208 :          idx = inpp_find_variable(inpp, var_name)
     619              : 
     620          208 :          IF (.NOT. is_valid_varname(var_name)) THEN
     621              :             WRITE (UNIT=message, FMT="(5A,I6)") &
     622            0 :                "Invalid variable name ${", var_name, "} in file: ", &
     623            0 :                TRIM(input_file_name), "  Line:", input_line_number
     624            0 :             CPABORT(TRIM(message))
     625              :          END IF
     626              : 
     627          208 :          IF (idx == 0) THEN
     628              :             WRITE (UNIT=message, FMT="(5A,I6)") &
     629            0 :                "Variable $", var_name, " not defined in file: ", &
     630            0 :                TRIM(input_file_name), "  Line:", input_line_number
     631            0 :             CPABORT(TRIM(message))
     632              :          END IF
     633              : 
     634          208 :          newline = input_line(1:pos1 - 2)//TRIM(inpp%variable_value(idx))//input_line(pos2 + 1:)
     635         6090 :          input_line = newline
     636              :       END DO
     637              : 
     638        11764 :    END SUBROUTINE inpp_expand_variables
     639              : 
     640              : ! **************************************************************************************************
     641              : !> \brief return index position of a variable in dictionary. 0 if not found.
     642              : !> \param inpp ...
     643              : !> \param varname ...
     644              : !> \return ...
     645              : !> \par History
     646              : !>      - standalone proof-of-concept implementation (22.02.2008,AK)
     647              : !>      - integrated into cp2k (23.02.2008)
     648              : !> \author AK
     649              : ! **************************************************************************************************
     650        11031 :    FUNCTION inpp_find_variable(inpp, varname) RESULT(idx)
     651              :       TYPE(inpp_type), POINTER                           :: inpp
     652              :       CHARACTER(len=*), INTENT(IN)                       :: varname
     653              :       INTEGER                                            :: idx
     654              : 
     655              :       INTEGER                                            :: i
     656              : 
     657        11031 :       idx = 0
     658       130941 :       DO i = 1, inpp%num_variables
     659       130941 :          IF (TRIM(varname) == TRIM(inpp%variable_name(i))) THEN
     660        11031 :             idx = i
     661              :             RETURN
     662              :          END IF
     663              :       END DO
     664              :       RETURN
     665              :    END FUNCTION inpp_find_variable
     666              : 
     667              : ! **************************************************************************************************
     668              : !> \brief print a list of the variable/value table
     669              : !> \param inpp ...
     670              : !> \param iochan ...
     671              : !> \par History
     672              : !>      - standalone proof-of-concept implementation (22.02.2008,AK)
     673              : !>      - integrated into cp2k (23.02.2008)
     674              : !> \author AK
     675              : ! **************************************************************************************************
     676            0 :    SUBROUTINE inpp_list_variables(inpp, iochan)
     677              :       TYPE(inpp_type), POINTER                           :: inpp
     678              :       INTEGER, INTENT(IN)                                :: iochan
     679              : 
     680              :       INTEGER                                            :: i
     681              : 
     682            0 :       WRITE (iochan, '(A)') '   #   NAME                   VALUE'
     683            0 :       DO i = 1, inpp%num_variables
     684              :          WRITE (iochan, '(I4," | ",A,T30," | ",A," |")') &
     685            0 :             i, TRIM(inpp%variable_name(i)), TRIM(inpp%variable_value(i))
     686              :       END DO
     687            0 :    END SUBROUTINE inpp_list_variables
     688              : 
     689            8 : END MODULE cp_parser_inpp_methods
        

Generated by: LCOV version 2.0-1