Converting Easytrieve Logic

Contents

Converting Easytrieve Logic. 1

Introduction. 1

Preparing to Convert Easytrieve Logic. 1

The Easytrieve Conversion Notepad. 1

Using the Conversion Notepad. 1

General Changes made by [Convert] 1

PUT. 1

Conditions. 1

Invalid Conditions. 1

Searching Tables. 1

Loops and Indexes. 1

DISPLAY statements. 1

GO TO statements. 1

Direct Access: READ.. 1

Status Checking following READ.. 1

Updating Records. 1

Easytrieve Procedures. 1

EZT DLI Statements. 1

Printing and Reports. 1

Instream Table Lookups. 1

Testing Lookup Success. 1

Optional Changes. 1

Easytrieve Macros. 1

Appendices. 1

Easytrieve Example 1. 1

Example1 after [Convert] 1

Converted Easytrieve inserted into Jazz. 1

 

Introduction

JazzUGEasytrieve provided just an initial introduction to Easytrieve conversion.  You will already have looked at that Help page to get a basic understanding of the process of converting Easytrieve to MANASYS Jazz and generating equivalent COBOL.  There are then further Help pages giving more detail enabling you to deal with more than simple examples.

JazzUGEZTData gives detailed information about creating Jazz definitions of the data defined in Easytrieve programs. It deals with the conversion of the Easytrieve “Library” – the part of the Easytrieve program from the beginning to the first SORT or JOB statement – where the files and fields were defined, and also DEFINE and HEADING statements within the body of your Easytrieve program.  This is the first step of converting your EZT program into Jazz, so that it can be converted into COBOL.

JazzUGEZTLogic1 is the second step.  Here you create the structure of your Jazz program, processing one or more input files to produce output (usually reports) like the EZT programs.  You can take advantage of dialog options to print and copy output, and in simple cases this may be all you need to do to complete your task. But usually this is only the start: in all but the simplest cases you’ll have logic within your program for calculations, printing reports, etc that require EZT logic within the program structure.   For this third step you will convert your EZT logic in chunks to Jazz logic, using the Easytrieve Conversion Notepad.  This is the subject of this Help page.

Read this page if you need to

·                     Understand the rules of Easytrieve to Jazz conversion

·                     Understand the role of the Easytrieve Conversion Notepad

·                     Deal with various issues that you’ll encounter in more complex Easytrieve programs

The final process, converting Jazz to COBOL is 1 click – just click the [Process] button – but converting EZT to Jazz is not so easy and this is where you’ll spend most of your time.   Although MANASYS will do much of the conversion for you, the key to success is knowing how MANASYS works.  Remember that the objective is ALWAYS to convert the EZT program into a Jazz program that produces the results you want, it is NEVER to convert each line of EZT code into the equivalent lines of Jazz.  You will often find that the best solution is to ignore parts of the EZT code and write new code directly into MANASYS.  This is particularly true with loops, updating files, and merging files (“Synchronized File Processing”) where Jazz logic can be significantly different to EZT logic and MANASYS does a lot for you automatically.

Preparing to Convert Easytrieve Logic

When we have written the program outline we may be so close to the final solution that we don’t need to go back to the Easytrieve code.  For example, in JazzUGEZTLogic1,  “Selecting and Reformatting Data with SORT” was most easily completed by simply editing the Jazz program.   In more complex cases like Easytrieve Example 1 we will need to convert Easytrieve logic into equivalent Jazz using the Easytrieve Conversion Notepad.  

Before using the Conversion Notepad, we will already have used Data/Convert from Easytrieve to create a Jazz-format definition (in this example, EZT-EXAMPL1-Data), and defined an appropriate Job structure with Logic/Batch Program: -

Here is the program that results.

Because we checked [ü] Enable EZT Conversion, the PROGRAM statement has the EZT option. Because of this option the 8th button above is labelled [EZT Conv].  Click this and the Easytrieve Conversion Notepad is invoked.

The Easytrieve Conversion Notepad

