CALL

Function. 1

Format 1

Interface Definitions. 1

Parameter Names and Formats. 1

CALL and TYPE(PARAMETERS CICS) 1

Direct Reference to Parameter fields. 1

Passing Constants. 1

Passing other fields. 1

Passing Group Parameters. 1

Passing Tables. 1

RETURNS parameter 1

ABENDIF. 1

 

CALL and INVOKE both pass control [and parameters] to another object, but they are not the same: - 

·         CALL passes control to a subprogram which is written separately but linked into the same executable program as the object containing the CALL. CALL may be used in either Batch or CICS programs.   Control will return to the statement following CALL unless there’s a program error (Abnormal termination, or “Abend”).

·         INVOKE is only valid in CICS programs and web services, and the “call” is managed by CICS.  The invoked object may be another CICS program, including a CICS program within another CICS system, or it may be a web service.  Program execution may be terminated after INVOKE has passed control.

Function

To pass control and parameters to a subprogram. Control is expected to return to the calling program when the subprogram finishes.

Format

            CALL Name [(parameter [,parameter]...)] [RETURNS parameter] [ABENDIF(condition)];

For example:

            CALL CHKORDER (ORDER.*); 

 

Subprograms are written separately. This creates some error possibilities: -

·         The order and type of the parameters in the CALL statement must match exactly the corresponding parameters in the subprogram. For example, suppose that you had a routine that converted a CHAR(20) string into a DECIMAL(17) number according to particular rules.  You might write: -

      CALL StrNbr (CHARField, DECField);
But what if
CHARField were not defined as CHAR(20)?  Or DECField were BINARY or FLOAT or some other numeric format?  Or you wrote

      CALL StrNbr(DECField, CHARField);

mistakenly writing the parameters in the wrong order?

·         The subprogram and calling program must be compatible.  A subprogram can’t used in both Batch and CICS environments unless it avoids statements that are only valid in one environment, or are handled differently. This means that a dual-use subprogram can’t use any I/O statement (PROCESS, GET, DELETE, PRINT) or CICS-Specific statements (SEND, INVOKE).

 

To prevent these errors Jazz requires a DEFINE statement to define the interface.  Somewhere in your program before the CALL statement you will write (as a COPY statement) a statement like this

DEFINE StrNbr PARAMETERS BOTH DATA(

            CHARField CHAR(20) INPUT,

            Number DECIMAL(17) OUTPUT);

Now with the statement

CALL StrNbr (w.CF, w.Nbr);

Jazz can check that w.CF is either a CHAR(20) field, or some format that can be assigned to one.  Similarly w.Nbr must be compatible with DECIMAL(17).  If necessary Jazz will ensure that assignments to the exact format required by the routine are inserted before and after the CALL. 

 

If you write StrNbr with Jazz, then it must start like this: -

COPY StrNbr;

SUBPROGRAM StrNbr;

with the COPY providing the DEFINE statement above.   This COPY will also be required by Jazz with any CALL StrNbr, ensuring that the CALL and the SUBPROGRAM agree about the parameter formats.

 

A PARAMETERS definition is like any other DEFINE except with extra properties OPTIONAL for situations where a parameter is not always required, and INPUT, OUTPUT, or INOUT to show the parameter type.   Refer to Interface Definitions below for more information

Interface Definitions

When a CALL statement is encountered Jazz first looks for a corresponding DEFINE name with type PARAMETERS in the program. If it can’t find one it will attempt to find one in the Jazz CopyLib, and if necessary a COPY statement will be inserted. Interface definitions are required in Jazz both before a CALL statement, and before the SUBPROGRAM statement that starts your Jazz logic when you are writing a subprogram rather than a batch or CICS main program..

 

From the interface definition Jazz can check that

1.            If the subprogram is written for CICS, or BATCH, and so whether it is being called from the correct kind of program.

2.            There are the correct number of parameters.   A parameter is a “Level 1 item”, i.e. a Field or Group that is not within a group.

