× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



Good stuff, Chuck - would we had the *POINTER type and all sooner.

I'll also take a look at the references. I've long wondered exactly what IBM developers did for the various RTV* types of commands, so that we did not have to specify all the return variables.

To add to the MONMSG idea - a generally good idea is to clean up unneeded messages from the job log. So the RCVMSG you describe would best have DLT(*YES) - again, an easy thing to add that removes confusing entries from the job log.

This same technique is well applied to almost any test where an exception is checked, yet the test need not be visible to customers or users.

Enough rambling late of an evening! Waiting to watch the latest Doctor Who!

Regards
Vern

On 4/13/2013 4:27 PM, CRPence wrote:
On 12 Apr 2013 16:30, CRPence wrote:
<<SNIP>>
I do not recall, but I think the most common way utilized to more
conspicuously force the MCH3601 error before any processing, was to
have the first request for each parm### processing issue the request
CHGVAR &RTNVAR### &RTNVAR### just as Vern had noted in an earlier
reply. <<SNIP>>
I probably also should have noted that the technique described, of
using the MONMSG MSGID(MCH3601) [with RCVMSG MSGTYPE(*EXCP)] to deal
with the *NULL addressing for the parameter variable, is compatible all
the way back to the S/38. So I went on a quest for something better
[near the end of this message]. Along the way...

FWiW I searched to find if there was some apparent /convention/ for
handling the condition. In some examples I had located, a CHGVAR from
the return variable into a local variable was used to detect the
condition early, and others used local variables to do all of the work
earlier in the program and then only in the end of the program do they
set the return values into parameter variables from the local variables
where the monitor would be in effect. I also did see a couple doing the
CHGVAR &V &V, but the more I looked at that request, the more I disliked it.

Here is an example using a global monitor to ignore the condition,
but then cleaning up all of the messages upon a normal exit:
Subject; Tool - Retrieve Message Queue Attributes with Command: RTVMQGQA
by API QMHRMQAT
http://archive.midrange.com/midrange-l/200712/msg01228.html

Here is a discussion thread on the same topic of RTNVAL(*YES), plus
use of a CLLE for which the CL CALL does not get CPD0172 and thus for
which there is a similar usage for the same MCH3601 monitor:
Subject: CL Parameter
http://archive.midrange.com/rpg400-l/200207/threads.html#00033

And a discussion thread on optional parameters for CLLE but also
RTNVAL(*YES):
http://archive.midrange.com/midrange-l/200904/threads.html#00555

So I figured... There are almost certainly better ways, having since
become available, to accomplish the same thing in a CLP or CLLE.? For
example just as with RPG using its %ADDR to perform the test without
having to deal with an exception, the CL eventually added a builtin with
the same name [also as %ADDRESS]. So very likely the effectively
identical technique used for a PARM in RPG can be used in a CLP.?
Although probably not for this case [per being invoked by a command],
there should be the parameter operational descriptor information as a
possibility, to be obtained when using a CLLE; e.g. Test for Omitted
Argument (CEETSTA) API.

So anyhow... I was wondering if perhaps the following can be used to
avoid the MCH3601. Although the parameter variable is declared as
automatic storage, there is a chance that trying to address the value
using the %ADDR would yield a *NULL pointer result instead of the
MCH3601. I seem to recall playing around with something like this
sometime after the *PTR type became available, but I do not recall what
was the effect:

Pgm Parm(&RtnVal001 &RtnVal002)
/* parameter declarations */
Dcl &RtnVal001 *char 10
Dcl &RtnVal002 *char 10
/* pseudo-constant null pointer variable; for a CLP */
Dcl &NullPtr *PTR STG(*AUTO) ADDRESS(*NULL)
/* In a CLP ; the docs say this is still required */
If cond(%addr(&RtnVal001) *eq &NullPtr) Then(*n)
Else Do
/* processing for RtnVal001 can occur here */
EndDo
/* In a CLLE ; the docs say the *NULL as spcval is OK */
If cond(%addr(&RtnVal001) *eq *NULL) Then(*n)
Else Do
/* processing for RtnVal001 can occur here */
EndDo

Reference for difference between CLP and CLLE noted above:
http://pic.dhe.ibm.com/infocenter/iseries/v7r1m0/topic/cl/if.htm
"...
Condition (COND)
...
To test if a pointer has a null value, the CL pointer variable can be
compared to the special value *NULL if the CL source is being compiled
with the Create CL Module (CRTCLMOD) or Create Bound CL Program
(CRTBNDCL) command. If the CL source is being compiled with the Create
CL Program (CRTCLPGM) command, compare the CL pointer variable to
another CL pointer variable that was declared with ADDRESS(*NULL) and
has not been changed.
..."

Then after some more searching the web... I found the following
source at the following link with the apparent intended "Subject: Number
of Parameters in CL program". There the author later claims the code
"rocks as expected", which I infer means the code is functional :-)
Whether using the CHGVAR is required first as shown, as contrasted with
my code above which just uses the expression in the COND(), is not
clear. But per use of the special value *NULL in the COND(), the
following code would be valid only for a CLLE rather than a CLP; i.e.
use the pseudo-constant null pointer variable to compare against, if
using CLP. From this example, I am guessing that my above code probably
would also be functional as written:
http://www.code400.com/forum/showthread.php/8263-Number-of-Parametesrs-in-CL-program

pgm parm(&Parm1 &Parm2)
dcl &ptrParm type(*ptr)
chgvar var(&ptrParm) value(%addr(&Parm1))
if cond(&ptrParm = *NULL ) then(do)
/* Parm1 not passed ? */
enddo
chgvar var(&ptrParm) value(%addr(&Parm2))
if cond(&ptrParm = *NULL ) then(do)
/* Parm2 not passed ? */
enddo



As an Amazon Associate we earn from qualifying purchases.

This thread ...

Replies:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.