21
Sat, Dec
3 New Articles

The CL Corner: Letting the User Know What's Right and Wrong

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

Use a message subfile to return error information to the user.

 

Anyone who has been following this column for a while probably knows that I believe in using messages whenever possible. Messages are a wonderful way of keeping textual information out of my code, thereby allowing me to reword some text without having to change an application program, a command definition, and so on. One place where I find that many developers (CL and otherwise) are underutilizing messages is in the area of display file error-reporting.

 

Many display files are still being coded using the ERRMSG DDS keyword and the associated (hard-coded) message text for reporting an input validation error to a user. While there's nothing wrong with ERRMSG, today we will look at how you can use a message subfile to return error information to the user. Using a message subfile, you can decide tomorrow to clarify error-related textual information and simply change a message description—with no need to even recompile the display file, let alone the program, in order to start using the new text. We'll also take a quick look at how to use status messages to let the user know that the program has been running for a while and everything is OK.

 

In our sample application, we'll prompt the user for various inputs, validate the input provided, and then either return error-related information to the user or run the request. The inputs the user will provide are a starting and ending year for a report, the type of report, whether the report should be of a summary or detail nature, and whether the report should be run in batch or interactively. This last choice, running the report in batch or interactively, is only being done to show how to send status messages, not to suggest that I would actually allow a user to run batch-type reports in an interactive session.

 

The source for the display file is shown below and, assuming the source is stored in member CLRPTDSPF (CL Report Display File) of source file QDDSSRC, can be created using the CRTDSPF command CRTDSPF FILE(CLRPTDSPF) SRCFILE(QDDSSRC).

 

 

A          R CRITERIA                  OVERLAY                 

A                                      CA03(03 'Exit')         

A                                      CF10(10 'Run immediate')

A                                  1  2SYSNAME                 

A                                  1 70DATE EDTCDE(Y)           

A                                  2  2USER                    

A                                  2 34'Sample Screen'         

A                                      COLOR(WHT)              

A                                  2 70TIME                     

A                                  4  2'Start year . . . .'    

A            STRYEAR        4Y 0B  4 22EDTCDE(4)               

A                                  5  2'Ending year  . . .'    

A            ENDYEAR        4Y 0B  5 22EDTCDE(4)                

A                                  7  2'Report type  . . .'    

A            REPORT         1Y 0B  7 22EDTCDE(4)               

A                                  8  5'1 - Report 1'          

A                                  9  5'2 - Report 2'          

A                                 10  5'3 - Report X'          

A                                 12  2'Report detail  . .'    

A            RPT_DTL        1A  B 12 22                        

A                                 12 24'Y/N'                   

A                                 23  2'F3=Exit'               

A                                 23 15'F10=Run immediately'   

A************************************************************* 

A          R MSGSFL                    SFL                     

A                                      SFLMSGRCD(24)           

A            MSGKEY                    SFLMSGKEY               

A            PGM                       SFLPGMQ                 

A************************************************************* 

A          R MSGSFLCTL                 SFLCTL(MSGSFL)          

A                                      SFLINZ                  

A                                      SFLPAG(1)               

A                                      SFLSIZ(2)               

A                                      SFLDSP SFLDSPCTL      

A N99                                  SFLEND                

A            PGM                       SFLPGMQ               

 

There are three record formats defined within CLRPTDSPF. Record format CRITERIA is the format used to prompt the user for the report. Record formats MSGSFL and MSGSFLCTL are used for controlling how messages are shown to the user.

 

For demonstration purposes, we will be creating several messages using the Add Message Description (ADDMSGD) command. As shown below, the messages will be added to message file USERMSGF in library VINING. The error message IDs will be prefixed by ERR, status message IDs by STS, and informational message IDs by INF. Feel free to use any library, message file, and prefix you would like; there's nothing magic about any of these values. If you do not currently have a message file handy, you can use the Create Message File (CRTMSGF) command as with CRTMSGF MSGF(VINING/USERMSGF). With this introduction, create the following message descriptions:

 

ADDMSGD MSGID(ERR0101) MSGF(VINING/USERMSGF)

MSG('Start date must be within the last four years')

 

ADDMSGD MSGID(ERR0102) MSGF(VINING/USERMSGF)

MSG('End date cannot be before start date')

 

ADDMSGD MSGID(ERR0103) MSGF(VINING/USERMSGF)

MSG('A valid report type must be specified')

 

ADDMSGD MSGID(ERR0104) MSGF(VINING/USERMSGF)

MSG('Report detail must be Y or N')

 

ADDMSGD MSGID(ERR0105) MSGF(VINING/USERMSGF)

MSG('Report detail Y is only valid for report type 2') 

 

