インテル® Fortran コンパイラー 19.0 デベロッパー・ガイドおよびリファレンス

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

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

インテル® Fortran ランタイム・ライブラリー (RTL) の I/O サポートルーチンでは、I/O のためにファイルが最初に開かれたときに通常使用されるシステムコールの代わりに、USEROPEN 関数を呼び出します。OPEN 文の USEROPEN 指定子では、制御を受け取る関数の名前を指定します。

呼び出される関数は、ファイル (またはパイプ) を開いて、RTL に制御を戻す際にそのファイル (またはパイプ) のファイル記述子を返す必要があります。ファイルを開く際に、呼び出される関数は、標準の OPEN 文で指定されるものとは異なるオプションを指定したり、異なるファイルを指定することがあります。

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

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

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

USEROPEN 指定子を含む OPEN 文でファイル名が指定されると、STATUS=DELETE (または DISPOSE=DELETE) を指定する後続の CLOSE 文は、OPEN 文で指定されたファイル名に対してのみ適用されます。USEROPEN 文の名前付き関数で異なるファイル名を指定した場合、CLOSE 文はそのファイル名に対して効果がありません。

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 関数内でその他のシステムコールまたはライブラリー・ルーチンを使用することができます。

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

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

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

次に、Linux* および macOS*、Windows* で利用可能な引数と定義を示します。

Linux* および macOS* の引数と定義:

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

Linux* および macOS* において、インテル® Fortran RTL から渡される関数の定義と引数は次のとおりです。

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

  2. 開くパス名 (ファイル名を含む) を指定します。

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

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

  5. 論理ユニット番号を指定します。

  6. パス名の長さ (パス名の文字長の隠し引数) を指定します。

Linux* および macOS* の引数に関する注意事項:

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

Windows* の引数と定義:

int uopen_ (                              (1)
char   *filename,                         (2)
int    *desired_access,                   (3)
int    *share_mode,                       (4)
int     a_null,          /* 常に 0 */   (5)
int    *flags_attr,                       (6) 
int     b_null,          /* 常に 0 */   (7)
int    *unit,                             (8)
int    *flen);                            (9)

Windows* において、インテル® Fortran RTL から渡される関数の定義と引数は次のとおりです。

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

  2. 開くパス名 (ファイル名を含む) を指定します。

  3. アクセスモードを指定します。読み取り、書き込み、または読み取り/書き込みを指定できます。

  4. ファイルの保護モードを指定します。

  5. NULL の場合、文字ゼロとして値渡しされます。

  6. これは、ファイルモードといくつかのファイル機能 (シーケンシャル・アクセスかランダムアクセスか、閉じるときに削除するかどうかなど) を指定するフラグを設定します。

  7. NULL の場合、文字ゼロとして値渡しされます。

  8. 論理ユニット番号を指定します。

  9. パス名の長さ (パス名の文字長の隠し引数) を指定します。

Windows* の引数に関する注意事項:

Windows* では、USEROPEN ルーチンの引数リストは、Microsoft* Windows* の CreateFile 関数の引数リストとよく似ています。そのため、簡単に USEROPEN ルーチンを記述し、入力引数を CreateFile の呼び出しに渡すことができます。CreateFile システムコールには、filename、desired_access、shared_mode、flags_attr が必要です。これらの引数は、OPEN 文で必要なファイルのセマンティクスに対応しています。OPEN 文で指定された論理ユニット番号は、USEROPEN 関数で必要となる場合に備えて渡されます。また、パス名の文字長の隠し引数も渡されます。

32 ビットの Windows* では、Fortran の USEROPEN 関数はデフォルトの "C、REFERENCE" 呼び出し規約を使用しなければなりません。iface コンパイラー・オプションでデフォルトの呼び出し規約を "stdcall" または "cvf" に変更した場合は、関数のソースに !DIR$ ATTRIBUTES DEFAULT ディレクティブを追加して、正しい呼び出し規約が使用されるようにする必要があります。

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

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

Linux* では、ファイル記述子を返さないシステムコールおよびライブラリー・ルーチンとして、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 の規則に基づいて名前が修飾されます。

!DIR$ 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
      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')
     
!     OPEN 文が実行されると、UOPEN 関数が制御を受け取ります。
!     この関数は CreateFile( ) を呼び出してファイルを開き、
!     指定された操作を行ってから呼び出しプログラムに制御
!     (および CreateFile( ) によって返されたハンドル) を返します。
      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
!DIR$ IF DEFINED(_WIN32)
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! WIN32 用の UOPEN 関数:
! 
! UOPEN 関数はデフォルトの呼び出し規約を使用するように宣言されているため、
! Fortran RTL の USEROPEN ルーチンの宣言と一致します。
! 
! 次の関数定義と引数がインテル® Fortran ランタイム・ライブラリーから
! USEROPEN の名前付き関数に渡されます。
! 
! 最初の 7 つの引数は CreateFile( ) API 引数に対応しています。
! これらの引数の値は呼び出し元の OPEN( ) 引数に応じて設定されます。
! 
! FILENAME
!      ファイル名を示す NULL で終わる文字列のアドレス
! DESIRED_ACCESS
!      参照で渡されるアクセス (読み取り/書き込み) モード
! SHARE_MODE
!      参照で渡されるファイルの共有モード
! A_NULL
!      常に NULL。Fortran ランタイム・ライブラリーは
!      CreateFile( ) 呼び出しの SECURITY_ATTRIBUTES 構造体への
!      ポインターに対して常に NULL を渡します。
! CREATE_DISP
!      作成時の処理。ファイルが既に存在する場合あるいは
!      存在しない場合の動作を指定します。
!      参照で渡されます。
! FLAGS_ATTR
!      ファイル属性とファイルに対するフラグを指定します。!      参照で渡されます。
! B_NULL
!      常に NULL。Fortran ランタイム・ライブラリーは
!      CreateFile( ) 呼び出しのテンプレート・ファイルへの
!      ハンドルに対して常に NULL を渡します。
! 
! 最後の 2 つの引数は、Fortran ユニット番号とファイル名の長さです。
! UNIT
!      この OPEN が実行される Fortran ユニット番号。
!      参照で渡されます。
! FLEN
!      終端の NULL を除くファイル名の長さ。
!      値で渡されます。
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      INTEGER(4) FUNCTION UOPEN( FILENAME,       &
                              DESIRED_ACCESS, &
                              SHARE_MODE, &
                              A_NULL, &
                              CREATE_DISP, &
                              FLAGS_ATTR, &
                              B_NULL, &
                              UNIT, &
                              FLEN )
      !DIR$ ATTRIBUTES DEFAULT :: UOPEN
      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)
!     サニティーチェック
      IF (UNIT .NE. 10) THEN
         WRITE(*,140) UNIT
      END IF
      !! WRITE(*,*) "FILENAME=",FILENAME !! ファイル名のフルパスを出力します。
! CreateFile( ) に渡すフラグ属性の FILE_FLAG_WRITE_THROUGH ビットを設定します。
! (どのような理由であっても)
!     FLAGS_ATTR = FLAGS_ATTR + FILE_FLAG_WRITE_THROUGH
! CreateFile( ) を呼び出し、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
!DIR$ ELSE ! Linux* または macOS*
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! Linux*/macOS* 用の UOPEN 関数:
! 
! UOPEN 関数は cdecl 呼び出し規約を使用するように宣言されているため、
! Fortran RTL の USEROPEN ルーチンの宣言と一致します。
! 
! 次の関数定義と引数がインテル® Fortran ランタイム・ライブラリーから
! USEROPEN の名前付き関数に渡されます。
! 
! FILENAME
!      ファイル名を示す NULL で終わる文字列のアドレス
! OPEN_FLAGS
!      読み取り/書き込みフラグ (file.h または open(2) を参照)。
! CREATE_MODE
!      新しいファイルを作成する場合は設定します。
! UNIT
!      この OPEN が実行される Fortran ユニット番号。
!      参照で渡されます。
! FLEN
!      終端の NULL を除くファイル名の長さ。
!      値で渡されます。
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      INTEGER(4) FUNCTION UOPEN( FILENAME,       &
                              OPEN_FLAGS, &
                              CREATE_MODE, &
                              UNIT, &
                              FLEN )
      IMPLICIT NONE
      INTEGER(4) OPEN_FLAGS
      INTEGER(4) CREATE_MODE
      INTEGER(4) UNIT
      INTEGER(4) FLEN
      CHARACTER*(FLEN) FILENAME
      INTEGER(4) ISTAT
      !DIR$ ATTRIBUTES C, DECORATE, ALIAS:'open'  :: OPEN
      external OPEN
      INTEGER(4) OPEN
140   FORMAT( X, "ERROR: USEROPEN Passed Wrong Unit Number",I)
!     サニティーチェック
      IF (UNIT .NE. 10) THEN
         WRITE(*,140) UNIT
      END IF
!     OPEN システムルーチンを呼び出します。
      ISTAT = OPEN ( %ref(FILENAME),     &
                     OPEN_FLAGS, &
                     CREATE_MODE )
      UOPEN = ISTAT
      RETURN
      END
!DIR$ ENDIF ! UOPEN 関数の終わり
!---------------------------------------------------------------
! サブルーチン: ParseForFileName
!             フルパスを受け取り、拡張子を含むファイル名を返します。
!---------------------------------------------------------------
      SUBROUTINE ParseForFileName(FullName,FileName)
      Character*255 :: FullName
      Character*100 :: FileName
      Integer       :: P
!DIR$ IF DEFINED(_WIN32)
      P = INDEX(FullName,'\',.TRUE.)
      FileName = FullName(P+1:)
!DIR$ ELSE ! Linux*/macOS*
      P = INDEX(FullName,'/',.TRUE.)
      FileName = FullName(P+1:)
!DIR$ ENDIF
      END

関連情報