Chapter 10
INPUT-OUTPUT

The semantics of SIMULA I/O facilities rely on the intuitive notion of "files" ("data sets"), i.e. collections of data external to the the program, organized for sequential or random access. In the language, sequential access files are called "sequential files" and random access files "direct files". When it is necessary to distinguish between the file concept of the language and the underlying files of the environment the latter are called external files.

Actually a file may in practice be any kind of external device with communication capabilities, such as a terminal, a sensory device, etc.

Examples of sequential files are:

An example of a direct file is a collection of data items on a disk, with each item identified by a unique integer.

The standard I/O facilities are contained by a class called "BASICIO". They are available to the program through block prefixing as described below.

Note: The use of upper case letters indicates that this identifier is inaccessible to the user program (cf 1.10).

The user's main program acts as if it were embedded as follows:

            BASICIO (inlength, outlength) Note  ! prefixed block;
                          inspect SYSIN do
                          inspect SYSOUT do
                             begin  <external-head> <program>   end
            end prefixed block

In any program execution the unique instance of this prefixed block constitutes the system head of the outermost quasi-parallel system (see 7.2).

The values of inlength and outlength are implementation-defined; they normally depend upon the actual device(s) associated with SYSIN and SYSOUT (the standard input and output files).

SYSIN and SYSOUT may represent the input and output features of an interactive terminal, in which case inlength and outlength are probably equal. In other cases, for example batch runs, SYSIN may represent record-oriented input and SYSOUT may represent line printer oriented output. Typical values of inlength and outlength would then be 80 and 132, resp.

A program may refer to the corresponding file objects through sysin and sysout respectively. Most attributes of these file objects are directly available as the result of the connection blocks enclosing the program.

Note: Within this chapter the term "file object" refers to an instance of one of the classes "in(byte)file", "out(byte)file" and "direct(byte)file" or of a subclass of one of these.

The overall organization of "BASICIO" is as follows:

 ENVIRONMENT class BASICIO (INPUT_LINELENGTH, OUTPUT_LINELENGTH);
                    integer INPUT_LINELENGTH, OUTPUT_LINELENGTH;
             begin ref (infile) SYSIN; ref (printfile) SYSOUT;
                ref (infile)    procedure sysin;   sysin  :- SYSIN;
                ref (printfile) procedure sysout;  sysout :- SYSOUT;

                procedure terminate_program;
                begin ... ;  goto STOP  end terminate_program;

                     class file ............................ 10.1 ;
                file class imagefile ....................... 10.3 ;
                file class bytefile ........................ 10.8 ;
           imagefile class infile .......................... 10.4 ;
           imagefile class outfile ......................... 10.5 ;
           imagefile class directfile ...................... 10.6 ;
             outfile class printfile ....................... 10.7 ;
            bytefile class inbytefile ...................... 10.9 ;
            bytefile class outbytefile ..................... 10.10 ;
            bytefile class directbytefile .................. 10.11 ;

                SYSIN  :- new infile("...");    ! Implementation-defined
                SYSOUT :- new printfile("..."); ! files names;
                SYSIN.open(blanks(INPUT_LINELENGTH));
                SYSOUT.open(blanks(OUTPUT_LINELENGTH));
                inner;
          STOP: SYSIN.close;
                SYSOUT.close
          end BASICIO;

Note: The files SYSIN and SYSOUT are opened and (if not done explicitly prior to program termination) closed within "BASICIO", i.e. outside the program itself.

The class file and its predefined subclasses are available at any block level of a program (but see (2) of 5.5.1). An implementation may restrict, in any way, the use of these classes for class or block prefixing. An implementation may provide additional subclasses of class file.

Within a program, an object of a subclass of file may represent an external file. The effect of several such file objects representing the same external file is implementation-defined.

The procedure "terminate_program" terminates program execution. It closes SYSIN and SYSOUT. It is implementation-dependent with respect to whether or not other open files are also closed.

The class file

    class file(FILENAME);  value FILENAME;  text FILENAME;
    begin Boolean OPEN;
       text procedure filename;  filename :- copy(FILENAME);
       Boolean procedure isopen; isopen := OPEN;
       Boolean procedure setaccess(mode);  text mode; ... 10.1.1;

       if FILENAME = notext then error("...");
    end file;

"File" is the common prefix class for all input/output classes.

A file is either open or inaccessible as indicated by the variable "OPEN". The procedure "isopen" returns the current value of "OPEN". A file is initially inaccessible (e.g. closed).

Each file object has a text attribute FILENAME. This text value must at "open" identify an external file which, through an implementation-defined mechanism, becomes associated with the file object. If the parameter value is notext, a run-time error occurs.

The procedure "filename" retrieves the value of FILENAME.

External file access control

Certain attributes (not specified in the file outline) control the access to the external file. The values of these attributes are set when the file object is opened or closed, from a set of default values possibly modified by successive calls to the procedure "setaccess".

The standard attribute modes are SHARED, APPEND, CREATE, READWRITE, BYTESIZE, REWIND and PURGE.

 SHARED:     If the value is "shared", the external file may be shared
             by other programs. The value "noshared" implies that the
             file must be exclusively assigned to this program.

 APPEND:     If the value is "append", output to the file is added to
             the existing contents of the file. The value "noappend" implies
             for a sequential file that, after "close", the external file will
             contain only the output produced while the file was open. The
             mode is not relevant for in(byte)files. For direct files
             "append" prohibits output before "lastloc". For out(byte)files,
             the value "append" implies that SHARED has the value
             "noshared".

 CREATE:     If the value is "create", the external file associated with
             FILENAME must not exist at "open" (if it does, "open" returns
             false); a new file is created by the environment. If the
             value is "nocreate", the associated file must exist at "open".
             The value "anycreate" implies that if the file does exist at "open"
             the file is opened, otherwise a new file is created.

 READWRITE:  If the value is "readonly", output operations cannot be
             performed. If the value is "writeonly", input operations cannot
             be performed. The value "readwrite" enables both input and
             output. This mode is relevant only for direct files.

 BYTESIZE:   The value of this mode is a positive integer specifying the
             size of bytes, measured in bits. This mode is relevant only
             for bytefiles. An implementation may restrict the possible
             values in any way. If not set explicitly the value is
             implementation-defined.

 REWIND:     The value "rewind" indicates that some resetting of the
             external file occurs at "close" (e.g. rewind of a magnetic tape).
             The value "norewind" implies no such reset.

 PURGE:      The value "purge" implies that the external file may be deleted
             by the environment when it is closed (in the sense that it
             becomes inaccessible to further program access). The value
             "nopurge" implies no such deletion.

Additional values and modes may be defined by an implementation.

The parameter "mode" to procedure "setaccess" contains one of the standard values as given above, namely "shared", "noshared", "append", "noappend", "create", "nocreate", "anycreate", "readonly", "writeonly", "readwrite", "bytesize:X" (where X is a positive integer), "rewind", "norewind", "purge" and "nopurge". It is recommended that implementation-defined parameter values have the percent character % as the first character of the text.

The parameter "bytesize:0" (zero) specifies the (implementation-defined) default byte size for bytefiles.

Only one mode may be specified in each "setaccess" call, the case of the individual letters of the parameter being insignificant. Unrecognized modes are ignored and "setaccess" then returns the value false. The value is true otherwise. A specific mode is interpreted either at next "open" or next "close". A mode which is set after "open" or "close" has no effect until the next "close" or "open" respectively.

The default values of the access modes are given in table 10.1, where "NA" means "not applicable" (i.e. ignored for this file kind) and "*" means that the value is implementation-defined.

                            Files of kind
     Mode:           In-       Out-       Direct-     Takes effect at

     SHARED          shared    noshared   noshared        open
     APPEND            NA      noappend   noappend        open
     CREATE            NA      anycreate  nocreate        open
     READWRITE         NA         NA      readwrite       open
     BYTESIZE:x        *          *          *            open
     REWIND          norewind  norewind      NA           open,close
     PURGE           nopurge   nopurge    nopurge         close

          Table 10.1. Default values of file access modes.

Open and close

Most subclasses of "file" defined in BASICIO contain these procedures.

Procedure "open" establishes the association with an external file (as identified by FILENAME), checks the access modes and causes corresponding opening actions on the external file. If the external file is closed, it is opened.

Procedure "close" causes closing actions on the external file, as specified by the access modes. In addition, the association between the file object and the external file is dissolved. If possible, the external file is closed.

The details of these procedures are subclass- and implementation-defined. All versions conform, however, to the following patterns.

 OPEN     Boolean procedure open ... ;
          if not OPEN
               and ... ! FILENAME association is established;
               and ... ! access modes compatible with external file;
               and ... ! external file is opened;
          then begin
             ... ; ! implementation-defined and access mode
                     specified actions on external file, followed by
                     subclass dependent actions;
             open := OPEN := true;
          end open;


 CLOSE    Boolean procedure close;
          if OPEN then begin
             ... ; ! implementation-defined and access
                     mode specified actions on external file;
             ... ; ! subclass dependent actions;
             OPEN  := false;
             close := true;
          end close;

These patterns will not be repeated in detail for each subclass; a short comment will serve to remind the reader of these general actions of the procedures.

Structure of file subclasses

There are two predefined subclasses of class file:

     "imagefile" - image (record) oriented files
     "bytefile"  - character (stream) oriented files

These subclasses each have three subclasses defining the direction of data transfer and the file organisation: input-oriented sequential files (i.e. in(byte)files), output-oriented sequential files (i.e. out(byte)files) and bidirectional direct files (i.e. direct(byte)files).

                            ---------------------------------------
                           |imagefile subclass | bytefile subclass |
          -----------------+-------------------+-------------------|
         |sequential input |    infile         |   inbytefile      |
         |-----------------+-------------------+-------------------|
         |sequential output|    outfile        |   outbytefile     |
         |-----------------+-------------------+-------------------|
         |direct file      |    directfile     |   directbytefile  |
          ---------------------------------------------------------

                   Table 10.2. Subclasses of class "file".

In addition, a standard subclass for line printer oriented output, outfile class printfile, is defined.

Procedure "checkpoint"

All files producing output (sequential output or direct files) contain a Boolean procedure "checkpoint". The procedure causes the environment to attempt to secure the output produced so far. Depending on the nature of the associated external device, this causes completion of output transfer (i.e. intermediate buffer contents are transferred). If this is not possible or meaningful, "checkpoint" is a dummy operation in which case the value false is returned.

Direct file locking

Direct files contain the following variable and procedures for control of simultaneous access to the external file (cf. access mode SHARED).

           Boolean LOCKED;

 LOCKED    Boolean procedure locked;  locked:= LOCKED;

 LOCK      integer procedure lock(timelimit,loc1,loc2);
                    real timelimit; integer loc1,loc2;
           begin
              lock := -1;
              if timelimit>0.0 then begin
                 if LOCKED then unlock;
                 ... ! try to lock indicated part of file, see below;
                 if !success; then begin LOCKED := true; lock := 0 end
              end
           end lock;

 UNLOCK   Boolean procedure unlock;
          begin
             unlock := checkpoint;
             if LOCKED then begin !release file; LOCKED := false end
          end unlock;

The variable "LOCKED" indicates whether the file is currently locked by the executing program. The procedure "locked" returns the current value.

Procedure "lock" enables the program to get exclusive access to all or part of the file. The effect of a "lock" call while the file is locked ("LOCKED" is true) is that the previous lock is immediately released (prior to the new locking attempt).

The parameter "timelimit" is the (clock) time in seconds that is the maximum waiting time for the resource. If "timelimit" is less than or equal to zero, the procedure returns immediately without performing any actions upon the file.

The parameters "loc1" and "loc2" identify the part of the file to be locked, by giving the ordinal numbers of two external images (bytes). The program is given exclusive access to a part of the file which includes the requested region. If the two parameters are both zero, this implies locking the whole file. Otherwise, the size of the part of the file that is actually locked, is implementation-dependent; it may even include the entire file.

A return value of zero indicates a successful "lock" operation. The value -1 indicates that "timelimit" was exceeded (or was zero or negative). A negative value less than -1 indicates "lock" failure and its interpretation is implementation-defined.

The Boolean procedure "unlock" eliminates the effect of any preceding "lock" call. The Boolean procedure "checkpoint" is called initially. The returned value is that returned by the "checkpoint" call.

Imagefiles

The (file) class "imagefile" defines the common attributes for all image- oriented files.

      file class imagefile;
           begin text image;
              procedure setpos(i);  integer i;  image.setpos(i);
              integer procedure pos;     pos    := image.pos;
              Boolean procedure more;    more   := image.more;
              integer procedure length;  length := image.length;
           end imagefile;

The individual logical unit of an external file associated with an imagefile is called an "external image". Each external image is an an ordered sequence of characters.

The variable "image" is used to reference a text frame which acts as a buffer, in the sense that it contains the external image currently being processed.

The procedures "setpos", "pos", "more" and "length" are introduced for reasons of convenience.

The three standard subclasses of imagefile are "infile" (sequential input file), "outfile" (sequential output file) and "directfile" (bidirectional direct file). In addition, "printfile", a standard subclass of class outfile, is available. It represents a line printer oriented file.

The class "infile"

 imagefile class infile;
     begin Boolean ENDFILE;
        Boolean procedure endfile;  endfile:= ENDFILE;
        Boolean procedure open(fileimage); text fileimage; ... 10.4.1;
        Boolean procedure close; ............................. 10.4.1;
        procedure inimage; ................................... 10.4.2;
        Boolean procedure inrecord; .......................... 10.4.2;
        character procedure inchar; .......................... 10.4.3;
        Boolean procedure lastitem; .......................... 10.4.4;
        text procedure intext(w); integer w; ................. 10.4.5;
        integer procedure inint; ............................. 10.4.6;
        long real procedure inreal; .......................... 10.4.6;
        integer procedure infrac; ............................ 10.4.6;

        ENDFILE:= true
        ...
     end infile;

An object of the class "infile" is used to represent an image-oriented sequential input file.

The variable ENDFILE is true whenever the file object is closed or the external file is exhausted (i.e. "end of file" has been encountered). The procedure "endfile" gives access to the value of ENDFILE.

Open and close

 OPEN      Boolean procedure open(fileimage);  text fileimage;
           if ... then begin ...  ! see 10.1.2;
              ENDFILE := false;
              image   :- fileimage;
              image   := notext;
              setpos(length+1);
              open    := OPEN := true;
           end open;

If successful, "open" returns true and sets ENDFILE false. In addition, "image" references the parameter "fileimage" which is space-filled.

 CLOSE     Boolean procedure close;
           if OPEN then
           begin ... ; ! perform closing actions, see 10.1.2;
              image :- notext;
              OPEN  := false;
              close := ENDFILE := true
           end close;

If successful, "close" returns true. In addition, OPEN is false, ENDFILE is true and "image" references notext.

Inimage and inrecord

 INIMAGE   procedure inimage;
           if not OPEN or ENDFILE then error("...")
           else begin
              ... ; ! attempt to transfer external image to "image";
              if ... ! "image" too short; then error("...")
              else if ... ! there was no more to read;
              then begin
                 ENDFILE := true;
                 image   := "!25!" end
              else  ... ; ! pad "image" with space(s);
              setpos(1)
           end inimage;

The procedure "inimage" performs the transfer of an external file image into "image". A run-time error occurs if "image" is notext or too short to contain the external image. If it is longer than the external image, the latter is left-adjusted within "image" and the remainder of the text is filled with spaces. The position indicator is set to one.

 INRECORD  Boolean procedure inrecord;
           if not OPEN or ENDFILE then error("...")
           else begin
              ... ; ! transfer external image to "image" (no space-filling);
              if ... ! no more to read;
              then begin
                 ENDFILE        := true;
                 setpos(1);
                 image.putchar('!25!') end  Note - POS = 2 now
              else begin
                 setpos(... !number of characters transferred + 1; );
                 inrecord:= not ...! whole external image received?;
              end if
           end inrecord;

The procedure "inrecord" is similar to "inimage" with the following exceptions. Whenever the number of characters accessible in the external image is less than "length", the rest of "image" is left unchanged. The part of the "image" that was changed is from pos 1 upto (but not including) the resulting value of POS. Moreover, if the external image is too long, only the "length" first characters are input. The value returned by the procedure is true and the remaining characters may be input through subsequent "inrecord" (or possibly "inimage") statements. Otherwise, if the input of the external image was completed, the value false is returned.

Note: If an "end of file" is encountered, EM ('!25!') is generated as a single character external image, and the variable ENDFILE is given the value true. A call on "inimage" or "inrecord" when ENDFILE already has the value true constitutes a run-time error.

Inchar

 INCHAR    character procedure inchar;
           begin
              if not more then inimage;
              inchar:= image.getchar
           end inchar;

The procedure "inchar" gives access to and scans past the next character. Note: The result may be the "EOF-character" EM (ISOrank 25).

Lastitem

 LASTITEM  Boolean procedure lastitem;
           begin character c;
              c := ' ';
              while not ENDFILE and then (c=' ' or else c='!9!')
              do c := inchar;
              lastitem := ENDFILE;
              if c <> ' ' then setpos(pos-1)
           end lastitem;

The purpose of the procedure "lastitem" is to skip past all SP and HT characters (ISOrank 32 and 9 respectively). The process of scanning may involve the transfer of several successive external images. If the file contains no further non-space, non-tab characters the value true is returned.

Intext

 INTEXT    text procedure intext(w); integer w;
           begin text t;
              intext :- t :- blanks(w);
              while t.more do t.putchar(inchar)
           end intext;

The expression "intext(w)" where "w" is a positive integer is a reference to a new alterable main frame of length w containing a copy of the next w characters of the file. POS is set to the following character. The expression "intext(0)" references notext. In contrast to the item-oriented procedures (see below), "intext" operates on a continuous stream of characters, reading several images if necessary.

Note: The result may be a reference to an "EOF-image" (cf. 10.4.2).

Item-oriented input

 ININT     integer procedure inint;
           if lastitem then error("..." ! Inint: End of file ;)
           else begin text t;
              t     :- image.sub(pos,length-pos+1);
              inint := t.getint;
              setpos(pos+t.pos-1)
           end inint;


 INREAL    long real procedure inreal;
           if lastitem then error("..." ! Inreal: End of file; )
           else begin text t;
              t      :- image.sub(pos,length-pos+1);
              inreal := t.getreal;
              setpos(pos+t.pos-1)
           end inreal;


 INFRAC    integer procedure infrac;
           if lastitem then error("..." ! Infrac: End of file; )
           else begin text t;
              t      :- image.sub(pos,length-pos+1);
              infrac := t.getfrac;
              setpos(pos+t.pos-1)
           end infrac;

The procedures "inint", "inreal" and "infrac" are defined in terms of the corresponding de-editing procedures of "image". These three procedures, starting at the current "pos", skip spaces and tab's, and then scan past and convert a numeric item.

The class "outfile"

 file class outfile;
      begin
         Boolean procedure open(fileimage);  text fileimage; ... 10.5.1;
         Boolean procedure close; .............................. 10.5.1;
         procedure outimage; ................................... 10.5.2;
         procedure outrecord; .................................. 10.5.3;
         procedure breakoutimage; .............................. 10.5.4;
         Boolean procedure checkpoint; ......................... 10.2.1;
         procedure outchar(c); character c; .................... 10.5.6;
         procedure outtext(t); text t; ......................... 10.5.7;
         text procedure FIELD(w); integer w; ................... 10.5.8;
         procedure outint(i,w); integer i,w; ................... 10.5.8;
         procedure outfix(r,n,w); long real r; integer n,w; .... 10.5.8;
         procedure outreal(r,n,w); long real r; integer n,w; ... 10.5.8;
         procedure outfrac(i,n,w); integer i,n,w; .............. 10.5.8;

        ... ;
     end outfile;

An object of the class "outfile" is used to represent an image-oriented sequential output file.

Note: See 10.7 for a special property of procedures "open", "close", "outimage" and "outrecord".

Open and close

 OPEN      Boolean procedure open(fileimage);  text fileimage;
           if ... then begin ...  ! see 10.1.2;
              image :- fileimage;
              setpos(1);
              open  := OPEN := true;
           end open;


 CLOSE     Boolean procedure close;
           if OPEN then begin ... ! see 10.1.2;
              if pos <> 1 then outimage;
              image :- notext;
              ... ; ! perform closing actions on external file;
              OPEN  := false;
              close := true;
           end close;

The procedure "close" calls "outimage" if the position indicator is not equal to 1.

Outimage

 OUTIMAGE  procedure outimage;
           if not OPEN then error("..." ! file closed; )
           else begin
              ... ; ! transfer "image" to external image;
              image := notext;
              setpos(1)
           end outimage;

The transfer of an image from the text "image" to the file is performed by the procedure "outimage". The procedure reacts in an implementation-defined way if the "image" length is not appropriate for the external file. (Depending on file type and host system, the external file does not necessarily record trailing blanks from the "image".) After the transfer, "image" is cleared to blanks and the position indicator is set to 1.

Outrecord

 OUTRECORD procedure outrecord;
           if not OPEN then  error("..." ! file closed; )
           else begin
              ... ; ! transfer image.sub(1,pos-1);
                    ! Note: no blanking of "image";
              setpos(1)
           end outrecord;

The procedure "outrecord" transfers to the file only that part of "image" which precedes POS. The contents are not blanked after the transfer, although POS is set to one.

Breakoutimage

 BREAKOUTIMAGE
           procedure breakoutimage;
           if not OPEN then error("..." ! file closed; )
           else begin
              ... ; ! output image.sub(1,pos-1);
              image := notext;
              setpos(1)
           end breakoutimage;

The procedure "breakoutimage" outputs the part of "image" that precedes POS. The output is performed as a partial output of an external image, in the sense that implicit line terminators are suppressed. On some external files this operation is not possible. It then has an effect identical to "outrecord".

After transfer the "image" is blanked and POS is set to one.

One use of "breakoutimage" is to allow input from a terminal display on the same line as one on which output (e.g. a prompt) has already been written.

Checkpoint

The procedure "checkpoint" is described in 10.2.1.

Outchar

 OUTCHAR   procedure outchar(c); character c;
           begin
              if not more then outimage;
              image.putchar(c)
           end outchar;

The procedure "outchar" stores a character in the POS position of "image". If "more" is false, "outimage" is called first.

Outtext

 OUTTEXT   procedure outtext(t); text t;
           begin
              if pos>1 and then t.length>length-pos+1 then outimage;
              t.setpos(1);
              while t.more do outchar(t.getchar);
           end outtext;

Procedure "outtext" always transfers the complete contents of the text parameter to the file.

Item-oriented output

     text procedure FIELD(w); integer w;
     if w>length then error("..." ! Item too long; )
     else begin
        if pos+w-1 > length then outimage;
        FIELD :- image.sub(pos,w);
        setpos(pos+w)
     end FIELD;


 OUTINT    procedure outint(i,w); integer i,w;
           if      w = 0 then FIELD(...).putint(i)   ! see below;
           else if w < 0
           then begin text f;
              f :- FIELD(-w);
              f := notext;
              f.sub(1,...).putint(i) end
           else FIELD(w).putint(i);


 OUTFIX    procedure outfix(r,n,w); long real r; integer n,w;
           ... ; ! as body of outint, with "putfix" substituted for "putint";

 OUTREAL   procedure outreal(r,n,w); long real r; integer n,w;
           ... ; ! as body of outint, with "putreal" substituted for "putint";

 OUTFRAC   procedure outfrac(i,n,w); integer i,n,w;
           ... ; ! as body of outint, with "putfrac" substituted for "putint";

The procedures "outint", "outfix", "outreal" and "outfrac" are defined in terms of the corresponding editing procedures of "image". They provide facilities for "item-oriented" output. Each item is edited into a "field" (subtext of "image") normally starting at the current accessible character. POS is advanced correspondingly. If the remainder of "image" is too short to contain the item, "outimage" is called implicitly prior to the editing operation. The field is space-filled before the editing operation.

A run-time error occurs if a field cannot be contained within the full length of "image".

Parameter "w" determines both the length of this field and the adjustment of the item within it, as follows.

     w > 0    The field length is w, the item is right-adjusted.

     w < 0    The field length is abs(w), the item is left-adjusted.

     w = 0    The field length is the exact number of characters needed
              to contain the item (i.e. no leading or trailing spaces).

The class "directfile"

 imagefile class directfile;
    begin   integer LOC, MAXLOC;  Boolean ENDFILE, LOCKED;
       integer procedure location;  location:= LOC;
       Boolean procedure endfile;   endfile := ENDFILE;
       Boolean procedure locked;    locked  := LOCKED;
       Boolean procedure open(fileimage); text fileimage; ...... 10.6.1;
       Boolean procedure close; ................................ 10.6.1;
       integer procedure lastloc; .............................. 10.6.2;
       integer procedure maxloc; ............................... 10.6.2;
       procedure locate(i); integer i; ......................... 10.6.2;
       procedure inimage; ...................................... 10.6.3;
       procedure outimage; ..................................... 10.6.4;
       Boolean procedure deleteimage; .......................... 10.6.5;
       character procedure inchar; ............................. 10.6.6;
       integer procedure lock(t,i,j); real t; integer i,j; ..... 10.6.7;
       Boolean procedure unlock; ............................... 10.6.7;
       Boolean procedure checkpoint; ........................... 10.2.1;
       Boolean procedure lastitem; ............................. 10.4.4;
       text procedure intext; .................................. 10.4.5;
       integer procedure inint; ................................ 10.4.6;
       long real procedure inreal; ............................. 10.4.6;
       integer procedure infrac; ............................... 10.4.6;
       procedure outchar(c); character c; ...................... 10.5.6;
       procedure outtext(t); text t; ........................... 10.5.7;
       text procedure FIELD(w); integer w; ..................... 10.5.8;
       procedure outint(i,w); integer i,w; ..................... 10.5.8;
       procedure outfix(r,n,w);  long real r; integer n,w; ..... 10.5.8;
       procedure outreal(r,n,w); long real r; integer n,w; ..... 10.5.8;
       procedure outfrac(i,n,w); integer i,n,w; ................ 10.5.8;

       ENDFILE:= true
       ...
    end directfile;

An object of the class "directfile" is used to represent an image-oriented direct file in which the individual images are addressable by ordinal numbers.

The variable LOC contains the current ordinal number. When the file is closed, the value of LOC is set to zero. The procedure "location" gives access to the current value of LOC.

The variable ENDFILE is true when the file is closed or when an image with location greater than "lastloc" has been input (through "inimage"). It is set after each "inimage" statement. The procedure "endfile" returns the current value.

The variable MAXLOC indicates the highest permitted value of LOC. On some systems this value corresponds to the size of a preallocated file while, on other systems which allow the file to be dynamically extended, this variable is assigned the value "maxint"-1.

Open and close

 OPEN      Boolean procedure open(fileimage);  text fileimage;
           if ... then begin ...  ! see 10.1.2;
              MAXLOC := ... ; ! See below;
              image  :- fileimage;
              setpos(1);
              locate(1);
              open   := OPEN := true;
           end open;

 CLOSE     Boolean procedure close;
           if OPEN then begin ... ! see 10.1.2;
              image :- notext;
              if LOCKED then unlock;
              LOC   := MAXLOC := 0;
              ... ;
              OPEN  := false;
              close := ENDFILE := true;
           end close;

The procedure "open" locates the first image of the file. The length of "image" must, at all "inimage" and "outimage" statements, be identical to the length of "image" at the "open" call. The value assigned to MAXLOC at "open" is either a maximum length determined from the external file, or it is "maxint"-1 if no such length exists.

Locate, lastloc, and maxloc

 LOCATE    procedure locate(i); integer i;
           if i<1 or i>MAXLOC then error("..." ! Parameter out of range; )
           else begin
              LOC:= i;
              ... ;
           end locate;

 LASTLOC   integer procedure lastloc;
           if not OPEN then error("..." ! file closed; )
           else  lastloc := ... ;

 MAXLOC    integer procedure maxloc;
           if not OPEN then error("..." ! file closed; )
           else  maxloc := MAXLOC;

Procedure "locate" may be used to assign a given value to the variable LOC. This assignment may be accompanied by implementation-defined checks and (possibly asynchronous) instructions to an external memory device associated with the file; no transfer to/from "image" is, however, performed. A parameter to "locate" less than one or greater than MAXLOC constitutes a run-time error.

The procedure "lastloc" indicates the largest location of any written image. For a new file the value returned is zero.

Inimage

 INIMAGE   procedure inimage;
           if not OPEN then error("..." !file closed; )
           else begin
              setpos(1);
              ENDFILE:= LOC > lastloc;
              if ENDFILE then image:= "!25!" else
              if ... ! external written image at LOC exists ; then
                ... ! transfer to "image";...
              else begin
                while more do image.putchar('!0!')
                   ! Note: now pos = length+1;
             end not written;
             locate(LOC+1)   ! Location for *next* image;
           end inimage;

The procedure "inimage" transfers into the text "image" a copy of the external image as currently identified by the variable LOC. If the file does not contain an image with an ordinal number equal to the value of LOC, the effect of the procedure "inimage" is as follows. If the location indicated is greater than "lastloc", then ENDFILE is set to true and the end of file text ("!25!") is assigned to "image". Otherwise, if the image is a non-written image but there exists at least one written image whose LOC is greater than current LOC, then the "image" is filled with NUL ('!0!') characters and the position indicator is set to "length"+1 (i.e. "more" becomes false). Finally the value of LOC is incremented by one through a "locate" call.

Outimage

 OUTIMAGE  procedure outimage;
           if      not OPEN     then error("..." !file closed; )
           else if LOC > MAXLOC then error("..." ! file overflow; );
           else begin
              ... ; ! output "image" to external image at LOC;
              locate(LOC+1);
              image := notext;
              setpos(1)
           end outimage;

The procedure "outimage" transfers a copy of the text value "image" to the external image, thereby storing in the file an external image whose ordinal number is equal to the current value of LOC. If the file contains another image with the same ordinal number, that image is overwritten. The value of LOC is then incremented by one through a "locate" call.

Deleteimage

 DELETEIMAGE
           Boolean procedure deleteimage;
           if OPEN and then ... ! image LOC was written;
           then begin
              ... ; ! attempt to delete image;
              if ... ! delete operation successful;
              then begin
                 deleteimage := true;
                 locate(LOC+1);
              end successful
           end deleteimage;

The Boolean procedure "deleteimage" makes the image identified by the current value of LOC effectively un-written. Irrespective of any physical differences on the external medium between never-written images and deleted ones, there is no difference from the program's point of view. Note that this means that "deleteimage" may decrement the value returned by "lastloc" (in case LOC was equal to "lastloc").

Note: Outputting a NUL-filled image at location "lastloc" in the file does not necessarily decrement the "lastloc" value; explicit writing (outimage) of such images should be avoided.

Inchar

 INCHAR    character procedure inchar;
           begin
              while not more do inimage;
              inchar:= image.getchar
           end inchar;

Note: Inchar skips all unwritten images.

Lock and Unlock

The procedures "lock" and "unlock" (see 10.2.2) provide locking mechanisms. The last two parameters of "lock" indicate the minimum range of locations to be locked (inclusive).

Item-oriented input/output

The remaining procedures ("lastitem" to "intext" and "outchar" to "outtext") are defined in accordance with the corresponding procedures of "infile" and "outfile" respectively, i.e. their definitional algorithms are exact copies of those given in these two classes.

The class "printfile"

The class "printfile" defines a class for line printer oriented output.

 outfile class printfile;
         begin   integer   LINE, LINES_PER_PAGE, SPACING, PAGE;
         integer procedure line;  line := LINE;
         integer procedure page;  page := PAGE;
         Boolean procedure open(fileimage);  text fileimage; ..... 10.7.1;
         Boolean procedure close; ................................ 10.7.1;
         procedure linesperpage(n); integer n; ................... 10.7.2;
         procedure spacing(n); integer n; ........................ 10.7.3;
         procedure eject(n);  integer n; ......................... 10.7.4;
         procedure outimage; ..................................... 10.7.5;
         procedure outrecord; .................................... 10.7.5;

         SPACING        := 1;
         LINES_PER_PAGE := ... ;
         ...
      end printfile;

An object of the class "printfile" is used to represent a line printer oriented output file. The class is a subclass of "outfile". A file image normally represents a line on a printed page.

It is a property of this class that "outfile" attributes, which are redeclared at "printfile" level, are not accessible to the user's program through explicit qualification (qua). Thus these "outfile" procedures ("open", "close", "outimage", "outrecord") may be envisaged as including the following initial code:

              procedure X...;
              inspect this outfile
                 when printfile do X...
                 otherwise ...;

Note: Consequently, possible implicit calls of outimage from outchar, close and the item-oriented output procedures are understood to invoke "printfile.outimage".

The variable LINE indicates the ordinal number of the next line to be printed (on the current page), provided that no implicit or explicit "eject" statement occurs. Its value is accessible through the procedure "line". Note that the value of LINE may be greater than LINES_PER_PAGE (see 10.7.5).

The variable PAGE indicates the ordinal number of the current page. Its value may be retrieved by means of procedure "page".

Open and close

 OPEN      Boolean procedure open(fileimage);  text fileimage;
           if ... then begin ...  ! see 10.1.2;
              image :- fileimage;
              PAGE  := 0;
              LINE  := 1;
              setpos(1);
              eject(1);
              open  := OPEN := true;
           end open;


 CLOSE     Boolean procedure close;
           if OPEN then begin ... ! see 10.1.2;
              if pos <> 1 then outimage;
              eject(LINES_PER_PAGE);
              LINE    := 0;
              SPACING := 1;
              LINES_PER_PAGE:= ... ;
              image   :- notext;
              ... ;
              OPEN    := false;
              close   := true;
           end close;

The procedures "open" and "close" conform to the rules of 10.2. In addition, "close" outputs the current value of "image" if POS is not equal to 1 and set LINE to zero.

Lines per page

 LINESPERPAGE
           integer procedure linesperpage(n); integer n;
           begin
              linesperpage := LINES_PER_PAGE;
              LINES_PER_PAGE:= if n > 0 then n
                              else if n < 0 then maxint
                                   else  ... ; ! default value;

The variable LINES_PER_PAGE indicates the maximum number of physical lines that may be printed on each page, including intervening blank lines. An implementation-defined value is assigned to the variable at the time of object generation, and when the printfile is closed. The value of the variable may be retreived by a call on "linesperpage"; in addition the variable is givan a new value as follows.

If the parameter to "linesperpage" is zero, LINES_PER_PAGE is reset to the original value (assigned at object generation). A parameter value less than zero may be used to indicate an "infinite" value of LINES_PER_PAGE, thus avoiding any automatic calls on "eject".

Spacing

 SPACING   procedure spacing(n); integer n;
           if  0<=n and n<=LINES_PER_PAGE  then SPACING := n
           else  error("..." ! Parameter out of range; );

The variable SPACING represents the value by which the variable LINE is incremented after the next printing operation. Its value may be changed by the procedure "spacing". A call on the procedure "spacing" with a parameter less than zero or greater than LINES_PER_PAGE constitutes an error. The effect of a a parameter to "spacing" which is equal to zero may be defined as forcing successive printing operations on the same physical line. Note, however, that on some physical media this may not be possible, in which case spacing(0) has the same effect as spacing(1) (i.e. no overprinting).

Eject

 EJECT     procedure eject(n); integer n;
           if        not OPEN then  error("..." ! file closed;)
           else if   n <= 0   then  error("..." ! Parameter out of range;)
           else begin
              if n > LINES_PER_PAGE then n := 1;
              if n <= LINE then
              begin
                 ... ; ! change to new page on external file;
                 PAGE := PAGE + 1
              end;
              ... ; ! move to line "n" on current (external) page;
              LINE := n
           end eject;

The procedure "eject" is used to position to a certain line identified by the parameter, n. The variable "PAGE" is incremented by one each time an explicit or implicit "eject" implies a new page.

The following cases can be distinguished:

     n <= 0                 : ERROR
     n >  LINES_PER_PAGE    : Equivalent to eject (1)
     n <= LINE              : Position to line number n on the next page
     n >  LINE              : Position to line number n on the current page

The tests above are performed in the given sequence.

Outimage and outrecord

 OUTIMAGE  procedure outimage;
           if not OPEN then  error("..." ! file closed; )
           else begin
              if LINE > LINES_PER_PAGE then eject(1);
              ... ; ! output the image on the line indicated by LINE;
              LINE  := LINE + SPACING;
              image := notext;
              setpos(1)
           end outimage;


 OUTRECORD procedure outrecord;
           if not OPEN then  error("..." ! file closed; )
           else begin
              if LINE > LINES_PER_PAGE then eject(1);
              ... ; ! output image.sub(1,pos-1) on the line indicated by LINE;
              LINE := LINE + SPACING;
              setpos(1)
           end outrecord;

The procedures "outimage" and "outrecord" operate according to the rules of 10.2.3. In addition, they update the variable LINE (and possibly PAGE).

Note: In addition, the procedure "breakoutimage" is inherited from the class prefix "outfile". This procedure does not update LINE or PAGE.

Bytefiles

The class bytefile is the common prefix class for all byte-oriented files.

    file class bytefile;
         begin short integer BYTESIZE;
            short integer procedure bytesize; bytesize := BYTESIZE;

         end bytefile;

Bytefiles read and write files as continuous streams of bytes. The variable BYTESIZE defines the range of the byte values transferred. Byte values are integers in the range (0:2**BYTESIZE-1). The BYTESIZE value of the file object is accessible through procedure "bytesize".

Note: "Bytesize" returns zero before first "open" of the bytefile.

There are three standard subclasses of "bytefile":

     "inbytefile"      representing a sequential file for which input
                       operations are available.

     "outbytefile"     representing a sequential file for which output
                       operations are available.

     "directbytefile"  representing a direct file with facilities for
                       both input and output.

The class "inbytefile"

 bytefile class inbytefile;
          begin Boolean ENDFILE;
          Boolean procedure endfile;  endfile:= ENDFILE;
          Boolean procedure open; ......................... 10.9.1;
          Boolean procedure close; ........................ 10.9.1;
          short integer procedure inbyte; ................. 10.9.2;
          text procedure intext(t);   text t; ............. 10.9.3;

          ENDFILE:= true;
          ...
       end inbytefile;

An object of the class "inbytefile" is used to represent a byte-oriented sequential input file.

Variable "ENDFILE" is true if there are no more bytes to read. The procedure "endfile" returns the value of ENDFILE.

Open and close

 OPEN      Boolean procedure open;
           if ... then begin ...  ! see 10.1.2;
              ENDFILE  := false;
              BYTESIZE := ... ! value of access mode BYTESIZE;
              open     := OPEN := true;
           end open;


 CLOSE     Boolean procedure close;
           if OPEN then begin ... ! see 10.1.2;
              ... ;
              OPEN  := false;
              close := ENDFILE := true;
           end close;

Inbyte

 INBYTE    short integer procedure inbyte;
              if ENDFILE then error("..." ! End of file ;)
              else if ... ! no more bytes to read;
              then ENDFILE := true  ! inbyte returns zero;
              else inbyte  := ...! next byte of size BYTESIZE;

The procedure "inbyte" returns the short integer value corresponding to the input byte. If there are no more bytes to read, a zero result is returned. If prior to an "inbyte" call ENDFILE is true, a run-time error occurs.

