We have been able to create our own commands, I believe, since the AS400 was first launched. Why would I want to create my own commands?

I create them just for ease of use. In my opinion it is easier to remember:

ITTOOLS/ITTOOLS

Than this:

CALL ITTOOLS/ITT001

For a command I just need two things:

A command object (type = *CMD ) A program object that is called by the command. This can be written in any IBM i programming language.

I can have a "validity checking program" too to validate the information input into the command, but it is optional.

I have spend hours having spirited discussions with some programmers when they ask: "Where is the display file?" There is no display file, the user interface for the command is generated when it is compiled.

Let me start with the simplest command, one that requires no parameters, it just calls the "command processing program". The source member for this command, source type CMD , contains just one line:

01 CMD PROMPT('Start IT Tools')

All commands require the CMD statement. The prompt text is what is displayed when your prompt the command with the F4 key.

This command is going to display the main menu, ITTMENU1 , from the IT tools library, ITTOOLS . The CL program that is called is simple:

01 PGM 02 ADDLIBLE LIB(ITTOOLS) POSITION(*LAST) 03 MONMSG MSGID(CPF0000) 04 GO MENU(ITTOOLS/ITTMENU1) 05 RMVLIBLE LIB(ITTOOLS) 06 ENDPGM

The Create Command command, CRTCMD , is used to compile the command. If you are using PDM you can just put "14" next to the command's member and press Enter.

Create Command (CRTCMD) Type choices, press Enter. Command . . . . . . . . . . . . > ITTOOLS Library . . . . . . . . . . . > ITTOOLS Program to process command . . . > ITT0001 Library . . . . . . . . . . . > ITTOOLS Source file . . . . . . . . . . > TOOLSRC Library . . . . . . . . . . . > ITTOOLS Source member . . . . . . . . . *CMD Threadsafe . . . . . . . . . . . *NO

I changed the "program to process command" from the command's default, ITTOOLS , to the name of the program I want to be called, ITT0001 . I have chosen to hard code the library names. By doing this I do not need to have the library ITTOOLS in my library list when I execute this command.

I don't need any parameters for this command I just type:

ITTOOLS/ITTOOLS

All I want to happen is the menu ITTMENU1 to be displayed.

The create command does not validate if the program the command will call exists. Be careful to make sure to enter the correct name of the program, or you are going to get unexpected results.

My next example is a command with just one parameter, the name of a library.

01 CMD PROMPT('Do something with a library') 02 PARM KWD(LIBRARY) TYPE(*NAME) LEN(10) + MIN(1) PROMPT('Library')

PARM is used to define the command's parameters.

KWD is the keyword the command's parameter will be known as.

TYPE as this parameter is going to be the name of something I have made it a *NAME . I explain below what happens if I had defined it as *CHAR .

LEN is self explanatory, this parameter can only be a maximum of ten characters.

MIN and a minimum of one character.

PROMPT is the text for the parameter.

When I compiled this command I left the library names as *LIBL .

Create Command (CRTCMD) Type choices, press Enter. Command . . . . . . . . . . . . > TESTCMD Library . . . . . . . . . . . > MYLIB Program to process command . . . > TESTPGM Library . . . . . . . . . . . > *LIBL Source file . . . . . . . . . . > MYSRC Library . . . . . . . . . . . > *LIBL Source member . . . . . . . . . *CMD Threadsafe . . . . . . . . . . . *NO

Having successfully compiled when I prompt my command I see.

Library (TESTCMD) Type choices, press Enter. Library . . . . . . . . . . . . Name

If I had define this parameter as *CHAR rather than Name being displayed to the right of the parameter field the words 'Character value' would have displayed instead. In my opinion that is not as obvious to the user what should be entered.

If I press F11 to display the keywords for the command it now looks like.

Library (TESTCMD) Type choices, press Enter. Library . . . . . . . . . . . . LIBRARY

How about I make this a little more complicated. In this example I have a file and library, I want to library to "belong" to the file.

01 CMD PROMPT('File & library') 02 PARM KWD(FILE) TYPE(Q1) MIN(1) PROMPT('File') 03 Q1: QUAL TYPE(*NAME) LEN(10) MIN(1) 04 QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) + SPCVAL((*LIBL)) PROMPT('Library')

Line 2: Rather than have *NAME I have used a name in the TYPE . This name refers to a "Qualifier definition". I can use the same qualifier name in more than one PARM .

Line 3: The Qualifier definition starts with the label that is its name, in this case Q1 . All I have to do here is just the minimum: type, length, and minimum length. All the following QUAL are included in Q1 until there is another Qualifier definition with a label, or the end of source member.

Line 4: This QUAL is used to define the parameter for the library, that "belongs" to the file name. Here I have given a default, DFT , and as it is a special value (it starts with an asterisk) I have to include it in a list of special values, SPCVAL .

After compiling the command when I prompt it I see that the library "belongs" to the file name.

File & library (TESTCMD) Type choices, press Enter. File . . . . . . . . . . . . . . Name Library . . . . . . . . . . . *LIBL Name, *LIBL

I did not want to show what the called program looks like for the previous example, library only, as it was too simple. This time I do want to show how the command passes the library and file name.

01 PGM PARM(&FILELIB) 02 DCL VAR(&FILELIB) TYPE(*CHAR) LEN(20) 03 ENDPGM

The called program has a parameter variable for each of the command's parameters. In this case the file and library names were contained in one parameter, therefore, they are passed as one 20 long character variable. If I put a debug statement in this CL program I can see that the file and library are in the one variable, the file starting at the first position and ten long, the library starting at the eleventh position and ten long.

&FILELIB = 'FILE1 MYLIB '

The called program could just as well be in RPG.

01 **free 02 ctl-opt main(Main) ; 03 dcl-pr Main extpgm('TESTPGM') ; 04 *n char(20) ; 05 end-pr ; 06 dcl-proc Main ; 07 dcl-pi *n ; 08 FileLib char(20) ; 09 end-pi ; 10 return ; 11 end-proc ;

In this RPG program I used a Main procedure with a procedure interface, rather than a fixed format parameter list.

We have all seen those commands with a list of values next to them, well this is how I do it.

01 CMD PROMPT('File & library') 02 PARM KWD(SPACE) TYPE(Q1) MIN(1) PROMPT('File') 03 Q1: QUAL TYPE(*NAME) LEN(10) MIN(1) 04 QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) + SPCVAL((*LIBL)) PROMPT('Library') SPCVAL((*LIBL)) PROMPT('Library') 05 PARM KWD(NUMBER) TYPE(*DEC) LEN(1) RSTD(*YES) + DFT(1) VALUES(1 3 5 7 9) MIN(0) + PROMPT('Number')

Lines 1 – 4: Are the same as the previous example.

Line 5: The parameter is numeric, TYPE(*DEC) , with a length of 1. The allowed values are contained in the values, I also need to restrict the values to those in the list, RSTD(*YES) . As I have given a default, the minimum length is zero, as if no value is given for this parameter the default is used.

After compiling the command now look like this:

File & library (TESTCMD) Type choices, press Enter. File . . . . . . . . . . . . . . > NOT_A_FILE Name Library . . . . . . . . . . . > QTEMP Name, *LIBL Number . . . . . . . . . . . . . 1 1, 3, 5, 7, 9

When I press F4 on the "Number" parameter, I can see the list of allowed values. This did not require any additional programming.

Specify Value for Parameter NUMBER Type choice, press Enter. Number . . . . . . . . . . . . . 1 1 3 5 7 9

The values in the command validates like the values keyword does in DDS. If, for example, I enter "6" I receive the following message at the bottom of my screen:

'6 ' not valid for parameter NUMBER.

This simple validation required no additional programming.

To include everything I want to discuss about creating command would make this post too long, therefore, the rest of what I want to discuss is in the part two.

This article was written for IBM i 7.3, and should work for earlier releases too.