ADDMSGD MSGID(STS0101) MSGF(VINING/USERMSGF)

MSG('Report is being generated, this may take a while.')

 

ADDMSGD MSGID(INF0101) MSGF(VINING/USERMSGF)

MSG('Report has been completed')

 

ADDMSGD MSGID(INF0102) MSGF(VINING/USERMSGF)

MSG('Report has been submitted')

 

Having created the display file CLRPTDSPF and the message descriptions shown above, you can now run the CL program below, which validates user input, reports any user input errors that are found, and (in theory) runs a report. Assuming the following CL source is in member CLRPT (CL Report) of source file QCLSRC, you can create the program into library VINING using the command CRTBNDCL PGM(VINING/CLRPT).

 

Pgm                                                           

DclF       File(CLRptDspF)                                   

                                                             

Dcl        Var(&ErrorFnd)   Type(*Lgl)                       

Dcl        Var(&MinYear)    Type(*Dec)  Len(4 0)             

Dcl        Var(&DateTime)   Type(*Char) Len(20)              

                                                             

ChgVar     Var(&Pgm) Value('CLRPT')                          

RtvJobA    DateTime(&DateTime)                                

ChgVar     Var(&StrYear) Value(%sst(&DateTime 1 4))          

ChgVar     Var(&EndYear) Value(&StrYear)                     

ChgVar     Var(&Rpt_Dtl) Value('N')                          

ChgVar     Var(&MinYear) Value(&StrYear - 4)                  

 

                                                             

RmvMsg     Clear(*All)                                       

                                                             

DoWhile    Cond(&IN03 *NE '1')                                 

           SndF RcdFmt(MsgSFLCtl)                             

           SndRcvF RcdFmt(Criteria)                           

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

           RmvMsg Clear(*All)                                  

                                                              

           If Cond(&IN03 = '1') Then(Leave)                   

                                                              

           If Cond(&StrYear *LT &MinYear) Then(Do)             

              SndPgmMsg MsgID(ERR0101) MsgF(UserMsgF) +       

                        ToPgmQ(*Same)                         

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

              EndDo                                            

                                                              

           If Cond(&EndYear *LT &StrYear) Then(Do)            

              SndPgmMsg MsgID(ERR0102) MsgF(UserMsgF) +       

                        ToPgmQ(*Same)                          

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

              EndDo                                                

                                                                   

           If Cond((&Report *NE 1) *And (&Report *NE 2) *And +     

                   (&Report *NE 3)) Then(Do)                       

              SndPgmMsg MsgID(ERR0103) MsgF(UserMsgF) +            

                        ToPgmQ(*Same)                              

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

              EndDo                                                

                                                                   

           If Cond((&Rpt_Dtl *NE 'Y') *And +                        

                   (&Rpt_Dtl *NE 'N')) Then(Do)                    

              SndPgmMsg MsgID(ERR0104) MsgF(UserMsgF) +            

                        ToPgmQ(*Same)                              

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

              EndDo                                                

                                                                   

           If Cond((&Report *NE 2) *And +                       

                   (&Rpt_Dtl *EQ 'Y')) Then(Do)                 

              SndPgmMsg MsgID(ERR0105) MsgF(UserMsgF) +         

                        ToPgmQ(*Same)                           

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

              EndDo                                              

                                                                

           Select                                               

              When Cond(&ErrorFnd) Then(Iterate)                

                                                                 

              When Cond(&IN10 = '1') Then(Do)                   

                   SndPgmMSg MsgID(STS0101) MsgF(UserMsgF) +    

                             ToPgmQ(*Ext) MsgType(*Status)      

                   DlyJob Dly(5)                                

                   SndPgmMsg MsgID(INF0101) MsgF(UserMsgF) +    

                             ToPgmQ(*Same)                      

                   EndDo                                         

                                                                 

              Otherwise Cmd(Do)                                  

                   SbmJob Cmd(Signoff)                           

                   RmvMsg Clear(*All)                             

                   SndPgmMsg MsgID(INF0102) MsgF(UserMsgF) +     

                             ToPgmQ(*Same)                       

                   EndDo                                         

           EndSelect                                              

EndDo                                                            

RmvMsg Clear(*All)                                               

                                                                 

EndPgm 

 

For now ignoring the message subfile support, the program declares display file CLRPTDSPF and a few CL variables related to user-input validation. The variables declared are &ErrorFnd (a logical variable which, if on ('1'), indicates that one or more validation checks failed), &MinYear (a 4-digit decimal variable with zero decimal positions representing the minimum year for which a report can be run), and &DateTime (a 20-byte character variable representing the current date and time in YYYYMMDDHHMMSSmmmmmm format).

 

The program then does the following:

 

1. Sets initial default values for various user inputs using the current year for the report start year (&StrYear), the current year for the report end year (&EndYear), and 'N' for report detail (&Rpt_Dtl)

 

2. Calculates the earliest year the report can be run for (&MinYear) by subtracting four years from the current year

 

3. Enters into a DOWHILE loop where the program:

  a. Prompts the user for report criteria by sending and receiving record format CRITERIA

  b. Sets the &ErrorFnd logical variable to off ('0') indicating that no user validation errors have been found

  c. Checks if command key 3 was used, in which case the program returns

  d. Validates the user inputs. If any errors are found, the program redisplays record format CRITERIA with all validation errors listed in a message subfile located on line 24 of the workstation. If no errors are found and command key 10 was used, the program runs the report interactively while displaying a status message on line 24 letting the user know the report is being run (and to be patient). If no errors are found and command key 10 was not used, the program submits the report to run in batch and displays a message on line 24 letting the user know the report has been submitted.

  e. Re-runs the DOWHILE loop, allowing the user to run another report

 

Validate the User Inputs

The remainder of this month's column will focus on the preceding "Validate the user inputs" step. Next month, we'll look at the nitty-gritty details of constructing the message subfile. And note that two of the steps shown above—"Sets the &ErrorFnd logical variable to off" and "Checks if command key 3 was used"—can be reversed. It's simply my preference to clear error-related variables immediately and unconditionally.

 

The error validation is quite straightforward, with each validation check being done in a manner such as this:

 

If Cond(&StrYear *LT &MinYear) Then(Do)        

   SndPgmMsg MsgID(ERR0101) MsgF(UserMsgF) +   

             ToPgmQ(*Same)                      

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

   EndDo                                       

 

For instance, if the requested report starting year (&StrYear) is less than the report's earliest supported year (&MinYear), then the CL code snippet shown above will…

 

  • send an appropriate message (such as ERR0101) to the program queue of the program running the Send Program Message (SNDPGMMSG) command—in other words, itself. The type of message being sent will be, due to the defaulted message type (MSGTYPE) parameter of the SNDPGMMSG command, informational. As we will see in a future article, other message types can be used.
  • set the &ErrorFnd variable to on, indicating that a validation error has been encountered.

 

After performing all validation checks, the program checks to see if any error was encountered (condition &ErrorFnd is true) and, if so, writes the message subfile associated with the current program (using record format MSGSFLCTL) and then writes and waits for further input using the CRITERIA record format.

 

As mentioned previously, next month we'll look at the DDS details of implementing the message subfile (record formats MSGSFL and MSGSFLCTL). As this article does, however, provide the DDS source for the subfile record formats, feel free to "skip ahead" and do your own study of message subfiles. Independent study certainly never hurts.

 

Before ending this column, though, I want to point out that the CLRPT program also sends messages in non-error situations. To mimic the running of a report interactively, CLRPT sends a status message (STS0101 – 'Report is being generated, this may take a while.') and then delays for five seconds (this delay giving you a chance to see the message). Sending a status message, and having the message appear on line 24 of the display, is as simple as using the SNDPGMMSG command, specifying a MSGTYPE of *STATUS, and sending the message to the external message queue: TOPGMQ(*EXT). This part of the sample program has no dependency on whether or not a message subfile is being used.

 

Message subfiles can also be used for more than just error conditions. When the report is run interactively (using command key 10) and has "completed" or when the report has been submitted for running in batch, CLRPT will also send a message (INF0101 and INF0102, respectively). These messages, unlike the STS0101 status message, are displayed to the user using message subfile support, letting the user know what has happened with the latest request, but they clearly do not represent an error situation.

 

And last but not least, you may notice that the fields in error are not highlighted to the user (as ERRMSG would have done). This can be easily remedied by adding appropriate DSPATR(RI) conditioning to the display file and CLRPT program. To highlight the start year being prior to &MinYear, as an example, you could add the following:

 

  • To the CLRPTDSPF display file

 

A            STRYEAR        4Y 0B  4 22EDTCDE(4)             

A  51                                  DSPATR(RI)  <- new line             

 

  • To the CLRPT setting off of &ErrorFnd

 

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

ChgVar Var(&IN51) Value('0')   <- new line     

 

  • To the CLRPT error validation

 

If Cond(&StrYear *LT &MinYear) Then(Do)         

   SndPgmMsg MsgID(ERR0101) MsgF(UserMsgF) +    

             ToPgmQ(*Same)                      

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

   ChgVar Var(&IN51) Value('1')  <- new line       

   EndDo                                        

 

With these simple changes, you get the flexibility of messages and the preciseness of highlighting the fields that are in error.

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.. I'll try to answer your burning questions in future columns.

                                                                                      

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: