LCOV - code coverage report
Current view: top level - src/common - cp_files.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 76.7 % 210 161
Test Date: 2026-10-15 00:55:44 Functions: 87.5 % 8 7

            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 Utility routines to open and close files.
      10              : !> \par History
      11              : !>      - Creation CP2K_WORKSHOP 1.0 TEAM
      12              : !>      - Revised (18.02.2011, MK)
      13              : !>      - Enhanced error checking (22.02.2011, MK)
      14              : !>      - Preconnected units removed (03.10.2026, MK)
      15              : !> \note Positive unit numbers are used instead of OPEN(NEWUNIT=...), because NEWUNIT returns
      16              : !>       negative numbers and CP2K treats a unit number > 0 as "output enabled".
      17              : !>       open_file is thread-safe: finding a free unit and connecting the file are done within
      18              : !>       the OpenMP critical region cp_files_connect. Concurrent use of the same unit (I/O,
      19              : !>       REWIND, close_file) must be avoided by the caller.
      20              : !> \author Matthias Krack (MK)
      21              : ! **************************************************************************************************
      22              : MODULE cp_files
      23              :    USE ISO_C_BINDING,                   ONLY: C_CHAR,&
      24              :                                               C_F_POINTER,&
      25              :                                               C_NULL_CHAR,&
      26              :                                               C_PTR
      27              :    USE kinds,                           ONLY: default_path_length
      28              :    USE machine,                         ONLY: default_error_unit,&
      29              :                                               default_input_unit,&
      30              :                                               default_output_unit,&
      31              :                                               m_getcwd
      32              :    USE string_utilities,                ONLY: uppercase
      33              : #include "../base/base_uses.f90"
      34              : 
      35              :    IMPLICIT NONE
      36              : 
      37              :    PRIVATE
      38              : 
      39              :    PUBLIC :: close_file, &
      40              :              open_file, &
      41              :              file_exists, &
      42              :              get_data_dir, &
      43              :              discover_file, &
      44              :              join_paths
      45              : 
      46              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_files'
      47              : 
      48              :    ! Upper bound for the search of a free logical unit number
      49              :    INTEGER, PARAMETER :: max_unit_number = 1024
      50              : 
      51              : CONTAINS
      52              : 
      53              : ! **************************************************************************************************
      54              : !> \brief Closes an open file given by its logical unit number.
      55              : !> \param unit_number Logical unit number of the file to be closed
      56              : !> \param file_status File status after closing: KEEP or DELETE (default: KEEP for named,
      57              : !>                    DELETE for unnamed SCRATCH files)
      58              : !> \author Matthias Krack (MK)
      59              : !> \note  The program is aborted, if the unit is one of the default units (stdin, stdout,
      60              : !>        stderr). A unit which is not open is ignored silently.
      61              : ! **************************************************************************************************
      62       139465 :    SUBROUTINE close_file(unit_number, file_status)
      63              : 
      64              :       INTEGER, INTENT(IN)                                :: unit_number
      65              :       CHARACTER(LEN=*), INTENT(IN), OPTIONAL             :: file_status
      66              : 
      67              :       CHARACTER(LEN=11)                                  :: status_string
      68              :       CHARACTER(LEN=2*default_path_length)               :: message
      69              :       CHARACTER(LEN=default_path_length)                 :: iomsg_string
      70              :       INTEGER                                            :: istat
      71              :       LOGICAL                                            :: exists, is_named, is_open
      72              : 
      73       139465 :       INQUIRE (UNIT=unit_number, EXIST=exists, NAMED=is_named, OPENED=is_open, IOSTAT=istat)
      74              : 
      75       139465 :       IF (istat /= 0) THEN
      76              :          WRITE (UNIT=message, FMT="(A,I0,A,I0,A)") &
      77            0 :             "An error occurred inquiring the unit with the number ", unit_number, &
      78            0 :             " (IOSTAT = ", istat, ")"
      79            0 :          CALL cp_abort(__LOCATION__, TRIM(message))
      80       139465 :       ELSE IF (.NOT. exists) THEN
      81              :          WRITE (UNIT=message, FMT="(A,I0,A)") &
      82            0 :             "The specified unit number ", unit_number, &
      83            0 :             " cannot be closed, because it does not exist."
      84            0 :          CALL cp_abort(__LOCATION__, TRIM(message))
      85              :       END IF
      86              : 
      87              :       ! Close the specified file
      88              : 
      89       139465 :       IF (is_open) THEN
      90              : 
      91              :          ! Refuse to close any default unit
      92            0 :          SELECT CASE (unit_number)
      93              :          CASE (default_error_unit)
      94              :             WRITE (UNIT=message, FMT="(A,I0)") &
      95            0 :                "Attempt to close the default error unit number ", unit_number
      96            0 :             CALL cp_abort(__LOCATION__, TRIM(message))
      97              :          CASE (default_input_unit)
      98              :             WRITE (UNIT=message, FMT="(A,I0)") &
      99            0 :                "Attempt to close the default input unit number ", unit_number
     100            0 :             CALL cp_abort(__LOCATION__, TRIM(message))
     101              :          CASE (default_output_unit)
     102              :             WRITE (UNIT=message, FMT="(A,I0)") &
     103            0 :                "Attempt to close the default output unit number ", unit_number
     104       139462 :             CALL cp_abort(__LOCATION__, TRIM(message))
     105              :          END SELECT
     106              : 
     107              :          ! Define status after closing the file (KEEP for named, DELETE for unnamed SCRATCH files)
     108       139462 :          IF (PRESENT(file_status)) THEN
     109        90444 :             IF (LEN_TRIM(ADJUSTL(file_status)) > LEN(status_string)) THEN
     110              :                CALL cp_abort(__LOCATION__, &
     111              :                              "An invalid file STATUS="//TRIM(ADJUSTL(file_status))// &
     112            0 :                              " was specified.")
     113              :             END IF
     114        90444 :             status_string = TRIM(ADJUSTL(file_status))
     115        90444 :             CALL uppercase(status_string)
     116        49018 :          ELSE IF (.NOT. is_named) THEN
     117            4 :             status_string = "DELETE"
     118              :          ELSE
     119        49014 :             status_string = "KEEP"
     120              :          END IF
     121              : 
     122       139462 :          SELECT CASE (status_string)
     123              :          CASE ("DELETE", "KEEP")
     124       139462 :             CLOSE (UNIT=unit_number, IOSTAT=istat, IOMSG=iomsg_string, STATUS=TRIM(status_string))
     125       139462 :             IF (istat /= 0) THEN
     126              :                CALL cp_abort(__LOCATION__, &
     127              :                              "An error occurred closing the file with the logical unit number "// &
     128              :                              TRIM(int_to_string(unit_number))//" (IOSTAT="// &
     129            0 :                              TRIM(int_to_string(istat))//"): "//TRIM(iomsg_string))
     130              :             END IF
     131              :          CASE DEFAULT
     132              :             CALL cp_abort(__LOCATION__, &
     133       139462 :                           "An invalid file STATUS="//TRIM(status_string)//" was specified.")
     134              :          END SELECT
     135              : 
     136              :       END IF
     137              : 
     138              :       ! A unit which is not open is ignored silently. close_file is called by cp_logger_release,
     139              :       ! e.g. for a unit shared by several loggers and already closed by one of them. No warning can
     140              :       ! be issued at that point, since the logger being released might still be the default logger.
     141              : 
     142       139465 :    END SUBROUTINE close_file
     143              : 
     144              : ! **************************************************************************************************
     145              : !> \brief Returns the first free positive logical unit number.
     146              : !> \return First free unit in 1..max_unit_number (excluding the default units), or -1 if none
     147              : !>         is free
     148              : !> \author Matthias Krack (MK)
     149              : !> \note  Must be called within the critical region cp_files_connect together with the OPEN
     150              : !>        statement, so that no other thread can obtain the same unit number in between.
     151              : ! **************************************************************************************************
     152       140199 :    FUNCTION get_unit_number() RESULT(unit_number)
     153              : 
     154              :       INTEGER                                            :: unit_number
     155              : 
     156              :       INTEGER                                            :: istat
     157              :       LOGICAL                                            :: exists, is_open
     158              : 
     159       766115 :       DO unit_number = 1, max_unit_number
     160            0 :          SELECT CASE (unit_number)
     161              :          CASE (default_error_unit, default_input_unit, default_output_unit)
     162       699613 :             CYCLE
     163              :          CASE DEFAULT
     164       699613 :             INQUIRE (UNIT=unit_number, EXIST=exists, OPENED=is_open, IOSTAT=istat)
     165      1465728 :             IF (exists .AND. (.NOT. is_open) .AND. (istat == 0)) RETURN
     166              :          END SELECT
     167              :       END DO
     168              : 
     169       140199 :       unit_number = -1
     170              : 
     171              :    END FUNCTION get_unit_number
     172              : 
     173              : ! **************************************************************************************************
     174              : !> \brief Opens a file and returns its logical unit number.
     175              : !> \param file_name File name; must be omitted for an anonymous SCRATCH file
     176              : !> \param unit_number Logical unit number of the opened file
     177              : !> \param file_status Fortran file status OLD, NEW, REPLACE, UNKNOWN, or SCRATCH for an
     178              : !>                    anonymous temporary file (default: OLD)
     179              : !> \param file_form FORMATTED or UNFORMATTED (default: FORMATTED)
     180              : !> \param file_action READ, WRITE, or READWRITE (default: WRITE for STATUS=NEW, REPLACE, and
     181              : !>                    SCRATCH, otherwise READ)
     182              : !> \param file_position ASIS, REWIND, or APPEND (default: REWIND)
     183              : !> \param file_pad YES or NO (default: YES); only allowed for FORMATTED files
     184              : !> \param file_access SEQUENTIAL or STREAM (default: SEQUENTIAL); DIRECT is not supported
     185              : !> \param debug Print the connection properties to the default output unit
     186              : !> \author Matthias Krack (MK)
     187              : !> \note  - If the file is already open, its unit number is returned and no new connection is
     188              : !>          made. ACTION, FORM, and ACCESS must match the existing connection; with
     189              : !>          POSITION=REWIND the file is rewound.
     190              : !>        - For STATUS=OLD and ACTION=READ, the file is also looked up in the data directory
     191              : !>          (see discover_file). Files opened for writing are never taken from there.
     192              : !>        - Any error aborts the program; there is no IOSTAT return.
     193              : ! **************************************************************************************************
     194       142186 :    SUBROUTINE open_file(file_name, unit_number, file_status, file_form, file_action, &
     195              :                         file_position, file_pad, file_access, debug)
     196              : 
     197              :       CHARACTER(LEN=*), INTENT(IN), OPTIONAL             :: file_name
     198              :       INTEGER, INTENT(OUT)                               :: unit_number
     199              :       CHARACTER(LEN=*), INTENT(IN), OPTIONAL             :: file_status, file_form, file_action, &
     200              :                                                             file_position, file_pad, file_access
     201              :       LOGICAL, INTENT(IN), OPTIONAL                      :: debug
     202              : 
     203              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'open_file'
     204              : 
     205              :       CHARACTER(LEN=11) :: access_string, action_string, current_access, current_action, &
     206              :          current_form, form_string, pad_string, position_string, status_string
     207              :       CHARACTER(LEN=2*default_path_length)               :: message
     208              :       CHARACTER(LEN=default_path_length)                 :: cwd, iomsg_string, real_file_name
     209              :       INTEGER                                            :: inquire_stat, open_stat
     210              :       LOGICAL                                            :: connect, exists, is_named, is_open
     211              : 
     212       142186 :       real_file_name = ""
     213       142186 :       unit_number = -1
     214              : 
     215       142186 :       IF (PRESENT(file_access)) THEN
     216           25 :          access_string = TRIM(ADJUSTL(file_access))
     217           25 :          CALL uppercase(access_string)
     218           25 :          IF (access_string == "DIRECT") THEN
     219              :             CALL cp_abort(__LOCATION__, &
     220            0 :                           "ACCESS=DIRECT is not supported.")
     221              :          END IF
     222              :       ELSE
     223       142161 :          access_string = "SEQUENTIAL"
     224              :       END IF
     225              : 
     226       142186 :       IF (PRESENT(file_status)) THEN
     227       108256 :          status_string = TRIM(ADJUSTL(file_status))
     228       108256 :          CALL uppercase(status_string)
     229              :       ELSE
     230        33930 :          status_string = "OLD"
     231              :       END IF
     232              : 
     233       142186 :       IF (PRESENT(file_form)) THEN
     234        99226 :          form_string = TRIM(ADJUSTL(file_form))
     235        99226 :          CALL uppercase(form_string)
     236              :       ELSE
     237        42960 :          form_string = "FORMATTED"
     238              :       END IF
     239              : 
     240       142186 :       IF (PRESENT(file_pad)) THEN
     241            2 :          pad_string = TRIM(ADJUSTL(file_pad))
     242            2 :          CALL uppercase(pad_string)
     243            2 :          IF (form_string == "UNFORMATTED") THEN
     244              :             CALL cp_abort(__LOCATION__, &
     245            0 :                           "The PAD specifier is not allowed for an UNFORMATTED file.")
     246              :          END IF
     247              :       ELSE
     248       142184 :          pad_string = "YES"
     249              :       END IF
     250              : 
     251       142186 :       IF (PRESENT(file_action)) THEN
     252       108255 :          action_string = TRIM(ADJUSTL(file_action))
     253       108255 :          CALL uppercase(action_string)
     254              :       ELSE
     255              :          ! A new or emptied file cannot be read, thus WRITE is the only sensible default
     256            0 :          SELECT CASE (status_string)
     257              :          CASE ("NEW", "REPLACE", "SCRATCH")
     258            0 :             action_string = "WRITE"
     259              :          CASE DEFAULT
     260        33931 :             action_string = "READ"
     261              :          END SELECT
     262              :       END IF
     263              : 
     264       142186 :       IF (PRESENT(file_position)) THEN
     265       102055 :          position_string = TRIM(ADJUSTL(file_position))
     266       102055 :          CALL uppercase(position_string)
     267              :       ELSE
     268        40131 :          position_string = "REWIND"
     269              :       END IF
     270              : 
     271       142186 :       IF (PRESENT(file_name)) THEN
     272       142182 :          IF (LEN_TRIM(file_name) == 0) THEN
     273              :             CALL cp_abort(__LOCATION__, &
     274            0 :                           "The specified FILE name is empty.")
     275              :          END IF
     276       142182 :          IF (LEN_TRIM(file_name) > LEN(real_file_name)) THEN
     277              :             CALL cp_abort(__LOCATION__, &
     278              :                           "The FILE name <"//TRIM(file_name)//"> exceeds the maximum length of "// &
     279            0 :                           TRIM(int_to_string(LEN(real_file_name)))//" characters.")
     280              :          END IF
     281       142182 :          IF (file_name(1:1) == " ") THEN
     282              :             CALL cp_abort(__LOCATION__, &
     283            0 :                           "The FILE name <"//TRIM(file_name)//"> has leading blanks.")
     284              :          END IF
     285       142182 :          IF (status_string == "SCRATCH") THEN
     286              :             CALL cp_abort(__LOCATION__, &
     287            0 :                           "A FILE name specifier is not allowed for SCRATCH files.")
     288              :          END IF
     289              :          ! Resolve the file name. The data directory is only searched for existing files
     290              :          ! opened read-only, so that installed data files are never modified.
     291       142182 :          IF ((status_string == "OLD") .AND. (action_string == "READ")) THEN
     292        39033 :             real_file_name = discover_file(file_name)
     293              :          ELSE
     294       103149 :             real_file_name = TRIM(ADJUSTL(file_name))
     295              :          END IF
     296              :       END IF
     297              : 
     298       142182 :       SELECT CASE (status_string)
     299              :       CASE ("SCRATCH")
     300              :          ! No file name required
     301              :       CASE ("NEW", "OLD", "REPLACE", "UNKNOWN")
     302       142182 :          IF (LEN_TRIM(real_file_name) == 0) THEN
     303              :             CALL cp_abort(__LOCATION__, &
     304              :                           "A FILE name length of zero for a file with STATUS="// &
     305            0 :                           TRIM(status_string)//" is not allowed.")
     306              :          END IF
     307              :       CASE DEFAULT
     308       142186 :          CALL cp_abort(__LOCATION__, "A file STATUS="//TRIM(status_string)//" is not supported.")
     309              :       END SELECT
     310              : 
     311              :       ! Inquire the file, find a free unit, and connect the file atomically with respect to other
     312              :       ! threads. All checks and error messages follow outside the critical region, because
     313              :       ! cp_abort and cp_warn may call open_file again via the logger, which would deadlock.
     314       142186 :       connect = .FALSE.
     315       142186 :       exists = .FALSE.
     316       142186 :       is_open = .FALSE.
     317       142186 :       inquire_stat = 0
     318       142186 :       open_stat = 0
     319       142186 :       iomsg_string = ""
     320       284372 : !$OMP CRITICAL(cp_files_connect)
     321       142186 :       IF (status_string == "SCRATCH") THEN
     322              :          connect = .TRUE.
     323              :       ELSE
     324       142182 :          INQUIRE (FILE=TRIM(real_file_name), EXIST=exists, OPENED=is_open, IOSTAT=inquire_stat)
     325       142182 :          IF (inquire_stat == 0) THEN
     326       142182 :             IF (is_open) THEN
     327              :                INQUIRE (FILE=TRIM(real_file_name), NUMBER=unit_number, &
     328         1987 :                         ACTION=current_action, FORM=current_form, ACCESS=current_access)
     329              :             ELSE
     330           12 :                SELECT CASE (status_string)
     331              :                CASE ("NEW")
     332           12 :                   connect = (.NOT. exists)
     333              :                CASE ("OLD")
     334        41888 :                   connect = exists
     335              :                CASE DEFAULT
     336       140195 :                   connect = .TRUE.
     337              :                END SELECT
     338              :             END IF
     339              :          END IF
     340              :       END IF
     341        41900 :       IF (connect) THEN
     342       140199 :          unit_number = get_unit_number()
     343       140199 :          IF (unit_number > 0) THEN
     344       140199 :             IF (status_string == "SCRATCH") THEN
     345            4 :                IF (form_string == "FORMATTED") THEN
     346              :                   OPEN (UNIT=unit_number, &
     347              :                         STATUS=TRIM(status_string), &
     348              :                         ACCESS=TRIM(access_string), &
     349              :                         FORM=TRIM(form_string), &
     350              :                         POSITION=TRIM(position_string), &
     351              :                         ACTION=TRIM(action_string), &
     352              :                         PAD=TRIM(pad_string), &
     353              :                         IOMSG=iomsg_string, &
     354            2 :                         IOSTAT=open_stat)
     355              :                ELSE
     356              :                   OPEN (UNIT=unit_number, &
     357              :                         STATUS=TRIM(status_string), &
     358              :                         ACCESS=TRIM(access_string), &
     359              :                         FORM=TRIM(form_string), &
     360              :                         POSITION=TRIM(position_string), &
     361              :                         ACTION=TRIM(action_string), &
     362              :                         IOMSG=iomsg_string, &
     363            2 :                         IOSTAT=open_stat)
     364              :                END IF
     365              :             ELSE
     366       140195 :                IF (form_string == "FORMATTED") THEN
     367              :                   OPEN (UNIT=unit_number, &
     368              :                         FILE=TRIM(real_file_name), &
     369              :                         STATUS=TRIM(status_string), &
     370              :                         ACCESS=TRIM(access_string), &
     371              :                         FORM=TRIM(form_string), &
     372              :                         POSITION=TRIM(position_string), &
     373              :                         ACTION=TRIM(action_string), &
     374              :                         PAD=TRIM(pad_string), &
     375              :                         IOMSG=iomsg_string, &
     376       117836 :                         IOSTAT=open_stat)
     377              :                ELSE
     378              :                   OPEN (UNIT=unit_number, &
     379              :                         FILE=TRIM(real_file_name), &
     380              :                         STATUS=TRIM(status_string), &
     381              :                         ACCESS=TRIM(access_string), &
     382              :                         FORM=TRIM(form_string), &
     383              :                         POSITION=TRIM(position_string), &
     384              :                         ACTION=TRIM(action_string), &
     385              :                         IOMSG=iomsg_string, &
     386        22359 :                         IOSTAT=open_stat)
     387              :                END IF
     388              :             END IF
     389              :          END IF
     390              :       END IF
     391              : !$OMP END CRITICAL(cp_files_connect)
     392              : 
     393       142186 :       IF (inquire_stat /= 0) THEN
     394              :          CALL cp_abort(__LOCATION__, &
     395              :                        "An error occurred inquiring the file <"//TRIM(real_file_name)// &
     396            0 :                        "> (IOSTAT="//TRIM(int_to_string(inquire_stat))//").")
     397              :       END IF
     398              : 
     399       142186 :       IF (is_open) THEN
     400              :          ! The file is already connected: check the connection and reuse it
     401         1987 :          CALL uppercase(current_action)
     402         1987 :          IF (TRIM(current_action) /= TRIM(action_string)) THEN
     403              :             CALL cp_abort(__LOCATION__, &
     404              :                           "Attempt to re-open the existing file <"// &
     405              :                           TRIM(real_file_name)//"> with the modified ACTION attribute "// &
     406              :                           TRIM(action_string)//". The current ACTION attribute is "// &
     407            0 :                           TRIM(current_action)//".")
     408              :          END IF
     409         1987 :          CALL uppercase(current_form)
     410         1987 :          IF (TRIM(current_form) /= TRIM(form_string)) THEN
     411              :             CALL cp_abort(__LOCATION__, &
     412              :                           "Attempt to re-open the existing "// &
     413              :                           TRIM(current_form)//" file <"//TRIM(real_file_name)// &
     414            0 :                           "> as "//TRIM(form_string)//" file.")
     415              :          END IF
     416         1987 :          CALL uppercase(current_access)
     417         1987 :          IF (TRIM(current_access) /= TRIM(access_string)) THEN
     418              :             CALL cp_abort(__LOCATION__, &
     419              :                           "Attempt to re-open the existing "// &
     420              :                           TRIM(current_access)//" file <"//TRIM(real_file_name)// &
     421            0 :                           "> with ACCESS="//TRIM(access_string)//".")
     422              :          END IF
     423         1987 :          IF (status_string == "NEW") THEN
     424              :             CALL cp_abort(__LOCATION__, &
     425              :                           "Attempt to re-open the existing file <"// &
     426            0 :                           TRIM(real_file_name)//"> with STATUS=NEW.")
     427              :          END IF
     428         1987 :          IF (position_string == "REWIND") REWIND (UNIT=unit_number)
     429              :       ELSE
     430              :          ! Check the outcome of the connection attempt
     431           12 :          SELECT CASE (status_string)
     432              :          CASE ("NEW")
     433           12 :             IF (exists) THEN
     434              :                CALL cp_abort(__LOCATION__, &
     435              :                              "The file <"//TRIM(real_file_name)// &
     436            0 :                              "> cannot be opened with STATUS=NEW, because it already exists.")
     437              :             END IF
     438              :          CASE ("OLD")
     439       140199 :             IF (.NOT. exists) THEN
     440            0 :                IF (action_string == "READ") THEN
     441              :                   CALL cp_abort(__LOCATION__, &
     442              :                                 "The specified file <"//TRIM(real_file_name)// &
     443              :                                 "> cannot be opened with STATUS=OLD. It does not exist. "// &
     444            0 :                                 "Data directory path: "//TRIM(get_data_dir()))
     445              :                ELSE
     446              :                   CALL cp_abort(__LOCATION__, &
     447              :                                 "The specified file <"//TRIM(real_file_name)// &
     448              :                                 "> cannot be opened with STATUS=OLD and ACTION="// &
     449            0 :                                 TRIM(action_string)//". It does not exist.")
     450              :                END IF
     451              :             END IF
     452              :          END SELECT
     453       140199 :          IF (unit_number < 1) THEN
     454            0 :             IF (status_string == "SCRATCH") THEN
     455              :                CALL cp_abort(__LOCATION__, &
     456            0 :                              "Could not obtain a unit number to open a SCRATCH file.")
     457              :             ELSE
     458              :                CALL cp_abort(__LOCATION__, &
     459              :                              "Cannot open the file <"//TRIM(real_file_name)// &
     460            0 :                              ">, because no unused logical unit number could be obtained.")
     461              :             END IF
     462              :          END IF
     463       140199 :          IF (open_stat /= 0) THEN
     464            0 :             IF (status_string == "SCRATCH") THEN
     465              :                CALL cp_abort(__LOCATION__, &
     466              :                              "An error occurred opening a SCRATCH file (UNIT="// &
     467              :                              TRIM(int_to_string(unit_number))//", IOSTAT="// &
     468            0 :                              TRIM(int_to_string(open_stat))//"): "//TRIM(iomsg_string))
     469              :             ELSE
     470            0 :                CALL m_getcwd(cwd)
     471              :                CALL cp_abort(__LOCATION__, &
     472              :                              "An error occurred opening the file <"//TRIM(real_file_name)// &
     473              :                              "> (UNIT="//TRIM(int_to_string(unit_number))// &
     474              :                              ", IOSTAT="//TRIM(int_to_string(open_stat))//"): "// &
     475            0 :                              TRIM(iomsg_string)//". Current working directory: "//TRIM(cwd))
     476              :             END IF
     477              :          END IF
     478              :       END IF
     479              : 
     480       142186 :       IF (PRESENT(debug)) THEN
     481          157 :          IF (debug) THEN
     482              :             INQUIRE (UNIT=unit_number, &
     483              :                      OPENED=is_open, &
     484              :                      NAMED=is_named, &
     485              :                      POSITION=position_string, &
     486              :                      ACCESS=access_string, &
     487              :                      FORM=form_string, &
     488          144 :                      ACTION=action_string)
     489              :             ! The NAME specifier is undefined for unnamed (SCRATCH) files
     490          144 :             IF (is_named) THEN
     491          144 :                INQUIRE (UNIT=unit_number, NAME=message)
     492              :             ELSE
     493            0 :                message = "<unnamed>"
     494              :             END IF
     495          144 :             WRITE (UNIT=default_output_unit, FMT="(T2,A)") "BEGIN DEBUG "//TRIM(routineN)
     496          144 :             WRITE (UNIT=default_output_unit, FMT="(T3,A,I0)") "NUMBER  : ", unit_number
     497          144 :             WRITE (UNIT=default_output_unit, FMT="(T3,A,L1)") "OPENED  : ", is_open
     498              :             WRITE (UNIT=default_output_unit, FMT="(T3,A)") &
     499          144 :                "NAME    : "//TRIM(message), &
     500          144 :                "POSITION: "//TRIM(position_string), &
     501          144 :                "ACCESS  : "//TRIM(access_string), &
     502          144 :                "FORM    : "//TRIM(form_string), &
     503          144 :                "ACTION  : "//TRIM(action_string), &
     504          288 :                "END DEBUG "//TRIM(routineN)
     505              :          END IF
     506              :       END IF
     507              : 
     508       142186 :    END SUBROUTINE open_file
     509              : 
     510              : ! **************************************************************************************************
     511              : !> \brief Checks if a file exists, considering also the file discovery mechanism.
     512              : !> \param file_name Name of the file
     513              : !> \return True, if the file exists in the current or the data directory
     514              : !> \author Ole Schuett
     515              : ! **************************************************************************************************
     516          713 :    FUNCTION file_exists(file_name) RESULT(exist)
     517              :       CHARACTER(LEN=*), INTENT(IN)                       :: file_name
     518              :       LOGICAL                                            :: exist
     519              : 
     520              :       CHARACTER(LEN=default_path_length)                 :: real_file_name
     521              :       INTEGER                                            :: istat
     522              : 
     523          713 :       real_file_name = discover_file(file_name)
     524          713 :       INQUIRE (FILE=TRIM(real_file_name), EXIST=exist, IOSTAT=istat)
     525          713 :       IF (istat /= 0) exist = .FALSE.
     526              : 
     527          713 :    END FUNCTION file_exists
     528              : 
     529              : ! **************************************************************************************************
     530              : !> \brief Searches for a file in the current directory and then in the data directory.
     531              : !> \param file_name Name of the file
     532              : !> \return File name as given, if it exists, otherwise its path in the data directory, if
     533              : !>         it exists there, else the file name stripped of blanks
     534              : !> \author Ole Schuett
     535              : ! **************************************************************************************************
     536        39771 :    FUNCTION discover_file(file_name) RESULT(real_file_name)
     537              :       CHARACTER(LEN=*), INTENT(IN)                       :: file_name
     538              :       CHARACTER(LEN=default_path_length)                 :: real_file_name
     539              : 
     540              :       CHARACTER(LEN=default_path_length)                 :: candidate, data_dir
     541              :       INTEGER                                            :: stat
     542              :       LOGICAL                                            :: exists
     543              : 
     544              :       ! Strip leading and trailing blanks from file name
     545        39771 :       real_file_name = TRIM(ADJUSTL(file_name))
     546              : 
     547        39771 :       IF (LEN_TRIM(real_file_name) == 0) THEN
     548            0 :          CALL cp_abort(__LOCATION__, "A file name length of zero for an existing file is invalid.")
     549              :       END IF
     550              : 
     551              :       ! First try file name directly
     552        39771 :       INQUIRE (FILE=TRIM(real_file_name), EXIST=exists, IOSTAT=stat)
     553        56327 :       IF (stat == 0 .AND. exists) RETURN
     554              : 
     555              :       ! Then try the data directory
     556        16647 :       data_dir = get_data_dir()
     557        16647 :       IF (LEN_TRIM(data_dir) > 0) THEN
     558        16647 :          candidate = join_paths(data_dir, real_file_name)
     559        16647 :          INQUIRE (FILE=TRIM(candidate), EXIST=exists, IOSTAT=stat)
     560        16647 :          IF (stat == 0 .AND. exists) THEN
     561        16556 :             real_file_name = candidate
     562        16556 :             RETURN
     563              :          END IF
     564              :       END IF
     565              : 
     566        39771 :    END FUNCTION discover_file
     567              : 
     568              : ! **************************************************************************************************
     569              : !> \brief Returns path of data directory if set, otherwise an empty string
     570              : !> \return Path of the data directory or an empty string
     571              : !> \author Ole Schuett
     572              : ! **************************************************************************************************
     573        22611 :    FUNCTION get_data_dir() RESULT(res)
     574              :       CHARACTER(len=default_path_length)                 :: res
     575              : 
     576              :       CHARACTER(LEN=1, KIND=C_CHAR), DIMENSION(:), &
     577        22611 :          POINTER                                         :: path_f
     578              :       INTEGER                                            :: i
     579              :       TYPE(C_PTR)                                        :: path_c
     580              :       INTERFACE
     581              :          FUNCTION get_data_dir_c() BIND(C, name="get_data_dir")
     582              :             IMPORT :: C_PTR
     583              :             TYPE(C_PTR)                               :: get_data_dir_c
     584              :          END FUNCTION get_data_dir_c
     585              :       END INTERFACE
     586              : 
     587        22611 :       path_c = get_data_dir_c()
     588        45222 :       CALL C_F_POINTER(path_c, path_f, shape=[default_path_length])
     589              : 
     590        22611 :       res = ""
     591       339165 :       DO i = 1, default_path_length
     592       339165 :          IF (path_f(i) == C_NULL_CHAR) RETURN
     593       316554 :          res(i:i) = path_f(i)
     594              :       END DO
     595              : 
     596            0 :       CALL cp_abort(__LOCATION__, "The CP2K_DATA_DIR path is too long")
     597              : 
     598        22611 :    END FUNCTION get_data_dir
     599              : 
     600              : ! **************************************************************************************************
     601              : !> \brief Joins two file paths, inserting '/' as needed.
     602              : !> \param path1 Leading path, e.g. a directory
     603              : !> \param path2 Trailing path; returned unchanged if it is an absolute path
     604              : !> \return Joined path; the program is aborted, if it exceeds default_path_length
     605              : !> \author Ole Schuett
     606              : ! **************************************************************************************************
     607        16655 :    FUNCTION join_paths(path1, path2) RESULT(joined_path)
     608              :       CHARACTER(LEN=*), INTENT(IN)                       :: path1, path2
     609              :       CHARACTER(LEN=default_path_length)                 :: joined_path
     610              : 
     611              :       INTEGER                                            :: joined_length, n1, n2
     612              :       LOGICAL                                            :: absolute
     613              : 
     614        16655 :       n1 = LEN_TRIM(path1)
     615        16655 :       n2 = LEN_TRIM(path2)
     616              : 
     617        16655 :       absolute = .FALSE.
     618        16655 :       IF (n2 > 0) absolute = (path2(1:1) == '/')
     619              : 
     620              :       ! Determine the length of the joined path before assigning it to avoid silent truncation
     621        16655 :       IF (absolute .OR. (n1 == 0)) THEN
     622              :          joined_length = n2
     623        16647 :       ELSE IF (path1(n1:n1) == '/') THEN
     624            0 :          joined_length = n1 + n2
     625              :       ELSE
     626        16647 :          joined_length = n1 + 1 + n2
     627              :       END IF
     628        16655 :       IF (joined_length > LEN(joined_path)) THEN
     629              :          CALL cp_abort(__LOCATION__, &
     630              :                        "The joined path of <"//path1(1:n1)//"> and <"//path2(1:n2)// &
     631              :                        "> exceeds the maximum length of "// &
     632            0 :                        TRIM(int_to_string(LEN(joined_path)))//" characters.")
     633              :       END IF
     634              : 
     635        16655 :       IF (absolute .OR. (n1 == 0)) THEN
     636            8 :          joined_path = path2(1:n2)
     637        16647 :       ELSE IF (path1(n1:n1) == '/') THEN
     638            0 :          joined_path = path1(1:n1)//path2(1:n2)
     639              :       ELSE
     640        16647 :          joined_path = path1(1:n1)//'/'//path2(1:n2)
     641              :       END IF
     642              : 
     643        16655 :    END FUNCTION join_paths
     644              : 
     645              : ! **************************************************************************************************
     646              : !> \brief Converts an integer to a left-adjusted string.
     647              : !> \param i Integer value
     648              : !> \return String representation of i
     649              : !> \author Matthias Krack (MK)
     650              : ! **************************************************************************************************
     651            0 :    FUNCTION int_to_string(i) RESULT(string)
     652              :       INTEGER, INTENT(IN)                                :: i
     653              :       CHARACTER(LEN=11)                                  :: string
     654              : 
     655            0 :       WRITE (UNIT=string, FMT="(I0)") i
     656              : 
     657            0 :    END FUNCTION int_to_string
     658              : 
     659              : END MODULE cp_files
        

Generated by: LCOV version 2.0-1