C+ C NAME: C bOpenFile C PURPOSE: C Opens a file or checks for its existence. C By default, the user will be prompted to enter a filename until a file is C successfully opened. This behaviour can be modified in several ways using C options listed under the input argument 'Act' below. C CATEGORY: C I/O: opening files C CALLING SEQUENCE: logical function bOpenFile(Act,iU,cFile,iRecl) C INPUTS: C More information may be available in the include openfile.h C C Act integer sum of parameters defined in include file openfile.h C (the safest way to combine options is to use the .or. operator C e.g. OPN__NOMESSAGE .or. OPN__TRYINPUT) C C OPN__NOMESSAGE suppress informational messages to screen C (error messages are always displayed) C C OPN__TRYINPUT Skip first prompt and try input file name instead C Default: prompt for file name C C OPN__SEARCHONLY Search only (i.e. check for existence) C Default: open file C C OPN__ONEPASS Do not activate prompt loop on failure C Default: keep prompting until success C C Used only if OPN__ONEPASS is set: C C OPN__STOP On failure, STOP execution C Default: RETURN with .FALSE. return value C C C The following are only useful for opening files (OPN__SEARCHONLY not set) C C OPN__NOPARSE Used only in combination with OPN__TRYINPUT: C Useful for bypassing a call to iSearch which may intervene C with a wildcard search. The iSearch call is responsible for C returning a fully qualified filename in cFile. OPN__NOPARSE C should be used only if the input value already is fully qualified C (e.g. output from another iSearch call). C C OPN__SEQUENTIAL Open for sequential access C Default: direct access C C OPN__FORMATTED Open for formatted read C Default: unformatted read C C OPN__TRYALL Try all seq/direct, form/unform C Default: use OPN__SEQUENTIAL and OPN__FORMATTED C C OPN__READONLY Open for read only C Default: open for read/write C (g77 does not support read-only files, so this C value is ignored on Linux) C C OPN__RECLBYTE Is set to indicate that the record length iRecl is specified C in bytes, rather than 4-byte longwords. C C By default bOpenFile tries to open an existing file and aborts if the file C does not exist. Modify this by one of the following three values: C C OPN__APPEND Opens an existing file for append and aborts if the C file does not exist C OPN__NEW Opens a new file and aborts if it already exists C OPN__UNKNOWN Opens a file whether it exists or not. C C Special definitions: C OPN__REOPEN = OPN__TRYINPUT+OPN__ONEPASS+OPN__NOPARSE C Useful for reopening a file known to exist: C the input value cFile is tried only once without parsing. C C OPN__BINARY Same as OPN__SEQUENTIAL: C opens a sequential access, unformatted file, i.e. C a generic binary file. C C OPN__TEXT Same as OPN__SEQUENTIAL+OPN__FORMATTED C opens a generic ascii file. C C OPN__HOS Open Helios file. C Some trickery is required to determine the record length C of a Helios file on DOS/WIN or Unix. Use this parameter to C to identify an existing file as a Helios data file. C Helios files are always opened for direct, unformatted access. C C cFile character*(*) File to be opened C (used only if OPN__TRYINPUT is set) C iRecl Record length in 4-byte longwords (unless option OPN__RECLBYTE is used). C On Linux and WIN record length only need to specified when opening C a file for direct access. C OUTPUTS: C bOpenFile C logical = .FALSE : if open/check failed or was aborted by user C = .TRUE. : if open/check succesful C Act integer (only if OPN__TRYALL was set) C mode used to open file, i.e. bits for OPN__SEQUENTIAL and/or C OPN__FORMATTED are set C iU integer On Failure: set to FIL__NOUNIT C On Success: Logical unit number of open file (open) C or FIL__NOUNIT+1 (check only) C cFile character*(*) On Failure: input value is retained C On Success: Fully qualified file name of opened/existing file C If the input file was a gzipped (.gz) file and the file was C ` unzipped successfully, then the file of the unzipped file created C by href=iOSgunzip= is returned. To get rid of the temporary file C closed the logical unit with href=iFreeLun=. C iRecl On Failure: input value is retained C On Success: record length in 4-byte longwords C INCLUDE: include 'filparts.h' include 'dirspec.h' include 'openfile.h' C CALLS: C AskChar, iSearch, itrim, iGetSymbol, iSetSymbol, uppercase, iOpenFile, Say, bHOSName, C iGetFileSpec, iSetFileSpec, iPutFileSpec, iOSgunzip, iScratchLun C RESTRICTIONS: C iOpenFile is a system dependent function. Currently versions are available for C VMS, NT, Unix and Linux C SIDE EFFECT: C On success the output filename cFile is parsed using iSetFileSpec C PROCEDURE: C > The function href=iOpenFile= called by this subroutine contains the actual open statements. C Separate versions of this function exists for every operating system. C > iOpenFile tries to determine the record length of the file. If unsuccessful, C the input value of iRecl is used. C On DOS and UNIX iOpenFile can only determine the record length for HELIOS data files. C > Act is a read-only variable, UNLESS all access methods are to be tried C (OPN__TRYALL used). In this case the OPN__TRYALL bit is cleared and the C the OPN__SEQUENTIAL and OPN__FORMATTED bits are set to the values used to open the file C The other bits are unchanged C > The existence check is performed by href=iSearch=. C > A default for the file prompt is read from the symbol DEF_FILE (on VMS a global symbol). C > The file prompt allows for changing file name components separately, e.g C typing '.dat' will only change the extension of the default file name while keeping C all the other components. C > For HELIOS data file with standard file names (e.g. A76V4_007.DAT), the following C additional abbreviated responses are possible: C .ZLD results in cFile = 'A76V4_007.ZLD' C _111 results in cFile = 'A76V4_111.DAT' C _111.ZLD results in cFile = 'A76V4_111.ZLD' C 9 results in cFile = 'A76V9_007.DAT' C MODIFICATION HISTORY: C NOV-1990, Paul Hick (UCSD/CASS) C SEP-1998, Paul Hick (UCSD/CASS) C Complete overhaul and merged with bOpenHOS C JUL-2002, Paul Hick (UCSD/CASS; pphick@ucsd.edu) C Changed exit error code (set by Say) on open error from 'S' C (=1) to 'E' (=2) C JUN-2004, Paul Hick (UCSD/CASS; pphick@ucsd.edu) C Introduced use of cHideLogical (implicit through '#' prefix in Say call). C- integer Act integer iU character cFile*(*) integer iRecl character cGet *(FIL__LENGTH) character cSave *(FIL__LENGTH) character cSpecSave*(FIL__LENGTH) character cGetName *(FIL__LENGTH) character cFileName*(FIL__LENGTH) character cFileUnzipped*(FIL__LENGTH) character cStatus*3 character cSay*9 /'bOpenFile'/ logical bSearch logical bTryInp logical bOnePass logical bStop logical bHOS logical bExists logical bTryAll logical bNew logical bUnknown logical bGo logical bFirst logical bHOSName logical bSay logical bUnzip iAct = Act ! Don't modify input value bSearch = iand(iAct,OPN__SEARCHONLY) .ne. 0 bTryInp = iand(iAct,OPN__TRYINPUT ) .ne. 0 bOnePass= iand(iAct,OPN__ONEPASS ) .ne. 0 bNew = iand(iAct,OPN__NEW ) .ne. 0 bUnknown= iand(iAct,OPN__UNKNOWN ) .ne. 0 bStop = iand(iAct,OPN__STOP ) .ne. 0 bHOS = iand(iAct,OPN__HOS ) .ne. 0 bExists = iand(iAct,OPN__NOPARSE ) .ne. 0 bTryAll = iand(iAct,OPN__TRYALL ) .ne. 0 .and. .not. bHOS bSay = iand(iAct,OPN__NOMESSAGE ) .eq. 0 ! Sanity checks if (bTryInp) then if (itrim(cFile) .eq. 0) call Say(cSay,'E','Try','input requested, but no file specified') else iAct = iAct-iand(iAct,OPN__TRYINPUT) end if ! These consistency checks are probably redundant if (.not. bTryAll) iAct = iAct-iand(iAct,OPN__TRYALL ) if (bTryAll .and. (bNew .or. bUnknown)) then! bTryAll only makes sense for status='OLD' bTryAll = .FALSE. iAct = iAct-iand(iAct,OPN__TRYALL) end if if (bUnknown) then ! Status='UNKNOWN' takes precedence over status='NEW' bNew = .FALSE. iAct = iAct-iand(iAct,OPN__NEW) end if ! bHOS =.TRUE.:HELIOS files are always opened for direct, unformatted access ! bTryAll=.TRUE.: we start with direct, unformatted access, then loop over the other combinations ! In both cases several bits in iAct should be cleared if (bTryAll .or. bHOS) iAct = iAct-iand(iAct,OPN__SEQUENTIAL)-iand(iAct,OPN__APPEND) & -iand(iAct,OPN__FORMATTED )-iand(iAct,OPN__TRYALL) cStatus = 'OLD' if (bNew) cStatus = 'NEW' if (bUnknown) cStatus = '???' I = iGetFileSpec(0,0,cSpecSave) cSave = cFile bGo = .TRUE. bFirst = .TRUE. do while (bGo) if (bTryInp) then cGet = cFile if (bSay) call Say(cSay,'I','#'//cGet,cStatus) else ! Prompt required if (bFirst) then bFirst = .FALSE. if (iGetSymbol('DEF_FILE',cGet) .eq. 0) then cGet = 'no default' else if (iSearch(1,cGet,cGet) .ne. 1) cGet = 'no default' end if if (bHOS .and. cGet .eq. 'no default') then cGetName = cWildChar(:5)//'_'//cWildChar(:3)//'.'//cWildChar(:3) I = iSearch(1,'A'//cGetName(2:),cGet) if (I .ne. 1) I = iSearch(1,'B'//cGetName(2:),cGet) if (I .ne. 1) cGet = 'no default' end if end if do while (bGo) cFile = cGet call AskChar(cStatus//' data file (0=STOP)',cGet) if (cGet .eq. cFile .or. cGet(:1) .eq. '0') then bGo = .FALSE. else if (cFile .ne. 'no default') then if (bHOSName(cFile,iSc,iYr,I,L)) then I = iGetFileSpec(FIL__NAME,FIL__NAME,cFileName) I = iSetFileSpec(cGet) I = iGetFileSpec(FIL__NAME,FIL__NAME,cGetName) J = 1 if (cGetName(:1) .eq. '_') J = 6 ! Change doy label if (cGetName(:1) .eq. '9') J = 5 ! Change to 90 deg file if ('1' .le. cGet(:1) .and. cGet(:1) .le. '5') J = 5 if (J .eq. 1) cFileName = cGetName(:I) if (J .gt. 1) cFileName(J:J-1+I) = cGetName(:I) I = iPutFileSpec(FIL__NAME,FIL__NAME,cFileName) I = iGetFileSpec(0,0,cGet) end if I = iSetFileSpec(cFile) I = iPutFileSpec(0,0,cGet) I = iGetFileSpec(0,0,cGet) bGo = cGet .eq. cFile else bGo = cGet .eq. 'no default' end if end do cFile = cGet end if if (bOS__NotCaseSensitive) call uppercase(cFile) iU = FIL__NOUNIT if (.not. bTryInp .and. cFile(:1) .eq. '0') then! Aborted by user bOnePass = .TRUE. else if (.not. bSearch) then ! Open a file !------- ! The iSearch call is used to intercept conditions which make ! a call to iOpenFile unnecessary: (iOpenFile contains a lot of ! OS/compiler dependent kludges, which are better left alone). ! 1. it parses the file name and returns a valid, fully qualified ! file name (if the file name is invalid there is no point ! in calling iOpenFile) ! 2. if status='OLD' is requested and the file does not exist, the ! call to iOpenFile is bypassed ! 2. if status='NEW' is requested and the file already exists, the ! call to iOpenFile is bypassed ! 2. if status='UNKNOWN' is requested, then the request is changed ! to 'OLD' or 'NEW' depending on wheter the file does/does not exist. ! ! Since this call can get in the way of a wildcard search using ! iSearch, a mechanism is needed to bypass it. In this case the ! input file spec presumably is output from iSearch, and refers to an ! existing file. This leads to the following bypass conditions: ! 1. set the OPN__TRYINPUT bit (bTryInp=.TRUE. on first pass only) ! 2. set the OPN__NOPARSE bit (bExists=.TRUE.) ! 3. do not set the OPN__UNKNOWN bits ! (bUnknown=.FALSE., .i.e. request status='OLD' .or. 'NEW'). ! The first two conditions are contained in the OPN__REOPEN parameter ! (which also contains OPN__ONEPASS). Note that status OPN__KNOWN ! cannot be used in conjunction with OPN__NOPARSE. jAct = iAct I = 1 if (.not. bTryInp .or. .not. bExists .or. bUnknown) then I = 0 if (bNew .or. bUnknown) I = 10 ! Suppress messages I = iSearch(I+1,cFile,cFile) if (bNew) then if (I .eq. 0) then ! Valid file name, but file does not exist I = 1 else if (I .eq. 1) then ! File exists if (cOpSys .eq. OS__VMS) then! On VMS, strip version number I = iSetFileSpec(cFile) I = iGetFileSpec(0,FIL__TYPE,cFile) I = 1 end if end if end if if (bNew .and. I .eq. 0) I = 1 ! Valid file name, but file does not exist !------- ! bUnknown=.TRUE. will force bExists=.FALSE., so we can decide here ! whether to use status='NEW' or 'OLD' if (bUnknown .and. I .ne. 2) then ! No parse error on file name jAct = iAct-OPN__UNKNOWN ! Clear OPN__UNKNOWN bit if (I .eq. 0) then jAct = iAct+OPN__NEW ! File does not exist: status='NEW' I = 1 end if end if end if if (I .eq. 1) then ! For existing (OLD) file, gunzip if necessary bUnzip = iand(jAct,OPN__NEW) .eq. 0 if (bUnzip) bUnzip = iOSgunzip(cFile,cFileUnzipped) .eq. 1 ! iNext = 0: Direct, unformatted iNext = 1: Sequential, unformatted ! iNext = 2: Direct, formatted iNext = 3: Sequential, formatted iNext = -1 do while (iNext .eq. -1 .or. (bTryAll .and. iU .eq. FIL__NOUNIT .and. iNext .lt. 3)) iNext = iNext+1 I = jAct if (bTryAll) I = jAct+mod(iNext,2)*OPN__SEQUENTIAL+(iNext/2)*OPN__FORMATTED if (bUnzip) then iU = iOpenFile(I,cFileUnzipped,iRecl) else iU = iOpenFile(I,cFile,iRecl) end if end do if (iU .ne. FIL__NOUNIT) then if (bUnzip ) iU = iScratchLun(iU) if (bTryAll) Act = I ! The succesful open code end if end if else if (iSearch(1,cFile,cFile) .eq. 1) then! Check for existence only iU = FIL__NOUNIT+1 iRecl = 1 end if bGo = .not. bOnePass .and. iU .eq. FIL__NOUNIT bTryInp = .FALSE. ! Activate prompt loop end do bOpenFile = iU .ne. FIL__NOUNIT if (bOpenFile) then I = iSetFileSpec(cFile) ! Please, don't remove I = iSetSymbol('DEF_FILE',cFile,2) ! Save file spec in DEF_FILE else ! Failure to open/check if (bStop) call Say(cSay,'E','StopPlay','Exit') I = iSetFileSpec(cSpecSave) cFile = cSave ! Retain input value end if return end