Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28446 Discussions

A READ statement is altering the contents of the string read...

jajdavid
Beginner
226 Views

*Intel Visual Fortran Compiler Professional for applications running on IA-32, Version 11.1 Build 20090930 Package ID: w_cprof_p_11.1.048
*Copyright (C) 1985-2009 Intel Corporation. All rights reserved.

*SPR 12/29/2011

*"09NOV2011" is OK

*"11 09/2011" is NOT OK - should be "11/09/2011"

*Internal variable DATE is being modified when the FORMAT statement at LABEL 4
*is used. If the format statement at LABEL 6 is used, then output is OK.

*John David
*jdavid@tntem.com

IMPLICIT INTEGER (A-Z)
CHARACTER DATE*10,LINE*256
LINE='NOV 2 2011'
L=10
CALL DATE_M8D2Y4_ADJ9(DATE,LINE(1:L),7,*1)
WRITE(6,*) DATE
CALL DATE_M8D2Y4_ADJ(DATE,LINE(1:L),7,*1)
WRITE(6,*) DATE
1 CALL EXIT
END


SUBROUTINE DATE_M8D2Y4(DATE1,DATE2,*)
IMPLICIT INTEGER (A-Z)
PARAMETER MA=9
CHARACTER DATE1*(*),DATE2*(*),DATE*10,LINE*256,YYMMDD*8
CHARACTER MONTH(0:11)*9,MON(0:11)*2
INTEGER ASTR(0:MA),AEND(0:MA)
DATA MONTH/'JANUARY','FEBRUARY','MARCH','APRIL','MAY','JUNE',
*'JULY','AUGUST','SEPTEMBER','OCTOBER','NOVEMBER','DECEMBER'/
CHARACTER MONTH3(12)*3/'JAN','FEB','MAR','APR','MAY',
*'JUN','JUL','AUG','SEP','OCT','NOV','DEC'/
DATA MON/'01','02','03','04','05','06',
*'07','08','09','10','11','12'/
DATA DATE/'00/00/2000'/
REVERSE=0
ADJ=0
2 L=10
LINE(1:L)=DATE2
ARGS=2
ASTR(0)=1
AEND(0)=3
ASTR(1)=5
AEND(1)=5
ASTR(2)=7
AEND(2)=10
IF(ARGS.NE.2.AND.ARGS.NE.3) GOTO 5
DO I=0,11
IF(LINE(ASTR(0):AEND(0)).EQ.MONTH(I).OR.LINE(ASTR(0):AEND(0)).EQ.MONTH(I)(1:3)) THEN
DATE(1:2)=MON(I)
GOTO 1
ENDIF
END DO
IF(AEND(0)-ASTR(0).EQ.0) THEN
DATE(1:1)='0'
DATE(2:2)=LINE(ASTR(0):AEND(0))
ELSE IF(AEND(0)-ASTR(0).EQ.1) THEN
DATE(1:2)=LINE(ASTR(0):AEND(0))
ELSE
GOTO 5
ENDIF
1 IF(AEND(1)-ASTR(1).EQ.0) THEN
DATE(4:4)='0'
DATE(5:5)=LINE(ASTR(1):AEND(1))
ELSE IF(AEND(1)-ASTR(1).EQ.1) THEN
DATE(4:5)=LINE(ASTR(1):AEND(1))
ELSE
GOTO 5
ENDIF
IF(AEND(2)-ASTR(2).EQ.1) THEN
DATE(7:10)=YYMMDD(1:4)
ELSE IF(AEND(2)-ASTR(2).EQ.3) THEN
DATE(7:10)=LINE(ASTR(2):AEND(2))
ELSE
GOTO 5
ENDIF
IF(DATE(1:2).EQ.'00'.OR.DATE(4:5).EQ.'00'.OR.DATE(7:7).EQ.'0') GOTO 5
IF(ADJ.NE.0) THEN
READ(DATE,3,ERR=5) MM,DD,YY
3 FORMAT(I2,1X,I2,1X,I4)
YMD=YY*10000+MM*100+DD
YMD=20111109
YY=YMD/10000
YMD=YMD-YY*10000
MM=YMD/100
DD=YMD-MM*100
WRITE(DATE,4,ERR=5) MM,DD,YY
4 FORMAT(I2,'/',I2,'/',I4)
IF(DATE(1:1).EQ.' ') DATE(1:1)='0'
IF(DATE(4:4).EQ.' ') DATE(4:4)='0'
ENDIF
IF(REVERSE.EQ.0) THEN
DATE1=DATE
ELSE IF(REVERSE.GT.0) THEN
DATE1=DATE(7:10)//'/'//DATE(1:5)
ELSE IF(REVERSE+1.EQ.0) THEN
READ(DATE(1:2),4) I
6 FORMAT(I2)
DATE1=DATE(4:5)//MONTH3(I)//DATE(7:10)
ELSE
DATE1=DATE(7:10)//'-'//DATE(1:2)//'-'//DATE(4:5)//' 00:00:00.000'
ENDIF
RETURN
5 RETURN 1

ENTRY DATE_M8D2Y41(DATE1,DATE2,*)
REVERSE=1
ADJ=0
GOTO 2

ENTRY DATE_M8D2Y4_ADJ(DATE1,DATE2,ADJ1,*)
REVERSE=0
ADJ=ADJ1
GOTO 2

ENTRY DATE_M8D2Y4_ADJ9(DATE1,DATE2,ADJ1,*)
REVERSE=-1
ADJ=ADJ1
GOTO 2

ENTRY DATE_M8D2Y4_ADJ23(DATE1,DATE2,ADJ1,*)
REVERSE=-2
ADJ=ADJ1
GOTO 2

ENTRY DATE_M8D2Y41_ADJ(DATE1,DATE2,ADJ1,*)
REVERSE=1
ADJ=ADJ1
GOTO 2

END

0 Kudos
2 Replies
Steven_L_Intel1
Employee
226 Views
I can reproduce this in your program, but when I extract the WRITE into a separate program, it works fine. Puzzling. I will investigate further.
0 Kudos
Steven_L_Intel1
Employee
226 Views
This was, in a way, fun - and required that I stretch my memory WAAAAAAYYY back....

Here's what's going on.

You have the following WRITE, the one that is giving you the blank on the second time through:

WRITE(DATE,4,ERR=5) MM,DD,YY
4 FORMAT(I2,'/',I2,'/',I4)

where DATE is a CHARACTER(10) variable. This is perfectly fine.

Then, later in this routine, you have this:

READ(DATE(1:2),4) I

Note that it is using the same format, 4, as for the WRITE. Note also that format 4 has two '/' edit descriptors. What do you suppose these do on a READ?

[Insert Final Jeopardy! music here...]

Pencils down!

In Fortran 77, and later versions of the standard, this is not legal. An "apostrophe edit descriptor must not be used on input". But... In Fortran 66, this did have a meaning - it caused characters from the input stream to be read into the format, as many characters as there were in the edit descriptor. (Well, technically, Fortran 66 used the H format for this, but most compilers accepted an apostrophe string as equivalent). This was used to construct labels and column headers that were read from the input deck, since Fortran 66 had no character type.

Intel Fortran still supports the old F66 feature and this is what you got. The first time the function was called, and this READ was executed, one character was transferred from the input stream. Since the input stream was only two characters long, it was effectively padded with blanks and the first slash in the format was replaced with a blank. On the second call, the format was used in a WRITE except the first slash was now a blank, hence the "wrong" output.

Clearly this is old code you are compiling (at least I certainly hope so!), and it is not surprising to me that some other compiler might treat this usage differently. I do note that our compiler fails to give a standards warning about this (it can do so because it DOES notice you have an apostrophe edit descriptor used in a READ and it then puts the format in read-write memory.) I will ask the developers to add a standards warning for that - not that you would have seen that normally, since this code is non-standard (for recent standards) in so many other ways.

The solution for you is to use a different format for the READ that doesn't have an apostrophe edit descriptor. You could just use '(I2)' in the READ instead of the label.
0 Kudos
Reply