ROUTINE and PERFORM

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));

Report Routines

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 PROCESSORDER (…) 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.