C-----------------------------------------------------------------------
      PROGRAM PEFFMT
C-----------------------------------------------------------------------
C
C     A simple PEF file parser and reader.
C
C     May be used as a starting point for a PEF converter.
C
C     Language:  FORTRAN 77
C
C     Created:   20.4.1996   Martin Hepperle
C
C-----------------------------------------------------------------------
      INTEGER IUNIT, IRET, ILEN, ILPT
      INTEGER ISETS, IS, IPOLAR, IP, IPOINT, IPT
      REAL REYNO
      CHARACTER*128 CNAME      
      CHARACTER*128 CPOINT
      CHARACTER*32 CSET
      CHARACTER*32 CVAL

C     block header for set
1001  FORMAT ( 'Set', I1 )
1002  FORMAT ( 'Set', I2 )
C     block header for polar
1011  FORMAT ( 'Set', I1, '-Polar', I1 )
1021  FORMAT ( 'Set', I2, '-Polar', I1 )
1012  FORMAT ( 'Set', I1, '-Polar', I2 )
1022  FORMAT ( 'Set', I2, '-Polar', I2 )
C     key for data point
1010  FORMAT ( 'Value', I2.2 )

C     open the PEF file
      IUNIT = 10
      OPEN ( IUNIT, FILE='MH32.PEF', STATUS='OLD' )

C     locate at start of [Airfoil] block to lookup a key-value pair
      IRET = ILBLOK ( IUNIT, 'Airfoil', 7 )
      IF ( IRET .NE. 1 ) THEN
         write (6,*) ' *** Cannot locate Airfoil block.'
         write (6,*) '     Probably no PEF file..'
         GO TO 600
      END IF

C     we have to use a variable for ILEN, because IGTKEY adjusts
C     the value to the actual length of the key's value.
      ILEN = 128
      IRET = IGTKEY ( IUNIT, 'Description1', 12, CNAME, ILEN )

C     locate at start of block again to lookup next key-value pair
      IRET = ILBLOK ( IUNIT, 'Airfoil', 7 )
      IRET = IGTINT ( IUNIT, 'NumberSets', 10, ISETS )
      write (6,*) 'Airfoil:       ', CNAME(1:ILEN)
      write (6,*) 'Number of Sets:', ISETS

C     --- Loop over all sets in this file: --
      DO 400 IS=1,ISETS,1
         IF ( IS .LT. 10 ) THEN
            WRITE ( CSET, 1001 ) IS
            ILEN = 4
         ELSE
            WRITE ( CSET, 1002 ) IS
            ILEN = 5
         END IF

C        locate at start of block to lookup next key-value pair
         IRET = ILBLOK ( IUNIT, CSET, ILEN )            
         IRET = IGTINT ( IUNIT, 'NumberPolars', 12, IPOLAR )
         IF ( IRET .NE. 1 ) THEN
            write (6,*) ' *** Cannot read number of polars.'
            GO TO 600
         END IF

         write (6,*) 'Set:', IS
         write (6,*) '   Number of Polars:', IPOLAR

C        --- Loop over all polars in this set: ---
         DO 300 IP=1,IPOLAR
            IF ( IS .LT. 10 ) THEN
               IF ( IP .LT. 10 ) THEN
                  WRITE ( CSET, 1011 ) IS, IP
                  ILEN = 9+2
               ELSE
                  WRITE ( CSET, 1012 ) IS, IP
                  ILEN = 9+3
               END IF
            ELSE
               IF ( IP .LT. 10 ) THEN
                  WRITE ( CSET, 1021 ) IS, IP
                  ILEN = 9+3
               ELSE
                  WRITE ( CSET, 1022 ) IS, IP
                  ILEN = 9+4
               END IF
            END IF

            IRET = ILBLOK ( IUNIT, CSET, ILEN )
            IF ( IRET .NE. 1 ) THEN
               write (6,*) ' *** Cannot locate polar in set.'
               GO TO 600
            END IF
            IRET = IGTINT ( IUNIT, 'NumberPoints', 12, IPOINT )
C           we have to locate the start of the block again,
C           to make sure that we are independant of sequence:
            IRET = ILBLOK ( IUNIT, CSET, ILEN )
            IRET = IGTFLT ( IUNIT, 'ReynoldsNumber', 14, REYNO )

            write (6,*) '   Polar:', IP
            write (6,*) '      Number of Points:', IPOINT
            write (6,*) '      Reynolds Number: ', REYNO
            
C           --- Loop over all points in this polar: ---
            DO 200 IPT=1,IPOINT,1
               IRET = ILBLOK ( IUNIT, CSET, ILEN )
               WRITE ( CVAL, 1010 ) IPT
               ILPT = 128
               IRET = IGTKEY ( IUNIT, CVAL, 7, CPOINT, ILPT )
               IF ( IRET .NE. 1 ) THEN
                  write (6,*) ' *** Cannot locate point in polar.'
                  GO TO 600
               END IF

               write(6,*) CPOINT(1:ILPT)
C              here the data points should be parsed into an array,
C              - this is left to the reader as an execise in 
C                FORTRAN programming...

C              -> next data point in polar
200         CONTINUE
            
C           -> next polar in set
300      CONTINUE

C        -> next set
400   CONTINUE

600   CONTINUE
      
      CLOSE ( IUNIT )      

      END
C-----------------------------------------------------------------------
      INTEGER FUNCTION ILBLOK ( IUNIT, CBLTIT, IBLLEN )
C-----------------------------------------------------------------------
C
C     locates a specified block in a file
C
C     IUNIT  ... file
C     CBLTIT ... block name
C     IBLLEN ... length of block name (no. of characters)
C
C-----------------------------------------------------------------------
C     Parameters
      INTEGER IUNIT, IBLLEN
      CHARACTER *(*) CBLTIT

C     Multipurpose buffer
      CHARACTER*255 CBUF
      COMMON /BUFFER/ CBUF
C-----------------------------------------------------------------------

      REWIND ( IUNIT )
      
100   CONTINUE
      READ ( IUNIT, '(A255)', ERR=300, END=400 ) CBUF
      
      IF ( CBUF(1:1) .EQ. '[' ) THEN
         IF ( CBUF(2:1+IBLLEN)        .EQ. CBLTIT .AND.
     &        CBUF(2+IBLLEN:2+IBLLEN) .EQ. ']' ) THEN
C           Block header found.
            GO TO 200
         END IF
      ENDIF

C     GO ON      
      GO TO 100

C     Successful!            
200   CONTINUE
      ILBLOK = 1
      RETURN

300   CONTINUE
      ILBLOK = -1
      RETURN

400   CONTINUE
      ILBLOK = -2
      RETURN

      END
C-----------------------------------------------------------------------

C-----------------------------------------------------------------------
      INTEGER FUNCTION IGTKEY ( IUNIT, CKEY, IKEYLN, CVALUE, IVALLN )
C-----------------------------------------------------------------------
C
C     Gets the value of the specified key from a file.
C     The value is returned in the string buffer CVALUE.
C     IVALLN is adjusted to the length of the string.
C     The equal sign can be separated by spaces from key name
C     i.e. "KEY=" or "KEY =". Following spaces are assumed to be
C     part of the key's value.
C
C     Returns:
C              -  1 on success
C                -3 if a read error occured
C                -2 if end of file was reached
C                -3 if block was not found
C              - the value of the key via argument CVALUE
C              - the length of the value of the key via argument IVALLN
C
C                (I ... input)
C                (O ... output)
C     IUNIT  ... (I)   file
C     CKEY   ... (I)   key name
C     IKEYLN ... (I)   length of key name (no. of characters)
C     CVALUE ... (O)   value corresponding to CKEY
C     IVALLN ... (I/O) length of key value (no. of characters)
C
C-----------------------------------------------------------------------
C     Parameters
      INTEGER IUNIT, IKEYLN, IVALLN
      CHARACTER *(*) CKEY, CVALUE

C     Multipurpose buffer
      CHARACTER*255 CBUF
      COMMON /BUFFER/ CBUF
C-----------------------------------------------------------------------

100   CONTINUE
      READ ( IUNIT, '(A255)', ERR=300, END=400 ) CBUF
      
      IF ( CBUF(1:IKEYLN) .EQ. CKEY ) THEN
         IF ( CBUF(1+IKEYLN:1+IKEYLN) .EQ. ' ' ) THEN
C           space found, skip all following spaces
            DO 110 IEQUAL=1+IKEYLN, 255-1, 1
               IF ( CBUF(IEQUAL:IEQUAL) .NE. ' ' ) THEN
C                 break that loop
                  GO TO 115
               END IF
110         CONTINUE
C           non space character or end of buffer found
115         CONTINUE
         ELSE
            IEQUAL = 1+IKEYLN
         END IF
         IF ( CBUF(IEQUAL:IEQUAL) .EQ. '=' ) THEN
C           Key found.
            ILEN = MIN(IVALLN,255)            
            CVALUE = CBUF(2+IKEYLN:ILEN)
            IVALLN = IRTRIM ( CVALUE, ILEN )
            GO TO 200
         END IF
      ELSE IF ( CBUF(1:1) .EQ. ']' ) THEN
C        next block begins here
         GO TO 500
      END IF

C     GO ON      
      GO TO 100

C     Successful!            
200   CONTINUE
      IGTKEY = 1
      RETURN

300   CONTINUE
      IGTKEY = -1
      RETURN

400   CONTINUE
      IGTKEY = -2
      RETURN

500   CONTINUE
C     key not found
      IGTKEY = -3
      RETURN

      END
C-----------------------------------------------------------------------
      
C-----------------------------------------------------------------------
      INTEGER FUNCTION IRTRIM ( CBUFF, ILEN )
C
C     Right Trim function for strings.
C     Replaces trailing blanks with ASCII(0) characters.
C
C     Returns:
C              - the length of the trimmed string
C              - the trimmed string via argument CBUFF
C
C               (I ... input)
C               (O ... output)
C     CBUFF ... (I/O) string, may have trailing blanks
C     ILEN  ... (I)   length of string (no. of characters)
C-----------------------------------------------------------------------
C     Parameters:
      CHARACTER *(*) CBUFF
      INTEGER ILEN
C-----------------------------------------------------------------------
      
      DO 100 I=ILEN,1,-1
         IF ( CBUFF(I:I) .EQ. ' ' ) THEN
            CBUFF(I:I) = CHAR(0)
         ELSE
            GO TO 200
         END IF
100   CONTINUE

200   CONTINUE
      
      IRTRIM = I
      RETURN
      END
C-----------------------------------------------------------------------

C-----------------------------------------------------------------------
      INTEGER FUNCTION IGTINT ( IUNIT, CKEY, IKEYLN, IVALUE )
C
C     Reads a integer (INTEGER) value IVALUE corresponding to
C     the given key CKEY from the file adressed by IUNIT.
C
C     Returns:
C              - 1 on success, -ERR otherwise (see IGTKEY())
C              - the read value via argument IVALUE
C
C                (I ... input)
C                (O ... output)
C     IUNIT  ... (I)   file
C     CKEY   ... (I)   key name
C     IKEYLN ... (I)   length of key name (no. of characters)
C     IVALUE ... (O)   integer value corresponding to CKEY
C
C-----------------------------------------------------------------------

C     Parameters
      INTEGER IUNIT, IKEYLN, IVALUE
      CHARACTER *(*) CKEY
      
C     local variables:
      CHARACTER*32 BUFFER, FORM

1001  FORMAT ( '(I', I1, ')' )
1002  FORMAT ( '(I', I2, ')' )

      ILEN = 32
      IRET = IGTKEY ( IUNIT, CKEY, IKEYLN, BUFFER, ILEN )
      
      IF ( IRET .EQ. 1 ) THEN
         IF ( ILEN .LT. 10 ) THEN
            WRITE ( FORM, 1001 ) ILEN
         ELSE
            WRITE ( FORM, 1002 ) ILEN
         END IF
         READ(BUFFER(1:ILEN),FORM) IVALUE
      END IF

      IGTINT = IRET
      
      RETURN
      END
C-----------------------------------------------------------------------

C-----------------------------------------------------------------------
      INTEGER FUNCTION IGTFLT ( IUNIT, CKEY, IKEYLN, FVALUE )
C
C     Reads a floating point (REAL) value FVALUE corresponding to
C     the given key CKEY from the file adressed by IUNIT.
C
C     Returns:
C              - 1 on success, -ERR otherwise (see IGTKEY())
C              - the read value via argument FVALUE
C
C                (I ... input)
C                (O ... output)
C     IUNIT  ... (I)   file
C     CKEY   ... (I)   key name
C     IKEYLN ... (I)   length of key name (no. of characters)
C     FVALUE ... (O)   REAL value corresponding to CKEY
C
C-----------------------------------------------------------------------

C     Parameters
      INTEGER IUNIT, IKEYLN
      REAL FVALUE
      CHARACTER *(*) CKEY

C     local variables:
      CHARACTER*32 BUFFER, FORM

1001  FORMAT ( '(F', I1, '.0)' )
1002  FORMAT ( '(F', I2, '.0)' )

      ILEN = 32
      IRET = IGTKEY ( IUNIT, CKEY, IKEYLN, BUFFER, ILEN )
      
      IF ( IRET .EQ. 1 ) THEN
         IF ( ILEN .LT. 10 ) THEN
            WRITE ( FORM, 1001 ) ILEN
         ELSE
            WRITE ( FORM, 1002 ) ILEN
         END IF
         READ(BUFFER(1:ILEN),FORM) FVALUE
      END IF

      IGTFLT = IRET
      
      RETURN
      END
C-----------------------------------------------------------------------

C-----------------------------------------------------------------------
C----------------------------- END OF FILE -----------------------------
C-----------------------------------------------------------------------

IF
         READ(BUFFER(1:ILEN),FORM) FVALUE
      END IF

      IGTFLT = IRET
      
      RETURN
      END
C-----------------------------------------------------------------------

C-----------------------------------------------------------------------
C----------------------------- END OF FILE -----------------------------
C-----------------------------------------------------------------------


