Getting to Grips with Pointers and User Spaces in RPG IV

advertisement
ComCon
Coming to Grips with
Pointers and User
Spaces in RPG IV
ComCon
5, Oakton Court
Ballybrack
Co. Dublin
Ireland
Phone: +353 1 282 6230
e-Mail: tuohyp@comconadvisor.com
Web: www.ComConAdvisor.com
Paul Tuohy
ComCon
Agenda
What are pointers?
How to use pointers.
Why use pointers?
Allocating record layouts in trigger programs
Used with C functions
Dynamic memory allocation
User spaces
Procedure pointers
ComCon
What is a pointer?
Basing pointers are used to locate the
storage for based variables. The storage is
accessed by defining a field, array, or data
structure as based on a particular basing
pointer variable and setting the basing
pointer variable to point to the required
storage location.
From: WebSphere(R) Development Studio ILE RPG Reference - Basing
Pointer Data Type
ComCon
What is a pointer?
A pointer is a field that contains a memory address.
Assuming that Name is a 30-character field, translate the eval operation
as "from the address of Name, blank out the next thirty characters".
If we could control "the address of Name", we would have a pointer!
Program Storage
Eval
Name = *Blanks
ComCon
Pointers have always been used in . . .
Pointers are not new to RPG -- we just have not been able to
manipulate them.
Multiple Occurrence Data Structures
The occurrence of the database is based on an offset of the address of
the data structure.
– DS = Address of MODS + (Length of DS * (Occurrence – 1))
Parameter Lists
When passing a parameter the actual parameter field is not passed, but a
pointer containing the address of the parameter field. This address is then
used as the basis for the parameter field in the called program.
Lets take a closer look at parameters!
ComCon
Parameter lists
I
J
K
Storage of Calling
Program
Storage of Called Program
X
D
D
D
D
Y
Z
BProgram(I: J: K);
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
BProgram
PI
X
15
Y
10
Z
5
ComCon
The problem with pointers
I
J
K
Storage of Calling
Program
Storage of Called Program
X
D
D
D
D
Y
Z
BProgram(I: J: K);
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
BProgram
PI
X
15
Y
10
Z
15
Oops!
Z = *Blanks;
ComCon
The problem with pointers
I
J
K
Storage of Calling
Program
Storage of Called Program
X
D
D
D
D
Y
Z
BProgram(I: J: K);
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
BProgram
PI
X
15
Y
10
Z
15
Oops!
Z = *Blanks;
ComCon
Better get used to . . .
Message ID . . . . . . : RNQ0222
Date sent . . . . . . : 13/09/02
Time sent . . . . . . : 11:40:31
Message . . . . : Pointer or parameter error (C G D F).
Cause . . . . . : RPG procedure BASICF in program SPACE01/BASICF at
statement 51 had an error due to a pointer not being correctly set. The
cause of the error is most likely one of the following:
* A basing pointer was not set.
* A procedure pointer was not set.
* The pointer was set, but the object it referenced has been destroyed.
* A parameter was not passed to the program containing the procedure.
* A parameter was not passed to the procedure by its caller within the program.
* A pointer offset was greater than the size of the space the pointer was pointing to.
ComCon
Remember
When you are using pointers . . .
You are indiscriminately playing with memory.
You must be careful.
ComCon
Pointers in RPG IV
We can now define pointer data types.
Also, we can define fields, arrays and data structures whose
"positioning" in memory is based on the value of a pointer.
In other words, when a field is based on a pointer, memory is not
allocated for the field when the program loads but is allocated dynamically
based on the value of the pointer field.
If a pointer is used but not defined, the compiler will
automatically define it – so watch out for spelling!
DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords++++++++++++++++++++
D pPointer
S
*
D BasedField
S
20
Based(pPointer)
ComCon
Pointers at work
1.
Storage of Program
pPointer = *Null
1
BasedField
ComCon
Pointers at work
5
1.
2.
3.
4.
5.
pPointer
pPointer
pPointer
pPointer
pPointer
=
=
=
=
=
*Null
An Address
Another Address
Yet Another Address
%Addr(BlueField)
4
Storage of Program
3
2
1
BasedField
ComCon
Using pointers
Pointers have a data type of '*' and you don't define a length.
Actually uses 16 bytes of storage.
Fields are "subject" to a pointer using the Based Keyword.
The value of a pointer is set using the %Addr Built-in Function.
DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords++++++++++++++++++++
D pPointer
S
*
Inz(%Addr(Text1))
D BasedField
S
* "Overlays" Text1
D MyDS
D Text1
D Text2
C
5
Based(pPointer)
4
4
Inz('ABCD')
Inz('WXYZ')
DS
Eval
pPointer = %Addr(Text2)
* Now, BasedField "Overlays" Text2
ComCon
Why use pointers?
* When allocating record layouts in trigger programs.
* Used with C functions.
* Dynamic memory allocation.
* Used with many APIs - e.g., user spaces
* As a way of calling procedures.
ComCon
Standard trigger buffer
D TriggerBuffer
DS
D FileName
D LibraryName
D MemberName
D Event
D Time
D CommitLock
D Fill01
D CCSID
D RRN
D Fill02
D OldOffset
D OldLength
D OldNullOff
D OldNullLen
D NewOffset
D NewLength
D NewNullOff
D NewNullLen
* Before and After Images
Qualified
10
10
10
1
1
1
3
10I
10I
4
10I
10I
10I
10I
10I
10I
10I
10I
0
0
0
0
0
0
0
0
0
0
Offset to Original
Record
Offset to New
Record
ComCon
Accessing the Trigger Buffer
The %SUBST Built-in Function can be used to copy the
contents of the Trigger Buffer to the relevent externally
described data structures.
D OldFile
D
D NewFile
E DS
E DS
ExtName(FileName)
Qualified
ExtName(FileName)
OldFile = %SubST(TriggerBuffer:
TriggerBuffer.OldOffset+1:
TriggerBuffer.OldLength);
NewFile = %SubST(TriggerBuffer:
TriggerBuffer.NewOffset+1:
TriggerBuffer.NewLength)
ComCon
Using pointers
The two externally described data structures can be mapped
onto the relevent portions of the Trigger Buffer by basing them
on pointers and setting the values of the pointers to be the
address of the buffer + the relevent offset.
No data is copied!!!
D OldFile
D
D
D NewFile
D
E DS
D OldPtr
D NewPtr
S
S
ExtName(FileName)
Qualified
Based(OldPtr)
ExtName(FileName)
Based(NewPtr)
E DS
*
*
OldPtr = %Addr(TriggerBuffer) + TriggerBuffer.OldOffset
NewPtr = %Addr(TriggerBuffer) + TriggerBuffer.NewOffset
ComCon
C functions
Many C functions require pointers as parameters and return a
pointer.
 Example: The strtok (string tokenize) function.
 This function breaks up a string into "tokens“
 Refer to the Redbook "Who Knew You Could Do That With RPG IV?" for
detailed details.
C functions are not easy to interpret.
• Function names are case sensitive.
• Refer to Barbara Morris’ "Converting from C prototypes to RPG
prototypes"
http://www.opensource400.org/callc.html.
D GetToken
D pString
D pDelimiters
Pr
*
*
*
ExtProc('strtok')
Value Options(*String)
Value Options(*String)
ComCon
Other C functions
qsort and bsearch can be used as more powerful versions of
SORTA and LOOKUP.
 Refer to the Redbook "Who Knew You Could Do That With RPG IV?" for
details and examples.
D SortIt
D DataStart
D Elements
D Size
D CompFunc
PR
ExtProc('qsort')
*
Value
10U 0 Value
10U 0 Value
*
ProcPtr Value
D FindIt
D LookFor
D DataStart
D Elements
D Size
D CompFunc
PR
*
ExtProc('bsearch')
*
Value
*
Value
10U 0 Value
10U 0 Value
*
ProcPtr Value
ComCon
Dynamic Memory Allocation
Dynamic Memory Allocation is useful if you are unsure how
much space will be required by a variable at run time.
%Alloc
- allocates the required amount of storage.
%ReAlloc
- reallocates the current storage to a new size
DeAlloc
- frees the allocated storage
–N.B. Allocated storage should be freed.
D Array
S
10
Based(pArray) Dim(10000)
D pArray
S
*
D MaxElem
S
10U 0 Inz(10)
/Free
pArray = %Alloc(%Size(Array) * MaxElem);
MaxElem = MaxElem + 10;
pArray = %ReAlloc(pArray: %Size(Array) * MaxElem);
DeAlloc pArray;
*InLR = *On;
/End-Free
ComCon
Example of Dynamic Memory Allocation
This example shows the use of dynamic memory allocation for
an array that may have more then 32767 elements.
The array is “repositioned” every 32767 elements.
D PathArray
S
*
Dim(32767)
D
Based(pPathArray)
// Allocate memory for the array of pointers
pPathArray = %alloc((%size(pDataPtr) * NumberInList));
// Build the array of pointers to the path entries
for i = 1 to NumberInList;
j = j + 1;
If (j > %Elem(PathArray));
pPathArray = pPathArray +
(%Size(pDataPtr) * %Elem(PathArray));
j = 1;
EndIf;
PathArray(j) = pDataPtr;
ComCon
Example of Dynamic Memory Allocation
1. NumberInList = 70,000
%Size(PDataPtr) = 16
PathArray
2. pPathArray= %alloc((%size(pDataPtr)*NumberInList));
%Alloc assigns 1,120,000 bytes
< 1 ----------------------------------------------------- 1,120,000 >
2. PathArray
4. PathArray
5. PathArray
< 1 ---------------- 524,272 >
< 524,273------------ 1,048,544 >< 1,048,545 --------- 1,572,816 >
pPathArray = address of allocated memory
3. Program loops through 32767 elements of PathArray
4. “Move” the position of the array
pPathArray = pPathArray +
(%Size(pDataPtr) * %Elem(PathArray));
5. etc.
ComCon
What is a user space?
Contrary to popular belief, a user space is not what you find
between a user's ears.
It is
An object on the iSeries (I5, AS/400) with an object type of *USRSPC.
It is simply a stream of bytes that you can access directly from within a
program.
A user space effectively becomes a field in your program.
More precisely (even though it might sound extremely vague), a user
space is whatever you want it to be.
The advantages to employing a user space lie in speed of
access and the fact that data can be shared between programs
without having to perform I/O!!!!
ComCon
User space APIs
You must use APIs to create user spaces and manipulate their
contents.
In fact, the only user space command you will find is the Delete User
Space (DLTUSRSPC) command.
Incorporating a user space into an application involves two
user space APIs:
Create User Space (QUSCRTUS).
Retrieve Pointer to User Space (QUSPTRUS).
ComCon
Create user space
The QUSCRTUS API is called to create a user space
D CreateSpace
D UserSpaceName
D Attribute
D Size
D Initial
D Authority
D Text
*
D
D
D
*
D
*
D
D
PR
Optional Parameter Group 1
Replace
ErrorCode
Optional Parameter Group 2
Domain
Optional Parameter Group 3
TransferSize
OptimumAlign
ExtPgm('QUSCRTUS')
20
Const
10
Const
10I 0 Const
1
Const
10
Const
50
Const
10
Const Options(*NOPASS)
Const Options(*NOPASS)
Like(StandardAPIError)
10
Const Options(*NOPASS)
10I 0 Const Options(*NOPASS)
1
Const Options(*NOPASS)
CreateSpace(UserSpace:'DTA':10000: X'00':'*ALL':Text);
ComCon
Create user space
The parameters used on the QUSCRTUS API are:
UserSpace: The name and library of the user space.
Attribute:
The attribute parameter is any name you wish it to be.
Size:
The initial length of the user space in bytes.
Initial:
The initial value used to fill the user space.
Authority:
Public authority to the user space.
Text:
The text description.
DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords++++++++++++++++++++
D UserSpace
S
20
Inz('USERSPACE *CURLIB')
D Attribute
S
10
Inz('DTA')
D Size
S
10I 0 Inz(10000)
D Initial
S
1
Inz(X'00')
D Authority
S
10
Inz('*ALL')
D Text
S
50
Inz('Sample User Space')
ComCon
Fill user space
We map a variable in the program onto the user space.
 If we change the variable, we are also changing the user space.
 We map the CATSPACE array onto the CATEGORY user space.
 Each element of CATSPACE will contain a record from the Category file.
D CatData
E DS
D NumRows
D pNumRows
S
S
D CatSpace
D
D pCatSpace
S
S
ExtName(Category)
5I 0 Based(pNumRows)
*
Dim(32767) Based(pCatSpace)
Like(CatData)
*
ComCon
Fill user space
The call to QUSPTRUS API returns a value in the pNumRows
field.
 This value reflects the address of the requested user space.
 NumRows now overlays the first two bytes of the user space.
 pCatSpace is equal to the value of pNumRows + 2.
 The array CatSpace overlays the user space starting at position 3.
D GetSpace
PR
D SpaceName
D pSpacePtr
* Optional Parameter Group
D ErrorCode
D
D
UserSpace
S
ExtPgm('QUSPTRUS')
Const
20
*
Const Options(*NOPASS)
Like(StandardAPIError)
20
Inz('CATEGORY
GetSpace(SpaceName:pNumRows);
pCatSpace = pNumRows + %Size(NumRows);
*LIBL
')
ComCon
Fill user space
We have a loop that fills the user space by reading a record
from the category file and adding it to the next element of the
array.
NumRows = 0;
Read Category;
DoW Not %EOF(Category);
NumRows = NumRows + 1;
CatSpace(NumRows) = CatData;
Read Category;
EndDo;
ComCon
Using the user space
This example shows a subfile being loaded from a user space
instead of a file.
 The program DOES NOT contain a F spec for the file.
 Again, we define the array based on a pointer.
D CatData
E DS
D NumRows
D pNumRows
S
S
D CatSpace
D
D pCatSpace
S
S
ExtName(Category)
5I 0 Based(pNumRows)
*
Dim(32767) Based(pCatSpace)
Like(CatData)
*
ComCon
Using the user space
The call to the QUSPTRUS API maps the array to the user
space.
The call to QUSPTRUS is usually issued in the *INZSR subroutine, since
it needs to be done only when the program is first loaded.
// Obtain pointers to the user space
GetSpace(SpaceName:pNumRows);
pCatSpace = pNumRows + %Size(NumRows);
ComCon
Using the user space
The subfile is now loaded from the array as opposed to the
category file.
 The relative record number (RRN) for the subfile doubles as the element
pointer for the array.
 Each iteration of the For loop places the next element of the array in the
next subfile record.
- The same field names are used in the subfile record format and the
CatData data structure.
For RRN = 1 To NumRows;
CatData = CatSpace(RRN);
Write SubRec;
EndFor;
ComCon
APIs and user spaces
User spaces are used with many of the system-supplied APIs,
especially any of the "list style" APIs.
Data is "output" to a user space and your program pages through the user
space.
This is an example of using the List Objects API
D ListObjects
D UserSpace
D Format
D Objects
D ObjectType
D ErrorCode
PR
20
8
20
10
ExtPgm('QUSLOBJ')
Const
Const
Const
Const
Like(StandardAPIError)
CreateSpace('MYSPACE
QTEMP
':'DTA':10000: X'00':'*ALL':
'All Objects in MYLIB');
ListObjects('MYSPACE
'*ALL
QTEMP
MYLIB
':'OBJL0100':
':'*ALL
':APIError);
ComCon
API documentation
The user space APIs are documented in the Information
Center under Programming->APIs->APIs by Category->Object
APIs.
The use of user spaces for other APIs is detailed in the
documentation of the individual APIs (like QUSLOBJ)
ComCon
Categories of APIs
Each has its own section, so pick a topic and while away a
weekend in perusal.
Backup and Recovery APIs
Client Management Support APIs
Communications APIs
Configuration APIs
Debugger APIs
Dynamic Screen Manager APIs
Edit Function APIs
File APIs
Hardware Resource APIs
Hierarchical File System APIs
High-Level Language APIs
ILE CEE APIs
Journal and Commit APIs
Message Handling APIs
National Language Support APIs
Network Management APIs
Object APIs
Office APIs
Operational Assistant APIs
Performance Collector APIs
Print APIs
Problem Management APIs
Program and CL Command APIs
Registration Facility APIs
Remote Procedure Call APIs
Security APIs
Server Support APIs
Software Product APIs
UNIX-Type APIs
User Interface APIs
Virtual Terminal APIs
Work Management APIs
Work Station Support APIs
Miscellaneous APIs
ComCon
Procedure pointers
Procedure pointers point to the address of a procedure
Identified by the ProcPtr Keyword
The ExtProc keyword has the name of the pointer
Value set using the %PAddr BIF.
–Watch those quotes!
–Watch case!
–Parameters should be the same for all procedures. No check; it is up to you.
D pGenProc
D GenProc
pGenProc
Returned
pGenProc
Returned
S
PR
=
=
=
=
*
30
ProcPtr
ExtProc(pGenProc)
%PAddr('Proc01');
GenProc();
%PAddr('AnotherProcAltogether');
GenProc();
ComCon
Any clearer now?
Basing pointers are used to locate the
storage for based variables. The storage is
accessed by defining a field, array, or data
structure as based on a particular basing
pointer variable and setting the basing
pointer variable to point to the required
storage location.
From: WebSphere(R) Development Studio ILE RPG Reference - Basing
Pointer Data Type
ComCon
Check out the RPG IV Redbook
Available now - SG24-5402
 Go to www.redbooks.ibm.com
–You can read it online, download
the PDF file, or order a hardcopy
Includes worked examples of
– TCP/IP sockets
– CGI programming
– Using the C function library
– ILE error handling
– and much more
Who Knew You Could Do That with
RPG IV?
A Sorcerer's Guide to System Access and More
SG245402
International Technical Support Organization
Rochester, Minnesota
ComCon
Or check out
Available at
www.mcpressonline.com
www.midrange.com
www.amazon.com
ISBN 1-58347-006-9
ComCon
Summary
Pointers open new possibilities.
Pointers can be dangerous.
Treat them with respect.
They are a neccessity for many C functions.
They are a neccessity for many APIs.
User spaces are great!
Download