Prototype (PR) and procedure interface (PI) D-specs are special and different from a regular D-spec data structure, so they have some special keywords that apply only to them.
by David Shirey
Editor's Note: This article is excerpted from chapter 15 of 21st Century RPG: /Free, ILE, and MVC, by David Shirey.
In an earlier excerpt, we explored ILE RPG's prototype structure. Now let's look at PR- and PI-specific Keywords.
PR- and PI-specific Keywords: Top-Level Keywords
The first set of keywords that we can look at apply to the top level of the PR/PI D-spec. This would be things like
EXTPGM('DWS0001')
This tells the prototype what program ID is being accessed with this prototype structure. It is used on the PR in the calling program. It is not used in the called program since it already knows who it is.
This keyword is required if you are using the CRTBNDRPG compile command.
The keyword is not required using CRTRPGMOD/CRTPGM option where they are bound together if the name of the PR D-spec is the same as the module being called.
One thing to note is that you cannot use this keyword if you are doing a function call and have a length on the top level of the PR. Which means a program doing a function call must use the program name as the name of the PR D-spec, and it must be compiled using CRTRPGMOD/CRTPGM. You cannot do it using CRBNDRPG because that requires the EXTPGM keyword.
There, see. What could be simpler than that?
EXTPROC
This keyword indicates the name of a sub-procedure that is being accessed by the prototype. It is used on the PR.
Since this is calling a sub-procedure (EXTPGM calls a program), the program must be compiled with CRTRPGMOD/CRTPGM, and so this keyword is optional as long as the name of the PR D-spec is the same as the name of the sub- procedure being called. That is why we did not need to specify it on our service program example in chapter 10.
OPDESC
This keyword passes operational descriptors (length and character type) to the called module. It is mostly used for APIs and requires the keyword on both the PR and the PI.
Even though I will probably be sorry that I do this, I want to also mention the EXPORT keyword that is used in service programs.
This is used on the prototyping P-specs for sub-procedures in a service program to indicate if a given sub-procedure can be used outside of that service program. It is not placed on the PR or PI D-specs.
Early on, I would get confused and think that this keyword went on the PR or PI associated with that sub-procedure. It does not. I thought you might get confused, too, so I mentioned this now. Now you will probably get confused because of what I have said. Can’t win.
PR and PI-specific Keywords: Subfield Keywords
The first thing I want to stress is that all the keywords that you could normally apply to a D-spec can be applied here. That includes things like LIKE (which lets you relate a field on a D-spec, even a PR or PI D-spec) to a field that is already defined in the program), LIKEDS (which lets you define a data structure in the prototype), and so on.
The other keywords that we are going to look at are applied to the subfields within the PR or PI D-spec and are specific to ILE. The rest of this chapter and the next will pretty much be devoted to these subfield-level keywords.
Each particular subfield can have multiple keywords applied to it, so don’t let that throw you if you see it.
Of course, subfields can also use the other keywords that you apply to regular, more normal D-specs; often people get confused about what has been introduced for ILE and what was there all along. For example, you will often see the VARYING keyword involved in a discussion of prototyping keywords, but that is (in the opinion of some experts) really a data type with special characteristics (even though it is a keyword) and is not confined to prototyping. Against my better judgment, we will talk about this keyword a bit more in the next chapter.
Options(*NOPASS)
Let’s start with the easy one, the OPTIONS keyword and most of its family of parameters.
The first parm is *NOPASS, which lets you decide if the passing of a parm is required or optional. Specifying *NOPASS makes it optional; otherwise it is required.
This is pretty simple, but keep one thing in mind. If you have multiple parms on the prototype, then you must list them so that the required parms (not *NOPASS) are listed first. This is because once you code one parm to be *NOPASS, then every parm after that must be *NOPASS (that is, optional). Can you dig what I’m sayin’?
Remember that *NOPASS is not the same as omitting something. *NOPASS simply means that you don’t have to include that parameter, that it is not required. I know that sounds weird, but keep reading.
In fact, skipping parms is not allowed when you use *NOPASS. That is, in the example above, you can’t skip MSG2 and expect to send MSG3 and MSG4. You can really only skip working your way backward from the end of the parms. That is, you could decide not to send MSG3 and therefore MSG4 but send MSG2. What’s important is that your parameter string is contiguous. There can’t be any holes because when using *NOPASS the system can’t tell what is missing. In essence, *NOPASS allows you to skip the rest of the parameter list.
While it sounds like a good idea (to be able to not send parms), just be careful in the called program. If you would reference one of those *NOPASS parms then, as IBM puts it, “unpredictable results will occur.” Sometimes, just because you can do something, doesn’t mean you should. Know what I mean, Vern?
Skipping Parms: OPTIONS(*OMIT)
Hey, didn’t I just say that you can’t skip parms?
Well, yes, but, baby, I can explain! What I said is you can’t skip parms by using the *NOPASS. But there is a way to do it.
I’m talking about the *OMIT parm on the OPTIONS keyword. By using that and *NOPASS, you make the parm optional and allow it to be skipped. For example:
Now in this case, we can call the sub-procedure and omit MSG3 while still passing MSG4 (but not MSG5 because we don’t need to this time, and it is optional).
CALL VAL_PRDNO(PRDNO:MSG2:*OMIT:MSG4);
Please note that when we do the call, we will use the *OMIT in place of the parm being skipped.
Now, if you’re a smart aleck, you may be wondering how to tell in your logic in the called program which parms have been skipped. It’s pretty easy, actually. If you think that a skip is possible, check to see how many parms there are and then start working backward from the end to see which ones are null.
Obviously, there is a bit of fooling around you have to do if you skip parms, but it’s up to you. I would just always send the parms, but people rarely ask me what I think, so who cares? And, equally obviously, if your parms are ginormous, you may have good reason to not send them if they are not needed.
Oddball Keywords
Just so no one feels left out and I don’t get angry texts from IBM keywords, here are a couple more.
Options(*STRING)
This will stick an x'00' value onto the end of the string you are dealing with. This is for use with UNIX-oriented APIs.
Options(*RIGHTADJ)
Can’t figure out what this one does. Oh, wait a minute. Just a wild guess, but—right-adjust the parameter?
I did happen to notice, though, in one of Scott Klement’s presentations that he mentions that he has never found a use for this option. Seriously? If Scott hasn’t found a use, I really doubt any of us will.
Options(*TRIM)
This keyword will trim blanks off of the front and back of the field. This one could really be useful, saving you the trouble of doing it with a BIF in your program.
Options(*NULLIND)
This keyword indicates that you are going to pass null-capable data. You know where that comes in, right? Yep, SQL databases. Freaks. You have to use the %NULLIND BIF in your RPG program to determine what is in the field you pass, but it all starts with the Options keyword.
LATEST COMMENTS
MC Press Online