01 - Programming (EN)01a - RPG (EN)

RPG – FAQ & Howtos (EN)

Last Updated on 22 September 2019 by Roberto De Pedrini

This is a collection of FAQs and tips about IBM RPG Language collected from forums or IBM i related websites. We’ll try to update this post constantly with new questions, new answers, and new tips too. Feel free to use the comments area to add new tips or new questions… you are welcome!.

RPG-FAQ-001: RPG and recursive calls.

The problem of recursive calls of RPG programs has always been a developers’ Achilles heel until the arrival of the ILE and the abandonment of the primary RPG cycle.

Basically if I want the PGMA to call the PGMB and the PGMB to call the PGMA without going into recursion I have two possible ways:

  1. I complete the program with DFTACTGRP(-NO) ACTGRP(-NEW) , indicating it in the CTL-OPT specifications or as an option at compile time with CRTBNDRPG or CRTPGM …. in this case, a new Activation Group is created every time pgMA is called with suboptimal performance and wasted memory and resources.
  2. I create a program without primary RPG cycle (linear main program) … then with a procedure declared as MAIN … in this case, I’ll have to be careful to close files: without a real *INLR, the end of main procedure leaves open files and locks too:
example:
 opt-ctl Main(MyMainProc);

dcl-pr MyMainProc ExtPgm('MYPGM');

dcl-proc Main;
  dcl-pi -N;
    ... Parameters if any
  end-pi

  ... Your code.

end-proc; 

Insights into this MCPress Online post “RPG Fundamentals: Work with linear main programs”

RPG-FAQ-002: RPG and Indicators … is it still relevant to use them?

Indicators in RPG no longer make sense … at least understood as indicators “IN55” or “IN(55), that is, in the numerical format of the same: they make the code cryptic for those who have not written it because they do not self-document … as a variable with its own name would do but of type “ind”.

The only thing that, in some way, keeps us tied to indicators are the attributes in DSPF Display Files or Printer Files PRTF … but even here there are tricks just to do without it.

I report below links to some interesting posts, even if old, that invite a smarter use of the indicators:

RPG-FAQ-003: STEP (STEP) functions of STRDBG vs. Debug Rdi

When we Debug a program or service program with the DEBUG of Rational Rdi we have the following functions of STEP:

  • F5 Step INTO
  • F6 Step OVER
  • F7 Step RETURN

Are they also available with the classic STRDBG?

Let’s start by saying that the difference between the STEP OVER and the STEP INTO is that the first one when it arrives on a program’s CALL or a Procedure’s call, executes the CALL or the Procedure and “stops” just after … the STEP INTO, as the word says, enters the called program or the called Procedure.

Step OVER and Step INTO also exist in STRDBG… Step Return no!

  • F10 executes the STEP OVER … but we can also write the command STEP n-righe OVER …
  • F22 executes the STEP INTO … but we can also write STEP n-lines INTO
  • However, there is no equivalent to Rational Rdi’s STEP RETURN in the STRDBG environment.

RPG-FAQ-004: STRDBG and SEP (Set Entry Point) as with Debug Rational Rdi?

With Rational Rdi it is very convenient to debug jobs in Batch … or web services called or jobs of other users by entering a Service Entry Point SEP. Is it possible to set an Entry Point with STRDBG as with the Rational Rdi Debug?

Yes, even if it’s not so simple… this IT-Jungle post “Debugging Server Jobs In Green Screen” by Susan Gantner explains it very well:

  • STRDBG mypgm
  • SBREAK line-number (or SBREAK line-number USER)
  • F12
  • SBMJOB or call to the program to be debugged
  • Wait for the message “Service Entry Point…” to appear in the session where you entered the debug
  • Press F1 to take the references to the JOB
  • Open a second session and run a STRSRVJOB JOB(123456/FAQ400/MYPGM) indicating the references to the JOB above
  • Run a STRDBG on the same program from this new session and you see the source stopped at the line indicated above
  • Go back to the previous session and press ENTER to “free” the JOB
  • Continue in the DEBUG with the other session!

