Intel® Fortran Compiler 18.0 Developer Guide and Reference

OPEN: USEROPEN Specifier

The USEROPEN specifier lets you pass control to a routine that directly opens a file. The file can use system calls or library routines to establish a special context that changes the effect of subsequent Fortran I/O statements.

The USEROPEN specifier takes the following form:

USEROPEN = function-name

function-name

Is the name of an external function of type INTEGER(INT_PTR_KIND()) on Windows and INTEGER(4) on Linux and macOS*. The external function can be written in Fortran, C, or other languages.

If the function is written in Fortran, do not execute a Fortran OPEN statement to open the file named in USEROPEN.

The Intel® Fortran Run-time Library (RTL) I/O support routines call the function named in USEROPEN in place of the system calls normally used when the file is first opened for I/O.

On Windows* systems, the Fortran RTL normally calls CreateFile( ) to open a file. When USEROPEN is specified, the called function opens the file (or pipe, etc.) by using CreateFile( ) and returns the handle of the file (return value from CreateFile( )) when it returns control to the calling Fortran program.

On Linux* and macOS* systems, the Fortran RTL normally calls the open function to open a file. When USEROPEN is specified, the called function opens the file by calling open and returns the file descriptor of the file when it returns control to the calling Fortran program.

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

NOTE

You may get unexpected results if you specify OPEN with a filename and a USEROPEN specifier that opens a different filename, and then use a CLOSE statement with STATUS=DELETE (or DISPOSE=DELETE). In this case, the run-time library assumes you want to delete the file named in the OPEN statement, not the one you specified in the USEROPEN function. For more information about how to use the USEROPEN specifier, see User-Supplied OPEN Procedures/USEROPEN Specifier.

Examples

The following shows an example on Linux and macOS* systems and an example on Windows systems.

Example on Linux and macOS* systems:


      PROGRAM UserOpenMain
      IMPLICIT NONE

      EXTERNAL      UOPEN
      INTEGER(4)    UOPEN

      CHARACTER(10) :: FileName="UOPEN.DAT"
      INTEGER       :: IOS
      CHARACTER(255):: InqFullName
      CHARACTER(100):: InqFileName
      INTEGER       :: InqLun
      CHARACTER(30) :: WriteOutBuffer="Write_One_Record_to_the_File. "
      CHARACTER(30) :: ReadInBuffer  ="??????????????????????????????"

110   FORMAT( X,"FortranMain: ",A," Created (iostat=",I0,")")
115   FORMAT( X,"FortranMain: ",A,": Creation Failed (iostat=",I0,")")
120   FORMAT( X,"FortranMain: ",A,": ERROR: INQUIRE Returned Wrong FileName")
130   FORMAT( X,"FortranMain: ",A,": ERROR: ReadIn and WriteOut Buffers Do Not Match")

      WRITE(*,'(X,"FortranMain: 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 uopen_ function opens the file by calling open(), and subsequently
!     returns control with the handle returned by open().

      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)
      WRITE(*,'(X,"FortranMain: Test of USEROPEN Completed")')

9999  CONTINUE
      END

!---------------------------------------------------------------
! SUBROUTINE: ParseForFileName
!             Takes a full pathname and returns the filename
!             with its extension. 
!---------------------------------------------------------------
      SUBROUTINE ParseForFileName(FullName,FileName)

      CHARACTER(255):: FullName
      CHARACTER(255):: FileName
      INTEGER       :: P

      P = INDEX(FullName,'/',.TRUE.)
      FileName = FullName(P+1:)

      END

