This morning I got question from an old RPG3 chum of mine:
I know a couple of questions they will ask me, what are the different parms used on sub-procedures like *OMIT/*Nopass. Didn’t we use those any way? I thought we were writing programs that did or did not necessarily get parms depending what called them using those keywords? To be honest, I know I can look it up but what the bloody hell is a sub-procedure?
My answer started off little then got into the huge waffling email stage.
Anyway, I just decided to copy/paste it here for future reference. Bear in mind this is a very high level overview and not designed to get into the nitty-gritty of anything, but if it helps anyone out there then its #winning and thats the purpose of this blog:
Lets you use the *OMIT keyword when calling you program. So, if you just dont want to pass anything, you can say *OMIT – I think it just passes *NULLS and in the program that is being called you would say something like
if %addr( parm1 ) = *NULL ; parmvalueinprogram = 'something'; else ; parmvalueinprogram = 'parm1'; endif ;
Don’t even bother. I think it just passes *NOTHING and in the program that is being called you would say something like
select ; when %parms() = 0 ; parmvalueinprogram = 'something'; when %parms() = 1 ; parmvalueinprogram = 'parm1'; endsl;
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 🙂
You can create two kinds of procedures in RPG: a main procedure (think: mainline) and a subprocedure.
A main procedure uses the RPG cycle. It is specified in the main source section. You do not need to code anything special to define the main procedure; it consists of everything before the first Procedure specification.
A sub procedure is kind of like a subroutine but you give it a name and then you can use like a %BIF.
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:
namefield = GetCustomerEmail( CusNum );
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 after the PSSR subroutine.
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:
IsThisJobInteractive = #Interactive();
The code for this sub-procedure looks like this:
// +-------------------------------------------------------------------------------------+ // | #interactive - purpose : check if job is running interactive | // | input : none | // | Returns : true or false (1/0) | // +-------------------------------------------------------------------------------------+ /if defined(#Interactive) P #Interactive B Export //*check if job is running interactive d #Interactive PI 1N //*retrieve job information (qusrjobi) api dRetrieveJobInfo... d PR Extpgm('QUSRJOBI') d @Receive Like(JobStatus) d @JobLength 10I 0 d @JobFormat 8A d @JobName 26A Const d @JobIndent 15A Const d @ErrCode Like(apiError) //data definition section //*procedure work variables dInteractive S N dJobLength S 10I 0 Inz(%Size(JobStatus)) dJobFormat S 8A Inz('JOBI0100') //*job status data-structure dJobStatus DS d JobBytesRtn 10I 0 Overlay(JobStatus:*Next) d JobBytesAvl 10I 0 Overlay(JobStatus:*Next) d JobName 10A Overlay(JobStatus:*Next) d JobUser 10A Overlay(JobStatus:*Next) d JobNumber 6A Overlay(JobStatus:*Next) d JobIdentifier 16A Overlay(JobStatus:*Next) d JobStatusCode 10A Overlay(JobStatus:*Next) d JobType 1A Overlay(JobStatus:*Next) d JobSubtype 1A Overlay(JobStatus:*Next) d JobReserv1 2A Overlay(JobStatus:*Next) d JobRunPriority 10I 0 Overlay(JobStatus:*Next) d JobTimeSlice 10I 0 Overlay(JobStatus:*Next) d JobDefaultWait 10I 0 Overlay(JobStatus:*Next) d JobPurge 10A Overlay(JobStatus:*Next) /free // Use API to retrieve job running status RetrieveJobInfo(JobStatus:JobLength:JobFormat: '*':' ':apiError); If JobType = 'I'; Interactive = *ON; Else; Interactive = *OFF; EndIf; Return Interactive; /end-free P E /endif
Now we wouldnt 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.
A service program is basically a little RPG thing you define all of you sub-procedures in. Sort of looks like an RPG program that just contains lots and lots of subroutines… but they are not subroutines they are sub-procedures. You can tell its a service program because the Hspec will say ‘NOMAIN’ and this literally means it has no MAINLINE CODE it’s just a list of sub-procedures.
Obviously, if you are using a service program in your RPG program you need to tell your RPG program to go and use that *SRVPGM to get its subprocedure list. You can either do that by adding it to your compile parm:
CRTPGM PGM('myprogram') BNDSRVPGM((TOBYSRVPGM))
or be much neater and use a Binding Directory.
Then just use your H spec:
In this example I will show you how I use the binding directory I created for Projex4i.
A binding directory is thing that has a list of service programs in it. you can add lots of them. you would use WRKBNDIRE to look at all the entries in a binding directory:
So, here you can see I have 4 service programs in my Projex4i binding directory.
Each of those service programs can have lots of sub-procedures in it. Or just one. It’s your call.
Look at SRVPGM(@SRVCORE) for example:
DSPSRVPGM SRVPGM(@SRVCORE) Service program . . . . . . . . . . . . : @SRVCORE Library . . . . . . . . . . . . . . . : PROJEX4I Owner . . . . . . . . . . . . . . . . . : NLITTEN Service program attribute . . . . . . . : RPGLE Detail . . . . . . . . . . . . . . . . . : *PROCEXP #CAPITALISE #CENTER #CHECKCOMMAND #CLEANCHEVRON #CLEANIFSDOCUMENT #CLEANIFSFOLDER #CLEANIFSURL #CLEANOBJECTNAME #CLEANWHACK #DISPLAY #DUMPCALLSTACK #FILEFMTNAME #FILEINFO #FINDCALLER #GENRANDOM #GETIBMILPAR #GETIBMISERIAL #GETIBMISYSNAME #COMMANDLINE #GETIBMIVERSION #GETPROJEXDAYS #GETPROJEXKEY #GETPROJEXSTATUS #GETSYSTEMVALUE #INTERACTIVE #LEANBACKWARD #LEANFORWARD #LOWERCASE #MBRTEXT #QUOTE #REGISTERPROJEX #RUNCOMMAND #SCANREPLACE #SEARCHINDEX #SPLITSTRING #SQUISH #SQUISHSINGLE #UNDERSCOREIT #UPPERCASE #VALID8EMAIL
For example – Note that this service program contains a sub-procedure called ‘#Interactive’ it could be called anything I just like to use #something so I know its one of my sub-procedures. Some people argue that using special characters is un-necessary noise. But I am not a number i am a free man!
So, in any program that defines this binding directory in its H-SPEC will have automatic access to all those sub-procedures from its RPG (or incidentally CL commands).
So, whenever you have repeatable code – you define it as a subprocedure then you can use it everywhere.
Procedures are as slippery as a sausage I’m sure you will agree.
IBM i Software Developer, Digital Dad, AS400 Anarchist, RPG Modernizer, Alpha Nerd and Passionate Eater of Cheese and Biscuits. Nick Litten Dot Com is a mixture of blog posts that can be sometimes serious, frequently playful and probably down-right pointless all in the space of a day. Enjoy your stay, feel free to comment and in the words of the most interesting man in the world: Stay thirsty my friend.
‘device file does not contain an entry for screen size’
Using QSNRTVMOD to find the last displayed screen size
How can I learn modern RPG using ILE or Free Form?
AS400 Modernization starts with Modernizing RPG Applications
Dirty RPG programmers need to write Clean RPG Code
IBM i create JOBLOG from RPGLE /FREE – a QMHSNDPM code example
Write to joblog messages from RPGLE /FREE – easy code example using Qp0zLprintf
How to use named indicators in RPG
What is RPG OA?