Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.

Use Return Value of GetEnvironmentStrings in Fortran

Allen_Barnett
Beginner
2,698 Views

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

0 Kudos
11 Replies
JVanB
Valued Contributor II
2,698 Views
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.
0 Kudos
IanH
Honored Contributor III
2,698 Views
(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.)
0 Kudos
Allen_Barnett
Beginner
2,698 Views
Thanks RO and IanH! With your help, I was able to access the contents. Even FreeEnvironmentStrings() appears to work with the coerced envptr variable.
0 Kudos
Robert_van_Amerongen
New Contributor III
2,698 Views
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
0 Kudos
Steven_L_Intel1
Employee
2,698 Views
I would recommend using the Fortran standard intrinsic GET_ENVIRONMENT_VARIABLE, as Robert suggests.
0 Kudos
JVanB
Valued Contributor II
2,698 Views
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.
0 Kudos
Allen_Barnett
Beginner
2,698 Views
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).
0 Kudos
Steven_L_Intel1
Employee
2,698 Views
The declaration as returning an integer predates Fortran 2003. Can't change it now, unfortunately. TRANSFER is your friend here.
0 Kudos
Robert_van_Amerongen
New Contributor III
2,698 Views
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
0 Kudos
Robert_van_Amerongen
New Contributor III
2,698 Views
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
0 Kudos
JVanB
Valued Contributor II
2,698 Views
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.
0 Kudos
Reply