SUBGROUPGFIO - An I/O library for George 3

In order to simplify the task of porting the programs from Kernighan and Plauger's "Software Tools", which are written to use ASCII as the internal character set I decided to write an I/O library that allowed use of the ICL ECMA character set.

The library also provides a Unix style "open" routine, allowing opening of filestore files at runtime.

All I/O to the terminal is performed using *TR (pseudo tape-reader) and *TP (pseudo tape-punch) devices in NORMAL (upper/lowercase) mode. I/O to filestore files uses *FR (file reader), *FW (file writer) and *FH (file handler - allows reading and writing) devices.

The library is somewhat based on Unix, the "open" routine returns a small integer representing the connection to the file, this number is passed to the read/write/close routines indicating which file is to be operated on. This number is conventionally referred to as the "fd" or "file descriptor".

The fd's 0, 1, 2 can be used without an open call, they will be automatically attached to the MOP console or job source/output. fd 0 is conventionally used as standard input, fd 1 as standard output and fd 1 is used for "standard error".

When fd 0 is used SUBGROUPIO checks to see if *FR0 is ASSIGNED, if it is then *FR0 will be used, if not it will try to use *TR0 in a MOP job, ONLINE to the mop console, or *FR0 in a background job, ASSIGNed to the job source.

In a similar fashion fd 1 will be *FW0 or *TP0 and fd 2 will be *FW1 or *TP1.

The equivalent of the Unix:

$ wc -l <file
would be:
12.23.45_ AS *FR, FILE
12.23.48_ LE PROGRAM WC,,PARAM(LINES)

The current versions of the routines are written to be callable from FORTRAN or Algol. They use the standard calling convention, routines are called with the link in X1, instructions are placed after the call which load the addresses of the arguments into X3 which the routine picks up with OBEY instructions. The return value from the routines is placed in X6.

When used from Algol all arguments are passed by value, except the buffers and character strings which are passed as integer arrays by name.

All routine names are prefixed with GF to indicate that they are Fortran callable.

The source code for the current versions can be found here, or linked to from the routine descriptions.

A magtape image containing all the source and instructions for compiling and installing the library can be found here.

Example program using subgroupgfio

An implementation of the Unix cat(1) command:
       LIST
       LIBRARY (SUBGROUPGFIO)
       PROGRAM (CAT)
       COMPRESS INTEGER AND LOGICAL
       EXTENDED
       END
       MASTER CAT

       INTEGER GFGETARG, GFOPEN, GFCLOSE

       INTEGER ARG(100)

       I = 1
100    CONTINUE
          L = GFGETARG (-1, ARG, 400)
          IF (L .LT. 0) GOTO 200
          M = GFOPEN (ARG, L, 0, 0)
          IF (M .LT. 0) STOP 'OPEN'
          CALL COPY (M, 1)
          IF (GFCLOSE (M) .LT. 0) STOP 'IO - CLOSE'
          I = I + 1
       GOTO 100

200    IF (I .EQ. 1) CALL COPY (0, 1)
       STOP
       END
       SUBROUTINE COPY (IFROM, ITO)

       INTEGER GFREADLN, GFWRITELN, GFREADECMA, GFWRITEECMA

       INTEGER BUF (1)

100    IF (GFREADLN (IFROM).LE.0) GOTO 900
200       CONTINUE
             K = GFREADECMA (IFROM)
             IF (K .LT. 0) GOTO 300
             BUF (1) = K
             IF (GFWRITEECMA (ITO, BUF, 1) .LT. 0) STOP 'IO - WRITECH'
          GOTO 200
300       IF (GFWRITELN (ITO) .LT. 0) STOP 'IO - WRITELN'
       GOTO 100
900    RETURN
       END

Routine descriptions

open - Open a file

integer procedure gf open (name, namelen, mode, type);
value namelen, mode, type;
integer namelen, mode, type;
integer array name [];

the return value is the fd if positive or a negative error code.

name
is the filename, in ICL 6 bit code. It should be passed as an array element, Hollerith constant or an array name, but not a simple variable. (A later version of the routines may allow for passing an Algol string).
namelen
is the length in characters of the name.
mode
0
read buffered. In this mode the file is read one block at a time, which is much faster than reading a record at a time. When a file is being read in buffered mode it is not possible to change the current read position other than a "rewind" to start reading the file from the beginning.
1
read. The file will be read a record at a time. The setpos function can be used to position to any record in the file.
2
read/write. The file can be read or written. By default writes append to the end of the file. The writemode function can be used to change to rewrite last record read mode. The delete function can be used to delete the last record read.
3
write (empty file). The file is emptied if it exists.
4
append. New data will be appended to an existing file.
type
0
don't care (implies AMORPHOUS for create)
1
GRAPHIC
2
NORMAL
3
ALLCHAR
We implement this using the *FR, *FW and *FH devices, with appropriate qualifiers on the ASSIGN.

close - Close a file

integer procedure gf close (fd);
value fd;
integer fd;

the return value is zero or a negative error code.

Any partly written data will be flushed.

write6 - Write 6 bit characters to a file

integer procedure gf write6 (fd, buf, pos, len);
value fd, pos, len;
integer fd, buf, pos, len;
integer array buf [];

the return value is positive or zero if no error occurs or a negative error code.

fd
The file to be written
buf
The data to write, in ICL 6 bit character set. This should be an array element, Hollerith constant or an array name, but not a simple variable.
pos
The offset in the buffer to start writing from (the first character is at position "0").
len
The number of characters to write.

writeint - Write an integer to a file

integer procedure gf writeint (fd, val, len);
value fd, val, len;
integer fd, val, len;

the return value is positive or zero if no error occurs or a negative error code.

fd
The file to be written.
val
The value to write. It will be output preceded by a "-" if negative.
len
The width of the field. If the width is negative the number will be written left justified. If the representation requires more space than the field width requested then the width will be expanded as necessary.

For example:

writeint (fd, 314, 5) - writes   |  314|
writeint (fd, -314, 5) - writes  | -314|
writeint (fd, 314, -5) - writes  |314  |
writeint (fd, -314, -5) - writes |-314 |
writeint (fd, 314, 2) - writes   |314|
writeint (fd, -314, 2) - writes  |-314|

writespaces - Write spaces to a file

integer procedure gf writespaces (fd, len);
value fd, len;
integer fd, len;

the return value is positive or zero if no error occurs or a negative error code.

fd
The file to be written
len
The number of spaces to write.

writeecma - Write ECMA 7 bit characters to a file

integer procedure gf writeecma (fd, buf, len);
value fd, len;
integer fd, len;
integer array buf [1:len];

the return value is positive or zero if no error occurs or a negative error code.

fd
The file to be written
buf
The data to write, in ECMA 7 bit character set. This should be an array element, or an array name, but not a simple variable. If the calling code is Fortran it should be compiled with COMPRESS INTEGER AND LOGICAL. (A later version of the routine may work without this restriction). The characters are stored one per array element, not packed.
len
The number of characters to write.

writeln - Write a line to a file

integer procedure gf writeln (fd);
value fd;
integer fd;

the return value is positive or zero if no error occurs or a negative error code.

fd
The file to be written
All data in the current buffer is written to the file and a new record is started.

readln - Read a line from a file

integer procedure gf readln (fd);
value fd;
integer fd;

the return value is positive if no error occurs, zero for eof or a negative error code.

fd
The file to be read.
A line is read from the indicated file into an internal buffer.

readecma - Read a character from a file

integer procedure gf readecma (fd);
value fd;
integer fd;

the return value is the character read, or negative if there are no more characters left on the line.

fd
The file to be read.
If readecma returns -ve then readln must be called before more characters can be read.

openstr - open a memory buffer for I/O

integer procedure gf openstr (shift, str, pos, len);
value shift, pos, len;
integer shift, pos, len;
integer array str [];

the return value is a fd which can be used to do I/O from the memory buffer passed in str.

shift
The initial shift. -1 indicates that the I/O should be unshifted, 0 (or any even number) that it starts in alpha shift or 1 (or any odd number) that it starts in beta shift.
str
The string buffer to write to. It should be an array element, or an array name, but not a simple variable.
pos
The position of the first character to write to or read from in the buffer, starting from zero.
len
The available buffer length in six bit characters.
Initially the fd is set for reading, readecma will read characters from the string. If the fd is written to it will be written from the start.

If the fd is written to the number of 6bit characters in the buffer can be found by using the written function.

Example:

       INTEGER BUF (5)
       DATA BUF /'ABCDEF'/
       I = GFOPENSTR (0, BUF(1), 0, 20)
       K = READECMA (I)
C - K will be set to 65

       K = GFWRITEECMA (I, 97, 1)
C - 1st two characters in buffer will be "]A"

       K = GFWRITTEN(I)
C - K is now 2.

openci - open a command issuer channel

integer procedure gf openci ();

the return value is a fd which can be used to write commands to George. Currently only an "unanticipated" command issuer is implemented so the commands will be run in the current job.

If a command produces an error the return from writeln will be negative.

getarg - get a program argument

integer procedure gf getarg (argno, buf, len);
value argno, len;
integer argno, len;
integer array buf [];

the return value is the length of the argument, or negative if there is no such argument.

argno
The argument number to read, or -1 to read the arguments in sequence starting with the first.
buf
A buffer to hold the argument value, in ICL 6 bit code. It should be an array element or an array name, but not a simple variable.
len
The maximum number of characters to write to the buffer.

written - get characters written to fd

integer procedure gf written (fd);
value fd;
integer fd;

the return value is the number of 6 bit characters that have been written to the internal buffer of fd. This is useful for determining how much of the user supplied buffer to openstr is used.

fd
The fd.

pack8 - pack 8 bit characters into a buffer

procedure gf pack8 (from, len, to, pos);
value len, pos;
integer len, pos;
integer array from [1:len], to[];

pack len 8 bit characters from from to to starting at offset pos

from
Source,one character per word
len
Number of characters to copy
to
destination
pos
offset (in the characters) from the start of the destination.

unpack8 - unpack 8 bit characters from a buffer

procedure gf unpack8 (from, pos, to, len);
value pos, len;
integer pos, len;
integer array from [], to[1:len];

unpack len 8 bit characters from from, starting at pos to to

from
Source,three character per word
pos
offset (in the characters) from the start of the source.
to
destination
len
Number of characters to copy

move - move words

procedure gf move (from, to, words);
value words;
integer words;
integer array from [1:words], to[1:words];

move len words from from, to to

from
Source
to
Destination
words
Number of words to copy
The move will be done as fast as possible, with the MOVE instruction unless that would overwrite the source with the destination