FLAM4 Record Interface (Windows and Linux conform with z/OS (MF-EDZ))
FLAM4 Record Interface

This interface provides a platform independent record-oriented read and write access to FLAM4 files. It contains all functions of the Windows, UNIX and HOST record interfaces to provide backward compatibility, required for sequential access. On Mainframes additional load modules are available for positioning, insert and update of records.

Interface standards

Each function is also available as a separate load module. On open platforms the function names are in lower case with '_' as prefix and 1 as postfix (_flmxxx1), on mainframes in upper case (FLMXXX). The libfl4recuc.dll/so provides the functions in upper case on Windows and Unix systems. This documentation use 'flmxxx' in lower case for each entry.

There are 4 types of parameters:

POINTER:   Pointer to an address (usually 32 (PIC S9(9) COMP) or 64 bit)
INTEGER:   Pointer to a 32 bit number in two's complement (PIC S9(9) COMP)
INTARY2:   Pointer to an array of 2 INTEGERs (2*32 bit)
STRING[x]: Pointer to a byte (8 bit) array of length x (PIC X(x))
STRING:    Pointer to a variable length byte (8 bit) array (PIC X(n))

The type INTEGER has local endianness. On mainframes, this is usually big endian. This means that the most significant byte is stored first (i.e. at the lowest memory address) and the least significant byte is stored last. On x86 platforms, the byte order is little endian. This means that the byte order is reversed.

Detailed description

The interface provides functions similar to the record-oriented file I/O functions used with COBOL, PL/I or assembler on mainframes. Only the file open function differs in that it gives 3 different open function and a few setter (or FLMSET()) which must be called in the right sequence, to open a FLAMFILE of version 4. To simplify the use of FKME (FLAM key management extensions) we have add the callable service FLMKME, which works like FLMPWD.

FL4REC consists of a number of subroutines that can be called by any programming language such as COBOL, PL/I, C, FORTRAN, etc., as well as by ASSEMBLER programs. Except for the key descriptions all parameters are implemented as elementary data types (INTEGER, STRING). Deliberately no control blocks are required to avoid alignment problems and additional copying of parameter values before and after a function call. Key descriptions are organized as a structured data type in order to shorten the parameter list.

Application programs written in C must include the header FL4REC.h. This C header file contains the definitions of the symbolic constants, as well as the structure of the key description. These definitions must be ported to other programming languages accordingly if C is not used.

Function arguments

All argument lists begin with an ID, which identifies the compression file uniquely. This flmid argument contains the address of the work area for the compressed file, which was specified by flmopn(), and must not be modified until flmcls(). All other arguments are only relevant to the function to which they are transferred.

The identification is followed by a return code that informs the caller about successful execution or occurring errors. Processing of a compressed file always starts with function FLMOPN that assigns the program to the compressed file and defines the operation mode. A file opened successfully must always be closed with function FLMCLS. There are no messages generated at the record level interface. During transfer of original data the parameter RECORD always contains the true data without any length fields or record delimiters. Or the parameter RECPTR points to a field with such a content. The parameter RECLEN always contains the length of the true data (exclusive length).

COBOL programs can be translated using the DYNAM option. As a result, the FLAM modules are loaded from the library only at the moment of execution. If a dynamic call is not wanted (NO-DYNAM option in COBOL or V constants in ASSEMBLER), the FLAM module FL4REC should be specified explicitly when linking.

Micro Focus EDZ support

The API is supported also in MF-EDZ environments. See install.txt on Windows or Unix for more information.

Functions passing pointer adresses, for example flmloc(), only work if the COBOL compiler directiv AMODE is NOT used. With AMODE mainframe pointers are used in the COBOL program which cannot be converted.

For use with Micro Focus Enterprise Server the following environment variables might be used.

The filename needs to be specified as either DD:name or //'name' if the Micro Focus support is needed. Otherwise normal FLAM4 use is done.
If DD:name or //'name' cannot be accessed an error is returned.
Micro Focus libraries will be used and an error is returned if they are not found.
The encoding is used to automatically convert all input character strings from this to the local system encoding. The output character strings are converted from the local system to this encoding.
The command flcl info get.enc prints a list of all supported encodings.
For convenience the strings :EBCDIC or :ASCII might be used. If the encoding strings begins with 'IBM' big endian is assumed and binary values will be byte swapped.
Micro Focus libraries will be used and an error is returned if they are not found.
No character conversion is done.
Micro Focus support is switched off, standard FLAM4 use.
This must be done in order to work with filenames starting with DD:

For tracing:

Without trace file name tracing of library calls is omitted.
trace output of library function calls is written to filename

For system symbols:

to define static system variables as environment variables.
to use the JCL user exit to define dynamic system symbols

