CD-Title: Laue Data Module (LDM) Routines
CD-end

CD-Intro:
C This chapter gives details of the routines which are available to
C read, write and access the Laue Data Module (LDM) Data.
CD-end

CD-Section_order:
C 1 2 3 4 5 9 6 10 8 7 11
CD-end

CD-Section: Read, Parse and Write LDM Data
C Routines are available to read lines of data from a file (accessing indirect
C file references if present) and to examine such lines for LDM data; if such
C data are found the data will be checked for validity and stored in the Laue 
C Data Module. Any non-LDM data lines will be returned to the calling program
C for interpretation by that program and this LDM and other control or parameters
C data may be included in the file being read. Lines of data from other sources
C may also be interpreted using the parsing routine and indirect file references
C in such data may be handled if required. A routine is also available to
C write out the current LDM data to a file; this has a number of options
C ranging from only writing non-default data items to writing all data items
C for every pack and plate where relevant. There is also an option to write
C out only LDM parameter values which have been changed since a particular
C point in a program.
CD-end

C LAST UPDATE: 
C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C
C**************************
C**     LDM_READLINE     **
C**************************
C
CD-Routine: Read Line of Data from a File - LDM_READLINE
C This routine will return, on repeated calls, the next logical line of data
C read from a parameters file. Any indirectly referenced parameter files will
C be read as required. The logical line returned will contain any
C continuation lines present but will exclude any comments found.
CD-end
CD-Fortran:
      SUBROUTINE LDM_READLINE (IUN, KUN, INDIRECT, LINE, EOF, IERR)
CD-end
      INCLUDE 'implicit_none.finc'
C
C Purpose: Read next logical line from a parameters/control file
C
C Author:  John W. Campbell, May 1993
C
C Arguments:
C
      INTEGER IUN
      INTEGER KUN
      INTEGER INDIRECT
      CHARACTER*(*) LINE
      LOGICAL EOF
      INTEGER IERR

CD-parameters:       
C IUN      i (R)   Logical unit number of file/stream being read.
C KUN      i (R)   Start logical unit number for use with indirect files.
C                  Unit nos. (up to MAXIND e.g. 20) in sequence will be 
C                  used but any already open will be skipped.
C INDIRECT i (R/W) Current indirection level. MUST be set to 0 on first 
C                  call to read the file and subsequently must give the 
C                  previously returned value.You should ensure that the 
C                  program repeats calls to the routine until EOF is 
C                  returned as .TRUE. or INDIRECT is returned as 0 
C                  (otherwise files will be left open)
C LINE     c (W)   Returns the next logical line with comments removed and
C                  with all continuation lines included.
C EOF      l (W)   .TRUE.  End of file encountered on main input stream 
C                          (IUN)   
C                  .FALSE. No end of file on main input stream.
C IERR     i (W)   Returned error flag = 0 OK
C                                      = 1 LINE too short, data truncated
C                                      = 2 Error opening indirect file
C                                      = 3 Maximum allowed level of 
C                                          indirection exceeded
C                                      = 4 Insufficient Fortran units 
C                                          available for opening indirect 
C                                          files
C                                      = 5 Calling error (invalid INDIRECT 
C                                          value)
C
C                  For error flags > 1, all opened indirect files will be 
C                  closed
C
C Notes:   Allows for indirect reads from specified files up to MAXIND
C          levels (e.g. 20) in depth. 
C
C          Conventions for comments & continuations similar to CCP4 parser
C          but only '!' introduces comments (and not '#')
C
C          If '@' not followed by a file name is found, then all
C          indirection is cancelled and the next line is read from
C          the main input stream.
CD-end
C
C====== Parameter statements
C 
      INTEGER MAXIND
      INTEGER MAXCH
      PARAMETER (MAXIND=20)
      PARAMETER (MAXCH=121)
C
C MAXIND is maximum level of files indirection
C MAXCH is the max. no. of characters in an input record
C
C====== GLOBALS:
C
      COMMON /LDMRDL/ ISTREAM(MAXIND)
      INTEGER ISTREAM

C ISTREAM   Array of unit numbers used for reading indirect files

      CHARACTER*(MAXCH) FILNAM
      COMMON /LDMRFL/ FILNAM

C FILNAM    Holds name of last indirect file opened after an error return
C
C====== FUNCTION TYPES:
C
      INTEGER LENSTR
      INTEGER NXTTOK
      LOGICAL CCPEXS
C
C====== LOCALS:
C
      LOGICAL OPN
      LOGICAL CONT
      LOGICAL TRUNC
      INTEGER LUN
      INTEGER JUN
      INTEGER I
      INTEGER L
      INTEGER LL
      INTEGER LMAX
      INTEGER IFAIL
      INTEGER NCH
      INTEGER IL
      INTEGER M1
      INTEGER M2
      CHARACTER*(MAXCH) LIN
      CHARACTER*4 SEP