RPG-FAQ-005: Where is my opened File in RPG

I’ve got the same name of one file in diferent libraries … there’s a way to determine the file/library opened by my F-Spec?

Try wiht INFDS, you can get Library and File name too.

Here’s an example.

 DCL-F MYFILE PRINTER(132) INFDS(OPNFBK);

   DCL-DS OPNFBK;
     ODP_TYPE      CHAR(2)    POS(81);     // ODP Type
     FILE_NAME     CHAR(10)   POS(83);     // File name
     LIBRARY       CHAR(10)   POS(93);     // Library name 

RPG-FAQ-006: XML-INTO and RPG… howto?

You can find more information and some examples of RPG code and XML-INTO at Yusi4code Blog: “XML parsing in AS400 (IBM-i) using XML-INTO


RPG-FAQ-007: Get IFS Object’s “creation date”

How can I get “creation date” for an IFS Object?

There’s an IFS API stat() to retrieve some object’s attributes … but if you need the “creation date” you have to take a look at Qp0lGetAttr()–Get Attributes API: see this example at Think400 website “CBX127 Change IFS attributes – CPP

With stat() API you can get some other interesting attributes:

D stat            PR            10I 0 ExtProc('stat')                   
D path * Value Options(*string)
D buf
-------------
D statDS DS Qualified Template
D st_mode 10U 0
D st_ino 10U 0
D st_nlink 5U 0
D st_reserved2 5U 0
D st_uid 10U 0
D st_gid 10U 0
D st_size 10I 0
D st_atime 10I 0
D st_mtime 10I 0
D st_ctime 10I 0
D st_dev 10U 0
D st_blksize 10U 0
D st_allocsize 10U 0
D st_objtype 11A
D st_reserved3 1A
D st_codepage 5U 0
D st_ccsid 5U 0
D st_rdev 10U 0
D st_nlink32 10U 0
D st_rdev64 20U 0
D st_dev64 20U 0
D st_reserved1 36A
D st_ino_gen_id 10U 0
-----------
D fileStats DS Likeds(statDS)


if stat('/path/to/file': fileStats) < 0;
// error handling
endif;

// ccsid now in fileStats.st_ccs


RPG-FAQ-008: Convert character Hex to Decimal

How can I convert a hex character string to the decimal value in RPG as in this online service ( https://www.binaryhexconverter.com/hex-to-decimal-converter ) ?

Try ctvch() API:

 **free

ctl-opt dftactgrp(*no);

dcl-pr cvtch extproc('cvtch');
  dest pointer value;
  src pointer value;
  len int(10) value;
end-pr;

dcl-s hexValue char (8) inz('00BC614E');
dcl-s binValue int (10);
dcl-s len int(10);

len = %len(hexValue);

cvtch(%addr(binValue):%addr(he
xValue):len);

*inlr = *on; 

Or with those API strol() and itoa(): you can choose radix… not only hex (16).

      ctl-opt actgrp(*new) option(*srcstmt:*nodebugio);

        dcl-pr strtol int(10) extproc('strtol');
          iString pointer value options(*string);
          oBuf pointer value;
          iRadix int(10) value;
        end-pr;
        dcl-s pdummy pointer;

        dcl-pr itoa extproc('__itoa');
          iNum int(10) value;
          oBuf pointer value;
          iRadix int(10) value;
        end-pr;

        dcl-s buffer char(20);
        dcl-s value int(10);

        value = strtol( '00000000000000000000000000111101':%addr(pdummy): 2);
        dsply value;  // Shows 61

        itoa( value: %addr(buffer): 16);
        dsply buffer;  // Shows 3d

        *inlr = *on;
 

REXX can do the same

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*             XCALC EXP('REVERSE("String")')                    */
/* ______________________________
______________________________
_ */
/*                                                               */
/*  Yet another *FREEWARE* utility from Prime Suspect Software,  */
/*        creating slightly above average products for the       */
/*                enlightened masses since 1982.                 */
/* ______________________________
______________________________
_ */
/*                                                               */
/*  REXX Program Name... XCALC                                   */
/*  Programmer.......... Matt Sargent                            */
/*  Internet Address.... M.SARGENT@GENIE.GEIS.COM                */
/*                                                               */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

signal on syntax

parse arg string
parse value space(string) with "'"expression"'"
interpret 'answer =' expression
answer = strip(expression) '=' answer
'SNDPGMMSG MSG(&answer)'
exit

syntax:
   syntaxerr = errortext(rc)
   'SNDPGMMSG MSG(&syntaxerr)'

================

  CMD        PROMPT('Expression Calculator')
  PARM       KWD(EXP) TYPE(*CHAR) LEN(256) MIN(1) +
               CHOICE('Character value') +
               PROMPT('Mathmatical expression')

=========

d2x() is the REXX function to convert Decimal to heXdecimal.  The
data conversions available in the AS400 implementation of REXX are:
b2x()  binary    to hex
x2b()  hex       to binary
c2d()  character to decimal     (EBCDIC)
d2c()  decimal   to character   (EBCDIC)
c2x()  character to hex         (EBCDIC)
x2c()  hex       to character   (EBCDIC)
d2x()  decimal   to hex
x2d()  hex       to decimal 

If you need to extract numeric value from a packed string:( ITJungle “Extracting Zoned and Packed Decimal Values from Character Fields“)

 D usrf01          ds 
 D   TypeCode              1      2s 0 
 D   Category              3      4p 0 
 D   Amount                5      8p 2 

-- Get the amount checking is sign
select dec(
         dec(substr(hex(substr(usrf01,5,4)),1,5)||'.'||
             substr(hex(substr(usrf01,5,4)),6,2),
         7,2) *
         (case when substr(hex(substr(usrf01,5,4)),8,1) = 'D'
                 then -1 else 1 end),
       7,2) as Price
  from usrfldpf

RPG-FAQ-009: Crypt e Decrypt in RPG (AES 128)

You can crypt and decrypt a string in RPG SQL Embedded using some SQL scalar functions.

SQL cipher and decipher functions are not only for Advanced Encryption Standard (AES) algorithm, but Triple DES (TDES) and RC2 too.

Let’s take a look to this simple SQL statement: we crypt and then decrypt a string in AES with a simple password

With mytext as (
 select  Encrypt_AES('This is my secret', 'Pa$$w0rd') as txtEncrypted
 from sysibm.sysdummy1)

 select Decrypt_char(txtEncrypted, 'Pa$$w0rd')
 from mytext;

In this example, we cipher a string in RPG with SQL Embedded … pay attention to the Encrypted variable length, the cipher algorithm generally give out a long string. Using a constant as a password string is not a good idea, store it in a table or in the ENCRYPTION PASSWORD special register.

DCL-S Text   VarChar(20);
DCL-S Encrypted VarChar(256);
DCL-S Password VarChar(15)  inz('yourPassWord')

Text = 'Whatever Text'
Exec SQL  Set :Encrypted = Encrypt_AES(Text, PassWord);
 

If you don’t like SQL and you want to get hurt wit system’s API you can see at:

Encrypt Data (QC3ENCDT, Qc3EncryptData) API

References:

RPG-FAQ-010: API by example

If you need some examples and howtos about system’s API in RPG there is a great website by Carsten Flesburg:

Articles on API – API by example – Carsten Flesburg

--- Roberto De Pedrini Faq400.com
About author

Founder of Faq400 Srl, IBM Champion, creator of Faq400.com and blog.faq400.com web sites. RPG developer since I was wearing shorts, strong IBM i supporter, I have always tried to share my knowledge with others through forums, events and courses. Now, with my company Faq400 Srl, I help companies to make the most of this great platform IBM i.

Leave a Reply

%d bloggers like this: