bug in F77 standard? 
Author Message
 bug in F77 standard?



Quote:
> I ran into a problem illustrated with the following test code on a VAX
> with VMS but have the same problem on an IBM with AIX, so if it's a bug
> then probably of a more general kind.  I noticed that although the file
> I opened was on the disk, it was empty, and the data were in FOR010.DAT
> (fort.10 with AIX) rather than in TEST.DAT.  The problem was that I
> opened another file in a subroutine call, read some stuff in and closed
> it after opening and before writing to TEST.DAT in the main programme.
> The problem goes away if I DON'T use the same unit number, which I
> coincidentally did when the problem cropped up.

    [Program demonstrating problem deleted...]

        Without laying my left hand on the Standard and raising my right
    hand :-), fortran logical  unit  numbers  are  "common" to an entire
    program.   That  allows you to do _modular_ :-) things like  OPEN  a
    unit in an initialization subroutine, WRITE to or READ from the unit
    in any number of i/o  routines,  and  close  the  unit  in  an  exit
    routine.   The  behaviour  you saw is exactly what I'd expect of any
    Fortran implementation.

        The problem of keeping  track  of  logical  unit  numbers is, in
    fact,  one  of the "squirrelliest" aspects of Fortran i/o, the  fact
    that you don't know what unit numbers the  author  of  some  library
    routine decided to use, temporarily or permanently.  VMS Fortran can
    use  the  run-time  library routines LIB$GET_LUN and LIB$FREE_LUN to
    coordinate the use  of  unit  numbers,  _provided_ that all routines
    needing  unit  numbers  use this mechanism, at least  for  the  unit
    numbers in the range "controlled" by  LIB$GET_LUN  (units  100-119).
    But  it doesn't help for lower unit numbers, nor for "uncooperative"
    routines.

        The machinery  for  doing  this  is  extremely  simple and could
    easily  be  implemented  in anyone's Fortran.  Which  leads  to  the
    obvious question, does Fortran 90 provide  any  new  intrinsics  for
    allocating/deallocating logical unit numbers?

        [To which I may be able  to  answer my own question: one _could_
    use  the INQUIRE statement (present in F77) to check whether a  unit
    was already OPENED before using that unit number.  The  unit  number
    you  finally  opened  would then be passed through COMMON or through
    subroutine arguments to those routines needing  to do i/o.  But I've
    _never_  seen  code  that uses INQUIRE for this purpose,  though  it
    seems somewhat obvious.  And it does nothing to prevent some _other_
    routine from usurping your unit number, which you painstakingly made
    sure was not in use before _you_ opened it, and  fouling  things  up
    royally.]

        -Ken
--

 SLAC, P.O.Box 4349, MS 46  |  DECnet:   45537::FAIRFIELD (45537=SLACVX)
 Stanford, CA   94309       |  Voice:    415-926-2924    FAX: 415-926-3515
 -------------------------------------------------------------------------
 These opinions are mine, not SLAC's, Stanford's, nor the DOE's...



Wed, 27 Aug 1997 15:06:18 GMT  
 bug in F77 standard?

Quote:

>I ran into a problem illustrated with the following test code on a VAX
>with VMS but have the same problem on an IBM with AIX, so if it's a bug
>then probably of a more general kind.  I noticed that although the file
>I opened was on the disk, it was empty, and the data were in FOR010.DAT
>(fort.10 with AIX) rather than in TEST.DAT.  The problem was that I
>opened another file in a subroutine call, read some stuff in and closed
>it after opening and before writing to TEST.DAT in the main programme.
>The problem goes away if I DON'T use the same unit number, which I
>coincidentally did when the problem cropped up.

Your subject is right on target - this is, in my opinion, a bug in the
F77 (and F90) standard.  The name of the bug is "Open on a connected unit",
probably #1 on my "most hated Fortran standard features" list.

What this feature does is as follows.  If you do an OPEN on a unit which
is already connected (open), if the filename in the second OPEN matches
that of the opened file, then all that happens is that the value of BLANK=
(and in F90, I think, PAD=) is changed to be what is specified in the
second OPEN.  Otherwise the first file is silently closed and the new
file opened.

So here's the sequence of operations in your code:

      OPEN (NUM,FILE=UTFILE,STATUS='NEW',ACCESS='SEQUENTIAL',
     1     FORM='FORMATTED', BLANK='NULL')

File 'TEST.DAT' (assigned to UTFILE) is opened on unit 10 (value of NUM)

      VAR = 10
      CALL OPENIT(VAR)
      [in OPENIT]
      OPEN(VAR, FILE='T.DAT',STATUS='OLD',ACCESS='SEQUENTIAL',
     $     FORM='FORMATTED', BLANK='NULL')

Filename doesn't match, TEST.DAT closed, T.DAT opened.

      CLOSE (VAR, STATUS='KEEP')

T.DAT closed

      [back in main program]
      WRITE (NUM, *) 2.0, SQRT(2.0)  

Unit 10 (NUM) was not open, so a default open using FOR010.DAT (on VMS)
is done, the write goes there.

      CLOSE(NUM, STATUS='KEEP')

Unit 10 is closed.

What to do?  Well, as you suggested, an INQUIRE by unit to see if the unit
is open will work - do it in a loop until you find one that's available.
On VMS you can use LIB$GET_LUN and LIB$FREE_LUN to arbitrate LUN usage,
but it's easy enough to do something similar in a portable fashion
using INQUIRE.


DEC Fortran Development           WWW:  http://www.digital.com/info/slionel.html
Digital Equipment Corporation     CompuServe: 75263,3001
110 Spit Brook Road, ZKO2-3/N30
Nashua, NH 03062-2698             "Free advice is worth every cent"




Thu, 28 Aug 1997 00:22:33 GMT  
 bug in F77 standard?

   Being a FORTRAN programmer, I always think `everything's local unless
   I put it in a common block'.  This is a serious hindrance to modularity,
   since every routine has to make sure not to use the same unit numbers as
   another one.

Unit numbers are global to a program, as are procedure names, COMMON
block names, and so on.

If they weren't, how do you suppose you could write a "modular" program
where one procedure handles opening a file, another procedure reads from
that file, and a third handles closing the file?

I've maintained largish Fortran packages that have to manage unit
numbers in a dynamic-allocation fashion to solve the problem you
identify resulting from their global nature, but believe me, the
problem would be far worse if every procedure had its own view
of unit numbers, and Fortran code would be far less modular.

If you need dynamic unit allocation, as in:

        INTEGER MYUNIT, GTUNIT()
        MYUNIT = GTUNIT ()
        OPEN (UNIT=MYUNIT,...)
        ...
        CLOSE (UNIT=MYUNIT)
        CALL FRUNIT (MYUNIT)

Then you do just write GTUNIT() and FRUNIT, which share information
on known-free/in-use units, and GTUNIT() uses INQUIRE to find new
free units if it doesn't already know about them.  (You might also
want to design RSUNIT(N), which reserves unit N -- like GTUNIT,
but forces it to pick unit N.  Useful for "preallocating" units 5
and 6 since many systems use those for I/O and you thus wouldn't
want to reuse them for files, or I/O to * might stop working.)

Just have your programs use a mechanism like this to do dynamic
unit allocation.  (Note that standard, and even old K&R C, I believe,
provides a mechanism like the above in the stdio library...i.e. C's
FILE * pointers are still global, but the interface to dynamically
acquire them, and the library code to support that interface, are
part of the C world already.)

(Boy, this brings up very OLD memories of PRIMOS, like FUTIL, ED, CX,
JOB/BATCH/FIXBAT/&c...!  I believe they all had dynamic unit allocation
mechanisms written into their Fortran code.  Hmm, you'd think I could
remember the name of the queue-manager program for the batch subsystem,
but maybe that's BATCH!)
--




Thu, 28 Aug 1997 00:55:46 GMT  
 bug in F77 standard?

Quote:

> If you need dynamic unit allocation, as in:
>    INTEGER MYUNIT, GTUNIT()
>    MYUNIT = GTUNIT ()
>    OPEN (UNIT=MYUNIT,...)
>    ...
>    CLOSE (UNIT=MYUNIT)
>    CALL FRUNIT (MYUNIT)
> Then you do just write GTUNIT() and FRUNIT, which share information
> on known-free/in-use units, and GTUNIT() uses INQUIRE to find new
> free units if it doesn't already know about them.  (You might also
> want to design RSUNIT(N), which reserves unit N -- like GTUNIT,
> but forces it to pick unit N.  Useful for "preallocating" units 5
> and 6 since many systems use those for I/O and you thus wouldn't
> want to reuse them for files, or I/O to * might stop working.)

Very nice, Craig, but now you have to deal with a (object-files-only)  
library, that opens its own 'temporary' files on 'temporarily used unit  
numbers' - Wherefore I say onto you, my Brethren: Pray for a  
Standard-Conforming Way To Determine Whether A Certain Unit Number Is  
Already In Use As A File Unit ....

Wow - got sour fingers from typing all this uppercase stuff ...

--

Saturnushof 14, 3738 XG  Maartensdijk, The Netherlands
Phone: +31 3461 4290; Fax: +31 3461 4286
The NeXT Generation (t-t-talking 'bout my g-g-generation ...).



Thu, 28 Aug 1997 03:11:17 GMT  
 bug in F77 standard?

Quote:
>Very nice, Craig, but now you have to deal with a (object-files-only)  
>library, that opens its own 'temporary' files on 'temporarily used unit  
>numbers' - Wherefore I say onto you, my Brethren: Pray for a  
>Standard-Conforming Way To Determine Whether A Certain Unit Number Is  
>Already In Use As A File Unit ....

AMEN!


Sat, 30 Aug 1997 13:42:31 GMT  
 bug in F77 standard?
It certainly is easy to use the INQUIRE statement to find a free logical
unit to use, and I append a subroutine which I believe is Standard
Fortran77 and which certainly works on a wide range of compilers.
I have been using it for many years, and many of my colleagues have been
using routines similar to or identical to this.  Please feel free to use
it.  It would have been nice to implement this as a function, so one
could say something like:
        OPEN(UNIT=GETLUN(), ...
but this would involve I/O recursion so would not be permitted.

I agree that it would have been nice for Fortran90 to have included an
intrinsic to do the same thing, but improvements to I/O were strangely
neglected by the various Fortran standards committees (otherwise we
wouldn't still be lumbered with the laughable "Fortran carriage-control"
convention).

*+GETLUN  Returns number of a logical unit which is free for use.
      SUBROUTINE GETLUN(LUN)
      INTEGER LUN
*LUN  Returns logical unit number to use, or -1 if none available
*-
* Allocates first available unit in range 8 to 99, since units up to 7
* are pre-connected on some systems, numbers >99 not always permitted.
      LOGICAL OPEN, EXISTS
*
      DO 100, LUN = 8, 99
          INQUIRE(UNIT=LUN, EXIST=EXISTS, OPENED=OPEN)
          IF(EXISTS .AND. .NOT. OPEN) GO TO 999
100   CONTINUE
      PRINT *, 'getlun: no more I/O units free'
      LUN = -1      
999   CONTINUE
      END

--
-------------------------------------------------------------------------

Dept of Physics & Astronomy,        
University of Leicester.        



Sat, 30 Aug 1997 22:35:18 GMT  
 
 [ 6 post ] 

 Relevant Pages 

1. f77 bug: 4.3bsd UNIX f77 improperly handles character constants

2. HELP: Is this f77/f90 standard?

3. Where can I get F77 standard?

4. Is this standard f77?

5. App F of F77 standard

6. Functions in F77 standard: Q uestion

7. syntax check to F77 ansi standard?

8. Question on F77 standards and compiler flavours

9. NOVICE-Q: f77 standards and extensions

10. F77 standard?

11. F77 Standard

12. F77 standard document

 

 
Powered by phpBB® Forum Software