Contents
Preparing to Convert Easytrieve Logic
The Easytrieve Conversion Notepad
General Changes made by
[Convert]
Status Checking following READ
Converted Easytrieve inserted into Jazz
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.
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 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 < 4; with 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.
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.
(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 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.
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].
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
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');
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.
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 DELETE. PROCESS 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.
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.
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
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.
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 (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.
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=1 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.
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.
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;
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);
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: -
…
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.
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-KEY) UPDATE;
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-KEY) UPDATE;
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 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.
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.
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. SEQUENCE, CONTROL,
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
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-PRT) LINE(1);
END ROUTINE HOREPORT;
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 PROCESS … END 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.
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.
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 ==>
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.
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.
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 BREAK, MYFILE.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 SUM) LINE(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 BREAK, MYFILE.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 SUM) LINE(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 BREAK, WKFILE.TOTAL-SAL DESC) REOPEN;
PRINT(WKFILE.BRANCH,WKFILE.FIRST-NAME,WKFILE.OLD-SAL,WKFILE.RAISE-DOL,WKFILE.RAISE-PCT,WKFILE.TOTAL-SAL) REPORT(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 BREAK, WKFILE.TOTAL-SAL DESC) REOPEN TALLY;
PRINT(WKFILE.BRANCH,WKFILE.FIRST-NAME,WKFILE.OLD-SAL SUM,WKFILE.RAISE-DOL SUM,
WKFILE.RAISE-PCT AVG, WKFILE.TOTAL-SAL SUM) REPORT(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 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.
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.
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.
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.
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-3, OUTPUT2-WS.W-POLICY-4) ;
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.
(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
(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;
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 ==>