06
Wed, Nov
7 New Articles

The API Corner: Reading a Message File

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

Retrieve, display, and generally work with messages your way.

 

In the last article, "Reducing the Use of Compile-Time Arrays," we looked at using the Retrieve Message API QMHRTVM to randomly access the first-level message text associated with a message description. In this article, we'll look at an optional parameter of the QMHRTVM API. This parameter, Retrieve option, enables us to sequentially read messages from a message file in addition to random access to messages. We'll use this capability to write a sample program that finds all messages, within a specified message file, that contain one or more specific words (or more accurately, a sequence of letters) within the first-level text of the message.

 

The actual "find" function will be implemented in the next article due to space reasons. This article will provide a basic message description work-with program, one that we will then enhance next month. Today's program will accept a qualified message file name and then display the messages found within the message file. From this display, you can change one or more message descriptions, display the details of one or more message descriptions, and/or remove one or more message descriptions. The APIs that we will be using initially are these:

 

  • Retrieve Message (QMHRTVM)—Depending on the function being performed, the API will retrieve the first message description from a message file, the next message description following a previously read message description, or a random message description.
  • Send Program Message (QMHSNDPM)—Send an escape message in an error condition.
  • Process Commands (QCAPCMD)—Depending on the function being performed, run the CL command Change Message Description (CHGMSGD), Display Message Description (DSPMSGD), or Remove Message Description (RMVMSGD).
  • Retrieve Object Description (QUSROBJD)—Resolve qualified message file names containing special values (such as *CURLIB and *LIBL) to actual library names.

 

The provided sample program is functional though hardly complete. For instance, there is no checking for when the subfile displaying the found message descriptions is full (more than 9,999 message descriptions within a message file), a message file not found condition results in an escape message being sent rather than a recoverable error message being shown to the user, etc. The sample program is, however, sufficient to demonstrate the use of various APIs.

 

To run the Find Messages (FNDMSGS) program, we will create a command also called FNDMSGS. Using the message file TEXTMSGS first created in the article "Still Using Compile-Time Arrays?," run the following four Add Message Description commands.

 

ADDMSGD MSGID(CMD0001) MSGF(TEXTMSGS) MSG('Find Messages')

ADDMSGD MSGID(CMD0002) MSGF(TEXTMSGS) MSG('Message file') 

ADDMSGD MSGID(CMD0003) MSGF(TEXTMSGS) MSG('Library')

ADDMSGD MSGID(DSP5001) MSGF(TEXTMSGS) MSG('*** Message Removed ***')

 

The first three message descriptions are used as prompt text in creating the FNDMSGS command. The fourth message, DSP5001, is used by the FNDMSGS command processing program to indicate that the user has removed a message from the currently displayed message file.

 

This is the source for the FNDMSGS command:

 

            CMD        PROMPT(CMD0001)                             

            PARM       KWD(MSGF) TYPE(QUALNAME) PROMPT(CMD0002)   

QUALNAME:   QUAL       TYPE(*NAME) LEN(10) DFT(TEXTMSGS)                       

            QUAL       TYPE(*NAME) DFT(*LIBL) SPCVAL((*LIBL) +    

                         (*CURLIB)) PROMPT(CMD0003)               

 

To create the FNDMSGS command, you can use this command:

 

CRTCMD CMD(FNDMSGS) PGM(FNDMSGS) PMTFILE(TEXTMSGS)

 

The FNDMSGS program uses a *DSPF, named FNDMSGSDF, to provide a work-with interface to the user. The source for the *DSPF follows:

 

                                       CA03(03 'Exit')      

                                       CF05(05 'Refresh')   

           R MSG_SFL                   SFL                  

             OPTION         1   B  9  3VALUES(' ' '2' '4' '5')                       

   40                                  DSPATR(PC)           

             MSGID          7   O  9  6                     

             MSGTXT        60   O  9 14                     

           R MSG_CTL                   SFLCTL(MSG_SFL)      

                                       OVERLAY              

                                       SFLPAG(12)           

                                       SFLSIZ(13)           

   31                                  SFLDSP               

  N32                                  SFLDSPCTL            

   32                                  SFLCLR               

   35                                  SFLEND               

  N35                                  PAGEDOWN(41)         

             SFL_DSPPAG     4S 0H      SFLRCDNBR                 

                                   1 26'Work with Found Messages'

                                       COLOR(WHT)                

                                   3  2'Message file:'           

             MSG_FILE      10   B  3 18                          

                                   3 33'Library:'                

             MSG_LIB       10   B  3 44                          

                                   5  2'Type options, press Enter.'

                                       COLOR(BLU)                

                                   6  4'2=Change'                

                                       COLOR(BLU)                

                                   6 15'4=Delete'                

                                       COLOR(BLU)                

                                   6 26'5=Display message'       

                                       COLOR(BLU)                

                                   8  2'Opt'                     

                                       COLOR(WHT)                

                                   8  6'MsgID'          

                                       COLOR(WHT)       

                                   8 14'Message text'   

                                       COLOR(WHT)       

           R MSG_KEYS                                   

                                  23  2'F3=Exit'        

                                       COLOR(BLU)       

                                  23 15'F5=Refresh'     

                                       COLOR(BLU)               

 

To create the *DSPF, use this command:

 

CRTDSPF FILE(FNDMSGSDF) SRCFILE(QDDSSRC)

 

The command processing program, FNDMSGS, is shown below. Note that the referenced binding directory, MSGSPTBD, was created in the previous article "Reducing the Use of Compile-Time Arrays."

 

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

                                                                  

fFndMsgsDF cf   e             workstn sfile(Msg_Sfl :MsgSflRRN1)  

                                                                   

dFndMsgs          pr                                              

d QualMsgF_in                   20a   const                       

                                                                  

dFndMsgs          pi                                              

d QualMsgF_in                   20a   const                       

                                                                  

dGetNewMsgF       pr                                               

                                                                  

dGetNxtMsgs       pr                                              

d NbrMsgsToGet                   5u 0 const                       

                                                                   

dGetCurMsg        pr                                              

d MsgID                          7a   const                   

                                                              

dRtvMsgTxt        pr                                           

dMsgRcv                      65535a   options(*varsize)       

dLenMsgRcv                      10i 0 const                   

dMsgID                           7a   const                   

                                                               

dRunCmd           pr              n                           

d Cmd                          512a   const                   

                                                              

dSndEscape        pr                                           

                                                              

dSetUp            pr                                          

                                                              

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)    

                                                                

dSndMsg           pr                  extpgm('QSYS/QMHSNDPM')   

d MsgID                          7    const                     

d QualMsgF                      20    const                     

d MsgDta                     65535    const options(*varsize)   

d LenMsgDta                     10i 0 const                      

d MsgType                       10    const                     

d CallStackEntry             65535    const options(*varsize)   

d CallStackCntr                 10i 0 const                     

d MsgKey                         4                               

d QUSEC                               likeds(QUSEC)             

d LenCSE                        10i 0 const options(*nopass)    

d CSEQual                       20    const options(*nopass)    

d DSPWaitTime                   10i 0 const options(*nopass)    

d CSEType                       10    const options(*nopass)    

d CCSID                         10i 0 const options(*nopass)    

                                                                

dProcessCmd       pr                  extpgm('QCAPCMD')         

d SourceCmd                  65535a   const options(*varsize)   

d LenSrcCmd                     10i 0 const                     

d CtlBlk                     65535a   const options(*varsize)   

d LenCtlBlk                     10i 0 const                     

d Format                         8a   const                     

d ChgCmd                         1a   options(*varsize)             

d LenAvlChgCmd                  10i 0 const                         

d LenRtnChgCmd                  10i 0                               

d QUSEC                               likeds(QUSEC)                 

                                                                    

dRtvObjD          pr                  extpgm('QUSROBJD')             

d ObjInfo                    65535a   options(*varsize)             

d LenObjInfo                    10i 0 const                         

d Format                         8a   const                         

d QualObjN                      20a   const                         

d ObjType                       10a   const                         

d QUSEC                               likeds(QUSEC) options(*nopass)

d ASPCtl                     65535a   const options(*nopass)        

                                                                     

 /copy qsysinc/qrpglesrc,qmhrtvm                                    

 /copy qsysinc/qrpglesrc,qcapcmd                                    

 /copy qsysinc/qrpglesrc,qusrobjd                                    

 /copy qsysinc/qrpglesrc,qusec                                

                                                              

dRcvVar           ds                  qualified               

d API                                 likeds(QMHM030000)      

d MsgDta                      4096a                           

                                                              

dObjInfo          ds                  qualified               

d API                                 likeds(QUSD0100)        

                                                              

dQualMsgF         ds                                          

d Msg_File                      10                            

d Msg_Lib                       10                             

                                                              

dErrCde           ds                  qualified               

d Common                              likeds(QUSEC)           

d MsgTxt                       512                             

                                                              

dMsgSflRRN1       s              4  0                    

dTopSflRRN1       s              4  0                    

dSizeOfSFLPage    s              5u 0 inz(12)            

dTopMsgID         s              7a                      

dRun              s               n                      

dUserAction       s               n                      

dPrvMsg_File      s                   like(Msg_File)     

dPrvMsg_Lib       s                   like(Msg_Lib)      

                                                         

dNotUsedChr       s              1                       

dNotUsedInt       s             10i 0                    

                                                          

 /free                                                   

                                                         

  SetUp();                                               

                                                         

  dow (not *in03);                                       

      select;                                        

         when ((Msg_File <> PrvMsg_File) or          

               (Msg_Lib <> PrvMsg_Lib));             

              GetNewMsgF();                           

                                                     

         when *in05;                                 

              GetNewMsgF();                          

                                                     

         when *in41;                                 

              GetNxtMsgs(SizeOfSFLPage);             

                                                     

         when TopSflRRN1 > 0;                        

              UserAction = *off;                      

              readc Msg_Sfl;                         

              dow (not %eof(FndMsgsDF));             

                  select;                            

                     when Option = '2';              

                          GetCurMsg(MsgID);                         

                          Run = RunCmd('?CHGMSGD ?*MSGID(' + MsgID +  

                                       ') ?*MSGF(' + %trimr(Msg_Lib) +

                                       '/' + %trimr(Msg_File) +     

                                       ') MSG(''' +                 

                                       %subst(RcvVar                

                                         :(RcvVar.API.QMHOMRtn + 1) 

                                         :RcvVar.API.QMHLMRtn04) +  

                                       ''')');                      

                          if Run;                                   

                             GetCurMsg(MsgID);                      

                             MsgTxt = %subst(RcvVar                 

                                         :(RcvVar.API.QMHOMRtn + 1) 

                                         :RcvVar.API.QMHLMRtn04);   

                          endif;                                    

                          UserAction = *on;                         

                                                                    

                     when Option = '4';                              

                          Run = RunCmd('RMVMSGD MSGID(' + MsgID +    

                                       ') MSGF(' + %trimr(Msg_Lib) + 

                                       '/' + %trimr(Msg_File) + ')');

                          if Run;                                    

                             RtvMsgTxt(MsgTxt :%size(MsgTxt)         

                                       :'DSP5001');                  

                          endif;                                     

                          UserAction = *on;                           

                                                                     

                     when Option = '5';                              

                          Run = RunCmd('DSPMSGD RANGE(' + MsgID +    

                                       ') MSGF(' + %trimr(Msg_Lib) + 

                                       '/' + %trimr(Msg_File) + ')');

                          UserAction = *on;                          

                  endsl;                                             

                                                                      

                  if *in03;               

                     leave;               

                  endif;                  

                                          

                  Option = *blanks;       

                  update Msg_Sfl;         

                  readc Msg_Sfl;          

              enddo;                      

                                          

              if (not UserAction);        

                 leave;                   

              endif;                      

                                          

         other;                           

              // Nothing left to do       

      endsl;                              

                                          

      write Msg_Keys;                             

      *in31 = (TopSflRRN1 > 0);                   

      exfmt Msg_Ctl;                              

  enddo;                                          

                                                   

  *inlr = *on;                                    

  return;                                         

                                                  

 /end-free                                        

                                                  

pGetNxtMsgs       b                               

dGetNxtMsgs       pi                              

d NbrMsgsToGet                   5u 0 const       

                                                   

dmyX              s              5u 0             

                                                  

 /free                                            

                                                            

  if TopMsgID <> RcvVar.API.QMHMID;                         

     // Need to refresh the first message to retrieve       

     GetCurMsg(TopMsgID);                                   

  endif;                                                    

                                                             

  *in40 = *on;                                              

  MsgSflRRN1 = TopSflRRN1;                                  

                                                            

  for myX = 1 to NbrMsgsToGet;                               

      MsgID = RcvVar.API.QMHMID;                            

      MsgTxt = %subst(RcvVar :(RcvVar.API.QMHOMRtn + 1)     

                      :RcvVar.API.QMHLMRtn04);              

                                                             

      MsgSflRRN1 += 1;                                      

      write Msg_Sfl;                                        

      *in40 = *off;                                         

                                                                

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

                :MsgID :QualMsgF                                

                :' ' :0 :'*NO' :'*NO' :QUSEC                    

                :'*NEXT' :0 :0);                                 

                                                                

      if RcvVar.API.QMHBAVL09 = 0;                              

         // End of message descriptions if bytes avail = 0      

         *in35 = *on;                                            

         leave;                                                 

      else;                                                     

         TopMsgID = RcvVar.API.QMHMID;                          

      endif;                                                     

                                                                

  endfor;                                                       

                                                                

  TopSflRRN1 = MsgSflRRN1;                                       

  Sfl_DspPag = MsgSflRRN1;             

                                       

 /end-free                             

                                       

pGetNxtMsgs       e                    

 *                                      

pGetNewMsgF       b                    

dGetNewMsgF       pi                   

                                       

 /free                                 

                                       

  *in32 = *on;                          

  write Msg_Ctl;                       

  *in32 = *off;                        

  MsgSflRRN1 = 0;                      

  TopSflRRN1 = 0;                      

  *in35 = *off;                        

                                                   

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

            :' ' :QualMsgF                        

            :' ' :0 :'*NO' :'*NO' :ErrCde         

            :'*FIRST' :0 :0);                     

                                                   

  select;                                         

     when ErrCde.Common.QUSBAvl > 0;              

          SndEscape();                            

                                                  

     when RcvVar.API.QMHBAVL09 = 0;               

          // No messages in message file          

          *in35 = *on;                            

                                                  

     other;                                       

          TopMsgID = RcvVar.API.QMHMID;           

          GetNxtMsgs(SizeOfSFLPage);              

  endsl;                                                 

                                                         

  if %subst(Msg_Lib :1 :1) = '*';                        

     // Resolve special values like *LIBL and *CURLIB    

     RtvObjD(ObjInfo :%size(ObjInfo) :'OBJD0100'         

             :QualMsgF :'*MSGF' :QUSEC);                 

     Msg_Lib = ObjInfo.API.QUSRL01;                      

  endif;                                                  

                                                         

  PrvMsg_File = Msg_File;                                

  PrvMsg_Lib = Msg_Lib;                                  

                                                          

 /end-free                                               

                                                         

pGetNewMsgF       e                                      

 *                                                       

pGetCurMsg        b                                      

dGetCurMsg        pi                                  

d MsgID                          7a   const           

                                                      

 /free                                                 

                                                      

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

            :MsgID :QualMsgF                          

            :' ' :0 :'*NO' :'*NO' :QUSEC              

            :'*MSGID' :0 :0);                         

                                                      

 /end-free                                            

                                                      

pGetCurMsg        e                                    

 *                                                    

pRunCmd           b                                   

dRunCmd           pi              n                   

d Cmd                          512a   const           

                                                          

 /free                                                   

                                                         

  ProcessCmd(Cmd :%len(%trimr(Cmd))                      

             :QCAP0100 :%size(QCAP0100) :'CPOP0100'      

             :NotUsedChr :0 :NotUsedInt :ErrCde);        

                                                         

  if ErrCde.Common.QUSBAvl > 0;                          

     select;                                              

        when ErrCde.Common.QUSEI = 'CPF6801';            

             if %subst(ErrCde.MsgTxt :1 :3) = 'F3 ';     

                *in03 = *on;                             

                return *off;                             

             else;                                       

                return *off;                             

             endif;                                      

        other;                                           

             SndEscape();                             

     endsl;                                          

  else;                                              

     return *on;                                     

  endif;                                             

                                                      

 /end-free                                           

                                                     

pRunCmd           e                                  

 *                                                   

pSetUp            b                                  

dSetUp            pi                                 

                                                     

 /free                                               

                                                      

  QUSBPrv = 0;                                       

  ErrCde.Common.QUSBPrv = %size(ErrCde);             

  QCAP0100 = *loval;              // init API ctls to nulls    

  QCACMDPT = 0;                   // Run command                

  QCABCSDH = '0';                 // Ignore DBCS               

  QCAPA = '2';                    // Prompt if controls found 

  QCACMDSS = '0';                 // Use i OS syntax           

                                                                

  QualMsgF = QualMsgF_in;                                      

                                                               

  GetNewMsgF();                                                

                                                                

  write Msg_Keys;                                              

  *in31 = (TopSflRRN1 > 0);                                    

  exfmt Msg_Ctl;                                               

                                                                

/end-free                                                     

                                                               

pSetUp            e                                             

 *                                                               

pSndEscape        b                                             

dSndEscape        pi                                            

                                                                

dLenMsgDta        s             10i 0                            

dMsgKey           s              4a                             

                                                                

 /free                                                          

                                                                 

  if ErrCde.Common.QUSBAVL < 16;                                

     LenMsgDta = 0;                                             

  else;                                                         

     LenMsgDta = ErrCde.Common.QUSBAVL - %size(ErrCde.Common);  

  endif;                                                        

                                                                

  SndMsg(ErrCde.Common.QUSEI :'QCPFMSG   *LIBL'                 

         :ErrCde.MsgTxt :LenMsgDta                    

         :'*ESCAPE' :'*PGMBDY' :1 :MsgKey :QUSEC);    

                                                      

 /end-free                                            

                                                       

pSndEscape        e                                   

 

The program can be created using the following command:

 

CRTBNDRPG PGM(FNDMSGS)

 

To run the program, you can enter a command such as this:

 

FNDMSGS

 

This command, which defaults to the qualified message file name *LIBL/TEXTMSGS per the command definition source, allows you to work with the message descriptions found in the specified message file.

 

The program, upon entry, runs the SetUp procedure. The SetUp procedure does the following:

 

  1. Initializes two instances of the API error code structure. One instance, QUSEC, has the Bytes provided field set to 0, indicating that any errors encountered are to be returned as escape messages. The second instance, ErrCde, has the Bytes provided field set to a non-0 value, indicating that any errors encountered are to be returned within the ErrCde structure. By convention, I use the QUSEC instance when I do not intend to provide error recovery and ErrCde when some error handling is being provided by the application.
  2. Initializes the Options control block of the Process Commands API (QCAPCMD) to run commands with optional prompting.
  3. Sets the data structure QualMsgF to the value of the FNDMSGS command MSGF keyword parameter.
  4. Runs the procedure GetNewMsgF.
  5. Displays up to the first 12 messages (the subfile page size) found in the message file identified by the QualMsgF data structure (these messages are loaded by way of the previously run GetNewMsgF procedure).
  6. Returns to its caller.

 

Before seeing what happens when SetUp returns to the mainline, let's review the processing of the procedures called by SetUp. The GetNewMsgF procedure is run whenever a new message file is to be used. This could be when the program is initially called or when the user changes the message file name and/or library name on the display record format MSG_CTL. The GetNewMsgF procedure does the following:

 

  1. Clears the subfile and initializes variables MsgSflRRN1 and TopSflRRN1 to 0. MsgSflRRN1 is used to identify the subfile record number currently being processed (the SFILE keyword of the *DSPF file specification); TopSflRRN1 is used to keep track of the current size of the subfile.
  2. Retrieves the first message description found in the message file identified by the QualMsgF data structure using the ErrCde data structure.
  3. Enters into a SELECT group. If an error is encountered retrieving the first message description, GetNewMsgF resends the escape message to the user. This is where, if desired, you might inform the user of a problem using a message subfile. If no error is encountered, GetNewMsgF checks the Bytes available variable of the QMHRTVM returned data structure for a value of 0. This indicates that, although the message file was found, there are no message descriptions defined for the message file. In this case, indicator 35 (SFLEND) is set on. If no error is encountered and a non-zero Bytes available variable is received from QMHRTVM, GetNewMsgF sets variable TopMsgID to the value of the message returned and runs the procedure GetNxtMsgs. The TopMsgID variable is used to identify the message ID, which should start the next subfile page when adding subfile entries.
  4. If the library name of the qualified message file starts with an asterisk, the program calls the Retrieve Object Description API to determine the name of the actual library used.
  5. Sets the variables PrvMsg_File and PrvMsg_Lib to reflect the resolved name of the message file being used.
  6. Returns to its caller.

 

The GetNxtMsgs procedure performs these actions:

 

  1. Determines if the message ID identified by the TopMsgID variable is still the message found in the QMHRTVM receiver variable. When called by the GetNewMsgF procedure, this will always be the case. When called by other procedures, the contents of the QMHRTVM receiver variable may or may not reflect the next message to be loaded to the subfile. That is, the QMHRTVM receiver variable may reflect (as you will see later) the last message displayed, changed, or removed by the user. If the QMHRTVM receiver variable does not contain the message description for TopMsgID, GetNxtMsgs runs the GetCurMsg procedure to re-access the message description for the message identified by TopMsgID.
  2. Sets on indicator 40, which is used to position the cursor to the first entry of the subfile page being loaded.
  3. Sets the current subfile relative record number (MsgSflRRN1) to the last written subfile relative record number (TopSflRRN1).
  4. Enters into a FOR loop, which will load the next page of the subfile with message descriptions from the user-specified message file. Within the FOR loop, the procedure moves the message ID and first-level text of the message description currently found in the QMHRTVM receiver variable to the subfile variables MsgID and MsgTxt. It then increments the current subfile relative record number by 1, writes the subfile record, sets off indicator 40, and attempts to retrieve the next message description found in the message file identified by the QualMsgF data structure, using QMHRTVM and the QUSEC error code data structure. If there is no "next" message description (Bytes available of the QMHRTVM receiver variable is 0), then indicator 35 (SFLEND) is set on and the FOR loop is exited. If there is a next message description, then TopMsgID is set to the message ID of the retrieved message and the FOR loop is run again. Upon exiting the FOR loop, TopSflRRN1 is set to reflect the relative record number of the last subfile record written and the subfile page to be displayed is set to be the page containing the last written subfile record. Assuming that the entire subfile page was written (that is, 12 message descriptions were successfully retrieved), the last message description retrieved is not written to the subfile. Rather, it is used as a resumption point for the next call to the GetNxtMsgs and to enable an accurate setting of SFLEND.
  5. Returns to its caller.

 

Having reviewed what happened when the SetUp procedure runs, SetUp now returns to the mainline of the FNDMSGS program. The mainline logic is a DO WHILE loop exited with command key 3. Within the DOW is a SELECT group used to determine what processing should be done.

 

If the user changes the message file name, the message file library name, or both, then the GetNewMsgF procedure is used to clear the current subfile and load a new first subfile page using the newly specified qualified message file name.

                                        

If command key 5 (indicator 5) is used, then the GetNewMsgF procedure is used to clear the current subfile and reload a new first subfile page using the current qualified message file name.

 

If PageDown (indicator 41) is used, then the GetNxtMsgs procedure is used to load the next subfile page of the current qualified message file name.

 

If none of the previous three conditions occurred, and there are message descriptions loaded in the subfile (TopSflRRN1 > 0), the program then sets indicator UserAction to indicate that no user action has (yet) been detected and enters a DOW to determine if the user has selected to change, remove, or display any of the message descriptions currently loaded in the subfile.                                                    

 

If the user selected option 2 (change), the GetCurMsg procedure is used to re-access the message description for the message identified by the MsgID variable of the read subfile record, and the RunCmd procedure is used to run the CHGMSGD command. The CHGMSGD command is prompted due to the leading question mark (?), rendering the user unable to change the MSGID or MSGF keyword values (the "?*" prompt controls). The first-level text of the message to be changed is included in the prompt, which I find a lot more useful than the default value of *SAME. The RunCmd procedure returns an indicator setting, which is stored in variable Run. If variable Run is set to on after the RunCmd procedure returns, then the program again uses the GetCurMsg procedure, this time to get the (presumably) changed first-level text of the message. This text will later be used to update the current subfile record to reflect the changed message text. As the user has performed some action (even if the user then canceled the prompted request), indicator UserAction is set to on.

 

The RunCmd procedure uses the Process Command (QCAPCMD) API, discussed in previous columns starting with "Running CL Commands from RPG," to run the command specified by its caller. After running the command, RunCmd checks to see if an error was returned and, if there was, if the error message is CPF6801 (Command prompting ended when user pressed &1). This error can be returned if the CL command (such as the CHGMSGD command) is prompted and the user then uses F3 or F12 to end the command prompt without actually running the command. If F3 was used, RunCmd sets on indicator 3 and returns an "off" indicator with the RETURN operation. If F12 was used, RunCmd simply returns an "off" indicator with the RETURN operation. If any error was returned by the API other than CPF6801, RunCmd resends the escape message using the SndEscape procedure. If no error was returned by the API, then RunCmd returns an "on" indicator with the RETURN operation.

 

If the user selected option 4 (remove) the RunCmd procedure is used to run the RMVMSGD command (without prompting). If the command runs successfully, then the text of message DSP5001 ("*** Message Removed ***"), added earlier in this column, is retrieved using the RtvMsgTxt procedure defined in the previous article "Reducing the Use of Compile-Time Arrays." This text will be used to later update the current subfile record text. As with the change option, indicator UserAction is also set on to indicate that the user has performed a function.                    

                                                                     

If the user selected option 5 (display), the RunCmd procedure is used to run the DSPMSGD command, and again the UserAction indicator is set to on.

 

After running the selected option, a check is made for indicator 3 being on. This is done as the user could have used F3 to exit from the command prompt for CHGMSGD. If indicator 3 is on, the DOW processing of the subfile is exited. If indicator 3 is off, the current subfile record is updated by setting the option value to blanks and writing the current text associated with the message (previously set by the processing associated with either option 2 or option 4). The next changed subfile record is then read and the DOW rerun.

 

After all changed subfile records have been processed, a check is made to determine if any user action was detected while processing the subfile. If not (variable UserAction is still off), then the outer DOW loop (conditioned by indicator 3) is exited and the program ends. Otherwise, the program redisplays the subfile and waits for the next user request.

 

That's our basic work-with message descriptions application. Next month, we'll add the ability to find and display only those messages where one or more words are found in the first-level text of the message description. And needless to say, we'll be using an API to help us in this task.

 

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,

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: