Give users valid parameter value lists derived from your database.
Brief: In these days of user friendly software, providing some kind of list of validvalues for input fields is something that users are apt to expect. Yet, it may not be something you provide in your command parameters because you never knew how it was done. Not only can choice programs provide valid value lists to your command parameters, but the lists can be dynamically linked to your database.
One of the best features of OS/400 is the availability of a list of valid choices at virtually any input field via the F4 (prompt) key. For example, at the command line, you can press F4 and get a list of the myriad of OS/400 commands via the MAJOR menu. When you choose the command you want, you can again use the F4 key to get a list of the parameters the command uses. It doesn't stop here. Now that you have the parameter list, the F4 key can be used on each parameter to derive a list of its valid entries. For instance, while you prompt for the Create Device Description Display (CRTDEVDSP) command, the TYPE parameter expects you to enter a valid device type, such as 5251 or 3477. With the cursor positioned at the TYPE parameter, you can press F4 to see a complete list of valid device types.
Although you may think otherwise, IBM-supplied commands are not the only ones that can take advantage of this capability. If you've been following Richard Shaler's article series about creating your own commands, you probably remember that one way you can get your command to provide a list of valid values is by adding two keywords to the PARM statement: the Restricted (RSTD) keyword with a value of *YES and the VALUES keyword with a list of valid values. The entire list can be displayed by pressing F4 when the cursor is in the parameter.
The only problem with this technique is that the list is static. When the list is based on the information in a database file, you'll probably find yourself needing to change the list every time the information in the file changes. For example, let's say a command parameter requires a valid salesperson ID to be entered. The turnover in the marketing department requires your company to install a revolving door. Needless to say, some programmer is constantly modifying the command source member.
What you need is a way to have your command retrieve the valid IDs list from the salesman file so it can dynamically respond to the changes that occur, eliminating the need to maintain the command source member.
A Powerful Tool
The little-used but powerful CHOICEPGM keyword in the PARM statement for a command parameter gives you this feature. This article will tell you how to implement the most powerful use of the CHOICEPGM keyword: displaying a list of valid choices for a command parameter, when the valid choices are contained in a database file.
Before going any further, I'll define the two levels of support provided for each command parameter when prompting (pressing F4).
1. When a user types a command name and presses F4, the first level of prompt support is provided. The list of command parameters is shown, along with a short list of choices to the right of each parameter. This descriptive text is known as "Choice Text."
2. When a user then positions the cursor at a parameter and presses F4 again, a second level of support is supplied: a list of valid values for the parameter (see 1). This list is known as a list of permissible values.
2. When a user then positions the cursor at a parameter and presses F4 again, a second level of support is supplied: a list of valid values for the parameter (see Figure 1). This list is known as a list of permissible values.
Choice text can be hard-coded into the source member for a command. A list of valid values can also be hard-coded, but should not.
The reason, then, for using a choice program is to customize a command to communicate with your database so the user is provided information about the values the command can accept. For example, let's say you have created a Display Sales History (DSPSLSHST) command. You've created the command so the user can select the sales history by salesperson ID. If a user is prompting for the command and decides to see a list of salesperson IDs, the standard support provided as described earlier will provide a list. However, since the list of salespersons is derived from the command source member, it is static. A better solution would be to provide the user with dynamic information. You can provide this support using the CHOICEPGM keyword to activate a program that builds a list of permissible values, drawing the information from your database.
Putting It to Work
By using the CHOICEPGM keyword for a command parameter, you can specify a program which will provide the choice text for that parameter when the user presses F4. You create this program. And while it is easier to hard-code the choice text into the command definition object (CDO) source using the CHOICE keyword, this method allows no way to provide a list of permissible values. On the other hand, a choice program can retrieve a dynamic list of permissible values from a database file and supply them to the command prompter. Using our example, when the company adds a salesperson to the master file, the command will include the new salesperson in the list of permissible values for the command. The command is automatically kept current.
The user now can see the actual values stored in the file. And although the user may select a value that is not in the list (a validity checking program could prevent this from happening; "Writing AS/400 Commands: Part 3" in the March issue of MC reveals how), the user will have a list of valid choices in front of him. The retrieved list can contain any number of individual values ("elements"), but the total length is limited to 1998 bytes.
A choice program can be written in any language, including CL. Writing a choice program is not difficult; in fact, a CL choice program is quite simple. It is important to remember that the same choice program will be used for two distinct purposes: to supply choice text, and to supply a list of permissible values. The parameters passed from the command processor to the choice program are based on the level of prompting support requested-that is, whether the command processor is requesting the choice text or a list of permissible values. The prompting support level specified will determine the layout of the output parameter that is returned from the choice program.
2 describes the parameters. When returning choice text to the command processor, the choice program places up to 30 characters of text into the returned parameter. A list of permissible values, however, is a slightly more complicated affair. The first two bytes must contain a binary number which contains the number of elements in the list, not the length of the list. The remaining 1998 bytes are made up of a series of two subfields-the first being a two-byte binary field containing the length of the following element, and the second consisting of the actual text of the list element.
Figure 2 describes the parameters. When returning choice text to the command processor, the choice program places up to 30 characters of text into the returned parameter. A list of permissible values, however, is a slightly more complicated affair. The first two bytes must contain a binary number which contains the number of elements in the list, not the length of the list. The remaining 1998 bytes are made up of a series of two subfields-the first being a two-byte binary field containing the length of the following element, and the second consisting of the actual text of the list element.
Because the name of the command and the keyword are passed to the choice program, it is possible to write one system-wide choice program to accommodate any parameter in any command-not something I'd recommend. But it does open the door to some sophisticated possibilities.
To illustrate the use of choice programs, let's create a salesperson file (SLSPRSN, 3) and load three fictitious salespersons: MOE, LARRY and CURLY. You can enter these records with the Update Data (UPDDTA) command, or using SQL. I have also included a command (DSPSLSHST, 4) and the choice program (SLSI, 5). The SLSI choice program is tied to the SLSI command parameter using the CHOICEPGM keyword. The SLSI parameter must also include CHOICE(*PGM). This means that the choice text should be obtained from a program-the program SLSI-named in CHOICEPGM.
To illustrate the use of choice programs, let's create a salesperson file (SLSPRSN, Figure 3) and load three fictitious salespersons: MOE, LARRY and CURLY. You can enter these records with the Update Data (UPDDTA) command, or using SQL. I have also included a command (DSPSLSHST, Figure 4) and the choice program (SLSI, Figure 5). The SLSI choice program is tied to the SLSI command parameter using the CHOICEPGM keyword. The SLSI parameter must also include CHOICE(*PGM). This means that the choice text should be obtained from a program-the program SLSI-named in CHOICEPGM.
When writing a choice program, begin by deciding on a good program name. This may seem like an insignificant starting point, but putting some thought into this step will pave the way for much smoother cruising in the future. The actual parameter keyword might be a good choice.
Under the Covers
How does this work, then? When you prompt for the DSPSLSHST command, the command prompter realizes that it needs to get the choice text from program SLSI. It therefore calls SLSI, automatically passing it the correct information in the input parameter (command name, parameter keyword and the constant 'C'). I'd like to emphasize that this occurs automatically-you've done nothing but prompt for the command.
If you then place the cursor at the SLSI parameter and press F4, the choice program is activated again-this time to build the list of permissible values. The command prompter calls SLSI automatically, passing the command name, parameter keyword and this time the constant 'P' to the choice program's input parameter.
The choice program needs to read the salesperson file, SLSPRSN, so it declares it with the Declare File (DCLF) command (see 5). It also declares a few variables it needs. The CHGVAR that follows extracts the 'C' or 'P' that directs the choice program to build either the choice text or the list of permissible values.
The choice program needs to read the salesperson file, SLSPRSN, so it declares it with the Declare File (DCLF) command (see Figure 5). It also declares a few variables it needs. The CHGVAR that follows extracts the 'C' or 'P' that directs the choice program to build either the choice text or the list of permissible values.
The two IF-THEN structures in the program handle the two output possibilities listed earlier. If the choice program option is a "C" (choice text), we simply move the text into the return parameter and exit the program.
The other IF-THEN structure, with the embedded loop, is the real workhorse, since this section of code prepares a list of permissible values. Prior to entering the loop, we initialize the element length to the length of the field (SLSI), plus two bytes to account for the binary number that is used to contain the field length.
In the loop, it's a simple matter of concatenating the element length and the element itself to the existing list, with the first two bytes of the list being reserved for the list size. When we reach the end of the input file, or when the maximum output list size is exceeded (2000 bytes), we exit the loop. Then we put the number of elements into the first two bytes of the output parameter, using the %BIN CL function that is new to V2R2 (for more details, see "Binary Support in CL," MC, November 1992). When the program ends, it returns a list of permissible values to the command prompter.
Play It Again, Sam
This sample program has purposely been written for quick and easy "cloning." I use a PC-based editor that allows me to recall program templates such as this program, and I can create a choice program for a field in under five minutes! That's a small development-time price to pay for a major gain in ease of use. And by using a choice program, you give your commands added flexibility. You also give your programmers a break, for they won't have to keep maintaining hard-coded lists in the CDO source.
Don Schenck is a programmer/analyst at Cross Pointe Paper Corp. in West Carrollton, Ohio.
Add Dynamic Choices to Commands
Figure 1 Second-level Prompt Support
Specify Value for Parameter SLSI Type choice, press Enter. Type . . . . . . . . . . . . . : CHARACTER Salesperson id . . . . . . . . . __________ CURLY LARRY MOE F3=Exit F5=Refresh F12=Cancel F13=How to use this display F24=More keys
Add Dynamic Choices to Commands
Figure 2 Choice Program Parameters
Choice programs must have two parameters. Because the choice program receives data through the first parameter and returns data through the second parameter, we can call the parameters the input and the output parameters. Input parameter (*CHAR 21), passed from the command processor to the choice program can be broken down as follows: Position Description 1 - 10 command name; in our example, DSPSLSHST 11 - 20 keyword name; in our example, SLSI 21 - 21 prompting level: 'C' = choice text requested 'P' = permissible values list requested Output parameter (*CHAR 2000), returned to the command processor from the choice program, can have two formats. o For choice text, a 30-byte string is returned. The string may be longer than 30 bytes; only the first 30 are used. o For permissible values: nnbbaaaaaaaaaabbaaaaaaaaaabbaaaaaaaaaabbaaaaaaaaaa ... where nn = number of elements in a two-byte binary number bb = length of following element in a two-byte binary number aaaaaaaaaa = the element text For example: 030ACURLY 0ALARRY 0AMOE ... (unused, up to 2000 bytes) where x'03' indicates that there are three permissible values x'0A' (repeated) indicates that each value has a length of 10
Add Dynamic Choices to Commands
Figure 3 Physical File SLSPRSN
A R SLSPRSNR * A SPSLSI 10A COLHDG('SALESPERSON' 'ID') A SPNAME 50A COLHDG('SALESPERSON' 'NAME') A SPTERR 7P 0 COLHDG('TERRITORY' 'ID') * A K SPSLSI
Add Dynamic Choices to Commands
Figure 4 Command DSPSLSHST
DSPSLSHST: CMD PROMPT('Display Sales History') PARM KWD(SLSI) TYPE(*CHAR) LEN(10) CHOICE(*PGM) + CHOICEPGM(SLSI) PROMPT('Salesperson ID') PARM KWD(BGNDATE) TYPE(*DATE) CHOICE('MMDDYY + format') PROMPT('Beginning date') PARM KWD(ENDDATE) TYPE(*DATE) CHOICE('MMDDYY + format') PROMPT('Ending date')
Add Dynamic Choices to Commands
Figure 5 Choice Program SLSI
SLSI: + PGM PARM(&INPUTPARM &OUTPUTPARM) DCL VAR(&BINWORK) TYPE(*CHAR) LEN(2) DCL VAR(&CHOICETXT) TYPE(*CHAR) LEN(30) VALUE('A valid + salesperson ID') DCL VAR(&ELEMENTLEN) TYPE(*DEC) LEN(2 0) DCL VAR(&ELEMENTS) TYPE(*DEC) LEN(2 0) VALUE(0) DCL VAR(&FLDLENGTH) TYPE(*DEC) LEN(2 0) VALUE(10) DCL VAR(&INPUTPARM) TYPE(*CHAR) LEN(21) DCL VAR(&OFFSET) TYPE(*DEC) LEN(4 0) VALUE(3) DCL VAR(&OUTPARMLEN) TYPE(*DEC) LEN(4 0) VALUE(2) DCL VAR(&OUTPUTPARM) TYPE(*CHAR) LEN(2000) DCL VAR(&PGMOPTION) TYPE(*CHAR) LEN(1) DCLF FILE(SLSPRSN) CHGVAR VAR(&PGMOPTION) VALUE(%SST(&INPUTPARM 21 1)) IF COND(&PGMOPTION *EQ 'C') THEN(DO) CHGVAR VAR(&OUTPUTPARM) VALUE(&CHOICETXT) GOTO CMDLBL(PGMEND) ENDDO ELSE CMD(IF COND(&PGMOPTION *EQ 'P') THEN(DO)) CHGVAR VAR(&ELEMENTLEN) VALUE(&FLDLENGTH + 2) LOOP: + RCVF MONMSG MSGID(CPF0864) EXEC(DO) GOTO CMDLBL(EXITLOOP) ENDDO CHGVAR VAR(&ELEMENTS) VALUE(&ELEMENTS + 1) CHGVAR VAR(%BIN(&BINWORK)) VALUE(&FLDLENGTH) CHGVAR VAR(%SST(&OUTPUTPARM &OFFSET &ELEMENTLEN)) + VALUE(&BINWORK *CAT &SPSLSI) CHGVAR VAR(&OFFSET) VALUE(&OFFSET + &ELEMENTLEN) CHGVAR VAR(&OUTPARMLEN) VALUE(&OUTPARMLEN + &ELEMENTLEN) IF COND(&OUTPARMLEN *GT 2000) THEN(GOTO CMDLBL(EXITLOOP)) GOTO CMDLBL(LOOP) ENDDO EXITLOOP: + CHGVAR VAR(%BIN(&OUTPUTPARM 1 2)) VALUE(&ELEMENTS) PGMEND: + ENDPGM
LATEST COMMENTS
MC Press Online