インテル® Fortran コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
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 文はそのファイル名に対して効果がありません。
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 から渡される関数の定義と引数は次のとおりです。
関数は 4 バイト整数 (int) として宣言する必要があります。
開くパス名 (ファイル名を含む) を指定します。
オープンフラグを指定します。オープンフラグについては、/usr/include/sys/file.h ヘッダーファイルまたは open(2) で説明されています。
作成モード (Linux* 形式のファイルの作成時に必要な保護) を指定します。作成モードについては、open(2) で説明されています。
論理ユニット番号を指定します。
パス名の長さ (パス名の文字長の隠し引数) を指定します。
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 から渡される関数の定義と引数は次のとおりです。
関数は 4 バイト整数 (int) として宣言する必要があります。
開くパス名 (ファイル名を含む) を指定します。
アクセスモードを指定します。読み取り、書き込み、または読み取り/書き込みを指定できます。
ファイルの保護モードを指定します。
NULL の場合、文字ゼロとして値渡しされます。
これは、ファイルモードといくつかのファイル機能 (シーケンシャル・アクセスかランダムアクセスか、閉じるときに削除するかどうかなど) を指定するフラグを設定します。
NULL の場合、文字ゼロとして値渡しされます。
論理ユニット番号を指定します。
パス名の長さ (パス名の文字長の隠し引数) を指定します。
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 ディレクティブを追加して、正しい呼び出し規約が使用されるようにする必要があります。
インテル® Fortran RTL は、1 つの論理ユニットごとにファイル記述子を 1 つだけ使用します。ファイル記述子は、呼び出された関数によって返される必要があります。このため、ファイルを開く際に使用できるのは、特定のシステムコールまたはライブラリー・ルーチンだけです。
Linux* では、ファイル記述子を返さないシステムコールおよびライブラリー・ルーチンとして、mknod (mknod(2) を参照) および fopen (fopen(3) を参照) があります。例えば、fopen ルーチンはファイル記述子の代わりにファイルポインターを返します。
次のインテル® 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 の 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