mgo
OS/400 Edition
Volume 2, Number 88 -- November 15, 2002

Data Structure Parameters in RPG Prototypes


Hey, Ted:

Back in my RPG III (RPG/400) days, it was easy to define an entry parameter as a data structure.

IPARM1      DS 
I                                       1   8 ACTION 
I                                       9  10 CODE   
I                                      11  120RTNVAL 
I* 
C          *ENTRY    PLIST
C                    PARM           PARM1

I used this same method in RPG IV before I started prototyping entry parameters.

D Parm1          DS 
D  Action                1      8  
D  Code                  9     10  
D  RtnVal               11     12  0 
I*  
C     *entry       plist                        
C                  parm                    Parm1

Now I prototype entry parameters, as you described in the November 16, 2001 issue of Midrange Guru. Since the D-spec for a parameter must be blank in positions 24-25, and a data structure must have DS in positions 24-25, how can I include a data structure in a prototyped parameter list?

-- Lee

You can do it, Lee. It just takes a little more work. With the help of Barbara Morris of IBM, I have come up with two methods.

The first method is the only one I know of that will work on releases prior to V5R1. Besides declaring the prototype and procedure interface, you must define a data structure and a pointer to the data structure, as in the following code for called program DSPARM.

D DSParm�������� pr����������������� extpgm('DSPARM')
D� Parm1���������������������������� like(ParmData)
D
D DSParm�������� pi
D� Parm1���������������������������� like(ParmData)
D
D ParmAddr������ s�������������� *
D ParmData������ ds����������������� based(ParmAddr)
D�� Action��������������������� 8
D�� Code����������������������� 2
D�� RtnVal��������������������� 2s 0
D
C����������������� eval����� ParmAddr = %addr(Parm1)
C     action       dsply                 
C     code         dsply                 
C     rtnval       dsply                 
C                  eval      rtnval = 21 

You must set the pointer to the address of the parameter so that manipulating the data structure manipulates the parameter. After the eval runs, anything you do to Action, Code, and RtnVal will take place within Parm1.

The second method is for V5R1 or later. Use the LIKEDS keyword to define subfields for the parameter. You will have to qualify references to the parameter's subfields by preceding each subfield name with the parameter name and a period. You no longer need the pointer.

D ParmData       ds 
D   Action                      8
D   Code                        2 
D   RtnVal                      2s 0
        D                                                       
D DSParm         pr                  extpgm('DSPARM')
D  Parm1                             likeds(ParmData)   
D  
D DSParm         pi 
D  Parm1                             likeds(ParmData)   
D 
C    Parm1.action  dsply 
C    Parm1.code    dsply 
C    Parm1.rtnval  dsply
C                   eval     Parm1.rtnval = 21          

Data structure ParmData and its three subfields are not equivalent to the parameter. To access the parameter's data, you must use the qualified subfields.

If you like to place the prototype in a member of its own, as I do, include the data structure in the prototype so that calling programs also have access to the data structure's definition. Here's the copy member that contains the prototype.

D ParmData       ds  
D   Action                      8 
D   Code                        2 
D   RtnVal                      2s 0
D   
D DSParm         pr                  extpgm('DSPARM')
D  Parm1                             likeds(ParmData) 
D 

Here's the called program. It receives the data structure as Parm1 and qualifies the subfields.

D/include prototypes,dsparm
D                                                        
D DSParm         pi 
D  Parm1                             likeds(ParmData)   
D 
C    Parm1.action  dsply 
C    Parm1.code    dsply 
C    Parm1.rtnval  dsply 
C                  eval      Parm1.rtnval = 21

Here's part of a calling program. MyDS is the data structure that is to be passed to the called program. Notice that all references to the subfields are qualified.

D/include prototypes,dsparm 
D 
D MyDS           ds                  likeds(ParmData)
D 
C                  eval      MyDS.Action = 'READNEXT'
C                  eval      MyDS.Code = '33'
C                  eval      MyDS.RtnVal = *zero
C                  callp     DSPARM (MyDS)
C                  if        MyDS.rtnval = *zero

Data structure ParmData is defined in both the calling and called programs, but is used only as a pattern. The real data is in MyDS in the caller and in Parm1 in the called program.

In this example, the data structure that is being passed from one program to another is only twelve bytes long. However, if it were much longer, you might want to keep the compiler from allocating storage for the pattern data structure in the copy member. To prevent the allocation of storage, use the BASED keyword.

                                 
D ParmData       ds                  based(typedefinition_dummy)             
D   Action                      8  
D   Code                        2
D   RtnVal                      2s 0 
D   
D DSParm         pr                  extpgm('DSPARM')
D  Parm1                             likeds(ParmData)
D 

Data structure ParmData is still defined in both the caller and called programs, but no storage is allocated for ParmData in either.

The use of the BASED keyword also prevents programmers from using the pattern data structure as a working variable. Instead, programmers must define data structures that are to serve as working variables by using the LIKEDS keyword.

Everything to this point works fine if there are no identifiers in the calling program that have the same names as those of the data structure subfields. To avoid such collisions, add the QUALIFIED keyword to the data structure definition in the prototype member.

D ParmData       ds                  based(typedefinition_dummy)
D                                    qualified 
D   Action                      8  
D   Code                        2  
D   RtnVal                      2s 0 
D  
D DSParm         pr                  extpgm('DSPARMQ') 
D  Parm1                             likeds(ParmData)
D                                                                

Here's a calling program that declares a variable named ACTION. Because of the QUALIFIED keyword, this program has no trouble distinguishing between ACTION the standalone variable and ACTION the subfield.

D/include prototypes,dsparm 
D                                                        
D MyDS           ds                  likeds(ParmData)
D Action         s             24 
D 
C                  eval      Action = 'Go getum!'
C                  eval      MyDS.Action = 'READNEXT'
C                  eval      MyDS.Code = '33' 
C                  eval      MyDS.RtnVal = *zero
C                  callp     DSPARM (MyDS)
C                  if        MyDS.rtnval <> *zero 

Here's a final example that Barbara gave me. This example uses two data structures as parameters.

Here's the prototype copybook member. The two pattern data structures have names that end with an underscore (_) and a lowercase letter t to remind programmers that these data structures serve as data types, not as real variables with allocated storage.

D custInfo_t�� ds�������������� qualified based(typedummy)
D� name����������������� 100a�� varying
D� id_no����������������� 10i 0
D� addr����������������� 100a�� varying

D partInfo_t�� ds�������������� qualified based(typedummy)
D� name����������������� 100a�� varying
D� id_no����������������� 10i 0
D� cost������������������ 15p 3

D buyOne������ pr
D� cust������������������������ likeds(custInfo_t) const
D� part������������������������ likeds(partInfo_t) const
D� num������������������� 10i 0 value

A caller of the procedure would use the data structure names as pseudo data types. All references to the subfields would be qualified.

�/copy prototypes,custtrans
D theCust����� ds�������������� likeds(custInfo_t)
D thePart����� ds�������������� likeds(partInfo_t)

 /free
������theCust.name = whatever;
������buyOne (theCust : thePart : num);
 /end-free

Prototyping data structure parameters is more complex than the old RPG III method you used. However, I believe that the advantages of prototyping parameters are worth the extra effort.

-- Ted


Sponsored By
COMMON

Get the IT training you need by attending COMMON Users Group's Spring 2003 IT Education Conference and Expo, March 9 - 13, in Indianapolis.

Choose from hundreds of sessions and labs covering the widest range of industry topics, including RPG IV, LPAR, WebSphere, and High Availability.

COMMON is the best value in IT education, so don't miss out!

Click and visit www.common.org for details!


THIS ISSUE
SPONSORED BY:

ASC
COMMON


BACK ISSUES

TABLE OF
CONTENTS

Access the Database from Qshell

Data Structure Parameters in RPG Prototypes

Reader Feedback and Insights: Indicators in RPG II Programs



Editors
Howard Arner
Joe Hertvik
Ted Holt
David Morris

Managing Editor
Mari Barrett

Publisher and
Advertising Director

Jenny Thomas

Advertising Sales Representative
Kim Reed

Contact the Editors
Do you have a gripe, inside dope or an opinion?
Email the editors:
[email protected]



Last Updated: 11/15/02
Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.