The Easytrieve Conversion Notepad is a modified Jazz Workbench.  The [Check] button has become [Convert], and [Show Data] has become [Get EZT.  Initially these, and [Exit], are the only active buttons.  

Start by clicking Get EZT, and Windows Explorer opens on the last Easytrieve folder that we used with Import from Easytrieve.  Select the program that we want to convert: here we’ve selected Example1.txt.  We will convert the logic in chunks, as much or as little at a time as we want: in this case we’ll select all the logic from the first statement after the JOB to the end of the program.  Copy/paste the selected chunk into the Conversion Notepad: -

You can Copy/paste as much or as little at a time as you like, but copy enough to make sense.  Too much and you’ll be overwhelmed.  Too little and conversion will take longer than necessary.  A good idea is to start with the logic that will go between PROCESS/END PROCESS.  Then, if this code includes PERFORM statements, [Convert] the related procedures.  Don’t copy partial logic, such as IF … without the corresponding END-IF, a DO without its END-DO, or PROC without its END-PROC.  If you really MUST copy partial logic, read the section Handling Partial Logic 

In this case we’ve copied all the EASYTRIEVE program from the line after JOB almost to the end, omitting only the final JOB. There is too much code to display without scrolling, but it is all shown in Easytrieve Example 1.

We now click [Convert], and the program is partly converted from Easytrieve to Jazz. Example1 after [Convert] shows the full result. If issues are found here you may choose to fix them here, but usually you’ll leave them to be fixed in the next step when the partly converted code is copied into Jazz and conversion completed.  You may see various conversion messages, like #706 below.

Usually, even when there are error messages, you’ll just click [Exit] and then [Yes] to copy it to the Jazz workbench.  

This will complete the conversion from Easytrieve to Jazz.  Fields are recognized and qualified, Jazz keywords are recognized and coloured, and statements are indented to show their logic structure.  Further errors might be discovered, because the Jazz Workbench, unlike the conversion notepad, has access to the program dictionary and so can check the code against the list of records and fields.  For example, copying this code into the program results in: -

PROGRAM EXAMPL1 BATCH EZT;

COPY EZT-EXAMPL1-DATA;

*# Copy Files here ==>

PROCESS INFILE SID(23);

    #346 W DSNAME option missing

    IF INFILE.I-ID = '01' & INFILE.I-FLAG = 'S';

        IF INFILE.I-CLIENT = TEMP1.T-CLIENT & INFILE.I-POLICY = TEMP1.T-POLICY;

        ELSE;

            TEMP1.T-CLIENT = INFILE.I-CLIENT;

            TEMP1.T-POLICY = INFILE.I-POLICY;

            TEMP1.T-FLAG = INFILE.I-FLAG;

            WRITE TEMP1;

            #346 W DSNAME option missing

            #378 W Batch WRITE used - you may need to edit the JCL

        END IF;

Converted Easytrieve inserted into Jazz shows the complete program.  Now we work through the program, dealing with the errors.  It’s not as bad as it looks, as one change may fix several messages. 

1.    Message #346.  Right-click the COPY statement and edit the data definitions to add DSNAME, e.g.

DEFINE INFILE ESDS DATA(

    GROUP1 GROUP,

        End GROUP)

    DSNAME 'JAZZUSR.FILES.INFILE';

DEFINE EZT-EXAMPL1-Data DATA(

    DSNAME '&&TEMP1';

 

2.    The form of the loop has to be changed, replacing FOR WHILE W-CTR < 4with FOR IX1 = 1 TO 4;  See Loops and Indexes for an explanation of what’s happening here.

3.    Jazz doesn’t use indexes, so we add subscript (IX1) to all references of MULTI-POL (10 instances).  

Now there are only Warning messages.   

To complete the program we need to add logic from the final job,

SORT TEMP-1 TO TEMP-2 USING (T-KEY)

*

JOB INPUT(TEMP-2)

   O-RECORD = I-RECORD

   PUT OUTPUT

*

END

This is simply handled by writing the required PROCESS statement manually.  Right-click COPY EZT-EXAMPL1-DATA to check that it contains OUTPUT: we see that it has become OUTPUT1 (OUTPUT is a COBOL reserved word), so we write: -

PROCESS TEMP1 REOPEN ORDER TEMP1.T-KEY;

WRITE OUTPUT1 FROM T-RECORD;

END PROCESS TEMP1;

[Check] turns this into

PROCESS TEMP1 REOPEN ORDER(TEMP1.T-KEY) SID(82);

    WRITE OUTPUT1 FROM(TEMP1.T-RECORD);

    #346 W DSNAME option missing

    #348 W VSAM file must be empty

END PROCESS TEMP1;

We add the correct DSNAME to the definition of OUTPUT1 – I’ve added DSNAME 'JAZZUSR.VSAM.OUTPUT1'; and optionally remove the definition of TEMP2 as it is not used.  This leaves us with only two warning messages, #378 and #348, which relate to the JCL which should be checked before we run the job. 

If the VSAM file doesn’t already exist, or already contains data and needs to be re-created, you will need to use IDCAMS.  You may find the dialog New/Data/VSAM helpful for this.

Finally, you complete the conversion by clicking [Process] which rechecks the program and generates COBOL.  Either: -

·         z/OS: a job is submitted to compile the COBOL and run the job

·         Micro Focus Enterprise: The COBOL and run JCL are written into shared COBOL folder, and where you compile the program and submit the JCL.

You’ve been introduced to the Easytrieve Conversion Notepad and seen it used for a real example.  In Using the Conversion Notepad it is discussed in more depth, and you are shown how to deal with various situations that you may encounter.

Handling Partial Logic

You were told above “Don’t copy partial logic, such as IF … without the corresponding END-IF, a DO without its END-DO, or PROC without its END-PROC.”  But sometimes you have no alternative.  Perhaps you have a very long block of code containing several complex statements, and somewhere within this block there are statements causing an error that you don’t understand.  You really need to break this logic down into shorter chunks so that you can find out where the error is and fix it. 

Here’s a simplified example to show you how this might be handled.  The example starts with a batch program, newly created with the New/Logic/Batch dialog: -

PROGRAM OAADTest BATCH DATABASE V05 DL1 EZT;

COPY JZDL1 JAZZ;

    *# SSA's go here ==>

COPY EZT-OAADTest-DATA;

*# Copy Files here ==>

PROCESS SYS031 ORDER(NULL) TALLY SID(21);

    #785 W File will be processed in its natural order

*#Copy Process logic here ==>

END PROCESS SYS031;

*#Copy Next Process here ==>

*#Copy Routines here ==>

Now we want to start converting the detail logic, starting with the logic of the main PROCESS loop.  But this is complicated: it starts with

 CASE E1-AES                                  

   WHEN 'E'                                   

    *                                         

     DLI V05 V05P2A 'GHU ' SSA SV05P1A SV05P2A

     IF V05-STC SPACE                         

       V2-KZSTATUS = '4'                      

       V2-STATDAT  = W-DATE                   

       DLI V05 V05P2A 'REPL'                  

     END-IF
   … lots more logic until the matching END-CASE                                   

and it continues with another (nested) CASE statement and other logic for many pages.  If we convert all the logic from CASE E1-AES to the corresponding END-CASE there will be a lot of logic to be converted all at once.  Somewhere within it is the error we want to find, but where?  But what happens if we break the “Don’t copy partial logic …” rule?   We’ll convert just the logic above and see.  Copy/paste the above logic into the conversion notepad and click [Convert].  It converts to

CASE E1-AES;

WHEN 'E';

DLI V05 V05P2A 'GHU ' SSA SV05P1A SV05P2A;

IF V05-STC =SPACE;

V2-KZSTATUS = '4';

V2-STATDAT = W-DATE;

DLI V05 V05P2A 'REPL';

END IF;

No problem so far, but when we click [Exit] this results: -

PROCESS SYS031 ORDER(NULL) TALLY SID(21);

    #785 W File will be processed in its natural order

    CASE(SYS031.E1-AES);

        WHEN('E');

            GET V05P2A UPDATE SSA(EZT-OAADTest-Data.SV05P1A,EZT-OAADTest-Data.SV05P2A);

            IF V05.V05-STC =SPACE;

                V05P2A.V2-KZSTATUS = '4';

                V05P2A.V2-STATDAT = EZT-OAADTest-Data.W-DATE;

                UPDATE V05P2A ;

            END IF;

*#Copy Process logic here ==>

    END CASE;[Inserted]

END PROCESS SYS031;

The EZT logic is correctly converted and inserted into Jazz at the *#Copy Process logic here ==> marker, which now appears below the converted logic.  But the next statement in the Jazz program would have been END PROCESS SYS031; leaving an unclosed CASE statement.  A matching END CASE is inserted to that the program remains correct.   Sometimes several END statements are inserted.  Errors may result when an inserted END statement duplicates one that is already present later in the program. 

How to proceed?   First, resolve any issues from this newly-converted code.   Then delete all the inserted END statements (do not click [Check], that will re-insert them) before converting the following chunk of EZT code.

Using the Conversion Notepad

General Changes made by [Convert]

(How the Easytrieve Conversion Notepad works)

First,

1.    If the raw Easytrieve contains any macro references, these are replaced by the macro text. Macros must be in the same folder as the program containing the reference, and have the same extension.  Macros may use parameters, as described in the Easytrieve Plus Reference Guide, Chapter 16.

Then, for each line (except comments),

2.    Multi-line Easytrieve statements become a single line.  If the line ends with an Easytrieve continuation character (- or +) the character is removed, else a semicolon is added to indicate end-of-Statement to Jazz. 

3.    END-IF is changed to END IF, ELSE-IF to ELSEIF, and END-DO to END FOR (see Loops and Indexes)

4.    Operators are changed:  EQ to =, NE to <>, LT to <, LE to <=, GT to >, and GE to >=, AND to &, OR to |.

For example

  IF I-ID = '01' +

  AND I-FLAG = 'S'

     IF I-CLIENT = T-CLIENT +

     AND I-POLICY = T-POLICY

     ELSE

becomes

IF I-ID = '01' & I-FLAG = 'S';

IF I-CLIENT = T-CLIENT & I-POLICY = T-POLICY;

ELSE;

This converts Easytrieve into something close to Jazz, but differences remain where Easytrieve and Jazz use different statements and concepts.  [Convert] then attempts to make the statement-specific changes to bridge the gap.  

You may have to complete the job by editing the result, either here or in the Jazz Workbench.  The Easytrieve Conversion Notepad recognizes words, punctuation, and operators, but it does not recognize data.  Thus, it does not know what words like I-CLIENT refer to, and so whether the reference is valid or there is an issue such as a missing subscript or definition.

The following are various statement-specific changes that may be made.  In some cases, you’ll need to help out with some editing.

PUT

PUT is changed to WRITE, and the file name is checked, and will be changed if it would not be valid for COBOL and z/OS.

For example,

            PUT TEMP-1

becomes

COPY TEMP1;

WRITE TEMP1;

FROM can be used, e.g.

            PUT TEMP1 FROM INPUT

becomes
      WRITE TEMP1 FROM(INPUT);

avoiding the necessity of writing
      TEMP1 = INPUT;

before the WRITE statement.

File names like TEMP-1 and OUTPUT that are invalid for COBOL are changed (to TEMP1 and OUTPUT1 respectively) to make them valid.  This reflects the changes that would have been made when the data definitions were converted by New/Data/Import from Easytrieve.

Conditions

All the conditions in Easytrieve Example 1 are converted properly, but not all conditions can be.  Easytrieve list and THRU conditions may cause problems, and also conditions with NUMERIC and others that don’t appear to have any comparison operator.  Conditions for Synchronised File Processing (PROCESS … MERGE in Jazz) like IF DUPLICATE and IF FILE1 are different and will probably need editing.

Easytrieve allows list conditions with = and a list of values.  For example

IF ACCOUNT = 6522 6524 6529 6530 6543 6544 6545 6548 6549 6666

The Jazz equivalent of this is a SQL-like IN comparison, in which the values are separated by commas: -

IF ACCOUNT IN(6522,6524,6529,6530,6543,6544,6545,6548,6549,6666)

EASYTRIEVE also allows range conditions like    

IF ACCOUNT = 6571 THRU 6579

The Jazz equivalent of this is BETWEEN: -

IF ACCOUNT BETWEEN 6571 AND 6579

Conditions like these are handled automatically by [CONVERT].  

Invalid Conditions

If Easytrieve conditions can’t be converted automatically, message #681, “Condition will need to be edited” is produced.   This message will occur if

·         list and THRU conditions are combined

·         Most conditions associated with Synchronized File Processing

Combining List and THRU conditions

If the Easytrieve condition combines both forms, as in

IF ACCOUNT = 6522 6524 6529 6530 6543 THRU 6548 6549 6666

then [Convert] will produce message #681

IF ACCOUNT IN(6522,6524,6529,6530,6543,THRU,6548,6549,6666);

#681 S Condition will need to be edited

You need to separate out the THRU condition so that this becomes

IF (ACCOUNT IN(6522,6524,6529,6530,6549,6666) OR ACCOUNT BETWEEN 6543 AND 6548);

It is strongly recommended that any edited condition containing an OR is enclosed in parentheses.  This condition

        IF  ACCOUNT = 6507 6640 6642 THRU 6649 6801 +

        AND COMP    = 'NINZ' 'IISZ'

converts to

IF ACCOUNT IN(6507,6640,6642,THRU,6649,6801) & COMP IN('NINZ','IISZ');

#681 S Condition will need to be edited

This is edited to the following.  The condition would be incorrect without the highlighted parentheses.

IF (ACCOUNT IN(6507,6640,6801) | ACCOUNT BETWEEN 6642 AND 6649) & COMP IN('NINZ','IISZ');

File Status Conditions

EZT READ statements are often followed by logic testing FILE-STATUS.  For example

READ VSAM1 KEY WS-KEY, STATUS                                                   

IF FILE-STATUS(VSAM1) NOT ZERO

These two statements are converted into

GET VSAM1 WHERE($KEY = WS-KEY);

IF VSAM1.$FOUND <> 0;

#679 E FILE-STATUS condition can't be automatically converted. See https://tinyurl.com/rjvtm2kj    

The IF condition is invalid because $FOUND is a BOOLEAN value, and can only be TRUE or FALSE.    Change the statement to

            IF VSAM1.$FOUND = FALSE;

In Jazz this will become

    GET VSAM1 WHERE(VSAM1.KFLD = EZT-Sample5-Data.WS-KEY);

    IF VSAM1.$FOUND = false;

If the condition had been

IF VSAM1.$FOUND = 0;

then the correct code would have been either

            IF VSAM1.$FOUND = TRUE

or you can omit “= TRUE” and simply write

            IF VSAM1.$FOUND

For sequential reading (EZT GET statements) the relevant flag is called $ENDFILE.  For example

  GET VSM1

  IF NOT EOF VSM1

Is converted to

        GET VSM1 NEXT;

        #707 E Consider using PROCESS instead of GET VSM1 NEXT

        IF VSM1.$Endfile = False;

But as message #707 notes, changing the logic to use PROCESS which has the relevant status checking built in, is better.  See GOTO below.

A general note about status code checking

MANASYS Jazz is already looking after status code checking, and in almost all cases it’s better to simply remove EZT status checking from your program and leave it to Jazz.

Jazz provides four I/O statements,  PROCESS, GET, WRITE, and DELETEPROCESS reads a collection of records sequentially, GET is used for direct access and update, WRITE is used to create new data, and DELETE deletes a record.  The same statements, sometimes with minor variations, are used whatever the file organization: for example PROCESS Table WHERE (…) might be reading a sequential file, a VSAM file or a SQL table. 

Notice that there is usually no separate UPDATE statement, and you update a file with

            PROCESS file WHERE (condition) UPDATE;

                Statements that might update the data

            END PROCESS file UPDATE;

Similarly, 

            GET file WHERE (condition) UPDATE;

                …

            END GET file UPDATE;

The generated COBOL logic knows when to use an UPDATE statement (REWRITE or EXEC SQL UPDATE …), or INSERT (WRITE or EXEC SQL INSERT …).

The only use of UPDATE as a separate statement are to turn an update off: for example: =

            PROCESS file WHERE (condition) UPDATE;

                Statements that might update the data

    IF Some Condition;

        UPDATE file CANCEL;

    END IF;

            END PROCESS file UPDATE;

All statements have built-in status code checking, and Jazz handles the result in one of three ways: -

1.    Perfect (status code 0).   The record that you want has been returned without error.

2.    Expected exception:  Endfile, record not found, etc.  Your program continues normally; the results are defined, and you can test for the condition with $Found, $Endfile, etc.  For example

                        IF RUNCNTL.$FOUND;

3.    Catastrophic error.  The program can’t continue: the file is not defined, the definition doesn’t agree with the data that you’re trying to get, etc.  These sorts of errors will be reported and your program will terminate.

DUPLICATE Conditions

Easytrieve DUPLICATE conditions have almost the same syntax in Jazz, e.g.
            IF DUPLICATE TRAN
will become
            
IF DUPLICATE TRAN
in Jazz.  However, Jazz and Easytrieve DUPLICATE conditions are not the same: -

1.    EZT DUPLICATE conditions are true when the previous or next record has the same key as the current record.   A Jazz DUPLICATE condition compares the record keys of the current and previous records, but not the next record (and so is always false for the first record for this key value).  

2.    A Jazz DUPLICATE condition is not restricted to PROCESS … MERGE (synchronized file processing), but may be written anywhere that makes logical sense.

3.    In Jazz, the object of the DUPLICATE test (e.g. TRAN) does not have to be a keyed file.  If the object is not keyed, then the whole object is compared.  For example,
      
IF DUPLICATE TABL.ROW(JZ.IX);
might be used within a loop to check for duplicates within a table.

4.    Jazz does not support FIRST-DUP and LAST-DUP.  EZT examples so far suggest that these are unnecessary with Jazz MERGE logic, but see below.

5.    EZT DUPLICATE tests seem to be related to the Job loop (not clear), so the True/False value of IF DUPLICATE may not be affected by any logic within the loop that might change the key values. A Jazz DUPLICATE test explicitly occurs at the point where it is written, and another test might return a different result if key values have been changed.

6.    EZT DUPLICATE tests can be part of a more complex condition: for example
      
IF DUPLICATE TRANS AND NOT FIRST-DUP TRANS
JAZZ DUPLICATE conditions must not be preceded by NOT, and may not be combined with other tests.  However, you can save the result and use this like any other BOOLEAN field
      
JZ2.FLAG1 = DUPLICATE TRANS;
      
IF JZ2.FLAG1 & TRANS.REGION = 23;

Refer to https://www.jazzsoftware.co.nz/Docs/JazzLRMConditions.htm#Duplicate for more information about Jazz DUPLICATE comparison.

Handling FIRST-DUP and LAST-DUP

MANASYS rejects FIRST-DUP and LAST-DUP comparisons. For example

        IF FIRST-DUP EINGABE;

            #029 E 'FIRST-DUP' is invalid here

            #199 S FIRST-DUP:Reference to a field expected

            #105 S Comparison operator missing

            EZT-ERESARA2-Data.RF-1 = 0;

            EZT-ERESARA2-Data.RF-2 = 0;

            EZT-ERESARA2-Data.RF-3 = 0;

            EZT-ERESARA2-Data.RF-4 = 0;

        END IF;

We don’t need this logic, we can simply remove it.  MANASYS always initializes working-data fields, almost always to ZERO or SPACES, as it has here.

If you ever do need first-time logic anywhere in your program you can simply use another flag.  BOOLEAN fields are always initialized False, so this logic is equivalent to the above when IF FIRST-DUP EINGABE is replaced with the two highlighted lines: -

        IF JZ2.FLAG2 = False;

JZ2.FLAG2 = True;

            EZT-ERESARA2-Data.RF-1 = 0;

            EZT-ERESARA2-Data.RF-2 = 0;

            EZT-ERESARA2-Data.RF-3 = 0;

            EZT-ERESARA2-Data.RF-4 = 0;

        END IF;

Similarly, Jazz doesn’t provide a LAST-DUP comparison operator. Here is part of an EZT program: -

JOB INPUT (EINGABE KEY (…)) FINISH TRAILER                           

IF NOT DUPLICATE EINGABE                                                       

ELSE                                                                           

   IF …

   ELSE                                                                        

     

      IF LAST-DUP EINGABE                                                      

         Some processing

      END-IF                                                                   

   END-IF                                                                      

END-IF                                                                         

        

Some processing in IF LAST-DUP …  END-IF is logic that will be performed for the last duplicate.  However, there is no way that IF LAST-DUP within the PROCESS loop will know whether this is the last duplicate – there may be further duplicates, or there may be following records that are not duplicates.  We have to move Some processing to follow the PROCESS loop because only then will we know that there are no more duplicates following, but also fool the moved logic into thinking it has just read the last duplicated record. Here’s how we solve this problem: -

1.    Define a copy of EINGABE: -

DEFINE EINGABE2 LIKE EINGABE TYPE WORK;

2.    Replace IF LAST-DUP EINGABE; with

EINGABE2 = EINGABE;

3.      Follow END PROCESS with the reverse assignment
EINGABE = EINGABE2;

4.      Move Some processing from its original location to follow this

5.    Remove the END IF that previously balanced IF LAST-DUP EINGABE to restore the IF/END IF balance.

 

The converted logic of this program now looks like this: -

PROCESS EINGABE SKEYS ( ) SID(19);

    ..

    IF JZ2.FLAG1 = False;

    ELSE;

           

            EINGABE2 = EINGABE;  <= This replaces IF LAST-DUP/ Some processing /END IF;

    END IF;

END PROCESS EINGABE;

EINGABE = EINGABE2;

Some processing 

 

Other Synchronized File Processing Tests

Easytrieve synchronized file processing provides tests MATCHED and Filename, as in this example: -

JOB INPUT (OLDMSTR KEY(O-KEY) TRANS KEY(T-KEY)) NAME MYPROG

 * FOR MATCHED: UPDATE WITH TRAN AMT AND PUT NEWMSTR.

 IF MATCHED

 END-IF

 * ON OLDMSTR ONLY: PUT THE NEWMSTR WITHOUT ANY UPDATE.

 IF OLDMSTR

 END-IF

 * ON TRANS ONLY: PRINT ERROR REPORT.

 IF TRANS

 END-IF

The equivalent comparisons in Jazz use the special values $CMergeOut and $CMerge.

Refer to https://www.jazzsoftware.co.nz/Docs/JazzLRMConditions.htm#SpecialValues for more information about these Jazz special values.  The Conversion Notepad automatically converts MATCHED to IF $CMergeOut = 0, but because the Conversion Notepad doesn’t have access to the data definitions it can’t tell which of OLDMSTR and TRAN are the first file, so it doesn’t know that the correct conversions are: -
            
IF OLDMSTR to IF $CMergeOut < 0; 
and      IF TRANS to IF $CMergeOut > 0; 

The conditions are left in their original form: you will need to edit them for yourself.

Searching Tables

EZT SEARCH statements are converted to Jazz SEARCH statements which have a very similar syntax.  For details of SEARCH see  https://www.jazzsoftware.co.nz/Docs/JazzUGEZTData.htm#ExternalTables, and for the full definition of the search statement see https://www.jazzsoftware.co.nz/Docs/JazzLRM_SEARCH.htm.  

Obviously an external table will have to be loaded at the start of the program so that there is some data to search.   Jazz can create these load procedures for you: see https://www.jazzsoftware.co.nz/Docs/JazzWKLProc.htm to find out how to do this.

Loops and Indexes

Loops (DO in Easytrieve, FOR in Jazz) cause issues that may require you to help out with editing.  EZT DO statements may convert to invalid Jazz.  Even if they don’t you should understand the differences between EZT and Jazz loops, and the purpose of the EZT logic.  

Also, you will often find loops written to search tables, or to load them.  You don’t even want the loop code for searching: delete it, and use a SEARCH statement.  You don’t want the EZT code to load the table, instead have Jazz create the load procedure for you (click [LProc], the next button to the right of [EZT Conv]).

Even in cases where DO logic is converted to a valid FOR statement you should check the Jazz logic that results. For example: -

Easytrieve Example 1 used a file whose definition included

FILE INFILE1 DISK VS (ES)

I-MULTI            36   68 A OCCURS 4 INDEX IX-A

I-MULTI-POL I-MULTI +20 06 A

The Data in I-MULTI was processed with this loop: -

IX-A = 0

W-CTR = 0

DO WHILE W-CTR < 4

   W-CTR = W-CTR + 1

   IX-A = IX-A + 68

END-DO

There are three issues with this: -

1.    MANASYS loop syntax is different to Easytrieve.  MANASYS uses FOR, not DO. See https://www.jazzsoftware.co.nz/Docs/JazzLRM_FOR.htm.  [Convert] will change DO to FOR and END-DO to END FOR; but produces

FOR WHILE W-CTR < 4

which becomes this when it is copied into Jazz

FOR WHILE EZT-EXAMPL1-Data1.W-CTR < 4;

There are no error messages, and it looks valid, but it’s not!

2.    BEWARE:  Easytrieve index variables are NOT the same as COBOL (or JAZZ) index variables, so IX-A = IX-A + 68 is wrong in COBOL (and Jazz).   An index (if Jazz used it) would vary from 0 to 3, or a subscript (which Jazz DOES use) would vary from 1 to 4.  The correct substitution is

     FOR JZ2.IX1 = 1 TO 4;

3.    All references to repeating fields MUST be subscripted.   Whenever there is a reference to I-MULTI or I-MULTI-POL the reference must be subscripted, with a subscript value of 1 to 4.  Thus Easytrieve

T-POLICY = I-MULTI-POL

becomes

   T-POLICY = I-MULTI-POL(IX1);

which Jazz qualifies to

TEMP1.T-POLICY = INFILE1.I-MULTI-POL(JZ2.IX1);

[Convert] attempts to convert this loop, producing

IX-A = 0;

W-CTR = 0;

FOR WHILE W-CTR < 4;

    …

    W-CTR = W-CTR + 1;

    IX-A = IX-A + 68;

    END FOR;

Remove the highlighted statements, and change the FOR loop to

FOR IX1 = 1 TO 4;

or    FOR I-MULTI(IX1);

Refer to The FOR Statement for more details.  IX1 is a counter provided automatically by Jazz, qualified to JZ2.IX1, so we don’t need to define it.   Whichever form of loop we’ve used, the loop variable is incremented by the FOR/END FOR.  

NEVER try to change the value of the loop variable with explicit assignments.  At best you’re doing something harmless that will be ignored, at worst your attempt to control the loop will interfere with the generated logic causing errors.

References to I-MULTI and fields within it like I-MULTI-POL will need to be subscripted, but this is best done after we’ve copied the converted code into the Jazz workbench.  The Easytrieve Conversion Notepad is aware of Jazz syntax, but it doesn’t have information about data definitions so it can’t tell whether IX1 is a variable or not, or whether I-MULTI-POL needs a subscript.  When the “converted” text is copied into the Jazz workbench the program dictionary is available and data-related errors can be detected, and so error messages will ensure that we won’t miss any of the required subscripts. Example1 after Correction shows the finished program.  Example 1 after [Exit] shows the program with only the changes above: it looks dreadful because it has so many errors, but actually there only 2 errors, a missing definition, and subscripts needed for each I-MULTI-POL reference.

Valid FOR statements from DO

Here is an example where Easytrieve’s DO logic is converted into a valid FOR statement. Even in this case you must check the resulting Jazz logic for potential errors.

WI-IX1 = 1

DO WHILE WI-IX1 LE WA-DIST-COUNT-EXPECTED

  VS-DIST-ID = WG-DIST1(WI-IX1)

...

  WI-IX1 = WI-IX1 + 1

END-DO

When you click [Convert] the EZT Conversion Notepad recognizes the situation
            Field = 1
followed by
            DO WHILE Field LE Limit
so it knows that it can combine these two statements into a FOR statement of the form
            
FOR Field = 1 TO Limit;

The test is quite specific.  First there must be an assignment Field = 1.  Not any other value, or Field = AnotherFieldWithValue1. And the NEXT statement must have the form DO WHILE Field LE Limit. Limit could be a constant or a field.

If these conditions are met then a valid FOR statement will be generated, and also

If the statement before END-DO has the form Field = Field + 1, e.g.
            
WI-IX1 = WI-IX1 + 1
it won’t be needed, and will be discarded.

And finally, Field should be a SMALLINT field.  If it has some other format, say PIC 999’, you will get messages from Jazz, and the COBOL will compile to less efficient code.

So, combining all this, [Convert] changes the EZT into

FOR $IX=1 TO WA-DIST-COUNT-EXPECTED;

WI-IX1=$IX; [If only reference to WI-IX1, may be removed]

#688 S Check Loop Logic: see https://tinyurl.com/22yfseeh

VS-DIST-ID = WG-DIST1($IX);

VS-PROG-ID = WP-ORIG-ID;

END FOR;

[Exit] inserts this into Jazz, converting $IX into one of the predefined SMALLINT fields in JZ2: -

    FOR JZ2.IX=TO EZT-AAP21BE-Data.WA-DIST-COUNT-EXPECTED;

        EZT-AAP21BE-Data.WI-IX1=JZ2.IX[If only reference to WI-IX1, may be removed]

        RUNCNTL.VS-DIST-ID = EZT-AAP21BE-Data.WG-DIST1(JZ2.IX);

        RUNCNTL.VS-PROG-ID = EZT-AAP21BE-Data.WP-ORIG-ID;

    END FOR;

You should check for potential errors.  Particularly as, in a large EZT program you won’t convert all of the logic at once but you’ll copy/paste it into the Conversion Notepad and [Convert] it in chunks.  For example, you will probably convert each procedure individually. 

1.    In case the routine logic includes a PRINT or PERFORM to logic that expects the value of WI-IX1 to be set by this loop, the logic above has added this assignment just after FOR
        EZT-AAP21BE-Data.WI-IX1=JZ2.IX[If only reference to WI-IX1, may be removed]

If there are no other references to WI-IX1, this assignment will be irrelevant and quite harmless. You can check and remove it if you wish.

2.    What if the loop variable, JZ2.IX, is used for something else in this program?  These uses may conflict.  For example, the loop above might be within a ROUTINE invoked by PERFORM that uses JZ2.IX for an unrelated purpose, perhaps controlling another loop.  Or conversely, the logic in the above loop might PERFORM a ROUTINE that includes unrelated use of JZ2.IX.

This should not happen because each cycle of
      Copy-EZT-to-conversion-notepad/
      [Convert]/Insert-into-Jazz
should convert $IX to a different
JZ2.IXn variable, but this can’t check that you haven’t used the IXn field for some unrelated function.  If there are any possible conflicts you should check all uses of JZ2.IX fields, and use separate variables to resolve conflicts if necessary.  Field names IX, IX1 to IX10, IXA to IXZ, and 3 more are predefined for you, so you should have plenty of names to choose from.

DISPLAY statements

An EZT DISPLAY statement may look like this: -
            DISPLAY SYS012 E1-SATZ +1 'F1: VK nicht gefunden' +1 V05-LEV
where SYS012 is the report file on which this data is to be displayed.   Another feature is the use of +1 to insert extra space between the adjacent items.

Where EZT places the report file as the first item of the data list, the Jazz (and COBOL) approach is to put this in an UPON option
            DISPLAY (data list) UPON SYS012;

However the UPON name must be one of the special COBOL names like SYSOUT, SYSLIST, etc. EZT conversion will change this to
            DISPLAY (data list) UPON SYSLIST;
and, for the first use of SYS012, create a REPORT statement
            REPORT NAME('SYSLIST') DISPLAY EZTNAME('SYS012');

Positive space adjustment like +1 is changed to ' ' for the relevant number of spaces.

GO TO statements

Jazz does not provide labels, so any GO TO label statements are reported as errors and need to be replaced by structured logic.  

GO TO JOB is valid if the statement is within the PROCESS loop: it is converted to CONTINUE PROCESS; This causes the loop to cycle, immediately branching to END PROCESS and then continuing from the top with the next record.  You may still need to edit the Jazz program: see https://www.jazzsoftware.co.nz/Docs/JazzLRM_CONTINUE.htm for more information.

If GO TO JOB is within a lower-level procedure, then it can’t be converted to CONTINUE PROCESS, and instead is converted into EXIT Proc.  This terminates the routine, but does not cause the controlling PROCESS loop to immediately continue with the next record.   To make this happen, you’ll need to set a flag to tell the invoking logic to cycle the controlling loop.   For example, in this program there was a GO TO JOB within R1, subject to condition IF REGION = 5.  R1 would have terminated if IF FR.Region = 5 is true, but the PROCESS loop would have continued with *   More logic. The highlighted Jazz statements were added so that the program behaves as intended, bypassing *   More logic for this record.   

PROGRAM Batch1 BATCH;

COPY FR;

PROCESS FR;

*   Logic    

    PERFORM R1;

    IF JZ2.FLAG1 = True THEN;

        CONTINUE PROCESS;

    END IF;

*   More logic

END PROCESS FR;

ROUTINE R1;

    JZ2.FLAG1 = false;

* Routine logic 1

    IF FR.Region = 5;

        JZ2.FLAG1 = true;

        EXIT R1;

    END IF;

* More routine logic

END ROUTINE R1;

GO TO Label is always invalid, as Jazz does not support GOTO statements and labels.   You should find a structured way of expressing the same logic.  For example, this Easytrieve logic: -

START-PROC. PROC.

GETIT.

  GET VSM1

  IF NOT EOF VSM1

    TAB-INDEX = TAB-INDEX + 1

    T-XYZ  (TAB-INDEX) = V-XYZ

    T-TP (TAB-INDEX) = V-TP

    IF V-TP = 'X'

      IF V-XYZ > '1234'

       T-TP(TAB-INDEX) = 'Y'

      END-IF

    END-IF

    GOTO GETIT

  END-IF

 END-PROC.

converts to this Jazz, leaving you with several issues to be dealt with: -

ROUTINE START-PROC;

        GETIT;

    #033 S 'GETIT' Not found

    #029 E 'GETIT' is invalid here

    GET VSM1 NEXT;

    #707 E Consider using PROCESS instead of GET VSM1 NEXT

    IF VSM1.$Endfile = False;

        #029 E 'VSM1.$Endfile' is invalid here

        #623 S Expression ends with operator =

        #199 S VSM1.$Endfile:Reference to a field expected

        #199 S =:Reference to a field expected

        EZT-INDEX.TAB-INDEX = EZT-INDEX.TAB-INDEX + 1;

        EZT-RPTTLY02-Data.T-XYZ (EZT-INDEX.TAB-INDEX= VSM1.V-XYZ;

        EZT-RPTTLY02-Data.T-TP (EZT-INDEX.TAB-INDEX= VSM1.V-TP;

        IF VSM1.V-TP = 'X';

            IF VSM1.V-XYZ > '1234';

                EZT-RPTTLY02-Data.T-TP(EZT-INDEX.TAB-INDEX= 'Y';

            END IF;

        END IF;

            GOTO GETIT;

        #684 S GOTO Statements not supported

        #029 E 'GOTO' is invalid here

    END IF;

END ROUTINE START-PROC;

You could solve the problem of GOTO GETIT by enclosing the logic in a FOR loop, like this: -

ROUTINE START-PROC;

    FOR JZ2.IX = 1 STEP 1 UNTIL VSM1.$ENDFILE = true;

        GET VSM1 NEXT;

        #707 E Consider using PROCESS instead of GET VSM1 NEXT

        IF VSM1.$Endfile = False;

            EZT-RPTTLY02-Data.T-XYZ (JZ2.IX ) = VSM1.V-XYZ;

            EZT-RPTTLY02-Data.T-TP (JZ2.IX ) = VSM1.V-TP;

            IF VSM1.V-TP = 'X';

                IF VSM1.V-XYZ > '1234';

                    EZT-RPTTLY02-Data.T-TP(JZ2.IX ) = 'Y';

                END IF;

            END IF;

        END IF;

    END FOR;

END ROUTINE START-PROC;

But what the logic above has done is to explicitly write the logic of a PROCESS loop.  Just write one, it’s simpler, more flexible, and more efficient.

ROUTINE START-PROC;

    JZ2.IX = 0;

    PROCESS VSM1 SID(26);

        JZ2.IX += 1;

        EZT-RPTTLY02-Data.T-XYZ (JZ2.IX ) = VSM1.V-XYZ;

        EZT-RPTTLY02-Data.T-TP (JZ2.IX ) = VSM1.V-TP;

        IF VSM1.V-TP = 'X';

            IF VSM1.V-XYZ > '1234';

                EZT-RPTTLY02-Data.T-TP(JZ2.IX ) = 'Y';

            END IF;

        END IF;

    END PROCESS VSM1;

END ROUTINE START-PROC;

Direct Access: READ

An Easytrieve READ statement is changed to a Jazz GET.   The Conversion Notepad converts

READ INNKEY KEY W-KEY STATUS

into
      GET INNKEY WHERE($KEY = W-KEY);

When this is copied into the Jazz workbench, $KEY appears to be invalid, and messages #29, and #425 are produced, but the problem is fixed and message #678 is also produced. 
 
    GET INNKEY WHERE(INNKEY.K-RECORD = INNKEY-WS.W-KEY);

    #029 E '$KEY' is invalid here

    #678 E $KEY has been replaced.  Click [Check] again

    #425 S = is not a valid comparison operator

Simply click [Check] and all these messages disappear: -

    GET INNKEY WHERE(INNKEY.K-RECORD = INNKEY-WS.W-KEY);

Status Checking following READ

Usually a READ statement is followed by logic to check whether a record was found or not.   This logic may be unnecessary: if its purpose is to just initialize the record when no record is found, then GET logic will have done this already and you can simply delete the EZT IF logic.   If the test is necessary: -  

IF FILE-STATUS EQ ZERO

   …

END-IF

[Convert] changes this to the equivalent Jazz IF statement

IF INNKEY.$FOUND;

Negative test, or tests for values other than zero, for example

IF INNKEY:FILE-STATUS NE ZERO

become

    IF INNKEY.$FOUND = FALSE;

If there are Easytrieve syntax errors or [Convert] can’t handle the condition for any reason then it will produce message #679: -

IF FILE-STATUS(INNKEY) ZERO

becomes

    IF INNKEY.$FOUND(INNKEY) 0;

    #679 E FILE-STATUS condition can't be automatically converted

If you don’t correct these errors in the Conversion Notepad further errors will be reported when the “converted” text is inserted into your Jazz program.

Updating Records

Easytrieve and Jazz update logic is different, and you can’t simply convert the EZT statement to Jazz statements.  For example: -

UPDATE-EM. PROC.

E-EM = X-EM

E-LN = X-LN

E-FN = S-FN

E-KEY   = S-KEY

READ EM KEY E-KEY, STATUS

IF FILE-STATUS (EM) NE 0

WRITE EM ADD                        

ELSE

WRITE EM UPDATE                  

END-IF

END-PROC

The VSAM file, and the input fields will have been defined. For illustration: -

DEFINE EM VSAM DATA(

    E-KEY CHAR(4) CAPS KEY,

    E-EM CHAR(5),

    E-LN SMALLINT,

    E-FN CHAR(1))

    DSNAME 'JAZZUSR.VSAM.EM';

DEFINE X DATA(

    X-EM CHAR(5),

    X-LN SMALLINT);

DEFINE S DATA(

    S-FN CHAR(1),

    S-KEY CHAR(4));

When you attempt to convert the EZT with the Conversion Notepad, you get messages from each of the WRITE statements: -

ROUTINE UPDATE-EM;

E-EM = X-EM;

E-LN = X-LN;

E-FN = S-FN;

E-KEY = S-KEY;

GET EM WHERE($KEY = E-KEY);

IF EM.$FOUND  <> 0;

#679 E FILE-STATUS condition can't be automatically converted

WRITE EM ADD;

#706 E Manual Conversion May Be Necessary: See https://tinyurl.com/2s4xz4vt

ELSE;

WRITE EM UPDATE;

#706 E Manual Conversion May Be Necessary: See https://tinyurl.com/2s4xz4vt

END IF;

END ROUTINE UPDATE-EM;

The reason for this is that update logic of Easytrieve and Jazz is very different.  The above routine cannot be converted automatically by the Conversion Notepad, but it is easily converted manually.  Here’s how. 

In spite of the error messages, copy the “converted” EZT into Jazz.  It at least establishes the ROUTINE structure, and some of the statements will be useful when they’re moved to their correct place, although most of the statements will be removed.  I’ve highlighted the lines that will be deleted: -

ROUTINE UPDATE-EM;

    EM.E-EM = X.X-EM;

    EM.E-LN = X.X-LN;

    EM.E-FN = S.S-FN;

    EM.E-KEY = S.S-KEY;

    #361 E Assignment to a key field

    GET EM WHERE(EM.E-KEY = EM.E-KEY);

    #201 E Reference to a field outside the current record expected

    IF EM.$FOUND  <> 0;

        #394 E Value incompatible with $Found

        WRITE EM(ADD);

        #035 S ADD not found

        #348 W VSAM file must be empty

        #508 S ADD not found.  Did you mean ADD.*?

        #155 S FROM item has wrong type

    ELSE;

        WRITE EM ;

        #348 W VSAM file must be empty

        UPDATE;

    END IF;

END ROUTINE UPDATE-EM;

1.    Change the GET statement.  Firstly, it must name the source value to assign to the key.  Secondly, it should include UPDATE, and there should be an END GET statement.  We change the statement to: -

    GET EM WHERE(EM.E-KEY = S.S-KEYUPDATE;

    END GET EM UPDATE;

The file will be updated at END GET EM UPDATE. The logic knows whether this is a new or existing record, so whether WRITE or REWRITE is needed in COBOL. 

2.    Move the first three assignments so that they come between GET and END GET.   We don’t need the fourth assignment, as the WHERE clause already handles this. 

3.    Simply delete the lines from IF EM.$FOUND  to END IF.

Here is our converted logic: -

ROUTINE UPDATE-EM;

    GET EM WHERE(EM.E-KEY = S.S-KEYUPDATE;

        EM.E-EM = X.X-EM;

        EM.E-LN = X.X-LN;

        EM.E-FN = S.S-FN;

    END GET EM UPDATE;

END ROUTINE UPDATE-EM;

Easytrieve Procedures

Easytrieve procedures start with labelled PROC statement, and finish with END-PROC: -

LAST-REC. PROC

END-PROC

This gets converted to a Jazz ROUTINE, becoming

ROUTINE LAST-REC;

    …

END ROUTINE LAST-REC;

Apart from the semicolon, PERFORM has the same format in Easytrieve and Jazz.

Each PROC is a natural chunk, so you’ll probably convert each independently.  As you do, the list of #476 messages like
            #476 S No ROUTINE for PERFORM L1AC-END
at the end of the program will change: the #476 message above will go, but new ones may appear because of 
PERFORM within LAST-REC.  The best way to handle PROCs is to work through the list of #476 messages until there are none, rather than working top-to-bottom down the EZT source.  It is common to find that a few of the PROCs are no longer needed.

EZT DLI Statements

The EZT DLI statement is used for all I/O operations involving DL1.  Here are couple of examples: -

DLI V05 V05P2A 'GHU ' SSA SV05P1A SV05P2A

IF V05-STC SPACE

  V2-KZSTATUS = '4'

  V2-STATDAT  = W-DATE

  DLI V05 V05P2A 'REPL'

This is a common format:  DLI PSBName Segment Operation [SSA Name [name]… ].  The first statement above requires the program to execute a “Get Hold Unique” operation to read a unique V05P2A segment from the database accessed through PSB V02. The key values required are described by the SSAs  SV05P1A and SV05P2A.  A GET operation may or may not find a record with these key values, so immediately after DLI the status code (field V05-STC within  V05) is tested:  SPACE means that a record was found. If the record was found it is held exclusively by this program: no other program can read or update it until the hold is released by a later DLI statement, or this program’s termination. 

A successful GET is followed by a couple of statements updating the V05P2A segment, and then DLI V05 V05P2A 'REPL' replaces the old V05P2A record in the database with the updated record, and releases the Hold. 

Jazz uses PROCESS, GET, UPDATE, and DELETE for I/O operations: Jazz works out which is needed and generates one from the DLI statement.  When relevant, Jazz I/O statements may have an SSA option naming Segment Search Arguments.  The SSAs will have been defined in the program’s data (as here) or be string constants with the correct format to be an SSA. 

The above code is converted to

            GET V05P2A UPDATE SSA(EZT-OAADN6MN-Data.SV05P1A,EZT-OAADN6MN-Data.SV05P2A);

            IF V05.V05-STC = SPACE;

                V05P2A.V2-KZSTATUS = '4';

                V05P2A.V2-STATDAT = EZT-OAADN6MN-Data.W-DATE;

                UPDATE V05P2A ;

            END IF;

The Jazz statements don’t need to give the PSBName, in this case V05, because that’s given in

            PROGRAM OAADN6MN BATCH DATABASE V05 DL1 EZT;

and will be the same for all DL1 I/O statements in this program.  Note that with DL1 UPDATE and DELETE statements actually cause DL1 segments to be updated or deleted, unlike the syntax that is normal for other data types, where UPDATE is an option of the PROCESS or GET statement and the actual update operation occurs at the corresponding END PROCESS or END GET statement.

Printing and Reports

Easytrieve and Jazz have different concepts for printing data. 

Easytrieve PRINT prints a named report.  Each report may contain several lines, and may define its own sequence and control breaks.   Which fields are summed may be implicit, or explicitly specified with a SUM statement. SEQUENCECONTROL, and SUM are all statements within a Report definition, and an Easytrieve program may define two or more reports with different sequences.  A report definition can include special-name procedures, such as

    BEFORE-BREAK. PROC

          RAISE-PCT = RAISE-PCT / TALLY

    END-PROC

In this case using AVG in your PRINT statement solves the problem.  If TALLY is used implicitly or explicitly, the corresponding PROCESS statement must include the TALLY option.  When PROCESS statements are generated by EZT conversion they will always include this option, just in case it is needed.

 

In Jazz, PRINT prints some data: it is more like Easytrieve’s LINE statement than its PRINT.  Ordering and control breaks are properties of the PROCESS statement that manages the I/O loop, so that while a Jazz program may produce several reports, they all have to use the same sequence and control breaks if they are within the same PROCESS loop.  Fields are summed if they have the SUM attribute in the PRINT statement.   Jazz does not support special-name procedures.  

These differences have consequences.  In particular, if you need to print reports in different sequences then multiple PROCESS loops are needed. EZT conversion will handle this issue for you, as we’ll see with program PRTEX3 in Example3

Example 1.

An Easytrieve program contained several

PRINT HO-REPORT

statements, and REPORT defined by

REPORT HO-REPORT PRINTER REPORT1 DTLCTL EVERY SUMCTL NONE NOADJUST

TITLE 1 'SCHEDULE OF INPUT FOR MSA GENERAL LEDGER - MSAB910.'

LINE  1  O-RECORD-PRT

END 

The REPORT statement will become a Jazz REPORT statement, and the TITLE statement becomes a TPRINT statement. EZT LINE statements are converted to JZPRINT statements, which become PRINT statements when they’re copied into the Jazz program.  (This trick avoids issues in the Conversion Notepad where it needs to distinguish between EZT PRINT and Jazz PRINT).

Converting the REPORT above, and copying it into the Jazz program, results in a REPORT statement, added at the *# Copy Files here ==> marker: -
            
REPORT(1) NAME 'HOREPORT';

A routine named HOREPORT is added at the *#Copy Routines here ==> marker.   (The routine name has been changed by MANASYS so that it is valid for COBOL and JCL).

ROUTINE HOREPORT [Report];

    TPRINT(1,'SCHEDULE OF INPUT FOR MSA GENERAL LEDGER - MSAB910.');

    PRINT (R1.O-RECORD-PRTLINE(1);

END ROUTINE HOREPORT;

Example 2

This example illustrates issues of control breaks and subtotaling, combined with using a Report routine.

 

An EZT report was defined

PRINT REPE

REPORT REPE

SEQUENCE REGION DISTRICT

CONTROL REGION DISTRICT

TITLE 'Printed at:' $Today COL 58 'Program AanexmlE' +

    COL 121 'PAGE ' $PageNbr

LINE Region District Name SalesThisMonth Datecommenced

This example is going to be inserted into this test program, which is based on the familiar Aanexmpl example (see Manasys Jazz Initial Demonstration): -

*# Last Updated by JAZZUSR at 6/07/2023 2:53:02 PM

PROGRAM AanexmlE BATCH EZT;

COPY IN1;

#388 E FR.Region and IN1.Region have different types

*# Copy Files here ==>

PROCESS IN1 WHERE(IN1.Region = 1 | IN1.Region=6) SID(23);

    GET FR WHERE (FR.Region = IN1.Region);

*#Copy Process logic here ==>

END PROCESS IN1;

*#Copy Routines here ==>

SEQUENCE and CONTROL specify that the data is sequenced by DISTRICT within REGION.  Subtotals will be printed on control break (change of either REGION or DISTRICT and grand totals will be printed at the end.  Issues here are that in Jazz: -

·         The equivalent of CONTROL belongs to PROCESS, not REPORT.

·         SUM is not a separate statement; it is a property of individual items in the PRINT statement.

This will be handled for you.  The EZT is copied into the Easytrieve Conversion Workbench, and [Convert] clicked to convert it to Jazz. If a dialog asks “In-line printing?”, respond [No]. It now looks like this in the Conversion Notepad: -

PERFORM REPE;

REPORT NAME 'REPE';

ROUTINE REPE [Report];

TPRINT(1,'Printed at:',DlrToday,'Program AanexmlE' COL(58),'PAGE ' COL(121),DlrPagenbr);

JZORDER(REGION BREAK, DISTRICT BREAK);

JZPRINT (Region,District,Name,SalesThisMonth,Datecommenced) LINE(1);

END ROUTINE REPE;

$Today and $Pagenbr are special Jazz names which we didn’t want changed.  We can edit DlrToday and DlrPagenbr back to their original names before we click [Exit], or we can leave them unchanged and sort it out within Jazz.  [Exit] completes the conversion and inserts the statements into the correct places in the program. 

SEQUENCE and CONTROL statements have combined into a JZORDER statement, which will become an ORDER option of the controlling PROCESS statement.  When this is inserted into the Jazz program, it becomes

*# Last Updated by JAZZUSR at 6/07/2023 2:53:02 PM

PROGRAM AanexmlE BATCH EZT;

COPY IN1;

#388 E FR.Region and IN1.Region have different types

REPORT(1) NAME 'REPE';

#726 W REPE will be assigned to RepNbr1

*# Copy Files here ==>

PROCESS IN1 WHERE(IN1.Region = 1 | IN1.Region=6) SID(23) ORDER(IN1.Region BREAK, IN1.District BREAK);

    GET FR WHERE (FR.Region = IN1.Region);

    PERFORM REPE LINKID(23);

*#Copy Process logic here ==>

END PROCESS IN1;

ROUTINE REPE [Report] LINKID(23);

    TPRINT(1,JAZZ.$Today,'Program AanexmlE' COL(58),'PAGE ' COL(121),JAZZ.$PAGENBR);

    PRINT (FR.Region SUM,IN1.District,FR.Name,IN1.SalesThisMonth SUM,IN1.DateCommenced) LINE(1) ;

END ROUTINE REPE;

*#Copy Routines here ==>

Notes

1.    The PROCESS statement is identified with SID(23).  SID means “Statement Index”.  By adding LINKID(23) to the PERFORM and ROUTINE statements, the PRINT statement can use the control break structure of the PROCESS statement so that can manage the appropriate subtotal and grand total printing, just as if it were placed directly within the PROCESSEND PROCESS.  ROUTINE REPE is “logically” within the PROCESS loop.

2.    The JZORDER has disappeared and become an ORDER option of the PROCESS statement. 

3.    MANASYS attempts to apply EZT rules, adding SUM to numeric fields that are not control fields. Check that it has got this correct: here it hasn’t, because REGION was resolved to FR.Region, not IN1.Region. Remove this SUM option, and correct the name to IN.Region.

Example 2A

What if the PROCESS already has an ORDER option?  It can’t add another!  Here’s what happens starting with this: -

*# Last Updated by JAZZUSR at 26/07/2023 4:29:54 PM

PROGRAM AanexmlE BATCH EZT;

COPY IN1;

#388 E FR.Region and IN1.Region have different types

*# Copy Files here ==>

PROCESS IN1 WHERE(IN1.Region = 1 | IN1.Region=6) SID(23) ORDER(NULL);

    #785 W File will be processed in its natural order

    GET FR WHERE (FR.Region = IN1.Region);

*#Copy Process logic here ==>

END PROCESS IN1;

*#Copy Next Process here ==>

*#Copy Routines here ==>

Then after converting the EZT as described above, when we click [Exit] this is what happens when MANASYS attempts to handle the JZOrder “statement”: -

We reply [Yes], and this results: -

*# Last Updated by JAZZUSR at 3/08/2024 3:04:41 PM

PROGRAM AanexmlE BATCH EZT;

COPY IN1;

#388 E FR.Region and IN1.Region have different types

REPORT(1) NAME 'REPE';

#726 W REPE will be assigned to RepNbr1

*  Workfile for report REPE

DEFINE JZWK1 FB DSNAME '&&JZWK1' DATA(

        Region LIKE FR.Region,

        District LIKE IN1.District,

        Name LIKE FR.Name,

        SalesThisMonth LIKE IN1.SalesThisMonth,

        DateCommenced LIKE IN1.DateCommenced);

*# Copy Files here ==>

PROCESS IN1 WHERE(IN1.Region = 1 | IN1.Region=6) SID(23) ORDER(NULL);

    #785 W File will be processed in its natural order

    GET FR WHERE (FR.Region = IN1.Region);

*  Workfile for report REPE

    JZWK1.Region = FR.Region;

    JZWK1.District = IN1.District;

    JZWK1.Name = FR.Name;

    JZWK1.SalesThisMonth = IN1.SalesThisMonth;

    JZWK1.DateCommenced = IN1.DateCommenced;

    WRITE JZWK1;

    #378 W Batch WRITE used - you may need to edit the JCL

*#Copy Process logic here ==>

END PROCESS IN1;

PROCESS JZWK1 TALLY REOPEN SID(27) ORDER(JZWK1.Region BREAK,JZWK1.District BREAK);

    PERFORM REPE LINKID(27);

END PROCESS JZWK1;

*#Copy Next Process here ==>

ROUTINE REPE [Report] LINKID(27);

    TPRINT(1,'Printed at:',JAZZ.$Today,'Program AanexmlE' COL(58),'PAGE ' COL(121),JAZZ.$PAGENBR);

    PRINT (JZWK1.Region,JZWK1.District,JZWK1.Name,JZWK1.SalesThisMonth SUM,JZWK1.DateCommenced) LINE(1);

END ROUTINE REPE;

*#Copy Routines here ==>

Because the first PROCESS statement already has ORDER, its sequence is fixed, so the best remaining approach is to create a work file, then PROCESS this in the correct sequence.

On the COBOL tab of Configure there is an option ORDER(NULL): -

If checked (default), ORDER(NULL) will be added to PROCESS statements by EZT conversion.  This is not always what you want – here Example2 is better than Example2A – but it will always work and is similar to EZT behavior.   If you usually don’t want ORDER(NULL) to be inserted, uncheck this option.  If you’re usually happy with the setting but you have a particular case where you don’t want the default, just remove it from the PROCESS statement.

Example 3

Program PRTEZ3 prints three reports from file INP.  Each of these reports require a particular data order, and they’re all different.

FILE PRT PRINTER

FILE INP       

INP-REC          1  80  A

E-TES            1   5  A

E-TES3           3   3  A

E-RB             22  1  A

E-PRCS           38  5  N

E-NM             49  34 A

E-TS             87  1  A

*                       

W-PRCS    W  5  N  0 VALUE 0

*             

JOB INPUT INP 

W-PRCS = E-PRCS

PRINT REPORT1 

PRINT REPORT2

PRINT REPORT3

REPORT REPORT1 SPACE 1  SUMMARY SUMCTL DTLCOPY +

  PAGESIZE 80 PRINTER PRT

SEQUENCE E-TES3         

CONTROL E-TES3          

SUM W-PRCS              

TITLE 1 'REPORT1-Title1'

TITLE 2 'REPORT1-Title2'

LINE 1 E-TES '-' E-NM W-PRCS TALLY

REPORT REPORT2 SPACE 1  SUMMARY SUMCTL DTLCOPY +

  PAGESIZE 80 PRINTER PRT

SEQUENCE E-RB E-TS      

CONTROL E-RB            

SUM W-PRCS              

TITLE 1 'REPORT2-Title1'

TITLE 2 'REPORT2-Title2'

LINE 1 E-RB W-PRCS TALLY

REPORT REPORT3 SPACE 1  SUMMARY SUMCTL DTLCOPY +

  PAGESIZE 80 PRINTER PRT

SEQUENCE E-NM E-TS      

CONTROL E-NM            

SUM W-PRCS              

TITLE 1 'REPORT3-Title1'

TITLE 2 'REPORT3-Title2'

LINE 1 E-NM W-PRCS TALLY

 

A data definition, PRTEX3.jzz, was created using Data/Import from Easytrieve, and using Logic/Batch program we’ve created a program outline: -

PROGRAM PRTEX3 BATCH EZT;

COPY EZT-PRTEX3-DATA;

*# Copy Files here ==>

PROCESS INP TALLY SID(18);

*#Copy Process logic here ==>

END PROCESS INP;

*#Copy Next Process here ==>

*#Copy Routines here ==>

Now the logic of program PRTEX3 is converted to Jazz.  Copy/Paste all the EZT statements after JOB INPUT INP to the EZT Conversion Notepad, click [Convert], then [Exit].   

REPORT1 was defined in EZT with

SEQUENCE E-TES3                                                                

CONTROL E-TES3                                                                 

and the PROCESS statement doesn’t have an ORDER option, so ORDER(INP.GROUP3.E-TES3 BREAK) is added to it.

REPORT2 has a different order, so it can’t share the same PROCESS.  A MsgBox appears: -

We select [Yes] and MANASYS generates appropriate Jazz logic to define a work file, write data to it from the first PROCESS loop, and process this work file to print Report2

REPORT3 also has a different order, this time we select [No].   Jazz doesn’t create a work file, instead another PROCESS loop re-processes INP.

Here is the completed program: -

PROGRAM PRTEX3 BATCH EZT;

COPY EZT-PRTEX3-DATA;

REPORT(1) NAME 'REPORT1' GAP(1)  PAGE(80) ;

#726 W REPORT1 will be assigned to RepNbr1

REPORT(2) NAME 'REPORT2' GAP(1)  PAGE(80) ;

#726 W REPORT2 will be assigned to RepNbr2

REPORT(3) NAME 'REPORT3' GAP(1)  PAGE(80) ;

#726 W REPORT3 will be assigned to RepNbr3

DEFINE JZWK1 FB DSNAME '&&JZWK1' DATA(

        E-RB LIKE INP.GROUP2.E-RB,

        E-TS LIKE INP.GROUP1.E-TS,

        W-PRCS LIKE EZT-PRTEX3-Data.GROUP1.W-PRCS);

*# Copy Files here ==>

PROCESS INP TALLY SID(18) ORDER(INP.GROUP3.E-TES3 BREAK);

    EZT-PRTEX3-Data.W-PRCS = INP.E-PRCS;

    PERFORM REPORT1 LINKID(18);

    JZWK1.E-RB = INP.GROUP2.E-RB;

    JZWK1.E-TS = INP.GROUP1.E-TS;

    JZWK1.W-PRCS = EZT-PRTEX3-Data.GROUP1.W-PRCS;

    WRITE JZWK1;

    #378 W Batch WRITE used - you may need to edit the JCL

*#Copy Process logic here ==>

END PROCESS INP;

PROCESS JZWK1 TALLY REOPEN SID(26) ORDER(JZWK1.E-RB BREAK,JZWK1.E-TS);

    PERFORM REPORT2 LINKID(26);

END PROCESS JZWK1;

PROCESS INP TALLY REOPEN SID(34) ORDER(INP.GROUP2.E-NM BREAK, INP.GROUP1.E-TS);

    PERFORM REPORT3 LINKID(34);

END PROCESS INP;

*#Copy Next Process here ==>

ROUTINE REPORT1 [Report] LINKID(18);

    TPRINT(1,'REPORT1-Title1');

    TPRINT(2,'REPORT1-Title2');

    PRINT (INP.E-TES,'-',INP.E-NM,EZT-PRTEX3-Data.W-PRCS SUM,Sums18.TALLY(1)) LINE(1) ;

END ROUTINE REPORT1;

ROUTINE REPORT2 [Report] LINKID(26);

    TPRINT(1,'REPORT2-Title1') REPORT(2);

    TPRINT(2,'REPORT2-Title2') REPORT(2);

    PRINT (JZWK1.E-RB,JZWK1.W-PRCS,Sums26.TALLY(1)) LINE(1) REPORT(2);

END ROUTINE REPORT2;

ROUTINE REPORT3 [Report] LINKID(34);

    TPRINT(1,'REPORT3-Title1') REPORT(3);

    TPRINT(2,'REPORT3-Title2') REPORT(3);

    PRINT (INP.E-NM,EZT-PRTEX3-Data.W-PRCS MSG768,Sums34.TALLY(1)) LINE(1) REPORT(3);

    #768 E Check that EZT-PRTEX3-Data.GROUP1.W-PRCS is correctly set

END ROUTINE REPORT3;

*#Copy Routines here ==>

Notes

1.    The files for report printing are defined towards the top of the program, using the *# Copy Files here ==> marker.

2.    Also defined here is the work file.  Each work file will be given a name “JZWKn”, with n starting at 1.  In this example there is only one work file.

3.    The first PROCESS loop is

PROCESS INP TALLY SID(18) ORDER(INP.GROUP3.E-TES3 BREAK);

    EZT-PRTEX3-Data.W-PRCS = INP.E-PRCS;

    PERFORM REPORT1 LINKID(18);

    JZWK1.E-RB = INP.GROUP2.E-RB;

    JZWK1.E-TS = INP.GROUP1.E-TS;

    JZWK1.W-PRCS = EZT-PRTEX3-Data.GROUP1.W-PRCS;

    WRITE JZWK1;

    #378 W Batch WRITE used - you may need to edit the JCL

*#Copy Process logic here ==>

END PROCESS INP;

The assignment and PERFORM are converted from

  W-PRCS = E-PRCS

  PRINT REPORT1 

The following statements assign data and write it to file JZWK1.  The data is that required by REPORT2.

4.    The 2nd PROCESS loop reads JZWK1 and prints REPORT2

5.    The 3rd PROCESS loop re-reads INP in the sequence required for REPORT3, and prints REPORT2

6.    Following the PROCESS loops are the ROUTINES which are PERFORMed to print the reports.

7.    All of these PROCESS statements include option TALLY.   In EZT conversion TALLY is always included when a PROCESS is generated, just in case a PRINT statement attempts to print it, or it is required for AVG. 

8.    Note the use of SID and LINKID.  Each PROCESS statement has an option SID, meaning “Statement ID”, which is a unique number that was the statement number when the PROCESS statement was first processed.  PERFORM statements within the PROCESS loop repeat this number as LINKID, as does the ROUTINE statement that is PERFORM ed.  You’ll also see this number repeated in (e.g.) Sums34.TALLY(1).   These ensure that the PRINT statements pick up the correct data for control breaks and sums.

9.    REPORT3 produces message 768 because it prints a field that is not from INP, and so may be incorrectly set.  Look back at the first PROCESS loop: you see that the first statement within this loop is EZT-PRTEX3-Data.W-PRCS = INP.E-PRCS;  Thus W-PRCS has a known value for PERFORM REPORT1 LINKID(18); and for assignment to JZWK1.   In the third PROCESS loop that re-processes INP it doesn’t have a known value: you need to repeat this statement before PERFORM REPORT3 LINKID(34); so that it also applies here also.  When you’ve corrected the error (or if there is no error), delete the keyword MSG768 so that the error message disappears.
       

Work file (Yes) or re-Process (no)

Program PRTEX3 was converted with Yes (Workfile) for REPORT2, and No (Re-Process) for REPORT3 to show the differences.  What should you choose?

Almost always, choose Yes.   The programs will be more efficient, and you avoid the MSG768 issue.   However, you can’t choose Yes if the initial loop has a condition that selects only some records unless this condition applies to all reports directly printed from the loop (Report1) or printed from a work file that it produces (REPORT2).   Suppose that the first PROCESS had been
           
PROCESS INP TALLY SID(18) ORDER(INP.GROUP3.E-TES3 BREAK) WHERE INP.GROUP1.E-TS = 'R';

You shouldn’t have used a work file for REPORT2 unless this condition applies to it.

Special Name Procedures

As noted above, MANASYS Jazz doesn’t support special name procedures.  However it provides some alternatives that might provide a good solution.  For example

    REPORT DETAIL-REPORT PRINTER OUTPUT1 LINESIZE 80

    SEQUENCE BRANCH TOTAL-SAL D

    CONTROL BRANCH

    TITLE 01 'EMPLOYEES DETAIL SALARY REPORT '

    TITLE 02 'DETAIL BY BRANCH – DESC BY NEW SAL'

    LINE 01 BRANCH FIRST-NAME OLD-SAL RAISE-DOL RAISE-PCT TOTAL-SAL

    BEFORE-BREAK. PROC

          RAISE-PCT = RAISE-PCT / TALLY

    END-PROC

           

;

FILE MYFILE

    INREC 1 80 A

    FIRST-NAME 1 6 A HEADING ('FIRST' 'NAME')

    SECOND-NAME 8 8 A HEADING ('SECOND' 'NAME')

    EMPLOYEE-NUM 17 8 N HEADING ('EMPLOYEE' 'NUM')

    BRANCH 26 4 A HEADING ('BRANCH' 'NAME')

    SALARY 31 3 N

    JOB-CAT 35 2 N

    OLD-SAL W 3 P 2

    RAISE-PCT W 3 P 2

    RAISE-DOL W 3 P 2

    TOTAL-SAL W 4 P 2

FILE OUTPUT1 PRINTER

JOB INPUT (MYFILE)

    OLD-SAL = SALARY

    IF JOB-CAT = 10

          RAISE-PCT = 7.00

    ELSE

          RAISE-PCT = 9.00

    END-IF

    RAISE-DOL = OLD-SAL * RAISE-PCT / 100

    TOTAL-SAL = OLD-SAL + RAISE-DOL

    PRINT DETAIL-REPORT

    PRINT SUMM-REPORT

    REPORT DETAIL-REPORT PRINTER OUTPUT1 LINESIZE 80

    SEQUENCE BRANCH TOTAL-SAL D

    CONTROL BRANCH

    TITLE 01 'EMPLOYEES DETAIL SALARY REPORT '

    TITLE 02 'DETAIL BY BRANCH – DESC BY NEW SAL'

    LINE 01 BRANCH FIRST-NAME OLD-SAL RAISE-DOL RAISE-PCT TOTAL-SAL

    BEFORE-BREAK. PROC

          RAISE-PCT = RAISE-PCT / TALLY

    END-PROC

    REPORT SUMM-REPORT PRINTER OUTPUT1 SUMMARY LINESIZE 80

    SEQUENCE BRANCH JOB-CAT

    CONTROL BRANCH JOB-CAT

    TITLE 01 'EMPLOYEES SUMMARY SALARY REPORT '

    LINE 01 BRANCH JOB-CAT OLD-SAL TOTAL-SAL RAISE-DOL

There are several issues in this program that we’ll have to handle.  Most importantly, the Report has two reports, in different sequences.  We can’t print both of them from one PROCESS loop, so we need two loops.  The simplest approach is to re-process the input file: -

PROCESS MYFILE;

*#Copy Process logic here ==>

END PROCESS MYFILE;

PROCESS MYFILE REOPEN;

*#Copy Process logic here ==>

END PROCESS MYFILE;

Each loop will have its own ORDER option giving sequence and control breaks, and may have WHERE to select a subset of the records in MyFILE. 

A different approach is to write a work file in the first loop, and then re-process this.   This is more code, but can result in more efficient COBOL programs, particularly if the work file has only a few fields.  Using a work file, the program logic would look like

1          Define a work file like

DEFINE WKFILE FB DATA(

        FIRST-NAME CHAR(6) HEADING 'FIRST' 'NAME' ,

        TOTAL-SAL MONEY(7,2))

    DSNAME '&&WKFILE';

            containing the data that will be required for the 2nd report.

2          In the first PROCESS  data is written to WKFILE, and the first report is produced.  The second PROCESS reads WKFILE back, producing the 2nd report

PROCESS MYFILE;

    WKFILE.* = MyFILE.* SIMPLE ;

    WRITE WKFILE;

*#Plus logic to produce 1st Report

END PROCESS MYFILE;

PROCESS WKFILE REOPEN;

*Logic to product 2nd Report

END PROCESS MYFILE

Both techniques produce the same results. There is no always-best approach, as “Best” depends on file size, complexity, and organization, and how important run-time efficiency is in this particular case.

The following example uses a work file.  The first PROCESS will directly print one report, and write data to a work file, the second will sort this and print it. But which report will we print directly?  Detail Report seems the obvious choice, but there are some issues with it: -

a.  The program uses

SEQUENCE BRANCH TOTAL-SAL D

But TOTAL-SAL is a working-storage field, it is not a field in the input file, so PROCESS  ORDER( MyFile-WS.TOTAL-SAL … is invalid, and an S-level message will prevent program generation.

b.  The special-name procedure BEFORE-BREAK will become a comment and be ignored

So, although it seems counter-intuitive, we’ll print the summary report directly, and print the detail report from a work file that we’ll create and then sort and reopen for printing. 

We start by creating the data definition for this program from esy3 with Input from Easytrieve.  It will be called EZT-esy3-Data

*# Converted from esy3.txt by JAZZUSR at 20/11/2022 2:52:01 PM

DEFINE MYFILE FB [Assumed] DATA(

    GROUP1 GROUP,

        INREC CHAR(80),

        End GROUP,

    GROUP2 GROUP REDEFINES MYFILE.GROUP1,

        FIRST-NAME CHAR(6) HEADING 'FIRST' 'NAME' ,

        FILLER CHAR(1),

        SECOND-NAME CHAR(8) HEADING 'SECOND' 'NAME' ,

        FILLER CHAR(1),

        EMPLOYEE-NUM PIC '99999999' HEADING 'EMPLOYEE' 'NUM' ,

        FILLER CHAR(1),

        BRANCH CHAR(4) HEADING 'BRANCH' 'NAME' ,

        FILLER CHAR(1),

        SALARY PIC '999',

        FILLER CHAR(1),

        JOB-CAT PIC '99',

        FILLER CHAR(44),

        End GROUP)

    DSNAME 'JAZZUSR.FILES.MYFILE';

DEFINE EZT-esy3-Data DATA(

    GROUP1 GROUP,

        OLD-SAL MONEY(5,2),

        RAISE-PCT MONEY(5,2),

        RAISE-DOL MONEY(5,2),

        TOTAL-SAL MONEY(7,2),

        End GROUP);

*DEFINE OUTPUT1 PRINTER

DSNAME is added to MYFILE. This will prevent message #346, more importantly it will allow MANASYS to create correct JCL.

Next we create the program outline with the Logic/Batch Program dialog, resulting in: -

PROGRAM ESY3 BATCH EZT;

COPY EZT-esy3-DATA;

*# Copy Files here ==>

PROCESS MYFILE;

*#Copy Process logic here ==>

END PROCESS MYFILE;

*#Copy Routines here ==>

With the EZT Conversion Workbench, convert the logic except for the two reports and copy this into the Jazz program.  Convert the summary report and copy this into the program.   Here is the Jazz program so far: -

PROGRAM ESY3 BATCH EZT;

COPY EZT-ESY3-DATA;

REPORT(2) NAME 'SUMM-REPORT' HEADING('EMPLOYEES SUMMARY SALARY REPORT 'WIDTH(80) ;

*# Copy Files here ==>

PROCESS MYFILE ORDER(MYFILE.GROUP2.BRANCH BREAKMYFILE.GROUP2.JOB-CAT BREAK);

    EZT-esy3-Data.OLD-SAL = MYFILE.SALARY;

    IF MYFILE.JOB-CAT = 10;

        EZT-esy3-Data.RAISE-PCT = 7.00;

    ELSE;

        EZT-esy3-Data.RAISE-PCT = 9.00;

    END IF;

    EZT-esy3-Data.RAISE-DOL = EZT-esy3-Data.OLD-SAL * EZT-esy3-Data.RAISE-PCT / 100;

    EZT-esy3-Data.TOTAL-SAL = EZT-esy3-Data.OLD-SAL + EZT-esy3-Data.RAISE-DOL;

*#Copy PRINT DETAIL-REPORT here ==>

    PRINT (MYFILE.BRANCH,MYFILE.JOB-CAT,EZT-esy3-Data.OLD-SAL SUM,EZT-esy3-Data.TOTAL-SAL SUM,EZT-esy3-Data.RAISE-DOL SUMLINE(01) REPORT(2);

*#Copy PRINT SUMM-REPORT here ==>

*#Copy Process logic here ==>

END PROCESS MYFILE;

*#Copy Routines here ==>

The conversion has added SUM to the numeric fields.  Edit the PRINT statement if necessary. Subtotals will be printed on every control break, and grand totals at the end. The program is complete as far as the Summary Report is concerned, but we need to write a work file that we can sort to produce the detail report.   We are going to print this data: -

    LINE 01 BRANCH FIRST-NAME OLD-SAL RAISE-DOL RAISE-PCT TOTAL-SAL

Right-click EZT-esy3-Data and add a work file definition to it.  Note: define fields with the same names and properties as the source field (either Copy/Paste, or else define with LIKE), and give a temporary ($$) DSNAME: -

DEFINE WKFILE FB DATA(

        FIRST-NAME CHAR(6) HEADING 'FIRST' 'NAME' ,

        BRANCH CHAR(4) HEADING 'BRANCH' 'NAME' ,

        OLD-SAL MONEY(5,2),

        RAISE-PCT MONEY(5,2),

        RAISE-DOL MONEY(5,2),

        TOTAL-SAL MONEY(7,2))

    DSNAME '&&WKFILE';

At *#Copy PRINT DETAIL-REPORT here ==> write: -

WKFILE.* = MyFILE.* simple;

WKFILE.* = EZT-ESY3-DATA.* simple;

WRITE WKFILE;

[Check] turns this into

    WKFILE.* = MyFILE.* SIMPLE ;

    #207 I GROUP2.FIRST-NAME,GROUP2.BRANCH, included in generic assignment

    WKFILE.* = EZT-ESY3-DATA.* SIMPLE;

    #207 I GROUP1.OLD-SAL,GROUP1.RAISE-PCT,GROUP1.RAISE-DOL,GROUP1.TOTAL-SAL, included in generic assignment

    WRITE WKFILE;

    #378 W Batch WRITE used - you may need to edit the JCL

Without SIMPLE nothing would have been assigned unless we’d defined WKFILE with the same GROUP hierarchy as MyFILE and EZT-ESY3-DATA.

Now the program will produce a work file containing the data required for the detail report.  Here’s the program so far, with position-marker comments removed: -

*# Last Updated by Jazzusr at 12/07/2022 1:34:19 PM

PROGRAM ESY3 BATCH EZT;

COPY EZT-ESY-DATA;

REPORT NAME 'SUMM-REPORT' HEADING 'EMPLOYEES SUMMARY SALARY REPORT '  WIDTH(80) ;

PROCESS MYFILE ORDER(MYFILE.GROUP2.BRANCH BREAKMYFILE.GROUP2.JOB-CAT BREAK);

    MYFILE-WS.OLD-SAL = MYFILE.SALARY;

    IF MYFILE.JOB-CAT = 10;

        MYFILE-WS.RAISE-PCT = 7.00;

    ELSE;

        MYFILE-WS.RAISE-PCT = 9.00;

    END IF;

    WRKFILE.* = MyFile.* SIMPLE;

    #207 I GROUP2.FIRST-NAME,GROUP2.BRANCH, included in generic assignment

    WRKFILE.* = MyFile-WS.* SIMPLE;

    #207 I GROUP1.OLD-SAL,GROUP1.RAISE-PCT,GROUP1.RAISE-DOL,GROUP1.TOTAL-SAL, included in generic assignment

    WRITE Wrkfile;

    #378 W Batch WRITE used - you may need to edit the JCL

    PRINT (MYFILE.BRANCH,MYFILE.JOB-CAT,MYFILE-WS.OLD-SAL SUM,MYFILE-WS.TOTAL-SAL SUM,MYFILE-WS.RAISE-DOL SUMLINE(01);

END PROCESS MYFILE;

Now the program will produce the Summary report and a work file containing the data required for the detail report.

To produce the detailed report we add another PROCESS loop to sort the work file and print the report. After END PROCESS MYFILE; write

PROCESS WKFILE ORDER(BRANCH BREAK, TOTAL-SAL DESC) REOPEN;

PRINT WKFILE.? Report(2);

End process WKFILE;

Click [Check].  PRINT WKFILE.? invokes a dialog where we select the fields from WKFILE in the order that we want them in the printout. Our program now contains

PROCESS WKFILE ORDER(WKFILE.BRANCH BREAKWKFILE.TOTAL-SAL DESCREOPEN;

    PRINT(WKFILE.BRANCH,WKFILE.FIRST-NAME,WKFILE.OLD-SAL,WKFILE.RAISE-DOL,WKFILE.RAISE-PCT,WKFILE.TOTAL-SALREPORT(2);

END PROCESS WKFILE;

Note the use of REOPEN, which causes WKFILE to be closed and re-opened so that it can be read back.

Add SUM to the numeric fields that we want totalled, and AVG to RAISE-PCT.   Add a TALLY option to the PROCESS statement (because you’ve used AVG, you’ll be prompted by a message): -

PROCESS WKFILE ORDER(WKFILE.BRANCH BREAKWKFILE.TOTAL-SAL DESCREOPEN TALLY;

    PRINT(WKFILE.BRANCH,WKFILE.FIRST-NAME,WKFILE.OLD-SAL SUM,WKFILE.RAISE-DOL SUM,

        WKFILE.RAISE-PCT AVGWKFILE.TOTAL-SAL SUMREPORT(2) ;

END PROCESS WKFILE;

Our program is now equivalent to the Easytrieve program, including the special-names procedure.  Now [Process] the program to create COBOL and JCL. 

Instream Table Lookups

Instream tables are converted by New\Data\Import From Easytrieve into a single field definition with a single or paired CODES property. For example MTHTAB was defined

FILE MTHTAB TABLE INSTREAM

  ARG                   01  02 N

  DESC                  04  15 A

01 January

02 February

03 March

04 April

05 May

06 June

07 July

08 August

09 September

10 October

11 November

12 December

ENDTABLE

Because MTHTAB is defined with a numeric ARG, and values are given in sequence without any gaps, Import From Easytrieve converted this into a single CODES table, allowing values to be found by subscript: -

DEFINE MTHTAB DATA(

    DESC PIC '99' CODES('January','February','March','April','May','June','July','August',

    'September','October','November','December'));[Value Length = 15]

If the ARG field has missing values, or is defined as A 2 rather than N 2, a paired CODES property is generated.

DEFINE MTHTAB DATA(

    DESC CHAR(2) CODES('01':'January','02':'February','03':'March','04':'April','05':'May','06':'June','07':'July',

    '08':'August','09':'September','10':'October','11':'November','12':'December'));[Value Length = 15]

#647 E CAPS/LOWER option recommended

With either form, [Convert] will attempt to convert Easytrieve SEARCH statements into a Jazz SEARCH statement.  For example

      SEARCH MTHTAB WITH W-DATE2-MM GIVING W-ARRAY1-MTH

will be converted into something like

SEARCH(MTHTAB.DESC)WITH W.W-DATE2-MM GIVING W.W-ARRAY1-MTH;

For a paired-value CODES a search will have been used, with a single-value CODES the “search” gets the array value by subscripted reference.  In either case MANASYS logic will check that the code value is valid, and will assign asterisks, e.g '***************', if not.

Testing Lookup Success

Following a SEARCH an Easytrieve program might test the lookup success with IF filename.  For example

SEARCH CLASSES WITH CODE, GIVING DESCRIPTION

IF CLASSES

 DISPLAY DESCRIPTION

ELSE

 DISPLAY 'CLASS NOT FOUND'

END-IF

This IF would be invalid if simply converted to Jazz.  If you need to test lookup success in Jazz, test the special value SEARCH-FOUND for True or False, which is qualified to

IF JZ2.SEARCH-FOUND = false;

Since Build #309, Jazz will convert statements like IF CLASSES and IF NOT CLASSES to IF JZ2.SEARCH-FOUND = true or IF JZ2.SEARCH-FOUND = false.

Optional Changes

You may see Easytrieve code that when converted following the rules above, could be improved further.  Here are some of the situations that have been encountered so far.

Reducing Logic Nesting Level

IF nesting can be reduced by using ELSEIF.  If you see logic like this you can shorten and simplify it by changing the ELSE IF to ELSEIF

IF COMP = 'NINA' 'CICA'

   V-ACCOUNT = 5902

ELSE

   IF COMP = 'NIFF'

      V-ACCOUNT = 5945

   ELSE

      IF COMP = 'NICC'

         V-ACCOUNT = 5993

                              ELSE

                                 IF COMP = 'TELZ'

                                    V-ACCOUNT = 5928

                                 ELSE

                                    V-ACCOUNT = 5900

                                 END-IF

                              END-IF

                           END-IF

                        END-IF

                     END-IF

                  END-IF

               END-IF

            END-IF

         END-IF

      END-IF

   END-IF

END-IF

Initially this was converted as written, but the excessive level of IF statements made the logic ugly and difficult to understand.  It’s worse in the generated COBOL which allows only 66 characters.  The following code is logically identical and much neater using ELSEIF: -

        IF VIRCARD.COMP IN('NINA','CICA');

            VIRTFLE.V-ACCOUNT = 5902;

        ELSEIF VIRCARD.COMP = 'NIFF';

            VIRTFLE.V-ACCOUNT = 5945;

        ELSEIF VIRCARD.COMP = 'NICC';

            VIRTFLE.V-ACCOUNT = 5993;

        ELSEIF VIRCARD.COMP = 'TELZ';

            VIRTFLE.V-ACCOUNT = 5928;

        ELSE;

            VIRTFLE.V-ACCOUNT = 5900;

        END IF;

It is probably best to edit this in the Jazz workbench.   Work from the innermost ELSE … IF upwards, and either remove surplus END IF; statements as you go, or later click [CHECK] and use the error messages to show you.

Shorten Conditions

IF condition OR condition OR condition might be better expressed as IN.  For example

   IF W-POLICY-1 = I-MULTI-POL +

    OR W-POLICY-2 = I-MULTI-POL +

    OR W-POLICY-3 = I-MULTI-POL +

    OR W-POLICY-4 = I-MULTI-POL

A shorter equivalent is

   IF I-MULTI-POL = W-POLICY-1 W-POLICY-2 W-POLICY-3 W-POLICY-4

which will be converted to a Jazz IN condition.  Whether rewritten or not, references to I-MULTI-POL need to be subscripted: -

    IF INFILE1.I-MULTI-POL(JZ.IX1)  IN(OUTPUT2-WS.W-POLICY-1,OUTPUT2-WS.W-POLICY-2,

            OUTPUT2-WS.W-POLICY-3OUTPUT2-WS.W-POLICY-4) ;

Easytrieve Macros

Macros are supported in the Easytrieve Conversion Notepad, as they are with Data/Import From Easytrieve.   As with Import from Easytrieve, macros must be in the same folder as the program containing the macro reference.  Both positional and keyword parameters are supported.

Appendices

Easytrieve Example 1

(Not shown: the Library section of this Easytrieve program, which would have contained definitions of files INFILE, TEMP1, and OUTPUT1), and was converted to Jazz-format definitions in EZT-EXAMPL1-Data)

JOB INPUT (INFILE)

*

  IF I-ID = '01' +

  AND I-FLAG = 'S'

     IF I-CLIENT = T-CLIENT +

     AND I-POLICY = T-POLICY

     ELSE

        T-CLIENT = I-CLIENT

        T-POLICY = I-POLICY

        T-FLAG = I-FLAG

        PUT TEMP-1

     END-IF

  ELSE

     IF I-ID = '02'

        W-POLICY-1 = ' '

        W-POLICY-2 = ' '

        W-POLICY-3 = ' '

        W-POLICY-4 = ' '

        T-CLIENT = I-CLIENT

        T-POLICY = ' '

        T-FLAG = I-FLAG

        W-RQD = 'Y'

* IF MORE THAN 4 POLICIES I-FLAG = 'X' AND MULTI-POL DETAILS SPACES

        IX-A = 0

        W-CTR = 0

        DO WHILE W-CTR < 4

           IF I-MULTI-POL NE ' '

              IF W-POLICY-1 = I-MULTI-POL +

              OR W-POLICY-2 = I-MULTI-POL +

              OR W-POLICY-3 = I-MULTI-POL +

              OR W-POLICY-4 = I-MULTI-POL

              ELSE

                 T-POLICY = I-MULTI-POL

                 PUT TEMP-1

                 W-RQD = 'N'

                 IF W-POLICY-1 = ' '

                    W-POLICY-1 = I-MULTI-POL

                 ELSE

                    IF W-POLICY-2 = ' '

                       W-POLICY-2 = I-MULTI-POL

                    ELSE

                       IF W-POLICY-3 = ' '

                          W-POLICY-3 = I-MULTI-POL

                       ELSE

                          W-POLICY-4 = I-MULTI-POL

                       END-IF

                    END-IF

                 END-IF

              END-IF

           END-IF

           W-CTR = W-CTR + 1

           IX-A = IX-A + 68

        END-DO

        IF W-RQD = 'Y'

           IF T-FLAG = 'X'

              IF T-CLIENT NE W-MULTI-X

                 PUT TEMP-1

                 W-MULTI-X = T-CLIENT

              END-IF

           ELSE

              PUT TEMP-1

           END-IF

           W-RQD = 'N'

        END-IF

     END-IF

  END-IF

*

SORT TEMP-1 TO TEMP-2 USING (T-KEY)

*

JOB INPUT(TEMP-2)

   O-RECORD = I-RECORD

   PUT OUTPUT

*

END

Example1 after [Convert]

(Not including the final SORT/JOB)

IF I-ID = '01' & I-FLAG = 'S';

IF I-CLIENT = T-CLIENT & I-POLICY = T-POLICY;

ELSE;

T-CLIENT = I-CLIENT;

T-POLICY = I-POLICY;

T-FLAG = I-FLAG;

WRITE TEMP1;

#158 W 'TEMP-1' is not valid as an external name

#706 E Manual Conversion May Be Necessary: See https://tinyurl.com/2s4xz4vt

END IF;

ELSE;

IF I-ID = '02';

W-POLICY-1 = ' ';

W-POLICY-2 = ' ';

W-POLICY-3 = ' ';

W-POLICY-4 = ' ';

T-CLIENT = I-CLIENT;

T-POLICY = ' ';

T-FLAG = I-FLAG;

W-RQD = 'Y';

IX-A = 0;

W-CTR = 0;

FOR WHILE W-CTR < 4;

#688 S Check Loop Logic: see https://tinyurl.com/22yfseeh

IF I-MULTI-POL <> ' ';

IF W-POLICY-1 = I-MULTI-POL | W-POLICY-2 = I-MULTI-POL | W-POLICY-3 = I-MULTI-POL | W-POLICY-4 = I-MULTI-POL;

ELSE;

T-POLICY = I-MULTI-POL;

WRITE TEMP1;

#158 W 'TEMP-1' is not valid as an external name

#706 E Manual Conversion May Be Necessary: See https://tinyurl.com/2s4xz4vt

W-RQD = 'N';

IF W-POLICY-1 = ' ';

W-POLICY-1 = I-MULTI-POL;

ELSE;

IF W-POLICY-2 = ' ';

W-POLICY-2 = I-MULTI-POL;

ELSE;

IF W-POLICY-3 = ' ';

W-POLICY-3 = I-MULTI-POL;

ELSE;

W-POLICY-4 = I-MULTI-POL;

END IF;

END IF;

END IF;

END IF;

END IF;

W-CTR = W-CTR + 1;

IX-A = IX-A + 68;

END FOR;

IF W-RQD = 'Y';

IF T-FLAG = 'X';

IF T-CLIENT <> W-MULTI-X;

WRITE TEMP1;

#158 W 'TEMP-1' is not valid as an external name

#706 E Manual Conversion May Be Necessary: See https://tinyurl.com/2s4xz4vt

W-MULTI-X = T-CLIENT;

END IF;

ELSE;

WRITE TEMP1;

#158 W 'TEMP-1' is not valid as an external name

#706 E Manual Conversion May Be Necessary: See https://tinyurl.com/2s4xz4vt

END IF;

W-RQD = 'N';

END IF;

END IF;

END IF;

Converted Easytrieve inserted into Jazz

PROGRAM EXAMPL1 BATCH EZT;

COPY EZT-EXAMPL1-DATA;

*# Copy Files here ==>

PROCESS INFILE SID(23);

    #346 W DSNAME option missing

    IF INFILE.I-ID = '01' & INFILE.I-FLAG = 'S';

        IF INFILE.I-CLIENT = TEMP1.T-CLIENT & INFILE.I-POLICY = TEMP1.T-POLICY;

        ELSE;

            TEMP1.T-CLIENT = INFILE.I-CLIENT;

            TEMP1.T-POLICY = INFILE.I-POLICY;

            TEMP1.T-FLAG = INFILE.I-FLAG;

            WRITE TEMP1;

            #346 W DSNAME option missing

            #378 W Batch WRITE used - you may need to edit the JCL

        END IF;

    ELSE;

        IF INFILE.I-ID = '02';

            EZT-EXAMPL1-Data1.W-POLICY-1 = ' ';

            EZT-EXAMPL1-Data1.W-POLICY-2 = ' ';

            EZT-EXAMPL1-Data1.W-POLICY-3 = ' ';

            EZT-EXAMPL1-Data1.W-POLICY-4 = ' ';

            TEMP1.T-CLIENT = INFILE.I-CLIENT;

            TEMP1.T-POLICY = ' ';

            TEMP1.T-FLAG = INFILE.I-FLAG;

            EZT-EXAMPL1-Data1.W-RQD = 'Y';

            EZT-INDEX.IX-A = 0;

            EZT-EXAMPL1-Data1.W-CTR = 0;

            FOR JZ.WHILE W-CTR < 4;

                #029 E 'W-CTR' is invalid here

                #684 S FOR statement has invalid syntax

                IF INFILE.I-MULTI-POL <> ' ';

                    #291 S Reference to INFILE.GROUP2.I-MULTI-REDEF.I-MULTI-POL should be followed by a subscript list

                    #029 E '<>' is invalid here

                    #049 S Subscript(s) expected for INFILE.GROUP2.I-MULTI-REDEF.I-MULTI-POL

                    IF EZT-EXAMPL1-Data1.W-POLICY-1 = INFILE.I-MULTI-POL | EZT-EXAMPL1-Data1.W-POLICY-2 = I-MULTI-POL | W-POLICY-3 = I-MULTI-POL | W-POLICY-4 = I-MULTI-POL;

                        #291 S Reference to INFILE.GROUP2.I-MULTI-REDEF.I-MULTI-POL should be followed by a subscript list

                        #029 E '|' is invalid here

                        #623 S Expression ends with operator |

                    ELSE;

                        TEMP1.T-POLICY = INFILE.I-MULTI-POL;

                        #049 S Subscript(s) expected for INFILE.GROUP2.I-MULTI-REDEF.I-MULTI-POL

                        WRITE TEMP1;

                        #346 W DSNAME option missing

                        #378 W Batch WRITE used - you may need to edit the JCL

                        EZT-EXAMPL1-Data1.W-RQD = 'N';

                        IF EZT-EXAMPL1-Data1.W-POLICY-1 = ' ';

                            EZT-EXAMPL1-Data1.W-POLICY-1 = INFILE.I-MULTI-POL;

                            #049 S Subscript(s) expected for INFILE.GROUP2.I-MULTI-REDEF.I-MULTI-POL

                        ELSE;

                            IF EZT-EXAMPL1-Data1.W-POLICY-2 = ' ';

                                EZT-EXAMPL1-Data1.W-POLICY-2 = INFILE.I-MULTI-POL;

                                #049 S Subscript(s) expected for INFILE.GROUP2.I-MULTI-REDEF.I-MULTI-POL

                            ELSE;

                                IF EZT-EXAMPL1-Data1.W-POLICY-3 = ' ';

                                    EZT-EXAMPL1-Data1.W-POLICY-3 = INFILE.I-MULTI-POL;

                                    #049 S Subscript(s) expected for INFILE.GROUP2.I-MULTI-REDEF.I-MULTI-POL

                                ELSE;

                                    EZT-EXAMPL1-Data1.W-POLICY-4 = INFILE.I-MULTI-POL;

                                    #049 S Subscript(s) expected for INFILE.GROUP2.I-MULTI-REDEF.I-MULTI-POL

                                END IF;

                            END IF;

                        END IF;

                    END IF;

                END IF;

                EZT-EXAMPL1-Data1.W-CTR = EZT-EXAMPL1-Data1.W-CTR + 1;

                EZT-INDEX.IX-A = EZT-INDEX.IX-A + 68;

            END FOR;

            IF EZT-EXAMPL1-Data1.W-RQD = 'Y';

                IF TEMP1.T-FLAG = 'X';

                    IF TEMP1.T-CLIENT <> EZT-EXAMPL1-Data1.W-MULTI-X;

                        WRITE TEMP1;

                        #346 W DSNAME option missing

                        #378 W Batch WRITE used - you may need to edit the JCL

                        EZT-EXAMPL1-Data1.W-MULTI-X = TEMP1.T-CLIENT;

                    END IF;

                ELSE;

                    WRITE TEMP1;

                    #346 W DSNAME option missing

                    #378 W Batch WRITE used - you may need to edit the JCL

                END IF;

                EZT-EXAMPL1-Data1.W-RQD = 'N';

            END IF;

        END IF;

    END IF;

*#Copy Process logic here ==>

END PROCESS INFILE;

*#Copy Routines here ==>