インテル® 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 言語が最適です。
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 から渡される引数を示します。
関数は 4 バイト整数 (int) として宣言する必要があります。
第 1 引数は、開かれるパス名 (ファイル名を含む) です。
オープンフラグについては、/usr/include/sys/file.h ヘッダーファイルまたは open(2) で説明されています。
作成モード (Linux* 形式のファイルの作成時に必要な保護) については、open(2) で説明されています。
第 4 引数は論理ユニット番号です。
最後の第 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 プロシージャーを呼び出します。
インテル® Fortran RTL は、1 つの論理ユニットごとにファイル記述子を 1 つだけ使用します。ファイル記述子は、呼び出された関数によって返される必要があります。このため、ファイルを開く際に使用できるのは、特定のシステムコールまたはライブラリー・ルーチンだけです。
ファイル記述子を返さないシステムコールおよびライブラリー・ルーチンには、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 の規則に基づいて名前が修飾されます。
!DEC$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 !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