Using Pointers
Using pointers can be an efficient method of sharing data between programs.
Pointing at a Data Structure
The program in this example has an argument list with three values expected as input and three values destined to become output. The first three values are required to find the required information. The rows are selected by the SQL statements and fetched into the data structure. The data structure is not a part of the argument list. The outbound parameters are an indication data was found, a pointer to where the information is located, and how many occurrences of data were counted.
ctl-Opt DEBUG(*YES) OPTION(*SRCSTMT : *NODEBUGIO) DFTACTGRP(*NO) ACTGRP(*CALLER) Main(PAEXDR) EXTBININT(*YES) ; ******************************************************************** * * * Program Name : PAEXDR * * * * Program Description : Returns Free format text entries * * * * Date : 99/99/99 * * * * Author : Steve Croy * * * ******************************************************************** * * * Modification Log * * * * Project Marker Date Description * * * ******************************************************************** Dcl-DS textRecords extName('PAUWLRCD') Occurs(100); END-DS; Dcl-C SQLstsOK '00000' ; Dcl-C SQLstsEOF '02000' ; Dcl-S textMessageFound ind ; Dcl-S companyNumber char(2) ; Dcl-S groupCOde char(2) ; Dcl-S policyNumber char(9) ; Dcl-S rows int(10) ; Dcl-S sentDate packed(8:0) ; Dcl-Proc PAEXDR ; Dcl-PI *N extPgm('PAEXDR') ; cmpIN char(2) CONST ; grpIN char(2) CONST ; polIN char(9) CONST ; textFound ind ; textPointer pointer ; rowCount int(5) ; END-PI; Exec SQL set option Commit = *None, Naming = *Sys, DECRESULT = (63, 63, 0), datfmt = *ISO ; Clear *all TextRecords ; textMessageFound = *off ; companyNumber = cmpIn ; groupCode = grpIn ; policyNumber = polIn ; rowCount = 0 ; sentDate = 0 ; Exec SQL Close PAEXDR01 ; Exec SQL Select '1', uwsdat into :textMessageFound, :sentDate from PAUWLR Where UWCO# = :companyNumber And UWGRP = :groupCode And UWPOL# = :policyNumber And UWFLAG = ' ' ; If textMessageFound ; // an excluded driver was found Exec SQL Select count(*) into :rows From PAUWLRCD Where UWCO# = :CompanyNumber And UWGRP = :groupCode And UWPOL# = :policyNumber And UWSDAT = :sentDate ; Exec SQL Declare PAEXDR01 insensitive cursor for ( Select * From PAUWLRCD Where UWCO# = :CompanyNumber And UWGRP = :groupCode And UWPOL# = :policyNumber And UWSDAT = :sentDate ) ; Exec SQL Open PAEXDR01 ; Exec SQL fetch PAEXDR01 for :rows rows into :textRecords ; ENDIF; Exec SQL Close PAEXDR01 ; textFound = TextMessageFound ; textPointer = %addr(TextRecords) ; rowCount = rows ; Return ; End-Proc PAEXDR ;
%ADDR returns a value of type basing pointer. The value is the address of the specified variable. It may only be compared with and assigned to items of type basing pointer. The location of the loaded data structure (TEXTRECORDS) is passed back to the calling program with the address to the parameter. Once returned, the address is used by the calling program to manage the DS entries from a data structure BASED on the value of the pointer.
Pointing to an Array
Another handy use of pointers is to attach some meaning to indicators. Typically, subfile applications require numerous indicators within an RPG application to manage the display. Here the standard indicator array has reference with a pointer.
. . . d indPtr s * inz( %addr(*in) ) * define named indicators d indicators ds 99 based( indPtr ) d ScreenChange n overlay( indicators : 22 ) d SflControl n overlay( indicators : 50 ) d SflDisplay n overlay( indicators : 51 ) d SflInitialize n overlay( indicators : 52 ) d SflClear n overlay( indicators : 53 ) d SflEnd n overlay( indicators : 54 ) d SflDelete n overlay( indicators : 55 ) d SflNxtChange n overlay( indicators : 58 ) d SflMSGQdisplay... d n overlay( indicators : 59 ) . . . Fig. 3
Once the array has been reference a data structure based on the array has been created to correspond to the indicators used in the DDS to signal subfile actions. This use of a pointer allows more meaningful references within the program code.
. . . SflInitialize = *ON; WRITE SC0320C1; SflInitialize = *OFF; SflEnd = *OFF; . . . sflControl = *ON; IF sflrcn > 0; sflDisplay = *ON; ENDIF; WRITE SC032001; EXFMT SC0320C1; sflControl = *OFF; sflDisplay = *OFF; . . . Fig. 4
Interpreting the code becomes easier when a developer does not have to refer to the display file to determine whether indicator *IN52 or *IN53 was used to initialize or clear the subfile, or what *IN50 was supposed to indicate.
Deugging a Pointer
Here's a useful tip, how to see the value of a variable a pointer references. Even when the variable is not based on the pointer, you can see the data a pointer is pointing to. When in debug mode in an RPG or COBOL program, you may display a pointer variable using :c or :x, following the variable name. The debugger will display the data that the pointer is pointing to rather than displaying the 16 bytes of the pointer variable itself.
D p S * D packedVal S 5P 0 INZ(12345) D charVal S 5A INZ('abcde') p = %addr(charVal); p = %addr(packedVal); return; In the debugger, after the first assignment to p: > EVAL p P = SPP:DE60CDB47B069738 > EVAL p:c 5 P:C 5 = 'abcde' > EVAL p:x 5 00000 81828384 85...... After the second assignment to p: > EVAL p P = SPP:DE60CDB47B06973D > EVAL p:c 3 P:C 3 = ' ¬' > EVAL p:x 3 00000 12345F..
The example above first appeared in MCPress Online, credited to Barabara Morris of IBM.