Storing Named Constants in Prototypes

Article ID: 57264

Use Constants for Greater Simplicity

The use of prototypes has lead to the widespread usage of /COPY members in virtually every new RPG IV source member. One thing that people don't often realize, however, is that you can store other things besides prototypes in these /COPYs. One component I often include is named constants. This lets the users of my subprocedures use special values as parameters. For example, if I have a subprocedure with a parameter that can accept any of three different values, I will code those values as named constants.

     D First           C                   Const(1)
     D Second          C                   Const(2)
     D Third           C                   Const(3)

Then when my subprocedure is called, the programmer can write something like the following:

        myProc(custno : second);

Note the use of the SECOND named constant. This provides a more documented value than simply hard-coding the number 2. These three named constants would be included in the /COPY member that also included the prototype for the MYPROC subprocedure. That way the programmer using MYPROC can take advantage of these values, which are arguably more memorable than the numbers themselves. Let's look at a concrete example.

CONVERT (Convert Case)

To illustrate how this would all fit together, let's look at a hybrid subprocedure named CONVERT. This subprocedure's purpose is to convert the data passed into it to all uppercase or all lowercase letters. The controlling parameter is the third parameter, which accepts a 0 or 1 as its value. Since I can never remember whether 0 means uppercase or 1 means lower case or vice versa, I've created two named constants, UPPER and LOWER, that may be passed to the subprocedure. Here's their declaration:

     D UPPER           C                   Const(0)
     D lower           C                   Const(1)

The nice thing about using the named constant approach is that you can name the constants anything you want: UPPER, ToUpper, UPIFY, etc.

The following is a source member named CONVERT that includes the prototype for CONVERT and the named constants UPPER and LOWER.

/COPY for Prototype CONVERT

      /if NOT DEFINED(CONVERTCASE)
      /define CONVERTCASE
     D convert         PR            10I 0 extProc('CONVERT')
     D  inString                  65535A   OPTIONS(*VARSIZE)
     D  inLen                        10I 0 Const
     D  option                       10I 0 Const
     
     D UPPER           C                   Const(0)
     D LOWER           C                   Const(1)
      /endif

The named constants UPPER and LOWER are stored in the same /COPY source member as the prototype named CONVERT. Anyone who uses the CONVERT /COPY and its CONVERT subprocedure will also have access to those named constants.

The CONVERT source member is a working subprocedure prototype and requires a couple other components: A data structure and an API prototype. The full and complete source member containing the CONVERT prototype and its related components is featured below.

 

      /if NOT DEFINED(CONVERTCASE)
      /define CONVERTCASE
     D convert         PR            10I 0 extProc('CONVERT')
     D  inString                  65535A   OPTIONS(*VARSIZE)
     D  inLen                        10I 0 Const
     D  option                       10I 0 Const
     
     D UPPER           C                   Const(0)
     D LOWER           C                   Const(1)
     
      /IF NOT DEFINED(FRCB_T)
      /define FRCB_T
      ******************************************************
      **  Control structure for QlgConvertCase
      ******************************************************
     D FRCB_T          DS                  Align Qualified
     D  reqType                      10I 0 Inz(1)
     D  CCSID                        10I 0 Inz(0)
     D  case                         10I 0 Inz(LOWER)
     D  reserved                     10A   Inz(*ALLX'00')
      /endif

      /IF NOT DEFINED(QLGCONVERTCASE)
      /define QLGCONVERTCASE
      ******************************************************
      **  Prototype for QlgConvertCase
      ******************************************************
     D QlgCvtCase      PR                  extProc('QlgConvertCase')
     D  ctrlBlock                          LikeDS(FRCB_T) Const
     D  inString                  65535A   Const Options(*VARSIZE)
     D  OutString                 65535A   Options(*VARSIZE)
     D  nLength                      10I 0 Const
     D  APIErrorDS                   16A   OPTIONS(*VARSIZE)
      /endif
      /endif

To show how this can be used, I've created an example source member that implements the CONVERT subprocedure and shows how to call it using the named constants.

Implementation Source for Subprocedure CONVERT

     H OPTION(*NODEBUGIO:*SRCSTMT)
      /if DEFINED(*CRTBNDRPG)
     H DFTACTGRP(*NO)
      /ENDIF
   
      /INCLUDE RPGCODER/QCPYSRC,convert
      
     D myFRCB          DS                  LikeDS(FRCB_T)  Inz(*LIKEDS)
     D myApiErrorDS    S             16A   Inz(*ALLX'00')
     D myName          S             32A   Inz('Bob Cozzi')

     C                   MOVE      *ON           *INLR
      /FREE
            convert(myName : %len(%TrimR(myName)) : UPPER);
            convert(myName : %len(%TrimR(myName)) : lower);
            return;
      /END-FREE

     P convert         B
      /if DEFINED(*CRTRPGMOD)
     P                                     EXPORT
      /endif
     D convert         PI            10I 0
     D  inString                  65535A   OPTIONS(*VARSIZE)
     D  inLen                        10I 0 Const
     D  option                       10I 0 Const

      /free
          if (inLen = 0);
             return 0;
          endif;
          myApiErrorDS = *ALLX'00';

          myFRCB.case = option; // Convert to upper/lower case

          QlgCvtCase(myFRCB : inString : inString : inLen : myApiErrorDS);
          return  inLen;
      /end-free
     P convert         E
 

Copy this source code to your QRPGLESRC source member. If you've been following along, store it in the CONVERT source member in QRPGLESRC in the RPGCODER library; however, any library will work. Then add the prototype source member named CONVERT to the QCPYSRC source file in RPGCODER.  To compile, just use PDM option 15 (CRTBNDRPG).

I like to include the DBGVIEW(*SOURCE) and then run a test to see the results in debug mode.

A Note about the QlgConvertCase API

The QlgConvertCase is a system API that converts between upper/lower case letters using NLS (nation language support) and taking the CCSID into consideration. Other conversion methods, such as using the RPG IV %XLATE built-in function are tied to the CCSID of the program and don't often work when the program is pushed onto a System i that isn't in North America. The QlgConvertCase API is the right way to do upper/lower case conversion.


Bob Cozzi lectures on RPG IV and System i development to corporate customers and user groups all year long. He is author of RPG TnT: 101 Dynamic Tips 'n Techniques with RPG IV and hosts iWeekly, a weekly video podcast for RPG developers and managers aired live on RPGWorld.com at noon Eastern time every Friday (16:00 GMT). Bob also produces RPG World, the most popular RPG IV developer conference of the year. The next RPG World conference is planned for May 2009 in Las Vegas. Start planning now for your 2009 trip to RPG World and join Bob Cozzi, Bruce Hoffman, Greg Veal, Aaron Bartell, and more for the best RPG and System i developer training you can find. Details are posted at RPGWorld.com.

ProVIP Sponsors

ProVIP Sponsors