      program PMESS
c     .  Copyright (C) 1991, California Institute of Technology.
c     .  All rights reserved.  U. S. Government sponsorship under
c     .  NASA contract NAS7-918 is acknowledged.
c>  2008-01-08 PMESS Krogh  Fixed integer/parameter output.
c>> 2008-01-06 PMESS Krogh  Added output of comment at end.
c>> 2006-06-30 PMESS Krogh  Removed unused labels.
c>> 2002-05-12 PMESS Krogh  Fixed minor prob. with separator lines.
c>> 2001-12-28 PMESS Krogh  Fixed for new NSKIP feature in MESS.
c>> 1998-11-27 PMESS Krogh  Fixed bug in last extensive change.
c>> 1998-11-27 PMESS Krogh  Fixed bug in last extensive change.
c>> 1998-11-20 PMESS Krogh  Extensive changes for 1 item/data statement.
c>> 1998-11-18 PMESS Krogh  Improved diagnostics.
c>> 1995-12-01 PMESS Krogh  Big fix so char. data at col. 72 is not ' '.
c>> 1992-04-24 PMESS Krogh  Rewritten for new MESS.
c This program prepares data for message processors MESS, SMESS and
c DMESS.  Input is from standard input, output is to a file named tmess.
c Input consists of lines (max. length is 80 characters) which contain
c one or more entries of the form:
c "text"$c
c where "text" is arbitrary text c is a character defining the action in
c MESS, SMESS or DMESS.  See comments there
c for more details.  A $c anyplace, means for c=B,E,R, ...:
c B   Break in text, later text continues on the same line.
c E   End of the text, later text continues on next line.
c R   End of the text, later text repeats the same text.
c H   Used to separate columns in a heading.
c I   Print integer from IDAT.
c J   Print integer from IDAT using user format.
c F   Print floating point number from FDAT.
c G   Print floating point number from FDAT using user format.
c M   Print integer set from MACT.
c N   Start a new line in the message, the message continues.
c (   Define a user format.
c T   Gives a tab.
c #   Use to get a row or column number in matrix output.
c $   Treat the "$$" as an embedded "$$" in the input.  Messages
c     will output the "$$" as a single "$".
c -   Start a negative number for skipping
c 0-9 Digits for skipping
c other    Don't use.
c
c The following characters are used by this program.
c C        Continue the text, don't output the "$C".  This should only
c          be used at the end of a line.
c "blank"  This can be used to introduce additional options.  If the
c          rest of the line is blank, this ends the input for the
c          current array.  If the blank is followed by a D, then the
c          data statement made up for the data above makes up a separate
c          data statement for each array element, and a header comment
c          is output so that the conversion to C will work with a single
c          array. (Until the next line starting with "$ ".)
c          These are the only options currently defined.
c
c PMESS generates parameter names of the form LTXTxx, where xx takes
c values of AA, AB, \ldots .  These names are associated with individual
c messages that might be printed, and are identified by comments of the
c form cAA, cAB, \ldots generated by PMESS.  The values generated for
c these parameters are the character positions of the message in the
c particular character array in which that message is stored.  Messages
c are first stored in a character array named MTXTAA, but if a line
c consisting of a single `\$' in column 1 is encountered the last two
c letters of this name are advanced as for LTXTxx, and further text is
c stored in the new character array.  PMESS generates both the
c declarations and the data for these character arrays.
c
c The comments (and just the comments) generated by PMESS can be used as
c inputs to PMESS.  Thus we recommend including these comments in the
c code both as documentation for the messages, and to simplify
c generating the data if changes to messages are desired.  If these
c comments are passed as input to PMESS, then the reference to column~1
c above should be to column~5.
c
c When generating the data for character strings, PMESS replaces a blank
c in column 72 with a `\$', and starts the next line with a blank.  This
c is done because some editors delete trailing blanks, and some
c compilers require that the trailing blanks in continued character data
c be present.

c Recall that for error messages, the text must start with the
c subprogram name, this name should be terminated with "$B".  We
c suggest that after the subprogram name, one give the text for the
c error messages in order.  Then the text for error message i, can be
c located from an array referenced by the error index.
c
c ************************ Variables Used ******************************
c
c BUF    Array of buffers holding the input.
c CDAT   Used to hold subscript for data statments.
c CHEAD  Text as start of output lines that contain the input lines.
c DBUF   Array used to hold the output data statement.
c I      Last index used currently in BUF.  And temporary index.
c I1     Temporary index.
c I2     Temporary index.
c IN     Index for input buffer, BUF.
c IBEG   Beginning of real input in BUF.  = 1 if doesn't start with
c        "c *" on first line, else is 5.
c IFIRST First index to use next in BUF.
c IFMT   Character variable holding format for integer output.
c ILTEXT Last location used in the output string.
c IOUT   Integer value to be output.
c ISAVE  Array containing values to output for the parameters output.
c        This is < 0 when we are working on a continued line, or it is
c        the last of a group of entries in which case its absolute value
c        is where the next entry would have started.
c ISAVE1 Value of ISAVEI for first ISAVE location of current set.
c ISAVEI Last index for storing into ISAVE.
c J      Temporary index.
c JFIRST First index used currently in BUF.
c K      Temporary index.
c KBR     used to track where character strings break.
c KCDAT  Number of charcters in CDAT, 0 if no array is output.
c KK     Temporary storage.
c KLINE  number of lines to hold the data statments.
c KLINEI Value of KLINE for first data statement in the current set.
c KM     Index of character following a "$" in 'BER#CNIFJGHM(T$'.  If
c        = 5, (a "C") then skip last two characters and continue; if <7,
c        got something allowed at end of line; else got something that
c        shouldn't appear at the end of a line.
c KML    The last value of KM (-1 initially).  Used to decide if a line
c        is a continuation line.
c KONLIN Number of continuation lines in the current data statement.
c KTEXT  Count of characters in current output array.
c KV     Used as index into LCE and LCA.
c LBUF   Array giving index of last character to save in BUF().  If this
c        is not a continuation line, the negative of the index is saved.
c LCA    LCA(KV) gives number of elements in array for text.
c LCE    Array, LCE(KV) gives character length for array elements in the
c        KV-th text array.
c LDONE  Set = .true. if we are finished with a data output line.
c LEFT   Number of characters left before current character array entry
c        is filled.
c LEND   End of text in OBUF.
c LI     Absolute value of current location in LBUF.
c LINE   Number of lines in the current parameter statement.
c LLOC   Location of next character to be stored in current array.
c MAXP   Used in computing maximum value for a parameter.
c MORE   Logical variable set .true. until we hit an end of file.
c        Also set .true. if we have an extra comment line to output.
c OBUF   Buffer holding the output, and used for temporary storage.
c PARAM  Contains text (that is modified) for output of parameter data.
c
c ************************ Variable Declarations ***********************
c
      character BUF(200)*80,CDAT*8,IFMT*4,OBUF*160,DBUF(300)*72
      character PARAM*7, MTXT*6, CHEAD*4
      logical LDONE, MORE
      integer I, I1, I2, IBEG, IFIRST, ILTEXT, IN, ISAVE(1000),
     1   ISAVE1, ISAVEI, J, JFIRST, K, KBR, KCDAT, KK, KLINE,
     2   KLINEI, KM, KML, KONLIN, KTEXT, KV, LBUF(200), LCA(500),
     3   LCE(500), LEFT, LEND, LI, LINE, LLOC, MAXP
      data PARAM/ 'LTXTAA=' /
      data CHEAD/ 'cAA ' /
      data MTXT / 'MTXTAA' /
      data IFMT / '(Ix)' /
   10 format(' $$$$ Warning -- Have', I3, ' continuation lines.'/
     1  ' Use line starting with "$ " to correct.')
   20 format(1X, A/
     1  ' The above line is missing a "$"  and is ignored.')
   30 format(1X, A/
     1  ' Last line given above must end with $B, $E, $R, or $M.')
   40 format('Unrecognized option in line below'/ A)
   50 format(' Ignored line starting with'/ A)
   60 format(' Line below is too long, use "$C" to correct.'/ 1X,A)
   70 format('C End of storing data by elements.')
c
c ************************ Start of executable code ********************
c                                    Open files.
c debug      open (UNIT=9, FILE='TMP.ERR')
      open (UNIT=10, STATUS='SCRATCH')
      open (UNIT=11, STATUS='UNKNOWN', FILE='tmess')
      write(11, '(''c ********* Error message text ***************''/
     1''c[Last 2 letters of Param. name]  [Text generating message.]'')'
     2            )
      MAXP = 0
      IBEG = 0
      MORE = .true.
      KML = -1
      KLINE = 0
      ISAVEI = 0
      KV = 0
  100 KTEXT = 0
      KCDAT = 0
      IN = 0
