Is there an alternative to GETCWD () in Fortran 2003-2008

The GNU extension for the GNU Fortran compiler provides the GETCWD() routine, which, well, gets the current working directory. However, my code must be portable to the ifort and nagfor , and I use the F2003 functions.

So, is there an alternative to GETCWD() for F2003 and later?

I have a standard here, but it is pretty significant, and I survived this for a while and did not find anything useful ...

+5
source share
3 answers

You can also use ISO_C_Binding and call the appropriate C functions:

cwd.c:

 #ifdef _WIN32 /* Windows */ #include <direct.h> #define GETCWD _getcwd #else /* Unix */ #include <unistd.h> #define GETCWD getcwd #endif void getCurrentWorkDir( char *str, int *stat ) { if ( GETCWD(str, sizeof(str)) == str ) { *stat = 0; } else { *stat = 1; } } 

test.F90:

 program test use ISO_C_Binding, only: C_CHAR, C_INT interface subroutine getCurrentWorkDir(str, stat) bind(C, name="getCurrentWorkDir") use ISO_C_Binding, only: C_CHAR, C_INT character(kind=C_CHAR),intent(out) :: str(*) integer(C_INT),intent(out) :: stat end subroutine end interface character(len=30) :: str integer(C_INT) :: stat str='' call getCurrentWorkDir(str, stat) print *, stat, trim(str) end program 

This code is valid for Windows and Unix derivatives (Linux, OSX, BSD, etc.)

+5
source

As noted in the comments, you can use get_environment_variable , which is the standard Fortran (e.g. F2008 13.7.67). In this example, the program requests the value of $PWD , which should contain the directory in which your shell is located when the executable file is called.

 program test implicit none character(len=128) :: pwd call get_environment_variable('PWD',pwd) print *, "The current working directory is: ",trim(pwd) end program 

And his conclusion:

 casey@convect code % pwd /home/casey/code casey@convect code % so/getpwd The current working directory is: /home/casey/code 

This is standard Fortran, but portability will be limited to Unix and Unix-like shells that set this variable.

Another option, although standard, but ugly (in my opinion) would be to use execute_command_line to run a command that can output the working directory to a temporary file (for example, pwd > /tmp/mypwd ), and then read this file.

+6
source

The accepted answer contains two errors (it passes the wrong value as the length of the string to GETCWD and leaves it in C_NULL_CHAR ). This answer corrects these errors and makes the interface more convenient to use in Fortran.

The basic idea is the same: call getcwd or _getcwd using C, and call the C shell using the Fortran C interaction functions. On the Fortran side, the wrapper routine is used to handle the length of the string, so it does not need to be passed explicitly.

In addition, C_INT and C_CHAR optional, as are the default integers and default characters that C_CHAR on the Fortran side (although in practice I don’t know a single system where C_CHAR and char are by default). The shell also converts them. In addition, the string returned from C contains the trailing C_NULL_CHAR , which must be deleted so that the string can be used on the Fortran side.

Code C:

 #ifdef _WIN32 #include <direct.h> #define GETCWD _getcwd #else #include <unistd.h> #define GETCWD getcwd #endif /* Return 0 on success, 1 on error. */ int getCWDHelper(char *str, int len) { return GETCWD(str, len) != str; } 

Fortran Code:

 module cwd use iso_c_binding, only: C_INT, C_CHAR, C_NULL_CHAR implicit none private public :: getCWD interface function getCWDHelper(str, len) bind(C, name="getCWDHelper") use iso_c_binding, only: C_INT, C_CHAR integer(kind=C_INT) :: getCWDHelper character(kind=C_CHAR), intent(out) :: str(*) integer(kind=C_INT), value :: len end function getCWDHelper end interface contains ! Writes the current working directory path into str. ! Returns 0 on success, or 1 on error. function getCWD(str) integer :: getCWD character(*), intent(out) :: str integer :: i, length character(len=len(str), kind=C_CHAR) :: str_copy ! Call the C helper, passing the length as the correct int kind getCWD = getCWDHelper(str_copy, len(str_copy, kind=C_INT)) if (getCWD /= 0) then str = '' ! Error, clear the string return end if ! Copy the C_CHAR string to the output string, ! removing the C_NULL_CHAR and clearing the rest. length = index(str_copy, C_NULL_CHAR) - 1 do i = 1, length str(i:i) = char(ichar(str_copy(i:i))) end do str(length+1:) = '' end function getCWD end module 

Test code:

 program test use cwd, only: getCWD implicit none character(len=255) :: path integer :: error error = getCWD(path) print *, error if (error == 0) print *, path end program 

By making the return value placementable and circular to get enough size, we leave it to the reader as an exercise.

0
source

All Articles