Deck: A utility for every RPG programmer's bag of tricks.
One of the most annoying aspects of RPG as a programming language is its fixed format columnar structure. Although IBM has created most of the standard structured operations found in modern programming languages, the fixed format requirement prevents the programmer from indenting structures so that the reader can easily decipher the levels of structure being used.
In free-format languages such as COBOL, C or PL/I, indenting code has never been a problem, and understanding code in these free-format languages is normally easier than reading RPG. This is why I created the Indent RPG Source (INDRPGSRC) command. While you still have to write in fixed format, it makes reading RPG programs much easier. 1a and 1b illustrates how INDRPGSRC can improve readability of an RPG program. This utility indents the RPG code it finds between the structured operations IFxx, DO, DOWxx, DOUxx, SELEC/WHxx, and their corresponding END or ENDxx statements. It also draws vertical lines to show which portions of the program have been indented. The results can be viewed on the screen or sent to the printer.
In free-format languages such as COBOL, C or PL/I, indenting code has never been a problem, and understanding code in these free-format languages is normally easier than reading RPG. This is why I created the Indent RPG Source (INDRPGSRC) command. While you still have to write in fixed format, it makes reading RPG programs much easier. Figure 1a and 1b illustrates how INDRPGSRC can improve readability of an RPG program. This utility indents the RPG code it finds between the structured operations IFxx, DO, DOWxx, DOUxx, SELEC/WHxx, and their corresponding END or ENDxx statements. It also draws vertical lines to show which portions of the program have been indented. The results can be viewed on the screen or sent to the printer.
Some of you may ask, "Why is MC publishing this utility when IBM added the INDENT parameter to the CRTRPGPGM command in V2R1?" When MC first heard about this new indent feature from IBM, they decided not to publish this utility. However, after working with IBM's indention facility, they decided that you should have something better. Later I'll give you more information on the weaknesses and limitations of IBM's version, but for now read on and find out how you can program more easily with this utility.
How INDRPGSRC Works
The code for the command, programs, display file and pritner file that make up INDRPGSRC are shown in2a through 2e. The INDRPGSRC command, shown in 2a, has the following parameters:
The code for the command, programs, display file and pritner file that make up INDRPGSRC are shown in Figures 2a through 2e. The INDRPGSRC command, shown in Figure 2a, has the following parameters:
SRCMBR: Name of the source member containing the RPG source code to be indented. Normally this is also the name of the program. This is the only mandatory parameter.
SRCFILE: Qualified name of the source physical file where the source member resides. It defaults to QRPGSRC in *LIBL.
LOWSEQ: The beginning sequence number of the source member to start displaying or listing. The default is 0000.00.
HISEQ: The ending sequence number of the source member to stop displaying or listing. The default is 9999.99.
SYMBOL: The symbol you enter here is used by INDRPGSRC to join the beginning and ending of an indented block of code, such as an IFxx and its END. It defaults to a vertical bar. If your printer can't print a vertical bar, change it to some other character such as a colon (:) or even an opening parenthesis.
COLUMNS: The number of columns to the right that INDRPGSRC should indent each level of code. You can enter any value between one and five. The default value is 2.
OUTPUT: Leave the default value of * to display the indented code, or change it to *PRINT to send it to the printer.
If OUTPUT(*PRINT) is specified, the command prompter will ask for another parameter:
PAGEBRK: Whether to break the listing in separate pages (each with a heading) when overflow occurs. The default is *NO, meaning that the printing is continuous, even over the perforation; this makes it easier to follow the indentations.
If you press F10, the command prompter displays the following additional parameter:
MARKCHG: Mixed list of three elements, which causes INDRPGSRC to mark the source code lines that have been changed since a specific date. The first element is the date of change. If you leave it blank, no marking will occur. The second element is a relationship, such as *EQ for equal. The third element is a four-character symbol you choose to mark the changed lines. For example, MARKCHG(070491 *GE '>>>') will mark with '>>>' all lines that have been changed since July 4, 1991.
If you choose to view the output on the screen, you'll notice that the screen looks very much like SEU in browse mode. One difference is that there is a field on the screen labeled "ROLL==>." The value in this field is the number of lines to roll when the Roll Up or Roll Down keys are pressed. The default is 20 lines, which is one full screen. You can increase or decrease this number to position the screen exactly where you want it. For example, try entering a one in this field and repeatedly press Roll Up. You'll notice that the screen scrolls very slowly. Entering 50 would cause you to jump through the source code very quickly.
If you choose to print a listing you'll notice that it looks very much like an SEU source listing. The difference here is that there is a column labeled "IND USE." This column is used to show in which position you have coded resulting indicators. A one, two or three in this column represents the corresponding indicator position. This is the same representation used by IBM on a compile listing. It is necessary on the indent listing because the indicators are shifted over when indented.
IBM's Version
With OS/400 V2R1, IBM has added a parameter to the Create RPG Program (CRTRPGPGM) command which allows you to create an indented compile listing. To use this new feature, change the parameter INDENT from the default of *NONE to the indention symbol of your choice. This is a nice feature and shows that IBM agrees that indenting RPG code is a good idea. However, it has several disadvantages over the INDRPGSRC command. It requires you to compile the source in order to see it in its indented form, and we know how slow compiles can be; you may decide that the old method of drawing lines with a pencil is faster. (I did discover that using OPTION(*NOGEN) in the CRTRPGPGM command prevents you from having to replace the object, but it doesn't decrease by one iota the time it takes to go through a compile).
With IBM's method you cannot display an indented listing without creating a spool file. INDRPGSRC gives you a choice of output device (screen or printer). INDRPGSRC allows you to display or print sections of the source member via the LOWSEQ and HISEQ parameters. So, if you only need to work on part of the source member, such as a subroutine, you can display or print only those statements.
Take INDRPGSRC For a Test Drive
Many AS/400 shops may already have a utility similar to this one. If you are one of these people I'd like to encourage you to try this version anyway. It has some features which I don't think you'll find in other versions. If you're an RPG programmer and you don't have a utility similar to this one, then you need this utility. I can almost guarantee it will make you a better programmer. Personally, I cannot imagine coding in RPG without it.
Indenting RPG Source
Figure 1A Unindented RPG code
Figure 1a: Unindented RPG Code C X DOWLE100 C AZ1,X ANDGT0 C #ZIP3 IFGE AZ1,X C #ZIP3 ANDLEAZ2,X * ADD TO APPROPRIATE COUNTER C SELEC C SMS400 WHEQ 'Y' C ADD 1 AC1,X C SMS36 WHEQ 'Y' C ADD 1 AC2,X C OTHER C ADD 1 ACU,X C ENDSL C ADD 1 X C ENDIF C ENDDO
Indenting RPG Source
Figure 1B Indented RPG code using INDRPGSRC
Figure 1b: Indented RPG Code Using INDRPGSRC C X DOWLE100 C AZ1,X ANDGT0 C #ZIP3 || IFGE AZ1, C #ZIP3 || ANDLEAZ2, * || || ADD TO APPROPRIATE COUNT C || || SEL C SMS400 || || WHEQ ' C || || || ADD 1 AC C SMS36 || || WHEQ ' C || || || ADD 1 AC C || || OTH C || || || ADD 1 AC C || || END C || || ADD 1 C || ENDI C ENDDO
Indenting RPG Source
Figure 2A Command INDRPGSRC
INDRPGSRC: CMD PROMPT('Indent RPG Source') PARM KWD(SRCMBR) TYPE(*NAME) MIN(1) + PROMPT('Source member') PARM KWD(SRCFILE) TYPE(Q1) PROMPT('Source file') PARM KWD(LOWSEQ) TYPE(*DEC) LEN(6 2) DFT(0000.00) + RANGE(0000.00 9999.99) PROMPT('Lowest + sequence') PARM KWD(HISEQ) TYPE(*DEC) LEN(6 2) DFT(9999.99) + RANGE(0000.00 9999.99) PROMPT('Highest + sequence') PARM KWD(SYMBOL) TYPE(*CHAR) LEN(1) DFT(|) + PROMPT('Indent symbol') PARM KWD(COLUMNS) TYPE(*DEC) LEN(1 0) DFT(2) + RANGE(1 5) PROMPT('Columns to indent') PARM KWD(OUTPUT) TYPE(*CHAR) LEN(6) RSTD(*YES) + DFT(*) VALUES(* *PRINT) PROMPT('Output') PARM KWD(MARKCHG) TYPE(E1) PMTCTL(*PMTRQS) + PROMPT('Mark changes') PARM KWD(PAGEBRK) TYPE(*CHAR) LEN(4) RSTD(*YES) + DFT(*NO) VALUES(*YES *NO) PMTCTL(PC1) + PROMPT('Break to new page on overflow') E1: ELEM TYPE(*DATE) PROMPT('On date') ELEM TYPE(*CHAR) LEN(3) RSTD(*YES) DFT(*EQ) + VALUES(*EQ *GT *LT *GE *LE) + PROMPT('Comparison') ELEM TYPE(*CHAR) LEN(4) DFT('CHG>') PROMPT('Mark + symbol') PC1: PMTCTL CTL(OUTPUT) COND((*EQ *PRINT)) Q1: QUAL TYPE(*NAME) DFT(QRPGSRC) QUAL TYPE(*NAME) DFT(*LIBL) SPCVAL((*LIBL)) + PROMPT('Library')
Indenting RPG Source
Figure 2B CL program RPG002CL
RPG002CL: + PGM PARM(&SRCMBR &QSRCFILE &LOWSEQ &HISEQ &SYMBOL &COLUMNS + &OUTPUT &MARKCHG &PAGEBRK) DCL VAR(&CHGDATE) TYPE(*CHAR) LEN(7) DCL VAR(&CHGDT) TYPE(*DEC) LEN(7 0) DCL VAR(&CHGID) TYPE(*CHAR) LEN(4) DCL VAR(&COLUMNS) TYPE(*DEC) LEN(1 0) DCL VAR(&COMPARE) TYPE(*CHAR) LEN(3) DCL VAR(&FILE) TYPE(*CHAR) LEN(10) DCL VAR(&HISEQ) TYPE(*DEC) LEN(6 2) DCL VAR(&LIB) TYPE(*CHAR) LEN(10) DCL VAR(&LOWSEQ) TYPE(*DEC) LEN(6 2) DCL VAR(&MARKCHG) TYPE(*CHAR) LEN(16) DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(132) DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) DCL VAR(&OUTPUT) TYPE(*CHAR) LEN(6) DCL VAR(&PAGEBRK) TYPE(*CHAR) LEN(4) DCL VAR(&QSRCFILE) TYPE(*CHAR) LEN(20) DCL VAR(&SRCF) TYPE(*CHAR) LEN(21) DCL VAR(&SRCMBR) TYPE(*CHAR) LEN(10) DCL VAR(&SYMBOL) TYPE(*CHAR) LEN(1) MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) /* Break qualified name */ CHGVAR VAR(&FILE) VALUE(%SST(&QSRCFILE 1 10)) CHGVAR VAR(&LIB) VALUE(%SST(&QSRCFILE 11 10)) RTVMBRD FILE(&LIB/&FILE) MBR(&SRCMBR) RTNLIB(&LIB) /* Break mixed list */ CHGVAR VAR(&CHGDATE) VALUE(%SST(&MARKCHG 3 7)) CHGVAR VAR(&COMPARE) VALUE(%SST(&MARKCHG 10 3)) CHGVAR VAR(&CHGID) VALUE(%SST(&MARKCHG 13 4)) /* Override files as needed */ OVRDBF FILE(QRPGSRC) TOFILE(&LIB/&FILE) MBR(&SRCMBR) LVLCHK(*NO) IF COND(&OUTPUT *EQ '*PRINT') THEN(OVRPRTF FILE(RPG002P1) + USRDTA(&SRCMBR)) CHGVAR VAR(&SRCF) VALUE(&LIB *TCAT '/' *CAT &FILE) CHGVAR VAR(&CHGDT) VALUE(&CHGDATE) CALL PGM(RPG002RG) PARM(&SRCMBR &SRCF &LOWSEQ &HISEQ &SYMBOL + &COLUMNS &CHGDT &COMPARE &CHGID &OUTPUT &PAGEBRK) GOTO CMDLBL(END) /* Send error message */ ERROR: + RCVMSG MSGTYPE(*EXCP) MSGDTA(&MSGDTA) MSGID(&MSGID) SNDPGMMSG MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) + MSGTYPE(*ESCAPE) /* End program */ END: + ENDPGM
Indenting RPG Source
Figure 2C Display file RPG002DF
A*% %TS SD 19911017 133631 MALERN REL-V2R1M0 5738-PW1 A*% %EC A DSPSIZ(24 80 *DS3) A PRINT A CA03 A CA12 A R SFLREC SFL A SEQNBR 7A O 3 2 A DSPLIN 71A O 3 10 A R CTLREC SFLCTL(SFLREC) A*% %TS SD 19911017 133631 MALERN REL-V2R1M0 5738-PW1 A SFLSIZ(0022) A SFLPAG(0021) A SFLDSP A SFLDSPCTL A 1 2'Columns . . . : 1 71' A 1 32'Indent RPG Source' A DSPATR(HI) A SRCF 21A O 1 60 A 2 2'ROLL==>' A MBR 10A O 2 60 A ROLL 4 0B 2 10SFLROLVAL
Indenting RPG Source
Figure 2D Printer file RPG002P1
A R HEADER A 1 1DATE A EDTCDE(Y) A 1 12TIME A 1 50'INDENT RPG SOURCE' A 1125'PAGE' A 1129PAGNBR A EDTCDE(3) A 3 1'SOURCE FILE . . . . . . .' A SRCF 21 3 28 A 4 1'MEMBER . . . . . . . . .' A MBR 10 4 28 A 6 1'SEQ NBR' A 6 9'*...+... 1 ...+... 2 ...+... - A 3 ...+... 4 ...+... 5 ...+... - A 6 ...+... 7 ...+... 8 ...+... - A 9 ...+... 0' A 6115'IND USE' A 6125'CHG DATE' A R DETAIL SPACEB(1) A SEQNBR 7A 1 A PRTLIN 105 9 A INDUSE 5 116 A SRCDAT 6 0 125EDTCDE(Y) A R FOOTER SPACEB(2) O 38 '* * * *' O 47 'E N D O F S O U R C E' O 72 '* * * *'
Indenting RPG Source
Figure 2E RPG program RPG002RG
FQRPGSRC IF F 92 DISK FRPG002P1O E 01 PRINTER UC FRPG002DFCF E WORKSTN UC F SFLRN KSFILE SFLREC * E LIN 105 1 E BAR 1 2 71 * IQRPGSRC NS I 1 62SRCSEQ I 7 120SRCDAT I 13 92 SRCDTA I 20 92 COMENT I 18 18 SPEC I 19 19 ASTRSK I 13 19 COMSPC I 13 15 ARRAYS I 40 41 OPCD2 I 40 42 OPCD3 I 40 44 OPCD5 I 13 39 LSRC I 40 92 RSRC I 66 67 IND1 I 68 69 IND2 I 70 71 IND3 I DS I 1 5 INDUSE I 1 1 USE1 I 3 3 USE2 I 5 5 USE3 I DS I 1 7 SEQNBR I 1 4 SEQNM1 I 5 5 DECPNT I 6 7 SEQNM2 ***************************************************************** C *ENTRY PLIST C PARM MBR 10 C PARM SRCF 21 C PARM LOWSEQ 62 C PARM HISEQ 62 C PARM SYMBOL 1 C PARM COLS 10 C PARM CHGDAT 70 C PARM CMPARE 3 C PARM CHGID 4 C PARM OUTPUT 6 C PARM PAGBRK 4 * C EXSR WRTHDR * C READ QRPGSRC 99 C *IN99 DOWEQ'0' C SRCSEQ ANDLEHISEQ C SRCSEQ IFGE LOWSEQ C EXSR CHKLVL C EXSR INDENT C EXSR WRTDTL C END C READ QRPGSRC 99 C END * C EXSR WRTFTR C SETON LR ***************************************************************** C CHKLVL BEGSR C MOVEA*BLANK LIN C MOVE *BLANK INDUSE * C SHIFT IFEQ 'Y' C OPCD3 ANDNE'AND' C OPCD2 ANDNE'OR' C ADD 1 LEVEL 30 C MOVE *BLANK SHIFT 1 C END * C SPEC IFEQ 'C' C ASTRSK ANDNE'*' C OPCD2 IFEQ 'IF' C OPCD2 OREQ 'DO' C OPCD5 OREQ 'SELEC' C MOVE 'Y' SHIFT C ELSE C OPCD3 IFEQ 'CAS' C MOVE 'Y' CASE 1 C ELSE C OPCD3 IFEQ 'END' C CASE IFNE 'Y' C LEVEL IFGT *ZERO C SUB 1 LEVEL C ELSE C Z-ADD*ZERO LEVEL C END C ELSE C MOVE *BLANK CASE C END C END C END C END C IND1 IFNE *BLANK C MOVE '1' USE1 C END C IND2 IFNE *BLANK C MOVE '2' USE2 C END C IND3 IFNE *BLANK C MOVE '3' USE3 C END C END C ENDSR ***************************************************************** C INDENT BEGSR C LEVEL IFEQ *ZERO C MOVEASRCDTA LIN C ELSE * C MOVE *BLANK ELSE 1 C ASTRSK IFNE '*' C MOVEALSRC LIN C OPCD5 IFEQ 'ELSE ' C OPCD2 OREQ 'WH' C OPCD5 OREQ 'OTHER' C MOVE 'Y' ELSE C END C END * C Z-ADD28 X 30 C 1 DO LEVEL LVLNUM 30 C ASTRSK IFEQ '*' C ELSE ORNE 'Y' C LVLNUM ORNE LEVEL C LVLNUM IFLE MAXLVL C MOVEASYMBOL LIN,X C ADD COLS X C END C END C END * C ASTRSK IFNE '*' C MOVEARSRC LIN,X C ELSE C MOVEACOMSPC LIN C MOVEACOMENT LIN,X C END C END C ENDSR ***************************************************************** C WRTDTL BEGSR C ARRAYS IFEQ '** ' C MOVE 'Y' DATA 1 C END * C CHGDAT IFGT *ZERO C DATA ANDNE'Y' C MOVEA' ' LIN C CMPARE IFEQ '*EQ' C SRCDAT ANDEQCHGDAT C CMPARE OREQ '*GT' C SRCDAT ANDGTCHGDAT C CMPARE OREQ '*LT' C SRCDAT ANDLTCHGDAT C CMPARE OREQ '*GE' C SRCDAT ANDGECHGDAT C CMPARE OREQ '*LE' C SRCDAT ANDLECHGDAT C MOVEACHGID LIN C END C END * C MOVELSRCSEQ SEQNM1 C MOVE '.' DECPNT C MOVE SRCSEQ SEQNM2 * C OUTPUT IFEQ '*PRINT' C MOVEALIN PRTLIN C MULT 100.0001 SRCDAT C PAGBRK IFEQ '*YES' C *IN01 ANDEQ'1' C WRITEHEADER C MOVE '0' *IN01 C END C WRITEDETAIL C ELSE C MOVEALIN DSPLIN C ADD 1 SFLRN C WRITESFLREC C END C ENDSR ***************************************************************** C WRTHDR BEGSR C OUTPUT IFEQ '*PRINT' C WRITEHEADER C ELSE C Z-ADD20 ROLL C MOVELBAR,1 DSPLIN C Z-ADD1 SFLRN 50 C WRITESFLREC C END C ENDSR ***************************************************************** C WRTFTR BEGSR C OUTPUT IFEQ '*PRINT' C WRITEFOOTER C ELSE C MOVE *BLANK SEQNBR C MOVELBAR,2 DSPLIN C ADD 1 SFLRN C WRITESFLREC C EXFMTCTLREC C END C ENDSR ***************************************************************** C *INZSR BEGSR C OUTPUT IFEQ '*PRINT' C OPEN RPG002P1 C ELSE C OPEN RPG002DF C END C 40 DIV COLS MAXLVL 20 C ENDSR ***************************************************************** ** *************** Beginning of data ************************************* ****************** End of data ****************************************
LATEST COMMENTS
MC Press Online