2-14 FORTRAN carriage-control
******************************
(Thanks to Clive Page for a clear discussion of this topic)
Many users find FORTRAN carriage-control a confusing issue.
The origin and history of carriage-control
------------------------------------------
Files intended to be displayed on a terminal screen or printed are
composed of lines, technically, these lines are records - sub-units
of data with well-defined boundaries, separated from each other.
On byte-oriented file systems (e.g. UNIX) lines are separated by
a control character, UNIX uses the line-feed character (ASCII 10),
Macs use carriage-control (ASCII 13), PCs use a carriage-control/
line-feed combination. Technically, each line is a delimited record.
On record-oriented file systems (e.g. VMS, IBM mainframes) each line
is a variable-size or fixed-size record. See the chapter on Files
and records for more details on the subject.
When a terminal/printer receives a sequence of records, it is supposed
to start a new line after processing each record, so each of them will
be displayed/printed on a separate line.
Generally, an output device may act in different ways upon reaching
the end of a line (in formatted I/O), for example:
1) Do nothing special and continue printing (No carriage-control)
this is not very useful
2) Start a new line (Carriage-return carriage-control),
this is the usual behaviour
3) Perform a user-selected action, one of the following:
a) Start a new line
b) Skip one line and start a new line (double space printing)
c) Start a new page
d) Over-write the previous line for special effects, e.g. create
the not-equal sign by superimposing the '=' and '/' signs
Option #3 is more general, and gives more control over the output,
you may say it supplements the horizontal formatting capabilities
of formatted I/O with 'vertical formatting'.
Note that carriage-control is supposed to be implemented by means
external to Fortran, i.e. the I/O sub-system itself (see below on VMS),
as it is supposed to apply also in non-FORTRAN contexts, e.g. viewing
a file written by a FORTRAN program. The FORTRAN compiler can only
affect I/O performed by a running FORTRAN program, i.e. interactive I/O.
The problem with #3 is that it requires support from the I/O subsystem
that some operating systems (e.g. UNIX, DOS) can't provide. Typically
record-oriented filesystems can support #3, and byte-oriented ones can't.
We will call option #3 Fortran Carriage-Control (FCC), as it is now
used only in the context of Fortran, you might say that being included
into the Fortran standards artificially prolonged its life.
FORTRAN was designed on systems that implemented FCC (IBM mainframes).
As systems with byte-oriented filesystems (e.g. UNIX) became more and
more common, it was impractical to require vendors to implement FCC
for all the devices, and the FORTRAN 77 standard evaded the issue by
requiring an implementation (by the ASA method) only for "printers",
but intentionally left the device specification vague.
The ASA (American Standards Association) method
-----------------------------------------------
In this old carriage-control method (approved by ASA) the first
character in every line is not considered a part of the line,
but is used to control printing and screen display.
Using ASA you 'waste' one character (the first) in each record,
you can't use it for data, it is a "vertical formatting command".
List directed output sends an extra space character prepended
to the data to avoid truncation of the first data character.
Note that when you display a file and get to the end of
a line, two independent actions must take place:
Action Name CODE ASCII Action
--------------- ---- ----- ------------------------------------------
Carriage return CR 13 Go to the beginning of the current line
Line feed LF 10 Go down to the next line, at same column
A table of ASA codes:
Control character Effect Possible implementation
----------------- ---------------- -----------------------
Space Normal behaviour printing/CR/LF
0 Double spacing LF/printing/CR/LF
+ Overwrite mode CR/printing/CR/LF
1 Next page m*LF/CR/LF/n*LF/printing/CR/LF
Remarks:
1) m,n are integers dependant on the number of lines in the "page",
and subject to bounds that are implementation defined.
2) On program startup an extra CR is sent
3) You can check the behaviour of your system with a terminal that
have a "display controls mode" (e.g. VTs), in this mode the
control characters are displayed instead of being interpreted.
When the ASA I/O scheme is in effect, the first character in the
line will be extracted and used to control the output, and will
not be displayed. For example, if the first character happened
to be a '+' the line will be written on top of the previous line.
The classical workaround for carriage-control
---------------------------------------------
Fortran carriage-control is a "vertical extension" of the ordinary
formats, few programmers use it today, probably because UNIX systems
provide incomplete support, and the feature turned into a 'bug'.
You should begin 'output formats' that require no special processing
with a '1X', so a space character will be written at the beginning
of each line, and the 'normal' behavior will be produced.
'Input formats' reading files written with such format, should also
have an '1X', so on reading the extra space will be ignored.
By the way, list-directed I/O gives reasonable results on systems
that supports FCC by emulating Fortran carriage-control (adding an
extra blank at the beginning of each record).
Another view of carriage-control
--------------------------------
The Fortran Standards (F77 and regrettably F90) both specify that
the first character has to be chopped off for any formatted record
sent to a 'printer' but don't define what a printer is (see the
table in the chapter: 'formatted/List-directed/unformatted I/O').
Unix and DOS systems don't have the VMS luxury of defining a special
file type for Fortran output (no file type concept at all, really),
so they have problems with this. Some define the user's terminal
screen as a printer, others do not. Indeed some systems like those
made by SUN seem to define all devices as being not a printer,
and never remove the first character. But they usually provide
a utility which chops the first char off each line and converts
it to a form-feed, or whatever. This utility may be called 'asa'
(posix standard spelling) or 'fpr' on BSD flavored/influenced systems.
Operating | Interactive | Viewing | Printing | Converter |
System | session | files | files | utility |
| affected | affected | affected | |
------------|-------------|------------|------------|-------------|
VMS | Yes | Yes | Yes | Not needed |
------------|-------------|------------|------------|-------------|
SunOS | | No | No | |
------------|-------------|------------|------------|-------------|
IRIX | | | | asa |
------------|-------------|------------|------------|-------------|
------------|-------------|------------|------------|-------------|
The VMS implementation of ASA
-----------------------------
On a VMS machine, you usually meet the FORTRAN carriage-control, when
you 'type' a file written by a FORTRAN program on the screen or print
it, and in some mysterious way the first character in every line is
missing, and/or some lines are completely missing or mixed up.
The VMS operating system knows that the file was written by a FORTRAN
program, and so has to be treated in a different way, if it has the
FORTRAN CARRIAGE-CONTROL ATTRIBUTE that is kept with other information
on the file.
On VMS the default carriage-control for files written by a FORTRAN
program is FORTRAN carriage-control, you can make FORTRAN programs write
'normal' files if you OPEN them with:
CARRIAGECONTROL = 'LIST'
A small example program
-----------------------
PROGRAM CRCTRL
C ------------------------------------------------------------------
WRITE(*,*)
WRITE(*,*) ' LIST DIRECTED I/O '
WRITE(*,*) ' ================= '
C ------------------------------------------------------------------
WRITE(*,*) ' Writing line: "+abcd" (Overwrite Mode): '
WRITE(*,*) '+abcd'
WRITE(*,*)
C ------------------------------------------------------------------
WRITE(*,*) ' FORMATTED I/O '
WRITE(*,*) ' ============= '
C ------------------------------------------------------------------
WRITE(*,*) ' Writing line = "xabcd" (A non-control char): '
WRITE(*,'(A)') 'xabcd'
WRITE(*,*)
C ------------------------------------------------------------------
WRITE(*,*) ' Writing line = " abcd" (Normal Mode): '
WRITE(*,'(A)') ' abcd'
WRITE(*,*)
C ------------------------------------------------------------------
WRITE(*,*) ' Writing line = "+abcd" (Overwrite Mode): '
WRITE(*,'(A)') '+abcd'
WRITE(*,*)
C ------------------------------------------------------------------
WRITE(*,*) ' Writing line = "0abcd" (Double-spacing): '
WRITE(*,'(A)') '0abcd'
WRITE(*,*)
C ------------------------------------------------------------------
WRITE(*,*) ' Writing line = "1abcd" (New-page): '
WRITE(*,'(A)') '1abcd'
WRITE(*,*)
C ------------------------------------------------------------------
END
Return to contents page