Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 75

Basic AS/400 Tips

1.Data Areas:

Data Areas are chunks of memory to hold a few control values. A typical use is to keep track of
the last invoice number for a system.

To create a data area, use the command CRTDTAARA (Create Data Area). For example, to
create a 100-character data area named LASTINV#:

CRTDTAARA DTAARA (MYLIB/LASTINV#) TYPE (*CHAR) LEN (100)


Now, load the first 10 positions with the value "AA12345678" with the CHGDTAARA (Change
Data Area) command
CHGDTAARA DTAARA (QTEMP/LASTINV# (1 10)) VALUE ('AA12345678')
Look at the value of the data area with DSPDTAARA (Display Data Area):
DSPDTAARA MYLIB/LASTINV#

A CL program can retrieve the value with RTVDTAARA. An RPG program uses the "IN" operation
to retrieve the value and the "OUT" operation to change it.

There is a special Data Area known as the LDA (Local Data Area). It is 1024 characters and is
associated with a job. So, any display session has an LDA associated with it. Not only that,
when a job is submitted to run in batch, the LDA gets sent with the job so the batch job can
read the LDA of the display session that submitted it.

View and change your LDA by using *LDA instead of a data area name:

DSPDTAARA *LDA
CHGDTAARA DTAARA (*LDA (1 10)) VALUE ('AA12345678')
Using the LDA is considered by many to be an obsolete style. Older programs use the LDA to
store and pass parameters.

2.Reading Files created by QUERY/400:

When QUERY/400 creates a database, it gives the file and the record of the file the same
name. RPG will not compile if the file name and record name are the same.
So, you must rename the record. For example, if you are reading a file named QRYFIL and that
file was created by QUERY/400, you need to rename the record name to anything unique... in
this case QRYREC

RPG/400

FMT FX .....FFilenameIPEAF........L..I........Device+......KExit++Entry+A....U

0061.00 FQRYFIL IF E DISK A


0062.00 F QRYFIL KRENAMEQRYREC

RPG/IV

FMT FX FFilename++IPEASF.....L.....A.Device+.Keywords+++++++++++++++++++++++++

1
0116.00 FQRYFIL IF E DISK
0117.00 F RENAME(QRYFIL:QRYREC)

or simply

0116.00 FQRYFIL IF E DISK RENAME (QRYFIL:QRYREC)

3.Relationship Between Libraries, Files & Members:

On the AS/400 every file is in a library. The data in the file is actually stored in individual
members. Typically, a file has only one member and it has the same name as the file.

When you use commands to work with files, there is a parameter that gives you the ability to
choose which member to use. The default for this parameter is *FIRST. So you rarely actually
specify the member name.
So, the data is in a member, which is in a file, which is in a library.

Imagine a sheet of paper with a spreadsheet printed on it. The lines on the spreadsheet are
like the records. If you put only one sheet of paper in a file folder and you put that folder in a
cabinet, if would be similar to the AS/400 file structure:

Cabinet -----> Library

File Folder -----> File (or database file)

Sheet of Paper -----> Member of the file

Data on the Sheet -----> Records in the Member

If you want to see the data in a file, you are actually wanting to see the data in the first and
only member of the file. This is why the command to display the data in a file is not DSPF or
DSPFIL.
The command to display the data in a member of a file is:
DSPPFM - Display Physical File Member
The term physical file refers to the records in the member that are in arrival sequence. With
the database facility, you can build logical views (indexes) to select only certain fields and only
certain records and to resequence the records.
However, there is no Display Logical File Member command. You usually simply view the data
using DSPPFM and use your imagination to picture the logical data. In a while, there will be a
tip for seeing the logical file data.

4.Looking at Printer Output:

When you print data on the AS/400 the printer output is written to a printer spool file.
Typically, this is the default printer specified in your user profile.

To see your printer output, use the command Work with Spool File:
WRKSPLF
By using the command this way you are actually specifying:
WRKSPLF SELECT(*CURRENT)
You can look at another user's spool file (if you have authority) by using:

2
WRKSPLF USERXXX
The WRKSPLF command shows a list of all spool files in your queue. It will look like:

Work with All Spooled Files

Type options, press Enter.


1=Send 2=Change 3=Hold 4=Delete 5=Display 6=Release
8=Attributes 9=Work with printing status

Device or Total
Opt File User Queue User Data Sts Pages
FXR001 CHAPGMR P1 RDY 14
FXR001 CHAPGMR P1 RDY 14
If the list is too big for one page, use the PAGE DOWN key to scroll down.

To look at the output file, key a 5 next to the file and hit enter.

Use the following information to move around in your printer file:

Use PAGE DOWN and PAGE UP


F20 to shift to the right (SHIFT and F8)
F19 to shift back left (SHIFT and F7)
B in the CONTROL field at the top and ENTER to go to bottom of file
T in the CONTROL field at the top and ENTER to go back to the top
Key a value in the field FIND and hit F16 (SHIFT and F4) to search for the value
W12 in the CONTROL field to shift the Window to column 12
1087 in the CONTROL field to go to line 1,087
+200 in the CONTROL field to go forward 200 lines

When you are done viewing your printer output, hit F3 to return to the spool file list. Key 4
next to the file and hit ENTER to delete it.

5.Use DSPPFM and RUNQRY similar to TYPE command in DOS:

To get a quick look at the records in a physical file, use the Display Physical File Member
command (DSPPFM).
To see the unformatted data in the file PR001:

DSPPFM PR001

or to see the file PR001 that is in the library MYLIB


DSPPFM MYLIB/PR001
Use F20 (shift and F8) to scroll right, F19 to scroll left.
Key B (for bottom) in the CONTROL field at the top and hit ENTER
to go to the end of the file. Or, use T for top to return to the top.

To get a formatted look at the records, use the Run Query (RUNQRY) command. Essentially,
this command builds a query to view the data:

RUNQRY QRYFILE(PR001)

3
or key in RUNQRY, hit F4 and fill in the file name. This command displays the data in columns
with the field names. It also formats the data, including packed numeric fields that look like
garbage with DSPPGM command.

6.Analyze Disk Space:

The AS/400 has a very "easy-to-use" disk analysis tool.

GO DISKTASKS to see it.


That shows you a menu like this:

1. Collect disk space information


2. Print disk space information

10. Work with libraries


11. Work with folders
12. Work with objects by owner

The first step is to run selection 1 to collect disk information. This starts a job that may run for
15 minutes or so.
When the job is done, use selection 2 to print reports from the disk info. The most interesting
are:

1. Print all libraries sorted from largest to smallest without file details.
2. Print details of any library to see each file and how much space it is using.

7. Display files using SDA

When changing a display file using SDA (Screen Design Aid), the added fields are placed at the
bottom of the DDS program when it is saved and compiled. This can make it difficult for the
user to easily locate the changed fields. To re-sort the fields before exiting SDA, hit the F4 key,
then F6, and the statements will be placed in order.

8. Changing Field Names

There are times when you may have the same field name in different programs with varying
lengths. To get a clean compile, it may be necessary to use the following I-spec coding.

FMT I IFilename++SqNORiPos1+NCCPos2+NCCPos3+NCC..............................

0029.00IACTMAS
0030.00I CALL24 XALL24

9. Customizing the AS/400 sign-on display

In order to customize the AS/400 sign-on display, you must first create the DDS that you want
to use for your sign-on display. There are 2 ways to accomplish this: modifying IBM's sign-on
display, using member QDSIGNON in the physical file QGPL/QDDSSRC; or by writing your own
DDS and copying the fields in QDSIGNON. In either instance, all IBM fields must remain in the

4
same order in the display file, but you can reposition them on the display. The only IBM field
that can be modified is the UBUFFER field, which is the last field. The 128-byte field can be
modified with input/output fields thus allowing users to input data into the sign-on displays.
The UBUFFER fields can appear anywhere on the display, but they must follow the IBM fields in
the display file.

Compile the display file. Once the display is created, be sure to test the new sign-on display on
one subsystem or on a test version of a controlling subsystem. By issuing the CHGSBSD (Change
Subsystem Description) command, and specifying the new display file on the SGNDSPF
parameter, the subsystem will now use the new sign-on display. Once testing is complete, you
can change the subsystem descriptions for all the subsystems for which you want to use the
modified sign-on display.

For example, for subsystem QINTER, issue the command CHGBSD QINTER SGNDSPF(your
library/your file)

10. Listing Library Information

In this program, you will find 2 CL programs and 1 RPG-ILE program that will create a file
named ALLFILES. You can write a query on this file and sort on object size or last date changed
to help identify good candidates for deletion.

--------------------------------------------------------------------------------

Figure 1 - CL Program to Display Libraries - UTC001

FMT ** ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7


*************** Beginning of data *************************************
0001.00PGM
0002.00/* */
0003.00 DLTF FILE(your library/ALLFILES)
0004.00 MONMSG MSGID(CPF0000)
0005.00 DSPOBJD OBJ(QSYS/*ALL) OBJTYPE(*LIB) +
0006.00 OUTPUT(*OUTFILE) OUTFILE(your library/ALLLIBS)
0007.00/* */
0008.00 CALL UTR0001
0009.00/* */
0010.00ENDPGM
****************** End of data ****************************************

Figure 2 - CL Program to Create List of Files in Libraries - UTC002

FMT ** ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7


*************** Beginning of data *************************************
0001.00PGM PARM(&LIBNAME)
0002.00/* */
0003.00 DCL VAR(&LIBNAME) TYPE(*CHAR) LEN(10)
0004.00 DSPOBJD OBJ(&LIBNAME/*ALL) OBJTYPE(*FILE) +

5
0005.00 OUTPUT(*OUTFILE) OUTFILE(QTEMP/ALLFILES)
0006.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(EOJ))
0007.00/* */
0008.00 CHKOBJ OBJ(your library/ALLFILES) OBJTYPE(*FILE)
0009.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(FRSTTIME))
0010.00 CPYF FROMFILE(QTEMP/ALLFILES) +
0011.00 TOFILE(your library/ALLFILES) MBROPT(*ADD)
0012.00 GOTO EOJ
0013.00/* */
0014.00FRSTTIME:
0015.00 CPYF FROMFILE(QTEMP/ALLFILES) +
0016.00 TOFILE(your library/ALLFILES) MBROPT(*ADD) +
0017.00 CRTFILE(*YES)
0018.00EOJ:
0019.00ENDPGM
****************** End of data ****************************************

Figure 3 - RPG-ILE Program Run by CL Program to List Library and Information - UTR001

FMT * *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+.


*************** Beginning of data *************************************
0001.00***************************************************************
0002.00** System Name: **
0003.00** **
0004.00** Program Name: **
0005.00** **
0006.00** Program Text: Read file ALLLIBS and list all libraries **
0007.00** and last date used > 6 months **
0008.00** **
0009.00** Date Written: **
0010.00** **
0011.00** Written By: **
0012.00***************************************************************
0013.00 *
0014.00FALLLIBS IF E DISK
0015.00 *
0016.00D Library S 1
0017.00 *---------------------------------------------------------------------
0018.00C Read ALLLIBS 90
0019.00 *
0020.00C DoW *IN90 = *Off
0021.00C ExSr CheckLib
0022.00 *
0023.00C Read ALLLIBS 90
0024.00C EndDo
0025.00 *
0026.00C Eval *INLR = *On
0027.00C Return
0028.00 *---------------------------------------------------------------------
0029.00 * Subroutine to format PATNUM
0030.00 *---------------------------------------------------------------------

6
0031.00C CheckLib BegSr
0032.00 *
0033.00C MoveL ODOBNM Library
0034.00C If Library <> 'Q' and
0036.00 *
0037.00C Call 'UTC0002'
0038.00C Parm ODOBNM
0039.00C EndIf
0040.00 *
0041.00C EndSr
****************** End of data ****************************************

11. Using RENAME in the File Specs

There are times when you will be writing an RPG program that uses both physical and logical
files. When using both a physical file and logic file, both having the same record name, and
updating or writing to records, the keyword RENAME must be used to differentiate between
which record name is to be updated. Figures 1 and 2 show the file specs for RPG and RPG ILE.

Figure 1 - Using RENAME in RPG

FMT FX .....FFilenameIPEAF........L..I........Device+......KExit++Entry+A....U
0059.00 FTCLTRNK1IF E K DISK
0060.00 FTCPRACY UF E K DISK
0061.00 FTCPRACY1O E DISK A
0062.00 F RACY KRENAMERA1
0063.00 FTCPRACY2O E DISK A
0064.00 F RACY KRENAMERA2
0065.00 FTCLRACY E DISK A U
0066.00 F RACY KRENAMERA3

Figure 2 - Using RENAME in RPG ILE

FMT FX FFilename++IPEASF.....L.....A.Device+.Keywords+++++++++++++++++++++++++
0114.00 FTCLTRNK1 IF E K DISK
0115.00 FTCPRACY UF E K DISK
0116.00 FTCPRACY1 O A E DISK
0117.00 F RENAME(RACY:RA1)
0118.00 FTCPRACY2 O A E DISK
0119.00 F RENAME(RACY:RA2)
0120.00 FTCLPRACY O A E DISK USROPN
0121.00 F RENAME(RACY:RA3)

12.Make a CL Job to Send Data using FTP

Create a physical file of 50 to 80 characters to hold the FTP commands. Name it something like
FTPIN.

Then use DFU to enter the FTP commands. The first record should be your user ID and
password. Then the following records have the remaining FTP commands.

7
For example, to sign on as davidmount with password of as400, then change directory to
UPLOAD and then PUT a file, the records should look like:

davidmount as400
cd UPLOAD
put xyzzy.txt abc.csv
quit

You may also create a file for the output. Say... FTPOUT

Then, the CL to execute overides the specially named INPUT file and OUTPUT file.

The CL looks like:

OVRDBF FILE(INPUT) TOFILE(FTPIN)


OVRDBF FILE(OUTPUT) TOFILE(FTPOUT)
FTP '123.12.12.123'

What would normally be displayed on the screen as output is written to the FTPOUT file. This is
very powerful. You can (with some effort), use FTP to get a directory of the files on a remote
system. Then, you can read thru the directory (it's in the FTPOUT file) and then build other FTP
scripts to GET specific files and even delete specific files.
In a related matter, to check to see if a transfer is complete, you must read through the
FTPOUT file to see if you find the phrase "Transfer complete" in a record somewhere.

OS/400 will NOT return an error if you do not successfully transfer the data. It will simply write
the output display to the OUTPUT file and consider this a successful execution of the FTP.

13.Brief Overview of Using Embedded SQL with RPG

A cursor is defined in the RPG or RPGLE source code. Then FETCH is used in a loop to access
the data from the file. In this loop to process the fetched data, RPG/RPGLE code can be used
and the output can be sent to the spool or to the display.

The following are the steps in sequence.

1) Declare the SQL Communication Area. This is a must.

C/EXEC SQL
C+ INCLUDE SQLCA
C/END-EXEC

2) SQL Cursor Declaration

C/EXEC SQL
C+ DECLARE GETREC CURSOR FOR SELECT XABCDE, XFGHIJ, XKLMN, FROM
C+ XFILE WHERE
C+ XSTRIN LIKE :STRING
C/END-EXEC
:STRING IS A VARIABLE

3) SQL FETCH Subroutine Declaration

C Fetch begsr

8
C
C/EXEC SQL
C+ FETCH NEXT FROM GETREC INTO :XABCD, :XEFGH
C/END-EXEC
ENDSR

4) SQL Close Subroutine Declaration (To Close the Cursor)

C Close begsr
C
C/EXEC SQL
C+ CLOSE GETREC
C/END-EXEC
C endsr

5) * SQL Open Subroutine Declaration (To Open the Cursor)

C Open begsr
C
C/EXEC SQL
C+ OPEN GETREC
C/END-EXEC
C endsr

First step in main process would be to open the cursor

EXSR OPEN
sqlcod doune 0
exsr Fetch
rpg code

rpg code
enddo
exsr close

The source type for RPG/400 with embedded SQL is SQLRPG, with ILE it is SQLRPGLE.

14. Viewing the Job Log for an Interactive Session

When you are signed on to an AS400, you can view your job log by keying the command
DSPJOBLOG. Then you must hit F10 (to see details) and use PAGE UP to see the log.

15.Preventing Third Party Relay Spam on Your iSeries AS400 SMTP Server

If you have the SMTP (e-mail) server running on your iSeries / AS400, you may have had the
misfortune of learning about third party relay spammers. These are people who use your e-mail
server to deliver their spam. Not only will this overload your server, it will inevitably get your
domain listed as one that sends spam. With release V4R4, OS/400 provides a way to prevent
third party relay of mail. V4R3 has a PTF for this.

The method to do this involves defining the TCP/IP addresses that may send e-mail on your
server. In my case, it is the specific address of my AS/400. In your case, it may include
everyone on your network.

9
Create a source physical file in library QUSRSYS named QTMSADRLST. The file must be created
with CCSID value set to "500".

Start PDM on this new source file and create a new member named ACCEPTRLY. For each IP
address that should be able to send e-mail, you add a line to this file member. Each line will
contain an IP address and an address mask.

I use an entry like this:

66.12.223.253 255.255.255.255

An entry like this would allow any address starting with 66.12.223 to send e-mail:

66.12.223.1 255.255.255.0

Then end and restart your SMTP server.

16.Debugging RPG ILE with the iSeries / AS400 Debugger STRDBG

The AS/400 has a built in debugging tool, though very powerful, it is not completely intuitive.
Sometimes you may find yourself in need of a procedure that can help you locate program
errors that you cannot visually find by looking at your program. RPG-ILE's program debugger
can be very useful in these situations. It allows you to trace a program as it is executing,
stepping through a program a statement at a time, or stopping at "breakpoints" that you
designate so you can see the values of fields at that point of execution. Follow the steps below
to start the "debugging" mode for your programs.

First, you must compile the program in an appropriate mode. Do this from PDM by keying a 14
next the program source and hitting F4.

Your screen should look like this:

Create Bound RPG Program (CRTBNDRPG)

Type choices, press Enter.

Program . . . . . . . . . . . . > LXR001 Name, *CTLSPEC


Library . . . . . . . . . . . > T40 Name, *CURLIB
Source file . . . . . . . . . . > QRPGLESRC Name, QRPGLESRC
Library . . . . . . . . . . . > T40 Name, *LIBL, *CURLIB
Source member . . . . . . . . . > LXR001 Name, *PGM
Generation severity level . . . 10 0-20
Text 'description' . . . . . . . *SRCMBRTXT

Default activation group . . . . *YES *YES, *NO

Now, hit F10 to get more options. Key in *LIST as the value for "Debugging View".
The screen should look like:

Create Bound RPG Program (CRTBNDRPG)

10
Type choices, press Enter.

Program . . . . . . . . . . . . > LXR001 Name, *CTLSPEC


Library . . . . . . . . . . . > T40 Name, *CURLIB
Source file . . . . . . . . . . > QRPGLESRC Name, QRPGLESRC
Library . . . . . . . . . . . > T40 Name, *LIBL, *CURLIB
Source member . . . . . . . . . > LXR001 Name, *PGM
Generation severity level . . . 10 0-20
Text 'description' . . . . . . . *SRCMBRTXT

Default activation group . . . . *YES *YES, *NO

Additional Parameters

Compiler options . . . . . . . . *XREF, *NOXREF, *GEN...


+ for more values
Debugging views . . . . . . . . *LIST *STMT, *SOURCE, *LIST...
Output . . . . . . . . . . . . . *PRINT *PRINT, *NONE

Now ENTER to compile your program. If this program calls other programs, you may want to
compile them in debug mode also.
Now it gets a little tricky. Start the debugging mode with the "Start Debug" for the program you
want to debug. In this case, the program is LXR001 so the command to use is STRDBG LXR001.
Key in STRDBG LXR001 and hit F14:

Start Debug (STRDBG)

Type choices, press Enter.

Program . . . . . . . . . . . . > LXR001 Name, *NONE


Library . . . . . . . . . . . *LIBL Name, *LIBL, *CURLIB
+ for more values
*LIBL
Default program . . . . . . . . *PGM Name, *PGM, *NONE
Maximum trace statements . . . . 200 Number
Trace full . . . . . . . . . . . *STOPTRC *STOPTRC, *WRAP
Update production files . . . . *NO *NO, *YES
OPM source level debug . . . . . *NO *NO, *YES
Service program . . . . . . . . *NONE Name, *NONE
Library . . . . . . . . . . . Name, *LIBL, *CURLIB
+ for more values

If your program updates or writes data to a file in a library that is defined as *PROD, you must
change the "Update production files" option to *YES. Then, hit ENTER.
The debugger now displays the source code of the program. You MUST define a breakpoint
where the debugger will actually start debugging. The easiest thing to do is to page down to
the first executable statement of the program. Put the cursor on that line of source code and
hit F6 to define that line as a breakpoint.

Now, hit F3 and you will return to the PDM menu.

Your session is now in "debug" mode. It will stay in "debug" mode until you end debug mode
with the command ENDDBG.

11
Finally, it is time to start running your program. Call the program from the command line. In
this case: CALL LXR001

The program will start running. The debug feature will display a listing of the program. The
display is showing that the breakpoint is about to execute. You can scroll up or down, position
the cursor on any field and hit F11. The debugger will display the value of the field.

Now hit F10 repeatedly to step through the source code. The line of code that is about to
execute will be highlighted.

Note that the debugger has the annoying habit of stepping through every field in each file that
is read or updated. To prevent this, add a "header" record as the first line of code in the
program. "Header" records are not required and not usually used. Use an "H" as the record type
with a value of "option(*nodebugio). That is, add this line to the beginning of your program:

H OPTION(*NODEBUGIO)

When you are finished debuggin, key ENDDBG to turn off the debugger.

To summarize:

1) Add this line to the beginning of your program: H OPTION(*NODEBUGIO)

2) Compile the program with Debug View set to *LIST

3) Start the debugger with the command: STRDBG pgmname (Update Production files *YES)

4) Put cursor on the first line that you want to see and hit F6. Exit with F3.

5) Call your program: CALL pgmname

6) Use F10 to step through the program. Use F11 to see values.

7) If you wish, set additional breakpoints and use F12 to run until the next breakpoint.

17. Debugging an RPG program in batch

Submit your program into batch and make sure it is held. Do this by either holding the job
queue that you are submitting the job to, or use the HOLD(*YES) option on the SBMJOB
command.

Use the WRKUSRJOB and display the job you with to debug with the display job option (5).

Write down the user name, job name and number.

Start a service job using STRSRVJOB entering the name, job name and number from the
previous step.

STRDBG PGM(YOURPGM) - Press F12 to exit the source display (Sorry, can't enter breakpoints
yet). Release your submitted job by releasing the job queue or the job itself.

A display will appear asking you to press F10 function key. Press F10 and you will be brought to
a command line.

12
Enter DSPMODSRC and enter your breakpoints. Leave source display and command line by
pressing F3 until you are back to the screen that asks you to press F10 to enter breakpoints.

Press Enter to start your job.

After that the job begins running and stops at the first breakpoint reached.

18.Viewing a Compiler Listing

To view the results of a program compiling, use the Work With Spool File command, WRKSPLF.

You will see a list of reports in your spool file. It will look like:

Device or Total
Opt File User Queue User Data Sts Pages
QSYSPRT AIRPGMR PRTDGM RDY 1
QPJOBLOG AIRPGMR QPRINT AIRNRA RDY 2
QSYSPRT AIRPGMR PRTDGM RDY 1
QSYSPRT AIRPGMR PRTDGM RDY 1
QPJOBLOG AIRPGMR QPRINT TQE07 RDY 2
QSYSPRT AIRPGMR PRTDGM RDY 1
QSYSPRT AIRPGMR PRTDGM RDY 1

Each line is the name of a report on your Spool File. The most recent reports are at the
bottom. Key a 5 next the report you want to view.
You should now be looking at the compiler listing. To quickly locate errors, key B (for bottom)
in the CONTROL field and hit ENTER. You are now looking at the bottom of the compiler report.

If your program compiled successfully, the last few lines will look like:

***** END OF FINAL SUMMARY ****


Program CMNR020 placed in library AIR. 00 highest severity. Created on
***** END OF COMPILATION*****

If not, it will look more like:

***** END OF FINAL SUMMARY


Compilation stopped. Severity 30 errors found in program.
***** END OF COMPILATION**

To find the errors, hit the PAGE UP key until you see:

***** END OF EXTERNAL REFERENCES **


5769RG1 V4R2M0 980228 RN IBM ILE RPG AIR/CMNR020
Message Summary
Msg id Sv Number Message text
*RNF7031 00 61 The name or indicator is not referenced.
*RNF7066 00 1 Record-Format name of Externally-Described file is not
*RNF7030 30 1 The name or indicator is not defined.
*RNF7503 30 1 Expression contains an operand that is not defined.
***** END OF MESSAGE SUMMARY ****

13
These are the errors that need correcting. Anything with severity level 00 is NOT an error.
To find the error, go to the top of the report. Do this by keying T in the CONTROL field and
hitting ENTER.

Then, key the error message ID in the FIND field. In this case, I keyed RNF7030 in the FIND
field. Then, hit F16 to search. Remember F16 is SHIFT / F4.

In my case, the errors look like:

*RNF7066 00 2 000200 Record-Format CUSREC not used for


*RNF7030 30 123 005200 The name or indicator SYSDTECC is
*RNF7503 30 123 005200 Expression contains an operand tha

The errors RMF7030 and RNF7503 need to be fixed. They are both related to sequence # 123 in
the compile listing which is line number 52.00 in the source file.
In my case, I misspelled a variable name. This caused 2 errors. Often, 1 error will cause more
than 1 error message.

19. Use CPYF Command Similar to COPY Command in DOS

One of the most powerful commands on the AS/400 is the Copy File command. To use it, key
CPYF and hit F4.

To copy the file ABC from MYLIB to ABCBKUP in MYLIB, fill in the screen like this:

Copy File (CPYF)

Type choices, press Enter.

From file . . . . . . . . . . . ABC


Library . . . . . . . . . . . MYLIB
To file . . . . . . . . . . . . ABCBKUP
Library . . . . . . . . . . . MYLIB
From member . . . . . . . . . . *FIRST
To member or label . . . . . . . *FIRST
Replace or add records . . . . . *NONE
Create file . . . . . . . . . . *YES
Print format . . . . . . . . . . *CHAR

Notice, the "Create File" option is *YES.


To copy ABCBKUP back to ABC and replace the existing file, change the "Replace or add
records" to *REPLACE and leave the "Create File" as *NO:

Copy File (CPYF)

Type choices, press Enter.

From file . . . . . . . . . . . ABCBKUP


Library . . . . . . . . . . . MYLIB
To file . . . . . . . . . . . . ABC
Library . . . . . . . . . . . MYLIB

14
From member . . . . . . . . . . *FIRST
To member or label . . . . . . . *FIRST
Replace or add records . . . . . *REPLACE
Create file . . . . . . . . . . *NO
Print format . . . . . . . . . . *CHAR

Hit F10 to see the 5 extra screens of options. Use PAGE DOWN to get to the different screens.
To copy only 100 records, key 100 in the "Copy to Record Number" parameter. Or, use the
"Number of records to copy" parameter.

To add data from the file ABC01 to ABC, use *ADD for "Replace or add records":

Copy File (CPYF)

Type choices, press Enter.

From file . . . . . . . . . . . > ABC01


Library . . . . . . . . . . . > MYLIB
To file . . . . . . . . . . . . > ABC
Library . . . . . . . . . . . > MYLIB
From member . . . . . . . . . . *FIRST
To member or label . . . . . . . *FIRST
Replace or add records . . . . . > *ADD
Create file . . . . . . . . . . > *NO
Print format . . . . . . . . . . *CHAR

20.Use WRKACTJOB to See What is Going On

To see all jobs running on your system, use the Work with Active Jobs command, WRKACTJOB.

Each sub-system will be displayed with the jobs running in it. Every terminal signed on the
system is a job. There are many system jobs running to do things like spool reports and service
Telnet and FTP.

The first sub-system listed is often QBATCH. This sub-system runs user submitted jobs.

The sub-system for on-line users is usually named QINTER. Most of the users signed on to your
system will have their job running here.

Put the cursor in a column and hit F16 (Shift-F4) to sort the display. To see the users that are
consuming most resources, put the cursor in the CPU% column and hit F16. To sort the users
alphabetically, move the cursor to the User column and hit F16.

Key a 5 next to a job to see its attributes. Key a 4 to end it.

21.Getting Help for Commands and Menu Selections

To get help for menu selections, key the number of the selection and then hit F1 instead of
ENTER.

To get help for a command, key the command, put the cursor on the command and hit F1.

15
To get prompting information for a command, key the command and then hit F4. If
"F10=ADDITIONAL PARAMETERS" is at the bottom of the screen, hit F10 to get prompts for all
keywords. You may need to PAGE DOWN to additional screens.

22. Job Scheduler

The AS/400 has an excellent job scheduler. It will submit any job at a pre-scheduled time.

Use the command Work With Job Schedule Entries, WRKJOBSCDE.

From the Job Schedule menu, hit F6 to add a job. Simply fill in the values to define when and
how often the job runs.

Use anything for the job name. The "Command to run" is what will be submitted.

To run a program named ABC001 from the PROD library every night at 3:00am:

Add Job Schedule Entry (ADDJOBSCDE)

Type choices, press Enter.

Job name . . . . . . . . . . . . nightlyjob


Command to run . . . . . . . . . call prod/ABC001
Frequency . . . . . . . . . . . *Weekly
Schedule date, or . . . . . . . *none
Schedule day . . . . . . . . . . *all
+ for more values
Schedule time . . . . . . . . . 3:00

The only surprise with the job scheduler is that it uses the default library list. So, in this case,
the job ABC001 might need to establish a correct library list as its first few commands.

23.Current Library, QGPL and QTEMP

In your library list, the first user library is the current library. The predecessor to the AS/400,
the System 38, did not have a current library concept. To allow for this, a special value
*CRTDFT is allowed.

The default value of the library parameter of some commands is *CURLIB. For example, if you
use the Create Physical File command, CRTPF and do not specify a destination library, the
system will create the file in your current library. But, if your current library is defined as
*CRTDFT, the system will create the file in QGPL. This library, the "General Purpose Library", is
similar to the root directory in a PC. That is, if the system does not know where to put
something, it will likely end up here.

System Administrators fight to keep garbage out of QGPL. For many administrators, the G in
QGPL stands for Garbage.

Another system supplied library is QTEMP. Every job has its own QTEMP libary. The library gets
cleared everytime the job ends. So, this is a great place to put truly temporary files.

16
24.Running Jobs in Batch or Background
Most AS/400's are configured so on-line sessions run in the subsystem named QINTER. Usually
these jobs are assigned a job priority of 30. This means that these jobs get serviced before any
jobs with a higher priority number.

For jobs that can run unattended, use the command to Submit Job. For example, if you have a
program that prints a report and it is named PRT100, submit the job to the batch subsystem
with this command:

SBMJOB CMD(CALL PRT100)

If you wish, use F4 to see the command options. Typically, this will submit the job to run in the
QBATCH subsystem with a job priority of 50. This means this job will be serviced only after all
the interactive or on-line jobs in the QINTER subsystem.

To run a query in QBATCH, use something like:

SBMJOB CMD(RUNQRY QR100)

When a job is submitted, it brings along the library list and the local data area of the job that
submitted it.

25. Creating a Data File

Generally, a file has to be defined before you can write records to it.

Sometimes, you may need a simple "flat" file with no field definitions. For that, the Create
Physical File command without DDS specifications will work. To create a file named FTPOUT
that is 100 characters in length:

CRTPF FILE(MYLIB/FTPOUT) RCDLEN(100)

The AS/400 actually creates a file named FTPOUT, a member named FTPOUT and a field of
length 100 that is named FTPOUT.

To make a database file, you use the DDS specifications. You must start the Programming
Development Manager and create a member with TYPE of PF (for physical file). Usually, this
goes in the object QDDSSRC.

The first line defines the record name. For a simple 3 field file:

A R CUSREC
A NAME 20A
A PHONE 10S 0
A STATUS 1A

Name the member in QDDSSRC the same as the desired file. In this case, I named it CUS.
Then, you must compile or create the file. In PDM you can do this with the option 14. When you
use option 14, you actually execute the command:

CRTPF FILE(MYLIB/CUS) SRCFILE(MYLIB/QDDSSRC) SRCMBR(CUS)

The AS/400 knows to use this command because you specified that this member is describing a
PF.

17
If you have wanted a key built on the PHONE field, the DDS would have been:

A R CUSREC
A NAME 20A
A PHONE 10S 0
A STATUS 1A
A K PHONE

26. Physical Files and Logical Files

Physical files hold the actual data of a database file. The data is written in arrival sequence.

Physical files are not required to have keyed fields. If a physical file has key fields, this is the
order that an RPG program will read the data if the File Spec in the program indicates to read
the data in keyed sequence.

Also, with a keyed field, an RPG program can CHAIN, SETLL, READE and READP.

A simple logical file is a different view of the physical file. It is actually a list of pointers to the
physical file. Most of the time, a logical file is nothing more than a way of accessing the
physical file with different key fields.

With the standard AS/400 supplied tools, it is hard to see the logical file. One way is to use the
copy file CPYF to copy the logical file to a new physical file. Then, look at the physical file... it
will be in the same order as the logical file.

The AS/400 Database is full featured. Logical files can join multiple files and select and create
new fields.

27. Creating a Logical File or Index

A logical file provides a different view of a physical file.

The most common and simplest use of logical files is to change the order of the data.

To define a logical file, you use the DDS specifications. You must start the Programming
Development Manager and create a member with TYPE of LF (for logical file). Usually, this goes
in the object QDDSSRC.

Here is how to make a logical file named CUS01 which orders the CUS physical file by name.

For simple logical files like this, the first line defines the record name of the physical file that
has the data. This line also has the PFILE function that names the physical file.

Then, add a K definition for each key file.

A R CUSREC PFILE(CUS01)
A*
A K NAME

Name the member in QDDSRC the same as the desired file. In this case, I named it CUS01.

18
Then, you must compile or create the file. In PDM you can do this with the option 14. When you
use option 14, you actually execute the command:

CRTLF FILE(MYLIB/CUS01) SRCFILE(MYLIB/QDDSSRC) SRCMBR(CUS01)

The AS/400 knows to use this command because you specified that this member is describing a
LF.
Add a SELECT spec to select only customers with STATUS of 'A'

A R CUSREC PFILE(CUS01)
A*
A K NAME
A S STATUS COMP(EQ 'A')

Or to omit records with a STATUS of 'D'


A R CUSREC PFILE(CUS01)
A*
A K NAME
A O STATUS COMP(EQ 'D')

An RPG program uses logical files almost identically to physical files. In this last example, an
RPG program that reads the file CUS01 would automatically bypass any records with STATUS of
D.

28. Command Line FTP

OS/400 has an FTP Client that works a lot like FTP from a MS-DOS command line.

From the command line enter either the command FTP or, the OS/400ized name, STRTCPFTP
and hit F4.

Fill in the IP address or the URL of the FTP server.

Use the standard FTP commands to put and get data.

When done, use QUIT as the FTP command.

29.Use Job Scheduler to Change Clock for Daylight Savings

The command to change the hour to 1:00 am on an AS/400 is:

CHGSYSVAL SYSVAL(QHOUR) VALUE('01')

To schedule this command to run at 2:00 am on October 27, use the job scheduler. Key in
WRKJOBSCDE

Then, hit F6 to add a new job. Fill in the values as:

Job name . . . . . . . . . . . . > FALLBACK Name, *JOBD


Command to run . . . . . . . . . > CHGSYSVAL SYSVAL(QHOUR) VALUE('01')
Frequency . . . . . . . . . . . *ONCE *ONCE, *WEEKLY, *MONT

19
Schedule date, or . . . . . . . 10/27/2002 Date, *CURRENT, *MONT
Schedule day . . . . . . . . . . *NONE *NONE, *ALL, *MON, *T
+ for more values
Schedule time . . . . . . . . . 02:00:00 Time, *CURRENT

I named my job FALLBACK and scheduled it to run once at 2:00 am on the day that we set the
clocks back.

30.Converting an AS/400 database file to a CSV file

You may find yourself in a situation where you want to run a Query on a file, save the
information to a database,and then convert that information to a Comma Separated Variable
(CSV) file. This is especially true when you need the data to be used in a "spread sheet" format
like Excel.

The simplest way to do this is to copy the information from the data file to your newly created
CSV file.

Enter this command:

CPYTOIMPF FROMFILE(*LIBL/DTAFIL) TOFILE(USER999/CSVPC)

Hit Enter, and then again 3 times and you have now created a Comma Separated Variable (CSV)
File.

Remember that you need a 'destination file' before you can use this command. To create a
'destination file', you will need to use the Create Physical File command. To create a file
named CSVPC that is 200 characters in length, type in the command:

CRTPF FILE(USER999/CSVPC)

Hit F4 to prompt the command, and type in the record length you need, for Member, be sure to
name it CSV.

Create Physical File (CRTPF)

Type choices, press Enter.

File . . . . . . . . . . . . . . > CSVPC Name


Library . . . . . . . . . . . > USER999 Name, *CURLIB
Source file . . . . . . . . . . QDDSSRC Name
Library . . . . . . . . . . . *LIBL Name, *LIBL, *CURLIB
Source member . . . . . . . . . *FILE Name, *FILE
Record length, if no DDS . . . . > 200 Number
Generation severity level . . . 20 0-30
Flagging severity level . . . . 0 0-30
File type . . . . . . . . . . . *DATA *DATA, *SRC
Member, if desired . . . . . . . > CSV Name, *FILE, *NONE
Text 'description' . . . . . . . *SRCMBRTXT

More...

20
F3=Exit F4=Prompt F5=Refresh F10=Additional parameters F12=Cancel
F13=How to use this display F24=More keys

Then hit F10 for Additional Parameters, and type in *NOMAX in the "Initial number of records"
field.

Create Physical File (CRTPF)

Type choices, press Enter.

Additional Parameters

Source listing options . . . . . *SRC, *NOSRC, *SOURCE...


+ for more values
System . . . . . . . . . . . . . *LCL *LCL, *RMT, *FILETYPE
Expiration date for member . . . *NONE Date, *NONE
Maximum members . . . . . . . . 1 Number, *NOMAX
Access path size . . . . . . . . *MAX1TB *MAX1TB, *MAX4GB
Access path maintenance . . . . *IMMED *IMMED, *DLY, *REBLD
Access path recovery . . . . . . *NO, *AFTIPL, *IPL
Force keyed access path . . . . *NO *NO, *YES
Member size:
Initial number of records . . > *NOMAX 1-2147483646, *NOMAX
Increment number of records . Number
Maximum increments . . . . . . Number
More...
F3=Exit F4=Prompt F5=Refresh F12=Cancel F13=How to use this display
F24=More keys

Now you have created a 'destination file' and can convert an AS/400 database to a CSV file.
To view the file you have created, simply type in this command:

DSPPFM USER999/CSVPC

Display Physical File Member


File . . . . . . : CSVPC Library . . . . : USER999
Member . . . . . : CSV Record . . . . . : 1
Control . . . . . __________ Column . . . . . : 1
Find . . . . . . . ________________________________
*...+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...
"R","04","LEC OFF-NET ",
"C","05","NON-NUMERIC DATA IN NUMERIC ",
"R","06","INVALID CREDIT LEC ",
"R","08","LEC MASTER FILE ERROR ",
"C","09","LEC NOT IN TPM FILE OR LEC MST",
"C","20","INVALID RECORD ID ",
"C","21","ORIGINATING NPA INVALID PER BC",
"C","22","ORIGINATING NPA/NXX NOT ON TPM",
"C","23","ORIG NUMBER = TERMINATING NUM ",
"R","24","SENT PAID CALL/ORIG OCN <> BIL",
"L","32","ORIGINATING NXX INVALID ",
"R","33","ORIGINATING NPA INVALID ",
"R","34","ORIGINATING NUMBER LENTH INVAL",

21
"L","35","ORIGINATING NUMBER INVALID ",
"R","36","ORIGINATING STATE INVALID ",
More...
F3=Exit F12=Cancel F19=Left F20=Right F24=More keys

31. Command to see what user signed on to a terminal

To see what user signed on to a terminal, use the Display Workstation User command,
DSPWSUSR.

32.Setting up an ODBC Connection to an AS/400 Database

After you set up client access and make sure that you install the ODBC driver, click on START,
SETTINGS, CONTROL PANEL. If you don’t see ”Data Sources (ODBC)” on the first screen, but see
“ADMINISTRATIVE TOOL”, click on ADMINISTRATIVE TOOLS, then DATA SOURCES(ODBC).

Click Add

22
Click Finish

23
Click Apply

24
Then click OK..Now you should be able to connect to the database. On the above screen, if you
want READ ONLY rights, make sure you click the read only option.

33. What is FTP and it's Commands

FTP is an acronym for "File Transfer Protocol". FTP is a powerful application which allows users
to access archives that are available on a large number of computer hosts. FTP is a
client/server application that allows the transfer of files between computers. This transfer can
take place between a mainframe and a local terminal, or as a transfer of information over the
Internet between your computer and a distant server. The key elements of FTP are:

Finding FTP sites from your client based system


Establishing a connection with the server
Using FTP commands to facilitate the transfer of information
Allowing for the differences in file types and compressions techniques.
Developing an ability to search through "archives" to retrieve information

Common FTP Commands

? to request help or information about the FTP commands


to set the mode of file transfer to ASCII (this is the default and transmits seven bits
ascii
per character)
to set the mode of file transfer to binary (the binary mode transmits all eight bits per
binary byte and thus provides less chance of a transmission error and must be used to
transmit files other than ASCII files)
bye to exit the FTP environment (same as quit)
cd to change directory on the remote machine
close to terminate a connection with another computer
delete to delete (remove) a file in the current remote directory (same as rm in UNIX)
get to copy one file from the remote machine to the local machine
help to request a list of all available FTP commands
lcd to change directory on your local machine (same as UNIX cd)
ls to list the names of the files in the current remote directory
mkdir to make a new directory within the current remote directory
to copy multiple files from the remote machine to the local machine; you are
mget
prompted for a y/n answer before transferring each file
copies all the files in the current remote directory to your current local directory,
mget *
using the same filenames. Notice the use of the wild card character, *.
to copy multiple files from the local machine to the remote machine; you are
mput
prompted for a y/n answer before transferring each file
open to open a connection with another computer

25
put to copy one file from the local machine to the remote machine
pwd to find out the pathname of the current directory on the remote machine
quit to exit the FTP environment (same as bye)
rmdir to to remove (delete) a directory in the current remote directory

 
34. Updating Data Areas

It seems like there are three different ways to solve any problem on the AS/400. Even
experienced IS professionals sometimes loose sight of alternate approaches to application
design. In this training track series I present basic AS/400 skills to help you keep those solutions
in sight. I'll show you how to use data areas to store control values for a fictitious invoicing
system.
Your invoicing system needs to keep track of the last invoice number used. You might also want
to store the sales tax percentage in a way that makes it easy to change. Finally, suppose you
have a standard handling charge that is added to each invoice.

One possible approach to storing these control values is to create a database file with one
record. That record would have a field for last invoice number, another field for sales tax
percentage and another for handling charge. The invoicing program would chain to this record
and use those values. You could then write a maintenance program so the administrator of the
system could change the values.

The AS/400 offers another approach. You could create a data area to store these values. Think
of a data area as a chunk of memory that is similar to a file with one record. You can change
the value of any character in the data area and you can retrieve the values from any program:
CL, RPG and COBOL.

To see the different ways of using data areas, I'll show you how to:

1) create the data area and assign it values using commands

2) retrieve, use and update the data area using an RPG program

3) use a CL program to give the system administrator an easy way to change the values
When you create the data area, you will need to supply a name and length. The name should
follow your naming conventions. For this example, name your data area "INVA100". You will
also need to supply a length for the data area. It doesn't hurt to create a little extra room, so
make this data area 100 characters in length. Finally, you will specify the library where the
data area will reside. So, to create a data area named "INVA100" in library "INVFILES", just key
in the command:

CRTDTAARA DTAARA(INVFILES/INVA100) TYPE(*CHAR) LEN(100)

You now have 100 characters of storage to work with. Suppose your invoice numbers are 7
positions long and your last invoice number was 100324. You want to change the value of the
first 7 characters of the data area to 0100324. You do this with the "Change Data Area"
command:

CHGDTAARA DTAARA(INVFILES/INVA100 (1 7)) VALUE('0100324')

26
Then use these commands to store your sales tax of 7.125% in positions 8 through 12 and your
handling charge of $2.00 in position 13 through 17:

CHGDTAARA DTAARA(INVFILES/INVA100 (8 5)) VALUE('07125') CHGDTAARA


DTAARA(INVFILES/INVA100 (13 5)) VALUE('00200')

Now use this "Display Data Area" command to display your data area:

DSPDTAARA DTAARA(INVFILES/INVA100)

The AS/400 will show that you have successfully stored your control values in the data area.
You have probably noticed the free format nature of this data area. There are no database
fields or special attributes for the data area. It will be up to you to keep track of the location
of each value in the data area.

I won't look at a complete invoicing program here. The important thing for now is that your
RPG program will need to retrieve the data area at the beginning of the program. Also, when
the program has finished creating the invoices, it needs to update the value of the last invoice
number.

Figure 1 shows the RPG code to retrieve and update the data area. It retrieves the data area
with the "IN" instruction. This instruction reads the 100 characters in the data area named
"INVA100" into the data structure named "ControlValues". This data structure breaks up the
data area into the three fields that you need: CtlLastInv#, CtlSalesTax and CtlHandling.

When the main logic of the program creates the invoices, it will increment the invoice number.
Before terminating, the program uses the "OUT" instruction to update the data area. After the
program runs, you could use the "Display Data Area" command to see that the value of the last
invoice number in the data area has changed.

You could document how the system administrator could use the "Change Data Area" command
to modify the sales tax and handling charge. It is more user friendly to write a program to
format the fields on a display file. You could write an RPG program that retrieves the data area
with an "IN" instruction, displays it using a display file and updates it with an "OUT" instruction.
Since I want you to see different ways of using data areas, I'll use a CL program to display and
change the values in the data area.

CL programs can declare one file. If this file is a display file, the CL can display and read a
screen. If you code and compile a simple display file, a CL program can use it to provide an
easy way to work with the values in the data area.

First, create a display file named "INVD100" with three fields:

DLSTIN for last invoice #


DSLSTX for sales tax
DHNDCH for the handling charge.
To keep our program simple, make all of the fields character fields. Figure 2 is the CL program
that retrieves the values in the data area, displays them on the display screen and changes the
data area with the values entered.

I can't leave the topic of data areas without mentioning the "Local Data Area". Every job
running on the AS/400 has a system defined data area of 1,024 characters. This means that any
interactive job has this area available at all times. Though this isn't considered a modern

27
programming style, many programmers use the "Local Data Area" as a way to pass parameters
between programs. You can use the "Display Data Area" and "Change Data Area" commands to
work with the "Local Data Area". Instead of specifying a data area name, use "*LDA" to indicate
that you are referring to the system defined "Local Data Area". Realize that each job has its
own "Local Data Area" which is cleared when you sign off.

--------------------------------------------------------------------------------
Figure 1 - This is all you need to read and update the data area from an RPG program.

0001.00 * This defines the data structure that defines the fields
0002.00 * of the data area named INVA100
0003.00 D ControlValues DS DtaAra(INVA100)
0004.00 D CtlLastInv# 1 7 0
0005.00 D CtlSalesTax 8 12 3
0006.00 D CtlHandling 13 17 2
0007.00 D CtlFiller 18 100
0008.00 * First time routine to retrieve the data area
0009.00 C *Lock IN ControlValues
0010.00 *
0011.00 * The main logic of the program goes here
0012.00 *
0013.00 * Before ending program, update the data area since CtlLastInv#
0014.00 * has changed
0015.00 C OUT ControlValues
0016.00 C Eval *InLR = *On
0017.00 C Return

Figure 2 - This is the CL program to easily modify the values of the data area.

0001.00 PGM
0002.00 /* This DCLF (declare file) names the display file that will be used */
0003.00 DCLF FILE(INVD100)
0004.00 /* These Retrieve Data Area commands read the data area and put the */
0005.00 /* the values in the fields in the Display File */
0006.00 RTVDTAARA DTAARA(INVA100 (1 7)) RTNVAR(&DLSTIN)
0007.00 RTVDTAARA DTAARA(INVA100 (8 5)) RTNVAR(&DSLSTX)
0008.00 RTVDTAARA DTAARA(INVA100 (13 5)) RTNVAR(&DHNDCH)
0009.00 /* Send Receive File shows the display & then reads what is entered */
0010.00 SNDRCVF RCDFMT(SCR1)
0011.00 /* These Change Data Area commands store what was entered back in the*/
0012.00 /* Data Area */
0013.00 CHGDTAARA DTAARA(INVA100 (1 7)) VALUE(&DLSTIN)
0014.00 CHGDTAARA DTAARA(INVA100 (8 5)) VALUE(&DSLSTX)
0015.00 CHGDTAARA DTAARA(INVA100 (13 5)) VALUE(&DHNDCH)
0016.00
0017.00 ENDPGM

35. Writing CL Programs

In this rapidly changing world of the AS/400, the only constant is change. In fact, it's not the
AS/400 anymore. So with topics like iSeries, Domino, Version 5, Websphere and Java

28
dominating the press, it is easy to loose track of the basic skills needed to survive and flourish
in the iSeries world. Here I present a small example of the power of Command Language (CL)
programming. This example is small enough to easily follow and yet it uses some of the less
obvious features of CL. Beginning programmers as well as system administrators can write
these simple programs and learn why experienced programs love the command language of
OS/400.

Parkinson's Law of Data is that data expands to fill the space available for storage. My corollary
to this law is that no matter how much disk storage you have, you only have 20% left. Here is a
simple and powerful tool to help discover where your disk space is going.

This tool consists of two small Command Language (CL) programs. These programs use two
features of CL that are somewhat hidden. These are:

· Using the *OUTFILE option to create a file

· Using RCVF to read a database file


This process builds a single database file that summarizes every file on your system. You can
use this file as input to a query to list:

· Files by size

· Files by last date changed

· Files by owner
The first CL program will generate a list of all user libraries. The second program will read this
list and use it to build a composite list of all files on the system.

OS/400 keeps a description of every library and file. You probably know that these descriptions
are viewable using the Display Object Description (DSPOBJD) command. By changing the
OUTPUT option to *PRINT, you can print the descriptions. But what is less obvious is that by
changing the OUTPUT option to *OUTFILE, the command will create a database file as output.

Figure 1 shows the Command Language program to create a file listing all libraries on the
system. The operating system keeps a description of each library in the General Purpose
Library (QGPL). By using the DSPOBJD command with the *OUTFILE option, OS/400 will build a
database file that has a record for each library. The database file is named in the OUTFILE
parameter of the DSPOBJD command.

Entering the DSPOBJD command in Figure 1 is a little tricky. Key in the command DSPOBJD and
hit F4. Then fill in the values for the object and object type. For the OUTPUT parameter, use
*OUTFILE. When you hit enter, OS/400 will see that you are creating an *OUTFILE and will
display more keywords. Then you can fill in the OUTFILE keyword.

The program in Figure 1 does a little housekeeping first to delete the list of libraries from the
last time this program was run. The MONMSG command tells the program to continue if the file
does not already exist. Finally, the DSPOBJD command finds the descriptions of all user
libraries on the system and creates a file named ALLLIBS to hold the descriptions.

After running this program, you can examine the records in ALLLIBS. OS/400 has a database
format already defined to hold this information. In the file are fields to hold the specific
information about the library. Included in these fields are:

ODOBNM - the object name which in this case is the library name

29
ODOBSZ - the object size which in this case is the size of the library description

ODLDAT - the date the object was last changed


Now, all that is needed is a program to read each record in ALLLIBS, find the description of all
files in each library and put the descriptions in a single output file. Figure 2 has the CL program
to read the data in ALLLIBS and use it to build the file ALLFILES.

In Figure 2, the second line is the Declare File (DCLF) command. This is like a File Specification
in RPG. It tells the compiler to look for this file and to use the field names in the file as part of
the compiled object. In other words, the CL can reference any field in the file.

The next two lines of the program take care of housekeeping to delete the ALLFILES file. The
next executable statement is the Receive File (RCVF) command. This is the instruction to read
a record from the file. Since CL allows only one Declare File (DCLF) statement per program, the
RCVF command does not need to specify a file name. It reads the only one mentioned in the
DCLF command.

When the end of file is reached, the message CPF0864 will be sent. The Monitor Message
instruction, MONMSG MSGID(CPF0864) will realize that the end of file has been reached and will
go to the label EOJ.

Otherwise, the program will continue with the next statement which is a Display Object
Description (DSPOBJD) command. We used this command in the other program to get the
descriptions of all libraries. Here, we use it to get a list of all files in the first library. The
name of the library is in the field named ODOBNM. So, by using the field name &ODOBNM as
the value of the library and using *ALL as the value for the file, the command will get the
object descriptions of all files in the first library. By using the *OUTFILE option, we tell OS/400
to write the file descriptions to a file named ALLFILES.

The program then goes back to the statement labeled LOOP. It reads another record from the
ALLLIBS file. It gets a list of descriptions of all files from that library and adds them to
ALLFILES. It continues until it has added all descriptions of all files.

When the program is done, you have the file, ALLFILES which has the size, description, owner
and last date changed of every file on your system. To help manage your disk space you can
write queries to find files that should be deleted. You can look for files owned by programmers
that no longer work at your company. You can sort the files by last changed date to find files
that are no longer in use. You may want to make it a month end procedure to re-create
ALLFILES and then print out a summary of file space being used by different systems. In short,
you have a tool to help manage disk space.

--------------------------------------------------------------------------------

Figure 1 - This CL program generates a list of all user libraries.

PGM

DLTF FILE(YOURLIB/ALLFILES)
MONMSG MSGID(CPF2105)
DSPOBJD OBJ(*ALLUSR) OBJTYPE(*LIB) OUTPUT(*OUTFILE) +
OUTFILE(YOURLIB/ALLLIBS)

30
ENDPGM

Figure 2 - This CL program reads the data in ALLLIBS and uses it to build ALLFILES.

PGM
DCLF FILE(YOURLIB/ALLLIBS)
DLTF FILE(YOURLIB/ALLFILES)
/* IF FILE DOES NOT EXIST, THAT'S OK */
MONMSG MSGID(CPF2105)
LOOP: /* READ A RECORD FROM "ALLLIBS" */
RCVF
/* IF END OF FILE IS REACHED, GO TO END */
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(EOJ))
DSPOBJD OBJ(&ODOBNM/*ALL) OBJTYPE(*FILE) +
OUTPUT(*OUTFILE) +
OUTFILE(YOURLIB/ALLFILES) OUTMBR(*FIRST +
*ADD)
/* IF LIBRARY HAS NO FILES, THAT'S OK */
MONMSG MSGID(CPF2123)
GOTO LOOP
EOJ:

36. Open Query Files

Whether you are experienced programmer who is new to the AS/400 or you are completely new
to programming, you will save time and leverage your efforts by learning the basic skills of the
AS/400. In this series I have focused on the techniques that are both essential and unique to
the AS/400. The AS/400 has so much to offer that it is easy to lose sight of the basic skills that
provide the building blocks for all solutions.
I had a manager once who thought programmers made system design more complicated than it
needed to be. In his words, "all you do is read them, sort them and print them". He was
certainly right that putting the data in the right sequence is an essential technique to master.

The AS/400 has such a robust operating system that programmers often get to choose among
several approaches to solving problems. In the case of sequencing data, four different
approaches come to mind:

Create a logical file to read the data in the desired sequence.

Use Query/400 to sort the data and create a copy of the original data in a new file.

Use the CL command, FMTDTA (format data) to sort the data and create a copy of the original
data in a new file.

Use the CL command OPNQRYF to read the data in the desired sequence.

The first approach, creating a logical file, is certainly effective. But each logical file that you
create must be maintained by the operating system each time a record is added or deleted to
the file. So, if you need the data resequenced only when a certain report is requested, you will
be adding unnecessary overhead to the system.

31
The second approach, Query/400, works well enough but creates a complete copy of the
original data. This makes it unnecessarily slow and requires extra disk space to run. The third
approach, FMTDTA, is rarely used. Like Query/400 it creates a complete copy of the original
data.

The Open Query File command. OPNQRYF, is a lot like creating a temporary logical file that
disappears when the job is done. It not only resequences the data but can easily select a subset
of the records. It resembles Structured Query Language (SQL) in structure. With it you can join
records from different files, group records together and even calculate new field values.

Consider a store sales evaluation system. Your user would like to list the sales in different
sequences. Also, the user sometimes wants to see the stores in only one state. Open Query File
is a great way to change the order of the data and select only certain records.

First, look at the very straightforward use of OPNQRYF to order the records by sales. That is,
list the store with the most sales first. There are five steps to using OPNQRYF:

Share the data path that you are building with the rest of the job

Run the OPNQRYF command

Call the program that uses the data from the OPNQRYF command

Close the file

Delete the override that you set up in step 1

It's not quite as messy as it sounds. You can see the five steps in Figure 1. The first step is
always to use an override database file command, OVRDBF, to open the file with the
"SHARE(*YES)" option. Without this, the program will not use the new data path that is created
with the OPNQRYF command.

The next step in Figure 1 is the OPNQRYF command. Here, I am creating a new data path to the
store sales file named "SLS". Since I want to order the data by monthly sales, "SLMNTH", I have
used "SLMNTH" as the value for the "KEYFLD" parameter. Also, I want the largest sales first, so I
used the "*DESCEND" option.

Now, when the program calls the RPG program to print the report, it will read the "SLS" file
using this newly created data path. The program finishes with the housekeeping tasks of closing
the file and deleting the override.

Figure 2 is a CL program that will order the data by store number and print only stores in one
state. The state is specified as a parameter. Running the command, CALL SLSC101 'TX' will call
this program and print the stores in Texas in order by store number.

In Figure 2, notice the parameter "STATE" in the first line. This tells the program that a
parameter will be used when the program is called. The "DCL" statement tells the program that
the parameter will be a 2 byte field.

The "OPNQRYF" statement will use the "QRYSLT" parameter to select only records for stores in
Texas. If I always wanted the records for Texas I would simply code the parameter as:
QRYSLT('SLSTAT = "TX" ').

32
Since I want the user to specify the state as a parameter, I have added a statement to the CL
program to build the value for the "QRYSLT". I declared a variable named "QSELECT" and gave it
the value needed to select only records for the value used in the CALL statement.

Once you understand these simple examples, you can easily write a program to prompt the user
for the desired sequence and state. That program would can call a CL program similar to the
one in Figure 2 which will sort and select to right records.

These two examples will get you started with the power and flexibility of Open Query File.

--------------------------------------------------------------------------------

Figure 1 - This CL program uses Open Query File to order data by sales.

0001.00 PGM
0002.00
0003.00 /* Use OPNQRYF (Open Query File) to sequence store sales in */
0004.00 /* descending order */
0005.00
0006.00 /* 1st step is to share the data path with rest of job */
0007.00 OVRDBF FILE(SLS) SHARE(*YES)
0008.00
0009.00 /* 2nd step is the OPNQRYF command to build new path to SLS */
0010.00 /* using monthly store sales in descending order */
0011.00 OPNQRYF File((SLS)) KEYFLD((SLMNTH *DESCEND))
0012.00
0013.00 /* 3rd step is to call the RPG program that lists SLS file */
0014.00 CALL PGM(SLSR100)
0015.00
0016.00 /* 4th step is to close the file created in step 1 */
0017.00 CLOF OPNID(SLS)
0018.00
0019.00 /* 5th step is to delete the override from step 2 */
0020.00 DLTOVR FILE(SLS)

Figure 2 - This Open Query File CL uses a parameter to select data from only one
state.

0001.00 PGM PARM(&STATE)


0002.00
0003.00 DCL VAR(&STATE) TYPE(*CHAR) LEN(2)
0004.00 DCL VAR(&QSELECT) TYPE(*CHAR) LEN(2000)
0005.00
0006.00 /* Build a string in QSELECT to use as the QSLT parameter */
0007.00 /* to select only the records for the state used in the CALL */
0008.00 /* it will build a value like SLSTAT = "TX" */
0009.00 CHGVAR VAR(&QSELECT)
0010.00 VALUE('SLSTAT = "' *CAT &STATE *CAT '"')
0011.00
0012.00 OVRDBF FILE(SLS) SHARE(*YES)
0013.00

33
0014.00 /* Order by SLSTOR (store#) - select only records for right STATE */
0015.00 OPNQRYF FILE((SLS)) QRYSLT(&QSELECT) KEYFLD((SLSTOR))
0016.00
0017.00 CALL PGM(SLSR100)
0018.00
0019.00 CLOF OPNID(SLS)
0020.00
0021.00 DLTOVR FILE(SLS)

37. Creating Menu's using SDA

The AS/400 has so many capabilities and options that it is easy to get overwhelmed with
choices. Learning the basic skills will help you apply your experience by using the built in
features of the AS/400. Each month, we will introduce you to essential AS/400 skills that are
powerful and easy to learn. Here we will look at the user friendly Screen Design Aid, SDA.
One of the most intuitive development tools on the AS/400 is SDA, Screen Design Aid. With it,
you build display screens and menus in a WYSIWYG (what you see is what you get) mode. We're
going to look at how easy it is to create a user menu.

Suppose a user says, "My department does only a few things on the AS/400 but the canned
software package that we have makes me navigate through too many screens. I'm training a
new hire and I wish you could make a special menu with only 6 selections:
1) Run the on-line Customer Maintenance program that is in our canned application
2) Submit the job to print all new orders
3) Run the query you wrote last week to display all back ordered parts
4) Run the query to print the customer service summary
5) Work with spool files to see if our reports are printing
6) Go to the Main "Customer Service Menu"

In only a few minutes, you can build a custom menu for your user. Start SDA with the command
STRSDA. You will see that SDA has three functions:
1) Design Screens
2) Design Menus
3) Test Display Files

You'll want to experiment with each of these later. For now, use selection 2 to design a menu.
Enter the name of your new menu, where you want to store the source (usually QDDSSRC) and
the library that it will be in. SDA will look for that menu and since it can't find it, it will create
it.

SDA creates a template for you that has the menu name and a list of ten selections. On this
screen, you list the selections for the user. On a separate screen, you list the commands
associated with each selection. Enter the prompts for your user, see Figure 1. Also, add a
selection 99 to signoff. Avoid keying in "insert" mode since that will shift all text on the screen.
To remove text, just space over it.

When you hit enter, SDA uses your screen to build literals in a display file. F20 provides a way
to display the text blocks that SDA will use. Each text block is preceded by a hidden character
that contains the display attribute for that string of text. If you key an "H" right in front of a
block of text, SDA will display that text in high intensity or white characters. An "R" will display
the text in reverse image. "D" will delete the text.

Next, define the commands for each selection. Hit F10 to enter the commands. You now can
key in the commands for selections 1 through 99.

34
Suppose your on-line Customer Maintenance program is run by calling the program, "CUSR000".
Tell SDA that you want selection 1 to "CALL CUSR000", see Figure 2. Suppose the job to print all
new orders is "ORDC110". You enter the command, "SBMJOB CMD(CALL ORDC110)" on line 2.
Now, when the user selects 2, the job "ORDC110" will be submitted to run as a batch job.

You can enter any command that you want the user to run. You can run queries, submit print
queries to run in batch and use standard utility commands such as "Work with Spool Files",
WRKSPLF. Finally, you can help the user navigate to another menu with the "GO" command
used for selection 6.

When you exit SDA, check the "object library" name. This is where your compiled menu objects
will go. Hit enter and the AS/400 will compile your source code and your menu will be ready to
run. SDA creates three objects, all with the same name: the commands, the display file and a
message file for the menu.

If you want some added fun, go back to the menu source using SDA and this time make the
selection to "work with menu help". Here you can define help screens that will display if your
user enters the selection number and hits F1.

Now you can tie this menu to your new employee's user profile. Use the work with user profile
command, WRKUSRPRF to change the new employee's profile. Put the new menu name in the
field, "first menu" at the bottom of the screen. Now, the user will see the MRCM001 menu when
he signs on the AS/400.

It's that easy to customize the screen selections for a user.

You can also use SDA to test and design display files. With the "Test Display Files" selection of
SDA, you can see the fields and presentation of a display file. This works even if you don't have
the source code.

The "Design Screens" selection of SDA is for building display files. You can reference the fields
in database files, move text and fields around the screen and modify the display attributes.
Knowing how to use SDA to design display files is an essential AS/400 skill but is beyond the
scope of this article. See IBM's "Screen Design Aid, User's Guide and Reference" for complete
coverage of SDA.

--------------------------------------------------------------------------------

Figure 1 - Custom Menu Designed Using SDA

MRCM001 Special Customer Service Menu

Select one of the following:

1. Online Customer Maintenance


2. Print all orders
3. Display backordered items
4. Print customer service summary report
5. Work with reports
6. Customer Service Menu
7.
8.
9.
10.

35
99. Sign Off

Selection or command

Figure 2 - SDA Commands for Special Customer Service Menu

Define Menu Commands

Menu . . . . . . : MRCM001 Position to menu option . . . . .

Type commands, press Enter.

Option Command
01 CALL CUSR000
02 SBMJOB CMD(CALL PGM(ORDC110))
03 RUNQRY QRY(PARQ020)
04 SBMJOB CMD(RUNQRY QRY(CSVQ100))
05 WRKSPLF
06 GO CSVM000
99 signoff

F3=Exit F11=Show all options F12=Cancel F24=More keys

Figure 3 - User Profile for New Employee

Change User

User . . . . . . . . . : JQSAMPLE

Type choices below, then press Enter.

User description . . . . New Customer Service Person


Password . . . . . . . . *SAME Characters
Type of user . . . . . . *USER Type, F4 for list
User group . . . . . . . *NONE Name, F4 for list

Restrict command line use N Y=Yes, N=No


Uses OfficeVision/400 . . N Y=Yes, N=No

Default library . . . . . Name


Default printer . . . . . Name, *WRKSTN, F4 for list
Sign on program . . . . . *NONE Name, *NONE
Library . . . . . . . . Name

First menu . . . . . . . MRCM001 Name


Library . . . . . . . . *LIBL Name
38. Setting up a Test Environment

In this training track series I have presented basic skills that programmers and managers need
to be effective in the AS/400 world. This article will describe the steps for setting up a test

36
library and creating test database files. Having a good test bed of data is essential for
accurately testing program changes.
Building a proper test environment can be time consuming. The time is well spent though.
Aside from the obvious benefit of being able to test your program, you will get a clear picture
of the data and the relationships between files when you create your test data.

Imagine that you have a program that uses three files:

1. a customer file (CUS)

2. an invoice file that has all invoices for a customer (INV)

3. a payment file that has all payments for an invoice (PMT)


Suppose you want to test the way the program handles the application of a credit memo to a
partially paid invoice. Applying the credit memo will add a record to the payment file and
change some fields in the invoice file. The customer file is not changed. Further, each file is
read using a logical file.

Figure 1 shows the steps to follow to set up a test environment. This may look like a lot of
work. The time spent setting up the test data will pay big dividends when you start testing. Not
only will you be able to test easily and quickly, you will be able to prove to your users and
quality assurance staff that your program is functioning correctly.

Create a Test Library

This is as easy as entering the command CRTLIB TEST1.

Isolate Test Data

The perfect tool for isolating test data is Query/400. Query will not only find the data easily
but will also find the matching records in the associated files.

Typical of relational database environments, you cannot randomly select records from each of
these files. That is, the invoice records must belong to a customer record and the payment
records must belong to selected invoice records.

In this case, write a query to display invoices that are partially paid. From these, select several
and write down the customer numbers.

Query/400 is an excellent tool for selecting the data. Now write a query to select the INV
records for these customers and make a work file named INVTEST. Use the "Select Output Type"
option, to tell Query that you want to create a database file as output. Name the output file
INVTEST and store it in the test library, TEST1.

Write a similar query to select the PMT records for these customers. Name that file, PMTTEST.

Create the Test Physical File Definitions

Now, make a skeleton file definition for each of the files in your test library. There are several
ways to do this. My favorite method is to use the WRKOBJ command to find the file in my
production library and then to use selection 3 to copy the file to my test library.

37
For example, to copy the INV file definition from library DMCLIB, the command: WRKOBJ
DMCLIB/INV *FILE will show the INV in list format. Then, by keying "3" next to it, you can copy
the file definition to the test library, TEST1.

Repeat the process to copy the payments file. Remember that this builds a file with no records.

Create the Logical Files

Similarly, copy the logical file definitions. If the logical file is named INV01, use the command:
WRKOBJ DMCLIB/INV01 *FILE to list the file and use the selection "3" to copy it to the test
library TEST1.

Repeat the process for each logical file that you need.

Copy the Data to the Test Physical Files

Now copy the test data to the files.

For the invoice file:

CPYF FROMFILE(TEST1/INVTEST) TOFILE(TEST1/INV) MBROPT(*REPLACE)

For the payments file:

CPYF FROMFILE(TEST1/PMTTEST) TOFILE(TEST1/PMT) MBROPT(*REPLACE)

Write a Program to Restore the Data

After you test your program, you will want to restore the data to its original state before
testing again. Write a simple CL program that consists of the two CPYF commands that you just
used to copy the test data to the test files. Once you compile this program, you can call the
program anytime you want reset your data.

Change library list and confirm location of objects

Change your library list so the test library, TEST1 is before your other libraries. For most
environments, changing the current library to TEST1 is the way to do this. The command for
that is: CHGCURLIB TEST1

Confirm that you created the files in the TEST1 library. Use WRKOBJ to find all occurrences of
each file in your library list. For example: WRKOBJ INV *FILE will list all INV files in your library
list. The first one in the list should be in the TEST1 library. If not, stop! The whole point of
setting up this test environment is to ensure that the INV file used for testing is the test copy in
TEST1.

When you run your program, the AS/400 looks through your library list for each object that it
needs. If you compile your test program in TEST1, that is the one that will be called. Likewise,
when the program reads or updates data in the INV or PMT file, it will use the files that it finds
first. In this case, it finds the files in TEST1 and uses them.

In the case of the CUS file, the AS/400 will not find the CUS file in the TEST1 library. That
works fine because the CUS file is not updated by this program.

You can now test your program without harming any production data. You can also restore your
test data by calling the CL program that you just wrote.

38
We have followed some important principles of testing. These include:
· Have a defined test bed of data that can be restored
· Have test copies of all data that is modified
· Test the final version of the program. That is, do not construct a test that requires changing
the program after testing is complete. In other words, don't disable the UPDATE's in a program
so you can test without altering data.
· Keep all test objects in an isolated area.

You now have a seven step process to follow when testing. It requires no high level language
programming. You need only knowledge of a few commands and the ability to write simple
queries.

Figure 1 - These are the steps to set up a test environment.

1) Create a test library


2) Isolate test data from each of the files that are changed
3) Create the test physical file definitions
4) Create the logical files
5) Copy data to the test physical files
6) Write a program to restore the data
7) Change library list and confirm location of objects

39. Subfiles Part 2

In this training track series I present essential AS/400 skills. Last month I discussed the design
of a simple sub-file display program. If you have lost track of last month’s article, e-mail me
for a copy. This article will expand that program to add the logic to process records selected by
the user.

AS/400 subfiles are equivalent to Windows list boxes. Getting comfortable with subfile
programming is essential for designing user friendly interfaces. Managers and business analysts
need to understand how to use this powerful technique. Using subfiles is an essential skill of
the AS/400 programmer.

Remember to implement sub-file processing, you must:

Clear the sub-file

Load the sub-file

Display the sub-file

Process sub-file records selected by the user.

Last month, I showed the code for a user to look up customers that belong to a salesperson.
Doing this is similar to running a query to display records in a file. While that is handy,
providing the ability to select records from that list is what makes subfile system design so
powerful.

With only a few instructions, the program can display more details about the customer using a
full screen display. A little more code will allow the user to update fields using that screen.
Finally, once the customer has been selected, the program can call another program that uses
a subfile to list the open orders for that customer.

39
First, the user must have a way of indicating which customer to select. There are advanced
techniques to select based on the cursor position. However, the easiest technique is to add a
one character field to the sub-file. The user simply keys X in the field next to the customer
number to select it.

I have added the field, SEL, to the subfile data record. I have also included a heading for it in
the subfile control record.

To see which record was selected, I added the subroutine SELRCD after the EXFMT operation.
Now, when a user keys an X on a line and hits ENTER, the subroutine can determine which
record was selected.

The AS/400 offers a simple and efficient way to read sub-file records. The READC operation
reads only records that have been changed. If the user keys a value in the SEL field, the READC
operation will read that record. It will automatically skip over any records that were not
selected.

So using the READC is an efficient way to look for selected records. Notice that if the user keys
spaces in SEL, the AS/400 sees those as changed records. Once the program reads a sub-file
data record, all the fields in that line are available to the program. So now, simply process the
customer selected.

In Figure 1 you can see the list of customers for salesperson # 6004 with a column for selection.
If the user keys X on the same line as Nick’s Deli, the READC operation in the subroutine
SELRCD will read that subfile data record. Then, the program can use that information to
display more detail about the customer.

Displaying more information about the customer is as simple as:

1) Adding a record in the display file to show more customer fields


2) Adding a File Spec to define the Customer Master File
as an input file
3) Doing a CHAIN operation to the customer master file
using the CUSNUM field from the subfile data
record as a key
4) Doing an EXFMT operation to display the screen

It is almost as easy to use this interface to update the customer information. Just open the file
for update and add an UPDATE operation after the EXFMT. When you’ve done that, the user has
a friendly way to select a customer, see details from the customer master and change any
information that needs updating.
So what is involved in using this program to call another program to show the open orders for
the customer? Use the SELRCD routine to determine which customer was selected. Then,
instead of chaining to the customer file, call a new program with CUSNUM as a parameter.

That new program will use the CUSNUM filed to read all open orders for the customer and
display them in a subfile list. You could then add similar features to that subfile program to
display or change the details of the open orders. You could even let the user select an open
order and use that as a parameter to call a program to list the items in the order.

40
You can see where this is headed. Subfiles give you the ability to design robust, user friendly
programs. Combining these techniques with modular programming gives you the ability to build
very complicated systems, one simple step at a time.

--------------------------------------------------------------------------------

Figure 1: This is the list of customers for salesperson # 6004.

Salesperson# 6004

Sel Cust# Name Phone#


_ 012795 JOHN'S ALL AMERICAN SPORTS 2105551234
_ 021365 AAA TERMITE INSPECTORS 9405556666
_ 034598 JONATHANS SPORTS CLUB 2125551212
_ 045654 NICKS DELI 4065551212
_ 085261 ZEBRA COMMUNICATIONS 4055551234
_ 085265 ANYTOWN INSTALLERS 9195551256
_ 097854 WIDGET CORP 8175556565
_ 124569 GOLD COAST LANDSCAPING 5045558654
_ 165432 LAST CHANCE GAS STATION 6455551212
_ 232356 TRM TELECOMMUNICATIONS 8885551211
_ 456215 NICKS RESTAURANT 8175559876
_ 546832 DANBURG CONSLUTING 9728176543
_ 561245 BOYDS CAR REPAIR 9625551256
_ 654654 CARLS REPAIRS 8175559963
_ 856234 ABC COMPANY 4055551122

More..

F3=Exit

Figure 2: This is the DDS for the display file to select a customer from a list.

A REF(*LIBL/CUS)
A PRINT
A CA03(03)
*----------------------------------------------------------------
A R ENTSLS
*
* Let user enter a salesperson # so program can show a list
* of customers
A O 2 20'List Customers for Sls#'
A SLSPER R B 2 46EDTCDE(4)
*----------------------------------------------------------------
A R SFDATA SFL
A SEL 1A I 4 2
A CUSNUM R O 4 5
A CUSNAM R O 4 15
A CUSPHN R O 4 50
*----------------------------------------------------------------
A R SFCTL SFLCTL(SFDATA)
A SFLPAG(0015)

41
A SFLSIZ(0045)
A OVERLAY
A N50 SFLCLR
A 50 SFLDSP
A 50 SFLDSPCTL
A 50 SFLEND(*MORE)
A 2 4'Salesperson#'
A SLSPER R O 2 17EDTCDE(4)
A 3 1'Sel'
A 3 5'Cust'
A 3 15'Name'
A 3 50'Phone#'
*----------------------------------------------------------------
A R CMDKEYS
A 24 40'F3=Exit'
*----------------------------------------------------------------

Figure 3: This is the part of RPG subfile program to process the selected customer.

* Define the subfile and the variable that will hold record # (REC#)
FCUSD001 CF E WORKSTN
F SFILE(SFDATA:REC#)
FCUS IF E K DISK
*
C *IN03 DOWEQ *OFF
* Show screen for user to enter the salesperson's number
C EXFMT ENTSLS
C *IN03 IFEQ *OFF
* Clear the subfile
C EXSR CLRSF
* Load the subfile
C EXSR LODSF
* Show the command key footer and then the subfile SFCTL
C WRITE CMDKEYS
C EXFMT SFCTL
* Process any seleted records
C EXSR SELRCD
C ENDIF
C ENDDO
C MOVE *ON *INLR
C RETURN
*---------------------------------------------------------------------
C SELRCD BEGSR
* Read the changed subfile data records
C READC SFDATA 96
C *IN96 DOWEQ *OFF
C SEL IFEQ 'X'
* Process the customer
* either CHAIN to customer master and EXFMT a display screen
* or CALL a program with CUSNUM as a parameter
C ENDIF
C ENDDO
C READC SFDATA 96
C ENDSR

42
Subfile written in ILE:

*************** Beginning of data *************************************


0001.00 * All "1 page at a time" logic is indicated with a comment that
0002.00 * has !!!!! at the beginning
0003.00 *
0004.00 * Define the subfile and the variable that will hold record # (R EC#)
0005.00 FT400D002 CF E WORKSTN
0006.00 F SFILE(SFDATA:REC#)
0007.00 FCUS01 IF E K DISK
0008.00 *
0009.00 D REC# S 4 0
0010.00 *
0011.00 C DoW *In03 = *off
0012.00 * Show screen for user to enter the salesperson's number
0013.00 C ExFmt ENTSLS
0014.00 C If *In03 = *off
0015.00 * Clear the subfile
0016.00 C ExSr ClearSubFile
0017.00 * !!!!! Start reading the customer file for this salesperson
0018.00 C CUSSLS SetLL CUS01
0019.00 C CUSSLS ReadE CUS01 95
0020.00 * !!!!! Turn off indicator that indicates SFLEND
0021.00 C Eval *In95 = *off
0022.00 * Load the subfile
0023.00 C ExSr LoadSubFile
0024.00 * Show the command key footer and then the subfile SFCTL
0025.00 C Write CMDKEYS
0026.00 C ExFmt SFCTL
0027.00 * !!!!! Loop to continue loading a new page when PAGE-DOWN hit
0028.00 C DoW *In21 = *on
0029.00 C ExSr LoadSubFile
0030.00 C ExFmt SFCTL
0031.00 C EndDo
0032.00 * Process any seleted records
0033.00 C ExSr SelectRecord
0034.00 C EndIf
0035.00 C EndDo
0036.00 C Eval *INLR = *on
0037.00 C Return
0038.00 *---------------------------------------------------------------
0039.00 C ClearSubFile BEGSR
0040.00 * Clear the subfile by writing a SFCTL record with Indicator 50
0041.00 C Eval *In50 = *off
0042.00 C Write SFCTL
0043.00 C Eval *In50 = *on
0044.00 * Set the record number variable to zero
0045.00 C Eval REC# = *zero
0046.00 C EndSr
0047.00 *--------------------------------------------------------------
0048.00 C LoadSubFile BEGSR
0049.00 * !!!!! Keep record number for positioning cursor in sub-file
0050.00 C Eval SFLRCD = REC# + 1

43
0051.00 * !!!!! load 1 page of subfile (DO this # of times = to SFLPAG)
0052.00 C Do 5
0053.00 C Eval REC# = REC# + 1
0054.00 C Write SFDATA
0055.00 C CUSSLS ReadE CUS01 95
0056.00 C If *In95 = *on
0057.00 C Leave
0058.00 C EndIf
0059.00 C EndDo
0060.00 * If subfile is empty, write a record that says "*NO RECORDS"
0061.00 C If REC# = *zero
0062.00 C Eval REC# = REC# + 1
0063.00 C Clear SFDATA
0064.00 C Eval CUSNAM = '*NO RECORDS*'
0065.00 C Write SFDATA
0066.00 C EndIf
0067.00 C EndSr
0068.00 *----------------------------------------------------------------
0069.00 C SelectRecord BEGSR
0070.00 * Read the changed subfile data records
0071.00 C ReadC SFDATA 96
0072.00 C DoW *In96 = *off
0073.00 C If SEL = 'X' or SEL = '1'
0074.00 * Process the customer
0075.00 * either CHAIN to customer master and EXFMT a display screen
0076.00 * or CALL a program with CUSNUM as a parameter
0077.00 C EndIf
0078.00 C ReadC SFDATA 96
0079.00 C EndDo
0080.00 C EndSr
0081.00 *----------------------------------------------------------------

40. Converting RPGIII to RPG-ILE

Experienced IS professionals can sometimes hack around in unfamiliar territory and solve
problems without completely understanding the details. But with an introductory knowledge of
the fundamentals of the AS/400 you can leverage your creative abilities and problem solving
skills. Each month, we will help you expand your AS/400 skills in only a few minutes. Whether
you are a manager who is spread too thin or a beginner with too much to learn in too little
time, you'll want to read this condensed overview of database files.
IBM introduced RPG-ILE in 1994 concurrent with release V3R1 of the OS/400 operating system.
You may have been scared away from trying RPG-ILE after reading articles about some of its
sophisticated features. Topics like activation groups, service programs and module binding may
have encouraged you to stay with the familiar RPG III. I'll show you how easy it is to convert
and compile your existing programs using RPG-ILE. You'll also see some great benefits from
simple additions in the language.

The simplest way to start using ILE is to convert an existing RPG III program. First, you will
need a place to put the new source code. The traditional name for an RPG III source file is
QRPGSRC. Similarly, the traditional name for an RPG-ILE source is QRPGLESRC.

Suppose there is RPG III source for a program XYZ in library PGMTEST. The source is in
QRPGSRC. Before you can convert the program to ILE, you must create a new physical source
file for it.

44
Do this with this command: CRTSRCPF FILE(PGMTEST/QRPGLESRC) RCDLEN(112)

It is important to specify the length. RPG-ILE source code uses records of 112 while
traditional RPG uses records of 96 characters.

To convert the program, use the convert RPG source command, CVTRPGSRC. It's this simple:

CVTRPGSRC FROMFILE(PGMTEST/QRPGSRC) FROMMBR(XYZ) + TOFILE(PGMTEST/QRPGLESRC)

In a few seconds, the AS/400 will create a new member named XYZ in QRPGLESRC. This new
member should have RPGLE as its type.

If you've heard about complicated compiling and binding of modules, you will be presently
surprised to learn that you compile this source code in a familiar way. Just use option 14 in
PDM to compile the source. The AS/400 sees that the type is RPGLE and executes the
CRTBNDRPG command which compiles the program as an executable, stand-alone program.

It's that simple. You don't need to worry about activation groups, service programs or binding of
modules to compile and run RPG-ILE.

Figure 1 shows some code snippets from an RPG III program. These snippets include examples
of some of the changes in syntax that you will see with RPG-ILE. Figure 2 shows the RPG III
source code after it has been converted to RPG-ILE.

Differences between Figure 1 and Figure 2

In the file specs, the overflow indicator for the printer is defined using the keyword OFLIND. In
the second file spec, the sub-file syntax has changed.

The E-specification has been replaced with the new D-specification. In this case, the array
definition has been replaced with the dimension statement, DIM(100).

The data structures in the I-specifications have also been replaced with D specs. The field
names in the D-spec can be 16 characters long. Not only that, you can indent fields to logically
group fields that belong together.

The DO and IF statements have not been changed noticeably by the conversion program. In a
moment, you'll see that the DO and IF statements have gained flexibility and readability in ILE.
The reference to the first element of the array now reads, ARA(1).

Since the operation field is larger in RPG-ILE, some operations are spelled completely. The old
operations UPDAT, SELEC and RETRN get spelled out as UPDATE, SELECT and RETURN.

You can see how easy it is to begin to use ILE. You may be asking the question, "Why bother?"
Certainly, converting to ILE without taking advantage of the flexibility of the new syntax isn't
advantageous.

Same Program, Different Syntax

Figure 3 shows the same code snippets rewritten using new ILE syntax. I've also added a
standalone field and a reference to a subroutine.

The most obvious difference is the use of upper and lower case characters. Most people keep
externally defined fields in all upper case. Temporary variables are most appropriately defined

45
in the D-specs. I defined the variable, AllRecsReadSw as a 1 character switch to indicate when
all records have been read. The "S" means this is a stand alone field. Defining variables in the
D-spec is considered good style and it allows you to use up to 16 characters for the field name.

I changed the data structure only slightly be indenting the fields that are subordinate to the
CCYY field.

The DO and IF statements are much easier to use and read. The Do-While-Equal syntax is
replaced with a Do-While statement. The conditional part of the statement is free format and
much easier to understand. The condition can use parentheses to remove any questions about
the intent of the logic.

To emphasize this, I coded a slightly complicated Do-While loop. It will execute the subroutine,
ReadAllCusts as long as the condition is true. The use of the parentheses makes the logical
evaluation of this statement unambiguous.

(AllRcdsReadSw = 'n') and


((*in90 = *off) or
(*in91 = *on))

I changed the MOVE statement for the array to an EVAL statement. EVAL is intended to replace
Z-ADD, ADD and MOVE statements.

General Notes on Style

As you experiment with ILE you will discover a more flexible language than RPG III. Here are
some generally accepted styles of coding you should begin to use.

· Define all variables in the D-specs

· Use long, meaningful names for the variables and subroutines.

· Use upper and lower case letters in variable names.

· Replace Z-ADD, ADD and MOVE with EVAL instructions.

· Use blank lines to improve readability.

· Use the new IF and DO syntax. Include parentheses to clarify logic.

· Use upper and lower case letters for comments.


I have intentionally kept this simple to encourage you to try out RPG-ILE. Once you convert and
compile an ILE program you will want to learn more about ILE. Go online to the Midrange
Computing company store at www.mc-store.com and choose a book appropriate to your
background.

--------------------------------------------------------------------------------

Figure 1 - Here are some RPG III code snippets.

FQPRINT O F 132 OF PRINTER


* SUBFILE
FXXD001 CF E WORKSTN

46
F R1 KSFILE SFL1
* ARRAY
E AAA 100 5 A 100 ENTRIES OF 5
* DATA STRUCTURE
I DS
I 1 40CCYY
I 1 20CC
I 3 40YY
* DO AND IF STATEMENT
C *IN90 DOWEQ*OFF
C YY IFGT 80
C MM OREQ 12
C ADD 1 CC
C ENDIF
C ENDDO
* REFERENCE 1ST ELEMENT OF ARRAY
C MOVE *BLANKS ARA,1

Figure 2 - This is the result of converting the code snippets to RPG-ILE.

FQPRINT O F 132 PRINTER OFLIND(*INOF)


* SUBFILE
FXXD001 CF E WORKSTN
F SFILE(SFL1:R1)
* ARRAY
D AAA S 5 DIM(100) ASCEND 100 ENTRIES OF 5
* DATA STRUCTURE
D DS
D CCYY 1 4 0
D CC 1 2 0
D YY 3 4 0
* DO AND IF STATEMENT
C *IN90 DOWEQ *OFF
C YY IFGT 80
C MM OREQ 12
C ADD 1 CC
C ENDIF
C ENDDO
* REFERENCE 1ST ELEMENT OF ARRAY
C MOVE *BLANKS ARA(1)

Figure 3 - Here are the code snippets written in ILE style.

D DS
D CCYY 1 4 0
D CC 1 2 0
D YY 3 4 0
* Stand Alone Field
D AllRcdsReadSw S 1
* Do and If statements
C DoW *in90 = *off
C If (YY > 80) or

47
C (MM = 12)
C Eval CC = CC + 1
C EndIf
C EndDo
* Reference 1st element of array
C Eval ARA(1) = *blanks
C DoW (AllRcdsReadSw = 'n') and
C ((*in90 = *off) or
C (*in91 = *on))
C ExSr ReadAllCusts
C EndDo

41. Using Output Specs to Print a Report

There are 3 ways that reports get printed using RPG.

The oldest and obsolete method uses the RPG cycle and is not covered in this tutorial.

The next and most widely used is covered in this topic. The report is formatted using Output
Specs. These are identified with the letter O. Be sure to use F4 when entering O specs because
they have many options.

An O spec is written by using the EXCEPT operation. This comes from the history of RPG. When
using the RPG cycle, the O Specs are automatically written. When you don't use the RPG cycle,
the O Specs are written as an EXCEPTion to the cycle.

The F spec for the printer file QPRINT identifies an indicator which the AS/400 turns *ON when
the page is full.

The third way of printing will be covered in the next topic. It uses a printer file defined using
DDS specs.

To view the print report and programming code in RPG,

Writing a Print Program in RPG with O specs:

This is the RPG program for writing a Print Report using O Specs. At the bottom, you will see a
sample of the report layout in the spool file.

Columns . . . : 1 71 Edit USER000/QRPGSRC


SEU==> TUTR005
FMT FX .....FFilenameIPEAF........L..I........Device+......KExit++Entry+A....U
*************** Beginning of data *************************************
0001.00 FCUST IF E DISK
0002.00 * The AS/400 includes a pre-defined printer file named QPRINT
0003.00 * Here, I use indicator 10 as the overflow indicator
0004.00 * That means that *IN10 will be *ON when the printed page
0005.00 * is full.
0006.00 FQPRINT O F 132 10 PRINTER

48
0007.00 *----------------------------------------------------------------
0008.00 C* Print the heading
0009.00 C EXCPTHEADS
0010.00 C* Read the first record
0011.00 C READ CUST 90
0012.00 C*
0013.00 C *IN90 DOWEQ*OFF
0014.00 C* See if the page is full. If so, print the heading.
0015.00 C *IN10 IFEQ *ON
0016.00 C EXCPTHEADS
0017.00 C MOVE *OFF *IN10
0018.00 C ENDIF
0019.00 C* Print the detail
0020.00 C EXCPTDETAIL
0021.00 C READ CUST 90
0022.00 C ENDDO
0023.00 C*
0024.00 C MOVE *ON *INLR
0025.00 C RETRN
0026.00 *----------------------------------------------------------------
0027.00 OQPRINT E 202 HEADS
0028.00 O 6 'PAGE'
0029.00 C* PAGE is a system value that will keep track of the page#
0030.00 O PAGE 10
0031.00 O 47 'CUSTOMER ORDER REPORT'
0032.00 O 65 'DATE'
0033.00 C* UDATE is a system value that is today's date
0034.00 C* The edit code Y will edit the date like xx/xx/xx
0035.00 O UDATE Y 75
0036.00 O*
0037.00 O E 1 HEADS
0038.00 O 61 '# OPEN'
0039.00 O 71 'AMT OPEN'
0040.00 O*
0041.00 O E 1 HEADS
0042.00 O 17 'CUST #'
0043.00 O 23 'NAME'
0044.00 O 61 'ORDERS'
0045.00 O 70 'ORDERS'
0046.00 O*
0047.00 O E 1 DETAIL
0048.00 O CSNBR 17
0049.00 O CSNAME 49
0050.00 C* The edit code 1 will edit the amount like 1,234.50
0051.00 O CS#OPN1 60
0052.00 O CS$OPN1 70
****************** End of data ****************************************

Once you have written the program, compile it using option 14. After you have compiled the
program, you want to call it and see what the report looks like. To call the program, simply
type on the command line: CALL PGM(USER000/TUTROO5)

Next, go to the Work Spool File (WRKSPLF), find the program, and key in a 5 to view the
report.

49
To view the print report and programming code in RPG-ILE,

Writing a Print Program in RPG-ILE with O specs:

This is the RPG-ILE program for writing a Print Report using O Specs. At the bottom, you
will see a sample of the report layout in the spool file.

Columns . . . : 6 76 Edit USER000/QRPGLESRC


SEU==> TUTR006
FMT FX FFilename++IPEASF.....L.....A.Device+.Keywords+++++++++++++++++++++++++
*************** Beginning of data *************************************
0001.00 FCUST IF E DISK
0002.00 * The AS/400 includes a pre-defined printer file named QPRINT
0003.00 * Here, I use indicator 10 as the overflow indicator
0004.00 * That means that *IN10 will be *ON when the printed page
0005.00 * is full.
0006.00 FQPRINT O F 132 PRINTER OFLIND(*In10)
0007.00 *----------------------------------------------------------------
0008.00 C* Print the heading
0009.00 C Except Headings
0010.00 C* Read the first record
0011.00 C Read CSREC 90
0012.00 C*
0013.00 C DoW *In90 = *Off
0014.00 C* See if the page is full. If so, print the heading.
0015.00 C If *In10 = *On
0016.00 C Except Headings
0017.00 C Eval *In10 = *Off
0018.00 C EndIf
0019.00 C Except Detail
0020.00 C Read CSREC 90
0021.00 C EndDo
0022.00 C*
0023.00 C Eval *InLR = *On
0024.00 C Return
0025.00 *----------------------------------------------------------------
0026.00 OQPRINT E Headings 2 2
0027.00 O 6 'PAGE'
0028.00 C* PAGE is a system value that will keep track of the page#
0029.00 O Page 10
0030.00 O 47 'CUSTOMER ORDER REPORT'
0031.00 O 65 'DATE'
0032.00 C* UDATE is a system value that is today's date
0033.00 C* The edit code Y will edit the date like xx/xx/xx
0034.00 O Udate Y 75
0035.00 O*
0036.00 O E Headings 1
0037.00 O 61 '# OPEN'
0038.00 O 71 'AMT OPEN'
0039.00 O*
0040.00 O E Headings 1
0041.00 O 17 'CUST #'
0042.00 O 23 'NAME'

50
0043.00 O 61 'ORDERS'
0044.00 O 70 'ORDERS'
0045.00 O*
0046.00 O E Detail 1
0047.00 O CSNBR 17
0048.00 O CSNAME 49
0049.00 C* The edit code 1 will edit the amount like 1,234.50
0050.00 O CS#OPN 1 60
0051.00 O CS$OPN 1 70
****************** End of data ****************************************

Once you have written the program, compile it using option 14. After you have compiled the
program, you want to call it and see what the report looks like. To call the program, simply
type on the command line: CALL PGM(USER000/TUTROO5)

Next, go to the Work Spool File (WRKSPLF), find the program, and key in a 5 to view the
report.

42. Using DDS Specs to Print a Report

As mentioned in the previous topic, there are 3 ways that reports get printed using RPG.

This topic will look at how to print using a print file defined with DDS specs.

In an earlier topic, we saw how to use DDS to define a physical file and a logical file. DDS is
also used to define print files and display files. A future topic will discuss display files.

A display and print file are different from a physical file in two ways:
1) A physical file can have only 1 record definition.
2) A print file and a display file are really defining different records, not data. I think of print
files as a buffer in memory that describes a print line.

To create the print file, STRPDM and add a member to QDDSSRC in your library. Make sure the
TYPE is PRTF.

Add a member named CUSW007. Enter the specs shown in the DDS attachment. Or if you are
lazy, copy it from library USER000.

Columns . . . : 1 71 Edit USER000/QDDSSRC


SEU==> CUSW007
FMT A* .....A*. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7
*************** Beginning of data *************************************
0001.00 A* THE NEXT LINE TELLS THE COMPILER TO LOOK IN THIS FILE
0002.00 A* FOR FIELDS THAT USE THE R FOR REFERENCE
0003.00 A REF(CUST)
0004.00 A* SKIPB(1) MEANS SKIP TO THE TOP OF THE NEXT PAGE BEFORE
0005.00 A* PRINTING THE HDG1 RECORD
0006.00 A R HDG1
0007.00 A SKIPB(1)
0008.00 A 2DATE(*YY)
0009.00 A 26'CUSTOMER ORDER REPORT'
0010.00 A 60'PAGE'

51
0011.00 A 67PAGNBR
0012.00 A* SPACEA(2) MEANS TO SPACE DOWN 2 LINES AFTER THE HDG1 RECORD
0013.00 A SPACEA(2)
0014.00 A*----------------------------------------------------------------
0015.00 A R HDG2
0016.00 A SPACEA(1)
0017.00 A 48'# OPEN'
0018.00 A 59'AMT OPEN'
0019.00 A*----------------------------------------------------------------
0020.00 A R HDG3
0021.00 A SPACEA(1)
0022.00 A 2'CUST #'
0023.00 A 10'CUSTOMER NAME'
0024.00 A 48'ORDERS'
0025.00 A 60'ORDERS'
0026.00 A SPACEA(2)
0027.00 A*----------------------------------------------------------------
0028.00 A R DETAIL
0029.00 A SPACEA(001)
0030.00 A CSNBR 6S 0O 2
0031.00 A CSNAME 30A O 10
0032.00 A* THE EDTCDE(1) INDICATES TO EDIT THE NUMERIC FIELD USING
0033.00 A* THE SYSTME DEFINED CODE OF 1. THIS IS WITH COMMAS, DECIMALS
0034.00 A* AND NEGATIVE SIGN
0035.00 A CS$OPN R O 45EDTCDE(1)
0036.00 A CS#OPN R O 58EDTCDE(1)
0037.00 A*----------------------------------------------------------------
0038.00 A R TOTAL
0039.00 A SPACEA(001)
0040.00 A 30'TOTAL'
0041.00 A TOTOPN 9S 2O 58EDTCDE(1)
****************** End of data ****************************************

I have chosen to use the same field names in the print file as the input file that I will read. I
could have used different field names, but RPG handles fields with identical names in an
interesting way.

If a field is defined in more than one place:


1) it must be the same length and type in all places.
2) the most recently assigned value will be used for all occurrences of the field.

So, since we use the same values in the print file as the input, we need only read the input file
and write the print records. As before, we still need to take care of headings and page control.

To show you different techniques, I stated the length and type of CSNBR and CSNAME in the
DDS. For the other fields, I put in R in the REF column. This tells the compiler to look for the
field with this name in the file named at the top in the REF option. It gets the field type and
length from the file CUST since that is the file named in the REF parameter. Defined fields
using the REF technique are easier and preferred.

If you are familiar with RLU (Report Layout Utility), you could use it to create the DDS for the
print file. RLU is confusing to most AS/400 programmers and is not widely used.

When you have entered the DDS, use option 14 to compile it. Since the type is PRTF, the
AS/400 compiler knows to execute command CRTPRTF.

52
Then, enter the RPG or RPG-ILE source code and compile. Notice that the RPG programs use
the printer file as the output file.

Call the program from the command line and a print file will be created. Use WRKSPLF to see
it.

Writing an RPG Print Program using DDS :

This is the RPG program for writing a Print Report using DDS. At the bottom, you will see a
sample of the report layout in the spool file.

Columns . . . : 1 71 Edit USER000/QRPGSRC


SEU==> TUTR007
FMT FX .....FFilenameIPEAF........L..I........Device+......KExit++Entry+A....U
*************** Beginning of data *************************************
0001.00 FCUST IF E DISK
0002.00 * The AS/400 includes a pre-defined printer file named QPRINT
0003.00 * Here, I use indicator 10 as the overflow indicator
0004.00 * That means that *IN10 will be *ON when the printed page
0005.00 * is full.
0006.00 FCUSW007 O E 10 PRINTER
0007.00 *----------------------------------------------------------------
0008.00 C* Print the heading
0009.00 C WRITEHDG1
0010.00 C WRITEHDG2
0011.00 C WRITEHDG3
0012.00 C* Read the first record
0013.00 C READ CUST 90
0014.00 C*
0015.00 C *IN90 DOWEQ*OFF
0016.00 C* See if the page is full. If so, print the heading.
0017.00 C *IN10 IFEQ *ON
0018.00 C WRITEHDG1
0019.00 C WRITEHDG2
0020.00 C WRITEHDG3
0021.00 C MOVE *OFF *IN10
0022.00 C ENDIF
0023.00 C* Print the detail
0024.00 C WRITEDETAIL
0025.00 C READ CUST 90
0026.00 C ENDDO
0027.00 C*
0028.00 C MOVE *ON *INLR
0029.00 C RETRN
****************** End of data ****************************************

Once you have written the program, compile it using option 14. After you have compiled the
program, you want to call it and see what the report looks like. To call the program, simply
type on the command line: CALL PGM(USER000/TUTROO7)

53
Next, go to the Work Spool File (WRKSPLF), find the program, and key in a 5 to view the
report.

Writing an RPGILE Print Program using DDS :

This is the RPG program for writing a Print Report using DDS. At the bottom, you will see a
sample of the report layout in the spool file.

Columns . . . : 6 76 Edit USER000/QRPGLESRC


SEU==> TUTR008
FMT FX FFilename++IPEASF.....L.....A.Device+.Keywords+++++++++++++++++++++++++
*************** Beginning of data *************************************
0001.00 FCUST IF E DISK
0002.00 * The AS/400 includes a pre-defined printer file named QPRINT
0003.00 * Here, I use indicator 10 as the overflow indicator
0004.00 * That means that *IN10 will be *ON when the printed page
0005.00 * is full.
0006.00 FCUSW007 O E PRINTER OFLIND(*In10)
0007.00 *----------------------------------------------------------------
0008.00 C* Print the heading
0009.00 C Write Hdg1
0010.00 C Write Hdg2
0011.00 C Write Hdg3
0012.00 C* Read the first record
0013.00 C Read CSREC 90
0014.00 C*
0015.00 C DoW *In90 = *Off
0016.00 C* See if the page is full. If so, print the heading.
0017.00 C If *In10 = *On
0018.00 C Write Hdg1
0019.00 C Write Hdg2
0020.00 C Write Hdg3
0021.00 C Eval *In10 = *Off
0022.00 C EndIf
0023.00 C Write Detail
0024.00 C Read CSREC 90
0025.00 C EndDo
0026.00 C*
0027.00 C Eval *InLR = *On
0028.00 C Return
****************** End of data ****************************************

Once you have written the program, compile it using option 14. After you have compiled the
program, you want to call it and see what the report looks like. To call the program, simply
type on the command line: CALL PGM(USER000/TUTROO8)

Next, go to the Work Spool File (WRKSPLF), find the program, and key in a 5 to view the
report.

Appendix:

54
1.It is important to understand the history behind the RPG language. The language was
originally developed in the 1960's. It was a very high-level language meaning that a lot could be
done with few programming statements. It was originally intended to be used as a report
writer, hence the name Report Program Generator.

This original form of RPG was unique is several ways:

1 - 5 different record types were used to do everything


"F" was for file definitions
"I" was for input definitions (record layouts)
"C" was for calculations
"O" was for output definitions
"E" was for exception processing

2 - There were many automatic processing features like the "cycle"


The cycle processing automatically read the input file and created the output
files… that is, no read or write statements were needed.

3 - Fixed column locations for values of each programming statement. That is, unlike
COBOL, C, Java, or Basic, the code is not free form.

4 - The use of Indicators or Switches was painfully required. A switch with a value of '0'
is off and a value of '1' is on. Switches were used to determine the results of I-O
operations and needed for simple compare instructions. For example, instead of a
statement that read like:

IF CTR > 0, Do SOMETHING

RPG read more like

COMPARE CTR to 0 and turn Indicator 90 on if it is >


If Indicator 90 is on, Do SOMETHING

The programs were sometimes rather ugly. The use of indicators made many programs very
hard to understand.

RPG has evolved nicely to look more and more like other modern languages. While indicators
are still used for Input-Output (read and write) operations, standard conditional operations are
now available. IF/THEN, DoWhile, Do Until and Select Case operands exist. While still not
completely freeform, the statements have portions that are free form. Also, powerful string
handling functions like %trim, %subst, %len and %scan are available. If you are familiar the
concepts of structured programming you will see that RPG has everything required for
structured code.

So, while RPG is about 40 years old, its newest form (RPG IV) is modern and structured. The
problem is that many programs are still in use that have very old programming styles. So, you
really must be familiar with both RPG/400 (also known as RPG III) and RPG IV (also known as
RPG ILE).

RPG is a full featured language that can do all functions of data processing: reading files,
randomly retrieving data, navigating through indexes, reading and writing to data terminal or
display files, creating print reports and database files.

55
If you are still concerned that RPG is too old to be useful, consider that Visual Basic and ASP
are really just new versions of BASIC. BASIC is as old as RPG. Also, you should know that RPG
ILE can create compiled objects that bind with modules written in other languages (like C) and
can be used to process CGI scripts on the internet and output dynamic HTML. No kidding.

If you have an RPG book, I suggest you use it in addition to (or in place of) this tutorial. It is a
challenging task to describe such a complex language in short, readable topics.

To proceed you need to be familiar with PDM (see topic 4) and should have completed the
exercise in topic 5 that copies a file.

Since it important to know the old way of doing things (RPG/400) and the new way (RPG/ILE), I
will present each program we write in both languages. Learn the RPG/400 style so you can get
a job. Learn the RPG/ILE so you can see how modern the language has become.

Topic 5 showed you how to copy a file named CUST into your user library. Since this will be the
input file to our program, make sure that your library list includes your user library. I prefer to
have this library as my current library.

So, use DSPLIBL to display your library list. If you don't see your user library in the list, use the
CHGCURLIB USER999 command. This will change your current library to USER999. Remember
that when I say USER999, I mean your user ID.

You can look at your data file with the command:


RUNQRY QRYFILE(CUST)

If this doesn't show your file, either you didn't copy the file (see Topic 5) or your library list
does not include your user library. You should see that the address for every record is "123
MAIN STREET". We will write a program to read the first record of the file and change the
address to "456 OAK". In the next tutorial we will convert the program to RPG-ILE (RPG IV). In
later topics we will change the program to read every record in the file and change the address
to "456 OAK" in every record.

We need to enter program source statements, so start PDM (STRPDM). You should see
something like:

------------------------------------------------------------------------------------
AS/400 Programming Development Manager (PDM)

Select one of the following:

1. Work with libraries


2. Work with objects
3. Work with members
4. Work with projects
5. Work with groups
6. Work with parts

9. Work with user-defined options


---------------------------------------------------------------------------------

Key in 3 and hit ENTER. Fill in the screen to look like:

Specify Members to Work With

56
Type choices, press Enter.

File . . . . . . . . . . QRPGSRC Name, F4 for list

Library . . . . . . . . user999 *LIBL, *CURLIB, name

Member:
Name . . . . . . . . . *ALL *ALL, name, *generic*
Type . . . . . . . . . *ALL *ALL, type, *generic*,

-------------------------------------------------------------------------------

Of course, change the USER999 to your user ID. Hit ENTER now.
If you get an error message that QRPGSRC was not found in USER999, you need to create the
file QRPGSRC to hold your RPG-III (RPG/400) source code. For a refresher on this, review the
topic on PDM. The command to create QRPGSRC in your library is:

CRTSRCPF USER999/QRPGSRC Your screen should look like:

File . . . . . . QRPGSRC
Library . . . . USER999 Position to . . . . .

Type options, press Enter.


2=Edit 3=Copy 4=Delete 5=Display 6=Print 7=Rename
8=Display description 9=Save 13=Change text 14=Compile 15=Create module..

Opt Member Type Text

(No members in file)

Remember from your PDM lesson that this is trying to show you a list of all of the RPG programs
that you have entered. Since you haven't entered any, there is nothing to show.
You need to add a program. Let's call the program TUTR001. This name could be any 10
characters but if you don't follow a naming convention you will confused quickly. This name is
derived from TUT (for tutorial), R for RPG and 001.

Hit F6 to add the program. Key in the name (the source member), RPG for the source type and
a short description. Your screen should look like:

---------------------------------------------------------------------------
Start Source Entry Utility (STRSEU)

Type choices, press Enter.

Source file . . . . . . . . . . > QRPGSRC Name, *PRV


Library . . . . . . . . . . . > USER000 Name, *LIBL, *CURLIB,
Source member . . . . . . . . . tutr001 Name, *PRV, *SELECT
Source type . . . . . . . . . . rpg Name, *SAME, BAS, BASP
Text 'description' . . . . . . . Change the first record in CUST

-----------------------------------------------------------------------

Now hit enter and you will see a blank screen where you can enter RPG source code.

57
Back in the seventies, programmers had to keep track of what column each operand of the RPG
statement was in. It was a mess.

With PDM (actually SEU, the Source Entry Utility), things are easier. Not easy, but easier. The
problem is that RPG is a fixed column language. It is not a free format language. SEU provides
prompting to help you but even it is a bit complicated at first.

The problem is that the different records types (F, I, E, C, O) do multiple things. That is, the I
record type can be used several different ways so it has several different ways of prompting.

The first statement of this program is a FILE specification. That is, it will name the file that we
will read and update. Since we want to read the CUST file, we will enter an F record to define
the file CUST.

To do this, hit F23. Since your PC keyboard doesn't have an F23 key, the Telnet5250 product
you are using has mapped the SHIFT-F11 key as an F23 key. So, hold down SHIFT and hit F11.
The top of your screen should look like:

Select Prompt

Type choice, press Enter.

Prompt type . . . . . . . . . . . . Values listed below

RPG/400: H,F,FC,FK,FX,U,E,L,I,IX,J (I cont),JX,DS,SS,SV,C,O,


OD,P (O cont),N,* (Comment)

Wow. This means that there are 21 different formats to choose from. This is an easy one. Since
this is a FILE specification, we will use the F prompt. So key F for the Prompt and hit ENTER.
You should now see:

0001.00
****************** End of data ********************************
Prompt type . . . F Sequence number . . . 0001.00

File File End of File


Filename Type Designation File Sequence Format

Record Mode of Length of Record


Length Processing Key Field Address Type

File Overflow Key Field Extn


Organization Indicator Start Loc Code Device

File File
Continuation Exit Entry Addition Condition

What a mess! A couple of things have happened. The first is that the display shows your first
line of the program as line 0001.00. Not only that, the SEU editor has highlighted it because it
is blank, RPG-III does not allow blank lines! The rest of the screen shows all of the fields that
might be used to define a file. Don't panic yet. All you need to enter is:

CUST for Filename

58
I for File Type
F for File Designation
E for File Format
DISK for Device (2nd line from the bottom on the right)

Hit ENTER and your values will go in the right places. Amazingly, the one value that you can't
enter here is the F that tells RPG that this is a FILE specification. So hit enter, your screen
looks like:

FMT F .....FFilenameIPEAF....RlenLK1AIOvKlocEDevice+
*************** Beginning of data ************
0001.00 CUST IF E DISK
****************** End of data ***************

It also displays an error that "The Type entry is not H, F, I, C ……"


So put your cursor on the character right before CUST and key an F.

Now you have a valid file specification:

FMT F .....FFilenameIPEAF....RlenLK1AIOvKlocEDevice+
*************** Beginning of data ************
0001.00 FCUST IF E DISK
****************** End of data ***************

Now, calm down. This may be the only time in your life that you actually key in a FILE
specification. In the world of programming, everything is copied and changed, cut and paste.
Normally, you will simple copy an existing program and then change and add statements to it.
So, what did you just define? You told the program that you will be using the file CUST, that
the file is being used for Input (you will read the file), that the file is Fixed length (almost all
files are fixed length), that the file is Externally defined (that is, it was defined by the
database language of the AS/400) and finally that the file is a DISK file (not a PRINTER or
Display Screen).

Imagine for a moment a program where the user enters a customer number on the display
screen. The program reads the customer record, looks up the customer's most recent order and
prints it. Such a program will have at least 4 files: Display screen file (a WORKSTN file)
Customer file (a DISK file) Order file (a DISK file) Printer file (a PRINTER file)

This is a simple program. It has only one file.

Now we are ready for the processing logic of the program. The total logic of this program will
be only 6 statements. Processing logic in RPG is known as CALCULATION statements and uses
the C specification and the C prompt type.

Soon, you will get more comfortable with PDM and SEU. Now, we need to add a line to after
the F statement. Do this by keying an I (for insert) on top of the 0001.00.

Your screen should look like:

FMT FX .....FFilenameIPEAF........L..I........Device+
*************** Beginning of data ************
I001.00 FCUST IF E DISK

59
When you hit ENTER, the editor will create a blank line for you and even place your cursor in
column 6 where you can enter the C for CALCULATION. With the cursor on the line with the C,
hit Shift-F11 to prompt and this time use C for the prompt type.
Your screen will now show:

Prompt type . . . C Sequence number . . . 0002.00

Level N01N02N03 Factor 1 Operation Factor 2 Result

Decimal
Length Positions H/N/P HI LO EQ Comment

Now finally some good news. Most of the RPG programming you do is using the C specification.
This type of statement is not too messy.
The first processing step of the program is to read the first record of the CUST
file. RPG needs to know 2 things about a read statement:

1)what file to read


2)what indicator to turn on if there was not a "next" record in the file
(that is, what indicator will tell you that there is no more data in the file)

Indicators are numbered from 01 to 99. There are some other special ones too.

I like to use indicators 90 thru 99 for the read statements. So enter


READ for the Operation
CUST for FACTOR 1
90 for EQ

Your screen should look like:

0001.00 FCUST IF E DISK


0002.00 C

****************** End of data *******************************

Prompt type . . . C Sequence number . . . 0002.00

Level N01N02N03 Factor 1 Operation Factor 2 Result


READ CUST
Decimal
Length Positions H/N/P HI LO EQ Comment
90

When you hit ENTER, it will look like:

FMT FX .....FFilenameIPEAF........L..I........Device+......KExit++En
*************** Beginning of data ***************************
0001.00 FCUST IF E DISK
0002.00 C READ CUST 90
****************** End of data ******************************

60
There are 3 places to enter indicators for statements. Unfortunately, it is not always easy to
figure out which place to use. The HI, LO and EQ headings come from the obsolete way
indicators were first used. In old RPG, there were no IF statements. Instead, you used a COMP
(Compare) statement to compare the values of FACTOR1 and FACTOR2 and then would set on
an indicator if FACTOR1 was higher than FACTOR2, a different indicator if FACTOR1 was lower
that FACTOR2 and finally an indicator if they were equal. We will NEVER do this.
The lesson here is simple. For a READ instruction, the indicator mentioned in the EQ field will
be turned on when there are no more records in the file.

Let's pause for a minute and look at all that is happening with these 2 statements.

The F specification tells the AS400 to set up a way to read the CUST file. It also tells it to find
the fields and attributes of the fields using the database definition of the CUST file. In most
other languages, you would need a statement to OPEN the file. Such a statement tells the
computer that you are ready to use the file. RPG assumes that you want to read the file and
automatically opens the file for you. There is a simple way to tell the AS400 that you want to
OPEN and CLOSE the file explicitly but there is no reason to do that.

The READ statement reads the first record of the file CUST and populates an area in your
program's memory with the data that is in the first field. You program has each field defined
and now has data in each field.

After the READ, the field CSNBR has a value of 1002, the field CSNAME has a value of E
LUMPKIN, the field CSADR1 has a value of 123 MAIN STREET.

We now want to change the value in CSADR1. Unlike other languages, if we move only a few
characters to a field that is 30 characters long, RPG will change only the first 3 characters. So
we will first blank out the field and then move 456 OAK to the address.

Insert a line for a new C statement. One way to do this is to key an I over the
0002.00 and hit ENTER. Then key C in column 6 and hit Shift-F11. Key C for prompt
type and hit ENTER. We want to blank out the CSADR1 field so we will move blanks
to it. RPG has some system values defined that are named like:
*BLANK or *BLANKS
*ZERO or *ZEROES
*ON or *OFF
*IN90 (for indicator 90)

As you might guess, we want to move the value *BLANK to CSADR1. So fill in your screen to look
like:

Prompt type . . . C Sequence number . . . 0003.00

Level N01N02N03 Factor 1 Operation Factor 2 Result


MOVE *BLANK CSADR1
Decimal
Length Positions H/N/P HI LO EQ Comment

Hit ENTER and your program should look like:

*************** Beginning of data *****************************


0001.00 FCUST IF E DISK

61
0002.00 C READ CUST 90
0003.00 C MOVE *BLANK CSADR1
****************** End of data ********************************

Now insert another line to MOVEL '456 OAK' to CSADR1. This says to move the characters
in between the quotes to the field named CSADR1. The operand is MOVEL for MOVE LEFT.
This means that since '456 OAK' is only 7 characters and CSADR1 is 30 characters,
move '456 OAK' to the left

You program should look like:

*************** Beginning of data **************************


0001.00 FCUST IF E DISK
0002.00 C READ CUST 90
0003.00 C MOVE *BLANK CSADR1
0004.00 C MOVE '456 OAK' CSADR1
****************** End of data *****************************

At this moment, the data on the disk has the value '123 MAIN STREET' in the area of
the record for CSADR1. If you ran this program, at this spot in the program, the
value of the field CSADR1 in memory would be '123 OAK'. But if you stopped here,
the new value ('123 OAK') would not get stored in the file. To do that you must
UPDATE the record. In RPG-III verbs or operands can be only 5 characters so the
verb is UPDAT. Also, you must use the record name for the file. This is too
complicated to explain here but trust me that the record name for the CUST file
is CSREC.

So add the statement to update the record CSREC. Now that we see that we are using
the file for Update (not just Input), it is time to change the I in the FILE
definition from I to U.

0001.00 FCUST UF E DISK


0002.00 C READ CUST 90
0003.00 C MOVE *BLANK CSADR1
0004.00 C MOVEL'456 OAK' CSADR1
0005.00 C UPDATCSREC

Now all that is left to do is to tell the program to stop.

First, we have to discuss a housekeeping item left over from the very early days
of RPG. We know that RPG will automatically open the file. However, it will only
close the file if the "LAST RECORD" indicator is ON. For now, just make sure the
last 2 statements to execute in a program are:
MOVE *ON *INLR
RETRN

The last statement is a RETRN which is an abbreviation of RETURN.

So the final program is:

0001.00 FCUST UF E DISK


0002.00 C READ CUST 90
0003.00 C MOVE *BLANK CSADR1
0004.00 C MOVEL'456 OAK' CSADR1
0005.00 C UPDATCSREC

62
0006.00 C MOVE *ON *INLR
0007.00 C RETRN

Now that you are finished, hit F3 and ENTER to save your statements.
So you now have the source statements to compile an RPG program. You compile it just like
you compiled the CL program. Key a 14 on the line next to the program name in PDM and hit
ENTER. Like:

Work with Members Using PDM

File . . . . . . QRPGSRC
Library . . . . USER999 Position to . . . . .

Type options, press Enter.


2=Edit 3=Copy 4=Delete 5=Display 6=Print 7=Re
8=Display description 9=Save 13=Change text 14=Compile 15=Cr

Opt Member Type Text


14 TUTR001 RPG Change the first record in CUST file

By the way, this program is in the USER000 library. You can see it using PDM.
After compiling your program, you will want to look at the compiled listing. Remember, you do
this with the command:

WRKSPLF

You will see something like:

Work with All Spooled Files

Type options, press Enter.


1=Send 2=Change 3=Hold 4=Delete 5=Display 6=Release
8=Attributes 9=Work with printing status

Device or Total
Opt File User Queue User Data Sts Pages
TUTR001 DAVIDMOUNT PRTDGM RDY 5
TUTR001 DAVIDMOUNT PRTDGM RDY 5

Put your cursor next to the last one and key in a 5 and hit ENTER.
You will see your compiler listing. If you key in a B at the top and hit ENTER, the AS400 will
take you to the bottom of your listing. If your compile worked, it will look like:

Final Summary
Message Count: (by Severity Number)
TOTAL 00 10 20 30 40 50
2 2 0 0 0 0 0
Program Source Totals:
Records . . . . . . . . . . : 7
Specifications . . . . . . : 7
Table Records . . . . . . . : 0
Comments . . . . . . . . . : 0

63
PRM has been called.
Program TUTR001 is placed in library USER000. 00 highest severity.
***** END OF COMPILATION ****

The phrase "Program TUTR001 is placed in library USER???" means the AS400 understood your
statements well enough to crate an executable program.
If your compile didn't work, start by making sure that you have your user library in your library
list. The easy way to do this is:

CHGCURLIB USER999

All that is left is to run the program. There are several ways to do this but the most
straightforward way is to use this command:

CALL TUTR001

The program will run almost instantly. Then if you look at the CUST file the address of the first
record will have changed:

RUNQRY QRYFILE(CUST)

2. Complete RPG Maintenance Program:

Writing an Add/Change/Delete/Inquiry maintenance program:

a) This is the DDS for the Display Program named CUSTD01.

---------------------------------------------------------------------------------------------------------------
A REF(CUST)
A CA03(03 'F3=EXIT')
A R SCR1
A 1 2USER
A O 1 28'ADD/UPDATE/DELETE/INQUIRE'
A DSPATR(HI)
A 1 72DATE
A EDTCDE(Y)
A 2 2'CUSTR01'
A 2 72TIME
A O 6 8'(A)dd, (U)pdate, (D)elete'
A O 6 34'(I)nquire, (N)ext'
A ACTION 1 B 6 53DSPATR(HI)
A O 8 28'Cust#'
A CUS# R B 8 35DSPATR(HI) EDTCDE(4)
A ERRLIN 78 O 22 2
A 90 DSPATR(RI)
A O 23 14'F3=EXIT'
A*----------------------------------------------------------------
A R SCR2
A CA09(09 'F9=DELETE')
A 1 2USER
A 1 28'CUSTOMER FILE MAINTENANCE'
A 1 72DATE
A EDTCDE(Y)
A 2 2'CUSTR01'

