2-8  LOGICAL UNITS AND FILES
 ****************************
 (thanks to Timothy Prince for the important comment)

 Note that since operating systems treat peripheral devices as
 files (see below), this discussion applies not just to files on
 disks and tapes, but also to non-file oriented devices.


 Logical Unit Numbers
 --------------------
 A FORTRAN program may read and write several files at the same time 
 (including the standard input and output), a convenient method to 
 'label' the files used is to assign small integers to them. 

 Similar methods are used in other languages, and the labeling 
 integers are called: LOGICAL UNIT NUMBERS (LUN) or file handles. 

 The separation of the file interface into two distinct logical 
 layers (LUN/file-name) makes it possible to perform the association
 between the two at run-time, giving an extra flexibility (see below).

 FORTRAN I/O is performed to or from a LOGICAL UNIT identified by the
 logical unit number (LUN), the LUN is CONNECTED to a file/device 
 either explicitly with an OPEN statement or implicitly.

 LUNs are global entities in a program, a LUN used in one procedure
 to open a file, will refer to the same file in other procedures.


 Explicit and Implicit OPEN
 --------------------------
 Using an 'OPEN' statement is not mandatory but is recommended, 
 otherwise you may work with system defaults that may be non-portable, 
 or just strange. 

 Using an OPEN statement is a good programming practice and 
 makes it possible to create files with optimal characteristics,
 and read existing files in the optimal way.

 The following standard OPEN keywords are useful:

    Keyword        Value           Comments
    -------      -------------    ---------------------------------
     UNIT         A LUN number    In the allowed range (see below)

     FILE         File name       May be a constant/variable

     STATUS       'OLD'           To use an existing file, 
                  'NEW'           To create a new file

     ACCESS       'SEQUENTIAL'    
                  'DIRECT'        Open for direct (random) access

     FORM         'FORMATTED'     For an ASCII file
                  'UNFORMATTED'   For a binary file

     BLANK        'NULL'          Ignore blanks

     ERR          Statement label to jump to if 'open' fails

 On an advantage of using the IOSTAT specifier over the ERR specifier
 see the chapter on the three I/O methods.

 Non-standard keywords can optimize I/O performance, or enable you 
 to use INDEXED (non-standard!) files.


 Redirecting implicitly opened files
 -----------------------------------
 If you use the 'FILE' keyword in the 'open' statement, you create
 a 'connection' between the LUN and the file name. If you don't use
 this keyword a default file name is assumed:

    System       Default file name
    ------       -----------------
     VMS         FORTnnn.DAT 
     UNIX        fort.n


 These default file names are used to create one more "naming level".
 Using an operating system command it is possible to make the program 
 process another file without having to re-compile it:

    System    Command syntax            Shell
    ------    ----------------------    -----
     VMS      define FOR010 new.dat     DCL

     IRIX     set FOR010 = new.dat      ???? 
              setenv FOR010 new.dat     ???? 

     AIX      ln -s new.dat fort.10     ???? 

 This is a common technique, it gives the programmer more flexibility 
 managing file I/O. 

 By the way, a more informative term for 'shell' is 'command language 
 interpreter'.



 Preassigned LUNs
 ----------------
 Some LUNs are permanently assigned (PRECONNECTED) to the standard 
 input and output devices (the keyboard and screen respectively in 
 an interactive session). 

 There is a popular (non-standard!) convention for preassigned LUNs 
 whose origin is not clear, it is probably derived from IBM practice, 
 not from the FORTRAN 66 standard:


    Unit   VMS logical  C stream     Old I/O     Interactive   Batch mode
    no.    device name   name         usage       mode usage    usage
    ----   ----------   --------   -----------   -----------   ----------
     0                   stderr                   screen        log file
     5     SYS$INPUT     stdin     card reader    keyboard      
     6     SYS$OUTPUT    stdout    line printer   screen        log file


 Using these LUNs explicitly is bad programming. A better way is:


   I/O Statement   VMS device     UNIX dev    Interactive       VMS Batch 
     example                                    session            job
   -------------   ----------    ---------    -----------     -------------
    read(*,...)    SYS$INPUT      stdin        keyboard        batch file
    write(*,...)   SYS$OUTPUT     stdout       screen          log file


 Unix-like redirection makes the use of the * specifiers convenient; 
 failing that, it's hard to get flexibility without relying on the 
 non-standard numeric values. 


 Output redirection
 ------------------
 There is no difference between WRITE(6,*) and WRITE(*,*) when you
 redirect program output, except on VMS.

 VMS redirects output by redefining the logical name SYS$OUTPUT,
 there are two ways an ordinary user can do that:

    DEFINE/USER_MODE SYS$OUTPUT FILE.OUT         (User-mode)
    DEFINE SYS$OUTPUT FILE.OUT                   (Supervisor-mode)

 In supervisor mode you will get one file called FILE.OUT containing
 the output of both  WRITE(6,*) and WRITE(*,*) statements.

 In user mode you will get two versions of the file FILE.OUT, the
 first version contains the WRITE(*,*) output and the second the 
 WRITE(6,*) output.


 Range of LUNs 
 -------------
 The range of LUNs is limited in FORTRAN to a subset of the positive
 integers:

    Operating system   Minimal LUN  Maximal Lun  Open by default
    ----------------   -----------  -----------  ---------------
     VMS                   0           119            none
     Typical UNIX          0         2**31 - 1       0, 5, 6


 DEC (and maybe IRIX) compilers use negative LUNs when you don't 
 explicitly specify a LUN in an I/O statement. 

 The default DEC unit numbers are:

    I/O STATEMENT   UNIT
    -------------   ----
     PRINT           -1
     TYPE            -2
     ACCEPT          -3
     READ            -4

 Negative unit numbers are unavailable to the programmer, so this 
 "trick" prevents conflicts between I/O statements that use the 
 default logical unit numbers and those that use explicit logical 
 unit numbers.

 You usually see these negative logical unit numbers only in error 
 messages, e.g. run-time error messages produced by the Fortran 
 run-time library for your compiler.


 LUN allocation
 --------------
 Once a LUN was connected to a file, the connection remains in 
 effect until an explicit CLOSE statement is executed, then the 
 LUN is 'released' and you can use it again.

 That means that you have to keep track of the LUNs you use in 
 your program, or have some way to ask the system about them.

 You can find if you have already used a certain LUN with the 
 INQUIRE statement: 


      INTEGER       u
      LOGICAL       log
      ............................
      u = 10
      INQUIRE (UNIT=u, OPENED=log)
C     ------------------------------------------------------------------
      IF (log) THEN
        WRITE (*,*) ' Unit ', u, ' is not free '
      ELSE
        WRITE (*,*) ' Unit ', u, ' is free '
      ENDIF
C     ------------------------------------------------------------------

 Other INQUIRE keywords check if the unit number is valid ('EXIST'),
 and supply information on the connected file.


 You may call a system routine (non-standard!) to find a 'free' 
 LUN and allocate it, afterwards you can deallocate the LUN.

      LIB$GET_LUN(u)           (VMS)
      LIB$FREE_LUN(u)


 However, you can easily write a PORTABLE such routine in FORTRAN 
 using the INQUIRE statement.


 Reading/Writing from/to peripheral devices
 ------------------------------------------
 Almost, if not all operating-system unified the I/O operations 
 performed on peripheral devices, so that devices like printers 
 and serial ports can be used as if they are files.

 Some DOS examples (Maybe you'll need sometimes to add a colon 
 ':' to the device name): 

    copy CON tmp.tmp      (copies anything you type to the file tmp.tmp
                           CON  is the name of the "console" device in 
                           this case it's the keyboard. Exit with CTRL/Z,
                           then a RETURN)
 
    copy tmp.tmp PRN      (prints the file tmp.tmp)
 
    copy tmp.tmp COM1     (sends the file tmp.tmp through the COM1 
                           serial port)

    type CON              (displays on the screen whatever you type, 
                           after you press RETURN. Exit with CTRL/Z 
                           then a RETURN) 


 Using the peripheral devices from a program is easy, use the 
 appropriate device as if it was a file, and do an OPEN:

      OPEN(UNIT=unitnum, FILE='devname', STATUS='OLD',...)

 than just read/write from/to the opened unit. 

 The examples here used DOS, but PC operating systems made by
 a certain company are rather bad, and you may have to use a
 routine library supplied with the compiler.



Return to contents page