For dynamic system variables the DD:SYSVAR is also supported.

To use the function in COBOL the libfl4recuc.dll/so must be copied in the working directory of the EDZ server under FLMOPN.dll/so and FLMERR.dll/so.

Return codes

Return codes are mainly the same between HOST and other platforms but in the higher values a few differences exists. This is mainly in cases where the return code is more the reason code for an error. To simplify the error handling a function (FLMERR) which provides the correct error message independent of the platform are add to this interface. Below you can find a list of important FLAM4 return codes. This list covers any return code to control the program, if another return code occur this will mainly a severe error to terminate execution.

0No error, success
1A record has been shortened to the length of the record buffer.
2The end of the file has been reached while reading; no data is transferred.
3A gap has been found in a relative file; the record length is zero.
4When a record is converted to fixed format, it is padded with fill characters.
5A key is missing when reading from or is invalid when writing to an index sequential file.
6When reading in a group file, a new file is starting; no data is transferred.
7Password / cryptokey missing on decompression.
8Parameter or function not supported.
9When compressing with the statistics switched on, FLAMUP or FLAM reports that the compressed file is larger than the original file (expansion).
10During decompression, the input file has not been recognized as being a FLAM compressed file.
11The format of the FLAMFILE is wrong.
14The checksum of a compressed record is wrong.
22Invalid compression method.
29Password missing or invalid (passed by FLMPWD).
30Input file is empty.
31Input file does not exist.

Programming the Record Interface at Compression

The process of creating a FLAMFILE can be divided into three phases:

  • open sequence
  • one or more compression cycles
  • termination (function flmcls())

The open sequence always starts calling the flmopn() function. flmopn() caters for the basic parameters (e.g., Compression/Decompression). flmopd() defines the file format of the FLAMFILE. flmopf() defines the compression parameters. If the flmopd() and flmopf() are not used, fixed values are used.

Subsequently, flmopd() and/or flmopf() can be called if flmopn() was called with continue_param set. When both functions are called, flmopd() must come first and also have continue_param set.

When flmopd() or flmopf() are not called by the application program, FLAM uses implicit settings to generate such calls internally. Default values used with the flam command and flamup calls are not effective here.

Finally, if encryption is used, a password must be provided by a flmpwd() call.

In the second phase, one compression cycle must be done for each file being compressed.

Such a cycle would normally begin with a flmphd() call to generate a common FLAM fileheader. Only when a single file is compressed without encryption, this may be omitted. If a FLAM fileheader was created, a user-specific header may be appended by invoking flmpuh(). With Secure FLAMFILEs, this invocation is mandatory even if the header data length is 0.

Now data can be submitted for compression by repeated execution of flmput(). Each such call passes a record in the FLAM terminology, which can be later replicated identically or with modified record attributes thanks to the structure information kept by FLAM. FLAM collects the data passed to it in the compression buffer and controls compression and the resulting output without involving the application program.

A compression cycle is terminated by a call to flmflu() which causes the remainder in the compression buffer to be compressed and the output of the result. This function also returns statistical information to the application. Following this, a new compression cycle may be initiated by another flmphd() or the FLAMFILE can be closed by calling flmcls().

Control is always returned to the invoking program. There are no error exits and no error messages are generated by the record interface. Rather, a return code is passed back to the application.

Programming the Record Interface at Decompression

As with compression, decompressing a FLAMFILE also consists of three phases:

  • open sequence
  • decompression cycle(s)
  • termination (function flmcls())

The open sequence here consists of the same function calls as at compression. Only the direction of the flow of information is reversed for some of the arguments, e.g. the compression mode. They are returned to the application.

Every function used in the compression cycle has its decompression counterpart that performs the complementary operation. The complements for flmphd() and flmpuh() are flmghd() and flmguh(), respectively, that for flmput() is flmget(). A decompression cycle is also terminated with flmflu(). In addition, there is a function, flmpos(), which advances the read position in a FLAMFILE to the beginning of the next original file. This function has no counterpart with compression.

Typically, a decompression cycle initially invokes flmghd() which returns details about the original file such as file name, record format, etc. This may be followed by flmguh() to retrieve the user-specific header, if present. Subsequent flmget() calls retrieve one record per call, with the last record of an original file being signalled by a special return code. Skipping the remaining records of an original file can be done by flmpos() which positions to the next file header. A flmflu() terminates a decompression cycle that may be followed by another cycle or by flmcls(), which terminates the processing. One flmflu() or flmpos() per cycle is mandatory, all other calls are optional.

Some of the function are not documented. These functions are for internal use only. The setter for FLMSET are also not documented because these entries are not available as load module. To simplify C programming these functions can be used, the functionality is explained over FLMSET. FLMSET is only available on mainframes, to define additional host specific parameters after FLMOPN.