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.