Reputation: 91
I am modifying this highly critical RPGLE program where the changes involve adding a new entry parameter to it.
*entry plist
parm ecorp corp
parm edivi divi
parm eplvl parent lv
parm ewrsc wc rscd
parm eplnt plnt
parm eclvl child lv
parm emord ord
parm easst asst
parm emrwk mrwk#
parm eseqn seq #
parm easeq alt seq #
parm epprd alt seq #
parm eotst alt seq #
parm ewpqt alt seq #
parm ecmpc alt seq #
parm ewurs alt seq #
parm emurs alt seq #
parm epcdt alt seq #
parm E_Optn option
parm eeoj end of job
parm E_Pgm program
parm E_GRP MO GROUP
The program entry parameter list is as above with the exception of the last parameter which I have added now. The program works fine. But what I am a bit concerned is if this would somehow impact other areas from where this program is called. i.e Caller Programs where the last entry parameter is not passed.
This new entry parameter is going to be passed from only one another program that is part of the change. There are quite a few other programs which are going to call the program passing the same parameter list as earlier.
If (%Addr(E_Grp) <> *NULL);
Chain (E_Grp:EWURS:ssmurs) MFMPP00;
If %Found();
MchAllotted = *On;
Leave;
EndIf;
EndIf;
The only other area in the code where this parameter is used is shown above. Here, I have ensured that before the parameter is referred, it is checked that the parameter has been passed.
I have tested and this works fine. However, considering the criticality of the application, still thought to seek expert help.
Any guidance/suggestions regarding this are welcome.
Upvotes: 1
Views: 2162
Reputation: 3664
If the parameter isn't going to be modified within the program, then a safer way to use it would be to have a variable initialized to the default value, and if the parameter is passed, copy the parameter to that variable. That way, if more code is added that uses the parameter value, they won't have to remember to add the check.
... Change the name of E_GRP parameter to E_GRP_parm
dcl-s E_GRP ... INZ(whatever);
if %parms() >= %parmnum(E_GRP_parm);
E_GRP = E_GRP_parm;
endif;
You can also use this technique with a parameter that is changed:
dcl-pi *n;
something_parm char(10) OPTIONS(*NOPASS);
end-pi;
dcl-s something char(10) INZ('Whatever');
// Get the value of the "someThing" parameter if it was passed
if %parms() >= %parmnum(something_parm);
someThing = someThing_parm;
endif;
...
// Update the "someThing" parameter if it was passed
if %parms() >= %parmnum(someThing_parm);
someThing_parm = someThing;
endif;
Upvotes: 2
Reputation: 23783
You have memory corruption bug waiting to happen...
If you've tried calling the program without the last parameter and it seems to have worked, you've just gotten lucky that the memory area had not been used...thus was zeros and your %Addr(E_Grp) <> *NULL
worked as expected.
For a comparison %Addr(E_Grp) <> *NULL
your calling programs have to pass the *OMIT
special value for that parameter. Obviously that would require changing all the calling programs.
What you want is to not have to change the calling programs, thus what you need in the called program is for the parameter to be *NOPASS
.
You should convert to called program to use a PR/PI instead of an *ENTRY PLIST. Then you can mark the last parameter as options(*NOPASS *OMIT)
Then in the called program, you can check
Code
// check if the parm was passed
if %parms() > = %parmnum(E_GRP);
// check if passed parm is not NULL
if %Addr(E_Grp) <> *NULL;
//ok to use E_Grp
Chain (E_Grp:EWURS:ssmurs) MFMPP00;
If %Found();
MchAllotted = *On;
Leave;
endif;
endif;
endif;
Upvotes: 6
Reputation: 1088
As far as I know RPG is considering the parameters from the caller as "Do what you want". Meaning if PGM01 is called by PGM02 where PGM1 accepts 3 parameters and PGM2 calls with 3 parameters everything is fine. When PGM01 wants 3 parameter and PGM02 gives 2 parameter, you can do that. But you have to take care of what happens if the third parameter is *NULL (as you do). If you call PGM01 with 4 parameters, whereas PGM01 only "wants" 3, there is no issue since PGM01 does not care about that.
But I would leave the *ENTRY style behind and instead use prototypes. There you can define that if a parameter is omittable, the parameter can be used but doesn't have to. Please read the manual for D-Spec
and the PR
keyword.
Upvotes: 2