c
  110 IN = IN + 1
  120 ILTEXT = 0
      BUF(IN) = ' '
c debug      read(9, '(A)', END=160) BUF(IN)
      read(*, '(A)', END=160) BUF(IN)
      if (IBEG .le. 0) then
c              Checks so we know where the real column 1 is.
         if (IBEG .eq. 0) then
            if (BUF(IN)(1:4) .eq. 'c **') then
               IBEG = -1
               go to 110
            end if
            IBEG = 1
         else
            if (BUF(IN)(1:2) .ne. 'c[') then
               print '(''Inconsistent use of "c" at start'')'
               go to 400
            end if
            IBEG = 5
            go to 110
         end if
      end if
      IFIRST = IBEG
c                 Check out individual lines.
      I = index(BUF(IN)(IFIRST:80), '$')
      JFIRST = IFIRST
      if (I .eq. 0) then
         if (BUF(IN) .eq. ' ') go to 120
         if (JFIRST .eq. 1) print 20, BUF(IN)
         go to 120
      else
  140    I = I + IFIRST
         IFIRST = I + 1
c                    123456789012345
         KM = index('BER#CNIFJGHM(T$', BUF(IN)(I:I))
  145    if (KM .eq. 0) then
c                          Check for '-' or a digit
            if (((BUF(IN)(I:I) .ge. '0') .and. (BUF(IN)(I:I) .le. '9'))
     1           .or. (BUF(IN)(I:I) .eq. '-')) then
               KM = 8
               go to 145
            end if
