23
Sat, Nov
1 New Articles

The CL Corner: Retrieving Test Case Information

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

Are you taking advantage of printer files and subfiles in your CL programs?

 

In the two previous columns, "A Much More Flexible SNDESCAPE Program" and "Controlling the CL Testing Environment," we saw how to use PowerCL: CL for Files commands to write and update records in a database file, respectively. In today's column, we'll look at how to work with printer files and subfiles, from a CL program, by implementing the command Display Test Cases (DSPTSTCASE).

 

The command definition for DSPTSTCASE is shown below:

 

    CMD        PROMPT('Display Test Cases')                

    PARM       KWD(CMD) TYPE(*NAME) LEN(10) MIN(1) +       

                 PROMPT('Command to test')                 

    PARM       KWD(OUTPUT) TYPE(*CHAR) LEN(10) RSTD(*YES) +

                 DFT(*) VALUES(* *PRINT) PROMPT('Output')

 

The DSPTSTCASE command defines one required and one optional parameter. The required parameter, keyword CMD for command, is the name of the command that we want to see the test cases for. The optional parameter, keyword OUTPUT, specifies where the output of the DSPTSTCASE command should be sent. The default value, an asterisk (*), indicates that the test cases should be displayed interactively. The special value *PRINT allows the test cases to be printed.

 

You can create the DSPTSTCASE command into library VINING using the following command:

 

CRTCMD CMD(VINING/DSPTSTCASE) PGM(VINING/DSPTSTCPP)

 

To support the interactive display of test cases, the DSPTSTCASE command uses display file DSPTSTDSPF. The source for this display file is shown below:

 

                R SFLTSTS                   SFL                      

      * Subfile listing testcases for command                        

                  TESTPGM   R        O  7  3REFFLD(TESTPGM ACTCMDTSTS)

                  TESTMSG   R        O  7 18REFFLD(TESTMSG ACTCMDTSTS)

                  TESTUSR   R        O  7 30REFFLD(TESTUSR ACTCMDTSTS)

                                                                     

                R SFLCTLTSTS                SFLCTL(SFLTSTS)          

                                            CA03(03)                 

      * Control record for subfile listing testcases                 

                                            SFLSIZ(11) SFLPAG(10)    

                                            OVERLAY ERASEINP(*ALL)   

        31                                  SFLDSPCTL         

        31                                  SFLEND(*MORE)            

       N31                                  SFLCLR                   

        32                                  SFLDSP

                                        3 21'List of Testcases for + 

                                            command:'                

                  TESTCMD   R        B    +1REFFLD(TESTCMD ACTCMDTSTS)

                                            COLOR(WHT)               

                                        6  3'Program   '             

                                            COLOR(WHT)               

                                        6 18'Message   '             

                                            COLOR(WHT)               

                                        6 30'Tester    '             

                                            COLOR(WHT)               

                                                                      

                R KEY                                                

      * Command key prompt                                           

                                       22  2'F3=Exit'                

The DSPTSTDSPF display file defines the subfile record format SFLTSTS, the subfile control record format SFLCTLTSTS, and the record format KEY, which is used to display the active command keys. While not fancy, DSPTSTDSPF is sufficient to demonstrate the basics of subfile use from CL. The field &TESTCMD of record format SFLCTLTSTS is defined as both input and output so that the user can select to view the test cases for other commands without having to exit and re-run the DSPTSTCASE command. Assuming that you have the database file ACTCMDTSTS, previously created in the article "A Much More Flexible SNDESCAPE Program," in your library list, you can create this display file into library VINING using the following command:

 

CRTDSPF FILE(VINING/DSPTSTDSPF) SRCFILE(QDDSSRC)

 

To support the printed output of test cases, the DSPTSTCASE command uses the printer file DSPTSTPRTF. The source for the printer file is shown below:

 

                R HEADING                   SPACEB(2)                 

                                          26'List of Testcases for +  

                                            command:'                 

                  TESTCMD   R             +1REFFLD(TESTCMD ACTCMDTSTS)

                                            SPACEA(3)                 

                                           3'Program   '              

                                          18'Message   '              

                                          30'Tester    '              

                                            SPACEA(1)                  

                                                                      

                R DETAIL                    SPACEA(1)                 

                  TESTPGM   R              3REFFLD(TESTPGM ACTCMDTSTS)

                  TESTMSG   R             18REFFLD(TESTMSG ACTCMDTSTS)

                  TESTUSR   R             30REFFLD(TESTUSR ACTCMDTSTS)

                                                                      

                R ENDING                    SPACEB(1)                 

                                           2'End of Listing'

 

As with the DSPTSTDSPF display file, the DSPTSTPRTF printer file is very simple but sufficient to demonstrate the use of external printer files from a CL program. There are three record formats defined: HEADING for the report titles; DETAIL, which will be used once for each test case; and ENDING, which indicates that the end of the report has been reached. You can use program-described printer files with CLF, but I find using externally described files to be much more productive than defining and maintaining report lines within the application program itself. You can create the printer file DSPTSTPRTF into library VINING using the following command:

 

CRTPRTF FILE(VINING/DSPTSTPRTF) SRCFILE(QDDSSRC)

 

The command processing program (CPP) for DSPTSTCASE, DSPTSTCPP, is shown below:

 

    Pgm       Parm(&TestCmd &Output)                         

    Dcl       Var(&Output) Type(*Char) Len(10)               

                                                              

    DclFCLF   FileID(ActCmdTsts)                             

    DclFCLF   FileID(DspTstDSPF)                             

    DclFCLF   FileID(DspTstPRTF)                             

                                                              

    Dcl       Var(&Count)  Type(*Dec)                        

    Dcl       Var(&EOF)    Type(*Lgl)                        

                                                             

(A) OpnFCLF   ActCmdTsts AccMth(*Key)                        

    Select                                                   

      When    Cond(&Output *EQ '*PRINT') Then(Do)            

(B)           OpnFCLF DspTstPRTF Usage(*Output)              

              WrtRcdCLF RcdFmt(Heading)                      

              PosDBFCLF ActCmdTsts Type(*Key) +              

                        KeyRel(*EQ) KeyList(&TestCmd)           

              ReadRcdCLF ActCmdTsts Type(*Key) +                

                         KeyRel(*NxtEQ) KeyList(&TestCmd) +     

                           EOF(&EOF)                            

              DoWhile Cond(*Not &EOF)                           

                WrtRcdCLF RcdFmt(Detail)                        

                ReadRcdCLF ActCmdTsts Type(*Key) +              

                           KeyRel(*NxtEQ) KeyList(&TestCmd) +   

                           EOF(&EOF)                            

                EndDo                                           

              WrtRcdCLF RcdFmt(Ending)                          

              CloFCLF DspTstPRTF                                

              EndDo                                             

                                                                

      When    Cond(&Output *EQ '*') Then(Do)                    

(C)           OpnFCLF DspTstDSPF Usage(*Both)                   

              DoWhile Cond(*Not &IN03)                          

                ChgVar Var(&IN31) Value('0')                         

                WrtRcdCLF RcdFmt(SFLCtlTsts)                        

                ChgVar Var(&Count) Value(0)                         

                PosDBFCLF ActCmdTsts Type(*Key) +                   

                          KeyRel(*EQ) KeyList(&TestCmd)             

                ReadRcdCLF ActCmdTsts Type(*Key) +                  

                           KeyRel(*NxtEQ) KeyList(&TestCmd) +       

                           EOF(&EOF)                                

                DoWhile Cond(*Not &EOF)                             

                  ChgVar Var(&Count) Value(&Count + 1)              

                  WrtRRNCLF RcdFmt(SFLTsts) RRN(&Count)             

                  ReadRcdCLF ActCmdTsts Type(*Key) +                 

                             KeyRel(*NxtEQ) KeyList(&TestCmd) +     

                             EOF(&EOF)                              

                  EndDo                                             

                WrtRcdCLF RcdFmt(Key)                                

                If Cond(&Count *GT 0) Then( +         

                   ChgVar Var(&IN32) Value('1'))      

                Else Cmd(ChgVar Var(&IN32) Value('0'))

                ChgVar Var(&IN31) Value('1')                         

                WrtReadCLF RcdFmt(SFLCtlTsts)                    

                EndDo                                            

              CloFCLF DspTstDSPF                                 

              EndDo                                               

                                                                 

      Otherwise Cmd(SndPgmMsg Msg('Output value of' *BCat +       

                          &Output *BCat 'is not supported.') +   

                          ToPgmQ(*Ext) MsgType(*Inq))                         

      EndSelect                                                  

                                                                 

    CloFCLF   ActCmdTsts                                          

                                                                 

    EndPgm                                                       

 

After opening the ACTCMDTSTS database file for keyed input at (A), DSPTSTCPP enters a SELECT group to determine where the output is to be sent.

 

In the case of printed output, (B) shows the logic required to create the report. DSPTSTCPP opens the printer file DSPTSTPRTF for output processing, writes the report headings using the Write Record using CLF (WRTRCDCLF) command with record format HEADING, and then randomly positions to the first ACTCMDTSTS record with a key equal to the CMD value specified when running the DSPTSTCASE command using the Position Database File using CLF (POSDBFCLF) command. The POSDBFCLF command, not seen in previous articles, is documented here. Having positioned to the first record (if one exists) with a matching command name, DSPTSTCPP reads the next record from the current file position if the record key value is equal to the requested command name. If no record with the command name is found, then logical variable &EOF is set to true.

 

As long as logical variable &EOF is false, DSPTSTCPP remains in a DOWHILE loop, writing the DETAIL record format showing the test case just read and attempting to read the next record of ACTCMDTSTS with a key equal to the requested command name. When all records for the command have been processed, CL variable &EOF is true, the DOWHILE loop is exited, the ENDING record format is written, and the DSPTSTPRTF printer file is closed.

 

In the case of displayed output, (C) shows the logic required to display a subfile containing the test cases for a given command. DSPTSTCPP opens the display file DSPTSTDSPF for both input and output processing and enters into a DOWHILE loop exited when the user presses command attention key 3. Within the DOWHILE loop, the subfile is cleared by writing record format SFLCTLTSTS with logical variable &IN31 set to false, the count (&Count) of test cases found for the command is set to 0, and the first record within the file with a key equal to the requested command name is read using the same approach as used in the printer file scenario (POSDBFCLF and READRCDCLF). As long as records with a matching key value are found (logical variable &EOF is false), DSPTSTCPP adds one to &Count, writes a subfile record containing the test case information using &Count as the subfile relative record number, and attempts to read the next record of ACTCMDTSTS with a key equal to the requested command name. When all records for the command have been processed, the DOWHILE loop is exited, record format KEY is written to let the user know command key 3 can be used to exit, logical variable &IN32 is set to true (used to display the subfile) if any subfile records have been written, and the subfile control record format is written and then read using the Write/Read Record using CLF (WRTREADCLF) command. WRTREADCLF, not seen previously, is documented here. From the subfile control record format, the user can type in a new command name and press Enter, in which case the DOWHILE loop is re-run as described above. If the user presses command attention key 3, the DOWHILE loop is exited and the DSPTSTDSPF display file is closed.

 

Quite a bit more could be provided within the DOWHILE processing shown at (C). For instance, loading the subfile one page at a time and providing generic command name support (where one approach is demonstrated in chapter 9, Using Display Files, of the CLF Programmer's Guide for CL Developers), but DSPTSTCPP should give you the general feel for what is required in supporting subfiles from your CL application program.

 

After having created the report or displaying all of the test cases of interest to the user, DSPTSTCPP closes the ACTCMDTSTS database file and returns.

 

To create DSPTSTCPP into library VINING, you can use the following command:

 

CRTBNDCLF PGM(VINING/DSPTSTCPP)

As you may have used the CLF precompiler due to previous test case-related articles, it's possible you will find that your trial period for CLF has expired. If that is the case, feel free to send me a note at This email address is being protected from spambots. You need JavaScript enabled to view it. (with your system serial number), and I can provide you with an additional month of precompiler access.

 

To display all test cases involving the DONOTHING command, you could enter the following command:

 

DSPTSTCASE CMD(DONOTHING)

 

As with the previous articles, here are the equivalent programs using RPG-like CL commands and the base run-time support. The source lines that have been changed are highlighted.

 

DSPTSTCPP Using RPG-like Commands

 

    Pgm       Parm(&TestCmd &Output)                       

    Dcl       Var(&Output) Type(*Char) Len(10)             

                                                           

    File      ActCmdTsts                                    

    File      DspTstDSPF                                   

    File      DspTstPRTF                                   

                                                           

    Dcl       Var(&Count)  Type(*Dec)                       

    Dcl       Var(&EOF)    Type(*Lgl)                      

                                                           

    Open      ActCmdTsts AccMth(*Key)                      

    Select                                                 

      When    Cond(&Output *EQ '*PRINT') Then(Do)          

              Open DspTstPRTF Usage(*Output)               

              Write RcdFmt(Heading)                        

              SetLL &TestCmd ActCmdTsts                    

              ReadE &TestCmd ActCmdTsts EOF(&EOF)          

              DoWhile Cond(*Not &EOF)                      

                Write RcdFmt(Detail)                       

                ReadE &TestCmd ActCmdTsts EOF(&EOF)        

                EndDo                                       

              Write RcdFmt(Ending)                         

              Close DspTstPRTF                             

              EndDo                                        

                                                            

      When    Cond(&Output *EQ '*') Then(Do)               

              Open DspTstDSPF Usage(*Both)                 

              DoWhile Cond(*Not &IN03)                     

                ChgVar Var(&IN31) Value('0')               

                Write RcdFmt(SFLCtlTsts)                   

                ChgVar Var(&Count) Value(0)                

                SetLL &TestCmd ActCmdTsts                  

                ReadE &TestCmd ActCmdTsts EOF(&EOF)         

                DoWhile Cond(*Not &EOF)                       

                  ChgVar Var(&Count) Value(&Count + 1)        

                  Write RcdFmt(SFLTsts) RRN(&Count)           

                  ReadE &TestCmd ActCmdTsts EOF(&EOF)          

                  EndDo                                       

                Write RcdFmt(Key)                             

                If Cond(&Count *GT 0) Then( +                 

                   ChgVar Var(&IN32) Value('1'))               

                Else Cmd(ChgVar Var(&IN32) Value('0'))        

                ChgVar Var(&IN31) Value('1')                  

                ExFmt RcdFmt(SFLCtlTsts)                      

                EndDo                                          

              Close DspTstDSPF                                

              EndDo                                           

                                                              

      Otherwise Cmd(SndPgmMsg Msg('Output value of' *BCat +    

                          &Output *BCat 'is not supported.') +

                          ToPgmQ(*Ext) MsgType(*Inq))  

      EndSelect                           

                                          

    Close   ActCmdTsts                     

                                          

    EndPgm                                

 

The RPG-like CLF commands you have not seen before are SETLL, READE, and EXFMT. The previous program can be created into library VINING with the following command:

 

CRTBNDCLF PGM(VINING/DSPTSTCPP)

 

DSPTSTCPP Using Base Run-time Support

 

    Pgm       Parm(&TestCmd &Output)                             

    Dcl       Var(&TestCmd)    Type(*Char) Len(10)               

    Dcl       Var(&Output)     Type(*Char) Len(10)               

                                                                  

/*  DclFCLF   FileID(ActCmdTsts)                               */

    Dcl       Var(&CmdTstRcd)  Type(*Char) Len(61)               

    Dcl       Var(&DB_TestUsr) Type(*Char) Len(10) +             

                Stg(*Defined)  DefVar(&CmdTstRcd 11)             

    Dcl       Var(&DB_TestPgm) Type(*Char) Len(10) +             

                Stg(*Defined)  DefVar(&CmdTstRcd 21)             

    Dcl       Var(&DB_TestMsg) Type(*Char) Len(7) +              

                Stg(*Defined)  DefVar(&CmdTstRcd 31)             

                                                                 

/*  DclFCLF   FileID(DspTstDSPF)                               */

    Dcl       Var(&SFLTsts)    Type(*Char) Len(27)               

    Dcl       Var(&DS_TestPgm) Type(*Char) Len(10) +             

                Stg(*Defined) DefVar(&SFLTsts 1)           

    Dcl       Var(&DS_TestMsg) Type(*Char) Len(7) +        

                Stg(*Defined) DefVar(&SFLTsts 11)          

    Dcl       Var(&DS_TestUsr) Type(*Char) Len(10) +       

                Stg(*Defined) DefVar(&SFLTsts 18)          

                                                           

    Dcl       Var(&SFLCtlTsts) Type(*Char) Len(13)         

    Dcl       Var(&IN03)       Type(*Lgl)  Len(1) +        

                Stg(*Defined) DefVar(&SFLCtlTsts 1)        

    Dcl       Var(&DS_Cmd_I)   Type(*Char) Len(10) +       

                Stg(*Defined) DefVar(&SFLCtlTsts 2)        

                                                            

    Dcl       Var(&IN31)       Type(*Lgl)  Len(1) +        

                Stg(*Defined) DefVar(&SFLCtlTsts 1)        

    Dcl       Var(&IN32)       Type(*Lgl)  Len(1) +        

                Stg(*Defined) DefVar(&SFLCtlTsts 2)        

    Dcl       Var(&DS_Cmd_O)   Type(*Char) Len(10) +       

                Stg(*Defined) DefVar(&SFLCtlTsts 3)              

                                                                 

    Dcl       Var(&Key)        Type(*Char) Len(1)                

                                                                 

/*  DclFCLF   FileID(DspTstPRTF)                               */

    Dcl       Var(&Heading)    Type(*Char) Len(10)               

    Dcl       Var(&PT_TestCmd) Type(*Char) Len(10) +             

                Stg(*Defined) DefVar(&Heading 1)                 

                                                                 

    Dcl       Var(&Detail)     Type(*Char) Len(27)               

    Dcl       Var(&PT_TestPgm) Type(*Char) Len(10) +             

                Stg(*Defined) DefVar(&Detail 1)                  

    Dcl       Var(&PT_TestMsg) Type(*Char) Len(7) +              

                Stg(*Defined) DefVar(&Detail 11)                 

    Dcl       Var(&PT_TestUsr) Type(*Char) Len(10) +             

                Stg(*Defined) DefVar(&Detail 18)                 

                                                                 

    Dcl       Var(&Ending)     Type(*Char) Len(1)                 

                                                                 

    Dcl       Var(&Count)  Type(*Dec)                            

    Dcl       Var(&EOF)    Type(*Lgl)                            

                                                                  

    OpnFCLF   ActCmdTsts AccMth(*Key) LvlChk(*No)                

    Select                                                       

      When    Cond(&Output *EQ '*PRINT') Then(Do)                

              OpnFCLF DspTstPRTF Usage(*Output) LvlChk(*No)      

              WrtRcdCLF DspTstPRTF RcdFmt(Heading) +             

                        RcdBuf(&Heading)                         

              PosDBFCLF ActCmdTsts Type(*Key) +                  

                        KeyRel(*EQ) KeyList(&TestCmd)            

              ReadRcdCLF ActCmdTsts Type(*Key) +                 

                         KeyRel(*NxtEQ) KeyList(&TestCmd) +      

                         EOF(&EOF) RcdBuf(&CmdTstRcd)            

              DoWhile Cond(*Not &EOF)                            

                ChgVar Var(&PT_TestPgm) Value(&DB_TestPgm)        

                ChgVar Var(&PT_TestMsg) Value(&DB_TestMsg)        

                ChgVar Var(&PT_TestUsr) Value(&DB_TestUsr)        

                WrtRcdCLF DspTstPRTF RcdFmt(Detail) +             

                        RcdBuf(&Detail)                           

                ReadRcdCLF ActCmdTsts Type(*Key) +                

                           KeyRel(*NxtEQ) KeyList(&TestCmd) +     

                           EOF(&EOF) RcdBuf(&CmdTstRcd)           

                EndDo                                             

              WrtRcdCLF DspTstPRTF RcdFmt(Ending) +               

                        RcdBuf(&Ending)                           

              CloFCLF DspTstPRTF                                  

              EndDo                                               

                                                                  

      When    Cond(&Output *EQ '*') Then(Do)                      

              OpnFCLF DspTstDSPF Usage(*Both) LvlChk(*No)         

              ChgVar Var(&IN03) Value('0')

              ChgVar Var(&IN32) Value('0')                   

              DoWhile Cond(*Not &IN03)                         

                ChgVar Var(&IN31) Value('0')                   

                WrtRcdCLF DspTstDSPF RcdFmt(SFLCtlTsts) +      

                          RcdBuf(&SFLCtlTsts)                  

                ChgVar Var(&Count) Value(0)                    

                PosDBFCLF ActCmdTsts Type(*Key) +              

                          KeyRel(*EQ) KeyList(&TestCmd)        

                ReadRcdCLF ActCmdTsts Type(*Key) +             

                           KeyRel(*NxtEQ) KeyList(&TestCmd) +  

                           EOF(&EOF) RcdBuf(&CmdTstRcd)        

                DoWhile Cond(*Not &EOF)                        

                  ChgVar Var(&Count) Value(&Count + 1)         

                  ChgVar Var(&DS_TestPgm) Value(&DB_TestPgm)   

                  ChgVar Var(&DS_TestMsg) Value(&DB_TestMsg)   

                  ChgVar Var(&DS_TestUsr) Value(&DB_TestUsr)   

                  WrtRRNCLF DspTstDSPF RcdFmt(SFLTsts) +       

                            RRN(&Count) RcdBuf(&SFLTsts)       

                  ReadRcdCLF ActCmdTsts Type(*Key) +           

                             KeyRel(*NxtEQ) +                  

                             KeyList(&TestCmd) +               

                             EOF(&EOF) RcdBuf(&CmdTstRcd)      

                  EndDo                                        

                WrtRcdCLF DspTstDSPF RcdFmt(Key) +             

                          RcdBuf(&Key)                         

                If Cond(&Count *GT 0) Then( +                  

                   ChgVar Var(&IN32) Value('1'))               

                Else Cmd(ChgVar Var(&IN32) Value('0'))         

                ChgVar Var(&IN31) Value('1')                    

                ChgVar Var(&DS_Cmd_O) Value(&TestCmd)          

                WrtReadCLF DspTstDSPF RcdFmt(SFLCtlTsts) +     

                           RcdBuf(&SFLCtlTsts)                 

                ChgVar Var(&TestCmd) Value(&DS_Cmd_I)          

                EndDo                                          

              CloFCLF DspTstDSPF                                 

              EndDo                                              

                                                                  

      Otherwise Cmd(SndPgmMsg Msg('Output value of' *BCat +      

                          &Output *BCat 'is not supported.') +   

                          ToPgmQ(*Ext) MsgType(*Inq))            

      EndSelect                                                   

                                                                 

    CloFCLF   ActCmdTsts                                         

                                                                 

    EndPgm                                                        

 

There are many, many possible ways to write DSPTSTCPP using CLF base run-time support. Some of the approaches can take much less source code than shown above; some can require more.

 

Quite a bit of the new code shown above is related to the file definitions for ACTCMDTSTS, DSPTSTPRTF, and DSPTSTDSPF. In previous articles, we simply defined ACTCMDTSTS as one *CHAR field (&CmdTstRcd) with a length of 61, which matched the record length of the ACTCMDTSTS database file. We then used the %sst CL built-in function to extract the fields of interest. This same technique could be used in the current article for all three files, but I believe the %sst approach would have a lasting, and quite negative, impact on productivity when later maintaining the program. The reason for this is that later in the program we must move (CHGVAR) the fields TESTPGM, TESTMSG, and TESTUSR from the database fields to the printer (or display) file fields for printing or display, a requirement you should be familiar with if you have ever used multiple file support with IBM-provided CL commands, RPG qualified data structure I/O, COBOL, or C in the past (but which does not exist when using the CLF precompiler). Using the %sst approach, you would need to code (and, more importantly, maintain) the following source when moving the fields TESTPGM, TESTMSG, and TESTUSR from ACTCMDTSTS to the DSPTSTDSPF subfile SFLTSTS:

 

    ChgVar Var(%sst(&SFLTsts 1 10)) Value(%sst(&CmdTstRcd 21 10))    

    ChgVar Var(%sst(&SFLTsts 11 7)) Value(%sst(&CmdTstRcd 31 7))     

    ChgVar Var(%sst(&SFLTsts 18 10)) Value(%sst(&CmdTstRcd 11 10))    

 

By using the V5R4 STG(*DEFINED) capabilities of CL, you can instead move these fields with the following source:

 

    ChgVar Var(&DS_TestPgm) Value(&DB_TestPgm)

    ChgVar Var(&DS_TestMsg) Value(&DB_TestMsg)

    ChgVar Var(&DS_TestUsr) Value(&DB_TestUsr)

 

I much prefer the second example when reviewing a program.

 

In the example base run-time program, I hand-coded the record definitions, prefixing each field name with DB_ if a database file field, PT_ if a printer file field, and DS_ if a display file field. This hand-coding can be avoided by using the Run-Time Generation Tools of CLF (option 2). In this case, the Generate File Field Definition (GENFFDCLF) command, documented here, can be used and the output of the command included into the above source. If you do decide to code your own file/record/field definitions, you will find the IBM-provided Display File Field Description (DSPFFD) command to be a good way to determine the correct DCL DEFVAR position values to use.

 

After declaring the database, printer, and display record formats and fields, DSPTSTCPP opens the ACTCMDTSTS file with LVLCHK(*NO) as was done in the previous articles (though note that the GENFFDCLF command mentioned in the previous paragraph does provide level-check information in the generated source so that you can utilize file-level checking without the need for the CLF precompiler). And as demonstrated in earlier articles, the base run-time version of DSPTSTCPP needs to add file ID and record buffer parameters to many of the CLF commands.

 

In the case of OUTPUT(*PRINT), DSPTSTCPP does not require much else in the way of change other than using CHGVAR to move the fields &DB_TestPgm, &DB_TestMsg, and &DB_TestUsr to &PT_TestPgm, &PT_TestMsg, and &PT_TestUsr, respectively, in preparing to output the test case detailed print line.

 

OUTPUT(*) however does require some additional changes beyond simply moving the DB_ fields to the WS_ fields in preparing to output the test case detailed subfile record. Because the logical variables &IN03, &IN31, and &IN32 are passed to workstation data management and these indicators are defined within the *CHAR record buffer, they are initialized to blanks rather than true ('1') or false ('0') values. As blanks do not necessarily compare as equal to true or false, DSPTSTCPP must ensure that these logical variables are correctly initialized before using them. Remove, for example, this statement from the outer DO logic involving OUTPUT(*) support:

 

    ChgVar Var(&IN03) Value('0')

 

You will find that the inner DoWhile Cond(*Not &IN03)test is always false (at least on my systems) on entry to the DOWHILE, meaning it never runs!

 

Another change that is required involves the display file field TESTCMD. TESTCMD is defined as both an input and an output field, so DSPTSTCPP must provide an output value when writing to record format SFLCTLTSTS and accept a new input value when reading record format SFLCTLTSTS (so that the user can change the command name). Due to different indicators being passed in the SFLCTLTSTS record buffer for input and output operations (&IN03 is used for input, &IN31 and &IN32 for output), this means that the TESTCMD display file field must be declared at two different locations within the record buffer: &DS_Cmd_I at position 2 of &SFLCtlTsts on input, &DS_Cmd_O at position 3 of &SFLCtlTsts for output. This in turn means updating the TESTCMD display file field prior to writing record format SFLCTLTSTS and updating &TestCmd after reading record format SFLCTLTSTS. This change is shown below:

 

   ChgVar Var(&DS_Cmd_O) Value(&TestCmd)     

   WrtReadCLF DspTstDSPF RcdFmt(SFLCtlTsts) +

              RcdBuf(&SFLCtlTsts)            

   ChgVar Var(&TestCmd) Value(&DS_Cmd_I)     

 

This particular change can be avoided if the display file DSPTSTDSPF is created using a separate indicator area (the DDS function INDARA), but as this article is already long enough without having to introduce a change to the display file, I elected not to show this alternative. If you are interested, an example using a separate indicator area for display file support can be found in the CLF Run-time Generation Tools Guide. You do not need to use the Run-time Generation Tools to use INDARA, but the example happens to be in that manual.

 

To create the base run-time example program into library VINING, you can use the command:

 

CRTBNDCL PGM(VINING/DSPTSTCPP)

 

In this article, you have seen how to use printer files and subfiles from your CL program. In the next article, we'll expand on DSPTSTCPP and look at how to implement a "Work with" function to further support test cases.

More CL Questions?

Wondering how to accomplish a function in CL? Send your CL-related questions to me at This email address is being protected from spambots. You need JavaScript enabled to view it..

Bruce Vining

Bruce Vining is president and co-founder of Bruce Vining Services, LLC, a firm providing contract programming and consulting services to the System i community. He began his career in 1979 as an IBM Systems Engineer in St. Louis, Missouri, and then transferred to Rochester, Minnesota, in 1985, where he continues to reside. From 1992 until leaving IBM in 2007, Bruce was a member of the System Design Control Group responsible for OS/400 and i5/OS areas such as System APIs, Globalization, and Software Serviceability. He is also the designer of Control Language for Files (CLF).A frequent speaker and writer, Bruce can be reached at This email address is being protected from spambots. You need JavaScript enabled to view it.. 


MC Press books written by Bruce Vining available now on the MC Press Bookstore.

IBM System i APIs at Work IBM System i APIs at Work
Leverage the power of APIs with this definitive resource.
List Price $89.95

Now On Sale

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: