21
Sat, Dec
3 New Articles

The API Corner: Reducing the Use of Compile-Time Arrays

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

Retrieve textual information from message files.

 

In the December 2010 "API Corner" article, "Still Using Compile-Time Arrays?", we looked at one approach to removing compile-time arrays containing textual information from a program. The text removed was being used to display the status of an order (order canceled, order shipped, etc.) to the user of an inquiry program. In this article, we will review one way to access the text that is to be displayed by the use of a message file (*MSGF) and a procedure being exported by a message support service program (*SRVPGM).

 

Before doing that, though, several alternative approaches were proposed by readers of the first article. In the previous article, I had simply replaced references to the compile-time array with messaged IDs. That is, where the original program had coded…

 

               Status = Txt(1);                          

 

…I replaced the line with…

 

          RtvMsgTxt(Status :%size(Status) :'DSP0100'); 

 

…where RtvMsgTxt is a procedure that returns the first %size(Status) bytes of the first-level text for message ID DSP0100 to the variable Status. Rory H., in a posting located here, proposed two alternative approaches that, while maintaining the RtvMsgTxt implementation we'll be looking at shortly, could simplify the changes to the program. The first alternative is to not remove the compile-time array containing the order status text, but to instead change the contents of the array so that the message IDs are now being accessed. That is, use an approach such as this:

 

     dTxt              s              7    dim(8) ctdata     

       select;                                               

          // Provide text description of order status        

          when OrdSts = 'P';                             

               RtvMsgTxt(Status :%size(Status) :Txt(1)); 

**CTDATA Txt                                 

DSP0100                                      

 

The second proposal is to use an alternating array as shown below, replacing the select group with a lookup operation.

 

     dOrdStsVal        s              1    dim(7) ctdata        

     dOrdStsMsg        s              7    dim(7) alt(OrdStsVal)

     dX                s             10i 0                      

       X = %lookup(OrdSts :OrdStsVal);                    

       if X > 0;                                          

          RtvMsgTxt(Status :%size(Status) :OrdStsMsg(X)); 

       else;                                              

          RtvMsgTxt(Status :%size(Status) :'DSP0107');    

       endif;                                             

**CTDATA OrdStsVal                                        

PDSP0100                                                  

 

Depending on the application, you might choose to use any of the three approaches, as each has its pros and cons, with all three enabling you to remove textual information from the source of the application program.

 

Going a step further are proposals from CJeffries and JVoris, using a separate program or a SQL user-defined function, respectively, to determine the order status text. That is, using approaches such as these:

 

               RtvOrdStsTxt(Status :%size(Status) :OrdSts); 

 

or

 

               Exec SQL Select … OrdStsTxt(ord.OrdSts),…

                         into  … :Status,…

                         from  … OrdMstr ord…

 

Or possibly, in order to isolate order status information entirely from the application, simply passing an order number as in the following:

 

               RtvOrdStsTxt(Status :%size(Status) :OrderNbr); 

 

or

 

               Exec SQL Select … OrdStsTxt(ord.OrderNbr),…

                         into  … :Status,…

                         from  … OrdMstr ord…

 

These last proposals, based on RtvOrdStsTxt and OrdStsTxt, would require us to write additional programs/procedures/functions that are not provided in the current article, but these functions would not be difficult to implement and may be just the ticket for some of your application programs.

 

I would be remiss if I didn't also point out that JVoris, in the posting found here, had concerns about using a *MSGF to store the order status text. While the concerns may be quite valid for some companies, this article will continue to use *MSGFs and the APIs related to their use. This is, after all, the API Corner!

 

Having seen how we might use the RtvMsgTxt procedure in the first few examples, let's now look at the procedure itself. The heart of the procedure is the Retrieve Message (QMHRTVM) API, which is documented here.

 

The QMHRTVM API defines 13 parameters, the last three of which are optional.

 

Required Parameter Group:

1

Message information

Output

Char(*)

2

Length of message information

Input

Binary(4)

3

Format name

Input

Char(8)

4

Message identifier

Input

Char(7)

5

Qualified message file name

Input

Char(20)

6

Replacement data

Input

Char(*)

7

Length of replacement data

Input

Binary(4)

8

Replace substitution values

Input

Char(10)

9

Return format control characters

Input

Char(10)

10

Error code

I/O

Char(*)

 

Optional Parameter Group:

11

Retrieve option

Input

Char(10)

12

CCSID to convert to

Input

Binary(4)

13

CCSID of replacement data

Input

Binary(4)

 

If you've been following my columns for long, you should readily recognize the purpose of the first several parameters. The Message information parameter is the receiver variable where the API will return message description information, and the Length of message information parameter is the allocated size of the Message information parameter.

 

Format name is the format of the information to be returned. The QMHRTVM API supports four formats, RTVM0100 through RTVM0400, and we'll be using the RTVM0100 format. This format returns everything we need for the RtvMsgTxt function introduced in the previous article. And, generally, the lower the number of the format, the faster the API runs.

 

The Message identifier and Qualified message file parameters, respectively, specify the message ID to be returned and the message file containing the message ID.

 

The next three parameters can be used to replace substitution variables numbers (that is, variables such as &1 and &2 that are found in the retrieved message text) with replacement data specified by the program (for instance, the name of the department holding the order). We will not be using this capability in today's example, but the ability to directly merge program data with message text can greatly simplify the display of textual information in some situations (such as text translated to various national languages, where sentence structure can differ significantly across spoken languages).

 

The ninth parameter, Return format control characters, allows you to control whether or not formatting controls found in the message text, such as &N for new line, should be returned. In our current use of the QMHRTVM API, we will have the API remove these controls from the text returned to the application program.

 

The tenth parameter is the standard API error code.

 

The first optional parameter, Retrieve option, will not be used by our sample program but will show up in a future article. The Retrieve option parameter allows you, through special values, to access message text without knowing the message ID in advance. There are special values to return the *FIRST message ID found in a message file (in which case the Message identifier parameter is ignored) and also the *NEXT message ID found following the message identified by the Message identifier parameter.

 

Using the QMHRTVM API, prototyped below, we can write the following procedure. The module is named MSGSPT, for Message Support, and our plan is to use this module to create a *SRVPGM (also named MSGSPT).

 

h nomain                                                     

                                                            

dRtvMsgTxt        pr                                      

dMsgRcv                      65535a   options(*varsize)   

dLenMsgRcv                      10i 0 const                

dMsgID                           7a   const                                 

                                                            

dRtvMsgAPI        pr                  extpgm('QMHRTVM')     

d MsgInfo                    65535a   options(*varsize)     

d LenMsgInfo                    10i 0 const                 

d Format                         8a   const                 

d MsgID                          7a   const                 

d QualMsgF                      20a   const                 

d RplDta                     65535a   const                 

d LenRplDta                     10i 0 const                 

d RplOpt                        10a   const                 

d RtnFmtOpt                     10a   const                  

d ErrCde                              likeds(QUSEC)         

d RtvOpt                        10a   const options(*nopass)

d ToCCSID                       10i 0 const options(*nopass)

d RplDtaCCSID                   10i 0 const options(*nopass)

                                                            

 /copy qsysinc/qrpglesrc,qmhrtvm                            

 /copy qsysinc/qrpglesrc,qusec                              

                                                            

pRtvMsgTxt        b                   export                

d                 pi                                        

dMsgRcv                      65535a   options(*varsize)     

dLenMsgRcv                      10i 0 const                 

dMsgID                           7a   const                 

                                                            

dRcvVar           ds                  qualified             

d API                                 likeds(QMHM010004)    

d MsgDta                      4096a                         

                                                            

dMsgF             s             20a                         

                                                                  

 /free                                                             

                                                                  

  QUSBPrv = 0;                                                    

                                                                  

  // Get the message file that corresponds to the MessageID prefix

  select;                                                         

     when ((%subst(MsgID :1 :3) = 'CPF') or                       

           (%subst(MsgID :1 :3) = 'MCH'));                         

          MsgF = 'QCPFMSG   *LIBL';                               

     when %subst(MsgID :1 :3) = 'DSP';                            

          MsgF = 'TEXTMSGS  *LIBL     ';                          

     other;                                                        

          MsgF = 'DEFAULT   *LIBL     ';                          

  endsl;                                                          

                                                                  

  // Get the message text                                         

  RtvMsgAPI(RcvVar :%size(RcvVar) :'RTVM0100'           

            :MsgID :MsgF                                

            :' ' :0 :'*NO' :'*NO' :QUSEC);              

                                                         

  // Return the first level text                        

     %subst(MsgRcv :1 :LenMsgRcv) =                     

        %subst(RcvVar.MsgDta :1 :RcvVar.API.QMHLMRTN02);

                                                         

 /end-free                                              

                                                        

p                 e                                     

 

The module uses /copy to access the QSYSINC RPGLE include members for QMHRTVM and the API error code structure QUSEC. The QMHRTVM member provides a data structure definition for format RTVM0100, named QMHM010004. This structure defines the fixed fields Bytes returned through Length of message help available that are found in the RTVM0100 format. This structure is then used (with LIKEDS) in defining our receiver variable RcvVar. As the message text starts immediately after the Length of message help available field, the sample program also defines the subfield MsgDta following the LIKEDS reference to QMHM010004. The size of MsgDta, 4096 bytes, is quite arbitrary; it just needs to be large enough to hold the largest message text that might be returned (assuming that we want access to all of the message text).

 

I will point out that this approach—defining the MsgDta subfield immediately after the base definition of the format—is generally not the way that APIs work when returning variable-length data (and message text is certainly variable length). Most APIs provide an offset to variable-length data, and any program accessing the variable-length data must use the provided offset value if you want to avoid rude surprises after installing a new release or even applying a PTF. For instance, QMHRTVM's format RTVM0300 provides the field Offset of message at decimal offset 64 of the format. Anytime an API provides an offset value, you should use it. In the case of format RTVM0100, a rather old format dating back to V2R1.1, there is no offset, so we can safely assume that the message text will always be returned immediately following Length of message help available. This assumption, however, is not valid in the majority of cases.

 

The actual processing done by the program is quite simple. After setting the API error code structure Bytes provided field to return escape messages in the case of a failure, and determining the correct message file to use when locating the message (based on the message ID prefix in the sample program), the program calls the API to retrieve the message text associated with message ID MsgID. The program then substrings the returned value—for up to the length returned (field  QMHLMRTN02 of the RcvVar data structure), into the first parameter passed to the RtvMsgTxt procedure—for up to the length of the first parameter (LenMsgRcv), and returns to its caller. Whichever value is smaller, QMHLMRTN02 or LenMsgRcv, will determine the actual number of bytes returned to the caller of RtvMsgTxt (and in the case of QMHLMRTN02 being less than LenMsgRcv, blank pad MsgRcv to LenMsgRcv). The use of these two length fields is critical when moving data from the QMHRTVM receiver variable, RcvVar, to the caller's receiver variable (Status in the sample program calling RtvMsgTxt). Both of these parameters are prototyped as being 65535 bytes in length with options(*varsize). You do not want the procedure attempting to copy more data than is actually being returned and/or allocated.

 

To create the MSGSPT module and service program you can use the following commands:

 

CRTRPGMOD MODULE(MSGSPT) 

CRTSRVPGM SRVPGM(MSGSPT) EXPORT(*ALL)

 

To create a binding directory, MSGSPTBD, and an entry for the MSGSPT *SRVPGM, you can use these:

 

CRTBNDDIR BNDDIR(MSGSPTBD)

ADDBNDDIRE BNDDIR(MSGSPTBD) OBJ((MSGSPT))

 

Compiling the program provided in the last article, and included again here, with the following command…

 

CRTBNDRPG PGM(RTVMSGD)

h dftactgrp(*no) bnddir('MSGSPTBD')                     

                                                        

dRtvMsgTxt        pr                                     

dMsgRcv                      65535a   options(*varsize) 

dLenMsgRcv                      10i 0 const             

dMsgID                           7a   const             

                                                        

dOrdSts           s              1                      

dStatus           s             25                      

                                                        

 /free                                                  

                                                         

  // Read a record containing order status (OrdSts)     

  select;                                               

     // Provide text description of order status        

     when OrdSts = 'P';                                  

          RtvMsgTxt(Status :%size(Status) :'DSP0100');  

     when OrdSts = 'O';                                 

          RtvMsgTxt(Status :%size(Status) :'DSP0101');  

     when OrdSts = 'C';                                 

          RtvMsgTxt(Status :%size(Status) :'DSP0102');  

     when OrdSts = 'H';                                 

          RtvMsgTxt(Status :%size(Status) :'DSP0103');  

     when OrdSts = 'I';                                 

          RtvMsgTxt(Status :%size(Status) :'DSP0104');  

     when OrdSts = 'R';                                 

          RtvMsgTxt(Status :%size(Status) :'DSP0105');  

     when OrdSts = 'S';                                 

          RtvMsgTxt(Status :%size(Status) :'DSP0106');  

     other;                                             

          RtvMsgTxt(Status :%size(Status) :'DSP0107');  

  endsl;                                                

                                                        

  // Do processing, including output of  

  // order status in textual form        

                                         

  *inlr = *on;                           

  return;                                

                                         

 /end-free                               

 

…you have now externalized the human-readable text of the application program from the program itself. If tomorrow the users want a change to the text of an order status, you can simply change the message description and you're done. No searching for programs to change, no program source changes to make and test, and no compiles.

 

Next month, we'll look at a few other ways to use the QMHRTVM API. In the meantime, if you have any API questions send them to me at This email address is being protected from spambots. You need JavaScript enabled to view it.. I'll see what I can do about answering your burning questions in future columns.   

as/400, os/400, iseries, system i, i5/os, ibm i, power systems, 6.1, 7.1, V7,

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: