## User Exits

To be even more flexible, FLAM provides user exits which can be used for pre- and post-processing of uncompressed records as well as FLAMFILE records.

User exits are needed for inserting, deleting and editing records or fields before or after a compression or decompression procedure.

FLAMFILEs can also be modified to make it personal and incompatible by swapping bytes via FLAM user exits. The effect is basically the same like enciphering (by symmetrical exit modules).

Code conversion is controlled via standard code tables or user defined code tables. For special cases where a 1:1 code conversion is not possible for all characters, user exits can be used, too.

### Specific Addressing Modes

User exits can be written for any addressing mode (`AMODE=ANY`, `AMODE=31`, `AMODE=24`, no mode specified).

The addressing mode only has to be taken into account if FLAM is loaded with `AMODE=31` and, for some reason, the user exit is only able to run with `AMODE=24`. Only in this case, the addressing mode must be switched in the user exit itself. It must be noted that the save area, the return address, the parameter list and the parameters can be addressed only in `AMODE=31`. The addressing mode used by FLAM is stored in the most significant bit of register R14 and can be looked up there.

In all other cases, the addressing mode is already set correctly and it is switched over again by FLAM after the return, if this is necessary. It is irrelevant whether the return is executed with a BR14 or a BSM 0,14 (Branch and Set Mode is a return branching instruction that set the addressing mode).

### Original Data Input EXK10

This user exit serves as an interface between the data record that is transferred to FLAM for compression.

Special processing can be defined for:

- start of file
- record level
- end of file

Records can be passed on, modified, deleted or inserted. This exit can be used to modify records in a structure dependent way.

EXK10 is only available in FLAM and FLAMUP and corresponds to EXD10 during decompression.

#### Principle of Operation EXK10

In this user exit, the original records (which shall be compressed) are passed to a user module immediately after they are read from the input file. This user exit can be used with the FLAM utility or with the subprogram FLAMUP. Records can be accepted, modified, inserted and deleted by this exit.

The exit is activated via the parameter `EXK10=<user module name>`. The user exit module must be contained in the library that has been assigned with the STEPLIB command.

user module name | free choice (max. 8 characters)
Register usage |
R1 | Address of parameter list
R13 | Points to save area (18 words)
R14 | Contains return address
R15 | Contains call address (entry point)

Parameter list |  |
--- | --- | ---
1. FUCO | F | Function code
| 0 | First call for file (after OPEN)
| 4 | Record read and passed
| 8 | Last call for file (before CLOSE)
2. RETCO | F | Return code
| 0 | Accept record / no error
| 4 | Do not accept record
| 8 | Insert record
| 12 | Enforce end of compression
| 16 | Error in user exit; abnormal termination
3. RECPTR | A | Record pointer
4. RECLEN | F | Record length (maximum 32760)
5. EXWORK | 256F | During the first call, the working storage area contains the symbolic file name of the original file within the first 8 characters. The rest of the area is padded with x00. This area can be used by the user exit module for any purpose. With each call this working storage area is made available again with the old content. If a record shall be extended or inserted, the necessary working storage area must be provided by the user exit module. Return code 12 is only necessary if the compression shall be finished before the end of the input file is reached. For function code 0 and 8, no record is passed to the module. For function code 8, it is allowed to insert a record with return code 8. For return code 8, the record provided by the user exit module is processed. Then the user exit module is called again for the old record from the input file. The following table shows the valid function and return codes:

Function code |  | 0 | 4 | 8
Return code | 0 | x | x | x
| 4 |  | x |
| 8 |  | x | x
| 12 |  | x |
| 16 | x | x | x

### Compressed Data Output EXK20

This user exit treats compressed data before it is written to a FLAMFILE.

Special processing can be defined for:

- start of file
- record level
- end of file

This exit can be used to modify records in a structure independent way.

With this exit it is possible to modify the data with an own encryption routine or a special code translation can be applied if a non-transparent file transmission method shall be used.

It is possible to insert own records in front of the compressed records, for example archiving control records or origin information.

Another possibility is the extension of records to append specific revision information.

EXK20 is available in FLAM, FLAMUP and FLAMREC and corresponds to EXD20 during decompression.

#### Principle of Operation EXK20

