Do you ever create your own CL command definition (*CMD) objects? If you do, would you like to add online command help for your commands like IBM commands have? This article shows you how to use the Generate Command Documentation (GENCMDDOC) command to quickly and easily do just that.
Background
"To know how far you have come, you must know where
you started." This may be a famous quote, but as far as I know, I made it up.
And it applies really well to the subject of this article!
IBM added
support for CL command online help in the first release of OS/400 in 1988.
Command help was shipped in objects called "panel groups." The source used to
define the help was a generalized markup language called User Interface Manager
(UIM). In the second release of OS/400 in 1989, IBM published documentation of
UIM syntax, and a new CL command, CRTPNLGRP, was shipped to compile UIM source
and create a panel group. This made it possible for customers to add online help
to their own commands. Possible, yes...easy, no! The Application Display
Programming book documented UIM syntax, but there were no examples that
showed how to put the various UIM tags together to create command help that
looked similar to the online help for IBM CL commands.
Breakthrough
Fast-forward to the year 2004 and release V5R3 of i5/OS. IBM changed how it produced all of the CL command documentation shipped in the Information Center. Tools written in Java and Extensible Stylesheet Language Transformation (XSLT) invoked i5/OS APIs that retrieved command description information and command help information as XML documents. These tools generated the HTML command documentation files for the Information Center, and IBM shipped the Java and XSLT code in i5/OS. Finally, a new CL command, Generate Command Documentation (GENCMDDOC), was written to provide an easy-to-use CL command interface to let customers use these new tools.
Four Easy Steps to Add Online Command Help
Adding online command help to a CL command requires four basic steps:
- Choose the command you want to add online help to.
- Run the GENCMDDOC command to create the UIM outline.
- Edit the UIM source generated by GENCMDDOC.
- Create the panel group and connect it to the command.
Of these four steps, the time-consuming one is editing the UIM source, but as you will see, almost all of the drudge work has been done for you, leaving the creative part of writing the descriptive text for you to complete.
Step #1: Choose the Command You Want to Add Online Help To
The GENCMDDOC command generates a file that contains
a set of UIM source tags for a command, using the existing *CMD object as input.
I've used a sample command named Display Object List (DSPOBJL) for demonstration
purposes. The code below shows the command definition source statements for the
DSPOBJL command.
PARM KWD(OBJ) TYPE(Q1) MIN(1) MAX(1) +
FILE(*NO) PROMPT('Objects')
PARM KWD(OUTPUT) TYPE(*CHAR) LEN(1) RSTD(*YES) DFT(*) +
SPCVAL(* (*PRINT P) (*OUTFILE F)) +
EXPR(*YES) PROMPT('Output')
PARM KWD(OUTFILE) TYPE(Q2) FILE(*OUT) +
PMTCTL(OUTFILE) PROMPT('File to receive output')
PARM KWD(OUTMBR) TYPE(E1) +
PMTCTL(OUTFILE) PROMPT('Output member options')
E1: ELEM TYPE(*NAME) LEN(10) DFT(*FIRST) +
SPCVAL(*FIRST) EXPR(*YES) +
PROMPT('Member to receive output')
ELEM TYPE(*CHAR) LEN(1) RSTD(*YES) +
DFT(*REPLACE) SPCVAL((*REPLACE R) (*ADD A)) +
EXPR(*YES) PROMPT('Replace or add records')
Q1: QUAL TYPE(*GENERIC) LEN(10) SPCVAL(*ALL) +
MIN(1) EXPR(*YES)
QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) +
SPCVAL(*LIBL *USRLIBL *CURLIB *ALL *ALLUSR) +
EXPR(*YES) PROMPT('Library')
Q2: QUAL TYPE(*NAME) LEN(10) MIN(1) EXPR(*YES)
QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) +
SPCVAL((*LIBL) (*CURLIB *CURLIB)) +
EXPR(*YES) PROMPT('Library')
DEP CTL(&OUTPUT *EQ F) PARM((&OUTFILE *NE ' ')) +
NBRTRUE(*EQ 1) MSGID(CPD9861)
DEP CTL(&OUTMBR *NE *FIRST) PARM((&OUTFILE *EQ ' ')) +
NBRTRUE(*EQ 0) MSGID(CPD9867)
DEP CTL(&OUTPUT *NE F) PARM((&OUTFILE *EQ ' ')) +
NBRTRUE(*EQ 1) MSGID(CPD9862)
OUTFILE: PMTCTL CTL(OUTPUT) COND((*EQ F))
Step #2: Run the GENCMDDOC Command to Create the UIM Outline
The GENCMDDOC command can generate two forms of
output. In this article, GENCMDDOC is used to create a UIM source member that
you will edit in step #3. Change the CMD and TODIR parameters to reference your
work library name (instead of MYLIB) and the command for which you want to
generate online help. The following code shows the GENCMDDOC command string that
will generate a UIM source member for the DSPOBJL command in library MYLIB; the
UIM output will be stored in member DSPOBJL of source file QPNLSRC in library
MYLIB.
TODIR('/QSYS.LIB/MYLIB.LIB/QPNLSRC.FILE')
TOSTMF(*CMD) GENOPT(*UIM)
Patience Is a Virtue
The CPP for GENCMDDOC is written in
C++ and will start a second job that creates a Java Virtual Machine (JVM) where
the Java and XSLT code runs. When the Java code finishes, the JVM is ended. On
older or smaller System i machines, starting and ending a JVM can take a minute
or so.
Check It Out!
The source member generated by GENCMDDOC
should contain valid UIM source that has help for the command and each command
parameter, as well as sample example and error message sections. If you are
eager to see the F1 (Help) key work for your command, go ahead and skip to step
#4, and use a CL command prompter to verify that your command has online help.
You will need to come back to step #3 to edit the online help to make it really
"helpful."
Step #3: Edit the UIM Source Generated by GENCMDDOC
For editing the UIM source member, use whichever
source editor you like. If you want to edit in a 5250 emulation session, you can
run the Start Source Entry Utility (STRSEU) command. If you want to use a GUI
source editor, you can use the Remote Systems Explorer (RSE) editor function of
WDSc.
Verifying the Edited UIM
If you jumped to Step #4 to
check out what the GENCMDDOC-generated command help looked like, you've already
hooked your command up to your panel group. The connection from the command to
the panel group is by name, so you can replace the help panel group with
a more-complete version and not break the connection. This means that you can do
your UIM editing a bit at a time rather than all at once. This is especially
important if you haven't worked with UIM source before and you want to build
your comfort level with UIM.
Whether you want to make a few UIM source
changes and run the CRTPNLGRP command to recreate the panel group or do them all
at once before running CRTPNLGRP, that's up to you. Don't be overly concerned if
the panel group creates but puts warning messages in the spooled file listing.
However, if the panel group is not created, you will need to look at the spooled
file (e.g., by running the WRKSPLF command) and find and fix the UIM syntax
errors.
Note that the default for the REPLACE parameter on the CRTPNLGRP
command is *YES, so your new panel group will be created in the specified
library, and the old panel group will be moved to library QRPLOBJ.
Let's Start Editing
The next part of this article goes into
detail on editing the four sections of command online help: command-level help,
parameter-level help for each command parameter, command examples, and command
error messages. Ready?
Command-Level Help
If you have worked
with HTML tags, you know that an HTML tag starts with a less-than sign (<)
and ends with a greater-than sign (>). For UIM tags, the tag starts with a
colon (:) and ends with a period (.). UIM tag names are not case-sensitive; I
show the tag names in all lowercase, but you could use uppercase or mixed case.
The very first generated UIM tag in the UIM source member is the
:pnlgrp tag, and the very last tag is the :epnlgrp tag. Between those two
tags, you will find a set of help modules. Each help module begins with a
:help tag and ends with a :ehelp tag. The first help module in the
UIM source generated by the GENCMDDOC command is the command-level help module.
Notice that the name attribute on this help module matches the name of
the command object. You should not need to modify the :help tag or the line that
follows the :help tag.
The :p tag is used to begin a paragraph, similar
to a
tag in HTML. GENCMDDOC generates a :p tag at the beginning of the
first sentence of the command-level help. Since GENCMDDOC is not smart enough to
know what the command does, it generates a text marker of <...>, which you
need to replace with the remainder of the first sentence and as many more
sentences as you feel are needed. To start a new paragraph, add another :p tag.
Note that UIM does not have an end-of-paragraph tag like you would find in HTML
or XML; one paragraph implicitly ends when another paragraph begins.
IBM
command-level help is where command-level restrictions are documented. The
generated UIM source contains a sample Restrictions list showing command-level
restrictions like what authorities are required to run the command, any
prerequisite commands, threadsafe restrictions (if conditionally threadsafe),
etc. The Restrictions heading is between the :hp2 and :ehp2 tags, which will
cause the text to appear in bold ("hp" stands for "highlighted phrase"). The
list begins with a :ul tag and ends with a :eul tag ("ul" stands for "unordered
list"), with a :li tag for each list entry ("li" stands for "list item"). Note
that there is no end-of-list-item tag to end a list item. If your command has no
command-level restrictions, it is recommended that you delete this list
(including the Restrictions heading) rather than say "None." Remember that
information about a specific parameter might be better added in the
parameter-level help module for that parameter.
As you might have
figured out already, putting .* in the first two columns makes any line a
comment. This can be handy if you want to comment out some UIM tags rather than
delete them.
The code below shows what the first part of the
GENCMDDOC-generated command-level help looked like:
Display Object List - Help
:p.The Display Object List (DSPOBJL) command <...>
.* Describe the function provided by the command.
This code shows what it might look like after editing:
:help name='DSPOBJL'.
Display Object List - Help
:p.The Display Object List (DSPOBJL) command provides a list of
objects in one or more libraries that match a specific or
generic name string.
Parameter-Level Help
Following the command-level help module
in the UIM source will be parameter-level help modules, one for each parameter
defined for the command. Of course, if your command has no parameters, there
won't be any parameter-level help modules. GENCMDDOC does not generate
parameter-level help modules for hidden or constant parameters.
Most of
the generated UIM source statements do not require any editing, including the
:help and :xh3 tags that begin the help module. Notice that the name attribute
on each parameter-level help module is the command name followed by a forward
slash followed by the keyword name associated with the parameter. The :xh3 tag
shows the parameter title text, which will appear when viewing Extended Help. A
:p (paragraph) tag is generated to start the description of the purpose of the
parameter. You can replace the generated <...> text marker with as much
text as you think is needed to explain the purpose of the parameter. To start a
new paragraph, just add another :p tag.
A couple of UIM tags that you
might find handy when documenting parameter restrictions or inter-parameter
dependencies are :nt and :ent, which generate the highlighted word "Note:",
followed by the text you enter after the :nt tag; no :p tag is needed before the
note text.
The :parml (parameter list) tag marks the start of the list
of parameter choices. There must be a matching :eparml (end parameter list) at
the end of the list. There is a :pt (parameter term) tag and a :pd (parameter
definition) tag for each parameter choice. Generally, you can leave the :pt tags
as they are generated. Following each :pd tag will be a <...> text marker
where you can describe the meaning of a specific value (e.g., what *YES means)
or describe what is expected for a user-defined value. The :pt and :pd tags do
not have matching end tags.
You will see :pk and :epk, or :pv and :epv
tags bracketing the parameter value on the :pt. tags. The :pk tag is generally
used for the default value and any value specified in the command definition for
a SNGVAL (single value), SPCVAL (special value), or VALUE. The :pv tag is used
when a user-defined value is allowed (e.g., an object name or a value within a
defined range). In online help, text bracketed by :pk/:epk will be boldface, and
text bracketed by :pv/:epv will be underlined. In the generated help HTML, text
bracketed by :pk/:epk will be boldface, and text bracketed by :pv/:epv will be
italicized. Default parameter values will be preceded by :pk def, which causes
the value to be boldface and underlined.
The code below shows what the
first part of a GENCMDDOC-generated parameter-level help module looked like:
Objects (OBJ) - Help
:xh3.Objects (OBJ)
:p.Specifies <...>
.* Describe the function provided by the parameter.
:p.This is a required parameter.
:p.:hp2.Qualifier 1: Objects:ehp2.
:parml.
:pt.:pk.*ALL:epk.
:pd.
<...>
.* Describe the function provided by the pre-defined parameter value.
And this is what it might look like after editing:
Objects (OBJ) - Help
:xh3.Objects (OBJ)
:p.Specifies the objects to be listed.
:p.This is a required parameter.
:p.:hp2.Qualifier 1: Objects:ehp2.
:parml.
:pt.:pk.*ALL:epk.
:pd.
List all objects, regardless of the object name.
Examples Help
After the parameter-level help modules, you'll
find a "special" help module where you can provide examples of valid command
strings that demonstrate the capabilities of the command. Notice that the name
attribute of the example's help module is the command name followed by a forward
slash followed by COMMAND/EXAMPLES'.
While it is not recommended to have online command help be a
tutorial on how to use the command, providing lots of good examples can save the
command user from having to search for additional documentation on using the
command.
If your command has no parameters or maybe one simple
parameter, you should only need a single example. As the command complexity
grows, you'll have to decide how many variations to provide as examples.
These examples can also encourage users of your command to use the
command the way you intended. It won't make your command foolproof (because
fools can be so ingenious), but it can help, because if the example command
string is basically performing the desired function, users will copy and paste
it to the command line and prompt it to modify it to their particular
situation.
You don't need to modify the :help and :ehelp tags that
GENCMDDOC generated for you, including the :xh3 tag. A :p (paragraph) tag is
generated for each example title, with the title text bracketed by :hp2/:ehp2
(highlighted phrase) tags. If you have only one example, this title can be
deleted. Edit the title text to describe the function performed by the command
example.
The actual command string starts with a :xmp (example) tag and
ends with a :exmp tag. Text between the :xmp and :exmp tags will be treated as
preformatted text (similar to
andtags in HTML). If your command string is longer than 63 characters, split the command string across multiple lines. Otherwise, when viewing the online help, the command will be wrapped and be less readable.
GENCMDDOC doesn't know what combination of parameters are valid, so the generated UIM examples show parameter keyword names of KWD1 and KWD2. Edit the examples to replace KWD1 and KWD2 with valid combinations of your command's parameters and parameter values.
Replace the generated <...> marker with sentences that describe the behavior of the example command string.
The following code shows what the first part of the GENCMDDOC-generated command examples help module looked like:
Examples for DSPOBJL - Help
:xh3.Examples for DSPOBJL
:p.:hp2.Example 1: Simple Command Example:ehp2.
:xmp.
DSPOBJL KWD1(PARMVAL1)
:exmp.
:p.This command <...>
.* Describe a simple invocation of the command.
And this is what it might look like after editing:
:help name='DSPOBJL/COMMAND/EXAMPLES'.
Examples for DSPOBJL - Help
:xh3.Examples for DSPOBJL
:p.:hp2.Example 1: Display Generic List of Objects in a
Single Library:ehp2.
:xmp.
DSPOBJL OBJ(MYLIB/ABC*)
:exmp.
:p.This command will list all of the objects with names
that begin with ‘ABC’ in library MYLIB.
Error Messages Help
The last help module in the generated UIM
source is the "special" error message help module. This help module should
contain the list of escape, notify, and status messages that the command will
signal. This information will let someone using the command know what messages
can be monitored for by using the MONMSG command. The name attribute of the
error messages help module is the command name followed by forward slash
followed by ERROR/MESSAGES'.
For most of your commands, you will only need to list *ESCAPE messages
signaled from your CPP; very few i5/OS commands signal *NOTIFY and *STATUS
messages to the program that called the command. IBM convention is to not list
CPF0001 or CPF9999 in this list.
The GENCMDDOC command doesn't know what
error messages are signaled by a command; it generates a sample list that you
need to edit. The generated :help tag and its associated :xh3 tag include a
reference to message CPX0005 using the &msg built-in function. The &msg
built-in function will cause the first-level text of the specified message to be
included in the UIM help text when you run the CRTPNLGRP command. The
first-level text of CPX0005 is "Error messages for."
A :p (paragraph)
tag is generated for the heading that precedes the list of messages. The heading
generated by GENCMDDOC is for the list of *ESCAPE messages. If your command
signals any monitorable *STATUS or *NOTIFY messages, you could copy this
paragraph and definition list. The heading includes a reference to CPX0006. The
first-level text of CPX0006 is "messages."
The set of messages begins
with a :dl (definition list) tag. For each message in the list, there is a :dt
(definition term) tag that identifies the message and a :dd (definition) tag
that should contain the message text. The list of messages generated by
GENCMDDOC shows two things:
How to use the UIM &msg built-in to
pull in the message text—The &msg built-in function normally has
three parameters: the message identifier, the message file name, and the message
file library name (or *LIBL). Here, a fourth parameter, nosub, is specified.
This is done so that blanks are not substituted for message replacement
variables (e.g., &1) in the message text.
Some i5/OS generic messages
that you might want to use in your CPP—All of these messages have
message identifiers that begin with CPF98.
The following code shows what
the first part of the GENCMDDOC-generated command error messages help module
looked like:
&msg(CPX0005,QCPFMSG). DSPOBJL - Help
:xh3.&msg(CPX0005,QCPFMSG). DSPOBJL
:p.:hp3.*ESCAPE &msg(CPX0006,QCPFMSG).:ehp3.
.**********************************************************************
.* List *ESCAPE, *STATUS, and *NOTIFY messages signaled from the command.
.* The following are generic messages defined in message file QCPFMSG.
.* Modify this list to match the list of error messages for the command.
.************************************************************************
:DL COMPACT.
:DT.CPF9801
:DD.&MSG(CPF9801,QCPFMSG,*LIBL,nosub).
:DT.CPF9802
:DD.&MSG(CPF9802,QCPFMSG,*LIBL,nosub).
:DT.CPF9803
:DD.&MSG(CPF9803,QCPFMSG,*LIBL,nosub).
:
:EDL.
This is what it might look like after editing:
&msg(CPX0005,QCPFMSG). DSPOBJL - Help
:xh3.&msg(CPX0005,QCPFMSG). DSPOBJL
:p.:hp3.*ESCAPE &msg(CPX0006,QCPFMSG).:ehp3.
:DL COMPACT.
:DT.CPF2110
:DD.&MSG(CPF2110,QCPFMSG,*LIBL,nosub).
:DT.CPF2113
:DD.&MSG(CPF2113,QCPFMSG,*LIBL,nosub).
:DT.CPF2124
:DD.&MSG(CPF2124,QCPFMSG,*LIBL,nosub).
:DT.CPF2176
:DD.&MSG(CPF2176,QCPFMSG,*LIBL,nosub).
:DT.CPF2182
:DD.&MSG(CPF2182,QCPFMSG,*LIBL,nosub).
:DT.CPF9899
:DD.&MSG(CPF9899,QCPFMSG,*LIBL,nosub).
:EDL.
Step #4: Create the Panel Group and Connect It to the Command
When you are ready to create the command help panel
group from the UIM source, you will run the CRTPNLGRP command. The code below
shows the CRTPNLGRP command string that will create a panel group object named
DSPOBJL in library MYLIB. In this example, the *PNLGRP object name is the same
as the *CMD object name, but the panel group name could be different from the
command name.
SRCFILE(MYLIB/QPNLSRC) SRCMBR(DSPOBJL)
Find and Fix UIM Compiler Errors
The UIM compiler is fairly
picky about syntax and will not create a panel group if you've left off
tag-delimiter periods or you've mismatched quotes on tag attributes, like help
module names. The good news is that those tags are generally ones that are
generated for you and that you don't need to modify. Also, the UIM compiler is
pretty good at identifying the line where an error occurred and determining what
needs to be fixed. Use WRKSPLF to find the UIM compiler spooled file and look
for severe errors. The UIM compiler may send a lot of warnings about potential
problems with translation space; generally, you can ignore these warning
messages.
Connect Your Command to Your Panel Group
In order
for i5/OS online help support to find the online help for your command, the
command object needs to point to the panel group that holds the help modules for
the command. If you haven't done so already, change your command to have a help
identifier (HLPID parameter) that is the same as the command name, and set the
name of the online help panel group (HLPPNLGRP parameter) for your command.
The following code shows the CHGCMD command string that will change
command DSPOBJL in library MYLIB so that the operating system will look for its
command help in panel group DSPOBJL in library MYLIB. By specifying HLPID(*CMD),
the operating system will expect that all of the help modules associated with
the DSPOBJL command begin with DSPOBJL.
HLPPNLGRP(MYLIB/DSPOBJL)
Use the 5250 Prompter to See the Online Help
Now you can test
your command help from the CL command prompter screen or from a command line; to
see all of the help modules, just type the command name on a command line and
press F1 (Help). Chances are good that when you see all the online help, you
will notice a few things that you want to fix or change, such as spelling or
grammar.
Go back to step #3 to add or change online help. Use a source
file editor to change the UIM source and run the CRTPNLGRP command again.
It is not necessary to delete the old panel group before creating
the updated panel group. The CRTPNLGRP command has a replace object (REPLACE
parameter) option that defaults to *YES. If the panel group creates
successfully, the old panel group is renamed and moved to the QRPLOBJ library.
It is not necessary to run the CHGCMD command again. The
association between the command and the help panel group is by name. This means
that if the old panel group is replaced, the next time you look at the command
help, the online help support will pull the help text from the newer version of
the panel group.
Congratulations! You've successfully added online help
to your command!
Getting "Fancy"
Once you've created online help for your command, you have everything you need to create HTML documentation. The second part of this article will show you how to create HTML documentation for your commands that looks like the HTML command documentation files for IBM commands in the IBM Information Center for System i5. Part two will also cover topics that let you share messages text and help text across the command help for multiple commands to ensure consistency and reduce online help development and maintenance.
More Information on UIM Tags
The Application Display Programming book is
still the most complete reference for UIM. Appendix A describes all of the UIM
tags used in this article and many more. The PDF for this book can be found in
the
V5R4 Information Center under the main topic Printable PDFs and Manuals.
Guy Vig is a senior software engineer with IBM
Systems and Technology Group and has worked in Rochester, Minnesota, and
Toronto, Ontario, on various parts of the operating system and compiler products
for System/38, AS/400, iSeries, and System i5 since joining IBM in 1978. As the
“CL Architect,” he has worked on revitalizing CL on System i. Guy
can be reached at
LATEST COMMENTS
MC Press Online