It's easy with the GENCMDDOC command!
This article is the sixth in a series related to creating user commands. The first five articles introduced how to define various command parameter features and then implement those features within the command's command processing program (CPP). In this article, we will look at one way to provide online help for user-created commands. The approach we will review utilizes the Generate Command Documentation (GENCMDDOC) command, which is provided starting with V5R3 of the i operating system. The GENCMDDOC command is documented here and, as one of its options, can generate an output file containing an outline to be used for documenting a CL command.
Before generating this outline, though, let's make a minor change to the TRMLFTCHR command definition. This change, though small, can improve our productivity down the road as you will see shortly. Currently, the TRMLFTCHR command is defined as shown below.
Cmd Prompt('Trim Left Characters')
Parm Kwd(Var) Type(*Char) Len(1) RtnVal(*Yes) +
Min(1) Vary(*Yes *Int4) +
Prompt('Decimal value')
Parm Kwd(TrmChr) Type(*Char) Len(1) Dft(0) +
SpcVal((0)) Max(50) +
Prompt('Character to trim')
Parm Kwd(AllTrmChr) Type(*Char) Len(1) +
Dft(*TrmChr) SpcVal((*TRMCHR X'FF')) +
Prompt('Character for all trimmed')
This definition has served us well so far, but having the prompt text for the command (and for all of the parameters of the command) coded as literals in the command definition is not necessarily the best way to go. If we were to ever decide to change some of this text (have you noticed, for instance, that the prompt text for the VAR keyword is still "Decimal value" even though the command has supported any character values since the fourth article of this series, "Cut, Snip, Trim with TRMLFTCHR"?), we would need to actually change the command source (and, having edited the command source, risk inadvertently changing more than just the prompt text). A better approach would be to use message descriptions for the prompt text. By using message descriptions, we could change the prompt text (including being able to provide translations to other languages if our company decided to go international) without needing to maintain the command definition (though on releases prior to V6R1, you would still need to recompile the command; you just wouldn't need to change the source).
Changing the TRMLFTCHR command to use message descriptions for prompting is quite easy to do. The following commands create a message file named USERMSGF in library VINING and then add message descriptions to the message file for the TRMLFTCHR command and each parameter of the command. Note that you should change VINING to whatever library name is appropriate for you.
CRTMSGF MSGF(VINING/USERMSGF)
ADDMSGD MSGID(TRM0001) MSGF(VINING/USERMSGF) MSG('Trim Left Characters')
ADDMSGD MSGID(TRM0002) MSGF(VINING/USERMSGF) MSG('Value')
ADDMSGD MSGID(TRM0003) MSGF(VINING/USERMSGF) MSG('Character to trim')
ADDMSGD MSGID(TRM0004) MSGF(VINING/USERMSGF) MSG('Character for all trimmed')
Do You Support Multiple Language Environments?
If all of your users run with the same language environment (national language, keyboard definitions, CCSID, etc.) as your developers do, then you can skip to the heading "Updating TRMLFTCHR". If you do support multiple language environments, then ensure that your job CCSID is not 65535 prior to adding the message descriptions shown above. If the Display Job command DSPJOB OPTION(*DFNA) shows that your current job has a Coded Character Set Identifier (CCSID) value of 65535, then use the Change Job command CHGJOB CCSID(XXX), replacing XXX with an appropriate CCSID value. You will discover the benefit of this change in a following article.
Updating TRMLFTCHR
With these messages in place, we can now make the following updates to the TRMLFTCHR command definition.
Cmd Prompt(TRM0001)
Parm Kwd(Var) Type(*Char) Len(1) RtnVal(*Yes) +
Min(1) Vary(*Yes *Int4) Prompt(TRM0002)
Parm Kwd(TrmChr) Type(*Char) Len(1) Dft(0) +
SpcVal((0)) Max(50) Prompt(TRM0003)
Parm Kwd(AllTrmChr) Type(*Char) Len(1) +
Dft(*TrmChr) SpcVal((*TRMCHR X'FF')) +
Prompt(TRM0004)
And we can recreate the TRMLFTCHR command using the command below (after ensuring that library VINING—or the library that you used for message file USERMSGF—is in your library list).
CRTCMD CMD(TRMLFTCHR) PGM(TRMLFTCHR) ALLOW(*IPGM *BPGM *IMOD *BMOD)
PMTFILE(USERMSGF)
Note that, if your system is at V6R1 or later, then you can also decide, rather than just PMTFILE(USERMSGF), to specify PMTFILE(USERMSGF *DYNAMIC) on the CRTCMD command or PMTFILE(USERMSGF *DYNAMIC) on the CMD statement of the TRMLFTCHR command definition. The specification of *DYNAMIC enables the command to dynamically retrieve the prompt text when the command is prompted, removing the need to recreate the command whenever a CMD or PARM PROMPT referenced message description is changed. With releases prior to V6R1, or if the default value of *STATIC is used with V6R1 and later releases, the message text is only brought into the command object at compile time, which is why recreation of the command is necessary if you want to change the prompt text. But the key point is that either of these approaches avoids the need to recompile the TRMLFTCHR CPP.
With the prompt text now defined through message descriptions, let's generate an outline of the command documentation for TRMLFTCHR using the GENCMDDOC command. As mentioned earlier, the GENCMDDOC command can generate an output file that contains an outline to be used as a starting point for documenting a CL command. This outline will be in a source language known as User Interface Manager (UIM) and will include information related to the command and its parameters, which is retrieved from the TRMLFTCHR command object itself. As the command definition doesn't include any information on how the parameters work (only how the parameters are defined), we will want to add descriptive text to this generated outline and then create a Panel Group (object type *PNLGRP) from the UIM source statements. A panel group is an object that, among other things, can contain online help information that is shown when prompting a CL command. The GENCMDDOC generated source is stored in a stream file (*STMF) that, among other types of files, can be a source file member. As the Create Panel Group (CRTPNLGRP) command supports only source physical files, and the default source file name is QPNLSRC, we will store our generated source in a source file named QPNLSRC. Assuming we want the source to be stored in library VINING, use the following command to create the QPNLSRC source file.
CRTSRCPF FILE(VINING/QPNLSRC)
To now generate the command documentation outline as member TRMLFTCHR of VINING/QPNLSRC, you can use the following command (again replacing VINING in the TODIR parameter to the appropriate library name).
GENCMDDOC CMD(TRMLFTCHR) TODIR('/QSYS.LIB/VINING.LIB/QPNLSRC.FILE')
GENOPT(*UIM)
Opening the source member TRMLFTCHR in source file QPNLSRC using whatever editor you typically use when viewing or changing CL source, the first few lines of the source should look similar to the following:
:pnlgrp submsgf='VINING/USERMSGF'.
.**********************************************************************
.* Help for command TRMLFTCHR
.**********************************************************************
:help name='TRMLFTCHR'.
&msg(TRM0001). - Help
:p.The &msg(TRM0001). (TRMLFTCHR) command <...>
.* Describe the function provided by the command.
:p.:hp2.Restrictions::ehp2.
What you are seeing is the generated UIM source. In the next article, we'll look at and update this source, but I do want to point out one item today. The sixth and seventh lines of the source should be similar to the following:
&msg(TRM0001). - Help
:p.The &msg(TRM0001). (TRMLFTCHR) command <...>
UIM supports the use of text replacement with a feature known as symbols. Symbols start with an ampersand (&), which is followed by a symbol name such as msg, and then, depending on the symbol name, additional information such as a message ID, and finally a period (.) to end the symbol. One very handy symbol is the &msg symbol. The symbol "&msg(TRM0001)." will cause the panel group compiler to extract the first-level message text of message description TRM0001 and then substitute this text in place of the symbol (everything from the initial ampersand to the closing period). That is, the help text for the sixth source line will actually display as "Trim Left Characters – Help" when displayed by a user prompting the TRMLFTCHR command. If a year from now we decide to change the textual name of the command or any of the parameter prompts, we can simply change the message text for the appropriate message and recreate the panel group. The help text will then reflect the latest and greatest command prompt text anywhere that we used the &msg symbol within the panel group, with no additional work on our part.
Contrast this with the GENCMDDOC output if we didn't use message descriptions for the prompt text. In that case, the first few lines of generated source would be this:
:pnlgrp.
.**********************************************************************
.* Help for command TRMLFTCHR
.**********************************************************************
:help name='TRMLFTCHR'.
Trim Left Characters - Help
:p.The Trim Left Characters (TRMLFTCHR) command <...>
.* Describe the function provided by the command.
:p.:hp2.Restrictions::ehp2.
In this case, the literal text from the command definition is brought in. Needing to change the prompt text in this situation will involve searching for each occurrence of the prompt text and then changing it (and hopefully changing it correctly in all cases as this is one very tedious task). Using literal prompt values in the command definition is clearly not a good use of a developer's time when message descriptions allow for such easy reuse of the prompt text—unless of course the command being created is just a "one time and then throw it away" solution. But I suspect we all know how often that "one time" fix is still in use five years later!
In the next article, we'll look at some of the details of the UIM as it relates to providing online help text for CL commands. In the meantime, if you just can't wait to dig into the UIM, you can find much of the UIM reference material in Appendix A: UIM Panel Group Definition Language, of the Application Display Programming manual, which is located here.
More CL Questions?
Wondering how to accomplish a function in CL? Send your CL-related questions to me at
LATEST COMMENTS
MC Press Online