3.            That they have compatible formats and value.  “Compatible” doesn’t mean “exactly the same”, just that you’d be able to assign one to the other.  Jazz will automatically use assignments to pass parameters when the format is different.

4.            For constants and INPUT parameters Jazz will assign the parameter value to a working-storage field of the correct format before invoking the subprogram, to ensure that its value doesn’t change in the calling program.

Parameter Names and Formats

In normal use the parameter names – X, Y, and Z in this example – are irrelevant: the CALL (or INVOKE) statement passes other fields (or groups) as arguments. In the earlier example we wrote: -

            DEFINE SubProg PARAMETERS CICS DATA(

                X SMALLINT,

                Y GROUP,

                  Y1 DECIMAL(3),

                  Y2 CHAR(10),

                Z MONEY(7,2));

           

            CALL SubProg(Work.A, Work.B.*, Work.C);

Hopefully Work.A is defined as a SMALLINT, and so on. The group Work.B.* should contain two fields with appropriate format, but these do NOT have to be named Y1 and Y2.

 

How many parameters are there?   Remember that a parameter is a “Level 1 item”, i.e. a Field or Group that is not within a group, so for SubProg there are three parameters, X, Y, and Z, not 5.  Y1 and Y2 are part of group Y, not separate parameters, i.e. they are not “level 1 names”.  

 

Terminology: parameters and arguments.  

·         A subprogram has parameters. 

·         A CALL statement passes arguments. 

Thus the parameters of Subprog are X, Y, and Z, the CALL statement passes arguments Work.A, Work.B.* and Work.C.  For the duration of the CALL (until control returns to the following statement) argument Work.A is associated with parameter Subprog.X and so on, but another CALL statement may associate different arguments with the parameters.  Within SubProg a reference to Subprog.X is a reference to Work.A from this call, but not from others.  SubProg may have its own data known as Work.A, but this would be unrelated to the argument passed to it.

CALL and TYPE(PARAMETERS CICS)

For CALL statements if the parameter definition includes CICS then two parameters are automatically inserted before any named parameters. These are DFHEIBLK and DFHCOMMAREA, special control areas used by CICS. Thus although we wrote

            CALL SubProg(Work.A, Work.B.*, Work.C);

above, at the COBOL level the generated CALL statement is

            CALL 'SubProg' USING DFHEIBLK DFHCOMMAREA A OF WORK B OF WORK C OF WORK.

 

·         Within the calling program you can ignore these parameters. 

·         If you write SubProg directly in COBOL then you must remember to include them in the USING clause and define them (and A, B, and C) in the linkage section. 

·         If you create SubProg with Jazz, then the SUBPROGRAM statement’s CICS option will ensure that they are included.

Direct Reference to Parameter fields

