When you pass control to another program or procedure, you can also pass information to it for modification or use within the receiving program or procedure.
You can specify the information to be passed on the PARM parameter on the Call (CALL) command or the Call Bound Procedure (CALLPRC) command. The characteristics and requirements for these commands are slightly different.
For instance, if PROGA contains the following command:
CALL PROGB PARM(&AREA)
then it calls PROGB and passes the value of &AREA to it. PROGB must start with the PGM command, which also must specify the parameter it is to receive:
PGM PARM(&AREA) /* PROGB */
For the Call (CALL) command or the Call Bound Procedure (CALLPRC) command, you must specify the parameters passed on the PARM parameter, and you must specify them on the PARM parameter of the PGM command in the receiving program or procedure. Because parameters are passed by position, not name, the position of the value passed in the Call (CALL) command or the Call Bound Procedure (CALLPRC) command must be the same as its position on the receiving PGM command. For example, if PROGA contains the following command:
CALL PROGB PARM(&A &B &C ABC)
it passes three variables and a character string, and if PROGB starts with:
PGM PARM(&C &B &A &D) /*PROGB*/
then the value of &A in PROGA is used for &C in PROGB, and so on; &D in PROGB is ABC. The order of the DCL statements in PROGB is unimportant. Only the order in which the parameters are specified on the PGM statement determines what variables are passed.
In addition to the position of the parameters, you must pay careful attention to their length and type. Parameters listed in the receiving procedure or program must be declared as the same length and type as they are in the calling procedure or program. Decimal constants are always passed with a length of (15 5).
When you use the Call Bound Procedure (CALLPRC) command and pass character string constants, you must specify the exact number of bytes, and pass exactly that number. The called procedure can use the information in the operational descriptor to determine the exact number of bytes passed. You can use the API CEEDOD to access the operational descriptor.
When you use the CALL command, character string constants of 32 bytes or less are always passed with a length of 32 bytes. If the string is longer than 32, you must specify the exact number of bytes, and pass exactly that number.
The following is an example of a procedure or program that receives the value &VAR1:
PGM PARM(&VAR1) /*PGMA*/ DCL VAR1 *CHAR LEN(36) . . . ENDPGM
The CALL command or Call Bound Procedure (CALLPRC) command must specify 36 characters:
CALLPRC PGMA(ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ)
The following example specifies the default lengths:
PGM PARM(&P1 &P2) DCL VAR(&P1) TYPE(*CHAR) LEN(32) DCL VAR(&P2) TYPE(*DEC) LEN(15 5) IF (&P1 *EQ DATA) THEN(CALL MYPROG &P2) ENDPGM
To call this program, you could specify:
CALL PROG (DATA 136)
The character string DATA is passed to &P1; the decimal value 136 is passed to &P2
Referring to locally defined variables incurs less overhead than referring to passed variables. Therefore, if the called procedure or program frequently refers to passed variables, performance can be improved by copying the passed values into a local variable and referring to the locally defined value rather than the passed value.
When calling an OPM CL program, the number of parameters that are passed to it must exactly match the number that is expected by the program. The number that is expected is determined at the time the program is created. (The operating system prevents you from calling a program with more or fewer parameters than the program expects). When calling an ILE program or procedure, the operating system does not check the number of parameters that are passed on the call. In addition, the space where the operating system stores the parameters is not reinitialized between procedure calls. Calling a procedure that expects "n" parameters with "n-1" parameters makes the system use whatever is in the parameter space to access the "nth" parameter. The results of this action are very unpredictable. This also applies to procedures written in other ILE languages that call CL procedures or are called by CL procedures.
This also gives you more flexibility when you write ILE CL procedures, because you can write procedures that have variable length parameter lists. For example, based on the value of one parameter, a parameter that is specified later in the list may not be required. If the controlling parameter indicated an unspecified optional parameter, the called procedure should not attempt to refer to the optional parameter.
You can also specify the special value *OMIT for any parameter that you want to omit from the parameter list. If you specify *OMIT for a parameter, the calling procedure passes a null pointer. The procedure that is called has to be prepared to handle a null pointer if it refers to a parameter that is omitted. In control language (CL), you can check for a null pointer by monitoring for MCH3601 on the first reference to the omittable parameter. The procedure must take appropriate action if it receives a MCH3601.
When calling procedures, you can pass arguments by reference and by value.
The following example has two CL procedures. The first procedure expects one parameter; if that parameter remains unspecified, results will be unpredictable. The first procedure calls another procedure, PROC1. PROC1 expects one or two parameters. If the value of the first parameter is '1', it expects the second parameter as specified. If the value of the second parameter is '0', it assumes that the second parameter remained unspecified and used a default value instead. PROC1 also uses the CEEDOD API to determine the actual length that is passed for the second parameter.
MAIN: PGM PARM(&TEXT)/* &TEXT must be specified. Results will be + unpredictable if it is omitted.*/ DCL VAR(&TEXT) TYPE(*CHAR) LEN(10) CALLPRC PRC(PROC1) PARM('0') CALLPRC PRC(PROC1) PARM('1' &TEXT) CALLPRC PRC(PROC1) PARM('1' 'Goodbye') ENDPGM PROC1: PGM PARM(&P1 &P2) /* PROC1 - Procedure with optional + parameter &P2 */ DCL VAR(&P1) TYPE(*LGL) /*Flag which indicates + whether or not &P2 will be specified. If + value is '1', then &P2 is specified */ DCL VAR(&P2) TYPE(*CHAR) LEN(10) DCL VAR(&MSG) TYPE(*CHAR) LEN(10) DCL VAR(&PARMPOS) TYPE(*CHAR) LEN(4) /* + Parameter position for CEEDOD*/ DCL VAR(&PARMDESC) TYPE(*CHAR) LEN(4) /* + Parameter description for CEEDOD*/ DCL VAR(&PARMTYPE) TYPE(*CHAR) LEN(4) /* + Parameter datatype from CEEDOD*/ DCL VAR(&PARMINFO1) TYPE(*CHAR) LEN(4) /* + Parameter information from CEEDOD */ DCL VAR(&PARMINFO2) TYPE(*CHAR) LEN(4) /* + Parameter information from CEEDOD */ DCL VAR(&PARMLEN) TYPE(*CHAR) LEN(4) /* + Parameter length from CEEDOD*/ DCL VAR(&PARMLEND) TYPE(*DEC) LEN(3 0) /* + Decimal form of parameter length*/ IF COND(&P1) THEN(DO) /* Parm 2 is+ specified, so use the parm value for the + message text*/ CHGVAR VAR(%BIN(&PARMPOS 1 4)) VALUE(2) /* Tell + CEEDOD that we want the operational + descriptor for the second parameter*/ CALLPRC PRC(CEEDOD) PARM(&PARMPOS &PARMDESC + &PARMTYPE &PARMINFO1 &PARMINFO2 &PARMLEN) + /* Call CEEDOD to get the length of data + specified for &P2*/ CHGVAR VAR(&PARMLEND) VALUE(%BIN(&PARMLEN 1 4)) /* + Convert the length returned by CEEDOD to + decimal format*/ CHGVAR VAR(&MSG) VALUE(%SST(&P2 1 &PARMLEND)) /* + Copy the data passed in to a local variable*/ ENDO ELSE CMD(CHGVAR VAR(%MSG) VALUE('Hello')) /* Use + "Hello" for the message text*/ SNDPGMMSG MSG(&MSG) ENDPGM