ユーザーが提供する OPEN プロシージャー: USEROPEN 指定子

インテル® Fortran の OPEN 文で USEROPEN 指定子を使用して、ファイルを直接開くルーチンに制御を渡すことができます。呼び出されるルーチンでは、システムコールまたはライブラリー・ルーチンを使用することで、ファイルを開き、後続のインテル® Fortran I/O 文の効果を変更する特別なコンテキストを確立することができます。

インテル® Fortran RTL I/O サポートルーチンでは、I/O のためにファイルが最初に開かれたときに通常使用されるシステムコールの代わりに、USEROPEN 関数を呼び出します。OPEN 文の USEROPEN 指定子では、制御を受け取る関数の名前を指定します。呼び出される関数は、ファイル (またはパイプ) を開いて、RTL に制御を戻す際にそのファイルのファイル記述子を返す必要があります。

ファイルを開く際に、呼び出される関数は、通常、標準の OPEN 文で指定されるものとは異なるオプションを指定します。

getfd ルーチンを使用して、インテル® Fortran RTL から特定のユニット番号のファイル記述子を取得することができます。

呼び出される関数は、C 以外の言語 (Fortran など) で記述することができますが、通常、open または create などのシステムコールの作成には、C 言語が最適です。

USEROPEN 指定子の構文および動作

OPEN 文の USEROPEN 指定子の形式は次のとおりです。

USEROPEN = function-name

function-name は外部関数の名前を示します。呼び出すプログラム側では、この関数は EXTERNAL 文で宣言する必要があります。例えば、次のインテル® Fortran コードを使用して、UOPEN という名前の USEROPEN プロシージャー (リンカーでは uopen_ として認識) を呼び出します。

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

OPEN 文が実行されると、uopen_ 関数は制御を受け取ります。関数はファイルを開き、指定された操作を実行し、そして RTL に制御 (およびファイル記述子) を返します。

USEROPEN 関数が C で記述されている場合、ファイル記述子を格納するために、この関数を 4 バイト整数 (int) の結果を返す C の関数として宣言します。次に例を示します。

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

次に、関数の定義およびインテル® Fortran RTL から渡される引数を示します。


  1. 関数は 4 バイト整数 (int) として宣言する必要があります。

  2. 第 1 引数は、開かれるパス名 (ファイル名を含む) です。

  3. オープンフラグについては、/usr/include/sys/file.h ヘッダーファイルまたは open(2) で説明されています。

  4. 作成モード (Linux* 形式のファイルの作成時に必要な保護) については、open(2) で説明されています。

  5. 第 4 引数は論理ユニット番号です。

  6. 最後の第 5 引数は、パス名の長さ (パス名の長さの隠し引数) です。

open システムコール (open(2) を参照) では、渡されたパス名、オープンフラグ (必要なアクセスタイプやファイルが存在するかどうかなどを定義)、および作成モードが必要です。OPEN 文で指定された論理ユニット番号は、USEROPEN 関数で必要となる場合に備えて渡されます。また、パス名の長さの隠し引数も渡されます。

新しいファイルを作成する場合、open システムコールの代わりに create システムコールを使用することができます (create(2) を参照)。通常は、USEROPEN 関数内でその他の適切なシステムコールまたはライブラリー・ルーチンを使用することができます。

ほとんどの場合、USEROPEN 関数はインテル® Fortran RTL によって渡されるオープンフラグ引数を変更するか、open (または create) システムコールの前に新しい値を使用します。関数は、ファイルを開いた後で RTL に制御を返す必要があります。

USEROPEN 関数が Fortran で記述されている場合、その関数を INTEGER (KIND=4) の結果 (場合によっては、インターフェイス・ブロック) を返す FUNCTION として宣言します。呼び出された関数は、RTL に 4 バイト整数のファイル記述子を返す必要があります。

C 言語を使用してファイルの開閉、およびすべてのレコード操作を行う必要があるアプリケーションでは、Fortran の OPEN 文を使用せずに、インテル® Fortran プログラムから適切な C プロシージャーを呼び出します。

呼び出された USEROPEN 関数の制限事項

インテル® Fortran RTL は、1 つの論理ユニットごとにファイル記述子を 1 つだけ使用します。ファイル記述子は、呼び出された関数によって返される必要があります。このため、ファイルを開く際に使用できるのは、特定のシステムコールまたはライブラリー・ルーチンだけです。

ファイル記述子を返さないシステムコールおよびライブラリー・ルーチンには、mknod (mknod(2) を参照) および fopen (fopen(3) を参照) があります。例えば、fopen ルーチンはファイル指定子の代わりにファイルポインターを返します。

USEROPEN プログラムおよび関数の例

次のインテル® Fortran コードは、UOPEN という名前の USEROPEN 関数を呼び出します。

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

UOPEN が Fortran 関数の場合は、Fortran の規則に基づいて名前が修飾されます。

UOPEN が C 関数の場合は、上記のコードに次の行が含まれている限り、C の規則に基づいて名前が修飾されます。

!DEC$ATTRIBUTES C::UOPEN

C およびインテル® Fortran プログラムのコンパイルとリンク

呼び出される C の uopen 関数 (uopen.c) は、icc または icl コマンドを使用してコンパイルします。インテル® Fortran の呼び出しプログラム (ex1.f) は、ifort コマンドを使用してコンパイルします。この ifort コマンドは、適切なライブラリーを使用することで、両方のオブジェクト・ファイルをリンクします。

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

ソースコード例

      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 or MAC OS X
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! Here is the UOPEN function for Linux/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
! 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/MAC OS X
      P = INDEX(FullName,'/',.TRUE.)
      FileName = FullName(P+1:)
!DEC$ ENDIF
      END