! ! Copyright (C) 2004-2013 Quantum ESPRESSO group ! This file is distributed under the terms of the ! GNU General Public License. See the file `License' ! in the root directory of the present distribution, ! or http://www.gnu.org/copyleft/gpl.txt . ! !-------------------------------------------------------------------------- MODULE clib_wrappers !------------------------------------------------------------------------ !! This module contains fortran wrappers to POSIX system calls. !! The wrappers are used to convert the Fortran CHARACTER array to !! null-terminated C *char. The conversion and the interface is done !! with the F95 intrinsic \(\texttt{iso_c_binding}\) module. !! Additionally, it provides interfaces to the C functions in clib/: !! \(\texttt{eval_infix, md5_from_file, f_mkdir_safe}\) ! ! NOTE: the mkdir function is NOT called directly as it returns error if ! directory already exists. We use instead a C wrapper c_mkdir_safe ! USE util_param, ONLY : DP USE ISO_C_BINDING IMPLICIT NONE ! ! C std library functions fortran wrappers: PUBLIC f_remove, f_rename, f_chdir, f_mkdir, f_rmdir, f_getcwd ! more stuff: PUBLIC f_copy, feval_infix, md5_from_file, f_mkdir_safe, memstat, get_mem_usage, get_mem_avail ! ! HELP: ! integer f_remove(pathname) ! integer f_rename(oldfile, newfile) ! integer f_chdir(newdir) ! integer f_chmod(mode) i.e. mode=777 (disable) ! integer f_mkdir(dirname, mode) mode is optional ! integer f_rmdir(dirname) ! subroutine f_getcwd(dirname) ! All "*name" are fortran characters of implicit length, ! "mode" are integers, all functions return 0 if successful, -1 otherwise ! ! real(dp) :: result = feval_infix(integer:: ierr, character(len=*) :: expression) ! subroutine md5_from_file(character(len=*) :: filename, character(len=32) ::md5) PRIVATE ! SAVE ! ! Interfaces to the C functions, these are kept private as Fortran ! characters have (?) to be converted explicitly to C character arrays. ! Use the f_* wrappers instead INTERFACE FUNCTION remove(pathname) BIND(C,name="remove") RESULT(r) USE iso_c_binding CHARACTER(kind=c_char),INTENT(in) :: pathname(*) INTEGER(c_int) :: r END FUNCTION FUNCTION rename(input,output) BIND(C,name="rename") RESULT(r) USE iso_c_binding CHARACTER(kind=c_char),INTENT(in) :: input(*) CHARACTER(kind=c_char),INTENT(in) :: output(*) INTEGER(c_int) :: r END FUNCTION FUNCTION chmod(filename,mode) BIND(C,name="chmod") RESULT(r) USE iso_c_binding CHARACTER(kind=c_char),INTENT(in) :: filename(*) INTEGER(c_int),VALUE ,INTENT(in) :: mode INTEGER(c_int) :: r END FUNCTION FUNCTION chdir(filename) BIND(C,name="chdir") RESULT(r) USE iso_c_binding CHARACTER(kind=c_char),INTENT(in) :: filename(*) INTEGER(c_int) :: r END FUNCTION FUNCTION mkdir(dirname,mode) BIND(C,name="mkdir") RESULT(r) USE iso_c_binding CHARACTER(kind=c_char),INTENT(in) :: dirname(*) INTEGER(c_int),VALUE ,INTENT(in) :: mode INTEGER(c_int) :: r END FUNCTION FUNCTION rmdir(dirname) BIND(C,name="rmdir") RESULT(r) USE iso_c_binding CHARACTER(kind=c_char),INTENT(in) :: dirname(*) INTEGER(c_int) :: r END FUNCTION FUNCTION getcwd(buffer,size) BIND(C,name="getcwd") RESULT(r) USE iso_c_binding CHARACTER(kind=c_char) ,INTENT(out) :: buffer(*) INTEGER(c_size_t),VALUE,INTENT(in) :: size TYPE(c_ptr) :: r END FUNCTION END INTERFACE ! ! ==================================================================== CONTAINS ! ==================================================================== ! fortran wrappers functions that call the C functions after converting ! fortran characters to C character arrays FUNCTION f_remove(filename) RESULT(r) CHARACTER(*),INTENT(in) :: filename INTEGER(c_int) :: r r= remove(TRIM(filename)//C_NULL_CHAR) END FUNCTION FUNCTION f_rename(input,output) RESULT(k) CHARACTER(*),INTENT(in) :: input,output INTEGER :: k k= rename(TRIM(input)//C_NULL_CHAR,TRIM(output)//C_NULL_CHAR) END FUNCTION FUNCTION f_chdir(dirname) RESULT(r) CHARACTER(*),INTENT(in) :: dirname INTEGER(c_int) :: r r= chdir(TRIM(dirname)//C_NULL_CHAR) END FUNCTION ! ! f_mkdir, causes an ERROR if dirname already exists: use f_mkdir_safe instead FUNCTION f_mkdir(dirname, mode) RESULT(r) CHARACTER(*),INTENT(in) :: dirname INTEGER,INTENT(in) :: mode INTEGER(c_int) :: r INTEGER(c_int) :: c_mode c_mode = INT(mode, kind=c_int) r= mkdir(TRIM(dirname)//C_NULL_CHAR, c_mode) END FUNCTION ! Note: permissions are usually in octal, e.g.: ! mode = o'640' => rw-r----- FUNCTION f_chmod(filename, mode) RESULT(r) CHARACTER(*),INTENT(in) :: filename INTEGER,INTENT(in) :: mode INTEGER(c_int) :: r INTEGER(c_int) :: c_mode c_mode = INT(mode, kind=c_int) r= chmod(TRIM(filename)//C_NULL_CHAR, c_mode) END FUNCTION FUNCTION f_rmdir(dirname) RESULT(r) CHARACTER(*),INTENT(in) :: dirname INTEGER(c_int) :: r r= rmdir(TRIM(dirname)//C_NULL_CHAR) END FUNCTION SUBROUTINE f_getcwd(output) CHARACTER(kind=c_char,len=*),INTENT(out) :: output TYPE(c_ptr) :: buffer INTEGER(C_SIZE_T) :: length,i ! was kind=C_LONG, which fails on WIN32 length=LEN(output) buffer=getcwd(output,length) DO i=1,length IF(output(i:i) == C_NULL_CHAR) EXIT ENDDO output(i:)=' ' END SUBROUTINE ! ==================================================================== ! copy a file, uses clibs/copy.c which currently does a binary copy ! using an 8kb buffer ! ! returns: ! 0 : no error ! -1 : cannot open source ! -2 : cannot open dest ! -3 : error while writing ! -4 : disk full while writing FUNCTION f_copy(source, dest) RESULT(r) INTERFACE FUNCTION c_copy(source,dest) BIND(C,name="copy") RESULT(r) USE iso_c_binding CHARACTER(kind=c_char),INTENT(in) :: source(*), dest(*) INTEGER(c_int) :: r END FUNCTION c_copy END INTERFACE CHARACTER(*),INTENT(in) :: source, dest INTEGER(c_int) :: r r= c_copy(TRIM(source)//C_NULL_CHAR, TRIM(dest)//C_NULL_CHAR) END FUNCTION ! ! safe mkdir from clib/c_mkdir.c that creates a directory, if necessary, ! and checks permissions. It can be called in parallel. ! Returns: 0 = all ok ! 1 = error ! -1 = the directory already existed and is properly writable FUNCTION f_mkdir_safe(dirname) RESULT(r) INTERFACE FUNCTION mkdir_safe(dirname) BIND(C,name="c_mkdir_safe") RESULT(r) USE iso_c_binding CHARACTER(kind=c_char),INTENT(in) :: dirname(*) INTEGER(c_int) :: r END FUNCTION mkdir_safe END INTERFACE CHARACTER(*),INTENT(in) :: dirname INTEGER(c_int) :: r r= mkdir_safe(TRIM(dirname)//C_NULL_CHAR) END FUNCTION ! ! Two more wrappers for eval_infix (simple algebric expression parser) ! and for get_md5 which computes the md5 sum of a file. ! FUNCTION feval_infix(fierr, fstr) USE ISO_C_BINDING IMPLICIT NONE REAL(DP) :: feval_infix INTEGER :: fierr CHARACTER(len=*) :: fstr INTEGER :: filen ! INTERFACE FUNCTION ceval_infix(cierr, cstr, cilen) BIND(C, name="eval_infix") !REAL(kind=c_double) FUNCTION ceval_infix(cierr, cstr, cilen) BIND(C, name="eval_infix") ! double eval_infix( int *ierr, const char *strExpression, int len ) USE ISO_C_BINDING REAL(kind=c_double) :: ceval_infix INTEGER(kind=c_int) :: cierr CHARACTER(kind=c_char) :: cstr(*) INTEGER(kind=c_int),VALUE :: cilen END FUNCTION ceval_infix END INTERFACE ! INTEGER(kind=c_int) :: cierr INTEGER(kind=c_int) :: cilen CHARACTER(len=len_trim(fstr)+1,kind=c_char) :: cstr ! INTEGER :: i ! filen = len_trim(fstr) cilen = INT(filen, kind=c_int) DO i = 1,filen cstr(i:i) = fstr(i:i) ENDDO cstr(filen+1:filen+1)=C_NULL_CHAR ! feval_infix = REAL( ceval_infix(cierr, cstr, cilen), kind=DP) fierr = INT(cierr) RETURN END FUNCTION feval_infix ! ! SUBROUTINE md5_from_file (ffile, fmd5) IMPLICIT NONE CHARACTER(LEN=*), INTENT (IN) :: ffile CHARACTER(len=32), INTENT (OUT) :: fmd5 ! INTERFACE SUBROUTINE cget_md5(cfile, cmd5, cierr) BIND(C, name="get_md5") ! void get_md5(const char *file, char *md5, int err) USE ISO_C_BINDING CHARACTER(kind=c_char) :: cfile(*) CHARACTER(kind=c_char) :: cmd5(*) INTEGER(kind=c_int) :: cierr END SUBROUTINE cget_md5 END INTERFACE ! INTEGER,PARAMETER :: md5_length = 32 INTEGER :: i ! CHARACTER(len=len_trim(ffile)+1,kind=c_char) :: cfile!(*) CHARACTER(len=(md5_length+1),kind=c_char) :: cmd5!(*) INTEGER(kind=c_int) :: cierr ! cfile = TRIM(ffile)//C_NULL_CHAR ! CALL cget_md5(cfile, cmd5, cierr) ! DO i = 1,md5_length fmd5(i:i) = cmd5(i:i) ENDDO ! END SUBROUTINE md5_from_file ! ! Wrapper for (buggy) C routine "memstat" ! SUBROUTINE memstat (kbytes) IMPLICIT NONE INTEGER, INTENT(OUT) :: kbytes ! INTERFACE FUNCTION c_memstat( ) BIND(C, name="c_memstat") USE ISO_C_BINDING INTEGER(kind=c_int) :: c_memstat END FUNCTION c_memstat END INTERFACE ! kbytes = c_memstat() ! END SUBROUTINE memstat ! ! Wrapper for C routine "getMemUsage" ! FUNCTION get_mem_usage() RESULT(kbytes) IMPLICIT NONE INTEGER(kind=c_size_t) :: kbytes ! INTERFACE FUNCTION c_getmemusage() BIND(C, name="c_getMemUsage") USE ISO_C_BINDING INTEGER(kind=c_size_t) :: c_getmemusage END FUNCTION c_getmemusage END INTERFACE ! kbytes = c_getmemusage() ! END FUNCTION get_mem_usage ! ! Wrapper for C routine "getMemAvail" ! FUNCTION get_mem_avail() RESULT(kbytes) IMPLICIT NONE INTEGER(kind=c_size_t) :: kbytes ! INTERFACE FUNCTION c_getmemavail() BIND(C, name="c_getMemAvail") USE ISO_C_BINDING INTEGER(kind=c_size_t) :: c_getmemavail END FUNCTION c_getmemavail END INTERFACE ! kbytes = c_getmemavail(); ! END FUNCTION get_mem_avail ! END MODULE ! ====================================================================