You may wish to write some of your logic in a paragraph to
make your program easier to understand, or to use this logic in more than one
place. You can do this using PERFORM and ROUTINE.
PERFORM
PROCESS-INPUT;
…
ROUTINE
PROCESS-INPUT;
IF eibcalen = 0 THEN;
SEND
Custnqry CLEAR;
END IF;
END
ROUTINE;
COBOL
programmers will be familiar with ROUTINE and PERFORM from COBOL as they follow similar rules to
COBOL’s PERFORM. Unlike COBOL, in Jazz a ROUTINE
can be passed parameters by the PERFORM. However,
unlike a subprogram that is invoked with CALL, a ROUTINE does not have any local data except for the
parameters, so that data defined by DEFINE
written within a ROUTINE is known to all following statements, including
those coming after END
ROUTINE;
The PERFORM statement may be written anywhere, including within the scope of logical-control statements like IF and FOR, within another Paragraph, and so on. When executed, control is passed to the first statement following the PERFORM statement. When the Paragraph has finished executing, control is passed back to the statement following the PERFORM statement.
ROUTINE will be written later in the program. It must not be within IF, FOR, etc, nor within another ROUTINE.
A feature of Jazz is that copy books may contain both DEFINE statements and procedural code, allowing you to write a single COPY with both the data structures and the logic to perform a function. Such procedural code should be written within a ROUTINE. Data definitions should use an appropriate record name so that it doesn’t clash with other definitions in your program. For example: -
ROUTINE RTN1 [Report] LINKID(25);
DEFINE RTN1-Data DATA(
X CHAR(5));
In Jazz data sequencing and control break management is a function of the PROCESS statement. For example, you might have written a program like Aanexmpl, with a PRINT statement within a PROCESS loop: -
*# Last Updated by JAZZUSR at 17/06/2023
2:30:59 PM
PROGRAM aanexmpl
BATCH;
COPY IN1;
#388 E FR.Region and IN1.Region have different types
COPY JZSMth;[23]
REPORT NAME 'Rpt1' HEADING('Program Aanexmpl', 'Heading 2'
COL(3));
#726 W Rpt1 will be assigned to RepNbr1
PROCESS IN1 WHERE (IN1.Region = 1 | IN1.Region = 6)
ORDER (IN1.Region BREAK, IN1.District BREAK, IN1.Name) SID(25);
GET FR WHERE (FR.Region
= IN1.Region);
PRINT (IN1.Region BREAK,FR.Name
BREAK (IN1.District) HEADING 'Region' 'Name',
IN1.District BREAK, '|',IN1.Name, IN1.SalesThisMonth
SUM RCOL(108), IN1.DateCommenced);
END PROCESS IN1;
The PRINT statement can take advantage of the sequencing
and control breaks defined by PROCESS … ORDER (…) because it is written directly within the PROCESS loop.
It can be convenient to put this logic into a routine, particularly when
you are converting Easytrieve into Jazz.
If you use a Report Routine, then you must establish the relationship
between the PROCESS statement and the ROUTINE. You do
this by adding LINKID options to the PERFORM and ROUTINE statements, giving the SID value from the PROCESS
statement: -
PROCESS IN1 WHERE (IN1.Region = 1 | IN1.Region = 6)
ORDER (IN1.Region BREAK, IN1.District BREAK, IN1.Name) SID(25);
GET FR WHERE (FR.Region
= IN1.Region);
PERFORM REPE LINKID(25);
END PROCESS IN1;
…
ROUTINE REPE [Report] LINKID(25);
TPRINT(1,JAZZ.$Today,'Program AanexmlE' COL(58),'PAGE ' COL(121),JAZZ.$PAGENBR);
PRINT (IN1.Region,IN1.District,FR.Name BREAK(IN1.Region),IN1.SalesThisMonth SUM,IN1.DateCommenced) LINE(1) ;
END ROUTINE REPE;
Note that
the SID and LINKID values are constants, not
variables, defining a fixed relationship, and is equivalent to the ROUTINE’s logic being physically within the PROCESS
loop. All PERFORM statements for a particular ROUTINE, e.g. REPE, must all specify the same LINKID value. Unless this relationship
is specified, a PRINT statement within a routine cannot use BREAK or SUM, nor reference TALLY.
A PERFORM within a PROCESS may PERFORM a ROUTINE [that PERFORMs a ROUTINE]…
that PERFORMs a print routine like ROUTINE REPE. In this case
each of the PERFORM statements use LINKID to pass the SID value down a level: -
PROCESS IN1 WHERE (IN1.Region = 1 | IN1.Region = 6)
ORDER (IN1.Region BREAK, IN1.District BREAK, IN1.Name) SID(25);
GET FR WHERE (FR.Region
= IN1.Region);
PERFORM RTN1 LINKID(25);
END PROCESS IN1;
…
ROUTINE RTN1 [Report] LINKID(25);
…
PERFORM REPE LINKID(25);
END ROUTINE RTN1;
…
ROUTINE REPE [Report] LINKID(25);
TPRINT(1,JAZZ.$Today,'Program AanexmlE' COL(58),'PAGE ' COL(121),JAZZ.$PAGENBR);
PRINT (IN1.Region,IN1.District,FR.Name BREAK(IN1.Region),IN1.SalesThisMonth SUM,IN1.DateCommenced) LINE(1) ;
END ROUTINE REPE;
There can be any number of levels, but they must all specify the same LINKID value.