When the program contains DEFINE name PARAMETERS DATA(… then a definition of these fields is created in working storage, just as if the DEFINE statement used TYPE(WORK). These fields will be initialised (VALUE clause, else zeros, blanks, etc), and you can use these fields in expressions in the same way as any other field of their type. This includes: you can directly name the parameter fields in the CALL statement: -

            CALL SubProg (SubProg.X, …

 

Obviously the use of a direct parameter reference ensures that the format is correct for the subprogram, but it is your responsibility to assign the appropriate value to the field before the CALL and assign it from the parameter field to the relevant field elsewhere in your program. Note however that if the parameter is defined with OUTPUT then the parameter field, SubProg.X in this example, will be initialised before the call, and any value that you have assigned to it before the CALL will be lost.

 

There will be a warning message if you directly name a parameter field defined with INPUT or OUTPUT.

 

If you’re using the parameter fields you should be aware that their value may be automatically reset by other CALL statements, so they should be treated as temporary fields and any output values should be assigned elsewhere as soon a possible.

Passing Constants

You can give constants as arguments, for example

            CALL SubProg (0, …

If the constant is invalid for the type (not a number in this case) there will be an error message, otherwise the constant will be assigned to the parameter field which will be passed to the subprogram. If the parameter is defined with OUTPUT or INOUT there will be a warning message.

 

If an optional parameter is omitted then the field in the parameter definition is set to its initial value and passed.

Passing other fields

With CALL SubProg(Work.A,… the behaviour of the CALL statement depends on the format of Work.A and whether it has been defined with INPUT, OUTPUT, or INOUT.   Thus with the parameters defined as before: -

            DEFINE SubProg PARAMETERS CICS DATA(

                X SMALLINT,

                Y GROUP,

                  Y1 DECIMAL(3),

                  Y2 CHAR(10),

                Z MONEY(7,2));

and a CALL statement: -

            CALL SubProg(Work.A, Work.B.*, Work.C);

 

If Work.A has the same format as SubProg.X (in this example SMALLINT) and the parameter is defined with INOUT (which is implied if INPUT and OUTPUT are not given) then it is passed directly.  If Work.A is any other kind of number, or has been defined with INPUT or OUTPUT, then Jazz will pass the parameter by assignment: -

            IF the parameter is INPUT or INOUT THEN

                        The value of Work.A will be assigned to SubProg.X

            ELSE

                        SubProg.X is initialized

            END IF

            CALL SubProg (SubProg.X

            IF the parameter is INOUT or OUTPUT THEN

                        Assign SubProg.X to Work.a

            END IF

 

This allows you to CALL SubProg(any-number, …) with Jazz handling all the data conversion for you.

 

If Work.A is another kind of field then an assignment SubProg.X = Work.A would be invalid, so an error message would be produced

 

For a parameter like Work.X to be passed directly it must not only be defined with INOUT, it must also have EXACTLY the same type as the corresponding field defined in the TYPE(PARAMETERS) definition. This means: -

1.            The same type:  SMALLINT <-> SMALLINT, INTEGER <-> INTEGER, DECIMAL<-> DECIMAL, etc. For this purpose Jazz regards MONEY and DECIMAL as the same type: the only difference between these types is in their display format.

2.            It must have the same number of digits, precision, and length.  Thus CHAR(10) and CHAR(11) are different, as are DECIMAL(5) and DECIMAL(4), or DECIMAL(5) and DECIMAL(5,2).

3.            Groups must have exactly the same structure. Thus in

                        CALL SubProg(Work.A, Work.B.*, Work.C);

Work.B must have a DECIMAL(3) element, followed by a CHAR(10) element, and no other elements. If Work.B were defined like this: -

            B GROUP,

                B1 DECIMAL(2),

                B2 CHAR(9),

                END GROUP,

then either the mismatch of B1 with Y1 or the mismatch of B2 with Y2 would have been sufficient to have implied “Different”. However this may be too strict in practice, so Jazz relaxes the rules a bit: -

Passing Group Parameters

If a group named in the CALL statement does not exactly match the parameter in the DEFINE, Jazz will still pass a group directly if the following rules are met: -

IF         CALL/INVOKE names a CHAR field or a GROUP that contains only CHAR and PIC fields

AND

            The corresponding parameter is also a CHAR field or a group containing only CHAR and PIC fields,

AND

            The field/group named in the CALL has the same length as the Field/Group defined as parameter

THEN  Jazz produces a warning message, and will pass the parameter directly for INOUT, by assignment for INPUT or OUTPUT. This allows you to write code like this: -

            CALL Routine(PrintLine1.*);

           

            CALL Routine(Printline2.*);

Now you don’t have to worry whether Printline1 and Printline2 have the same structure, merely that they have the same total length.

 

Provided that the groups have the same length, if either the passed field or parameter definition contains fields other than CHAR and PIC then an error message is produced rather than a warning. You can ignore this message if you are confident that there will be no problems: Jazz will create a COBOL CALL statement that passes the group by reference.   However if there are differences – for example the CALL group contains a SMALLINT value where the DEFINE group specifies DECIMAL – then unpredictable results, probably an unrecoverable abend, will result.

 

If these rules are followed except that the parameter/passed field have a different length, then there will be a message and the parameter will be passed by assignment.  Group assignment follows CHAR rules: if the target is too short the data is truncated, if the data is too long it is extended with blanks.

Passing Tables

Individual table elements can be passed as a normal (scalar) parameter.  For example, here we pass each element of W.Tabl to SubRtn.

DEFINE SubRtn PARAMETERS ANY DATA(

    Value DECIMAL(7,2) INOUT);

DEFINE W DATA(

    Tabl (10) DECIMAL(5,2));

FOR W.Tabl(JZ.IX1);

    CALL SubRtn(W.Tabl(JZ.IX1));

END FOR;

 

Because the format of SubRtn.Value is DECIMAL(7,2) but W.Tabl has format DECIMAL(5,2) then in this case the argument must be passed by assignment.  The logic above is equivalent to

FOR W.Tabl(JZ.IX1);

    SubRtn.Value = W.Tabl(JZ.IX1);

    CALL SubRtn(SubRtn.Value);

    W.Tabl(JZ.IX1) = SubRtn.Value;

END FOR;

 

A parameter item can have a dimension, and be passed like any other field.  For example

DEFINE TablData PARAMETERS ANY DATA(

    Table (10,3) DECIMAL(7,2) INOUT);

DEFINE W DATA(

    Tabl (10,3) DECIMAL(5,2));   

CALL TablData(W.Tabl(*,*));

 

In the CALL statement * indicates that the whole extent is passed, and distinguishes this situation from the previous example where a single table element was passed as a scalar parameter.  As always the parameter (TablData.Table) and argument (W.Tabl) must be compatible, with an additional rule for tables that the dimensions must be identical. 

 

You can pass an array cross section, i.e. a single extent of a multi-dimension table.

DEFINE TablData PARAMETERS ANY DATA(

    Table (10) DECIMAL(7,2) INOUT);

DEFINE W DATA(

    Tabl (10,3) DECIMAL(5,2));

FOR JZ.IX2 = 1 TO 3;   

    CALL TablData(W.Tabl(*, JZ.IX2));

END FOR;

or, with Tabl defined like this: -

DEFINE W DATA(

    Tabl (3, 10) DECIMAL(5,2));

FOR JZ.IX1 = 1 TO 3;   

    CALL TablData(W.Tabl(JZ.IX1, *));

END FOR;

 

For further information about Parameters and the use of External Routines, see

            Language Reference: The Define Statement

and      Users’ Guide: Jazz Logic/ External Routines

RETURNS parameter

You can add RETURNS to a CALL statement like this: -

            CALL SUB1  (INFILE.I-ID) RETURNS COBOL.RETURN-CODE;

This is equivalent to the normal form

CALL SUB1 (INFILE.I-ID, COBOL.RETURN-CODE);

with the corresponding parameter having property OUTPUT.

    DEFINE SUB1 PARAMETERS BATCH DATA(

            P1 LIKE INFILE.I-ID,

            P2 LIKE COBOL.RETURN-CODE OUTPUT);   

 

Both forms generate identical COBOL.  As with any OUTPUT parameter, the parameter is set to its default value (almost always 0 or blank) before the CALL.

 

RETURNS names a single scalar reference, it may not

·         give more than one reference

·         a generic reference

·         give a constant value: ('ROBERT', X'A1A2', 1234, 12.34) etc.

 

The reference must be the final parameter value of the DEFINE SUB1 statement, which must have property OUTPUT.

ABENDIF

This option is not yet available: this section is provided for discussion. The keyword might be FAILIF.

MANASYS Jazz programs usually terminate through their normal exit, but if they encounter an error from which they can’t recover, for example trying to read from a file that doesn’t exist, or add a decimal number that doesn’t have the correct packed-decimal format, then they “abend”, or terminate abnormally, and exit through their Abend Exit.

 

CALL and INVOKE statements may return to this program having executed “normally”, but the values returned in their output parameters may indicate an error that should force an abend.  For example, you’ve invoked a subprogram to perform an update but the parameters return indicate that the update failed.  If you wish this to immediately terminate your program and force it to abend, you can write

            ABENDIF (condition)

If the condition is true, then your program will abort with suitable messages.