User-Supplied OPEN Procedures: USEROPEN Specifier

You can use the USEROPEN specifier in an Intel Fortran OPEN statement to pass control to a routine that directly opens a file. The called routine can use system calls or library routines to open the file and establish special context that changes the effect of subsequent Intel Fortran I/O statements.

The Intel Fortran RTL I/O support routines call the USEROPEN function in place of the system calls usually used when the file is first opened for I/O. The USEROPEN specifier in an OPEN statement specifies the name of a function to receive control. The called function must open the file (or pipe) and return the file descriptor of the file when it returns control to the RTL.

When opening the file, the called function usually specifies options different from those provided by a normal OPEN statement.

You can obtain the file descriptor from the Intel Fortran RTL for a specific unit number with the getfd routine.

Although the called function can be written in other languages (such as Fortran), C is usually the best choice for making system calls, such as open or create.

Syntax and Behavior of the USEROPEN Specifier

The USEROPEN specifier for the OPEN statement has the form:

USEROPEN = function-name

function-name represents the name of an external function. In the calling program, the function must be declared in an EXTERNAL statement. For example, the following Intel Fortran code might be used to call the USEROPEN procedure UOPEN (known to the linker as uopen_):

EXTERNAL UOPEN INTEGER UOPEN . . . OPEN (UNIT=10, FILE='/usr/test/data', STATUS='NEW', USEROPEN=UOPEN)

During the OPEN statement, the uopen_function receives control. The function opens the file, may perform other operations, and subsequently returns control (with the file descriptor) to the RTL.

If the USEROPEN function is written in C, declare it as a C function that returns a 4-byte integer (int) result to contain the file descriptor. For example:

int uopen_ ( (1) char *file_name, (2) int *open_flags, (3) int *create_mode, (4) int *lun, (5) int file_length); (6)

The function definition and the arguments passed from the Intel Fortran RTL are as follows:


  1. The function must be declared as a 4-byte integer (int).

  2. The first argument is the pathname (includes the file name) to be opened.

  3. The open flags are described in the header file /usr/include/sys/file.h or open(2).

  4. The create mode (protection needed when creating a Linux* OS-style file) is described in open(2).

  5. The fourth argument is the logical unit number.

  6. The fifth (last) argument is the pathname length (hidden length argument of the pathname).

Of the arguments, the open system call (see open(2)) requires the passed pathname, the open flags (that define the type access needed, whether the file exists, and so on), and the create mode. The logical unit number specified in the OPEN statement is passed in case the USEROPEN function needs it. The hidden length of the pathname is also passed.

When creating a new file, the create system call might be used in place of open (see create(2)). You can usually use other appropriate system calls or library routines within the USEROPEN function.

In most cases, the USEROPEN function modifies the open flags argument passed by the Intel Fortran RTL or uses a new value before the open (or create) system call. After the function opens the file, it must return control to the RTL.

If the USEROPEN function is written in Fortran, declare it as a FUNCTION with an INTEGER (KIND=4) result, perhaps with an interface block. In any case, the called function must return the file descriptor as a 4-byte integer to the RTL.

If your application requires that you use C to perform the file open and close, as well as all record operations, call the appropriate C procedure from the Intel Fortran program without using the Fortran OPEN statement.

Restrictions of Called USEROPEN Functions

The Intel Fortran RTL uses exactly one file descriptor per logical unit, which must be returned by the called function. Because of this, only certain system calls or library routines can be used to open the file.

System calls and library routines that do not return a file descriptor include mknod (see mknod(2)) and fopen (see fopen(3)). For example, the fopen routine returns a file pointer instead of a file descriptor.

Example USEROPEN Program and Function

The following Intel Fortran code calls the USEROPEN function named UOPEN:

EXTERNAL UOPEN INTEGER UOPEN . . . OPEN (UNIT=1,FILE='ex1.dat',STATUS='NEW',USEROPEN=UOPEN, ERR=9,IOSTAT=errnum)

If UOPEN is a Fortran function, its name is decorated appropriately for Fortran.

Likewise, if UOPEN is a C function, its name is decorated appropriately for C, as long as the following line is included in the above code:

!DEC$ATTRIBUTES C::UOPEN

Compiling and Linking the C and Intel Fortran Programs

Use the icc or icl command to compile the called uopen C function uopen.c and the ifort command to compile the Intel Fortran calling program ex1.f. The same ifort command also links both object files by using the appropriate libraries:

icc -c uopen.c (Linux* OS) icl -c uopen.c (Windows* OS) ifort ex1.f uopen.o

Example Source Code

program UserOpenSample !DEC$ FREEFORM IMPLICIT NONE EXTERNAL UOPEN INTEGER(4) UOPEN CHARACTER*10 :: FileName="UOPEN.DAT" INTEGER*4 :: IOS Character*255 :: InqFullName Character*100 :: InqFileName Integer :: InqLun Character*30 :: WriteOutBuffer="Write_One_Record_to_the_File. " Character*30 :: ReadInBuffer ="??????????????????????????????" 110 FORMAT( X,A, ": Created (iostat=",I0,")") 115 FORMAT( X,A, ": Creation Failed (iostat=",I0,")") 120 FORMAT( X,A, ": ERROR: INQUIRE Returned Wrong FileName") 130 FORMAT( X,A, ": ERROR: ReadIn and WriteOut Buffers Do Not Match") 190 FORMAT( X,A, ": Completed.") WRITE(*,'(X,"Test the USEROPEN Facility of Open")') OPEN(UNIT=10,FILE='UOPEN.DAT',STATUS='REPLACE',USEROPEN=UOPEN, & IOSTAT=ios, ACTION='READWRITE') ! When the OPEN statement is executed, ! the UOPEN function receives control. ! The function opens the file by calling CreateFile( ), ! performs whatever operations were specified, and subsequently ! returns control (with the handle returned by CreateFile( )) ! to the calling Fortran program. IF (IOS .EQ. 0) THEN WRITE(*,110) TRIM(FileName), IOS INQUIRE(10, NAME=InqFullName) CALL ParseForFileName(InqFullName,InqFileName) IF (InqFileName .NE. FileName) THEN WRITE(*,120) TRIM(FileName) END IF ELSE WRITE(*,115) TRIM(FileName), IOS GOTO 9999 END IF WRITE(10,*) WriteOutBuffer REWIND(10) READ(10,*) ReadInBuffer IF (ReadinBuffer .NE. WriteOutbuffer) THEN WRITE(*,130) TRIM(FileName) END IF CLOSE(10, DISPOSE='DELETE') WRITE(*,190) TRIM(FileName) WRITE(*,'(X,"Test of USEROPEN Completed")') 9999 CONTINUE END !DEC$ IF DEFINED(_WIN32) !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! Here is the UOPEN function for WIN32: ! ! The UOPEN function is declared to use the cdecl calling convention, ! so it matches the Fortran rtl declaration of a useropen routine. ! ! The following function definition and arguments are passed from the Intel ! Fortran Run-time Library to the function named in USEROPEN: ! ! The first 7 arguments correspond to the CreateFile( ) api arguments. ! The value of these arguments is set according the caller's OPEN( ) ! arguments: ! ! FILENAME ! Is the address of a null terminated character string that ! is the name of the file. ! DESIRED_ACCESS ! Is the desired access (read-write) mode passed by reference. ! SHARE_MODE ! Is the file sharing mode passed by reference. ! A_NULL ! Is always null. The Fortran runtime library always passes a NULL ! for the pointer to a SECURITY_ATTRIBUTES structure in its ! CreateFile( ) call. ! CREATE_DISP ! Is the creation disposition specifying what action to take on files ! that exist, and what action to take on files ! that do not exist. It is passed by reference. ! FLAGS_ATTR ! Specifies the file attributes and flags for the file. It is passed ! by reference. ! B_NULL ! Is always null. The Fortran runtime library always passes a NULL ! for the handle to a template file in it's CreateFile( ) call. ! The last 2 arguments are the Fortran unit number and length of the ! file name: ! UNIT ! Is the Fortran unit number on which this OPEN is being done. It is ! passed by reference. ! FLEN ! Is the length of the file name, not counting the terminating null, ! and passed by value. !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ INTEGER(4) FUNCTION UOPEN( FILENAME, & DESIRED_ACCESS, & SHARE_MODE, & A_NULL, & CREATE_DISP, & FLAGS_ATTR, & B_NULL, & UNIT, & FLEN ) !DEC$ ATTRIBUTES C, DECORATE, ALIAS:'UOPEN' :: UOPEN !DEC$ATTRIBUTES REFERENCE :: FILENAME !DEC$ATTRIBUTES REFERENCE :: DESIRED_ACCESS !DEC$ATTRIBUTES REFERENCE :: SHARE_MODE !DEC$ATTRIBUTES REFERENCE :: CREATE_DISP !DEC$ATTRIBUTES REFERENCE :: FLAGS_ATTR !DEC$ATTRIBUTES REFERENCE :: UNIT USE KERNEL32 IMPLICIT NONE INTEGER*4 DESIRED_ACCESS INTEGER*4 SHARE_MODE INTEGER*4 A_NULL INTEGER*4 CREATE_DISP INTEGER*4 FLAGS_ATTR INTEGER*4 B_NULL INTEGER*4 UNIT INTEGER*4 FLEN CHARACTER*(FLEN) FILENAME INTEGER(4) ISTAT TYPE(T_SECURITY_ATTRIBUTES), POINTER :: NULL_SEC_ATTR 140 FORMAT( X, "ERROR: USEROPEN Passed Wrong Unit Number",I) ! Sanity check IF (UNIT .NE. 10) THEN WRITE(*,140) UNIT END IF !! WRITE(*,*) "FILENAME=",FILENAME !! prints the full path of the filename ! Set the FILE_FLAG_WRITE_THROUGH bit in the flag attributes to CreateFile( ) ! (for whatever reason) ! FLAGS_ATTR = FLAGS_ATTR + FILE_FLAG_WRITE_THROUGH ! Do the CreateFile( ) call and return the status to the Fortran rtl ISTAT = CreateFile( FILENAME, & DESIRED_ACCESS, & SHARE_MODE, & NULL_SEC_ATTR, & CREATE_DISP, & FLAGS_ATTR, & 0 ) if (ISTAT == INVALID_HANDLE_VALUE) then write(*,*) "Could not open file (error ", GetLastError(),")" endif UOPEN = ISTAT RETURN END !DEC$ ELSE ! LINUX OS or MAC OS X !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! Here is the UOPEN function for Linux OS/Mac OS X: ! ! The UOPEN function is declared to use the cdecl calling convention, ! so it matches the Fortran rtl declaration of a useropen routine. ! ! The following function definition and arguments are passed from the ! Intel Fortran Run-time Library to the function named in USEROPEN: ! ! FILENAME ! Is the address of a null terminated character string that ! is the name of the file. ! OPEN_FLAGS ! read-write flags (see file.h or open(2)). ! CREATE_MODE ! set if new file (to be created). ! UNIT ! Is the Fortran unit number on which this OPEN is being done. It is ! passed by reference. ! FLEN ! Is the length of the file name, not counting the terminating null, ! and passed by value. !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ INTEGER FUNCTION UOPEN( FILENAME, & OPEN_FLAGS, & CREATE_MODE, & UNIT, & FLEN ) !DEC$ATTRIBUTES C, DECORATE, ALIAS:'uopen' :: UOPEN !DEC$ATTRIBUTES REFERENCE :: FILENAME !DEC$ATTRIBUTES REFERENCE :: OPEN_FLAGS !DEC$ATTRIBUTES REFERENCE :: CREATE_MODE !DEC$ATTRIBUTES REFERENCE :: UNIT IMPLICIT NONE INTEGER*4 OPEN_FLAGS INTEGER*4 CREATE_MODE INTEGER*4 UNIT INTEGER*4 FLEN CHARACTER*(FLEN) FILENAME INTEGER*4 ISTAT !DEC$ATTRIBUTES C, DECORATE, ALIAS:'open' :: OPEN external OPEN integer*4 OPEN 140 FORMAT( X, "ERROR: USEROPEN Passed Wrong Unit Number",I) ! Sanity check IF (UNIT .NE. 10) THEN WRITE(*,140) UNIT END IF ! Call the system OPEN routine ISTAT = OPEN ( %ref(FILENAME), & OPEN_FLAGS, & CREATE_MODE ) UOPEN = ISTAT RETURN END !DEC$ ENDIF ! End of UOPEN Function !--------------------------------------------------------------- ! SUBROUTINE: ParseForFileName ! Takes a full pathname and retuns the filename ! with its extension. !--------------------------------------------------------------- SUBROUTINE ParseForFileName(FullName,FileName) Character*255 :: FullName Character*100 :: FileName Integer :: P !DEC$ IF DEFINED(_WIN32) P = INDEX(FullName,'\',.TRUE.) FileName = FullName(P+1:) !DEC$ ELSE ! LINUX OS/MAC OS X P = INDEX(FullName,'/',.TRUE.) FileName = FullName(P+1:) !DEC$ ENDIF END