64
A MODE 7 O 2 37
A 2 72TIME
A 3 28'Cust#'
A CUS# R O 3 37EDTCDE(4) DSPATR(RI)
A 8 28'Name'
A CUSNAM R B 8 42
A N80 DSPATR(HI)
A 80 DSPATR(PR)
A 9 28'Address 1'
A CUSAD1 R B 9 42
A N80 DSPATR(HI)
A 80 DSPATR(PR)
A 10 28'Address 2'
A CUSAD2 R B 10 42
A N80 DSPATR(HI)
A 80 DSPATR(PR)
A 11 28'City'
A CUSCTY R B 11 42
A N80 DSPATR(HI)
A 80 DSPATR(PR)
A 12 28'State'
A CUSSTA R B 12 42
A N80 DSPATR(HI)
A 80 DSPATR(PR)
A 13 28'Zip'
A CUSZIP R Y B 13 42
A N80 DSPATR(HI)
A 80 DSPATR(PR)
A ERRLIN 78 O 22 2
A 90 DSPATR(RI)
A O 23 14'F3=EXIT'

---------------------------------------------------------------------------------------------------------------------

b)This is the RPG III source code for the Add/Change/Delete program named CUSTR01.

---------------------------------------------------------------------------------------------------------------------

FCUSTD01 CF E WORKSTN
FCUST UF E K DISK A
*----------------------------------------------------------------
* Define error messages here
I 'RECORD ALREADY ON FI-C ERR1
I 'LE'
I 'RECORD IS NOT ON FIL-C ERR2
I 'E'
I 'NO MORE RECORDS' C ERR3
I 'ZIP CANNOT BE ZERO' C ERR6
I 'NAME MUST NOT BE BL-C ERR7
I 'ANK'
I 'STATE MUST NOT BE BL-C ERR8
I 'ANK'
I 'ACTION MUST BE A, U,-C ERR9

65
I ' D OR I'
I 'RECORD ADDED SUCCE- C MSG1
I 'SSFULLY'
I 'RECORD UPDATED SUC- C MSG2
I 'CESSFULLY'
I 'RECORD DELETED SUC- C MSG3
I 'CESSFULLY'
I 'HIT F9 TO DELETE' C MSG4
I 'NO ACTION TAKEN' C MSG9
*----------------------------------------------------------------
* Key List for customer file
* (a key list is not needed since this file has only 1 key
* field, but this makes the program easier to modify if
* the file has multiple key fields)
C KEYLST KLIST
C KFLD CUS#
*----------------------------------------------------------------
* Stay in Main DO LOOP until F3 is hit from SCR1
*----------------------------------------------------------------
C *IN03 DOWEQ*OFF
* Show main ADD/UPD/INQ/DLT screen
C EXFMTSCR1
C CLEARERRLIN
C MOVE *OFF *IN90
* If user didn't hit F3, process screen based on action
C *IN03 IFEQ *OFF
C SELEC
C ACTION WHEQ 'A'
C EXSR ADDREC
C ACTION WHEQ 'D'
C EXSR DLTREC
C ACTION WHEQ 'I'
C EXSR INQREC
C ACTION WHEQ 'N'
C EXSR NXTREC
C ACTION WHEQ 'U'
C EXSR UPDREC
C OTHER
C CLEARERRLIN
C MOVELERR9 ERRLIN
C MOVE *ON *IN90
C ENDSL
C ENDIF
C ENDDO
*
C MOVE *ON *INLR
C RETRN
*----------------------------------------------------------------
C ADDREC BEGSR
* Unprotect fields but setting *in80 off
C MOVE *OFF *IN80
C MOVE ' ADD ' MODE
* See if customer # is already in CUST file
C KEYLST CHAINCUST 91
C *IN91 IFEQ *OFF

66
* If customer # is already in cust file, load up ERR MSG
C CLEARERRLIN
C MOVELERR1 ERRLIN
C MOVE *ON *IN90
C ELSE
C EXSR ADDSCR
C ENDIF
C ENDSR
*----------------------------------------------------------------
* SHOW ADD SCREEN
*----------------------------------------------------------------
C ADDSCR BEGSR
* Clear customer record except for key field(s)
C *NOKEY CLEARCUSTR
C MOVE 'N' RECOK 1
* Keep showing screen until record passes edit or F3 is hit
C RECOK DOWEQ'N'
C *IN03 ANDEQ*OFF
C EXFMTSCR2
*
C *IN03 IFEQ *OFF
C EXSR EDTCUS
C RECOK IFEQ 'Y'
C WRITECUSTR
* Show messaage that ADD was successful
C CLEARERRLIN
C MOVELMSG1 ERRLIN
C ENDIF
C ELSE
* Show message that no action was taken because F3 was hit
C CLEARERRLIN
C MOVELMSG9 ERRLIN
C ENDIF
C ENDDO
*
C MOVE *OFF *IN03
*
C ENDSR
*----------------------------------------------------------------
C DLTREC BEGSR
* Disable fields for entry by setting *IN80 on
C MOVE *ON *IN80
C MOVE 'DELETE' MODE
C CLEARERRLIN
C MOVELMSG4 ERRLIN
C MOVE *ON *IN90
* See if customer # is in CUST file
C KEYLST CHAINCUST 91
C *IN91 IFEQ *ON
* If customer # is not in CUST file, show ERR MSG
C CLEARERRLIN
C MOVELERR2 ERRLIN
C MOVE *ON *IN90
C ELSE
C EXFMTSCR2

67
C MOVE *OFF *IN90
C *IN09 IFEQ *ON
C DELETCUSTR
C CLEARERRLIN
C MOVELMSG3 ERRLIN
C ELSE
C CLEARERRLIN
C MOVELMSG9 ERRLIN
C ENDIF
C ENDIF
*
C MOVE *OFF *IN03
*
C ENDSR
*----------------------------------------------------------------
C INQREC BEGSR
* Disable fields for entry by setting *IN80 on
C MOVE *ON *IN80
C MOVE 'INQUIRY' MODE
* See if customer # is in CUST file
C KEYLST CHAINCUST 91
C *IN91 IFEQ *ON
* If customer # is not in CUST file, show ERR MSG
C CLEARERRLIN
C MOVELERR2 ERRLIN
C MOVE *ON *IN90
C ELSE
* Show Inquiry Screen
C EXFMTSCR2
C ENDIF
*
C MOVE *OFF *IN03
*
C ENDSR
*----------------------------------------------------------------
C NXTREC BEGSR
*
C MOVE *ON *IN80
C MOVE 'INQUIRY' MODE
C CLEARERRLIN
* Go forward in the file to the next record
C KEYLST SETLLCUST 92 93
* If *in92 is on, we have reached end of file
C *IN92 IFEQ *ON
C MOVELERR3 ERRLIN
C MOVE *ON *IN90
C ENDIF
* Read next record
C ERRLIN IFEQ *BLANKS
C READ CUST 90
* If *in90 is on, we have reached end of file
C *IN92 IFEQ *ON
C MOVELERR3 ERRLIN
C MOVE *ON *IN90
C ENDIF

68
C ENDIF
* If *in93 is on, we are at an existing record and we need
* to read past it
C ERRLIN IFEQ *BLANKS
C *IN93 IFEQ *ON
C READ CUST 90
* If *in90 is on, we have reached end of file
C *IN90 IFEQ *ON
C MOVELERR3 ERRLIN
C MOVE *ON *IN90
C ENDIF
C ENDIF
C ENDIF
*
C ERRLIN IFEQ *BLANKS
C EXFMTSCR2
C ENDIF
*
C MOVE *OFF *IN03
*
C ENDSR
*----------------------------------------------------------------
C UPDREC BEGSR
* Unprotect fields but setting *in80 off
C MOVE *OFF *IN80
C MOVE 'UPDATE ' MODE
* See if customer # is already in CUST file
C KEYLST CHAINCUST 91
C *IN91 IFEQ *ON
* If customer # is not in cust file, load up ERR MSG
C CLEARERRLIN
C MOVELERR2 ERRLIN
C MOVE *ON *IN90
C ELSE
C EXSR UPDSCR
C ENDIF
C ENDSR
*----------------------------------------------------------------
* SHOW UPDATE SCREEN
*----------------------------------------------------------------
C UPDSCR BEGSR
C MOVE 'N' RECOK 1
* Keep showing screen until record passes edit or F3 is hit
C RECOK DOWEQ'N'
C *IN03 ANDEQ*OFF
C EXFMTSCR2
*
C *IN03 IFEQ *OFF
C EXSR EDTCUS
C RECOK IFEQ 'Y'
C UPDATCUSTR
* Show messaage that UPDATE was successful
C CLEARERRLIN
C MOVELMSG2 ERRLIN
C ENDIF

69
C ELSE
* Show message that no action was taken because F3 was hit
C CLEARERRLIN
C MOVELMSG9 ERRLIN
C ENDIF
C ENDDO
*
C MOVE *OFF *IN03
*
C ENDSR
*----------------------------------------------------------------
C EDTCUS BEGSR
* First, set error switch that record is OK
C MOVE 'Y' RECOK
* Now, perform each edit
C CUSNAM IFEQ *BLANKS
C MOVE 'N' RECOK
C CLEARERRLIN
C MOVELERR7 ERRLIN
C MOVE *ON *IN90
C ENDIF
*
C CUSSTA IFEQ *BLANKS
C MOVE 'N' RECOK
C CLEARERRLIN
C MOVELERR8 ERRLIN
C MOVE *ON *IN90
C ENDIF
*
C CUSZIP IFEQ *ZERO
C MOVE 'N' RECOK
C CLEARERRLIN
C MOVELERR6 ERRLIN
C MOVE *ON *IN90
C ENDIF
*
C ENDSR

c). This is the RPG IV source code for the Add/Change/Delete program named CUSTR01.

---------------------------------------------------------------------------------------------------------------------
FCUSTD01 CF E WORKSTN
FCUST UF A E K DISK
*---------------------------------------------------------------------
D RecOK S 1a
*---------------------------------------------------------------------
D Err1 C CONST('RECORD ALREADY ON FI-
D LE')
D Err2 C CONST('RECORD IS NOT ON FI-
D LE')
D Err3 C CONST('NO MORE RECORDS')
D Err4 C CONST('ZIP CAN NOT BE BLANK')
D Err5 C CONST('NAME IS MANDATORY')
D Err6 C CONST('STATE IS MANDATORY')

70
D Err7 C CONST('INVALID ACTION')
D Err8 C CONST('NO MORE RECORDS')
D Msg1 C CONST('RECORD ADDED')
D Msg2 C CONST('RECORD UPDATED')
D Msg3 C CONST('RECORD DELETED')
D Msg4 C CONST('HIT F9 TO DELETE')
D Msg9 C CONST('NO ACTION TAKEN')
*---------------------------------------------------------------------
C KEYLST KLIST
C KFLD CSNBR
C*---------------------------------------------------------------------
C* Display the add, delete, inquire, next, or update screen
C* and process unless user hit F3 (indicator 03)
C
C DoW *in03 = *off
C ExFmt SCR1
C Eval ERRLIN = *blanks
C Eval *in90 = *off
C If *in03 = *off
C Select
C When Action = 'A'
C ExSr AddRecord
C When Action = 'D'
C ExSr DltRecord
C When Action = 'I'
C ExSr InqRecord
C When Action = 'N'
C ExSr NextRecord
C When Action = 'U'
C ExSr UpdRecord
C Other
C Eval ERRLIN = Err7
C Eval *in90 = *on
C EndSl
C EndIf
C EndDo
C
C Eval *inlr = *on
C Return
C*---------------------------------------------------------------------
C AddRecord BegSr
C
C* Indicator 80 is used by the display file to protect most fields
C* since we are in ADD mode, set the indicator off to allow field entry
C Eval *IN80 = *off
C Eval MODE = ' ADD'
C* See if customer is already on file. If so, display error
C KEYLST Chain CUST 91
C If *in91 = *off
C Eval ERRLIN = Err1
C* Indicator 90 draws attention to the error line with reverse display
C Eval *in90 = *on
C Else
C ExSr AddScreen
C EndIf

71
C
C EndSr
C*---------------------------------------------------------------------
C AddScreen BegSr
C
C* Clear all fields except the key field
C *NOKEY Clear CSREC
C Eval RecOK = 'n'
C* Stay on this screen until user gets it right or hits F3
C Dow RecOK = 'n' and
C *in03 = *off
C ExFmt SCR2
C If *in03 = *off
C ExSr EditRecord
C If recOK = 'y'
C Write CSREC
C Eval ERRLIN = Msg9
C EndIf
C Else
C Eval ERRLIN = Msg9
C EndIf
C EndDo
C
C Eval *in03 = *off
C
C EndSr
C*---------------------------------------------------------------------
C DltRecord BegSr
C
C* Indicator 80 is used by the display file to protect most fields
C* since we are in DLT mode, set the indicator on for no field entry
C Eval *in80 = *on
C Eval MODE = 'DELETE'
C* Display "Hit F9 to DELETE" in ERRLIN
C Eval ERRLIN = Msg4
C Eval *in90 = *on
C* See if customer is on file. If not, show error Msg
C KEYLST Chain CUST 91
C If *in91 = *on
C Eval ERRLIN = Err2
C Else
C* If customer is on file, show screen again and see if user hit F9
C* to confirm delete
C ExFmt SCR2
C Eval *in90 = *off
C If *in09 = *on
C Delete CSREC
C Eval ERRLIN = Msg3
C Else
C Eval ERRLIN = Msg9
C EndIf
C EndIf
C
C Eval *in03 = *off
C EndSr

72
C*---------------------------------------------------------------------
C InqRecord BegSr
C
C* Indicator 80 is used by the display file to protect most fields
C* since we are in DLT mode, set the indicator on for no field entry
C Eval *in80 = *on
C Eval MODE = 'INQUIRY'
C
C KEYLST Chain CUST 91
C If *in91 = *on
C Eval ERRLIN = Err2
C Eval *In90 = *on
C Else
C ExFmt SCR2
C EndIf
C Eval *in03 = *off
C
C EndSr
C*---------------------------------------------------------------------
C NextRecord BegSr
C
C Eval *in80 = *on
C Eval MODE = 'INQUIRY'
C Eval ERRLIN = *blanks
C
C* Set file cursor at cust from screen
C KEYLST SetLL CUST 92 93
C If *in92 = *on
C Eval ERRLIN = Err3
C Eval *in90 = *on
C EndIf
C
C* Read file to get next customer
C If ERRLIN = *BLANKS
C Read CUST 90
C If *in92 = *on
C Eval ERRLIN = Err3
C Eval *in90 = *on
C EndIf
C EndIf
C* If *in93 is on, we are at an existing record and need to read past it
C If *in93 = *on and
C ERRLIN = *blanks
C Read CUST 90
C If *in90 = *on
C Eval ERRLIN = Err3
C Eval *in90 = *on
C EndIf
C EndIf
C
C If ERRLIN = *blanks
C ExFmt SCR2
C EndIf
C Eval *in03 = *off
C

73
C EndSr
C*---------------------------------------------------------------------
C UpdRecord BegSr
C
C Eval *IN80 = *off
C Eval MODE = ' UPDATE '
C KEYLST Chain CUST 91
C If *in91 = *on
C Eval ERRLIN = Err2
C Eval *in90 = *on
C Else
C ExSr UpdScreen
C EndIf
C
C EndSr
C*---------------------------------------------------------------------
C UpdScreen BegSr
C Eval RecOK = 'n'
C DoW RecOK = 'n' and
C *in03 = *off
C ExFmt SCR2
C If *in03 = *off
C ExSr EditRecord
C If RecOK = 'y'
C Update CSREC
C Eval ERRLIN = Msg2
C EndIf
C Else
C Eval ERRLIN = Msg9
C EndIf
C EndDo
C Eval *in03 = *off
C EndSr
C*---------------------------------------------------------------------
C EditRecord BegSr
C Eval RecOK = 'y'
C
C If CSNAME = *blanks
C Eval RecOK = 'n'
C Eval ERRLIN = Err5
C Eval *in90 = *on
C EndIf
C
C If CSSTE = *blanks
C Eval RecOK = 'n'
C Eval ERRLIN = Err6
C Eval *in90 = *on
C EndIf
C
C If CSZIP = *zero
C Eval RecOK = 'n'
C Eval ERRLIN = Err4
C Eval *in90 = *on
C EndIf
C

74
C EndSr

3.Different Prompts in AS/400.

H Control (H) Specification

F File (F) Description Specification

FC File (F) Description Specification Continuation (SFILE/RENAME)

FK File (F) Description Specification (Continuation)

FX File (F) Description Specification (External)

U Auto Report (U) Option Specification

E File Extension (E) Specification

L Line Counter (L) Specification

I Input (I) Specification (Record Identification)

IX Input (I) Specification (Record Identification-External)

J Input (I) Specification (Field Description)

JX Input (I) Specification (Field Description-External)

DS Data Structure (I) Specification

SS Data Structure Subfield (I) Specification

SV Data Structure Subfield Initialization (I) Specification

C Calculation (C) Specification

O Output (O) Specification (File Identification and Control)

OD Output (O) Specification (Output Disk)

P Output (O) Specification (Field Description)

N Named Constant Specification

* Comment (*) Specification

---------------------------------------------------THE END----------------------------------------------------

75

You might also like