Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

parm length question - cmd/ cl cpp/ called rpg program

213 views
Skip to first unread message

Craig Rutledge

unread,
Apr 8, 2000, 3:00:00 AM4/8/00
to
This is working in production.. The list parameter is not defined in the
command processing program the same as in the CMD or in the called RPG
program.


- - -
The command has a parm defined as

PARM KWD(SGRP) TYPE(*DEC) LEN(2 0) DFT(*ALL) +
SNGVAL((*ALL -1)) MAX(10) PROMPT('Sales +
Group# (Or *ALL)')

- - -
The command processing cl accepts this parm as ONE long
PGM PARM(&LIST1)
DCL VAR(&LIST1) TYPE(*CHAR) LEN(1)

CALL RPGPGM PARM(&LIST)

The cl does nothing with this value except pass it a RPG program.

- - - -

The called RPG program accepts this parm. then uses the info from the DS
C *ENTRY PLIST
C PARM LIST1

D LIST1 DS
D #SG 1 2B 0
D SG 3 22P 0
D DIM(10)
D PACKEVEN

- - -

Now my question is How the heck does this work? The field the CL program
is clearly defined as 1 long character. The field LIST1 in the RPG program
is defined as 22 long. Yet this works fine. The RPG processes the parm
like a normal list parm..

I have always believed the parm attributes and length had to match between
CMD / CPP / and any called programs..

- - -
I needed to check the list values in the CL for some processing logic..
Imagine my surprise when I saw the list wasn't even defined in the CL!
(v4r4)


Tim

unread,
Apr 8, 2000, 3:00:00 AM4/8/00
to
You have to remember how AS/400 passes parameters. The AS/400 passes
parameters by reference, that is, a pointer to the parameter is passed to
the called program. This pointer is then used as the base address for the
variable in the called program.

So in your example, the command parser is passing a pointer to a structure.
The CL program is setting the base address of the variable &LIST1 to the
value of that pointer. To be sure, if the CL program referenced the value of
&LIST is would only see the first byte. When the CL program calls the RPG
program, it also simply passes a pointer for each parameter. For &LIST1 the
value in the pointer happens to point at the same address that the command
passed to the CL program.

This is *VERY* common technique. I have used this technique to enable my OPM
programs to use ILE API's. I simply write an ILE CL wrapper and use 1 byte
parameters as place holders

"Craig Rutledge" <cra...@vol.com> wrote in message
news:Q7LH4.4184$hr2.9...@news-east.usenetserver.com...

Craig Rutledge

unread,
Apr 8, 2000, 3:00:00 AM4/8/00
to

Very good explanation...

It still looks kinda strange in the code though.

Guess I can take the rest of the day off now, I learned something new
today.

Thanks again.

- - -


Tim <scot...@home.com.xyz> wrote in message
news:48MH4.6202$T4.1...@news1.rdc1.ne.home.com...

Simon B

unread,
Apr 13, 2000, 3:00:00 AM4/13/00
to
Tim wrote in message <48MH4.6202$T4.1...@news1.rdc1.ne.home.com>...

>You have to remember how AS/400 passes parameters. The AS/400
passes
>parameters by reference, that is, a pointer to the parameter is
passed to
>the called program. This pointer is then used as the base address
for the
>variable in the called program.


(snip)

This thread pointed me in the right direction to fix a *different*
problem. We were writing a trigger program for a file with a large
variable length field in it.

As usual, we pulled on our trigger buffer description in from
another program:

* Trigger buffer
D TrgBuf DS 32767
D FileName 1 10
D LibName 11 20
D MbrName 21 30
D TrgEvent 31 31
D TrgTime 32 32
D ComtLckLvl 33 33
D CCSID 37 40B 0
D OldOff 49 52B 0
D OldLen 53 56B 0
D OldNullOff 57 60B 0
D OldNullLen 61 64B 0
D NewOff 65 68B 0
D NewLen 69 72B 0
D NewNullOff 73 76B 0
D NewNullLen 77 80B 0
D InsertEvt C Const('1')
D DeleteEvt C Const('2')
D UpdateEvt C Const('3')

The DS was set up with a length of 32767, the maximum allowed.

As usual, we pulled in the description of the file as an external
structure:

D RcdFmt e extname(ourfile)

and pulled the data from the after trigger into this structure using
%subst:

C eval Start = NewOff + 1
C eval RcdFmt = %subst(TrgBuf:Start:NewLen)

We have used this approach many times before, but this time it went
bang - our record was so large that the new record offset pointed
*outside* our 32767 structure, and we couldn't make the structure
any bigger.

It was it this point that I remembered that the AS/400 passes parame
ters*by reference*. This means that even if your parameter isn't
long enough to hold all the data, the data is still there. You just
can't usually see it. Pointers to the rescue!

We removed the 32767 from the trigger buffer structure - we can
really only rely on the first 80 anyway. We then added a based
pointer to the external file description:

D RcdFmt E DS extname(ourfile)
based(@RcdFmt)

and used the %addr BIF to position the pointer off in cyberspace
somewhere:

c eval @RcdFmt = %addr(BufTrg) + NewOff

And it worked!

This approach seems to me to have a couple of advantages. We don't
need an arbitrarily sized data structure, and because we aren't
copying records around it will be a bit quicker.

I hope someone finds this useful...

--
Cheers,
Simon Brunning
TriSystems Ltd.
sbru...@trisystems.co.uk
The opinions expressed are mine, and are not necessarily those of my
employer.

jonpi...@eircom.net

unread,
Feb 26, 2014, 9:48:05 AM2/26/14
to
THANK YOU, THANK YOU, THANK YOU, THANK YOU!

25 years I was working on IBM Midrange before getting sick and having 9 years off work. Now I'm back, I've been trying to find out how to call a trigger program from *LIBL (can't be done, obviously). It was suggested to me that I use a CL program, that will NEVER need to be changed, to call the program with the required processing, but how do I define a variable length parameter for the buffer? (I have to code for the possibility that the record length of the triggered file may change and for the fact that the same trigger program is called for multiple files).

I never realised that parameters are, in fact, pointers. (Does this make me stupid?)

I will never forget this technique and I thank you so much for "pointing" this out. (Did you see what I did there? :-) )

Ken Sims

unread,
Feb 26, 2014, 10:02:21 AM2/26/14
to
Hi Jon -

On Wed, 26 Feb 2014 06:48:05 -0800 (PST), jonpi...@eircom.net wrote:

>25 years I was working on IBM Midrange before getting sick and having 9 years off work. Now I'm back, I've been trying to find out how to call a trigger program from *LIBL (can't be done, obviously). It was suggested to me that I use a CL program, that will NEVER need to be changed, to call the program with the required processing, but how do I define a variable length parameter for the buffer? (I have to code for the possibility that the record length of the triggered file may change and for the fact that the same trigger program is called for multiple files).

The parameters passed to the trigger program are passed by reference.
That is, the values aren't passed. What is passed are the addresses
of where those values reside in memory.

So if the CL program is not going to actually do anything with the
buffer, just include it as a parameter on the call to the program that
will do that actual processing, the length is irrelevant. You can
define it as a character field of any length that you want.

--
Ken
Opinions expressed are my own and do not necessarily represent the views
of my employer or anyone in their right mind.
0 new messages