C
C This code is distributed under the terms and conditions of the
C CCP4 licence agreement as `Part i)' software. See the conditions
C in the CCP4 manual for a copyright statement.
C
C $Id: diskio.f,v 1.23 1999/12/22 16:34:25 pjx Exp $
C
C_BEGIN_CCPLIB
C A set of Fortran subroutines to perform random access I/O on various
C data items (including bytes). Uses the C functions fopen, fclose,
C fread, fwrite, fseek, ftell, etc - by calling routines in library.c
C Note: IUNIT is NOT A Fortran Unit number, but an internal identifier
C
C The calls provided are given below:
C
C CALL QOPEN (IUNIT,FILNAM,ATBUTE) - Open file
C [CALL QQOPEN (IUNIT,FILNAM,ISTAT) - Open file: use QOPEN]
C CALL QCLOSE (IUNIT) - Close file
C CALL QMODE (IUNIT,MODE,NMCITM) - Change mode
C CALL QREAD (IUNIT,ARRAY,NITEMS,IER) - Read nitems
C CALL QREADI (IUNIT,ARRAY,NITEMS,IER) - Read nitems into integer array
C CALL QREADR (IUNIT,ARRAY,NITEMS,IER) - Read nitems into real array
C CALL QREADQ (IUNIT,ARRAY,NITEMS,IER) - Read nitems into complex array
C CALL QREADC (IUNIT,CHAR,IER) - Read bytes into character var.
C CALL QWRITE (IUNIT,ARRAY,NITEMS) - Write nitems
C CALL QWRITI (IUNIT,ARRAY,NITEMS) - Write nitems from integer array
C CALL QWRITR (IUNIT,ARRAY,NITEMS) - Write nitems from real array
C CALL QWRITQ (IUNIT,ARRAY,NITEMS) - Write nitems from complex array
C CALL QWRITC (IUNIT,CHAR) - Write bytes from character var.
C CALL QSEEK (IUNIT,IREC,IEL,LRECL) - Move to irec,iel
C CALL QBACK (IUNIT,LRECL) - Backspace 1 record
C CALL QSKIP (IUNIT,LRECL) - Skip 1 record
C CALL QQINQ (IUNIT,LFILNM,FILNAM,LENGTH) - Get filename and length
C CALL QLOCATE (IUNIT,LOCATE) - Get position in file
C CALL QRARCH (IUNIT, IOFFSET) - set up number conversion
C CALL QWARCH (IUNIT, IOFFSET) - write conversion info
C
C QSEEK calculates the location as (IREC - 1)*LRECL + IEL. Note: as in
C Fortran, addressing begins at 1 for both record & element
C In these files, there are no true records: the use of "record length"
C and "record number" in QSEEK, QSKIP, QBACK is purely notional.
C For QSEEK, any combination of IREC, IEL & LRECL which gives the
C same value of (IREC - 1)*LRECL + IEL is equivalent.
C
C Where:
C
C IUNIT = Variable returned by (Q)QOPEN to identify a file stream
C
C FILNAM = file name for the stream (should be restricted to eight
C characters for CCP4 programs)
C
C ATBUTE = File status for opening file
C = 'UNKNOWN', 'SCRATCH', 'OLD', 'NEW', or 'READONLY'
C
C ISTAT = File status on opening the file:
C 1, 'UNKNOWN' open as 'OLD'/'NEW' check existence
C 2, 'SCRATCH' open as 'OLD' and delete on closing
C 3, 'OLD' file MUST exist or program halts
C 4, 'NEW' create (overwrite) new file
C 5, 'READONLY' self explanatory
C
C NOTE: When using QQOPEN or QOPEN with ATBUTE = 'NEW' [ISTAT = 4],
C a check is made on the environment variable CCP4_OPEN -
C if this is set to UNKNOWN then the file is opened with
C attribute UNKNOWN rather than NEW to allow overwriting files
C that already exist.
C
C MODE = Access mode = 0, BYTES
C = 1, SHORT INT
C = 2, (REAL) WORD
C = 3, SHORT COMPLEX
C = 4, COMPLEX
C = 6, INTEGER
C
C NMCITM = No. of machine items (eg bytes) per element
C ARRAY = Starting location for data storage in core
C NOTE: This should normally be an array of full-word fortran items
C (REAL or INTEGER) or double-word (COMPLEX) in the case that you
C want to transfer complex numbers (mode 4). If necessary, unpack
C bytes using the routines provided in the library (or new ones).
C In particular, DON'T try to use BYTE or INTEGER*2 arrays, as these
C will likely cause alignment errors on RISC architectures.
C CHAR = CHARACTER*n buffer for transfer
C NITEMS = Number of elements to transfer
C IER = Error flag (0 = no error) else number of words transferred
C IREC = Desired record number (starts at 1)
C IEL = Desired element number within record (word) (starts at 1)
C LRECL = Record length in elements
C
C No. of channels and buffer length in words set in #DEFINE statements
C
C NOTE: use of QREAD/QWRITE is deprecated -- use QREAD/QWRITE
C with a buffer of the correct type.
C
C
C Author: David Agard (Phil Evans and John Campbell)
C Modified: For Unix/F77 using words (and bytes if available) (John Campbell)
C Modified: For ccp ascii header system implemented (Jan Zelinka)
C_END_CCPLIB
C
C======================================================================
C_BEGIN_QQOPEN
C
C QQOPEN - Open a file unit
C
C NOTE: the routine QOPEN (which calls QQOPEN) is to be preferred
C to calling QQOPEN directly
C
C Usage: CALL QQOPEN (IUNIT, LOGNAME, ISTAT)
C INTEGER IUNIT, ISTAT
C CHARACTER*(*) LOGNAME
C
C Input: LOGNAME Logical name of file to open
C ISTAT File status: 1 (UNKNOWN), 2 (SCRATCH), 3 (OLD),
C 4 (NEW) or 5 (READONLY)
C
C Output: IUNIT Integer handle assigned to file. If negative
C the following error conditions occurred:
C -1 No more streams left
C -2 Could not open the file
C
C_END_QQOPEN
C======================================================================
SUBROUTINE QQOPEN(IUNIT,LOGNAM,ISTAT)
C =====================================
C
C .. Parameters ..
INTEGER ISTRLN,ISIZE
PARAMETER (ISTRLN=500,ISIZE=20)
C ..
C .. Scalar Arguments ..
INTEGER ISTAT,IUNIT
CHARACTER LOGNAM* (*)
C ..
C .. Local Arrays ..
CHARACTER MODES(5)*10
C ..
C .. Local Scalars ..
INTEGER JSTAT
CHARACTER ERRSTR*255,REWRIT* (ISIZE),USRNAM* (ISIZE),
+ FNAME* (ISTRLN),LNAME* (ISTRLN)
LOGICAL LNONAM
C ..
C .. External Subroutines ..
EXTERNAL CCPERR,CCPUPC,COPEN,QPRINT,UGTENV,UGTUID
C ..
C .. External Functions ..
INTEGER LENSTR
LOGICAL CCPEXS
EXTERNAL CCPEXS, LENSTR
C ..
C .. Data statements ..
DATA MODES/'UNKNOWN','SCRATCH','OLD','NEW','READONLY'/
C ..
C
IF (ISTAT.LT.1 .OR. ISTAT.GT.5) THEN
WRITE (ERRSTR,'(1X,A,I2)') ' (Q)QOPEN: bad mode: ',ISTAT
CALL CCPERR(1,ERRSTR)
END IF
C
C---- Test CCP4_OPEN for 'UNKNOWN' to switch mode 4 to 1
C
JSTAT = ISTAT
REWRIT = ' '
IF (JSTAT.EQ.4) THEN
CALL UGTENV('CCP4_OPEN',REWRIT)
CALL CCPUPC(REWRIT)
IF (REWRIT.EQ.'UNKNOWN') JSTAT = 1
END IF
C
C---- Check Logical Names
C
FNAME = ' '
LNAME = LOGNAM
LNONAM = .FALSE.
IF (LNAME.EQ.' ') LNAME = 'diskio.dft'
CALL UGTENV(LNAME,FNAME)
IF (FNAME.EQ.'/dev/null') THEN
JSTAT = 1
ELSE IF (FNAME.EQ.' ') THEN
IF (.NOT. CCPEXS(LNAME)) LNONAM = .TRUE.
FNAME = LNAME
END IF
IF (REWRIT.EQ.'UNKNOWN')
+ CALL QPRINT(2, '(Q)QOPEN status changed from NEW to '
+ //'UNKNOWN for '// LNAME)
IF (JSTAT.EQ.4 .AND. CCPEXS(FNAME)) THEN
ERRSTR = ' (Q)QOPEN NEW file already exists: '
ERRSTR(LENSTR(ERRSTR)+2:) = FNAME
CALL CCPERR(1,ERRSTR)
ENDIF
C
C---- Open the file as requested
C
CALL COPEN(IUNIT,FNAME,JSTAT)
C
C---- Error conditions
C
IF (IUNIT.EQ.-1) THEN
CALL CCPERR(1,' (Q)QOPEN failed - no streams left')
ELSE IF (IUNIT.EQ.-2) THEN
IF (LNONAM) THEN
ERRSTR = '(Q)QOPEN Logical name '//LNAME
ERRSTR(LENSTR(ERRSTR)+2:) = 'has no associated file name'
CALL CCPERR(2,ERRSTR)
END IF
ERRSTR = ' (Q)QOPEN failed - File name: '
ERRSTR(LENSTR(ERRSTR)+2:) = LOGNAM
CALL CCPERR (-1,ERRSTR)
END IF
call ccp4h_summary_beg()
CALL UGTUID(USRNAM)
WRITE (ERRSTR,'(1X,A,I2)') '(Q)QOPEN allocated # ',IUNIT
CALL QPRINT(1,ERRSTR)
ERRSTR = 'User: '//USRNAM//' Logical Name: '//LNAME
CALL QPRINT(1,ERRSTR)
ERRSTR = 'Status: '//MODES(JSTAT)//' Filename: '//FNAME
CALL QPRINT(1,ERRSTR)
call ccp4h_summary_end()
END
C
C
C======================================================================
C_BEGIN_QCLOSE
C
C QCLOSE - Close file unit
C
C Usage: CALL QCLOSE (IUNIT)
C INTEGER IUNIT
C
C Input: IUNIT unit number assigned to file
C
C Output: None.
C_END_QCLOSE
C See library.c
C======================================================================
C_BEGIN_QMODE
C
C QMODE - Set mode for file access
C
C Usage: CALL QMODE (IUNIT, MODE, NMCITM)
C INTEGER IUNIT, MODE, NMCITM
C
C Input: IUNIT unit number to assign to file
C MODE mode to switch into: 0 (BYTES), 1 (SMALL INTEGER),
C 2 (WORDS), 3 (SHORT COMPLEX),
C 4 (COMPLEX) 6 (INTEGER)
C
C Output: NMCITM number of bytes per item on this machine.
C_END_QMODE
C See library.c
C======================================================================
C_BEGIN_QREAD
C
C QREAD - Read from IUNIT into BUFFER, NITEMS items
C
C Usage: CALL QREAD (IUNIT,BUFFER,NITEMS,RESULT)
C INTEGER IUNIT, NITEMS, RESULT
C REAL BUFFER
C
C Input: IUNIT unit number assigned to file
C NITEMS number of items (item size set by QMODE)
C
C Output: RESULT 0 (no error), -1 (EOF) or number of items read
C BUFFER holds the items read
C_END_QREAD
C See library.c
C_BEGIN_QREADI
C
C QREADI - Read from IUNIT into BUFFER, NITEMS items
C
C Usage: CALL QREADI (IUNIT,BUFFER,NITEMS,RESULT)
C INTEGER IUNIT, NITEMS, RESULT
C INTEGER BUFFER
C
C Input: IUNIT unit number assigned to file
C NITEMS number of items (item size set by QMODE)
C
C Output: RESULT 0 (no error), -1 (EOF) or number of items read
C BUFFER holds the items read
C_END_QREADI
C_BEGIN_QREADR
C
C QREADR - Read from IUNIT into BUFFER, NITEMS items
C
C Usage: CALL QREADR (IUNIT,BUFFER,NITEMS,RESULT)
C INTEGER IUNIT, NITEMS, RESULT
C REAL BUFFER
C
C Input: IUNIT unit number assigned to file
C NITEMS number of items (item size set by QMODE)
C
C Output: RESULT 0 (no error), -1 (EOF) or number of items read
C BUFFER holds the items read
C_END_QREADR
C_BEGIN_QREADQ
C
C QREADQ - Read from IUNIT into BUFFER, NITEMS items
C
C Usage: CALL QREADQ (IUNIT,BUFFER,NITEMS,RESULT)
C INTEGER IUNIT, NITEMS, RESULT
C COMPLEX BUFFER
C
C Input: IUNIT unit number assigned to file
C NITEMS number of items (item size set by QMODE)
C
C Output: RESULT 0 (no error), -1 (EOF) or number of items read
C BUFFER holds the items read
C_END_QREADQ
C_BEGIN_QREADC
C
C QREADC - Read bytes from IUNIT to fill BUFFER
C
C Usage: CALL QREADC (IUNIT,BUFFER,RESULT)
C INTEGER IUNIT, RESULT
C CHARACTER*(*) BUFFER
C
C Input: IUNIT unit number assigned to file
C
C Output: RESULT 0 (no error), -1 (EOF) or number of items read
C BUFFER holds the items read. If necessary, use a substring
C of the CHARACTER variable
C_END_QREADC
C======================================================================
C_BEGIN_QWRITE
C
C QWRITE - Write to IUNIT from BUFFER, NITEMS items
C
C Usage: CALL QWRITE (IUNIT,BUFFER,NITEMS)
C INTEGER IUNIT, NITEMS
C REAL BUFFER
C
C Input: IUNIT unit number assigned to file
C NITEMS number of items (item size set by QMODE)
C BUFFER holds the items to write
C
C Output: None.
C_END_QWRITE
C_BEGIN_QWRITI
C
C QWRITI - Write to IUNIT from BUFFER, NITEMS items
C
C Usage: CALL QWRITI (IUNIT,BUFFER,NITEMS)
C INTEGER IUNIT, NITEMS
C INTEGER BUFFER
C
C Input: IUNIT unit number assigned to file
C NITEMS number of items (item size set by QMODE)
C BUFFER holds the items to write
C
C Output: None.
C_END_QWRITI
C_BEGIN_QWRITR
C
C QWRITR - Write to IUNIT from BUFFER, NITEMS items
C
C Usage: CALL QWRITR (IUNIT,BUFFER,NITEMS)
C INTEGER IUNIT, NITEMS
C REAL BUFFER
C
C Input: IUNIT unit number assigned to file
C NITEMS number of items (item size set by QMODE)
C BUFFER holds the items to write
C
C Output: None.
C_END_QWRITR
C_BEGIN_QWRITQ
C
C QWRITQ - Write to IUNIT from BUFFER, NITEMS items
C
C Usage: CALL QWRITQ (IUNIT,BUFFER,NITEMS)
C INTEGER IUNIT, NITEMS
C COMPLEX BUFFER
C
C Input: IUNIT unit number assigned to file
C NITEMS number of items (item size set by QMODE)
C BUFFER holds the items to write
C
C Output: None.
C_END_QWRITQ
C_BEGIN_QWRITEC
C
C QWRITEC - Write BUFFER to IUNIT
C
C Usage: CALL QWRITEC (IUNIT,BUFFER)
C INTEGER IUNIT, NITEMS
C CHARACTER*(*) BUFFER
C
C Input: IUNIT unit number assigned to file
C BUFFER holds the items to write. If necessary, use a
C substring of the CHARACTER variable
C
C Output: None.
C_END_QWRITEC
C See library.c
C======================================================================
C_BEGIN_QSEEK
C
C QSEEK - Position a file pointer in a IUNIT
C
C Usage: CALL QSEEK (IUNIT, IRECL, IEL, LRECL)
C INTEGER IUNIT, IRECL, IEL, LRECL
C
C Input: IUNIT unit number to assign to file
C IRECL "record number" to seek
C IEL element number to seek
C LRECL length of a "record"
C
C Output: None
C
C QSEEK calculates the location as (IREC - 1)*LRECL + IEL. Note: as in
C Fortran, addressing begins at 1 for both record & element
C In these files, there are no true records: the use of "record length"
C and "record number" in QSEEK, QSKIP, QBACK is purely notional.
C For QSEEK, any combination of IREC, IEL & LRECL which gives the
C same value of (IREC - 1)*LRECL + IEL is equivalent.
C
C_END_QSEEK
C See library.c
C======================================================================
C_BEGIN_QBACK
C
C QBACK - skip back 1 record of length LRECL
C
C Usage: CALL QBACK (IUNIT,LRECL)
C INTEGER IUNIT, LRECL
C
C Input: IUNIT unit number assigned to file
C LRECL length of a record in items
C
C Output: None
C_END_QBACK
C See library.c
C======================================================================
C_BEGIN_QSKIP
C
C QSKIP - skip forward 1 record of length LRECL
C
C Usage: CALL QSKIP (IUNIT,LRECL)
C INTEGER IUNIT, LRECL
C
C Input: IUNIT unit number assigned to file
C LRECL length of a record in items
C
C Output: None
C_END_QSKIP
C See library.c
C
C
C======================================================================
C_BEGIN_QQINQ
C
C QQINQ - check file name and size. Check IUNIT first, if no success
C then try LOGNAM, if this fails use LOGNAM as filename.
C
C Usage: CALL QQINQ (IUNIT,LOGNAM,FILNAM,LENGTH)
C INTEGER IUNIT,LENGTH
C CHARACTER*(*) LOGNAM,FILNAM
C
C Input: IUNIT handle to check (as returned by QOPEN)
C LOGNAM Logical name
C
C Output: FILNAM the full file name or "" if no file
C LENGTH file size or -1 if no file
C
C_END_QQINQ
C======================================================================
C
SUBROUTINE QQINQ(IUNIT,LFN,FILNAM,LENGTH)
C =========================================
C
C .. Parameters ..
INTEGER ISTRLN
PARAMETER (ISTRLN=500)
C ..
C .. Scalar Arguments ..
INTEGER IUNIT,LENGTH
CHARACTER FILNAM* (*),LFN* (*)
C ..
C .. Local Scalars ..
CHARACTER FNAME* (ISTRLN),LNAME* (ISTRLN)
C ..
C .. External Subroutines ..
EXTERNAL CQINQ,UGTENV
C ..
FNAME = ' '
LNAME = LFN
IF (LNAME.EQ.' ') LNAME = 'diskio.dft'
CALL UGTENV(LNAME,FNAME)
IF (FNAME.EQ.' ') FNAME = LNAME
CALL CQINQ(IUNIT,FNAME,LENGTH)
FILNAM = FNAME
C
END
C
C
C======================================================================
C_BEGIN_QLOCATE
C
C QLOCATE - return current position in file (measured in items)
C
C Usage: CALL QLOCATE (IUNIT,LOCATE)
C INTEGER IUNIT,LOCATE
C
C Input: IUNIT stream to check
C
C Output: LOCATE Current position in file or -1 for no file
C_END_QLOCATE
C See library.c
C
C======================================================================
C_BEGIN_QOPEN
C
C QOPEN - Open a file unit
C
C Usage: CALL QOPEN (IUNIT, LOGNAME, ATBUTE)
C INTEGER IUNIT
C CHARACTER*(*) LOGNAME, ATBUTE
C
C Input: IUNIT unit number number to assign to file
C LOGNAME Logical name of file to open
C ATBUTE File status = 'UNKNOWN', 'SCRATCH', 'OLD',
C 'NEW', or 'READONLY'
C
C Output: None.
C_END_QOPEN
C
C======================================================================
C
SUBROUTINE QOPEN(IUNIT,LOGNAM,ATBUTA)
C =====================================
C
C .. Scalar Arguments ..
INTEGER IUNIT
CHARACTER ATBUTA* (*),LOGNAM* (*)
C ..
C .. Local Scalars ..
INTEGER ISTAT
CHARACTER FOO*80
C ..
C .. External Subroutines ..
EXTERNAL QQOPEN, CCPUPC
C ..
ISTAT = 0
CALL CCPUPC(ATBUTA)
IF (ATBUTA(:1).EQ.'U') ISTAT = 1
IF (ATBUTA(:1).EQ.'S') ISTAT = 2
IF (ATBUTA(:1).EQ.'O') ISTAT = 3
IF (ATBUTA(:1).EQ.'N') ISTAT = 4
IF (ATBUTA(:1).EQ.'R') ISTAT = 5
IF (ISTAT.EQ.0) THEN
FOO = ATBUTA
CALL CCPERR(1,'Bad attribute in QOPEN: '//FOO)
ENDIF
C
CALL QQOPEN(IUNIT,LOGNAM,ISTAT)
END
C======================================================================
C_BEGIN_QRARCH
C
C QRARCH - set up number conversion
C
C Usage: CALL QRARCH (IUNIT, IOFFSET, IRESLT)
C INTEGER IUNIT, IOFFSET, IRESLT
C
C Input: IUNIT unit number number to assign to file
C IOFFSET offset in words at which to find architecture
C information
C
C Output: IRESLT fileFT + (16*fileIT) (see library C code)
C Zero if the stamp isn't present.
C
C Reads the `machine stamp' giving information about the
C architecture with which the file was written and arranges to
C translate a foreign format to native with QREAD, dependent on the
C current diskio mode.
C
C_END_QRARCH
C======================================================================
C
C======================================================================
C_BEGIN_QWARCH
C
C QWARCH - set up number conversion
C
C Usage: CALL QWARCH (IUNIT, IOFFSET)
C INTEGER IUNIT, IOFFSET
C
C Input: IUNIT unit number number to assign to file
C IOFFSET offset in words at which to write architecture
C information
C
C Output: None.
C
C Writes the `machine stamp' giving information about the
C architecture with which the file was written and which is used by
C QRARCH
C
C_END_QWARCH
C======================================================================
C for correct typing of qread/write calls
SUBROUTINE QREADI (IUNIT,BUFFER,NITEMS,RESULT)
INTEGER IUNIT, NITEMS, RESULT
INTEGER BUFFER(*)
CALL QREAD (IUNIT,BUFFER,NITEMS,RESULT)
END
SUBROUTINE QREADQ (IUNIT,BUFFER,NITEMS,RESULT)
INTEGER IUNIT, NITEMS, RESULT
COMPLEX BUFFER(*)
CALL QREAD (IUNIT,BUFFER,NITEMS,RESULT)
END
SUBROUTINE QREADR (IUNIT,BUFFER,NITEMS,RESULT)
INTEGER IUNIT, NITEMS, RESULT
REAL BUFFER(*)
CALL QREAD (IUNIT,BUFFER,NITEMS,RESULT)
END
SUBROUTINE QWRITR (IUNIT,BUFFER,NITEMS)
INTEGER IUNIT, NITEMS
REAL BUFFER(*)
CALL QWRITE (IUNIT,BUFFER,NITEMS)
END
SUBROUTINE QWRITI (IUNIT,BUFFER,NITEMS)
INTEGER IUNIT, NITEMS
INTEGER BUFFER(*)
CALL QWRITE (IUNIT,BUFFER,NITEMS)
END
SUBROUTINE QWRITQ (IUNIT,BUFFER,NITEMS)
INTEGER IUNIT, NITEMS
COMPLEX BUFFER(*)
CALL QWRITE (IUNIT,BUFFER,NITEMS)
END
C======================================================================
C_BEGIN_QISNAN
C
C QISNAN - check for `magic number'
C
C Usage: LOGICAL FUNCTION QISNAN (VALUE)
C
C Input: VALUE REAL value to test
C
C Returns .true. if VALUE is a `magic number' indicating the
C absence of data. In the current implementation, this is a NaN in
C IEEE or Rop on a VAX or Convex native. Any NaN (or Infinity)
C will return .true.
C
C_END_QISNAN
C======================================================================
LOGICAL FUNCTION QISNAN (VALUE)
REAL VALUE
INTEGER CISNAN
EXTERNAL CISNAN
QISNAN = CISNAN (VALUE) .NE. 0
END
C======================================================================
C_BEGIN_QNAN
C
C QNAN - return canonical `magic number'
C
C Usage: SUBROUTINE QNAN (VALUE)
C Output: VALUE REAL `magic' value
C
C Returns a `magic number' which can be used to indicate the absence
C of data in an MTZ file. In the current implementation, this is a
C NaN in IEEE or Rop on a VAX or Convex native.
C
C_END_QNAN
C======================================================================