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 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 the default ifort options are used, the external name is passed using lowercase letters with an appended trailing underscore (_). In the preceding example, the external function UOPEN would be known as uopen_ to the linker and must be declared in C as uopen_.

Compiling and Linking the C and Intel Fortran Programs

Use the icc 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 to create the file a.out file, as follows:

icc -c uopen_.c
ifort ex1.f uopen_.o

Source Code for the C Function and Header File

The following example shows the C language function called uopen_ and its associated header file.

/*

** File: uopen.h -- header file for uopen_.c
*/

#ifndef UOPEN
#define UOPEN 1
/*
**
**    Function Prototypes
**
*/
int   uopen_ (
     char  *file_name,    /* access read: name of the file to open. */
     int   *open_flags,   /* access read: READ/WRITE, see file.h or open(2)*/
     int   *create_mode,  /* access read: set if new file (to be created).*/
     int   *lun,          /* access read: logical unit file opened on.*/
     int  file_length);   /* access read: number of characters in file_name*/

#endif

/* End of file uopen.h */

/*
** File: uopen_.c
*/

/*
** This routine opens a file using data passed by Intel Fortran RTL.
**
**  INCLUDE FILES
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include "uopen.h"/* Include file for this module */

int uopen_ (file_name, open_flags, create_mode, lun, file_length)

/*
** Open a file using the parameters passed by the calling Intel
**   Fortran program.
**
**  Formal Parameters:
*/

char  *file_name;    /* access read: name of the file to open. */
int   *open_flags;   /* access read: READ/WRITE, see file.h */
int   *create_mode;  /* access read: set if new file (to be created). */
int   *lun;          /* access read: logical unit number file opened on. */
int   file_length;   /* access read: number of characters in file_name. */

/*
**  Function Value/Completion Code
**
** Whatever is returned by open is immediately returned to the
** Fortran OPEN.  The returned value is the following:
**    value >= 0 is a valid fd.
**    value <  0 is an error.
**
**  Modify open flags (logical OR) to specify the file be opened for
**  write access only, with records appended at the end (such as
**  writing to a shared log file).
*/

{
      int    result ;           /* Function result value */

      *open_flags =                 
            O_CREAT  |
            O_WRONLY |
            O_APPEND;

     result = open (file_name, *open_flags, *create_mode) ;

      return (result) ;         /* return file descriptor or error */

      }/* End of routine uopen_ */

     /* End of file uopen_.c */

Source Code for the Calling Intel Fortran Program

The following example shows the Fortran program that calls the uopen_ C function and then performs I/O.

!
!  Program EX1 opens a file using USEROPEN and writes records to it.
!  It closes and re-opens the file (without USEROPEN) and reads 10 records.
PROGRAM EX1

    EXTERNAL    UOPEN         ! The USEROPEN function.
    INTEGER     ERRNUM, CTR, I

1   FORMAT (I)
    ERRNUM = 0
    WRITE (6,*) 'EX1. Access data using formatted I/O.'
    WRITE (6,*) 'EX1. Open file with USEROPEN and put some data in it.'

   OPEN (UNIT=1, FILE='ex1.dat', STATUS='NEW', USEROPEN=UOPEN, ERR=9,IOSTAT=errnum)
    DO CTR=1,10
     WRITE (1,1) CTR
    END DO
    WRITE (6,*) 'EX1. Close and re-open without USEROPEN.'
    CLOSE (UNIT=1)
    OPEN (UNIT=1, FILE='ex1.dat', STATUS='OLD', FORM='FORMATTED', ERR=99, IOSTAT=errnum)
    WRITE (6,*) 'EX1. Read and display what is in file.'
    DO CTR=1,10
       READ (1,1) i
       WRITE (6,*) i
    END DO
    WRITE (6,*) 'EX1.  Successful if 10 records shown.'
    CLOSE (UNIT=1,STATUS='DELETE')
    STOP
  9 WRITE (6,*) 'EX1.  Error on USEROPEN is ', errnum
    STOP
 99 WRITE (6,*) 'EX1.  Error on 2nd open is ', errnum
END PROGRAM EX1