There are many good reasons to use message descriptions when programming on the AS/400. For instance, message descriptions can help eliminate the hard coding of error messages into user programs, second-level message text can be provided to offer more in-depth explanations to operators, and variable data can be passed into messages to offer program end users more concise information.
While the advantages of using message descriptions on the AS/400 are many, the tools for working with them have not changed much since the days of the S/38. This may not pose much of a problem if you do not frequently use message descriptions or if your application is limited in scope. However, if you have incorporated message descriptions into your system, you may have noticed that the Work with Message Descriptions (WRKMSGD) command somewhat lacks flexibility.
If you're looking for a particular message description in the message file and you don't happen to have the message ID handy, you're left with the monotonous task of using the page keys to scroll through the entire file looking for the message description in question. This isn't much of a problem if your message file consists of a few dozen message descriptions, but it could be a very monotonous task with larger message files. Alternatively, you could run the WRKMSGD command with OUTPUT(*PRINT) and then scan the spool file, but this would entail several steps, and you probably wouldn't be able to see all of the desired message descriptions on the screen at the same time.
Since our applications rely heavily on message descriptions, we decided to take matters into our own hands and make our own version of the WRKMSGD command-with a notable enhancement.
We wrote a utility called the Scan Message Description (SCNMSGD) command. You can see that the interface screen in 1 is somewhat similar to the IBM WRKMSGD command, except that a new option was added to allow you to scan for text. This option allows you to search for specific data in the message description text field. This is a much needed enhancement for those who use message descriptions a lot. Dozens of duplicate message descriptions in our message files were added simply because this option was not available.
We wrote a utility called the Scan Message Description (SCNMSGD) command. You can see that the interface screen in Figure 1 is somewhat similar to the IBM WRKMSGD command, except that a new option was added to allow you to scan for text. This option allows you to search for specific data in the message description text field. This is a much needed enhancement for those who use message descriptions a lot. Dozens of duplicate message descriptions in our message files were added simply because this option was not available.
What makes this program unique is that no work file is required. We chose to use APIs to retrieve information about the message descriptions.
The SCNMSGD command in 2 prompts the operator for the name and library of a message file. These values are then validated in the CL program MSG016CL, shown in 3. If the CL program does not determine any errors, it calls an RPG program to display the message descriptions using the MSG016DF display file, shown in 4. The RPG program MSG016RG (shown in 5 on page 102) uses APIs to retrieve the message descriptions and writes them to a page-at-a-time subfile. The RPG program calls the Retrieve Message (QMHRTVM) API to retrieve the message descriptions that are used to load the subfile.
The SCNMSGD command in Figure 2 prompts the operator for the name and library of a message file. These values are then validated in the CL program MSG016CL, shown in Figure 3. If the CL program does not determine any errors, it calls an RPG program to display the message descriptions using the MSG016DF display file, shown in Figure 4. The RPG program MSG016RG (shown in Figure 5 on page 102) uses APIs to retrieve the message descriptions and writes them to a page-at-a-time subfile. The RPG program calls the Retrieve Message (QMHRTVM) API to retrieve the message descriptions that are used to load the subfile.
When using the "scan for" message text option, you may notice a slight delay if you happen to be working with a very large message file. This is because the program will use the APIs to walk through the message file until it finds enough entries to fill a subfile page. The amount of time you have to wait depends upon the size of the message file and how many occurrences of the requested text are found.
The MSG016RG program initially loads the subfile with the first message descriptions found in the message file specified on the SCNMSGD command. The LODSFL subroutine functions similarly to routines designed to load a subfile from database records, except that the message descriptions are retrieved with the QMHRTVM API. Once the first page of subfile records is written, the subfile is written to the display.
The values for the retrieve option (RTVOPT) parameter on the QMHRTVM API are *FIRST (first record), *NEXT (next record), and *MSGID (record with a specific message ID) and are used to determine the manner in which the API retrieves the message description. The missing value in this API is *PREV, which would of course be used to retrieve the previous message description. This caused us some design problems when we tried to figure out what the program should do when the Page Up key is pressed. Once the "position to" option was executed, we had to temporarily disable the Page Up key since there is no viable way to read backward through the message file.
What happens next depends entirely on the operator's response. If the operator presses F3 or F12, the program is terminated. If the F8 key is pressed, the WRKMSGD command is run for the specified message file. If the Page Down key is pressed, the LODSFL subroutine is executed, which writes the next "page" of records to the subfile.
Since the rest of the options require the pointer to be reset, the program clears the subfile and performs the GETNXT subroutine, which resets the pointer based upon the options chosen by the operator. Failure to clear the subfile first would result in a subfile in which the message descriptions were no longer in message number sequence.
If the operator keys values into the "Scan for" field, the program ensures that the match is not case-sensitive by utilizing the translate (XLATE) op code along with two named constants (one for lowercase and one for uppercase). If matching text is found, the program makes the matching characters high intensity by using the appropriate hex values for display control and a series of string-handling op codes before writing the subfile record.
If the operator elects to key a "position to" message ID, the GETNXT subroutine sets the pointer for the message file to the message ID equal to the one keyed in the "position to" field. If an exact match is not found, the pointer is set to the message ID closest to the characters keyed.
Once the pointer has been set, the program calls the LODSFL subroutine, which writes the next page of records to the subfile. The LODSFL subroutine will call the GETNXT subroutine repeatedly to get the next message description matching the selected criteria.
The next time you need to look for a message with a particular word or phrase in it, you will surely appreciate the value of this utility. It will help you keep your duplicate messages' descriptions to a minimum without the hassle of building and maintaining a work file.
Doug Pence is the founder and Ron Hawkins is the research and development manager of Computer Processing Unlimited, Inc. in San Diego, California. They are the authors of Power RPG III, published by Midrange Computing. Doug Pence can be reached by E-mail at
Reference
OS/400 System API Reference V3R1 (SC41-3801, CD ROM QBKAVD00).
Souping Up the WRKMSGD Command
Figure 1: An Example of the SCNMSGD Utility
Souping Up the WRKMSGD Command
Figure 2: The SCNMSGD Command
/*==================================================================*/ /* To compile: */ /* */ /* CRTCMD CMD(XXX/SCNMSGD) PGM(XXX/MSG016CL) + */ /* SRCFILE(XXX/QCMDSRC) */ /* */ /*==================================================================*/ CMD PROMPT('Scan Message File') PARM KWD(MSGF) TYPE(QUAL) MIN(1) PROMPT('Message + file') QUAL: QUAL TYPE(*NAME) LEN(10) QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) + SPCVAL((*LIBL)) PROMPT('Library')
Souping Up the WRKMSGD Command
Figure 3: The MSG016CL Program
/*==================================================================*/ /* To compile: */ /* */ /* CRTCLPGM PGM(XXX/MSG016CL) SRCFILE(XXX/QCLSRC) */ /* */ /*==================================================================*/ PGM PARM(&FILLIB) DCL VAR(&FILLIB) TYPE(*CHAR) LEN(20) DCL VAR(&RTNLIB) TYPE(*CHAR) LEN(10) DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) DCL VAR(&MSGF) TYPE(*CHAR) LEN(10) DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10) DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(80) /* Send all errors to error handling routine */ MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) /* Validate message file and retrieve library name */ RTVOBJD OBJ(%SST(&FILLIB 11 10)/%SST(&FILLIB 1 10)) + OBJTYPE(*MSGF) RTNLIB(&RTNLIB) CHGVAR VAR(%SST(&FILLIB 11 10)) VALUE(&RTNLIB) /* Call program to scan message file */ CALL PGM(MSG016RG) PARM(&FILLIB) /* Branch around error handling routine */ GOTO CMDLBL(ENDPGM) /* Error handling routine */ ERROR: RCVMSG MSGTYPE(*EXCP) MSGDTA(&MSGDTA) MSGID(&MSGID) + MSGF(&MSGF) MSGFLIB(&MSGFLIB) SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) + MSGDTA(&MSGDTA) MSGTYPE(*ESCAPE) ENDPGM: ENDPGM
Souping Up the WRKMSGD Command
Figure 4: The MSG016DF Display File
*=============================================================== * To compile: * * CRTDSPF FILE(XXX/MSG016DF) SRCFILE(XXX/QDDSSRC) * *=============================================================== *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 A DSPSIZ(24 80 *DS3) A CA03(03) A CF08(08) A CA12(12) A ERRSFL A R SFLRCD SFL A DFMSGK 7A O 9 3 A DFSEVR 2Y 0O 9 17EDTCDE(1) A DFMSGD 51A O 9 24 A R SFLCTL SFLCTL(SFLRCD) A ROLLUP(95) A OVERLAY A 21 SFLDSP A SFLDSPCTL A 25 SFLCLR A N03 SFLEND(*MORE) A SFLSIZ(22) A SFLPAG(11) A RRNRCD 4S 0H SFLRCDNBR(*TOP) A 1 26'Scan Message Descriptions' A DSPATR(HI) A 3 2'Message file:' A MSGFIL 10A O 3 18 A 3 33'Library:' A MSGLIB 10A O 3 44 A 5 2'Position to . . . . . . .' A ZMSGKY 7A B 5 31DSPATR(UL) A 5 40'Message ID' A 6 2'Scan for. . . . . . . . .' A ZTEXT 15A B 6 31DSPATR(UL) CHECK(LC) A 42 ERRMSG('No records found that + A meet search criteria.') A 8 2'Message ID Severity Message Text' A DSPATR(HI) A R FOOTER A 22 2'F3=Exit' A COLOR(BLU) A 22 15'F8=Work with message descriptions' A COLOR(BLU) A 22 54'F12=Cancel' A COLOR(BLU)
Souping Up the WRKMSGD Command
Figure 5: The MSG016RG Program
*=============================================================== * To compile: * * CRTRPGPGM PGM(XXX/MSG016RG) SRCFILE(XXX/QRPGSRC) * *=============================================================== *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 FMSG016DFCF E WORKSTN F RRN KSFILE SFLRCD F KINFDS INFO E AM 500 1 E A52 52 1 IMESSAG DS 500 I B 1 40BR I B 9 120SEV I 27 33 RMSGID I B 65 680MO I B 69 720ML IINFO DS I B 378 3790FSTL I IDS I B 1 40MSGLEN I B 5 80RPLLEN I B 9 120CONVRT I B 13 160REPLAC IERROR IDS I B 1 40BYTPRV I B 5 80BYTAVA I 9 15 EMSGID I 17 116 MSGDTA I 'abcdefghijklmnopqrst-C LOW I 'uvwxyz' I 'ABCDEFGHIJKLMNOPQRST-C UPR I 'UVWXYZ' I 'WRKMSGD MSGF(' C WRKC I '000000' C SIX0 *=============================================================== C *ENTRY PLIST C PARM FILLIB 20 C MOVELFILLIB MSGFIL C MOVE FILLIB MSGLIB C BITOF'01234567'HI 1 C BITON'26' HI C BITOF'01234567'NM 1 C BITON'2' NM C Z-ADD116 BYTPRV * Retrieve first message in file C MOVEL'*FIRST' RTVOPT P C EXSR GETNXT C GOTONE IFEQ 'Y' C EXSR LODSFL C ENDIF C MOVEA'01' *IN,21 C MOVE *BLANKS ZTEXT C Z-ADD1 RRNRCD C *IN03 DOUEQ*ON C MOVE *BLANKS ZMSGKY C MOVE *OFF *IN21 C RRN IFNE *ZEROS C MOVE *ON *IN21 C ELSE C ZTEXT IFNE *BLANKS C MOVE *ON *IN42 C ENDIF C END C *IN42 IFEQ *OFF C WRITEFOOTER C ENDIF C EXFMTSFLCTL C MOVE *OFF *IN42 C *IN03 IFEQ *ON C *IN12 OREQ *ON C LEAVE C ENDIF * If rolling forward, retrieve next message C *IN95 IFEQ *ON C GOTONE IFEQ 'Y' C EXSR LODSFL C ENDIF C ITER C ENDIF * Work with message descriptions C *IN08 IFEQ *ON C MOVEL'*FIRST' STRKEY P C *IN21 IFEQ *ON C FSTL CHAINSFLRCD 68 C *IN68 IFEQ *OFF C MOVELDFMSGK STRKEY 7 C ENDIF C ENDIF C EXSR WRKMSG C Z-ADDHIRRN RRN C ITER C ENDIF * Clear the subfile C MOVE *ON *IN25 C WRITESFLCTL C MOVE *OFF *IN25 C Z-ADD0 RRN * Translate search phrase to uppercase C MOVE *BLANKS UPRTXT C ZTEXT IFNE *BLANKS C LOW:UPR XLATEZTEXT UPRTXT 15 C ENDIF * C ZMSGKY IFEQ *BLANKS C MOVEL'*FIRST' RTVOPT C ELSE C MOVEL'*MSGID' RTVOPT C MOVE ZMSGKY MSGID C ENDIF * Retrieve a message C EXSR GETNXT C GOTONE IFEQ 'Y' C EXSR LODSFL C ENDIF C ENDDO C MOVE *ON *INLR *=============================================================== * Format and execute the work with message descriptions command *=============================================================== C WRKMSG BEGSR C MSGLIB CAT '/':0 CFILLB 22 P C CAT MSGFIL:0 CFILLB C CAT ')':0 CFILLB C WRKC CAT CFILLB:0 COMAND P C CAT 'MSGID(':1COMAND C CAT STRKEY:0 COMAND C CAT ')':0 COMAND C CALL 'QCMDEXC' C PARM COMAND100 C PARM 100 LENGTH 155 C ENDSR *=============================================================== * Load subfile subroutine *=============================================================== C LODSFL BEGSR C Z-ADD0 X * Continue loading subfile until end of message file, or page size C RMSGID DOUEQ*BLANKS C X OREQ 11 C ADD 1 RRN 40 C X IFEQ 0 C Z-ADDRRN RRNRCD 40 C ENDIF C Z-ADDRRN HIRRN 40 C MOVE RMSGID DFMSGK C MOVE SEV DFSEVR C WRITESFLRCD C MOVELRMSGID MSGID C MOVEL'*NEXT' RTVOPT P C MOVE *BLANKS MESSAG C EXSR GETNXT C ADD 1 X 40 C ENDDO C ENDSR *=============================================================== * Retrieve a message subroutine *=============================================================== C GETNXT BEGSR C MOVE 'N' GOTONE C GOTONE DOUEQ'Y' C RMSGID OREQ *BLANKS C CALL 'QMHRTVM' C PARM MESSAG C PARM 500 MSGLEN C PARM 'RTVM0300'FMTNAM 8 C PARM MSGID 7 C PARM FILLIB C PARM RPLDTA 1 C PARM 1 RPLLEN C PARM '*NO' REPVAL 10 C PARM '*NO' RTNCHR 10 C PARM ERROR C PARM RTVOPT 10 C PARM CONVRT C PARM REPLAC * If message key not found, and looking for a specific * message, get closest to it C EMSGID IFEQ 'CPF2419' C RTVOPT ANDEQ'*MSGID' C MOVEL'*NEXT' RTVOPT P C ITER C ENDIF C EMSGID IFEQ 'CPF2499' C RTVOPT ANDEQ'*MSGID' C Z-ADD0 I C ' ' CHEKRMSGID I 10 C ADD 1 I C SELEC C I WHEQ 2 C CAT 'AA':0 MSGID C I WHEQ 3 C CAT 'A':0 MSGID C ENDSL C CAT SIX0:0 MSGID C MOVEL'*NEXT' RTVOPT P C ITER C ENDIF * C RMSGID IFNE *BLANKS C MOVEAMESSAG AM,1 * Must blank out information beyond the message text * Message offset (MO) + message length (ML) = index to begin blanking C MO ADD ML UI 30 C UI IFLT 500 C MOVEA*BLANKS AM,UI C ENDIF C MOVEAAM,MO DFMSGD P * If scanning for messages with a certain phrase, translate message * into upper case and scan. If found, (P>0), highlight phrase. C ZTEXT IFNE *BLANKS C ' ' CHEKRZTEXT Z 20 C LOW:UPR XLATEDFMSGD UPRNAM 51 C UPRTXT:Z SCAN UPRNAM P 30 C P IFNE *ZEROS C MOVE 'Y' GOTONE 1 C EXSR HIGH C ENDIF C ELSE C MOVE 'Y' GOTONE C ENDIF C ENDIF C MOVELRMSGID MSGID C MOVEL'*NEXT' RTVOPT P C ENDDO C ENDSR *=============================================================== * Control highlighting of search phrase in message text *=============================================================== C HIGH BEGSR C MOVE NM A52,1 C MOVEADFMSGD A52,2 C Z-ADDP R 30 C R DOUEQ0 C A52,R IFEQ *BLANKS C A52,R OREQ NM C MOVE HI A52,R C LEAVE C ENDIF C SUB 1 R C ENDDO C ADD Z P C P IFGT 51 C Z-ADD51 P C ENDIF * Shutoff highlight by inserting normal bits into first blank after * search phrase. C ' ' SCAN UPRNAM:P Q 30 C Q IFNE *ZEROS C Q IFLT 52 C ADD 1 Q C ENDIF C MOVE NM A52,Q C ENDIF C MOVEAA52,1 DFMSGD C ENDSR
LATEST COMMENTS
MC Press Online