c                          No match
            if (I .eq. IBEG+1) then
c                          Check if this is a special separator line.
               if ((BUF(IN)(IBEG+1:IBEG+1) .le. ' ')) then
c                     Separator line, error if last line was continued
                  if (KML .ge. 5) print 30, BUF(IN-1)
                  KML = -1
                  J = IBEG
                  if (BUF(IN)(J+2:J+2) .ne. ' ') then
  150                J = J + 1
                     if (BUF(IN)(J+1:J+1) .ne. ' ') then
                        if (BUF(IN)(J+1:J+1) .eq. 'D') then
c                            Setup for output of array subscripts.
                           KCDAT = 5
                        else
c                           Flag for unrecognized option
                           IBEG = -IBEG
                        end if
                        go to 150
                     end if
                     if (IBEG .lt. 0) then
c                           Output message for unrecognized option.
                        print 40, BUF(IN)(1:J)
                        IBEG = -IBEG
                     end if
                  end if
                  write (11, '(''c   '',A)') BUF(IN)(IBEG:J)
                  go to 170
               end if
            end if
            print 50, BUF(IN)(1:I)
            go to 110
         else if (KM .ge. 6) then
            I = index(BUF(IN)(IFIRST:80), '$')
            if (I .ne. 0) go to 140
            I = IFIRST - 1
         end if
      end if
      ILTEXT = ILTEXT + (I - JFIRST)
      if (ILTEXT .gt. 67) print 60, BUF(IN)
      ILTEXT = ILTEXT + IBEG
      if (KML .ge. 5) then
c              Line is being continued.
         write (11, '(A,A)') 'c   ', BUF(IN)(IBEG:ILTEXT)
      else
c              This is a header line.
         write (11, '(A,A)') CHEAD, BUF(IN)(IBEG:ILTEXT)
c              Update characters in CHEAD for the next one.
         if (CHEAD(3:3) .eq. 'Z') then
            CHEAD(2:2) = char(ichar(CHEAD(2:2))+1)
            CHEAD(3:3) = 'A'
         else
            CHEAD(3:3) = char(ichar(CHEAD(3:3))+1)
         end if
      end if
      if (KM .eq. 5) ILTEXT = ILTEXT - 2
      KTEXT = KTEXT + ILTEXT
c         Store negative of the count if line is not a continuation.
      if (KML .lt. 5) ILTEXT = -ILTEXT
      KML = KM
      LBUF(IN) = ILTEXT
      go to 110
c
c At this point the header comments have been written, BUF(IN)
c contains the input lines, and LBUF(IN) contains the number
c of characters on each of these input lines.  It may be necessary
c to adjust this count later.
  160 MORE = .false.
      if (KML .ge. 5) print 30, BUF(IN-1)
c Make up the data statements for the lines seen so far.
  170 IN = IN - 1
      KTEXT = KTEXT - (IBEG-1) * IN
      if (KTEXT .eq. 0) go to 300
      KV = KV + 1
      KLINEI = KLINE
      ISAVE1 = ISAVEI

      LCA(KV) = 1 + (KTEXT-1) / 248
      KBR = (KTEXT-1) / LCA(KV)
c Below is the tricky part.  Make up the data statments, assuming
c a character array of length KBR.  Need to fill up the lines,
c inserting a $ if a line would end with a blank.  Also, need to
c change ' to ''.  If we need to much space, KBR must be increased.
  210 KBR = KBR + 1
      LEFT = KBR
      LCE(KV) = KBR
      if (KCDAT .ne. 0) then
         KCDAT = 5
         CDAT = '(1)/'''
      end if
      KLINE = KLINEI
      ISAVEI = ISAVE1
      LEND = 0
      LLOC = 1
      do 280 I = 1, IN
         LI = LBUF(I)
         if (LI .lt. 0) then
            LI = -LI
            ISAVEI = ISAVEI + 1
            ISAVE(ISAVEI) = LLOC
         end if
         J = IBEG
  220    if (LEND .eq. 0) then
            OBUF(1:19) = '      data ' // MTXT // '/'''
            LEND = 19
            if (KCDAT .ne. 0) then
               LEND = KCDAT + 17
               OBUF(18:LEND) = CDAT(1:KCDAT)
               do 230 K = KCDAT-3, 2, -1
                  I1 = ichar(CDAT(K:K))
                  if (I1 .lt. ichar('9')) then
                     CDAT(K:K) = char(I1 + 1)
                     go to 240
                  end if
                  CDAT(K:K) = '0'
                  if (K .eq. 2) then
                     CDAT(2:2) = '1'
                     KCDAT = KCDAT + 1
                     CDAT(KCDAT-3:KCDAT) = '0)/'''
                     go to 240
                  end if
  230          continue
  240          continue
            end if
         end if
