Sub-Procedures are very cool, if you like that kind of thing (which I do!)
Probably my favorite RPG enhancement over the years. Coming from RPG3/400 to RPGLE this is something you will definitely need to learn. It’s been used extensively everywhere I’ve worked since leaving the boundaries of ‘JBA’ code and Green screen land 🙂
RPG Sub procedures The Basics
Quite simply a sub-procedure is just like a sub-routine with a few key differences
Here is a very simple example:
Imagine you wrote a sub-procedure that received a parameter of ‘customer number’ and it went and found the ‘customer email address’ and you decide to call this procedure ‘GetCustomerEmail’ then you would use it in your RPG like this:
and that would execute the procedure and return the name into the variable namefield.
now you could define that subprocedure in your program – right at the bottom, below any old subroutines.
Here is a slightly more complex example:
How to use a sub-procedure to easily do same thing in lots of programs. Lets say I have the need to check if I am running in Batch or Interactive?
I had this problem ages ago, so I added a sub-procedure to my main service program that would return a YES or NO when asked ‘am i running interactive’
You could code it in your RPG like this:
// do something
endif;
The code for this sub-procedure might look like this:
// check if job is running interactive
Dcl-Proc InteractiveJob Export;
Dcl-PI *n Ind;
end-pi;
// retrieve job information (qusrjobi) api
Dcl-PR RetrieveJobInfo EXTPGM('QUSRJOBI');
@Receive LIKE(JobStatus);
@JobLength Int(10);
@JobFormat Char(8);
@JobName Char(26) CONST;
@JobIndent Char(15) CONST;
@ErrCode LIKE(APIERROR);
End-PR;
// data definition section
// procedure work variables
Dcl-S Interactive Ind;
Dcl-S JobLength Int(10) INZ(%SIZE(JobStatus));
Dcl-S JobFormat Char(8) INZ('JOBI0100');
// job status data-structure
Dcl-DS JobStatus;
JobBytesRtn Int(10) OVERLAY(JobStatus:*NEXT);
JobBytesAvl Int(10) OVERLAY(JobStatus:*NEXT);
JobName Char(10) OVERLAY(JobStatus:*NEXT);
JobUser Char(10) OVERLAY(JobStatus:*NEXT);
JobNumber Char(6) OVERLAY(JobStatus:*NEXT);
JobIdentifier Char(16) OVERLAY(JobStatus:*NEXT);
JobStatusCode Char(10) OVERLAY(JobStatus:*NEXT);
JobType Char(1) OVERLAY(JobStatus:*NEXT);
JobSubtype Char(1) OVERLAY(JobStatus:*NEXT);
JobReserv1 Char(2) OVERLAY(JobStatus:*NEXT);
JobRunPriority Int(10) OVERLAY(JobStatus:*NEXT);
JobTimeSlice Int(10) OVERLAY(JobStatus:*NEXT);
JobDefaultWait Int(10) OVERLAY(JobStatus:*NEXT);
JobPurge Char(10) OVERLAY(JobStatus:*NEXT);
End-DS;
// Use API to retrieve job running status
RetrieveJobInfo (JobStatus:JobLength:JobFormat: '*':' ':apiError);
If JobType = 'I';
Interactive = *ON;
Else;
Interactive = *OFF;
EndIf;
Return Interactive;
End-Proc;
Now we wouldn't want to add this bunch of code to everything we wrote that wanted to use it would we?
In the olden days we might have done it in a /COPYBOOK but this requires re-compilation of everything if we change the copybook. Thats smelly.
Luckily the solution to this "lots of code being repeated" problem is SERVICE PROGRAMS. More on *SRVPGM's in a later section of this lesson.