Test268 Section 4

From MidrangeWiki
Revision as of 14:39, 2 January 2007 by Kjburkhalter (talk | contribs) (Use externally-described data structures)
Jump to: navigation, search

<< Previous Section | Home | Next Section >>

Section 4 - Advanced RPG techniques (25%)

Given an example of a complex logical expression, determine its results

Given an example of deeply-nested logic within a sample of RPG code, determine the results of running the code

Use Data Structure arrays

If MyDS is a data structure array of 10 elements, then MyDS(5) will access the fifth element of that data structure array. But how do you access the subfields? That requires a bit more discussion.

When you define a data structure array, you not only use the Dim keyword, but you must also specify the Qualified keyword. The Qualified keyword was introduced in V5R1, and it allows you to specify the name of a data structure subfield qualified by the name of the data structure. For example, if data structure MyDS is defined with the Qualified keyword and it contains a subfield named Subfield1, then you would use the following notation to access the subfield:

MyDS.Subfield1

If data structure MyDS is also defined with the Dim keyword, then something like the following notation is used to access subfields in a specific element:

MyDS(5).Subfield1

In this example, you would be accessing the subfield named Subfield1 in the fifth element in the data structure array MyDS.

Code complex D-specs (e.g., OVERLAY, coding fields without attributes, etc.)

D DataStruct1     DS                  QUALIFIED
D  Field1                       15A   INZ('12345ABCDE12345')
D   Field2                       5A   OVERLAY(Field1)
D   Field3                       5A   OVERLAY(Field1:*NEXT)
D   Field4                       5A   OVERLAY(Field1:*NEXT)
D   Field5                       7A   OVERLAY(Field3:3)

D DataStruct2     DS                  LIKEDS(DataStruct1) INZ(*LIKEDS)
D  Name           S             20
D  Long_name      S             +5    LIKE(Name)
D  Lda_fld        S                   LIKE(Name) DTAARA(*LDA)

Use modern techniques to handle numbered indicators

Named Indicators Indicators are now a recognized data type in RPG, so we can define them in the D Specs, as shown below. Note that when testing an indicator you do not need to compare it against *ON or *OFF.

  DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++
  D BadStatus       S               N     
  D MonthEnd        S               N


The below code shows a named indicator being used for printer overflow. This is a simple example of the benefit of a named indicator; the name Overflow is more self-explanatory than *IN96 or *INOV. Also, you don't need to define the Overflow indicator in the D Specs; the compiler will define it for you.

  FReport    O    E             Printer OflInd(OverFlow)  
                                                                                                  
      Write Detail;
      If OverFlow;
          Write Header;
          OverFlow = *Off;
      EndIf;


Logical Expressions The below code shows the traditional means of setting an indicator; it should look familiar. It is setting an error condition if it is a month end and if the status is neither 'I' nor 'C'. At least I think it is setting an error condition; that is what indicator 31 is -- right?

   *In31 = *Off;
   If EndMonth = 'Y';           
       If Status <> 'I' and Status <> 'C';
           *In31 = *On;
       EndIf;        
   EndIf;   


And below you'll the same piece of code as a logical expression. The result of a logical expression is true or false, therefore it can be assigned directly to an indicator. Also, the EndMonth field has been replaced by the indicator MonthEnd, and *IN31 has been replaced by the indicator BadStatus.

   If MonthEnd;
       BadStatus = (Status <> 'I' and Status <> 'C');
   EndIf;  


Built In-Functions We no longer need to use resulting indicators on operation codes. Instead, we can use the relevant I/O BIF. The I/O BIFs are %OPEN, %FOUND, %EOF, %ERROR, %EQUAL and %STATUS. The code below shows an example of using the %OPEN, %ERROR and %FOUND BIFs. The %OPEN BIF indicates whether or not the file is open. The %ERROR BIF is set when the E extender is defined on an operation code (Chain in this case). We use the E extender in place of an error indicator in the low position. The %FOUND BIF is set automatically by the Chain operation.

    If  %Open(FileB);
       Chain(E) Key FileB;
       Select;
         When %Error;
           Dsply 'File Error'; 
         When %Found(FileB);
           Dsply 'Got It';  
       EndIf; 
    EndIf;

One of the nice things about %FOUND is that it reads the right way round, as opposed to the indicator on the CHAIN operation where the indicator is true if the record is NOT found.

Indicator Data Structure By default, the indicators 01 to 99 on a display or print file are mapped to the indicators 01 to 99 in an RPG program. But when we use the file keyword INDDS (Indicator Data Structure), they are mapped to a data structure instead of the indicators. In other words, the 99 indicators used with the display or print file are now associated with the data structure instead of the indicators *IN01 to *IN99 in the program.

The code below shows an example of using the INDDS. The indicators for the display file are mapped to the data structure DspInd. DspInd is a 99 byte data structure, with each byte corresponding to one of the 99 indicators for the display file. This means that for the display file, we MUST use the indicators in the data structure and NOT the numbered indicators. For example, in this program, if we turned on indicator *IN31, it would have no impact on the display file. The program logic must refer to the indicator Error in order to have an impact on the display file. Named indicators are a lot easier to decipher!

FDisplay   CF   E             WORKSTN INDDS(DspInd) 
    
D DspInd         DS                                        
 * Response indicators              
D   F3Exit               3      3N                         
D   F12Cancel           12     12N                         
 * Conditioning indicators  
D  AllErrors            31     33    
D   Error               31     31N                         
D   StDateErr           32     32N                         
D   EndDateErr          33     33N                         
                                  
       Eval      AllErrors = *Zeros;  
                   
       StDateErr = StartDate < Today;
       EndDateErr = EndDate < StartDate;
       Error = StDateErr or EndDateErr;
       ExFmt     MyScreen;  
                         
       If  F3Exit or F12Cancel; 


The use of INDDS requires the use of the file level keyword INDARA in the DDS for the display/print file. In most cases, changing a file to use INDARA will have no effect unless a RESET or CLEAR operation is used. In this case it will now be necessary to also RESET/CLEAR the associated indicators.

Determine appropriate use of system APIs

Code subprocedures

  • Internal Program Sub-Procedure
D Inter_Func      PR            10I 0              
D  Term1                         5I 0 VALUE
D  Term2                         5I 0 VALUE
D  Term3                         5I 0 VALUE
  • External Module Sub-Procedure
D Extrn_Func      PR            10I 0 EXTPROC('MODULE_FUCT')             
D  Term1                         5I 0 VALUE
D  Term2                         5I 0 VALUE
D  Term3                         5I 0 VALUE
  • External Program Sub-Procedure
D Pgm_Func        PR            10I 0 EXTPGM('PGM_FUCT')             
D  Term1                         5I 0 VALUE
D  Term2                         5I 0 VALUE
D  Term3                         5I 0 VALUE

Declare and use subprocedures

Declare the Function and call it

D Function        PR            10I 0              
D  Term1                         5I 0 VALUE
D  Term2                         5I 0 VALUE
D  Term3                         5I 0 VALUE
D  RC             S             10I 0 INZ(*ZEROS)
 /free
   RC = Function(Term1:Term2:Term3);
   *INLR = *ON;
   RETURN;
 /end-free

start the function and return the results

P Function        B                             
D Function        PI            10I 0              
D  Term1                         5I 0 VALUE
D  Term2                         5I 0 VALUE
D  Term3                         5I 0 VALUE
D Result          S             10I 0                 
 /free
   Result = Term1 ** 2 * 17 + Term2 * 7 + Term3;
   return Result;
 /end-free
P Function        E

Create and use multiple occurrence data structures

 DS1 and DS2 are multiple occurrence data structures.
 Each data structure has 50 occurrences.
 D DS1             DS                  OCCURS(50)
 D  FLDA                   1      5
 D  FLDB                   6     80
  *
 D DS2             DS                  OCCURS(50)
 D  FLDC                   1      6
 D  FLDD                   7     11

DS1 is set to the third occurrence. The subfields FLDA and FLDB of the third occurrence can now be used. The MOVE and Z-ADD operations change the contents of FLDA and FLDB, respectively, in the third occurrence of DS1.

 C
 C     3             OCCUR     DS1
 C                   MOVE      'ABCDE'       FLDA
 C                   Z-ADD     22            FLDB

DS1 is set to the fourth occurrence. Using the values in FLDA and FLDB of the fourth occurrence of DS1, the MOVE operation places the contents of FLDA in the result field, FLDX, and the Z-ADD operation places the contents of FLDB in the result field, FLDY.

 C
 C     4             OCCUR     DS1
 C                   MOVE      FLDA          FLDX
 C                   Z-ADD     FLDB          FLDY

DS1 is set to the occurrence specified in field X. For example, if X = 10, DS1 is set to the tenth occurrence.

 C     X             OCCUR     DS1

DS1 is set to the current occurrence of DS2. For example, if the current occurrence of DS2 is the twelfth occurrence, DSI is set to the twelfth occurrence.

 C     DS2           OCCUR     DS1

The value of the current occurrence of DS1 is placed in the result field, Z. Field Z must be numeric with zero decimal positions. For example, if the current occurrence of DS1 is 15, field Z contains the value 15.

  C                   OCCUR     DS1           Z
  C

DS1 is set to the current occurrence of DS2. The value of the current occurrence of DS1 is then moved to the result field, Z. For example, if the current occurrence of DS2 is the fifth occurrence, DS1 is set to the fifth occurrence. The result field, Z, contains the value 5.

  C
  C     DS2           OCCUR     DS1           Z

DS1 is set to the current occurrence of X. For example, if X = 15, DS1 is set to the fifteenth occurrence. If X is less than 1 or is greater than 50, an error occurs and %ERROR is set to return '1'. If %ERROR returns '1', the LR indicator is set on.

  C
  C     X             OCCUR (E) DS1
  C                   IF        %ERROR
  C                   SETON                                        LR
  C                   ENDIF

Use externally-described data structures

Declare an externally-described data structure based on the inventory file (INVNTRY).
    d InvRec        e ds                  Based(pInvRec) ExtName(INVNTRY)

Write logic (including I/O operations) without numbered indicators

/Free
 SETLL (variable1:variable2) filename;
 IF %EQUAL(filename);
    READE(N) (variable1:variable2) filename;
    DOW NOT %EOF(filename);
       // logic
       READE(N) (variable1:variable2) filename;
    ENDDO;
 ENDIF; 
/End-Free
/Free
 CHAIN (variable3) filename;
 IF %FOUND(filename);
    // logic
    UPDATE filerec;
 ENDIF;
/End-Free

Code and use /Free format Calc specifications

/Free
 // Convert from a char to Num
 num = %DEC(char);
 // Chain to the correct record, checking for error with no rec lock
 CHAIN(EN) (char) filename1;
 IF %FOUND(filename1) and NOT %ERROR;  // If Condiditon
    CHAIN (num) filename2; // Chain to next file
    IF %FOUND(filename2); // If Condition
       filevar1 += 1;
       filevar2 = char;
       filevar3 = proc_call(filevar1:filevar2); // Call a Procedure
       // Update only field filevar3 in filename2
       UPDATE filerec2 %FIELDS(filevar3); 
    ENDIF;
 ELSEIF %ERROR;
    DSPLY 'There was an error';
    *INLR = %ERROR;
    RETURN;
 ENDIF;
 *INLR = *ON;
 RETURN;
/End-Free

Code and use Short Form expressions (e.g., + =)

i += 1;

Translate operation codes not supported in /Free form (e.g., MOVE, CALL, etc. into /Free form)

Use qualified Data Structures

Use pointer data types

Code and use Named Constants

Prototype program Calls

Determine appropriate use of passing parameters by value versus by reference

Prototype System APIs and C functions

Understand the ability for RPG procedures to call and be called by Java Methods

Enumerate advantages of Prototypes compared with PARM and PLIST

Determine appropriate use for prototype keywords, such as CONST, VALUE, and OPTIONS (*NOPASS, *OMIT, *VARSIZE)

<< Previous Section | Home | Next Section >>