The unit of information on a ZEBRA file is the data-structure. It may consist of zero, one, two, or more data-segments. The data-segments reflect the original residence of different parts of the data-structure in different divisions at the moment when the d/s was transferred from memory to the file with FZOUT. When the d/s is transferred back from the file to memory with FZIN individual data-segments may be directed to separate divisions, or may be ignored.
User information which may be associated with each d/s is the 'user header vector', specified and received via parameters to FZOUT and FZIN, and the 'text vector' taken from and delivered to the text-buffer associated to the file with FZTXAS (implementation of this routine is pending).
On the file the data-structure is represented by the 'pilot information' followed by the 'bank material'. The pilot carries all the control and context information, namely:
In Native Data Format the bank material on the file is a simple dump of the memory; but in Exchange Data Format the numbers have to be transformed from the internal to the exchange representation. To make this possible automatically, every bank has to carry its 'I/O characteristic' describing the integer/floating/Hollerith nature of its contents exactly; see the descriptions of the routines MZLIFT and MZBOOK. Banks of type 'undefined' cannot be transported.
The exact details for the file and data formats
are found in Chapter
.
The unit of information on a ZEBRA file is the data-structure.
Several data-structures may be (but need not) be grouped into an event. On the file events are separated by the 'start-of-event' flag being present in the first data-structure of each event. FZIN may be asked to skip forward to and read the next 'start-of-event' data-structure.
Several events (or d/s) may (but need not) be grouped into a run. On the file the start and the end of a run are marked by special StoR and EoR records written by calling FZRUN. FZIN may be asked to skip forward to and read the next 'start-of-run' record. (Skipping forward to next run or event should not be used for the medium Memory or Channel.)
A ZEBRA file has to be terminated. The writing of End-of-File is a perennial problem, as the requirements for different kinds of files are different for different machines and different media. Thus for example, on the IBM system MVS one should not terminate a disk file by an ENDFILE statement, as this inhibits the release of the unused space on the disk. A tape, on the other hand, should be terminated by a double EoF which may or may not be provided by the system, yet on the VAX the program will collapse if one tries to ENDFILE an unlabelled tape.
In principle, a Zebra file may logically consist of several files on the same medium. To implement this rigorously on all machines the special Zebra EoF record is provided (an end-of-run record which immediately follows a true end-of-run is also interpreted as EoF). It is written by a call to FZENDO with one of the options T, N, C, or I.
Whether or not the writing of a Zebra EoF signal is followed by the explicit request to write one or two system file-marks (for end-of-file or end-of-data) depends on the circumstances. Most machines do not support multi-file disk files, and some machines do not even support multi-file tape files.
In first approximation, a Zebra file is assumed not to contain imbedded system file-marks. For output this means that no file-marks are written explicitly, leaving the file termination to the system; for input it means that a system file-mark is interpreted as 'end-of-data'. A different behaviour can be selected when calling FZFILE by setting the NEOF parameter associated with the file to 1, 2, or 3 as explained in section 8.4.
Before using FZ, the routines MZEBRA and MZSTOR must have been called. FZ uses the system division of the primary store to hold the control-information about all its files. One bank per file is used, containing the parameters of the file, the statistics of usage of the file, and also the physical record buffer, if the file format is 'exchange'.
Before using a particular file, it should be opened, normally with the Fortran OPEN statement or with the C interface routine CFOPEN (except for files which are read/written by special machine-dependent packages, such as IOPACK on IBM). The ZEBRA handling of this file must be initialized by calling FZFILE.
Machine-dependent details about opening files are given in
chapter
.
The call to FZFILE specifies the properties of the file and the processing direction, for example:
CALL FZFILE (LUN,0,'.') native mode, input only, disk file
CALL FZFILE (LUN,0,'IO') native mode, disk file,
input-output or output-input,
CALL FZFILE (LUN,0,'XO') exchange mode, output only, disk file
CALL FZFILE (LUN,0,'D') exchange mode, input only, disk file
reading with direct-access Fortran
CALL FZFILE (LUN,0,'TL') exchange mode, input only,
tape file to be read via the C Library
Note that the Fortran systems on some Unix machines,
like on Sun or Silicon Graphics,
are not capable of handling fixed-length records in sequential mode,
ie. RECORDTYPE='FIXED' is not available in their Fortran
OPEN statement.
In this case one has to use the direct-access mode,
or the C library mode, of FZ for exchange format files.
If one is debugging a program, it can be useful to set the logging level of FZ for this file to 2 with
CALL FZLOGL (LUN,2)causing FZ to print a log message whenever it is called for this file.
To simply read the next data-structure, one calls for example with:
PARAMETER (NUHMAX=100)
DIMENSION IUHEAD(NUHMAX)
COMMON /QUEST/IQUEST(100)
NUH = NUHMAX
CALL FZIN (LUN, IXDIV, LSUP,JBIAS, '.', NUH,IUHEAD)
IF (IQUEST(1).NE.0) GO TO special
This will read the next d/s into the division indicated by IXDIV,
it will transfer the user-header-vector into IUHEAD*,
NUHMAX words at most, returning in *NUH* its useful size.
It will connect the d/s read into a higher level d/s (if any)
according to the parameters !LSUP and JBIAS,
which have the same significance as with MZLIFT or ZSHUNT.
On normal completion FZIN returns IQUEST(1)=0; a positive value indicates an exception, like Start-of-run or End-of-data; a negative value signals trouble. IQUEST(1) must be tested after every call to FZIN.
Frequently one is interested in processing only a particular kind of data-structure, wanting to rapidly skip any others which might be on the file. To make this possible the data must be organised to contain all the information relevant to selection in the user header vector, because one can ask FZIN to start the d/s by reading the pilot information only, delivering the user header vector to the caller, leaving the bank-material in suspense, waiting for a decision. If the d/s is to be rejected, all the work of bringing it into memory with adjustment of the links can be saved.
To get the user header vector of the next d/s one specifies the S option (Select) in a first call to FZIN; a second call with the A option will transfer the d/s to memory, for example:
C-- Ready to select next d/s
11 NUH = NUHMAX
CALL FZIN (LUN, IXDIV, 0,0, 'S', NUH,IUHEAD)
IF (IQUEST(1).NE.0) GO TO special
IF (not wanted) GO TO 11
C-- Accept pending D/S
CALL FZIN (LUN, IXDIV, LSUP,JBIAS, 'A', 0,0)
IF (IQUEST(1).NE.0) GO TO special
Whilst accepting is done by an explicit call with the A option,
rejection is done implicitly by asking for the next d/s.
Having reached the end of the input file (or having decided to stop input for some other reason), one can get the statistics of file usage printed by
CALL FZENDI (LUN,option)'option' indicates the further action to be taken on this file, such as REWIND and re-start reading from the beginning, or start writing on the file positioned by reading it, or simply terminate.
Beware: for exchange format files one can switch from input to output only after having read an end-of-run or end-of-file.
If one wants to read several different files on the same logical unit number (thereby possibly saving I/O buffers in the system), this can be done as indicated by this sketch, provided all the files have the same characteristics:
OPEN (LUN,FILE=<file 1>,...)
CALL FZFILE (LUN,0,opt)
read first file
CALL FZENDI (LUN,'NX') new file to be connected
OPEN (LUN,FILE=<file 2>,...)
read second file
CALL FZENDI (LUN,'NX')
OPEN (LUN,FILE=<file 3>,...)
read third file
. . . . .
If the files are not of the same kind,
for example if the first file is in native mode
and the second file is in exchange mode,
FZENDI must be told to forget all about the first file,
so that a new file can be started on the same
logical unit number, for example:
OPEN (LUN,FILE=<file 1>,...)
CALL FZFILE (LUN,0,'.') native mode
read first file
CALL FZENDI (LUN,'TX') terminate
OPEN (LUN,FILE=<file 2>,...)
CALL FZFILE (LUN,0,'X') exchange mode
read second file
CALL FZENDI (LUN,'TX')
(This is necessary because the size and character
of the FZ control bank depends on the nature of the file.)
It may be desirable to group the output into 'runs', in which case one would start a new run with, for example:
JRUN = run number
. . .
CALL FZRUN (LUN,JRUN,0,0)
It is possible to store user information into the 'start-of-run'
record via the last two parameters of the call.
There is however the danger,
if this information is essential for the processing of the
data of the run,
that the start-of-run record may get lost due to read errors.
(An end-of-run record can be requested explicitly, but normally this is not necessary, since it is triggered by a new run, or by FZENDO.)
To ouput a d/s from the primary store, supported by the bank at !LHEAD, together with a user header vector in IUHEAD of NUH integer words, one may call:
CALL FZOUT (LUN,0,LHEAD,0,'L',2,NUH,IUHEAD)In this case, the material to be output is defined solely by the entry address !LHEAD into the d/s. Therefore FZOUT has to do a logical walk through the complete d/s by following all the structural links, to mark all the banks belonging to this d/s. A subsequent sequential scan over the memory constructs the table of the memory regions to be output. For a large d/s the time spent on this operation may be non-negligible; it can be saved if the user has organized his data such that the d/s to be output resides in a separate division (or divisions) of which it has exclusive use. In this case one can instruct FZOUT to simply output the complete division IXDIV (or divisions IXDIV1 + IXDIV2), whithout the need for the logical walk, by calling:
[ IXDIV = MZIXCO (IXDIV1,IXDIV2,0,0) ]
CALL FZOUT (LUN,IXDIV,LHEAD,0,'D',2,NUH,IUHEAD)
The entry address !LHEAD is still needed,
no longer to define the data to be written,
but for the receiver to find his way into the d/s read.
Although option 'D' saves the logical walk, FZOUT still has to do the sequential scan of the division[s] to identify the live banks to be written, and the dead banks to be suppressed. If the user knows that there are no dead banks, or that their volume is negligible, he can indicate this to FZOUT with the DI option, causing it to write the complete division[s] as it stands:
CALL FZOUT (LUN,IXDIV,LHEAD,0,'DI',2,NUH,IUHEAD)
Occasionally the d/s to be written out is not described as easily as assumed above, for example one may want to write a data-structure minus some of its sub-structures. In this case (see section 8.21) the user may pre-mark the banks to be output and
CALL FZOUT (LUN,IXDIV,LHEAD,0,'M',2,NUH,IUHEAD)Output of a file must be terminated, to make sure that the last physical record is transfered from the buffer to the file, for example with:
CALL FZENDO (LUN,'I')to re-read the file just written; or with:
CALL FZENDO (LUN,'TX')if the program no longer needs this file.
The recommended procedure is to have a standard job-termination routine, called ZEND, normally called from the Main program. This routine is called also from the ZEBRA recovery system in case of abnormal job termination. Into this routine one should include a
CALL FZENDO (0,'TX')to terminate all pending output files. However, this call pulls in the non-negligible volume of code for the FZOUT complex, and should hence be present only for programs really using FZOUT.
Writing several different files to the same logical unit can be done in complete analogy to the case of reading; in the examples given above one has to add the 'O' option for FZFILE, and one has to change the calls to FZENDI into calls to FZENDO.
To initialize a Zebra file:
Fortran: OPEN (LUN, FILE=name, ...
C: CALL CFOPEN (LUNPTR, ..., name, ...)
IQUEST(1) = LUNPTR
with LUN: logical unit number (Fortran)
or Zebra stream identifier (otherwise),
this must be a unique small positive integer
LREC: record length, in words (ignored if A option)
native file format - maximum logical record length
zero: standard limit: 2440 words
+ve: user defined limit, but < 2500
exchange file format - physical record length
zero: standard length: 900 words
+ve: user defined length
must be a multiple of 30 words
CHOPT: character string,
individual characters select options:
medium: * sequential binary disk file, default
T magnetic tape
D direct access disk file
A alfa: 80 column card-image disk file
C channel mode
M memory mode
usage: F read/write with Fortran, default (except IBM)
Y read/write with special machine specific code
(IBM has IOPACK, NORD has MAGTAP)
L read/write with interface to the C Library
K read/write with user supplied code
file format: native file format is default
X exchange file format
modes M, C, A, D, L, K all imply 'X'
data format: native is default for native file format
exchange is default for exchange file format
N native data format
direction: default direction is 'input only'
I input enabled
O output enabled
IO input/output enabled
various: S separate d/ss
U unpacked d/ss, only with modes M or C
R initial rewind
Q quiet, set logging level to -2
P permissive, enable error return,
see 'Status returned' just below
NEOF: handling of system EoF
for output:
0 write no file-marks at all
1 write file-mark only for End-of-File
2 write file-mark only for End-of-Data
3 write file-marks both for EoF and EoD
for input:
1 or 3 one file-mark signals 'end-of-file',
otherwise: file-mark signals 'end-of-data'
IQUEST(1) = 0 all is well
1 file has already been initialized with FZFILE
2 LUN is invalid
3 requested format is not available on the particular
Zebra library (either because of the installation
options taken, or because the code is not ready
for the particular machine)
4 the file pointer is zero for modes L or K
The error returns are enabled only if the P option is selected, otherwise control goes to ZFATAL. If the P option is selected, the status must be checked, because the file will not be initialized if an error exit is taken.
M C A D T * K L Y
channel C - + combination useful
alfa A - - - combination not allowed
direct D - + - i option implied
tape T - - - d option default
neither * - - - - - ? depends on the user's
implementation
user K - - - ? ? +
lib C L - - - + + + -
special Y - - - - + + - -
Fortran F - - i d d d - - -
exchange X i i i i + + i i i
native N + + + + + d + + +
separate S i + + + + + + + +
unpacked U + + - - - - - - -
M C A D T * K L Y
FZFILE initializes only the Zebra controls for this file; the opening of the file has to be done by the user in his calling program, according to the needs of his machine and operating system.
if the file is to be handled with Fortran READ/WRITE one needs an
OPEN statement; one will find some hints in chapter
.
for modes L or K the file should be opened by calling CFOPEN (see the specifications at the end of this paragraph) and the 'file pointer' returned by CFOPEN must be passed on to FZFILE via IQUEST(1).
this is the Zebra stream identifier which will be used in all subsequent calls for this file; if the file is to be handled with Fortran this is at the same time the logical unit number.
for exchange file format it is important to choose a good value for
all one's files, and then stick to it.
One has to compromise between conflicting things:
on tapes one would like to make this large,
but this costs memory for the Zebra buffer,
multiplied by the number of files concurrently open,
and it wastes disk space for end-of-run records which occupy
a whole physical record.
Some numbers can be found in chapter
.
The physical record size for the exchange file format needs to be specified both to Zebra with FZFILE and to the system with the OPEN statement and maybe even with some JCL, in which case the user may need to know this: the block size is specified to Zebra in words, the default is 900 words. These words correspond to words in the Zebra dynamic store, such that a bank of 900 words could just fill one block. Except for 32-bit machines, the number of bits written to the file for each word depends on the data format: for the exchange data format each word generates 32 bits, for the native data format a full machine word is transferred. To the system the block size has to be specified either in bytes or in native words. For example, on the CRAY (64-bit words) the record-size of a standard block will have to be given as 7200 bytes (900 machine words) for the native data format, but as 3600 bytes (450 machine words) for the exchange data format.
for the media 'memory' and 'channel' the Exchange File Format is implied, and this cannot be changed. The Native Data Format can be selected by giving the N option. Instructions on the use of these media is given in separate sections near the end of this chapter.
Alfa mode should only be used to transmit data over a network connection which cannot handle binary file transfers. The character representation (ASCII, EBCDIC, etc) used is that of the originating machine; the translation is expected to happen in the network station. Alfa mode must not be used for writing magnetic tapes, it is at least a factor of ten slower than binary.
this serves two different purposes: on some machines Fortran is not capable of handling fixed-length records without system control words in sequential mode, only in direct-access mode, but this only for disk files. A side-effect advantage is better error recovery from lost records on files which have been moved from tape to disk. No timing studies have yet been made to check whether direct access is slower than sequential acccess.
The other purpose is random access to the d/ss on the file, this is described in section 8.18 ``Usage for random access''. Selecting D only gives the possibility, but no obligation for random access: for input Zebra will read the file sequentially except at moments when the user interfers with calls to FZINXT; for output Zebra operates strictly sequentially.
at the moment no distinction is made internally in Zebra between disk and tape files (exception: NORD), but it may turn out that the C interface will have to have a separate branch for tape files on some machines.
read/write with Fortran, option F, is the default if none of Y, L, K are specified. Exception IBM: up to including Zebra version 3.66 the default for sequental files is Y, that is handling with IOPACK; from version 3.67 onwards the default will be F. Most people give now (version 3.65) option F, those who really want IOPACK should change their programs to request Y to be insensitive to the transition to 3.67. The only other machine sensitive to Y is presently the NORD: magnetic tapes must be written through the MAGTAP utility, on this machine TX implies Y.
read/write is with the routines CFGET/CFPUT which are part of the interface to the C Library for handling files with fixed-length records. This mode must be used for exchange file format tape files on those Unix machines where Fortran does not provide the parameter RECORDTYPE='FIXED' (or equivalent) in the OPEN statement, like the Sun, or SGI, or DecStation. On the same machines one might use this also for disk files as an alternative to option D; no studies have yet been made to see which is faster. L can be combined with D for random access using the C interface.
this is a hook to enable a user to write his own handling of physical
records in case that none of the modes provided are satisfactory.
Chapter
gives some hints of how to do this.
default is 'native' if none of A, C, D, K, L, M is given, which necessarily operate with exchange file format.
for native file format this is 'native'; for exchange file format data format 'exchange' is assumed by default, but native data format can be requested by giving the N option. In this case LREC native words are written for each physical record, and no data translation, packing, or byte inversion, is done.
the option IO is needed in two separate cases: - if the program first writes a new file which it then reads; - if the program positions an existing file by reading for further output. In this case the input or output mode of the file is defined by the first I/O action on the file; it can be changed at the end of the first phase only with FZENDI from input to output, or with FZENDO the other way round.
for the exchange file format, FZOUT normally places the start of a given d/s just after the end of the previous structure in the same physical record, to economize file space. This may be inconvenient if the file is later to be handled by means other than calling FZIN: giving the S option will force each d/s to start on a new physical record. For the medium 'memory' the S option is implied.
only for media 'memory' and 'channel': When handling the physical records for the Data Format 'exchange' it may be more convenient for the user to do himself the unpacking (FZIN) or packing (FZOUT) operation needed, because in this case he has immediate access to the control information in the records. (Note: on the VAX 'packing/unpacking' is in fact byte inversion.) The U option allows this: if given, FZOUT delivers the data non-packed, and FZIN expects data which have already been unpacked by the user.
if the initial REWIND is selected the file has to be OPENed before calling FZFILE.
giving this option suppresses message printing for this file.
this parameter controls for output the explicit writing of system file-marks; for input it controls the interpretation of a system file-mark, which can mean either end-of-file or end-of-data (two file-marks in succession always act as end-of-data). On most machines the default value is NEOF=0, meaning single-file files only. This can be over-ridden by giving the 1, 2, or 3 option if multi-file files must be handled. See also section 8.2 for more explanations.
Since this is a new KERNLIB routine not yet documented we print this here.
CALL CFOPEN (LUNPTR*,MEDIUM,NWREC,IOMODE,NBUF,NAME,ISTAT*)
LUNPTR* is the 'file pointer' returned by the C library
routine 'fopen', CFOPEN returns it to the caller who
must hand it on to FZFILE via IQUEST(1).
This will be zero if the open fails.
MEDIUM = 0 for disk file, normal
1 tape file, normal
2 disk file, user coded I/O
3 tape file, user coded I/O
NWREC the number of machine words per physical record, this
is used to calculate the buffer size if NBUF not zero.
MODE the 'type' parameter of 'fopen', of type CHARACTER:
r open for reading
w truncate or create for writing
a append: open for writing at end of file, or
create for writing
r+ open for update (reading and writing)
w+ truncate or create for update
a+ append; open or create for update at EOF
NBUF not currently used, always give zero
NAME the name of the file, of Fortran type CHARACTER.
ISTAT* status returned, zero if all is well,
otherwise a system error code.
To change the logging level for a file:
with LUN: logical unit number
LOGLEV: logging level
-3: suppress all messages
-2: print error messages only
0: normal mode
1: normal mode + details of conversion problems
2: print to monitor CALLs to FZ
3: print short diagnostic dumps to debug
4: print full diagnostic dumps to debug
user-written output routines
A logging level is attached to each FZ file;
by default this is the general system-wide default logging level
set by MZEBRA.
By giving the Q (quiet) option with FZFILE the level is set to -2.
It can be changed later at any time by calling FZLOGL.
To connect the memory area for use by a 'file':
with LUN: stream number
MBUF: user memory of NWBUF machine words
This must be called after the 'file' has been initialized
with FZFILE, and before it is used with FZIN or FZOUT.
Different memory areas may be connected by recalling this
routine any number of times;
see section 8.19 for explanations.
To connect a particular user routine to be called by FZIN or FZOUT for this 'file':
EXTERNAL UserSR
with LUN: stream number
UserSR: name of the user routine
dummy: the third parameter is not at the moment used,
but it must be present in the call
This must be called after the 'file' has been initialized with FZFILE, and before it is used with FZIN or FZOUT. Different user routines may be connected by recalling this routine any number of times; see section 8.20 for explanations.
with LUN: logical unit number
ALIMIT: floating point number giving, in Mega-words, the
limit of the data to be written to one reel of tape;
if zero: increase the limit by one more reel of tape
if -ve: unlimited (as intialized by FZFILE)
Example: CALL FZLIMI (21, 12.75) sets the file-size
to 12.75 Mwords for unit 21
Re-calling later with:
CALL FZLIMI (21, 0.) sets the file-size to be the current
data-volume plus 12.75 Mwords
The reason for this facility is the fact that detecting 'end-of-tape' is a problem which cannot be solved satisfactorily in full generality. To help the user who wants control over tape reel switching, ZEBRA counts the total number of words written, and checks after every data-structure written out (but not for start-of-run, end-of-run, end-of-file) whether the limit has been reached. If so, it returns the 'pseudo end-of-tape' condition (cf. FZOUT) for every data-structure output until an increase of the limit to include one more reel of tape is requested with ALIMIT=0. Thus the user can switch tape, call FZLIMI (LUN,0.), and continue to write another tape, again waiting for the 'end-of-tape' signal.
The routines FZODAT and FZIDAT store and retrieve the direct-acces table onto and from a file.
See section refsec:random-access ``Usage for random access'' for explanations.
To store the Direct-access Table bank:
with LUN: logical unit number
IXDIV: index of division or store having the DaT bank
!LDAT: address of the DaT bank, if non-zero
If LDAT is zero the DaT 'forward reference' record is written
to be updated later to contain the address of the DaT;
this is useful only as the very first record on the file.
If LDAT is non-zero the DaT bank is written and the forward reference record is updated if possible.
To retrieve the DaT bank:
CALL FZIDAT (LUN,IXDIV,!LSUP,JBIAS)
with LUN: logical unit number
IXDIV: index of the division to receive the DaT bank
The d/s read is linked into a pre-existing d/s as directed by
!LSUP and JBIAS, which have the same significance as for MZLIFT:
!LSUP: if JBIAS < 1: !LSUP is the supporting bank,
JBIAS: connection to link LQ(!LSUP-JBIAS)
IQUEST(13) returns the entry adr to the d/s
if JBIAS = 1: *!LSUP is the supporting link,
connection to *!LSUP* (top-level d/s)
!LSUP* returns the entry adr to the d/s
if JBIAS = 2: stand-alone d/s, no connection
!LSUP* returns the entry adr to the d/s
Status return: IQUEST(1) = 0 success
-1 DaT not found
-2 file is empty
To write a start-of-run or end-of-run record:
CALL FZRUN (LUN,NRUN,NUH,IUHEAD)
with LUN: logical unit number
NRUN: run number,
if +ve: new run, run number literal
zero: new run, increase current run number by one
-ve: end-of-run record
NUH: length of the user information, may be zero, < 401
IUHEAD: NUH words of user information, integers only
Write / Error status returned: as for FZOUT
A start-of-run record will be preceded by an end-of-run signal if the last action on the file was the writing of a data-structure.
The request to write an end-of-run will be by-passed if the last action on the file was the writing of EoR or EoF.
For the media 'memory' or 'channel' the writing of end-of-run, if needed, should be requested by an explicit call to FZRUN with NRUN negative, since an implicit generation will not get through to the user.
To write one data-structure:
CALL FZOUT (LUN,IXDIV,!LENTRY,IEVENT,options,IOCH,NUH,IUHEAD)
with LUN: logical unit number
IXDIV: index of division(s)
may be zero [or IXSTOR] if the D option is not selected
may be a compound index if the D option is selected
!LENTRY: entry address of the d/s
may be zero if the Z option is selected
IEVENT: start-of-event flag
= 0 for event continued
1 for new event
the following values are for use by FZRUN and FZENDO
and are illegal for calls by the user:
13 flush the buffer 15 write end-of-file
(X mode only) 16 write end-of-data
14 write end-of-run -1 write start-of-run
options: character string,
individual characters select options:
select d/s: mutually exclusive options
by default the d/s supported by the bank at
LENTRY is written out (link 0 not followed)
L write the d/s supported by the linear structure
at LENTRY (link 0 followed)
M write the banks marked by the user
see section~\re{sec:FZmarking} for details
D write complete division(s)
default: dead banks are squeezed out
(slower but maybe more economic than DI)
DI immediate dump of division(s),
dead banks, if any, are also written out
S write the single bank at LENTRY
Z zero banks, ie. empty d/s, header only
others: N no links, ie. linkless handling (cf 'Principles')
default: links are significant
P permit error returns
default: exit to ZTELL
IOCH: the I/O characteristic for the user header vector; as
for a bank this may be either 'immediate' if the whole
vector is of the same type, or it may be composite.
- immediate: IOCH = 1 all bits
2 all integers
3 all floating
4 all double precision
5 all Hollerith
7 self-describing
- composite: set up with
CALL MZIOCH (IOCH,NW,'format') where
IOCH is now a vector of NW words at most
NUH: number of words in the user header vector, < 401,
may be zero, in which case IOCH is not used
IUHEAD: the user header vector
IQUEST(1) = 0 normal completion
+1 'pseudo end-of-tape' condition (cf. FZLIMI)
-1 first attempt to write after end-of-data
-2 error return
IQUEST(5) = word 1 of the direct access adr of the d/s just written
IQUEST(6) = word 2
IQUEST(9) = # of useful machine words ready in the user's memory
only for medium 'memory'
IQUEST(11) = NWBK, number of words of bank material
IQUEST(12) = NWTB, size of the relocation table
IQUEST(13) = number of pilot records written so far
IQUEST(14) = number of Mwords written so far
IQUEST(15) = number of words (up to 1 M) written so far
ie. the total is IQUEST(15) + IQUEST(14)*10**6
IQUEST(16) = number of logical records written so far
IQUEST(17) = number of physical records written (exchange mode only)
Further information about the file can be obtained
by calling FZINFO, see section
Normally FZOUT does not return to the caller for (program) errors, but exits to ZTELL. Exceptionally, error returns may be enabled by the P option.
IQUEST(1) = -2
IQUEST(2) = 11: !LENTRY invalid or pointing to a dead bank
= 12: bank chaining clobbered
= 13: not enough space for the relocation table
= 14: medium 'memory': user's memory too small
If the P option is not taken exit is with
CALL ZTELL (i,1) with
i=11,12,13, 14.
If the actual write operation fails, for example because the disk is full, control is handed to ZTELL (which may return) with:
CALL ZTELL (19,0)
with
IQUEST(1) = 19
IQUEST(2) = who is in trouble ?
1 - Fortran sequential
2 - Fortran direct access
21 - L mode sequential
22 - L mode direct-access
41 - Alfa mode
IQUEST(3) = IOSTAT error code return by the 'write'
IQUEST(4) = LUN (Zebra stream identifier)
IQUEST(5) = C file descriptor if writing in L mode
To read the next data-structure one calls FZIN. The return code in IQUEST(1) will tell the caller whether the READ operation was free of error, and whether the object read was a d/s, a start-of-run, an end-of-run, or an end-of-file signal. FZIN may be asked to skip to and then read the next start-of-event d/s or the next start-of-run record.
In the simplest case (opt = '.' or blank) FZIN will read the next data-structure into the division indicated by the parameter IXDIV, at the same time delivering the user-header vector to IUHEAD.
The selective read has been provided to rapidly skip unwanted d/ss without expansion into memory and without relocation of the links: calling FZIN with opt='S' causes reading of the next pilot information only, returning to the user the header-vector (and the text-vector, if any) for taking a decision to read or to skip the 'pending d/s'. Skipping is done by asking for the next d/s; accepting is done by calling FZIN with opt='A'. Note that every call to FZIN has to be checked for the success of the operation by testing on IQUEST(1).
In the cases described so far the complete data-structure is read and is deposited into one particular division. It is however possible to steer individual data segments of the d/s into particular divisions, or to cause them to be ignored. This can be done by using the options T and D, as described separately in the next paragraph.
FZIN returns the read status, either normal or error, in IQUEST; be careful about the meaning of status codes 4 and 5: '4' means EoF seen on a file which can be a multi-file file; '5' means 'End-of-Data'. Reading a file which cannot be multi-file can never produce status 4, the end will always be indicated by status 5.
IQUEST(1) = -8 . . .
-7 for 3 consecutive errors
-6 for 2 consecutive errors
-5 read error
-4 bad constructs, maybe not a file written by FZOUT
-3 bad data
-2 not enough space to read the d/s and its table
-1 faulty call: T,D,A option given, but no pending d/s
IQUEST(2) = number of logical records read so far
IQUEST(3) = number of physical records read so far (exchange mode)
Details about the error occurred are stored in IQUEST(11) ff.
as described in the diagnostics chapter.
To read the next data-structure:
CALL FZIN (LUN,IXDIV,!LSUP,JBIAS,opt,*NUH*,IUHEAD*)
with LUN: logical unit number
IXDIV: index of the default division to receive the d/s
zero: division 2 of the primary store
(ignored if S option given)
The d/s read is linked into a pre-existing d/s as directed by
!LSUP and JBIAS, which have the same meaning as for MZLIFT:
!LSUP: if JBIAS < 1: !LSUP is the supporting bank,
JBIAS: connection to link LQ(!LSUP-JBIAS)
IQUEST(13) returns the entry adr to the d/s
if JBIAS = 1: *!LSUP is the supporting link,
connection to *!LSUP* (top-level d/s)
!LSUP* returns the entry adr to the d/s
if JBIAS = 2: stand-alone d/s, no connection
!LSUP* returns the entry adr to the d/s
(ignored if options S or T selected)
options: character string,
individual characters select options:
event: default: go for the next d/s
E skip to and read the next start-of-event d/s
R skip to and read the next start-of-run record
2 skip to and read the next end-of-run record
3 skip to and read the next Zebra end-of-file
4 skip to and read the next machine end-of-file
any skip operation stops also on machine EoF;
option E or 2 skipping stop also on Zebra EoF,
option R skipping does not stop on Zebra EoF.
select: default: read the next header and its d/s
(may mean: skip pending d/s or current event)
S select, read next header and text-vector only
(may mean: skip pending d/s or current event)
(LSUP and JBIAS not used)
T table, load the segment table for the current
d/s into /FZCSEG/
(LSUP, JBIAS, NUH, and IUHEAD not used)
A accept, read the pending d/s
(NUH and IUHEAD not used)
D divisional accept, read the pending d/s under
control from /FZCSEG/
(NUH and IUHEAD not used)
F accept also DaT records, which are normally ignored;
see section~\re{sec:random-access}
*NUH*: size of the user header vector
on input: maximum size of IUHEAD
on output: useful size stored in IUHEAD
(ignored if options T, A, or D selected)
IUHEAD*: user header vector
(ignored if options T, A, or D selected)
IQUEST(1) = -ve error, see separate list
0 normal completion
1 start-of-run record
2 end-of-run record
3 Zebra end-of-file
4 system end-of-file, continuation possible
5 system end-of-data, continuation not possible
6 first attempt to read beyond EoD
IQUEST(2) = number of logical records read so far
IQUEST(3) = number of physical records read so far (exchange mode)
IQUEST(5) = word 1 of the direct access adr of the d/s read
IQUEST(6) = word 2 (exchange mode only)
IQUEST(11) if IQUEST(1)=0: = 1 or 0 for yes/no start new event
if IQUEST(1)=1: = run number for start/end of run
IQUEST(12) = processing bits of pilot, normally zero
IQUEST(13) = LENTRY, the entry address into the data structure
zero means: empty d/s
(not yet a valid address if S option return)
IQUEST(14) = NWBK, the number of words occupied by the d/s in memory
zero means: empty d/s
IQUEST(20) = NWIOCH, size of the I/O characteristic
IQUEST(21) = NWIOCH words of I/O characteristic
... for the user header vector
Further information about the file can be obtained
by calling FZINFO.
It may be convenient to represent an event by several separate d/ss on the file. This permits in an easy way to selectively read only a particular part of every event. This method has one draw-back: if there are reference links pointing from one part to an other part of the event, where both parts are residing simultaneously in memory, and if the two parts are written out by two separate calls to FZOUT, the cross links will be lost on read-back.
To amend for this, the following scheme has been implemented: when a data-structure is transferred from several divisions to the FZ file, the data are 'segmented', i.e. a table is included into the pilot information, indicating the divisions from which the different data segments originated, together with their sizes. On read-back the user can either skip particular data-segments or he can direct data-segments into particular divisions individually.
To do so, three calls to FZIN are necessary:
COMMON /FZCSEG/ NQSEG,IQSEGH(2,20),IQSEGD(22) where:
NQSEG = number of segments contained in the pending d/s
if NQSEG = 0: d/s is not segmented
IQSEGH(1,J) = char 1-4
IQSEGH(2,J) = 5-8 of the Hollerith name of the division
from which segment J derives
IQSEGD(J) index of division selected for segment J
Note: IQSEGD(21+22) are working elements of the system and,
like NQSEG, must not be modified by the user.
To direct segment J into a given division one should set
IQSEGD(J) to the index of that division
(or merely to the division number;
the store is selected by the parameter IXDIV to FZIN).
To cause this segment to be ignored IQSEGD(J) = -1 should be set.
IQSEGD(J) containing zero directs this segment into the
'default' division selected by the parameter IXDIV to FZIN.
(The vector IQSEGD is preset to zero by FZIN.)
Since /FZCSEG/ is used for segment handling with all streams, both input and output, there must not occur some other call to FZ for any stream between the second and the third call. Also, having called with the T option does not oblige the user to follow it by a call with the D option; he may call with the A or even the S option, in which cases the segment table is simply ignored.
To reset the read point:
with LUN: logical unit number or Zebra stream ID
the 2 word d/s address of the next d/s to be read,
MDSA1: word 1: physical record number
MDSA2: 2: off-set within the record,
if this is zero the first d/s
starting in the record will be used
See section 8.18 for context information.
FZCOPY will copy a data-structure from the input to the output 'file' without expansion into memory and without translating the data representation, thereby saving the time which would otherwise be spent on these operations.
The file-format and the data-format of the input or the output file may be 'exchange' or 'native', but the following restrictions are imposed:
CALL FZCOPY (LUNIN,LUNOUT,IEVENT,options,IOCH,NUH,IUHEAD)
with LUNIN: logical unit number of the input file
LUNOUT: logical unit number of the output file
IEVENT: start-of-event flag
= 0 for event continued
1 for new event
options: character string,
individual characters select options:
I/O descr.: by default the I/O descriptor from the input
file is used for IUHEAD
I use the new I/O descriptor given in IOCH for
the user header vector
P special 'permit' option not normally given
IOCH: the I/O characteristic for the user header vector;
this is ignored if the I option is not given; as
for a bank this may be either 'immediate' if the whole
vector is of the same type, or it may be composite.
- immediate: IOCH = 1 all bits
2 all integers
3 all floating
4 all double precision
5 all Hollerith
7 self-describing
- composite: set up with
CALL MZIOCH (IOCH,NW,'format') where
IOCH is now a vector of NW words at most
NUH: number of words in the user header vector, < 401,
may be zero, in which case IOCH is not used
IUHEAD: the user header vector
IQUEST(1) = 0 normal completion
+1 'pseudo end-of-tape' condition (cf. FZLIMI)
< 0 input error return, see below
> 1 output error return, see below
If normal completion:
IQUEST(5) = word 1 of the direct access adr of the d/s just written
IQUEST(6) = word 2
IQUEST(9) = # of useful machine words ready in the user's memory
only for medium 'memory'
IQUEST(11) = NWBK, number of words of bank material
IQUEST(12) = NWTB, size of the relocation table
IQUEST(13) = number of pilot records written so far
IQUEST(14) = number of Mwords written so far
IQUEST(15) = number of words (up to 1 M) written so far
ie. the total is IQUEST(15) + IQUEST(14)*10**6
careful: if this compound is bigger than 2G it
needs more than 32 bits to hold it
IQUEST(16) = number of logical records written so far
IQUEST(17) = number of physical records written (exchange mode only)
IQUEST(1) = -8 . . .
-7 for 3 consecutive errors
-6 for 2 consecutive errors
-5 read error
-4 bad constructs, maybe not a file written by FZCOPY
-3 bad data
-2 not enough space to read the d/s and its table
-1 faulty call: no pending d/s, or: Alfa mode,
or: input/output have differen data format,
or: both input/output in channel mode,
or: native input record length too long;
(code -1 causes ZFATAL unless P option given)
IQUEST(2) = number of logical records read so far
IQUEST(3) = number of physical records read so far (exchange mode)
Details about the error occurred are stored in IQUEST(11) ff.
as described in the diagnostics chapter for FZIN.
Normally FZCOPY does not return to the caller for (program) errors, but exits to ZTELL or to ZFATAL. Exceptionally, some such error returns may be enabled by giving the P option in the call.
IQUEST(1) = +2 IQUEST(2) = 14: medium 'memory': user's memory too small
To terminate one or all output files:
with LUN: logical unit number
if zero: all FZ output files
options: character string,
individual characters select options:
main: T terminate:
- ensure end-of-data (unless done)
- print file statistics (unless done)
- drop FZ control-bank
N continue output to a new file to be connected
by the user to LUN after this call:
- ensure end-of-data (unless done)
- print file statistics (unless done)
C continue on the next file of the same stream:
- ensure end-of-file (unless done)
- print file statistics (unless done)
I switch to input, to read the file just written:
- ensure end-of-data (unless done)
- print file statistics (unless done)
- remove the 'output' permission
- rewind and change status to 'input'
O output again, to over-write the file just written:
- ensure end-of-data (unless done)
- print file statistics (unless done)
- rewind
none print file statistics only
over-ruling: T -> N -> C -> I -> O
variants: R execute REWIND function, only with T or N
U execute UNLOAD function, only with T or N (no action yet)
X execute CLOSE function, only with T or N
O keep the 'output' permission, only with I
Q quiet, suppress printing of file statistics
0,1,2 or 3 only with I: change the NEOF parameter
of FZFILE for reading
To be sure that all output files are closed correctly,
even on abnormal job termination,
the user should call from ZEND: CALL FZENDO (0, 'TX')
If necessary this is taken as a final close-down signal to be passed on to special I/O packages on some machines (such as IOPACK on IBM).
To terminate one or all input files:
with LUN: logical unit number
if zero: all FZ input files
options: character string,
individual characters select options:
main: T terminate:
- print file statistics (unless done)
- drop FZ control-bank
N continue input from a new file to be connected
by the user to LUN after this call:
- print file statistics (unless done)
C continue on the next file of the same stream:
- print file statistics (unless done)
- step over the system EOF as required on some machines
I input again, to re-read the same file:
- print file statistics (unless done)
- rewind
O switch to output, to permit writing on a file
positioned by reading:
- print file statistics (unless done)
- change status to 'output'
none print file statistics only
over-ruling: T -> N -> C -> I -> O
variants: R execute REWIND function, only with T or N
U execute UNLOAD function, only with T or N (no action yet)
X execute CLOSE function, only with T or N
Q quiet, suppress printing of file statistics
0,1,2 or 3 only with O: change the NEOF parameter
of FZFILE for writing
Both FZENDI and FZENDO also load the file statistics into the Common /FZSTAT/ just like the routine FZINFO, to provide the final statistics, which are not yet available just before FZENDO, and maybe no longer available just after FZENDO.
For random access the location of a d/s within its file is specified by its 'data-structure address', the DsA, consisting of 2 words:
JDSAP = (JDSA1-1) * LREC + JDSA2where LREC is the number of words in each physical record, as specified to FZFILE.
For every successful call to FZOUT or FZIN Zebra returns the DsA of the latest d/s in IQUEST(5) and IQUEST(6), provided the file-format is 'exchange' and even for a tape file. To prepare a file for reading it randomly the user would construct a table, the 'direct access table', or DaT, which contains the relevant properties of the d/ss on the file plus their DsA's. This can be done either by an extra read pass over the file to collect the data, or more economically at the time when the file is created. In the latter case the DaT can be written to the file as the last d/s before end-of-file, and is then ready for use for any future reading of the file.
When reading a file initialized with mode D given to FZFILE, repeated calls to FZIN will read the data sequentially. To obtain a particular data-structure one has to call FZINXT specifying the DsA of the wanted d/s; this will reset the 'current read point' for the file and the next call to FZIN will then deliver the wanted d/s.
Do this:
Do this:
1) call FZFILE with CHOPT = 'D' or 'LD' to permit random access.
2) retrieve the direct-access table:
CALL FZIDAT (LUN,IXDIV,LDAT,1)
IF (IQUEST(1).NE.0) GO TO trouble
This will try to find the Direct access Table:
If acccess to the table was not immediate, FZIDAT will try to update the forward reference record, if it exists, to ease future use. It can do this only if the file hase been opened for read/write, and this has to be signalled by giving CHOPT='DIO' to FZFILE.
Keeping the DaT on the file to be read is obviously the simplest way to proceed, but other organisations are possible. For example, if one has a large disk with many files as the data-base for the events of an experiment, one may want to have a separate global DaT for all the events on the disk, with a structure reflecting the files and holding their names.
Remember: if one needs a data-base with key-word access or update capability one should use the RZ package of Zebra.
In this mode all the records assembled by FZOUT to represent one particular data-structure are placed one after the other contiguously into an area of memory belonging to the user (rather than being written to a file). One is then free to move the data around, normally from a machine which has no I/O facilities to a machine which has, as in emulator farms. They may there be written to tape. Eventually the data will be brought back to be read with FZIN, either directly from a file, or again from user memory. To 'read' a d/s from user memory, FZIN expects all the records representing the d/s to be present in the memory area.
FZ handles the medium 'memory' only with the file format 'exchange', ie. with logical 'records' blocked onto fixed-length physical 'records'. The data format can be 'exchange' or 'native'.
The details of this format are found in chapter
.
To use this mode the following is necessary:
CALL FZMEMO (LUN,MBUF,NWBUF)
indicating to FZ the where-abouts and the size of one's memory region for stream LUN. NWBUF gives the size in terms of machine words, it must be large enough to hold the largest d/s to be handled; see the memory-size considerations further down.
In the case of output one calls FZOUT (also FZRUN),
on return one will find the physical records representing
the d/s in one's memory.
FZOUT starts this string of records with a 'steering block',
ie. a physical record with 8 control words
(see chapter
for details),
placed at the start of the user's memory;
the remaining data are placed as 'fast blocks', if any.
The last block is normally used only partially,
the unused part is marked out with a padding record,
ie. a logical record of type 5,
of which only the record length and the type code are significant,
the data contents are irrelevant.
FZOUT returns in IQUEST(9) the number of useful machine words stored into the memory. It includes the (normally) 2 control words of the padding record, but not its data words. If one needs it, one can compute the number of physical records as 1 + (IQUEST(9)-1)/LENREC where LENREC is the physical record size in machine words. On machines with a word-size greater than 32 bits this needs a little care, as explained in the note about LREC in section 8.4 for FZFILE, and also below.
To obtain a start-of-run record one can call FZRUN to get it into the memory, the useful size is again found in IQUEST(9). To get an end-of-run record one has to call FZRUN explicitly; one may call FZENDO to have the file statistic printed, but this will not put anything into the user's memory.
To read back a d/s originally produced by FZOUT and then shipped around, one has to store it in the user memory, connected with FZMEMO, and call FZIN. This will transfer the data to the dynamic store, converted if the Exchange Data Format is in use, and relocate the links. The user's memory is left intact. IQUEST(1) returns the read status and must be checked after every call to FZIN.
Using the information of chapter
,
one obtains the lay-out of the d/s in the memory
produced by FZOUT as shown on the next page.
NWPHR is the physical record length as defined by the call
to FZFILE, it is 900 by default.
If one is using the native data format (or if one is running on a machine where the native format is identical to the exchange format, ie. on IEEE machines such as Apollo, Alliant, Motorola) this lay-out applies literally, the numbers are usable directly, and FZOUT will return IQUEST(9)=NWUSE.
However, if one is using the exchange data format the data are converted to their exchange representation, and they are also 'packed'. For example, on the Cray two words are packed into one machine word, and FZOUT will return IQUEST(9)=(NWUSE+1)/2. On a VAX 'packing' means byte inversion, so also in this case the data are not usable directly.
Use of the U option: the situation can arise that one needs the exchange format, because communication is between different machines, but that one also needs access to the control information at the beginning of the data. One could gain this access by local unpacking, but this is messy. It is more elegant to take charge of the packing oneself, and instruct FZOUT to deliver the data non-packed (by selecting the U option in FZFILE). In this case the lay-out shown on the next page applies again literally, or almost: the data are delivered as one word per each machine word (and on the VAX the bytes are not yet inverted), but they are converted to the exchange representation, 32 bits right justified with zero-fill. This conversion affects negative integers, floating point numbers, Hollerith, but not positive integers and bit patterns. Since the control information has been deliberately chosen to be of this invariant kind, it remains usable. FZOUT returns again IQUEST(9)=NWUSE. When shipping the data one has to execute the 'packing' operation applicable on the given machine such that they arrive in the correct form at the destination.
From these considerations one easily derives the size requirement on the memory to be connected with FZMEMO. On the Cray for example, to handle data-strutures of not more than 80000 words (including the control and context information) one needs a memory region of 40000 words if one operates in normal exchange mode, but 80000 words for native mode or if the U option is selected.
word
1-4 steering block stamp
= hex 0123CDEF 80708070 4321ABCD 80618061
5 bits 1->24: NWPHR, the physical record length
30: set if start-of-run in this block
31: set if end-of-run
32: set if emergency stop block
6 zero (physical record counter)
7 NWTOLR = 8
8 NFAST, the number of fast blocks to follow
9 NWLR, logical record length
10 LRTYP = 2 or 3, the record type
11 floating point 12345.0 as check word
12 Zebra version number, integer = 10000. * QVERSIO
13 zero
14 zero
15 NWTX=0, number of words in the text-vector
16 NWSEG, number of words in the segment table
17 NWTAB, number of words in the relocation table
18 NWBK, number of words of bank material
19 LENTRY, entry address into the d/s
20 NWUHIO = NWUH + NWIO, number of words in the user header
vector plus its I/O characteristic, zero if no header
NWIO words of the I/O characteristic for the u. h. vector
NWUH words of the user header vector
NWSEG words of the segment table
NWTX words of the text-vector
NWTAB words of the relocation table
NWBK words of bank material
word
NT is the last word of the d/s
NT+1 NWPAD, record length of the padding record
NT+2 5, record type
NWPAD-1 untouched padding words
The following numbers are calculated:
log. record length NWLR = 10+NWIO+NWUH+NWSEG+NWTX+NWTAB+NWBK
incl. log. c/words NWDS = 2 + NWLR
incl. phys. c/words NT = 8 + NWDS
# of fast blocks NFAST = (NT-1) / NWPHR
total # of words NALL = NWPHR * (NFAST+1)
padding length NWPAD = NALL - NT - 1 (can be 0 or -1)
# of useful words NWUSE = NT + 1 + MIN(NWPAD,1)
In this mode the records assembled by FZOUT are channelled through a user routine one-by-one to their destination; (rather than being written to a file or to memory). Similiarly for FZIN the data are acquired not from tape or disk directly, but through the same user routine. The name of this routine is not decided by Zebra.
Channelled mode operates with file format 'exchange', ie. the data are collected into fixed-length records, and each record is handed to the user routine when complete (for FZOUT, the inverse for FZIN).
The details of this format are found in chapter
.
The data format can be 'exchange' or 'native'.
To use this mode the following is necessary:
EXTERNAL UserSR
CALL FZHOOK (LUN, UserSR, 0)
passing to FZ the address of the user routine; the third argument is not used for the time being.
The specifications for the user routine are:
box setgray fillSUBROUTINE UserSR (IBUF,IOWAY)
with IBUF: the data of the 'record'
IOWAY: the I/O direction:
= 0 if called from FZIN for input
1 if called from FZOUT for output
other values are reserved to the user
IQUEST
(1): on entry: LUN, the stream ID
on exit: status flag
(2): on entry: the number of machine words for transmission
on exit: number of machine words delivered
(3): kind of record
(4): = zero if sequential access
= ordinal number of the record wanted if direct-access
(5): 0 / 1 for disk / tape
(6): if FZIN: number of words per physical record
In this case IOWAY is zero on entry, and IQUEST(2) specifies the maximum number of words which the buffer IBUF can accept without the program being destroyed.
IQUEST(3) indicates the kind of record expected, if this is zero a normal continuation record is wanted; if it is =1 then FZIN is expecting a physical record starting a new d/s; the user routine is supposed to discard trailing records of the previous d/s if this has been de-selected. Note that selective reading with FZIN in channel mode is not yet fully tuned.
UserSR is supposed to fill the buffer IBUF, store into IQUEST(2) the number of words received, and return zero in IQUEST(1). Exeptions may be signalled by setting
IQUEST(1) = -1 end of data
> 0 error, the value of this status code will be
displayed to the caller of FZIN in IQUEST(14)
In this case IOWAY is 1 on entry, and IQUEST(2) specifies the number of words in the buffer IBUF waiting to be transmitted.
UserSR is supposed to dispatch the buffer IBUF, and return zero in IQUEST(1). (At least for the time being, a non-zero status code in IQUEST(1) is ignored.)
Normally the identification of the banks belonging to the data-structure to be written out is left to FZOUT itself. Naturally this can cover only logically simple cases, such as the complete d/s supported by the bank at the entry address specified to FZOUT.
The situation does however arise that one needs a more complex description. For this the M option has been provided which tells FZOUT that the user has already marked the banks to be transfered by setting system status-bit IQMARK (=26), and that he has designated the memory interval which contains his banks by storing the addresses of the lowest and the highest bank into the COMMON/ZLIMIT/LLOW,LHIGH. Thus in principle one can set up one's selection in full generality, except that one must take care that the banks marked actually form a connected d/s with the entry address LENTRY.
It may however be quite tedious to do this job completely 'by hand'. So one tries to provide some tools for formalizable situations. At present the only such tool is MZMARK, which scans a d/s for marking, but at the start of every new linear structure reached during the scan it checks the Hollerith ID of the start bank with a list to see whether the new sub-structure should be included into the marking process.
To take an example, suppose the header bank at LENTRY supports 4 primary sub-structures with bank names RAW, GEOM, KIN, DST, of which the first 3 support in turn 4 sub-structures with bank names TEC, BGO, CAL, MUC, and at the even lower levels there may be any unspecified further sub-structures.
If now one wants to write out only the data for GEOM, KIN, DST, and for the first 2 only the BGO results, one can do this with
PARAMETER (NID=4)
DIMENSION IDLIST(NID)
DATA IDLIST / 4HRAW , 4HTEC , 4HCAL , 4HMUC /
CALL MZMARK (0,LENTRY,'-',NID,IDLIST)
CALL FZOUT (LUN,0,LENTRY,IEVENT,'M',IOCH,NUH,IUHEAD)
Note that we have used the anti-selection option (-) of MZMARK to veto at the high levels, which permits the low level linear stuctures to be accepted without one having to specify which exactly they are.
Because the format for processing an FZ file (native, exchange, ALFA mode) is selected by the initializing call to FZFILE, and because the handling of all formats is done by the one set of routines FZIN and FZOUT, the user's call to FZIN or to FZOUT causes the loading of all the code to handle all the formats. This volume is non-negligible, and for production programs one may want to suppress loading of the non-used parts of it. This can be done by adapting this dummy routine, which as it stands is valid for a program which only reads files in native mode and which does not call FZOUT/FZENDO:
SUBROUTINE FZDUMY
CHARACTER NAME*6
C-- No output native mode
*n ENTRY FZOFFN
*n NAME = 'FZOFFN'
*n GO TO 17
C-- No output exchange mode, neither binary nor ALFA
*n ENTRY FZOFFX
*n NAME = 'FZOFFX'
*n GO TO 17
C-- No output ALFA mode, but binary mode
*n ENTRY FZOASC
*n NAME = 'FZOASC'
*n GO TO 17
C-- No input native mode
*u ENTRY FZIFFN
*u NAME = 'FZIFFN'
*u GO TO 17
C-- No input exchange mode, neither binary nor ALFA
ENTRY FZIFFX
NAME = 'FZIFFX'
GO TO 17
C-- No input ALFA mode, but binary mode
*n ENTRY FZIPHA
*n NAME = 'FZIPHA'
17 CALL ZFATAM (NAME//' in FZDUMMY reached.')
END
Note that the dummy entry FZIFFN is not active because the true routine is needed, FZIPHA is not needed because FZIFFX is stronger, and that the entries FZO... are not needed because FZOUT is not called. If the dummy is reached by mistake, the program is stopped via ZFATAL with a message.
The various modes of operation of FZ have been made optional at the source code level to allow a tailor-made installation for specific applications. For example, if on a given machine, like an emulator, FZ is used exclusively in 'channeled mode', the code for all other modes can be removed by giving the command line
+USE, FZFFNAT, FZDACC, FZLIBC, FZMEMORY, FZALFA, T=INHIBIT.in the cradle to the Patchy run which generates the code to be compiled for the Zebra Library.
These are the options:
Global CERN library references
/user/goossens/cnasall/cnasbibl,/user/goossens/cnasall/textproc}