Previous: CHARACTER*n for Strings Up: Porting Fortran Next: Array I/O

READ & WRITE to Strings

The conversion of strings from BYTE to CHARACTER*n implies that the methods used to do input and output to strings must change as well. Previous code often set up a buffer, then used outcon to put numeric values in the string. The result would then be printed. For example (taken from the program amos):

      LOGICAL*1 MS1(52)/' ','V','E','L','=','*','*','*','*','*','.','*',
     &'*',' ',' ','(','V','R','A','D',',','V','T','A','N',')','=','(',
     &'*',')',' ','M','/','S','E','C'/
      CALL OUTCON(VRES,MS1(14),9,2)
      CALL OUTCON(VRAD,MS1(35),7,2)
      CALL OUTCON(VTAN,MS1(45),9,2)
      CALL QPRINT(MS1,52)

outcon (and its counterpart, incon) have many serious portability problems. They would have to be converted to output to CHARACTER*n variables instead of BYTE arrays, since the output would be printed via qprint or xvmessage anyway. outcon and incon were originally created to avoid using the Fortran I/O library in the days on the IBM mainframe when memory was at a premium. That is no longer a constraint. The Fortran I/O library is more portable, and easier to use. For these reasons, outcon and incon will not be supported in the portable system.

To perform input and output conversion, simply use the Fortran I/O package on what is called an ``internal file''. An internal file to Fortran is simply a CHARACTER*n variable. Just give the name of the variable (it may be a substring if you wish) instead of the unit number in a Fortran READ or WRITE statement. Note that you must still write to a string and send the string to qprint or xvmessage. Do not attempt to write directly to the terminal. Any messages written directly to the terminal will not appear in the session log, and could very well be printed in unexpected ways due to interaction with VICAR I/O. Also, messages written directly will not be handled properly by the forthcoming VICAR GUI.

Here is one way to code the above example (the leading blank is not required in xvmessage):

      CHARACTER*80 MS1
      WRITE (MS1,1001) VRES, VRAD, VTAN
 1001 FORMAT ('VEL=', F9.2, ' (VRAD,VTAN)=(', F7.2, ',', F9.2, ') M/SEC')
      CALL XVMESSAGE(MS1, ' ')

Since an internal file may be a substring as well, you can do a more direct conversion (although the previous example is generally the preferred method):

      CHARACTER*80 MS1
      DATA MS1 /'VEL=******.** (VRAD,VTAN)=(+***.**,+*****.**) M/SEC'/
      WRITE (MS1(5:13), '(F9.2)') VRES
      WRITE (MS1(28:34), '(F7.2)') VRAD
      WRITE (MS1(36:44), '(F9.2)') VTAN
      CALL XVMESSAGE(MS1, ' ')

There are three things to note about this example. First, the DATA statement is separate from the declaration. Putting initialization data on the declaration line is not portable. Second, the format specifier may be put in-line in the WRITE statement if you wish. Last, the numbers changed from the outcon call because the leading blank was eliminated. The xvmessage routine always prints the first character, with no carriage control. So, all the character position numbers are one less than in the outcon example.

Conversion of data from string to numeric form using READ is similar. Use standard Fortran I/O using the CHARACTER*n variable as the internal file. Substrings are much more useful on READ to read only the portion you are interested in. For example, the following call form able86 is typical:

      BUF(2) = PAR(1)                 !Frame number

where ALABEL is the input string (already a CHARACTER*n variable), BUF(2) is an integer receiving the value, and NPAR is ignored. The value is an integer in the range 0 to 99 (obtained from the documentation), so this call could be converted to:

      READ (ALABEL(OFF+I+5:),'BN,I2') BUF(2)

You may want to make use of the ERR=n clause on reads in order to trap errors such as a decimal point being present in an integer.