//
// File: UserOpen_Sub.c
//
// This routine opens a file using data passed from the Intel(c) Fortran OPEN statement.
//

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <errno.h>
int uopen_ ( char *file_name,   /* access read: name of the file to open (null terminated) */
             int  *open_flags,  /* access read: READ/WRITE, see file.h or open(2) */
             int  *create_mode, /* access read: set if the file is to be created */
             int  *unit_num,    /* access read: logical unit number to be opened */
             int  filenam_len ) /* access read: number of characters in file_name */
{
    /*
    ** The returned value is the following:
    **    value >= 0 is a valid file descriptor
    **    value < 0 is an error
    */
    int return_value;

    printf(" %s: Opening FILENAME = %s\n", __FILE__, file_name);
    printf(" %s: open_flags = 0x%8.8x\n", __FILE__, *open_flags);
    if ( *open_flags & O_CREAT ) {
        printf(" %s: the file is being created, create_mode = 0x%8.8x\n", __FILE__, *create_mode);
    }

    printf(" %s: open() ", __FILE__);
    return_value = open(file_name, *open_flags, *create_mode);
    if (return_value < 0) {
        printf("FAILED.\n");
    } else {
        printf("SUCCEEDED.\n");
    }

    return (return_value);
} /* end of uopen_() */
Example on Windows systems:

In the calling Fortran program, the function named in USEROPEN must first be declared in an EXTERNAL statement. For example, the following Fortran code might be used to call the USEROPEN procedure UOPEN:

  IMPLICIT INTEGER (A-Z)
  EXTERNAL UOPEN
  INTEGER(INT_PTR_KIND()) UOPEN
  ...
  OPEN(UNIT=10,FILE='UOPEN.DAT',STATUS='NEW',USEROPEN=UOPEN)

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.

Here is what the UOPEN function might look like:


        INTEGER(INT_PTR_KIND()) FUNCTION UOPEN( FILENAME,      &
                                DESIRED_ACCESS, &
                                SHARE_MODE,     &
                                A_NULL,         &
                                CREATE_DISP,    &
                                FLAGS_ATTR,     &
                                B_NULL,         &
                                UNIT,           &
                                FLEN )
        !DIR$ ATTRIBUTES C, ALIAS:'_UOPEN' :: UOPEN
        !DIR$ ATTRIBUTES REFERENCE :: FILENAME
        !DIR$ ATTRIBUTES REFERENCE :: DESIRED_ACCESS
        !DIR$ ATTRIBUTES REFERENCE :: SHARE_MODE
        !DIR$ ATTRIBUTES REFERENCE :: CREATE_DISP
        !DIR$ ATTRIBUTES REFERENCE :: FLAGS_ATTR
        !DIR$ ATTRIBUTES REFERENCE :: UNIT

        USE IFWIN
        IMPLICIT INTEGER (A-Z)
        CHARACTER*(FLEN) FILENAME
        TYPE(T_SECURITY_ATTRIBUTES), POINTER :: NULL_SEC_ATTR

! 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
        STS = CreateFile( FILENAME,             &
                          DESIRED_ACCESS,       &
                          SHARE_MODE,           &
                          NULL_SEC_ATTR,        &
                          CREATE_DISP,          &
                          FLAGS_ATTR,           &
                          0 )

        UOPEN = STS
        RETURN
        END

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:


        INTEGER(INT_PTR_KIND()) FUNCTION UOPEN( FILENAME,       &
                               DESIRED_ACCESS, &
                               SHARE_MODE,     &
                               A_NULL,         &
                               CREATE_DISP,    &
                               FLAGS_ATTR,     &
                               B_NULL,         &
                               UNIT,           &
                               FLEN )
        !DIR$ ATTRIBUTES C, ALIAS:'_UOPEN' :: UOPEN
        !DIR$ ATTRIBUTES REFERENCE :: DESIRED_ACCESS
        !DIR$ ATTRIBUTES REFERENCE :: SHARE_MODE
        !DIR$ ATTRIBUTES REFERENCE :: CREATE_DISP
        !DIR$ ATTRIBUTES REFERENCE :: FLAGS_ATTR
        !DIR$ ATTRIBUTES REFERENCE :: UNIT

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.

See Also