In this user exit, the compressed records are passed to a user module immediately before they are written to the compressed file. This user exit can be used with the FLAM utility or with the subprogram FLAMUP. This user exit can accept, modify, insert and delete records.

The exit is activated via the parameter `EXK20=<user module name>`. The user exit module must be contained in the library that has been assigned with the STEPLIB command.

user module name | free choice (max. 8 characters)
Register usage |
R1 | Address of parameter list
R13 | Points to save area (18 words)
R14 | Contains return address
R15 | Contains call address (entry point)

Parameter list |  |
--- | --- | ---
1. FUCO | F | Function code
| 0 | First call for file (after OPEN)
| 4 | Record passed
| 8 | Last call for file (before CLOSE)
2. RETCO | F | Return code
| 0 | Accept record / no error
| 4 | Do not accept record
| 8 | Insert record
| 12 | Enforce end of compression
| 16 | Error in exit; abnormal termination
3. RECPTR | A | Record pointer
4. RECLEN | F | Record length (maximum 32760)
5. EXWORK | 256F | During the first call the working storage area contains the symbolic file name of the original file within the first 8 characters. The rest of the area is padded with x00. This area can be used by the user exit module for any purpose. With each call, this working storage area is made available again with the old content. If a record shall be extended or inserted, the necessary working storage area must be provided by the user exit module. Return code 12 is only necessary if the compression shall be finished before the end of the input file is reached. For function code 0 and 8, no record is passed to the module. For function code 8, it is allowed to insert a record with return code 8. For return code 8, the record provided by the user exit module is written. Then the user exit module is called again for the old compressed record.

Table of valid function codes and return codes:

Function code |  | 0 | 4 | 8
Return code | 0 | x | x | x
| 4 |  | x |
| 8 |  | x | x
| 12 |  | x |
| 16 | x | x | x

### Original Data Output EXD10

This exit treats the decompressed records immediately before they are written to the target file.

Special processing can be defined for:

- start of file
- record level
- end of file

Records can be passed on, modified, deleted or inserted. This exit can be used to modify records in a structure dependent way.

EXD10 is only available in FLAM and FLAMUP and corresponds to EXK10 during compression.

#### Principle of Operation EXD10

In this user exit, the decompressed records are passed to a user module immediately before they are written to the output file. This user exit can be used with the FLAM utility or with the subprogram FLAMUP. This user exit can accept, modify, insert and delete records.

The exit is activated via the parameter `EXD10=<user module name>`. The user exit module must be contained in the library that has been assigned with the STEPLIB command.

user module name | free choice (max. 8 characters)
Register usage |
R1 | Address of parameter list
R13 | Points to save area (18 words)
R14 | Contains return address
R15 | Contains call address (entry point)

Parameter list |  |
--- | --- | ---
1. FUCO | F | Function code
| 0 | First call for file (after OPEN)
| 4 | Record passed
| 8 | Last call for file (before CLOSE)
2. RETCO | F | Return code
| 0 | Accept record / no error
| 4 | Do not accept record
| 8 | Insert record
| 12 | Enforce end of compression
| 16 | Error in exit; abnormal termination
3. RECPTR | A | Record pointer
4. RECLEN | F | Record length (maximum 32760)
5. EXWORK | 256F | During the first call the working storage area contains the symbolic file name of the original file within the first 8 characters. The rest of the area is padded with x00. This area can be used by the user exit module for any purpose. With each call this working storage area is made available again with the old content. If a record shall be extended or inserted, the necessary working storage area must be provided by the user exit module. Return code 12 is only necessary if decompression shall be finished before the end of the compressed file is reached. For function code 0 and 8, no record is passed to the module. For function code 8, it is allowed to insert a record with return code 8. For return code 8, the record provided by the user exit module is written. Then the user exit module is called again for the old record. A change of the record length is accepted if the output file is defined with `RECFORM=V`.

Table of valid function codes and return codes:

Function code |  | 0 | 4 | 8
Return code | 0 | x | x | x
| 4 |  | x |
| 8 |  | x | x
| 12 |  | x |
| 16 | x | x | x

### Compressed Data Input EXD20

This user exit treats the compressed data immediately after it is read from the FLAMFILE.

Special processing can be defined for:

- start of file
- record level
- end of file

This exit can be used to modify records in a structure independent way.

With this exit it is possible, to decrypt the data with an own decryption routine or to apply the reverse code translation as used during compression.

For a proper operation of FLAM it is indispensable that all changes applied to the compressed data are reversible. User exit EXD20 must deliver exactly the same data as user exit EXK20 received. All modifications applied to compressed data with EXK20 must be undone with EXD20.

EXD20 is available in FLAM, FLAMUP and FLAMREC and corresponds with EXK20 during decompression.

#### Principle of Operation EXD20

In this user exit, the compressed records are passed to a user module immediately after they are read from the compressed file. This user exit can be used with the FLAM utility or with the subprogram FLAMUP and in the record level interface FLAMREC. This user exit can accept, modify and delete records.

The exit is activated via the parameter `EXD20=<user module name>`. The user exit module must be contained in the library that has been assigned with the STEPLIB command.

user module name | free choice (max. 8 characters)
Register usage |
R1 | Address of parameter list
R13 | Points to save area (18 words)
R14 | Contains return address
R15 | Contains call address (entry point)

Parameter list |  |
--- | --- | ---
1. FUCO | F | Function code
| 0 | First call for file (after OPEN)
| 4 | Record passed
| 8 | Last call for file (before CLOSE)
2. RETCO | F | Return code
| 0 | Accept record / no error
| 4 | Do not accept record
| 8 | Insert record
| 12 | Enforce end of decompression
| 16 | Error in exit; abnormal termination
3. RECPTR | A | Record pointer
4. RECLEN | F | Record length (maximum 32760)
5. EXWORK | 256F | During the first call the working storage area contains the symbolic file name of the original file within the first 8 characters. The rest of the area is padded with x00. This area can be used by the user exit module for any purpose. With each call this working storage area is made available again with the old content. If a record shall be extended or inserted, the necessary working storage area must be provided by the user exit module. Return code 12 is only necessary if decompression shall be finished before the end of the compressed file is reached. Because of the necessary synchronisation with the construction of the matrix, this return code is not always possible. For function code 0 and 8, no record is passed to the module.

Table of valid function codes and return codes:

Function code |  | 0 | 4 | 8
Return code | 0 | x | x | x
| 4 |  | x |
| 8 |  | x | x
| 12 |  | (x) |
| 16 | x | x | x

### Key Management KMEXIT

This user exit returns a key to the FLAM utility for en-/decryption of a FLAMFILE.

So, it is possible to enter any PASWORD/CRYPTOKEY in a secure way without notice to the JCL or the protocol.

This exit is implemented as an interface to special key management systems, without influence to the FLAM utility programs.

#### Principle of Operation KMEXIT

This user exit is an interface to a special (e.g. user written) key management system.

On encryption, parameters (`KMPARM=...`) are passed to the module. It returns a key for encryption of the FLAMFILE and a string of up to 512 bytes. This data is stored in the FLAMFILE as a user header (see parameter COMMENT or function FLMPUH).

On decryption, parameters (`KMPARM=...`) and the data stored in the user header are passed to the exit. The module returns the same key as on encryption. It is up to the module, how to create a key and what kind of information is to be stored into the user header of the FLAMFILE. This data will help the module to find the correct key on decryption.

The exit is activated via the parameter `KMEXIT=<user module name>`. The user exit module must be contained in the library that has been assigned with the STEPLIB command.

user module name | free choice (max. 8 characters)
Register usage |
R1 | Address of parameter list
R13 | Points to save area (18 words)
R14 | Contains return address
R15 | Contains call address (entry point)

Parameter list |  |
--- | --- | ---
1. FUCO | F | Function code
| 0 | Decryption
| 1 | Encryption
2. RETCO | F | Return code
| 0 | No error
| else | Error(s) detected
3. PARMLEN | F | Length of parameter (up to 256 byte)
4. PARAM | XLn | Parameter
5. DATALEN | F | Decryption: -> Length of data Encryption: -> Buffer length of field DATA (512) <- Length of returned data (max. 512)
6. DATA | XLn | PData (in length of DATALEN)
7. CKYLEN | F | Length of key for en-/decryption -> Buffer length of field CRYPTOKEY (64) <- Length of returned key (max. 64)
8. CRYPTOKEY | XLn | Returned key (in length of CKYLEN)
9. MSGLEN | F | Message length -> Length of message buffer (field MESSAGE) (128) <- Length of returned Message length (max. 128)
10. MESSAGE | CLn | Returned message (in length of MSGLEN) If a message is returned (MSGLEN > 0), it is sent to the protocol (FLM0445 ...). The returned key is not sent to the protocol. The data DATA is stored 'as is' in the user header of the FLAMFILE. If special security is required, it has to be done by the exit. Usage of this exit overwrites the parameter COMMENT and CRYPTOKEY, if any. The exit is called only once if encryption of many files into a Group-FLAMFILE `(C,FLAMIN=user.*)` is required. It is called only at the beginning of the first file. The exit is called many times for decryption of many FLAMFILEs `(D,FLAMFILE=user.*.aes)`. It is called after opening each FLAMFILE. In the DD-statement, concatenated FLAMFILEs are treated as one FLAMFILE! Look for an example in FLAM.SRCLIB (KMX-SAMPL).

### User exits used by FLAM utility

#### Compression with EXK10, EXK20

During compression, it is possible to call additional routines for pre-processing of original records and for post-processing of compressed records.

E.g., pre-processing may perform a selection of specific records or fields.

Post-processing may introduce additional encryption of the compressed record.

Instead of using the more complicated record level interface record-orientated processing can be done often with user exit EXK10.

#### Decompression with EXD10, EXD20

During decompression, it is possible to call additional routines for pre-processing of compressed records and for post-processing of original records.

E.g., pre-processing may decrypt encrypted records.

Post-processing may perform a selection of specific records or fields.

Instead of using the more complicated record level interface record-orientated processing can be done often with user exit EXD10.

### User exits used by record interface

#### Compression with EXK20

The user exit for compressed records can also be used under the record level interface.

The actual interception of original records by the interface is not affected.

#### Decompression with EXD20

The user exit for compressed records can also be used under the record level interface.

The actual interception of original records by the interface is not affected.

### User exit examples

#### EXK10/EXD10-user exit

The following exit routine can be used for compression as well as for decompression and has the purpose of modifying fields within records.

The sample code is found in the library FLAM.SRCLIB.

             TITLE 'SEPARATE: EXIT FOR FLAM COMPRESSION'
    SEPARATE CSECT
    SEPARATE AMODE ANY
    SEPARATE RMODE ANY
    **********************************************************************
    *        THIS PROGRAM SEPARATES FIELDS WITHIN RECORDS WHICH CAN
    *        BE SEPARATED BY DELIMITER CHARACTERS INTO DIFFERENT FLAM RECORDS.
    *        THIS ENABLES A BETTER COMPRESSION.
    *        THE DESIGN OF THE PROGRAM ALLOWS TO MODIFY THE DELIMITER AND
    *        EVEN THE LENGTH OF THE DELIMITER BY CHANGING ONLY ONE STATEMENT.
    *
    *        THE DELIMITERS ARE REMOVED FROM THE RECORD AND ARE REPLACED
    *        BY FLAM SYNTAX.
    *        IF THE RECORD DOES NOT CONTAIN DELIMITERS IT IS PASSED TO
    *        FLAM WITHOUT MODIFICATIONS.
    *
    *        THE ROUTINE SEPARATE IS ACTIVATED VIA PARAMETER 'EXK10=SEPARATE'
    *        DURING THE CALL OF FLAM OR FLAMUP.
    *
    *        THE FIELDS CONSIST OF PRINTABLE CHARACTERS SEPARATED BY
    *        A TWO BYTE LONG DELIMITER (X'0D25').
    *
    *        THE DATA COMPRESSED IN THIS WAY IS TRANSMITTED VIA
    *        FILE TRANSFER TO A PC, DECOMPRESSED FIELD BY FIELD
    *        USING FLAM AND WRITTEN TO THE STORAGE MEDIUM (WITH
    *        DELIMITER OF THE OPERATING SYSTEM,  X'0D0A' WITH MSDOS
    *        OR X'0A' WITH UNIX).
    *
    *  NOTE:
    *
    *        FOR DECOMPRESSION ON A MAINFRAME A FILE WITH
    *        VARIABLE RECORD LENGTH MUST BE SPECIFIED.
    *        EACH FIELD SEPARATED DURING COMPRESSION IS WRITTEN
    *        AS A SEPARATE RECORD. THE DELIMITERS ARE NOT CONTAINED
    *        IN THE DECOMPRESSED RECORDS.
    *        THIS MEANS THAT THE ORIGINAL FILE CANNOT BE RECONSTRUCTED
    *        ON A MAINFRAME.
    *
    *        THIS MODULE IS REENTRANT AND REUSABLE
    *
    *
    *---------------------------------------------------------------------
    *
    *  AUTHOR:         LIMES DATENTECHNIK GMBH
    *                  D-61381 FRIEDRICHSDORF/TS.
    *                  TEL. 06172-5919-0
    *                  FAX  06172-5919-39
    **********************************************************************
    *
    *  INTERFACE:  R1 POINTS TO PARAMETER LIST
    *
    *   0(R1)   -   A(FUNCTION CODE)
    *   4(R1)   -   A(RETURN CODE)
    *   8(R1)   -   A(A(RECORD))  RECORD POINTER
    *  12(R1)   -   A(RECORD LENGTH)
    *  16(R1)   -   A(WORK AREA)       NEW WITH FLAM V2.5
    *
    **********************************************************************
             EJECT
             STM   R14,R12,12(R13)    SAVE REGISTERS
             LR    R12,R15            ENTRY ADDRESS USED AS PROGRAM BASE
             USING SEPARATE,R12       ASSIGN BASE REGISTER
             USING WORKAREA,R2        BASE REGISTER WORK AREA
             LA    15,0               INITIALISE RETURN CODE WITH 0
    *
             L     R3,0(,R1)          LOAD A(FC)
             CLC   0(4,R3),FCSATZ     PASS RECORD ?
             BE    SATZUEB            == YES
             CLC   0(4,R3),FCOPEN     OPEN ?
             BNE   RET                == NO
    *
    *  AT OPEN TIME RESET WORK AREA FIELDS
    *
             L     R2,16(,R1)        A(WORKAREA)
             MVI   FLAG,X'00'        RESET FLAGS
             B     RET
    SATZUEB  DS    0H
    *
    *        RECORD WAS PASSED
    *
             L     R10,8(,R1)        A(A(RECORD)) TO R10
             L     R4,0(,R10)        LOAD A(RECORD)
             L     R11,12(,R1)       A(RECORD LENGTH)
             L     R5,0(,R11)        LOAD RECORD LENGTH
             LA    R9,0(R5,R4)       A(RECORD END)
             L     R2,16(,R1)        A(WORK AREA)
    *
             TM    FLAG,SATZDA       RECORD ALREADY PRESENT ?
             BNO   BEGINN            == NO
             TM    FLAG,LOESCH       DELETE RECORD ?
             BO    LOESATZ           == YES
    *
    BEGINNA  DS    0H                RECORD WAS ALREADY PROCESSED
             L     R4,SATZPTR        A(FIELD) FROM LAST TIME
    *
    BEGINN   DS    0H
             OI    FLAG,SATZDA       INDICATE RECORD PRESENT
             LR    R7,R4             SAVE A(FIELD BEGIN)
             LR    R6,R9             A(FIELD END)
             SR    R6,R7             - A(FIELD BEGIN) = L'REMAINDER
             BZ    LEERSATZ          L'= 0, PASS EMPTY RECORD
             C     R6,LTRENNKZ
             BNL   SUCH              L'  L'DELIMITER - HAS NO DELIMITER
             OI    FLAG,LOESCH       INDICATE DELETE OPERATION FOR NEXT RUN
             LR    R4,R9             A(RECORD END)
             B     SUCHEND
    SUCH     DS    0H
             LA    R8,1              INCREMENT FOR BX INSTRUCTION
             S     R9,LTRENNKZ       FOR BX INSTR. SET RECORD END -L'
    SUCHLOOP DS    0H
    *
    *  SEARCH STRING IS (DELIMITER)
    *
             CLC   0(L'TRENNKZ,R4),TRENNKZ   DELIMITER ?
             BE    ISTDA             == YES
             BXLE  R4,R8,SUCHLOOP    NEXT CHARACTER
    *
             OI    FLAG,LOESCH       INDICATE DELETE OPERATION FOR NEXT RUN
             LA    R4,L'TRENNKZ-1(R4) FIELD IS BIGGER BY L'-1
             B     SUCHEND
    *
    ISTDA    DS    0H
             LA    R6,L'TRENNKZ(R4)  INCREMENT RECORD POINTER
             ST    R6,SATZPTR        SAVE RECORD POINTER
    SUCHEND  DS    0H
    *
    *  FILL FLAM PARAMETER LIST
    *
             SR    R4,R7             FIELD LENGTH
             ST    R4,0(R11)         IS RECORD LENGTH FLAM
             ST    R7,0(R10)         RECORD ADDR FOR FLAM
             LA    R15,8             RETURN CODE: INSERT RECORD
    *
    RET      DS    0H
    *
    *        RETURN TO FLAM
    *
             L     R3,4(,R1)          LOAD A(RC)
             ST    R15,0(,R3)         PASS RC
             L     R14,12(R13)        RESTORE REGISTERS
             LM    R0,R12,20(R13)
             BR    R14                RETURN
    *
    LOESATZ  DS    0H
             LA    R15,4              RETURN CODE: DELETE RECORD
             MVI   FLAG,X'00'         RESET FLAG
             B     RET                AND RETURN
    *
    LEERSATZ DS    0H                 AFTER DELIMITER AT RECORD END
             OI    FLAG,LOESCH        INDICATE DELETE OPERATION FOR NEXT RUN
             LA    R4,0               RECORD IS EMPTY
             ST    R4,0(R11)          RECORD LENGTH FOR FLAM
             LA    R15,8              RETURN CODE: INSERT RECORD
             B     RET                AND RETURN
    *
    *  CONSTANTS AND WORK AREAS
    *
    *
    FCSATZ   DC    F'4'               FUNCTION CODE RECORD PASSED
    FCOPEN   DC    F'0'                             OPEN
    LTRENNKZ DC    A(L'TRENNKZ)       LENGTH OF DELIMITER
    *--------------------------------------------------------------------
    *
    *  IN CASE OF DIFFERENT DELIMITER MAKE MODIFICATIONS HERE
    *
    TRENNKZ  DC    XL2'0D25'          DELIMITER TO BE FOUND
    *--------------------------------------------------------------------
    *
    *  REGISTER
    *
    R0       EQU   0
    R1       EQU   1                  PARAMETER ADDRESS
    R2       EQU   2                  BASE REGISTER FOR WORK AREA
    R3       EQU   3
    R4       EQU   4
    R5       EQU   5
    R6       EQU   6
    R7       EQU   7
    R8       EQU   8
    R9       EQU   9
    R10      EQU   10
    R11      EQU   11
    R12      EQU   12                 BASE REGISTER
    R13      EQU   13                 A(SAVE AREA)
    R14      EQU   14                 RETURN ADDRESS
    R15      EQU   15                 ENTRY ADDRESS
    *
             LTORG
    *
             DC    C'*** MODULE SEPARATE V1.02 FOR FLAM '
             DC    C' COPYRIGHT (C) 1990-91 BY LIMES DATENTECHNIK GMBH. '
             DC    C'DATE, TIME ASSEMBLED: '
             DC    C'&SYSDATE , &SYSTIME '
             DC    C'***'
    *
    *  WORKAREA IS PROVIDED BY FLAM (1024 BYTES)
    *
    WORKAREA DSECT
    *
    DDNAME   DS    CL8                DD-NAME OF CURRENT FILE
    SATZPTR  DS    A                  RECORD POINTER
    FLAG     DS    X                  INDICATORS FOR PROCESSING
    SATZDA   EQU   1                  RECORD ALREADY PRESENT
    LOESCH   EQU   2                  DELETE RECORD
             END

#### EXK20/EXD20-user exit

Since FLAM protects compressed files against manipulations by applying a checksum, it is possible to provide encryptions within the user exits with a very low overhead.

Because the compressed data is already encrypted, simple deterministic character swapping within the compressed data cannot be detected easily by an unauthorized user.

During decompression this character swapping - if not redone by an authorized user - will lead to a check sum error and the compressed file cannot be read.

The symmetric construction of the user exits allows to use the same routine for encryption as well as for decryption provided that algorithms are used that will restore the original data when executed twice. This is the case with mutual character swapping.

Similar results can be obtained with translate tables for cyclic (cycle length 2) character code exchange.

             TITLE 'EX20 (B) | VERSION 1.00:06/25/91 | '
    ***********************************
    * COLUMBUS-ASSEMBLER              *
    ***********************************
    * SYMBOLIC CONDITIONS FOR #IF,#WHEN,#WHIL(E),#TOR,#AND,#OR
    #LT      EQU   4   LESS THAN
    #GT      EQU   2   GREATER THAN
    #EQ      EQU   8   EQUAL
    #NE      EQU   7   NOT EQUAL
    #LE      EQU   13  LESS OR EQUAL
    #GE      EQU   11  GREATER OR EQUAL
    #LZ      EQU   4   LESS THAN ZERO
    #GZ      EQU   2   GREATER THAN ZERO
    #ZE      EQU   8   ZERO
    #NZ      EQU   7   NOT ZERO
    #ON      EQU   1   ONES
    #MI      EQU   4   MIXED
    #ZO      EQU   11  ZEROS OR ONES
    #ZM      EQU   14  ZEROS OR MIXED
    #OM      EQU   7   ONES OR MIXED
    #F       EQU   15  TRUE IN ANY CASE
    * FLOATING POINT REGISTERS, GENERAL REGISTERS, COLUMBUS REGISTERS
    FA       EQU   0
    FB       EQU   2
    FC       EQU   4
    FD       EQU   6
    R0       EQU   0
    R1       EQU   1
    R2       EQU   2
    R3       EQU   3
    R4       EQU   4
    R5       EQU   5
    R6       EQU   6
    R7       EQU   7
    R8       EQU   8
    R9       EQU   9
    R10      EQU   10
    R11      EQU   11
    R12      EQU   12
    R13      EQU   13
    R14      EQU   14
    R15      EQU   15
    R#PAR    EQU   R1
    R#BASE   EQU   R10
    R#STACK  EQU   R13
    R#EXIT   EQU   R14
    R#PASS   EQU   R15
             EJECT
    EX20     CSECT
             USING EX20,R#PASS
    ***********************************************************************
    *  NAME: EX20                                       VERSION: 13.03.91 *
    *  FUNCTION:                                                          *
    *        FLAMFILE IS ENCRYPTED AND DECRYPTED IN A SIMPLE WAY.         *
    *                                                                     *
    *        THE 16TH AND 17TH CHARACTER ARE SWAPPED WHICH                *
    *        CHANGES THE CHECKSUM. THE COMPRESSED DATA                    *
    *        CAN ONLY DECOMPRESSED IF THE SWAP OPERATION                  *
    *        DONE AGAIN.                                                  *
    *        PARAMETER                                                    *
    * 1 ->   ID       F    IDENTIFICATION                                 *
    * 2 <-   RETCO    F    RETURN CODE                                    *
    * 3 ->   RECPTR   A    RECORD POINTER                                 *
    * 4 ->   RECLEN   F    RECORD LENGTH                                  *
    ***********************************************************************
    *
    *  SAVE REGISTERS AND LOAD BASE REGISTERS
    *
             STM   R14,R12,12(R13)
    *
    *  LOAD PARAMETERS
    *
             LM    R1,R4,0(R1)
    *  PASS COMPRESSED RECORD
             CLC   0(4,R1),F4
             BC    #F-#EQ,#F1001
    *  LOAD RECORD LENGTH
             L     R4,0(R4)
    *  RECORD LENGTH GREATER 16
             LA    R14,16
             CR    R4,R14
             BC    #F-#GT,#F1002
    *
    *  SWAP 16TH AND 17TH CHARACTER
    *
             L     R3,0(R3)
             LA    R14,0(R3,R14)
             IC    R5,0(R14)
             MVC   0(1,R14),1(R14)
             STC   R5,1(R14)
    #F1002   DS    0H
    #F1001   DS    0H
    *
    *  RETURN CODE = ACCEPT RECORD / NO ERROR
    *
             LA    R0,0
             ST    R0,0(R2)
    *
    *  RETURN
    *
             LM    R14,R12,12(R13)
             BR    R#EXIT
    *
    *  LOCAL CONSTANTS
    *
    F4       DC    F'4'
    F16      DC    F'16'
             LTORG
             DS    0D
             DROP  R#PASS
             END