Midrange News for the IBM i Community

Posted by: Bob Cozzi
Rogue Programmer
Cozzi Productions, Inc.
RPG Report 2012
has no ratings.
Published: 05 Jun 2012
Revised: 30 Sep 2014 - 2920 days ago
Last viewed on: 23 Sep 2022 (4419 views) 

Using IBM i? Need to create Excel, CSV, HTML, JSON, PDF, SPOOL reports? Learn more about the fastest and least expensive tool for the job: SQL iQuery.

RPG Report - 05 June 2012 Published by: Bob Cozzi on 05 Jun 2012 view comments

© Robert Cozzi, Jr. All rights reserved. Reproduction/Redistribution prohibited.
A midrangeNews.com Publication

A Joblog Message Command

Is It Time to Abandon the 30-Year Old SNDPGMMSG Command?

Lately, when I'm working on legacy CL I tend to write a lot of messages to the joblog. Not only does this help keep the end-user informed of the progress the job stream is making, it helps me know where/when a failure occurred. Of course I've been using SNDPGMMSG for years/decades to do this, but the contemporary method I like to use, is to send 2 messages. One as MSGTYPE(*INFO) and a 2nd as MSGTYPE(*STATUS). That way I have both the end-user notification and the programmer-oriented (i.e., joblog) notification recorded.

But send 2 messages, while easy, just makes the CL messy. In fact, a recent v7.1 CL bug that prevented CPF9898 style messages from being sent correctly, led me to try another approach. Basically this bug is generated when you send a program message using CPF9898 or CPF9897 with the MSGDTA (message data) parameter filled in with the message text. Something like the following:


 The bug (again on v7.1) is that the first 2 characters of "Hello World!" are truncated and additional characters are added to the end. To me this meant that whomever maintains SNDPGMMSG was trying to include the VARY(*YES) keyword on the MSGDTA parameter definition, but failed. So rather than try to get IBM to fix it, I found a work around. If you  move the text into a CL variable and then pass the CL variable as the MSGDTA parameter, the command works as it always has--correctly. This led further to my conclusion that it may not be a Command Definition issue, but an actual bug in the CL parser, compiler, but who knows and who cares, I found the work-around!

Then I thought, we'll actually this makes it more correct for me when sending messages. Why? Because I tend to send on *INFO message and then immediately send a *STATUS message.  This (A) records the step in the joblog and (B) notifies the end-user what's going on. By moving the text into a CL variable, I simply issue the SNDPGMMSG command twice, once for the *INFO and once for *STATUS with TOPGMQ(*EXT) specified.

Another Forehead Slapping Moment for Cozzi

As I was coding the SNDPGMMSG command, I said to myself "It sure would be nice to have the COZTOOLS' JOBLOG subprocedure in CL." Slap! Okay Bob, write it!

It occurred to me that in COZTOOLS I would easily create a JOBLOG CL command that sends program messages. Then I'd only have to specify the so called impromptu text and not bother with those other parameters. And then I thought, why not allow it to send multiple messages with one JOBLOG command? That is, why not allow it to send an *INFO message and then a *STATUS message or whatever? That was the easy part as it turned out. The hard part was selecting a name for the command.

Obviously "JOBLOG" made sense to me, but I doubt it would make sense to anyone else. After all a "JOBLOG" command to Bizarro Bob Cozzi would think it was creating a joblog or something like that.

In my application code I want to write multiple identical messages to the joblog. I want to, for example, send MSG('Hello World!') as a *STATUS message and a *COMP message. To the name SNDMULTMSG (Send Multiple Messages) came to mind. Sure it isn't perfect, but it is good enough. Here's the definition for each SNDMULTMSG parameter:

SNDMULTMSG (Write Message Multiple Times to Joblog)

The SNDMULTMSG command sends an impromptu message to the joblog via the SNDPGMMSG command once for each entry on the MSGTYPE parameter. It correctly handles message types requiring special handling, such as *STATUS and *RQS message types. The purpose is to allow the programmer to send the same messages as a *STATUS message and a *COMP, *INFO or *DIAG message.

MSG - Up to 512 characters of message text to be sent to *PRV or *EXT (based on the message type).

MSGTYPE - *INFO Specify any of the message types supported by the SNDPGMMSG MSGTYPE parameter. Multiple message types are supported and when specified, the SNDMULTMSG command processing program will send one message for each type specified on this parameter. Up to 8 entries are permitted for this parameter. The valid message types are:

  • *INFO
  • *INQ
  • *RQS
  • *COMP
  • *DIAG

If *RQS is specified, the text specified on the MSG parameter is logged similar to a CL command. For example if you specify MSG('DSPLIBL') MSGTYPE(*RQS) the SNDMULTMSG command will properly send/receive that message as a *RQS message allowing the end-user to use F9 to retrieve the text as if it were a CL command entered on Command Entry.

When *STATUS is specified, the message text is sent to the *EXT program queue, which as you know, displays the message on the interactive screen. For batch jobs, the system swallows status messages automatically.

All other message types are sent to TOPGMQ(*PRV) meaning they are sent to the *PRV of the SNDMULTMSG command processing program, which is similar to you specify TOPGMQ(*SAME) on the SNDPGMMSG command in CL.


To send a simple "Hello World!' message:

SNDMULTMSG MSG('Hello World!')

To send 'Starting Monthly Processing...' as both a status message and an informational message:

SNDMULTMSG MSG('Starting Monthly Processing...') MSGTYPE(*INFO  *STATUS)

To record a command to the joblog for later retrieval via the F9 key:


Source for SNDMULTMSG Command

The source for SNDMULTMSG is relatively simple; two parameters, the first being the message text and has a limit of 512 characters; it includes the VARY(*YES) keyword so that it passes the message text length to the command processing program (CPP). The second parameter is MSGTYPE and allows up to 8 message types. The text specified on the MSG parameter is sent via the SNDPGMMSG command once for each MSGTYPE specified.

SNDMULTMSG: CMD        PROMPT('COZZI-Write Msg Multiple Times to Joblog')       
            PARM       KWD(MSG) TYPE(*CHAR) LEN(512) MIN(1) +        
                         EXPR(*YES) VARY(*YES) INLPMTLEN(80) +       
                         PROMPT('Message text')                      
            PARM       KWD(MSGTYPE) TYPE(*CHAR) LEN(10) RSTD(*YES) + 
                         DFT(*INFO) SPCVAL((*INFO) (*INQ) +    
                         (*RQS) (*COMP) (*DIAG) (*NOTIFY) +  
                         (*ESCAPE) (*STATUS))  MAX(8) +     
                         EXPR(*YES) PROMPT('Message type')

The Command Processing Program (CPP) source code for the SNDMULTMSG command is currently written in CL and is available to COZTOOLS Enterprise Edition licensees. The object-only version is available free in the runtime version available at www.cozTools.com


The CL source code is reproduced below for your information. Please note that it is © copyrighted material.

             /* (c) COPYRIGHT 2012 by R. Cozzi Jr.               */
             /*     All rights reserved.                         */
             /*     Reproduction in full or part is prohibited.  */
             DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(514)
             DCL        VAR(&MSGLEN) TYPE(*INT) STG(*DEFINED) LEN(2) +
             DCL        VAR(&MSGTEXT) TYPE(*CHAR) STG(*DEFINED) +
                          LEN(512) DEFVAR(&MSGDTA 3)
             DCL        VAR(&MSGTYPE) TYPE(*CHAR) LEN(82)
             DCL        VAR(&TYPECNT) TYPE(*INT) STG(*DEFINED) +
                          LEN(2) DEFVAR(&MSGTYPE)
             DCL        VAR(&TYPE) TYPE(*CHAR) LEN(10)
             DCL        VAR(&PGMQ) TYPE(*CHAR) LEN(10)
             DCL        VAR(&MSGKEY) TYPE(*CHAR) LEN(4)
             DCL        VAR(&COUNT) TYPE(*INT) LEN(2)
             DCL        VAR(&START) TYPE(*INT) LEN(2)
             MONMSG     MSGID(CPF0000)

             DOFOR      VAR(&COUNT) FROM(1) TO(&TYPECNT)
                CHGVAR     VAR(&START) VALUE(3+((&COUNT-1) * 10))
                CHGVAR     VAR(&TYPE) VALUE(%SST(&MSGTYPE &START 10))
                IF (&TYPE = ' ') THEN(DO)
                  CHGVAR VAR(&TYPE) VALUE('*INFO')
                IF  COND(&TYPE = '*STATUS') THEN(DO)
                   CHGVAR  VAR(&PGMQ) VALUE('*EXT')
                ELSE DO
                   CHGVAR  VAR(&PGMQ) VALUE('*PRV')
                IF  COND(&TYPE *NE '*RQS') THEN(DO)
                   SNDPGMMSG  MSGID(CPF9897) MSGF(QCPFMSG) +
                                MSGDTA(%SST(&MSGDTA 3 &MSGLEN)) +
                                TOPGMQ(&PGMQ) MSGTYPE(&TYPE) +
                ELSE       CMD(IF COND(&TYPE = '*RQS') THEN(DO))
                   SNDPGMMSG  MSG(%SST(&MSGDTA 3 &MSGLEN)) TOPGMQ(&PGMQ) +
                                MSGTYPE(&TYPE) KEYVAR(&MSGKEY)
                   RCVMSG     PGMQ(*PRV) MSGTYPE(*RQS) +
                                MSGKEY(&MSGKEY) RMV(*NO)




As I mentioned at the outset, it was a head-slapping moment for me when I "discovered" the SNDMULTMSG command. It really does remove the burden of using the SNDPGMMSG CL command, particularly when I want to record identical *STATUS and *INFO messages. Maybe the best part is that it is included in the free runtime version of COZTOOLS now available for download from www.cozTools.com

Cozzi Tools 2012 - Beta 5

Cozzi Tools 2012 Beta 5 includes the new SNDMULTMSG CL command and is available free at www.cozTools.com Watch midrangeNews.com for updates and documentation on COZTOOLS, or visit the COZTOOLS website for the latest information; and remember to tell your friends about this free tools library.  

Call Me

Bob Cozzi is a technical advisor to IBM i clients around the world. His specialty is solving difficult problems for his clients, training their programming staffs, and performing system migration/upgrades for small shops. His consulting rates are available online. To contact Bob, send an email to: bob at rpgworld.com

You can subscribe to RPG Report (we call it "follow") by visiting the RPG Report page on midrangeNews.com and then click the FOLLOW link in the table of contents for that page. To unsubscribe, simply click that same link. You must be signed up and signed in to midrangeNews.com to start following RPG Report.

Follow Bob Cozzi on Twitter

Return to midrangenews.com home page.
Sort Ascend | Descend