C     LOGICAL OPN       !Unit already open flag
C     LOGICAL CONT      !Continuation character found flag
C     LOGICAL TRUNC     !Returned line truncated flag
C     INTEGER LUN       !Unit number for next read
C     INTEGER JUN       !Unit number for next indirect file
C     INTEGER I         !Loop variable
C     INTEGER L         !Loop variable
C     INTEGER LL        !Length of character string
C     INTEGER LMAX      !Length of LINE
C     INTEGER IFAIL     !File open flag
C     INTEGER NCH       !Character count for LINE
C     INTEGER IL        !Last character position from token extraction
C     INTEGER M1        !Start position of token
C     INTEGER M2        !End position of token
C     CHARACTER*(MAXCH) LIN  !Buffer or reading record
C     CHARACTER*4 SEP        !Field separators
C
C====== SAVES
C
      SAVE /LDMRDL/,/LDMRFL/
C
C====== DATA:
C
      DATA SEP/'  ,='/
C
C-------------------------------------------------------------------------------
C
C====== Initialisations
C
      LINE = ' '
      EOF = .FALSE.
      IERR = 0
      SEP(2:2) = CHAR(9)
      FILNAM = ' '
      LMAX = LEN(LINE)
      NCH = 0
      TRUNC = .FALSE.
C
C====== Get required stream
C
100   IF (INDIRECT.LE.0) THEN
         INDIRECT = 0
         LUN = IUN
      ELSE
         IF (INDIRECT.GT.MAXIND) THEN
            IERR = 5
            RETURN
         END IF
         LUN = ISTREAM(INDIRECT)
      ENDIF
C
C====== Read line from file
C
      READ (LUN, '(A)', END=200) LIN
C
C====== Line read, remove any comments
C
      LL = LENSTR(LIN)
      IF (LL.GT.0) THEN
         DO 110 L = 1, LL
            IF (LIN(L:L).EQ.'!') THEN
               LIN(L:) = ' '
               GO TO 120
            END IF
110      CONTINUE
      END IF
120   LL = LENSTR(LIN)
C
C====== See if indirect file
C
      IL = 0
      I = NXTTOK (LIN,SEP,IL,M1,M2)
      IF (I.GT.0) THEN
         IF (LIN(M1:M1).EQ.'@') THEN
            IF (M2.EQ.M1) THEN
               I = NXTTOK(LIN,SEP,IL,M1,M2)
               IF (I.LE.0) THEN
                  IF (INDIRECT.GT.0) THEN
                     DO 130 I = 1, INDIRECT
                        CLOSE (UNIT=ISTREAM(INDIRECT))
130                  CONTINUE
                  END IF
                  INDIRECT = 0
                  GO TO 100
               END IF
            ELSE
               M1 = M1 + 1
            END IF
            IF (INDIRECT.GE.MAXIND) THEN
               IERR = 3
               GO TO 300
            ELSE
               IF (INDIRECT.EQ.0) THEN
                  JUN = KUN - 1
               ELSE
                  JUN = ISTREAM(INDIRECT)
               END IF
               INDIRECT = INDIRECT + 1
140            JUN = JUN + 1
               IF (JUN.GT.99) THEN
                  IERR = 3
                  GO TO 300
               ELSE
                  INQUIRE (UNIT=JUN,OPENED=OPN)
                  IF (OPN) GO TO 140
                  ISTREAM(INDIRECT) = JUN
                  FILNAM = LIN(M1:M2)
                  IF (.NOT.CCPEXS(FILNAM)) THEN
                     IERR = 2
                     GO TO 300
                  END IF
                  IFAIL = 1
                  CALL CCPDPN(-JUN,LIN(M1:M2),'READONLY','F',0,IFAIL)
                  IF (IFAIL.LT.0) THEN
                     IERR = 2
                     GO TO 300
                  ELSE
                    GO TO 100
                  END IF
               END IF
            END IF
         END IF
      END IF
C
C====== Test for continuation character
C
      CONT = .FALSE.
      LL = LENSTR(LIN)
      IF (LL.GT.0) THEN
         IF (LIN(LL:LL).EQ.'-'.OR.LIN(LL:LL).EQ.'&') THEN
            LIN(LL:LL) = ' '
            CONT = .TRUE.
         END IF
      END IF
C
C====== Add string to LINE
C
      LL = LENSTR(LIN)
      IF (LL.GT.0.AND..NOT.TRUNC) THEN
         IF (LINE.EQ.' ') THEN
            NCH = NCH + LL
            LINE = LIN
         ELSE
            LINE = LINE(1:LENSTR(LINE))//' '//LIN
            NCH = NCH + LL + 1
         END IF
      END IF
      IF (NCH.GT.LMAX) TRUNC = .TRUE.
      IF (CONT) GO TO 100
C
C====== Next logical now complete
C
      IF (TRUNC) IERR = 1
      RETURN
C
C====== End of file conditions
C
200   IF (INDIRECT.GT.0) THEN
         CLOSE (UNIT=ISTREAM(INDIRECT))
         INDIRECT = INDIRECT - 1
         GO TO 100
      ELSE
         EOF = .TRUE.
      END IF
      RETURN
C
C====== Error - close files & return
C
300   IF (INDIRECT.GT.0) THEN
         DO 310 I = 1, INDIRECT
            CLOSE (UNIT=ISTREAM(INDIRECT))
310      CONTINUE
      END IF
      INDIRECT = 0
      RETURN
      END
