Visible to Intel only — GUID: GUID-88ADA710-6CB9-4640-8381-DA2BCF3F564C
Visible to Intel only — GUID: GUID-88ADA710-6CB9-4640-8381-DA2BCF3F564C
Use USEROPEN to Pass Control To a Routine
You can use the USEROPEN specifier in an 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 may establish special context that changes the effect of subsequent I/O statements.
The Intel® Fortran runtime library (RTL) I/O support routines call the USEROPEN function in place of the system calls that are 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 a file (or pipe) and return the file descriptor of the file (or pipe) it has opened when control is returned to the RTL. The called function may specify different options when it opens the file than a normal OPEN statement would. It may specify a different file.
You can use the PXFFILENO routine to get the file descriptor from the RTL for a specific unit number.
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.
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.
If a file name was specified in the OPEN statement that included the USEROPEN specifier, any subsequent CLOSE statement specifying STATUS=DELETE (or DISPOSE=DELETE) only acts on the file name specified in the OPEN statement.
If you specified a different file name in the function named in USEROPEN, the CLOSE statement will have no effect on that file name.
Syntax and Behavior
The USEROPEN specifier for the OPEN statement has the form:
USEROPEN = function-name
The function-name represents the name of an external function. The external function can be written in Fortran, C, or other languages.
The return value is the file descriptor, which takes the following form:
Linux and macOS
It is a 4-byte integer on both 32-bit and 64-bit system.
Windows
It is a 4-byte integer on 32-bit systems and an 8-byte integer on 64-bit systems.
If an error occurs in the function, file descriptor returns -1.
Declarations depend on the language that the function is written in:
If the USEROPEN function is written in C, declare it as a C function.
If the USEROPEN function is written in Fortran, declare it as a FUNCTION, perhaps with an interface block.
In the calling program, the function must be declared in an EXTERNAL statement. For example, the following Intel® Fortran code can 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 execution of the OPEN statement, the external procedure called uopen_ receives control. The function opens the file, may perform other operations, and subsequently returns control (with the file descriptor) to the RTL. You can use other 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 it uses a new value before the open (or create) system call. After the function opens the file, it must return control to the RTL.The following shows the available arguments and definitions.
Linux and macOS
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:
The function must be declared as a 4-byte integer (int).
Indicates the pathname to be opened; the pathname includes the file name.
Indicates the open flags. The open flags are described in the header file /usr/include/sys/file.h or open(2).
Indicates the create mode, which is the protection needed when creating a Linux* OS-style file. The create modes are described in open(2).
Indicates the logical unit number.
Indicates the pathname length (hidden character length argument of the pathname).
The open system call (see open(2)) requires the passed pathname, the open flags (which define the type of 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 character length of the pathname is also passed.
Windows
int uopen_ ( (1) char *filename, (2) int *desired_access, (3) int *share_mode, (4) int a_null, /* always 0 */ (5) int *flags_attr, (6) int b_null, /* always 0 */ (7) int *unit, (8) int [*]flen); (9)
The function definition and the arguments passed from the Intel® Fortran RTL are as follows:
The function must be declared as a 4-byte integer (int) on 32-bit systems and an 8-byte integer (long long int) on 64-bit systems.
Indicates the pathname to be opened; the pathname includes the file name.
Indicates the mode of access. It can be set to read, write, or read/write.
Indicates the file protection mode.
This line indicates a NULL that is passed as a literal zero by value.
This sets flags that specify file modes and several kinds of file features, such as whether to use sequential access or random access, whether to delete on close, etc.
This line indicates a NULL that is passed as a literal zero by value.
Indicates the logical unit number.
Indicates the pathname length (the hidden character length argument of the pathname).
The argument list for a USEROPEN routine on Windows is very similar to the argument list for the Microsoft* Windows function CreateFile. This lets you easily write a USEROPEN routine and pass the input arguments to a call to CreateFile. The CreateFile system call requires the file name, the desired_access, the shared_mode, and the flags_attr. These arguments have been set to reflect the file semantics requested in the OPEN statement.
The logical unit number specified in the OPEN statement is passed in case the USEROPEN function needs it. The hidden character length of the pathname is also passed.
On 32-bit systems, a Fortran USEROPEN function must use the default "C, Reference" calling convention. If you have used the iface compiler option to change the default calling convention to stdcall or cvf, you will need to add a !DIR$ ATTRIBUTES DEFAULT directive in the function source to have it use the correct calling convention.
Restrictions
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.
On Linux* systems, 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.
The following 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:
!DIR$ ATTRIBUTES C::UOPEN
Examples
The following examples demonstrate how to use the USEROPEN specifier to pass control.
Linux and macOS
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 != -1 is a valid file descriptor
** value == -1 is returned on 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");
return_value = -1;
} else {
printf("SUCCEEDED.\n");
}
return (return_value);
} /* end of uopen_() */
Windows
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 runtime library declaration of a USEROPEN routine.
The following function definition and arguments are passed from the Fortran runtime 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 to 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 the action to take on files that exist, and the action to take on files that do not exist. The value is passed by reference. |
FLAGS_ATTR |
Specifies the file attributes and flags for the file. The value 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 its 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. The value is passed by reference. |
FLEN |
Is the length of the file name, not counting the terminating null, and passed by value. |