Using Edit Codes

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Often, when I'm writing an application, I need to use an edit code. The RPG IV built-in function %EDITC is great for editing on the fly within the Calc specs, and of course, the traditional RPG Output specs support edit codes in position 44.

One problem with edit codes in RPG IV is that they are fixed. You have to actually hard-code them in a program; you can't pass in an edit code to the program and then forward it on to the Output specifications. Even the %EDITC built-in function requires the edit code on its second parameter to be specified as a compile-time value. That is, the edit code must be known at compile time. So only a literal or named constant can be specified.

For example, see the line of code below. The 'J' edit code has to be a compile-time value; therefore, it cannot be a field name.

eval      szMyValue = %EDITC(Salary : 'J')

What I really want is the ability to call a procedure and have it return the character string containing the edited numeric value. There are two APIs on the system that can provide runtime editing of numeric values. This means you have to use APIs instead of the easy-to-use built-in function or the Output specification, but the benefit is you don't have to hard code the edit code at compile-time.

These two APIs are QECCVTEC (Convert Edit Code) and QECEDT (Apply Edit Mask). The QECCVTEC API converts an edit code into an internal "edit mask." An edit mask is a formatting string that is subsequently used by the QECEDT API to apply the edit code to the numeric value.

To use these two API programs (they are programs, not procedures), you can create a prototype to make calling the APIs much easier. I've created the prototypes for you and have listed them in Figures 1 and 2, respectively.

D CvtEditCode     PR                  ExtPgm('QECCVTEC')
D   EditMask                   256A   OPTIONS(*VARSIZE)
D   EditMaskLen                 10I 0
D   RcvVarLen                   10I 0
D   ZeroFill                     1A
D   EditCode                     1A   CONST
D   FillChar                     1A   CONST
D   Digits                      10I 0 CONST
D   DecPos                      10I 0 CONST
D   api_error                         Like(ApiError)

Figure 1: Prototype for the QECCVTEC (Convert Edit Code) API

D FmtEdit         PR                  ExtPgm('QECEDT')
D  szEditValue                  32A
D  nEditLen                     10I 0 Const
D  nNumValue                    15P 2 Const
D  szDataType                   10A   Const
D  nFldLen                      10I 0 Const
D  szEditMask                  256A   OPTIONS(*VARSIZE)
D  nEditMastLen                 10I 0 Const
D  bZeroBal                      1A   Const
D  api_Error                          Like(ApiError)

Figure 2: Prototype for the QECEDT (Edit Numeric Value) API

The logic for using these two APIs is that you call QECCVTEC with the edit code you want to use, along with the definition of the value being edited. Assuming all goes well, this call will return an edit mask. Then, you need to call QECEDT, passing to it the edit mask and a few other returned values from the call to QECCVTEC.

An Edit Example

Since I enjoy the ability to do edit code sampling, I created a simple program, DSPEDIT, that illustrates how to use these two APIs and provides a sampling of any edit code you provide.

The program supports three parameters. The first parameter is the edit code that you want to sample. The second parameter is the numeric value you want to use in the sample edited output. This value has the edit code applied to it and is printed to QPRINT. The second parameter is defined as a Pkd(15,5) value so that it may be specified from the command entry display. The third parameter is the currency symbol. If you want to use a floating currency symbol in the sample output, specify a currency symbol for the third parameter.

None of the parameters are required when calling the program. If no parameters are specified or if the edit code is specified as an asterisk (*), then a sample of all the RPG IV edit codes is generated.

Since this program is just an example of how to use these two APIs together, I didn't spend as much time formatting the output as you might want to. Also note that the output is sent to QPRINT, so to view the results, you need to look at the spool file listing. It would be fairly simple to convert the program to output a *COMP (completion) message so that it appears in the job log instead of a spool file.

The source for the DSPEDIT sample program is listed in Figure 3.

BNDDIR('QC2LE') OPTION(*SRCSTMT:*NODEBUGIO)
H/IF DEFINED(*CRTBNDRPG)
DFTACTGRP(*NO) ACTGRP('RPGLIB')
H/ENDIF

FQPRINT    O    F  132        PRINTER OFLIND(*INOV)

D DSPEDIT         PR
D  szEditCode                    1A
D  nValue                       15P 5
D  szCurSymb                     1A

D DSPEDIT         PI
D  szEditCode                    1A
D  nValue                       15P 5
D  szCurSymb                     1A

D szPlus          S             32A
D szMinus         S             32A
D szZero          S             32A

D nDftValue       S             15P 2 Inz(54321.78)
D nNumValue       S             15P 2
D nEditValue      S             15P 2
D szEditMask      S            256A
D nMaskLen        S             10I 0 Inz(%size(szEditMask))
D nTargetLen      S             10I 0
D bZeroBalances   S              1A
D cCurSymb        S                   Like(szCurSymb) 

D apiError        DS                  Inz
D  dsLen                        10I 0 Inz(%size(apiError))
D  RtnLen                       10I 0
D  msgid                         7A
D  szReserved                    1A
       
D editcodes       DS
D  ecData                       19A   Inz('1234ABCD+
D                                          JKLMNOPQ+
D                                          XYZ')
D  ec                            1A   Dim(%size(ecData))
D                                     Overlay(ecData)       

D szEdtCde        S                   Like(szEditCode)
D nCount          S             10I 0
D i               S             10I 0

 *************************************************************
 **  C O N V E R T  E D I T  C O D E  T o  E D I T M A S K  **
 *************************************************************
D CvtEditCode     PR                  ExtPgm('QECCVTEC')
D   EditMask                   256A   OPTIONS(*VARSIZE)
D   EdtMskLen                   10I 0
D   RcvVarLen                   10I 0
D   ZeroFill                     1A
D   EditCode                     1A   CONST
D   FillChar                     1A   CONST
D   Digits                      10I 0 CONST
D   DecPos                      10I 0 CONST
D   api_error                         Like(ApiError)

D FmtEdit         PR                  ExtPgm('QECEDT')
D  szEditValue                 256A   OPTIONS(*VARSIZE)
D  nEditLen                     10I 0 Const
D  nSrcValue                    15P 2 Const
D  szDataType                   10A   Const
D  nFldLen                      10I 0 Const
D  szEditMask                  256A   OPTIONS(*VARSIZE)
D  nEditMastLen                 10I 0 Const
D  bZeroBal                      1A   Const
D  api_Error                          Like(ApiError)

C                   if        %Parms >= 1
C                   eval      szEdtCde = szEditCode
C                   else
C                   eval      szEdtCde = 'J'
C                   endif

C                   if        %Parms >= 2
C                   eval      nNumValue = nValue
C                   else
C                   eval      nNumValue = nDftValue
C                   endif

     C                   if        %Parms >= 3
C                   eval      cCurSymb = szCurSymb
C                   if        Not (szEdtCde>='1' and szEdtCde<='4'
C                             or szEdtCde>='A' and szEdtCde<='D'
C                             or szEdtCde>='J' and szEdtCde<='Q')
 ** If asterisk-fill is specified, we can only do it
 ** when one of the above edit codes is specified.
C                   if        cCurSymb = '*'
C                   eval      cCurSymb = ' '
C                   endif
C                   endif
C                   endif

C                   if        szEdtCde = '*'  
C                   eval      nCount = %elem(ec)
C                   eval      i = 1
C                   else
C                   eval      ec(1) = szEdtCde 
C                   eval      nCount = 1
C                   endif

C                   Except    Header

C                   for       i = to nCount
C                   eval      nEditValue = nNumValue
C                   eval      szEditMask = ' '
C                   reset                   apiError
C                   callp     CvtEditCode(szEditMask : nMaskLen :
C                               nTargetLen : bZeroBalances : 
C                               ec(i) cCurSymb :        
C                               %Len(nEditValue) : 
C                               %DecPos(nEditValue):    
C                               ApiError)        

C                   eval      nEditValue%abs(nNumValue)
C                   callp     FmtEdit(szPlusnTargetLen : nEditValue:
C                                     '*PACKED'  : %Len(nEditValue) :
C                                     szEditMask : nMaskLen :
C                                     bZeroBalances : ApiError )

C                   eval      nEditValue%abs(nNumValue) * -1
C                   callp     FmtEdit(szMinusnTargetLen : nEditValue:
C                                     '*PACKED'  : %Len(nEditValue) : 
C                                     szEditMask : nMaskLen :
C                                     bZeroBalances : ApiError )

C                   eval      nEditValue0
C                   callp     FmtEdit(szZeronTargetLen : nEditValue:
C                                     '*PACKED'  : %Len(nEditValue) :
C                                     szEditMask : nMaskLen :
C                                     bZeroBalances : ApiError )
C                   eval      szMyValue = %EDITC(Salary : 'J')
C                   Except    Detail
C                   endfor

C     ENDPGM        TAG
C                   eval      *INLR = *ON
C                   return

OQPRINT    E            Header         1
O                                        +   5 'EdtCde' 
O                                        +  10 'Positive' 
O                                        +   5 'Negative'
O                                        +   5 'Zero'
OQPRINT    E            Detail         1
O                       ec(i)            +   7
O                       szPlus         B +   0
O                       szMinus        B +   0
O                       szZero         B +   0

Figure 3: DSPEDIT source code

How About a Prompter?

When I wrote CodeStudio, I created a prompter that displays a numeric value after applying an edit code to the value. This has been very beneficial in helping to decide which edit code to use; after all, even after all these years of programming, I still can't remember what the "4" edit code does, and why should I?

For an example of the CodeStudio Output specification prompter with "Edit Code Sampling" see Figure 4.

http://www.mcpressonline.com/articles/images/2002/Using%20Edit%20Codes00.png

Figure 4: Edit code with the CodeStudio prompter. (Click image to enlarge.)

Bob Cozzi has been programming in RPG since 1978. Since then, he has written many articles and several books, including The Modern RPG Language --the most widely used RPG reference manual in the world. Bob is also a very popular speaker at industry events such as RPG World and is the author of his own Web site and of the RPG ToolKit, an add-on library for RPG IV programmers.

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$0.00 Raised:
$