Use Return Value of GetEnvironmentStrings in Fortran

Use Return Value of GetEnvironmentStrings in Fortran

Hi: Is it possible to make use of the return value of the windows API call GetEnvironmentStrings()? It appears to return integer(LPSTR); but, I can't figure out how to convert this to a Fortran CHARACTER variable.

Thanks,
Allen

Allen
12 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

Use TRANSFER to convert the result to TYPE(C_PTR). Then compute the length via strlen() from MSVCRT.DLL and call a subroutine with those two results: call sub(ptr,length). The subroutine sub will have a local variable declared as character(length), pointer :: envstr and then call C_F_POINTER(ptr, envstr). Envstr now points at your string. You may want to consider GetEnvironmentVariable(); I think ifort does not yet support the GET_ENVIRONMENT_VARIABLE intrinsic.

(What RO said, but note that strlen will just give you the length of the first environment variable/value pair - you need to write your own variant that goes looking for the double null terminator. You can do that in Fortran using BIND(C) tricks.)

Thanks RO and IanH! With your help, I was able to access the contents. Even FreeEnvironmentStrings() appears to work with the coerced envptr variable.

Allen

I have made a small example how to obtain a string from the GetEnvironmentString function. The determination of the length of this string, in advance the C_F_POINTER operation, is unclear to me. Any idea how to solve this in a standard-comforming ways?

The GET_ENVIRONMENT_VARIABLE subroutine in Intel works fine (most recent update.)

Robert

Attachments: 

AttachmentSize
Downloadtext/plain ges.txt720 bytes

I would recommend using the Fortran standard intrinsic GET_ENVIRONMENT_VARIABLE, as Robert suggests.

Steve - Intel Developer Support

Just for fun, I made up an example that uses strlen to determine the length of the environment strings. Tested it with gfortran; I don't know what modifications env.f90 requires to function on ifort.

Attachments: 

AttachmentSize
Downloadtext/plain env.txt1.92 KB

Robert: Thanks! That's more or less what my code looks like. I don't like having to limit the size of the string; according to the MS documentation, the size of the evironment in windows 7 and later is essentially unlimited. I don't know what else to do without adopting RO's scheme.
Steve: Thanks, too! For diagnostic purposes, I need to see all the environment variables.
RO: Thanks again, too! Very clever. I think your declaration of GetEnvrionmentStrings as returning a C_PTR makes a bit more sense than the compiler's translation to integer(LPSTR).

Allen

The declaration as returning an integer predates Fortran 2003. Can't change it now, unfortunately. TRANSFER is your friend here.

Steve - Intel Developer Support

Allen: the reason to be worried on the length of the string and thus asks for a way to determine its length in advance is that I do not like to have arrays, strings etc. larger than needed. But it is not critical. And if you cannot find a \0\0 string, it is surely too short and must be reallocated.
Steve: I played some more with the intrinsic get_environment_variable and I found that problems arise if the length of the string that gets the value (second argument) is too short to store that value. I expect in that case the value argument to be truncated and the status argument (4th argument) to be set to -1, but I got severe error 408. Setting different compiler options does not resolve it. What is going wrong here? (See att. file)
Robert

Attachments: 

AttachmentSize
Downloadtext/plain gev.txt420 bytes

Sorry, I made an error in the example added with the previous post..
I wanted to print the result (value as a string) and in that line the error occurred because I tried to print that string with the length as given by the intrinsic. And that went wrong. It thus has nnoting to do with any error of get_environment_variable.

Robert

My previous example was less elegant than it could have been for two reasons. First, C_F_POINTER doesn't directly allow you to point at an assumed-size array, in fact there is no way to do so. However, the C function strlen() has the interface
size_t strlen(const char *str)
so you could write two styles of interface body for it:
interface strlen
function strlen1(str)
use ISO_C_BINDING
implicit none
integer(C_SIZE_T) strlen1
type(C_PTR), value :: str
end function strlen1
function strlen2(str)
use ISO_C_BINDING
implicit none
integer(C_SIZE_T) strlen1
character(kind=C_CHAR), intent(in) :: str(*)
end function strlen2
end interface strlen
Similarly one could write an implementation using either form. Accordingly, we have created a subroutine with the second form for implementation (but in Fortran, not C) and have written out an interface block that allows the compiler to invoke it either way at our discretion.
As a result, we have converted a type(C_PTR) value in the caller to an assumed-size array in the callee.
Another way would have been to use cray pointers, as they can point at an assumed-size array.

Second, we would like to point a deferred-length pointer at the memory pointed at by a variable of type(C_PTR), but again there is no syntax for achieving this directly.
Here, a three step process is necessary:
1) create a scope where the desired length is available as a specification expression and declare a scalar pointer of this length
2) point the pointer alluded to above at the memory via C_F_POINTER
3) point the deferred-length pointer at the previous pointer's target via pointer assignment.

I have created two examples, env3.f90 uses the multiple interface method to get the assumed-size array and a subroutine to create the new scope, while env4.f90 uses cray pointers to point at an assumed-size array and a BLOCK construct to create the new scope.
I don't know whether either will compile in ifort, you will just have to try.

Attachments: 

AttachmentSize
Downloadtext/plain env3.txt2.44 KB
Downloadtext/plain env4.txt1.5 KB

Leave a Comment

Please sign in to add a comment. Not a member? Join today