LCOV - code coverage report
Current view: top level - src/common - cp_files.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 77.3 % 220 170
Test Date: 2026-11-04 00:58:17 Functions: 88.9 % 9 8

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

Generated by: LCOV version 2.0-1