10.3. Transput declarations

{``So it does!'' said Pooh, ``It goes in!'' ``So it does!'' said Piglet, ``And it comes out!'' ``Doesn't it?'' said Eeyore, ``It goes in and out like anything,'' Winnie-the-Pooh, A.A. Milne.}
{Three ways of "transput" (i.e., input and output) are provided by the standard-prelude, viz., formatless transput {10.3.3}, formatted transput {10.3.5}and binary transput {10.3.6}.}
 
 
 

10.3.1. Books, channels and files

{"Books", "channels" and "files" model the transput devices of the physical machine used in the implementation.}
 
 
 

10.3.1.1. Books and backfiles

{

 aa) All information within the system is to be found in a number of "books". A book {a}is a structured value including a field text of the mode specified by FLEXTEXT {b}which refers to information in the form of characters. The text has a variable number of pages, each of which may have a variable number of lines, each of which may have a variable number of characters. Positions within the text are indicated by a page number, a line number and a character number. The book includes a field lpos which indicates the "logical end" of the book, i.e., the position up to which it has been filled with information, a string idf, which identifies the book and which may possibly include other information, e.g., ownership, and fields putting and users which permit the book to be opened {10.3.1.4.d}on more than one file simultaneously only if putting is not possible on any of them.

bb) The books in the system are accessed via a chain of backfiles. The chain of books available for opening {10.3.1.4.dd}is referenced by chainbfile. A given book may be referenced by more than one backfile on this chain, thus allowing simultaneous access to a single book by more than one process {10.2.4}. However such access can only be for reading a book, since only one process may access a book such that it may be written to {aa}. The chain of books which have been locked {10.3.1.4.o}is referenced by lockedbfile.

cc) Simultaneous access by more than one process to the chain of backfiles is prevented by use of the semaphore bfileprotect, which provides mutual exclusion between such processes.

dd) Books may be created (e.g., by input) or destroyed (e.g., after output) by tasks (e.g., the operating system) in the system-task-list {10.4.2}, such books being then added to or removed from the chain of backfiles.}

a) MODE #a#BOOK= STRUCT(FLEXTEXT text, POS lpos # logical end of book #, STRING idf # identification #, BOOL putting # TRUE if the book may be written to #, INT users # the number of times the book is opened #);

b) MODE #a#TEXT = REF [ ] [ ] [ ] CHAR, MODE #a#FLEXTEXT = REF FLEX [ ] FLEX [ ] FLEX [ ] CHAR; 

c) MODE #a#POS = STRUCT(INT p, l, c);

d) PRIO #a#BEYOND=5, OP BEYOND = (POS a, b)BOOL: IF p OF a < p OF b THEN FALSE ELIF p OF a > p OF b THEN TRUE ELIF l OF a < l OF b THEN FALSE ELIF l OF a > l OF b THEN TRUE ELSE c OF a > c OF b FI;

e) MODE #a#BFILE = STRUCT(REF BOOK book, REF BFILE next);

f) REF BFILE #a#chainbfile := NIL;

g) REF BFILE #a#lockedbfile := NIL;

h) SEMA #a#bfileprotect = (SEMA s; #F#fff OF s := #!PRIM#HEAP INT := 1; s);
 
 
 

10.3.1.2. Channnels

{

 aa) A "channel" corresponds to one or more physical devices (e.g., a card reader, a card punch or a line printer, or even to a set up in nuclear physics the resuls of which are collected by the computer), or to a filestore maintained by the operating system. A channel is a structured value whose fields are routines returning truth values which determine the available methods of access to a book linked via that channel, Since the methods of access to a book may well depend on the book as well as on the channel (e.g., a certain book may have been trapped so that it may be read, but not written to), most of these properties depend on both the channel and the book. These properties may be examined by use of the environment enquiries provided for files {10.3.1.3.ff}. Two environment enquiries are provided for channels. These are:

· estab possible, which returns true if another file may be "established" {10.3.1.4.cc}on the channel;

· standconv, which may be used to obtain the default "conversion key" {bb}for the channel,

bb) A "conversion key" is a value of the mode specified by conv which is used to convert characters to and from the values as stored in internal form and as stored in "external" form in a book. It is a structured value comprising a row of structures, each of which contains a value in internal form and its corresponding external value. The implementation may provide additional conversion keys in its library-prelude.

cc) Three standard channels are provided, with properties as defined below (e,f,g); the implementation may provide additional channels in its library-prelude. The channel number field is provided in order that different channels with otherwise identical possibilities may be distinguished.}

a) MODE CHANNEL = STRUCT(PROC(REF BOOK)BOOL #a#reset, #a#set, #a#get, #a#put, #a#bin, #a#compress, #a#reidf, PROC BOOL #a#estab, PROC POS #a#max pos, PROC(REF BOOK)CONV #a#standconv, INT #a#channel number); 

b) MODE #a#CONV = STRUCT([1: INT(SKIP)] STRUCT(CHAR internal, external) #F#fff);

c) PROC estab possible = (CHANNEL chan)BOOL: estab OF chan;

d) PROC standconv = (CHANNEL chan)PROC(REF BOOK)CONV: standconv OF chan; 

e) CHANNEL stand in channel = #! a channel value whose field selected by 'get' is a routine which always returns true, and whose other fields are some suitable values #SKIP;

f) CHANNEL stand out channel = #! a channel value whose field selected by 'put' is a routine which always returns true, and whose other fields are some suitable values #SKIP;

g) CHANNEL stand back channel = #! a channel value whose fields selected by 'set', 'reset', 'get', 'put' and 'bin' are routines which always return true, and whose other fields are some suitable values #SKIP;
 
 
 

10.3.1.3. Files

{

 aa) A "file" is the means of communication between a particular-program and a book which has been opened on that file via some channel. It is a structured value which includes a reference to the book to which it has been linked {10.3.1.4.bb}and a separate reference to the text of the book. The file also contains information necessary for the transput routines to work with the book, including its current position cpos in the text, its current "state" {bb}, its current "format" {10.3.4}and the channel on which it has been opened.

bb) The "state" of a file is determined by five fields:

now f1 and f2 use different codes; flexocode and telexcode are defined in the \p{library-prelude} for this implementation # } reset(f1); {\I # consequently, f2 is reset too # } on logical file end(f1, (REF FILE f)BOOL: GOTO done); FOR i DO get(f1, x [i]); n := i OD; {\I # too bad if there are more than 10000 integers in the input # } } done: {\I reset(f1); for i to n DO put(f2, x [i]) OD; close(f2) # f1 is now closed too # }END #\unhangrb# }\rb} c·sequential access books, \Acite{undefined} \R{\xref A314a|10.3.1.4.a>} is called if binary and character transput is alternated, \IE, after opening or resetting \R{\xref A316j|10.3.1.6.j>}, either is possible but, once one has taken place, the other may not until after another reset. \XXX{A313hh}\itema{hh}On sequential access books, output immediately causes the logical end of the book to be moved to the current position (unless both are in the same line); thus input may not follow output without first resetting \R{\xref A316j|10.3.1.6.j>}, \medbreak\noindent Example: \smallbreak \Acode{ BEGIN FILE f1, t2; [1: 10000] INT x; INT n := 0; {\I open(f1, "{}"{}, channel 2); f2 := f1; {\I # now f1 and f2 can be used interchangeably # } make conv(f1, flexocode); make conv(f2, telexcode); {\I # now f1 and f2 use different codes; flexocode and telexcode are defined in the \p{library-prelude} for this implementation # } reset(f1); {\I # consequently, f2 is reset too # } on logical file end(f1, (REF FILE f)BOOL: GOTO done); FOR i DO get(f1, x [i]); n := i OD; {\I # too bad if there are more than 10000 integers in the input # } } done: {\I reset(f1); for i to n DO put(f2, x [i]) OD; close(f2) # f1 is now closed too # }END #\unhangrb# }\rb} c read mood, which is true if the file is being used for input:

· write mood, which is true if the file is being used for output:

· char mood, which is true if the file is being used for character transput;

· bin mood, which is true if the file is being used for binary transput:

· opened, which is true if the file has been linked to a book.

cc) A file includes some "event routines", which are called when certain conditions arise during transput. After opening a file, the event routines provided by default return false when called, but the programmer may provide other event routines. Since the fields of a file are not directly accessible to the user, the event routines may be changed by use of the "on routines" (l,m,n,o,p,q,r). The event routines are always given a reference to the file as a parameter. If the elaboration of an event routine is terminated, then the transput routine which called it can take no further action: otherwise, if it returns true, then it is assumed that the condition has been mended in some way, and, if possible, transput continues, but if it returns false, then the system continues with its default action. The on routines are:

· on logical file end. The corresponding event routine is called when, during input from a book or as a result of calling set, the logical end of the book is reached (see 10.3.1.6.dd).

Example: The programmer wishes to count the number of integers on his input tape. The file intape was opened in a surrounding range. If he writes: ,

BEGIN INT n := 0; on logical file end(intape, (REF FILE file)BOOL: GOTO f); DO get(intape, LOC INT); n +:= 1 OD; f: print(n)


END##
 
 

then the assignment to the field of intape violates the scope restriction, since the scope of the routine (REF FILE file)BOOL: GOTO f is smaller than the scope of intape, so he has to write: .
BEGIN INT n := 0; FILE auxin := in tape; on logical file end(auxin, (REF FILE file)BOOL: GOTO f); DO get(auxin, icc INT); n+:= 1 OD; f: print(n)


END##
 
 

· on physical file end. The corresponding event routine is called when the current page number of the file exceeds the number of pages in the book and further transput is attempted (see 10.3.1.6.dd),

· on page end. The corresponding event routine is called when the current line number exceeds the number of lines in the current page and further transput is attempted (see 10.3.1.6.dd).

· on line end. The corresponding event routine is called when the current character number of the file exceeds the number of characters in the current line and further transput is attempted (see 10.3.1.6.dd),

Example: The programmer wishes automatically to give a heading at the start of each page on his file f: .

on page end(f, (REF FILE file)BOOL: (put(file, (newpage, "page number ", whole(i +:= 1.0), newline)); TRUE) # it is assumed that i has been declared elsewhere #) ##
· on char error. The corresponding event routine is called when a character conversion was unsuccessful or when, during input, a character is read which was not "expected" {10.3.4.1.ll}. The event routine is called with a reference to a character suggested as a replacement. The event routine provided by the programmer may assign some character other than the suggested one. If the event routine returns true, then that suggested character as possibly modified is used,

Example: The programmer wishes to read sums of money punched as "&dollar;123.45", ",&dollar;23.45", ",&dollar;3.45", etc.: .

on char error(stand in, (REF FILE f, REF CHAR sugg)BOOL: IF sugg = "0" THEN CHAR c; backspace(f); get(f, c); (c = " dollar;" | get(f, sugg); TRUE | FALSE) ELSE FALSE FI ); INT cents; readf(( 3z"."dd , cents))##
· on value error. The corresponding event routine is called when:
( 1)
during formatted transput an attempt is made to transput a value under the control of a "picture" with which it is incompatible, or when the number of "frames" is insufficient. If the routine returns true, then the current value and picture are skipped and transput continues; if the routine returns false, then first, on output, the value is output by put, and next undefined is called;
( 2)
during input it is impossible to convert a string to a value of some given mode (this would occur if, for example, an attempt were made to read an integer larger than max int {10.2.1.c}).
· on format end. The corresponding event routine is called when, during formatted transput, the format is exhausted while some value still remains to be transput. If the routine returns true, then undefined is called if a new format has not been provided for the file by the routine; otherwise, the current format is repeated.

dd) The conv field of a file is its current conversion key {10.3.1.2.bb}. After opening a file, a default conversion key is provided. Some other conversion key may be provided by the programmer by means of a call of make conv {j}. Note that such a key must have been provided in the library-prelude.

ee) The routine make term is used to associate a string with a file. This string is used when inputting a variable number of characters, any of its characters serving as a terminator.

ff) The available methods of access to a book which has been opened on a file may be discovered by calls of the following routines (note that the yield of such a call may be a function of both the book and the channel, and of other environmental factors not defined by this Report):

· get possible, which returns true if the file may be used for input;

· put possible, which returns true if the file may be used for output;

· bin possible, which returns true if the file may be used for binary transput;

· compressible, which returns true if lines and pages will be compressed {10.3.1.6.aa}during output, in which case the book is said to be "compressible";

· reset possible, which returns true if the file may be reset, i.e., its current position set to (1, 1, 1);

· set possible, which returns true if the file may be set, i.e., the current position changed to some specified value; the book is then said to be a "random access" book and, otherwise, a "sequential access" book:

· reidf possible, which returns true if the idf field of the book may be changed:

· chan, which returns the channel on which the file has been opened {this may be used, for example, by a routine assigned by on physical file end, in order to open another file on the same channel} .

gg) On sequential access books, undefined {10.3.1.4.a}is called if binary and character transput is alternated, i.e., after opening or resetting {10.3.1.6.j}, either is possible but, once one has taken place, the other may not until after another reset.

hh) On sequential access books, output immediately causes the logical end of the book to be moved to the current position (unless both are in the same line); thus input may not follow output without first resetting {10.3.1.6.j},
 

Example:

BEGIN FILE f1, t2; [1: 10000] INT x; INT n := 0; open(f1, "", channel 2); f2 := f1; # now f1 and f2 can be used interchangeably # make conv(f1, flexocode); make conv(f2, telexcode); # now f1 and f2 use different codes; flexocode and telexcode are defined in the library-prelude for this implementation # reset(f1); # consequently, f2 is reset too # on logical file end(f1, (REF FILE f)BOOL: GOTO done); FOR i DO get(f1, x [i]); n := i OD; # too bad if there are more than 10000 integers in the input # done: reset(f1); for i to n DO put(f2, x [i]) OD; close(f2) # f1 is now closed too # END ##

a) MODE file = STRUCT(REF BOOK #a#book, UNION(FLEXTEXT, TEXT) #a#text, CHANNEL #a#chan, REF FORMAT #a#format, REF INT #a#forp, REF BOOL #a#read mood, #a#write mood, #a#char mood, #a#bin mood, #a#opened, REF POS #a#cpos # current position #, STRING #a#term # string terminator #, CONV #a#conv # character conversion key #, PROC(REF FILE )BOOL #a#logical file mended, #a#physical file mended, #a#page mended, #a#line mended, #a#format mended, #a#value error mended, PROC(REF FILE, REF CHAR)BOOL #a#char error mended);

b) PROC get possible = (REF FILE f)BOOL: (opened OF f | (get OF chan OF f)(book OF f) | undefined; SKIP); 

c) PROC put possible = (REF FILE f)BOOL: (opened OF f | (put OF chan OF f)(book OF f) | undefined; SKIP); 

d) PROC bin possible = (REF FILE f)BOOL: (opened OF f | (bin OF chan OF f)(book OF f) | undefined; SKIP); 

e) PROC compressible = (REF FILE f)BOOL: (opened OF f | (compress OF chan OF f)(book OF f) | undefined; SKIP); 

f) PROC reset possible = (REF FILE f)BOOL: (opened OF f | (reset OF chan OF f)(book OF f) | undefined; SKIP); 

g) PROC set possible = (REF FILE f)BOOL: (opened OF f | (set OF chan OF f)(book OF f) | undefined; SKIP);

h) PROC reidf possible = (REF FILE f)BOOL: (opened OF f | (reidf OF chan OF f)(book OF f) | undefined; SKIP);

i) PROC chan = (REF FILE f)CHANNEL: (opened OF f | chan OF f | undefined; SKIP);

j) PROC make conv = (REF FILE f, PROC(REF BOOK)CONV c)VOID: (opened OF f | conv OF f := c(book OF f) | undefined);

k) PROC make term = (REF FILE f, STRING t)VOID: term OF f := t;

l) PROC on logical file end = (REF FILE f, PROC(REF FILE )BOOL p)VOID: logical file mended OF f := p; 

m) PROC on physical file end = (REF FILE f, PROC(REF FILE )BOOL p)VOID: physical file mended OF f:= p; 

n) PROC on page end = (REF FILE f, PROC(REF FILE )BOOL p)VOID: page mended OF f := p; 

o) PROC on line end = (REF FILE f, PROC(REF FILE )BOOL p)VOID: line mended OF f := p; 

p) PROC on format end = (REF FILE f, PROC(REF FILE )BOOL p)VOID: format mended OF f := p; 

q) PROC on value error = (REF FILE f, PROC(REF FILE )BOOL p)VOID: value error mended OF f := p; 

r) PROC on char error = (REF FILE f, PROC(REF FILE , REF CHAR)BOOL p)VOID: char error mended OF f := p; 

s) PROC reidf = (REF FILE f, STRING idf)VOID: IF opened OF f reidf possible(f) idfok(idf) THEN idf OF book OF f := idf FI;
 
 
 

10.3.1.4. Opening and closing files

{

 aa) When, during transput, something happens which is left undefined, for example by explicitly calling undefined {a}, this does not imply that the elaboration is catastrophically and immediately interrupted {2.1.4.3.h}, but only that some sensible action is taken which is not or cannot be described by this Report alone and is generally implementation-dependent.

bb) A book is "linked" with a file by means of establish{b}, create{c}or open{d}. The linkage may be terminated by means of close {n}, lock {o}or scratch {p}.

cc) When a file is "established" on a channel, then a book is generated {5.2.3}with a text of the given size, the given identification string, with putting set to true, and the logical end of the book at (1, 1, 1). An implementation may require {g}that the characters forming the identification string should be taken from a limited set and that the string should be limited in length, it may also prevent two books from having the same string, if the establishing is completed successfully, then the value 0 is returned; otherwise, some nonzero integer is returned (the value of this integer might indicate why the file was not established successfully). When a file is "created" on a channel, then a file is established with a book whose text has the default size for the channel and whose identification string is undefined.

dd) When a file is "opened", then the chain of backfiles is searched for the first book which is such that match {h}returns true. (The precise method of matching is not defined by this Report and will, in general, be implementation dependent. For example, the string supplied as parameter to open may include a password of some form.) If the end of the chain of backfiles is reached or if a book has been selected, but putting of the book yields true, or if putting to the book via the channel is possible and the book is already open, then the further elaboration is undefined. If the file is already open, an UP gremlins provides an opportunity for an appropriate system action on the book previously linked (in case no other copy of the file remains to preserve that linkage).

ee) The routine associate may be used to associate a file with a value of the mode specified by either REF [ ] CHAR, REF [ ] [ ] CHAR or REF [ ] [ ] [ ] CHAR, thus enabling such variables to be used as the book of a file,

ff) When a file is "closed", its book is attached to the chain of backfiles referenced by chainbfile. Some system-task is then activated by means of an UP gremlins. (This may reorganize the chain of backfiles, removing this book, or adding further copies of it. It may also cause the book to be output on some external device.)

gg) When a file is "locked", its book is attached to the chain of backfiles referenced by lockedbfile. Some system-task is then activated by means of an UP gremlins. A book which has been locked cannot be re-opened until some subsequent system-task has re-attached the book to the chain of backfiles available for opening.

hh) When a file is "scratched", some system-task is activated by means of an UP gremlins. (This may cause the book linked to the file to be disposed of in some manner.)}

a) PROC #a#undefined = INT: #! some sensible system action yielding an integer to indicate what has been done; it is presumed that the system action may depend on a knowledge of any values accessible {2.1.2.c}inside the locale of any environ which is older than that in which this pseudo-comment is being elaborated {notwithstanding that no ALGOL 68 construct written here could access those values} #SKIP;

b) PROC establish = (REF FILE file, STRING idf, CHANNEL chan, INT p, l, c)INT: BEGIN DOWN bfileprotect; #!PRIM#HEAP BOOK book := ( #!PRIM#HEAP FLEX [1 : p] FLEX [1 :l] FLEX [1: c] CHAR, (1, 1, 1), idf, TRUE, 1);

IF file available(chan) (put OF chan)(book) estab OF chan (POS(p, l, c) BEYOND max pos OF chan) (POS(1, 1, 1) BEYOND POS(p, l, c)) idfok(idf) THEN (opened OF file | UP gremlins | UP bfileprotect); file := (book, text OF book, chan, SKIP, SKIP, # state: # HEAP BOOL := FALSE, HEAP BOOL := TRUE,## HEAP BOOL := FALSE, HEAP BOOL := FALSE, HEAP BOOL := TRUE,## HEAP POS := (1, 1, 1), "", (standconv OF chan)(book), # event routines: # false, false, false, false, false, false,## (REF FILE f, REF CHAR a)BOOL: FALSE); ( bin possible(file) i | set char mood(file)); 0 ELSE UP bfileprotect; undefined FI END;

c) PROC create = (REF FILE file, CHANNEL chan)INT: BEGIN POS max pos = max pos OF chan; establish(file, SKIP, chan, p OF max pos, l OF max pos, c OF max pos) END;

d) PROC open = (REF FILE file, STRING idf, CHANNEL chan)INT: BEGIN DOWN bfileprotect; IF file available(chan) THEN REF REF BFILE bf := chainbfile; BOOL found := FALSE; WHILE (REF BFILE(bf) :/=: NIL) found DO IF match(idf, chan, book OF bf) THEN found := TRUE ELSE bf := next OF bf FI OD; IF found THEN UP bfileprotect; undefined ELSE REF BOOK book := book OF bf; IF putting OF book #|#OR (put OF chan)(book) users OF book >0 THEN UP bfileprotect; undefined # in this case opening is inhibited by other users - the system may either wait, or yield nonzero (indicating unsuccessful opening) immediately # ELSE users OF book +:= 1; ((put OF chan)(book) | putting OF book := TRUE ); REF REF BFILE(bf) := next OF bf; # remove bfile from chain # (opened OF file | UP gremlins | UP bfileprotect); file := (book, text OF book, chan, SKIP, SKIP, # state: # HEAP BOOL := FALSE, HEAP BOOL := FALSE,## HEAP BOOL := FALSE, HEAP BOOL := FALSE,## HEAP BOOL := TRUE, HEAP POS := (1, 1, 1), "",## (standconv OF chan)(book), # event routines: # false, false, false, false, false,## false,## (REF FILE f, REF CHAR a)BOOL: FALSE); ( bin possible(file) | set char mood(file)); ( get possible(file) | set write mood(file)); ( put possible(file) | set read mood(file)); 0 FI FI ELSE UP bfileprotect; undefined FI END;

e) PROC associate = (REF FILE file, REF [ ][ ][ ] CHAR sss)VOID: IF INT p = LWB sss; INT l = LWB sss [p]; INT c = LWB sss[p][l]; p = 1 l = 1 c = 1 THEN PROC t = (REF BOOK a)BOOL: TRUE; PROC f = (REF BOOK a)BOOL: FALSE; CHANNEL chan = (t, t, t, t, f, f, f, BOOL: FALSE, pos: (max int, max int, max int), SKIP, SKIP); (opened OF file | DOWN bfileprotect; UP gremlins); file := (HEAP BOOK := (SKIP, (UPB sss + 1,1,1), SKIP, TRUE,1), sss, chan, SKIP, SKIP, # state: # HEAP BOOL := FALSE, HEAP BOOL := FALSE,## HEAP BOOL := TRUE, HEAP BOOL := FALSE,## HEAP BOOL := TRUE,## HEAP POS := (1, 1, 1), "", SKIP, # event routines: # false, false, false, false, false,## false,## (REF FILE f, REF CHAR a)BOOL: FALSE) ELSE undefined FI;

f) PROC #a#file available = (CHANNEL chan)BOOL: #! true if another file, at this instant of time, may be opened on 'chan' and false otherwise #SKIP;

g) PROC #a#idf ok = (STRING idf)BOOL: #! true if 'idf' is acceptable to the implementation as the identification of a new book and false otherwise #SKIP;

h) PROC #a#match = (STRING idf, CHANNEL chan, REF BOOK book name)BOOL: #! true if the book referred to by 'book name' may be identified by 'idf', and if the book may legitimately be accessed through 'chan', and false otherwise #SKIP;

i) PROC #a#false = (REF FILE file)BOOL: FALSE # this is included for brevity in 'establish', 'open' and 'associate' #;

j) PROC #a#set write mood = (REF FILE f)VOID: IF put possible(f) #|#OR## set possible(f) bin mood OF f read mood OF f THEN undefined ELSE REF BOOL(read mood OF f) := FALSE; REF BOOL(write mood OF f) := TRUE FI;

k) PROC #a#set read mood = (REF FILE f)VOID: IF get possible(f)## set possible(f) bin mood OF f write mood OF f THEN undefined ELSE REF BOOL(read mood OF f) := TRUE; REF BOOL(write mood OF f) := FALSE FI;

l) PROC #a#set char mood = (REF FILE f)VOID: IF set possible(f) bin mood OF f THEN undefined ELSE REF BOOL(char mood OF f) := TRUE; REF BOOL(bin mood OF f) := FALSE FI;

m) PROC #a#set bin mood = (REF FILE f)VOID: IF bin possible(f) #|#OR set possible(f) char mood OF f THEN undefined ELSE REF BOOL(char mood OF f):= FALSE; REF BOOL(bin mood OF f):= TRUE FI;

n) PROC close = (REF FILE file)VOID: IF opened OF file THEN DOWN bfileprotect; REF BOOL(opened OF file) := FALSE; REF BOOK book = book OF file; putting OF book := FALSE; users OF book -:= 1; (text OF file | (FLEXTEXT): chainbfile := #!PRIM#HEAP bfile := (book, chainbfile)); UP gremlins FI;

o) PROC lock (REF FILE file)VOID: IF opened OF file THEN DOWN bfileprotect; REF BOOL(opened OF file) := FALSE; REF BOOK book = book OF file; putting OF book := FALSE; users OF book -:= 1; (text OF file | (FLEXTEXT): lockedbfile := #!PRIM#HEAP bfile = (book, lockedbfile)); UP gremlins FI;

p) PROC scratch = (REF FILE file)VOID: IF opened OF file THEN DOWN bfileprotect; REF BOOL(opened OF file) := FALSE; putting OF book OF file := FALSE; users OF book OF file -:= 1; UP gremlins FI;
 
 
 

10.3.1.5. Position enquiries

{

 aa) The "current position" of a book opened on a given file is the value referred to by the cpos field of that file. It is advanced by each transput operation in accordance with the number of characters written or read.

If c is the current character number and lb is the length of the current line, then at all times 1 £ c £ lb + 1. c = 1 implies that the next transput operation will be to the first character of the line and c = lb + 1 implies that the line has overflowed and that the next transput operation will call an event routine. If lb = 0, then the line is empty and is therefore always in the overflowed state. Corresponding restrictions apply to the current line and page numbers. Note that, if the page has overflowed, the current line is empty and, if the book has overflowed, the current page and line are both empty {e}.

bb) The user may determine the current position by means of the routines char number, line number and page number (a, b, c).

cc) If the current position has overflowed the line, page or book, then it is said to be outside the "physical file" (f, g, h).

dd) If, on reading, the current position is at the logical end, then it is said to be outside the "logical file" {i}.} {Each routine in this section calls undefined if the file is not open on entry.}

a) PROC char number = (REF FILE f)INT:## (opened OF f | c OF cpos OF f | undefined); 

b) PROC line number = (REF FILE f)INT:## (opened OF f | l OF cpos OF f | undefined); 

c) PROC page number = (REF FILE f)INT:## (opened OF f | p OF cpos OF f | undefined); 

d) PROC #a#current pos = (REF FILE f)POS:## (opened OF f | cpos OF f | undefined; SKIP);

e) PROC #a#book bounds = (REF FILE f)POS: BEGIN POS cpos = current pos(f); INT p = p OF cpos, l = l OF cpos; CASE text OF f IN (TEXT t1): (INT pb = UPB t1; INT lb = (p <= 0 #|#OR p>pb | 0 | UPB t1 [p]); INT cb = (l <= 0 #|#OR l>lb | 0 | UPB t1[p][l]); (pb, lb, cb)), (FLEXTEXT t2): (INT pb = UPB t2; INT lb = (p <= 0 #|#OR p>pb | 0 UPB t2[p]); INT cb = (l <= 0 #|#OR l>lb | 0 | UPB t2[p] [I]); (pb, lb, cb)) ESAC END; 

f) PROC #a#line ended = (REF FILE f)BOOL:## (INT c = c OF current pos(f); c > c OF book bounds(f));

g) PROC #a#page ended = (REF FILE f)BOOL:## (INT l = l OF current pos(f); l > l OF book bounds(f));

h) PROC #a#physical file ended = (REF FILE f)BOOL:## (INT p = p OF current pos(f); p > p OF book bounds(f));

i) PROC #a#logical file ended = (REF FILE f)BOOL:## (lpos OF book OF f BEYOND current pos(f));
 
 
 

10.3.1.6. Layout routines

{

 aa) A book input from an external medium by some system-task may contain lines and pages not all of the same length. Contrariwise, the lines and pages of a book which has been established {10.3.1.4.cc}are all initially of the size specified by the user. However if, during output to a compressible book {10.3.1.3.ff}, newline (newpage) is called with the current position in the same line (page) as the logical end of the book, then that line (the page containing that line) is shortened to the character number (line number) of the logical end. Thus print(("abcde", newline)) could cause the current line to be reduced to 5 characters in length. Note that it is perfectly meaningful for a line to contain no characters and for a page to contain no lines.

Although the effect of a channel whose books are both compressible and of random access {10.3.1.3.ff}is well defined, it is not anticipated that such a combination is likely to occur in actual implementations.

bb) The routines space {a}, newline {c}and newpage {d}serve to advance the current position to the next character, line or page, respectively. They do not, however, (except as provided in cc below) alter the contents of the positions skipped over. Thus print(("a", backspace, space)) has a different effect from print(("a", backspace, blank)).

The current position may be altered also by calls of backspace {b}, set char number {k} and, on appropriate channels, of set {i}and reset {j}.

cc) The contents of a newly established book are undefined and both its current position and its logical end are at (1, 1, 1). As output proceeds, it is filled with characters and the logical end is moved forward accordingly. If, during character output with the current position at the logical end of the book, space is called, then a space character is written (similar action being taken in the case of newline and newpage if the book is not compressible).

A call of set which attempts to leave the current position heyond the logical end results in a call of undefined (a sensible system action might then be to advance the logical end to the current position, or even to the physical end of the book). There is thus no defined way in which the current position can be made to be beyond the logical end, nor in which any character within the logical file can remain in its initial undefined state.

dd) A reading or writing operation, or a call of space, newline, newpage, set or set char number, may bring the current position outside the physical or logical file {10.3.1.5.cc, dd}, but this does not have any immediate consequence. However, before any further transput is attempted, or a further call of space, newline or newpage (but not of set or set char number) is made, the current position must be brought to a "good" position. The file is "good" if, on writing (reading), the current position is not outside the physical (logical) file {10.3.1.5.cc, dd}. The page (line) is "good" if the line number (character number) has not overflowed. The event routine {10.3.1.3.cc}corresponding to on logical file end, on physical file end, on page end or on line end is therefore called as appropriate. Except in the case of formatted transput (which uses check pos, 10.3.3.2.c), the default action, if the event routine returns false, is to call, respectively, undefined, undefined, newpage or newline. After this (or if true is returned), if the position is still not good, an event routine (not necessarily the same one) is called again.

ee) The state of the file {10.3.1.3.bb}controls some effects of the layout routines. If the read/write mood is reading, the effect of space, newline and newpage, upon attempting to pass the logical end, is to call the event routine corresponding to on logical file end with default action undefined; if it is writing, the effect is to output spaces (or, in bin mood, to write some undefined character) or to compress the current line or page (see cc). If the read/write mood is not determined on entry to a layout routine, undefined is called. On exit, the read/write mood present on entry is restored.}

a) PROC space = (REF FILE f)VOID: IF opened OF f THEN undefined ELSE BOOL reading = (read mood OF f | TRUE |: write mood OF f | FALSE## | undefined; SKIP); ( get good line(f, reading) | undefined); REF POS cpos = cpos OF f; IF reading THEN c OF cpos +:= 1 ELSE IF logical file ended(f)THEN IF bin mood OF f THEN (text OF f | (FLEXTEXT t2): t2[p OF cpos] [l OF cpos] [c OF cpos] := SKIP); c OF pos +:= 1; lpos OF book OF f := cpos ELSE put char(f, "") FI ELSE c OF cpos +:= 1 FI FI FI ;

b) PROC backspace = (REF FILE f)VOID: IF opened OF f THEN undefined ELSE REF INT c = c OF cpos OF f; (c>1 | c-:= 1 | undefined) FI;

c) PROC newline = (REF FILE f)VOID: IF opened OF f THEN undefined ELSE BOOL reading = (read mood OF f | TRUE |: write mood OF f | FALSE## | undefined; SKIP); ( get good page(f, reading) | undefined); REF POS cpos = cpos OF f, lpos = lpos OF book OF f; IF p OF cpos = p OF lpos l OF cpos = l OF lpos THEN c OF cpos := c OF lpos; IF reading THEN newline(f) ELSE IF compressible(f) THEN REF INT pl = p OF lpos, ll = l OF lpos; FLEXTEXT text = (text OF f | (FLEXTEXT t2): t2); text [pl] [ll] text [pl] [ll] [ : c OF lpos - 1] ELSE WHILE line ended(f) DO space(f) OD FI; cpos := lpos := (p OF cpos, l OF cpos + 1, 1) FI ELSE cpos := (p OF cpos, l OF cpos + 1, 1) FI FI; 

d) PROC newpage = (REF FILE f)VOID: IF opened OF f THEN undefined ELSE BOOL reading = (read mood OF f) | TRUE |: write mood OF f | FALSE## | undefined; SKIP); ( get good file(f, reading) | undefined); REF POS cpos = cpos OF f, lpos = lpos OF book OF f; IF p OF cpos = p OF lpos THEN cpos := lpos; IF reading THEN newpage(f) ELSE IF compressible(f) l OF lpos <= l OF book bounds(f) THEN REF INT pl = p OF lpos, ll = l OF lpos; FLEXTEXT text = (text OF f | (FLEXTEXT t2): t2); text[pl] [ll] text [pl] [ll]t: c OF lpos - 1]; text [pl] := text [pl] [ : (c OF lpos> 1 | ll | ll - 1)] ELSE WHILE page ended(f) DO newline(f) OD FI; cpos := lpos := (p OF cpos + 1, 1, 1) FI ELSE cpos := (p OF cpos + 1, 1, 1) FI FI;

{Each of the following 3 routines either returns true, in which case the line, page or file is good {dd}, or it returns false, in which case the current position may be outside the logical file or the page number may have overflowed, or it loops until the matter is resolved, or it is terminated by a jump. On exit, the read/write mood is as determined by its reading parameter.}

e) PROC #a#get good line = (REF FILE f, BOOL reading)BOOL: BEGIN BOOL not ended; WHILE not ended := get good page(f, reading); line ended(f) not ended DO ( (line mended OF f)(f) | set mood(f, reading); newline(f)) OD; not ended END;

f) PROC #a#get good page = (REF FILE f, BOOL reading)BOOL: BEGIN BOOL not ended; WHILE not ended := get good file(f, reading); page ended(f) not ended DO ( (page mended OF f)(f) | set mood(f, reading); newpage(f)) OD; not ended END;

g) PROC #a#get good file = (REF FILE f, BOOL reading) BOOL: BEGIN BOOL not ended := TRUE; WHILE set mood(f, reading); not ended (reading | logical file ended | physical file ended)(f) DO not ended := (reading | logical file mended OF f## | physical file mended OF f)(f) OD; not ended END;

h) PROC #a#set mood = (REF FILE f, BOOL reading)VOID: (reading | set read mood(f) | set write mood(f));

i) PROC set = (REF FILE f, INT p, l, c)VOID: IF opened OF f #|#OR get possible(f) THEN undefined ELSE BOOL reading = (read mood OF f | TRUE |: write mood OF f | FALSE undefined; SKIP); REF POS cpos = cpos OF f, lpos = lpos OF book OF f; POS ccpos = cpos; IF (cpos := (p, l, c)) BEYOND lpos THEN cpos := lpos; ( (logical file mended OF f)(f) | undefined); set mood(f, reading) ELIF POS bounds = book bounds(f); p < 1 #|#OR p > p OF bounds + 1 #|#OR l < 1 #|#OR l > l OF bounds + 1 #|#OR c < 1 #|#OR c > c OF bounds + 1 THEN cpos := ccpos; undefined FI FI;

j) PROC reset = (REF FILE f)VOID: IF opened OF f #|#OR reset possible(f) THEN undefined ELSE REF BOOL (read mood OF f):= put possible(f); REF BOOL (write mood OF f) := get possible(f); REF BOOL (char mood OF f) := bin possible(f); REF BOOL (bin mood OF f) := FALSE; REF POS (cpos OF f) := (1, 1, 1) FI;

k) PROC set char number = (REF FILE f, INT c)VOID: IF opened OF f THEN undefined ELSE REF REF POS cpos = cpos OF f; WHILE c OF cpos /= c DO IF c < 1 #|#OR c > c OF book bounds(f) + 1 THEN undefined ELIF c > c OF cpos THEN space(f) ELSE backspace(f) FI END FI;