Intext

 INTEXT    text procedure intext(t);   text t;
           begin
              t.setpos(1);
              while t.more and not ENDFILE do t.putchar(char(inbyte));
              if ENDFILE then t.setpos(t.pos-1);
              intext:- t.sub(1,t.pos-1)
           end intext;

The procedure "intext" fills the frame of the parameter "t" with successive input bytes.

The class "outbytefile"

 bytefile class outbytefile;
          begin
          Boolean procedure open; ....................... 10.10.1;
          Boolean procedure close; ...................... 10.10.1;
          procedure outbyte(x); short integer x; ........ 10.10.2;
          procedure outtext(t); text t; ................. 10.10.3;
          Boolean procedure checkpoint; ................. 10.2.1;

 end outbytefile;

An object of the class "outbytefile" is used to represent a sequential output file of bytes.

Open and close

 OPEN      Boolean procedure open;
           if ... then begin ...  ! see 10.1.2;
              BYTESIZE := ... ! value of access mode BYTESIZE;
              open     := OPEN:= true;
           end open;

 CLOSE     Boolean procedure close;
           if OPEN then begin ... ! see 10.1.2;
              OPEN  := false;
              close := true;
           end close;

Outbyte

 OUTBYTE   procedure outbyte(x);    short integer x;
              if not OPEN then error("..." ! file closed; )
              else if x < 0 or else x >= 2**BYTESIZE
              then error("..." ! Outbyte, illegal byte value ;)
              else ... ; ! output of x;

The procedure "outbyte" outputs a byte corresponding to the parameter value. If the parameter value is less than zero or exceeds the maximum permitted value, as defined by BYTESIZE, a run-time error occurs. If the file is not open, a run-time error occurs.

Outtext

 OUTTEXT  procedure outtext(t);   text t;
          begin
             t.setpos(1);
             while t.more do  outbyte(rank(t.getchar))
          end outtext;

The procedure "outtext" outputs all characters in the parameter "t" as bytes.

The class "directbytefile"

The class "directbytefile" defines a byte-oriented direct file.

 bytefile class directbytefile;
       begin integer LOC, MAXLOC;  Boolean LOCKED;
       Boolean procedure endfile; endfile:=OPEN and then LOC>lastloc;
       integer procedure location; location := LOC;
       integer procedure maxloc; maxloc := MAXLOC;
       Boolean procedure locked; locked := LOCKED;
       Boolean procedure open; ............................... 10.11.1;
       Boolean procedure close; .............................. 10.11.1;
       integer procedure lastloc; ............................ 10.11.2;
       procedure locate(i);   integer i; ..................... 10.11.2;
       short integer procedure inbyte; ....................... 10.11.3;
       procedure outbyte(x);  short integer x; ............... 10.11.3;
       Boolean procedure checkpoint; ......................... 10.2.1;
       integer procedure lock(t,i,j); real t; integer i,j; ... 10.11.4;
       Boolean procedure unlock; ............................. 10.11.4;
       procedure intext(t);   text t; ........................ 10.9.3;
       procedure outtext(t);  text t; ........................ 10.10.3;
          ...
       end directbytefile;

An object of the class "directbytefile" is used to represent an external file in which the individual bytes are addressable by ordinal numbers. The variable LOC is defined to represent such ordinal numbers. When the file is closed, the value of LOC is zero.

The variable MAXLOC indicates the maximum possible location on the external file. If this is not meaningful MAXLOC has the value of "maxint"-1. The procedure "maxloc" gives access to the current MAXLOC value.

The procedure "endfile" returns true whenever LOC indicates an address greater than "lastloc".

The procedures "intext" and "outtext" conform to the pattern for "inbytefile" and "outbytefile", respectively.

Open and close

 OPEN      Boolean procedure open;
           if ... then begin ...  ! see 10.1.2;
              LOC      := 1;
              MAXLOC   := ...; ! fixed size, or maxint-1;
              BYTESIZE := ... ! value of access mode BYTESIZE;
              open     := OPEN := true;
           end open;


 CLOSE     Boolean procedure close;
           if OPEN then begin ... ! see 10.1.2;
              MAXLOC := 0;
              OPEN   := false;
              close  := true;
           end close;

Locate and lastloc

 LOCATE    procedure locate(p);   integer p;
              if p < 1 or p > MAXLOC
              then error("..." ! Parameter out of range; )
              else LOC := p;

 LASTLOC   integer procedure lastloc;
              if not OPEN then error("..." ! file closed; )
              else lastloc := ...;

The current last written location is returned by the procedure "lastloc". The procedure "location" returns the current value of LOC. The procedure "locate" may be used to assign a given value to the variable. A parameter value to "locate" which is less than one or greater than MAXLOC constitutes a run-time error.

Inbyte and outbyte

 INBYTE    short integer procedure inbyte;
           if not OPEN then error("..." !file closed; )
           else if LOC <= lastloc
           then begin
              inbyte := ... ! next byte of size BYTESIZE;...;
              LOC    := LOC+1
           end inbyte;


 OUTBYTE   procedure outbyte(x);  short integer x;
           if not OPEN then error("..." !file closed; )
           else if x < 0 or else x >= 2**BYTESIZE
           then error("..." ! Outbyte, illegal byte value ;);
           else if LOC > MAXLOC then error("..." !file overflow; )
           else begin
              ... ! output of x;
              LOC := LOC + 1
           end outbyte;

The procedure "inbyte" reads one byte, returning its integer value. The result of "inbyte" from an unwritten LOC is zero (cf. 10.3.2).

The procedure "outbyte" outputs a byte according to the given parameter value (cf. 10.3.3).

Lock and Unlock

The procedures "lock" and "unlock" (see 10.2.2) provide locking mechanisms. The last two parameters of "lock" indicate the minimum range of (byte) locations to be locked (inclusive).