Languages and Scripting
cancel
Showing results for 
Search instead for 
Did you mean: 

Re: How to get filename a symbolic link points to from within Fortran

 
SOLVED
Go to solution
Highlighted
Regular Advisor

How to get filename a symbolic link points to from within Fortran

I need to be able to get the file name that a symbolic link points to from within a Fortran code. What is the easiest way to do this ?
13 REPLIES 13
Highlighted
Honored Contributor
Solution

Re: How to get filename a symbolic link points to from within Fortran

One method is to make a Fortran-callable C
function do the work, using the appropriate
C run-time function.

I haven't done any serious programming in
Fortran since it was FORTRAN, so you'll
probably want to edit this pretty heavily,
add better exception handling, and so on,
but, ...

dy # cat freadlink.c
#include /* For printf(). */
#include

int freadlink_( char *lname, char *ltext, int lname_len, int ltext_len)
{
int sts;

printf( " C-diag: lname_len = %d, ltext_len = %d.\n", lname_len, ltext_len);

/* NUL-terminate the Fortran string.
* Note that it's the caller's responsibility to provide the
* extra byte.
*/
lname[ lname_len] = '\0';

/* Get the link text. */
sts = readlink( lname, ltext, ltext_len);

/* Return the link text length. (-1 on error.) */
return sts;
}

dy # cat fln.f
program fln

implicit none

character* 1024 lname
character* 1024 ltext

integer* 4 lname_len
integer* 4 ltext_len

integer* 4 freadlink

lname = "slink"
lname_len = len( "slink")

write (*, *) " lname: >", lname(1: lname_len), "<"

ltext_len = freadlink( lname( 1: lname_len) , ltext)

write (*, *) " ltext_len = ", ltext_len, "."

if (ltext_len .ge. 0) then
write (*, *) " ltext: >", ltext( 1:ltext_len), "<"
endif

end

dy # ls -l
total 32
-rw-r--r-- 1 root sys 522 Mar 31 17:01 fln.f
-rw-r--r-- 1 root sys 519 Mar 31 17:00 freadlink.c
lrwxr-xr-x 1 root sys 9 Mar 31 16:46 slink -> link_text

dy # gcc -c freadlink.c
dy # gfortran fln.f -o fln freadlink.o

dy # ./fln
lname: >slink<
C-diag: lname_len = 5, ltext_len = 1024.
ltext_len = 9 .
ltext: >link_text<

Note that the details of how Fortran passes
a character string argument depend on the OS.
On VMS, it uses a descriptor. On UNIX, it
uses an extra (int) argument after the end
of the normal argument list. And on VMS, you
wouldn't need the "_" suffix on the C
function name.

Of course, if the Fortran run-time library
already offers a function like this, then
we've both wasted some time. (But I enjoy a
nice stroll down memory lane, and I've never
used "gfortran" in anger before, so it was
educational.)
Highlighted
Regular Advisor

Re: How to get filename a symbolic link points to from within Fortran

With a few mods and an alias command I was able to get this to work but then I found out that my check using stat was checking for hard links instead.

What is the easiest way to find out if a file is a symbolic link or not ?
Highlighted
Honored Contributor

Re: How to get filename a symbolic link points to from within Fortran

> With a few mods and an alias command

Pray, tell.

> I was able to get this to work but then I
> found out that my check using stat

Can't see it.

> was checking for hard links instead.

Hard links are often called files.

> What is the easiest way to find out if a
> file is a symbolic link or not ?

I don't know. readlink() seems to offer one
way.

[...]
ERRORS

The readlink() function will fail if:
[...]
[EINVAL]

The path argument names a file that is not a symbolic link.
[...]
Honored Contributor

Re: How to get filename a symbolic link points to from within Fortran

Compare inode values between stat() and
lstat() results?

There's probably a good way, too.
Highlighted
Regular Advisor

Re: How to get filename a symbolic link points to from within Fortran

I was able to get the following to work :

#include
#include
#include

int freadlink_( char *lname, char *buf, int lname_len, int buf_len)
{
int rc;
int i;

/* NUL-terminate the Fortran string. */
lname[ lname_len] = '\0';
for (i=0;i
// printf( " freadlink : lname = %s lname_len = %d, buf_len = %d.\n", lname, lname_len, buf_len);

/* Get the link text. */
rc = readlink( lname, buf, buf_len);
// printf(" freadlink : rc = %d\n",rc);

// if the readlink fails, return the filename as the output
if (errno!=0) strcpy(buf,lname);

// printf("freadlink : %s\n",buf);
return rc;
}


!FORTRAN CODE NEEDED AS A FUNCTION
!$HP$ ALIAS FREADLINK = 'freadlink_' (%REF, %REF, %VAL, %VAL)
Character* 255 Function linkFileName(filename)
Character* (*) filename

integer * 4 rc
character * 255 buf
integer * 4 bufsiz
integer * 4 ilen

bufsiz=255
ilen=len(trim(filename))

rc=freadlink(filename,buf,ilen,bufsiz)
linkFileName=buf

End

CALLING FORTRAN PROGRAM
character * 80 filename
character * 255 linkfilename

filename='test.fil'
write(6,100) trim(linkfilename(filename))
100 format(' test.fil -> ',A)

end

If test.fil is a link file then the filename pointed so is printed, if test.fil is not a link file then test.fil is printed.

Thanks for the help !
Highlighted
Regular Advisor

Re: How to get filename a symbolic link points to from within Fortran

Created Fortran callable C routine to call readlink to get the file pointed to by a symbolic link. If the filename passed in is not a symbolic link file then the filename is passed back out as the output.
Highlighted
Regular Advisor

Re: How to get filename a symbolic link points to from within Fortran

As it turns out you must also remove the nulls from the returned parm or if you pass it through asa the output will not print out right.

!$HP$ ALIAS FREADLINK = 'freadlink_' (%REF, %REF, %VAL, %VAL)
Character* 255 Function linkFileName(filename)
Character* (*) filename

integer * 4 rc
character * 255 buf
integer * 4 bufsiz
integer * 4 ilen

bufsiz=255
ilen=len(trim(filename))

rc=freadlink(filename,buf,ilen,bufsiz)
do i=1,255
if (buf(i:i).eq.char(0)) buf(i:i)=' '
end do
linkFileName=buf

End
Highlighted
Regular Advisor

Re: How to get filename a symbolic link points to from within Fortran

Created Fortran callable C routine to call readlink to get the filename a symbolic link points to.
Highlighted
Honored Contributor

Re: How to get filename a symbolic link points to from within Fortran

> [...] you must also remove the nulls from
> the returned parm or if you pass it through
> asa [...]

Who's "asa"?

Or throw in another integer (C: int *)
argument, and pass the valid length back to
the caller (who then must avoid the invalid
residue). As usual, many things are
possible.

Irregardful, thanks for the report. I hadn't
seen the HP-Fortran-specific doo-dah before.
(I don't think that I ever needed to use a
"cDEC$", either, but I'd heard of that one.)
All very educational.