c
  250    if (J .gt. LI) then
            if (I .lt. IN) go to 280
            J = 1
            LI = LEFT
            BUF(I)(1:LEFT) = ' '
         end if
  260    I1 = index(BUF(I)(J:LI), '''')
         if (I1 .eq. 0) I1 = LI - J + 1
         I2 = min(I1, LEFT)
         if (LEND + I2 .gt. 72) I2 = 72 - LEND
         OBUF(LEND+1:LEND+I2) = BUF(I)(J:J+I2-1)
         J = J + I2
         LLOC = LLOC + I2
         LEND = LEND + I2
         if (LEND .eq. 72) then
            if (OBUF(72:72) .eq. ' ') then
               if ((I .ne. IN) .or. (BUF(I)(1:LI) .ne. ' ')) then
c   Replace blank in col. 72 with $ and reread the blank later.
                  J = J  - 1
                  OBUF(72:72) = '$'
               end if
            end if
         end if
         if (OBUF(LEND:LEND) .eq. '''') then
c                           Double up on apostrophes.
            LEND = LEND + 1
            OBUF(LEND:LEND) = ''''
         end if
         LEFT = LEFT - I2
         LDONE = LEFT .eq. 0
         if (LDONE) then
            LEFT = KBR
            OBUF(LEND+1:LEND+2) = ''','
            LEND = LEND + 2
            LDONE = (I .eq. IN) .or. (KCDAT .ne. 0)
            if (LDONE) then
c  End of current data statement.
               if (I .eq. IN) then
c if (J .le LI) we didn't get all we should have, try again.
                  if (J .le. LI) go to 210
               end if
               OBUF(LEND:LEND) = '/'
            else
c  Start next array element.
               LEND = LEND + 1
               OBUF(LEND:LEND) = ''''
            end if
         end if
         if ((LEND .ge. 72) .or. LDONE) then
  270       KLINE = KLINE + 1
            DBUF(KLINE) = OBUF(1:min(LEND, 72))
            LEND = LEND - 72
            if (LEND .gt. 0) then
               OBUF(6:6+LEND) = '*' // OBUF(73:72+LEND)
               LEND = LEND + 6
               if (LDONE) go to 270
            end if
            if (LDONE) then
               if (I .eq. IN) go to 290
               LEND = 0
               go to 220
            else if (LEND .le. 0) then
               OBUF(6:6) = '*'
               LEND = 6
            end if
         end if
         if (J .le. LI) go to 260
         if (I .eq. IN) then
            if (LEFT .ne. 0) go to 250
         end if
  280 continue
c           Check here for too many continuation lines.
  290 if (KLINE .gt. KLINEI + 20) then
         if (KCDAT .eq. 0) print 10, KLINE - KLINEI - 1
      end if
      MAXP = max(MAXP, LLOC)
  300 if (MORE) then
         if (MTXT(6:6) .ne. 'Z') then
            MTXT(6:6) = char(ichar(MTXT(6:6))+1)
         else
            MTXT(5:6) = char(ichar(MTXT(5:5))+1) // 'A'
         end if
         go to 100
      end if

c                          Integer declarations for parameters
      LINE = 0
      do 320 I = 1, ISAVEI
 310    continue
        if (ISAVE(I) .gt. 0) then
          if (LINE .eq. 0) then
            LINE = 1
            OBUF(1:14) = '      integer '
            LEND = 14
          else if (LEND+7 .gt. 72) then
            write (11, '(A)') OBUF(1:LEND)
            LINE = LINE + 1
            if (LINE .gt. 19) then
              LINE = 0
              go to 310
            end if
            OBUF(1:7) = '     * '
            LEND = 7
          end if
          OBUF(LEND+1:LEND+6) = PARAM
          OBUF(LEND+7:LEND+7) = ','
          LEND = LEND + 7
        end if
        if (PARAM(6:6) .ne. 'Z') then
          PARAM(6:6) = char(ichar(PARAM(6:6))+1)
        else
          PARAM(5:6) = char(ichar(PARAM(5:5))+1) // 'A'
        end if
 320  continue
      if (LINE .ne. 0) write (11, '(A)') OBUF(1:LEND-1)
c
c                          Declare values for the parameters
      call PMESSI(MAXP-1, IFMT, K)
      K = K + 8
      KK = 18 - K
      if (LINE .ne. 0) then
        LINE = 0
        PARAM(5:6) = 'AA'
        do 350 I = 1, ISAVEI
          if (ISAVE(I) .gt. 0) then
 330        if (LINE .eq. 0) then
              LINE = 1
              OBUF(1:17) = '      parameter ('
              LEND = 17
            else if (LEND + K .gt. 72) then
              if (LINE .eq. 19) OBUF(LEND:LEND) = ')'
              write (11, '(A)') OBUF(1:LEND)
              LINE = LINE + 1
              if (LINE .gt. 19) then
                LINE = 0
                go to 330
              end if
              OBUF(1:KK) = '     * '
              LEND = KK
            end if
            OBUF(LEND+1:LEND+7) = PARAM
            write(OBUF(LEND+8:LEND+K), IFMT) ISAVE(I)
            LEND = LEND + K
            OBUF(LEND:LEND) = ','
          end if
          if (PARAM(6:6) .ne. 'Z') then
            PARAM(6:6) = char(ichar(PARAM(6:6))+1)
          else
            PARAM(5:6) = char(ichar(PARAM(5:5))+1) // 'A'
          end if
 350    continue
        OBUF(LEND:LEND) = ')'
        write(11, '(A)') OBUF(1:LEND)
      end if
c
c                          Declare the character variables
      KV = 0
      MTXT(5:6) = 'AA'
      do 360 I = 1, ISAVEI
        if (ISAVE(I) .eq. 1) then
          KV = KV + 1
          OBUF(1:23) = '      character ' // MTXT // '('
          call PMESSI(LCA(KV), IFMT, K)
          LEND = 23 + K
          write(OBUF(24:LEND), IFMT) LCA(KV)
          OBUF(LEND+1:LEND+5) = ') * ('
          call PMESSI(LCE(KV), IFMT, K)
          write(OBUF(LEND+6:LEND+5+K), IFMT) LCE(KV)
          LEND = LEND + 6 + K
          OBUF(LEND:LEND) = ')'
          write(11, '(A)') OBUF(1:LEND)
          if (MTXT(6:6) .ne. 'Z') then
            MTXT(6:6) = char(ichar(MTXT(6:6))+1)
          else
            MTXT(5:6) = char(ichar(MTXT(5:5))+1) // 'A'
          end if
        end if
  360 continue
c
c                          Write the data statements
      KONLIN = 0
      do 390 K = 1, KLINE
         if (DBUF(K)(6:6) .eq. ' ') then
            if (MORE) then
               if ((DBUF(K)(18:18).ne.'(').or.(DBUF(K)(19:20).eq.'1)'))
     1            then
                  MORE = .false.
                  write (11, 70)
               end if
            end if
            if (DBUF(K)(18:20) .eq. '(1)') then
               MORE = .true.
               write (11, '(''C++ Save data by elements if ~.C.'')')
            end if
         end if
         I = 72
         if (DBUF(K)(72:72) .eq. ' ') then
            do 370 I = 71, 7, -1
               if (DBUF(K)(I:I) .ne. ' ') go to 380
  370       continue
         end if
  380    write (11, '(A)') DBUF(K)(1:I)
  390 continue
      if (MORE) write (11, 70)
      write (11, '(''c **** End of automatically generated text'')')
      if (KONLIN .gt. 19) print 10, KONLIN
      print '('' tmess has been output.'')'
  400 close (10)
      close (11)
      stop
      end

      subroutine PMESSI(IOUT, IFMT, K)
c Sets IFMT to format for printing IOUT, and set K to number of digits
c that is printed by that format.
      integer IOUT, K, KK
      character*4 IFMT
c
      K = 1
      KK = 10
   10 if (KK .le. IOUT) then
         KK = 10 * KK
         K = K + 1
         go to 10
      end if
      IFMT(3:3) = char(ichar('0') + K)
      return
      end
