QSYSINCYour API Example Library
If youve written applications that use OS/400 APIs, you know what a chore it can be to figure out what some of the parameters are and how they are used. The API Reference manual is not very helpful either since it assumes you already understand what its referring to. However, help is available. The system library QSYSINC contains source include files you can copy into your RPG, COBOL, or C programs. These source include files contain source examples of the various data structures required by the APIs, written in the various languages for many of the APIs in the API Reference manual. The naming conventions for the source include files are the same as either the OPM API or the ILE service program name. If the API has a callable and a bindable interface, a source include file exists with both names.
The QSYSINC library is provided to you free with every copy of OS/400, but you need to install it by loading your OS/400 install media in the appropriate drive and typing GO LICPGM on a command line. Youll need to be signed on as QSECOFR or with a user profile that has *SECOFR *ALLOBJ special authorities. From the Licensed Programs menu, select option 11, Work with Licensed Programs. On the next panel, select the option OS/400Openness Includes. This option contains the QSYSINC library.
The table in Figure 1 lists the API source include files that are shipped with the QSYSINC library.
Shannon ODonnell Technical Editor Midrange Computing
Go to the Web to Understand PC File Formats
For years, AS/400 programmers have had to deal with only one filing systemDB2/400. Now that the AS/400 is connecting to every machine imaginable and has an Integrated File System (IFS), you may have to work with files of other formats. Fortunately, there is plenty of help for you on the World Wide Web.
A good place to start is at the People Helping One Another Know Stuff (PHOAKS) site at http://www.phoaks.com/. (Youll find plenty of information about all sorts of topics, not just computers.) Another good place to try is Val Mushinskiys Web site (http://www.geocities.com/~vmushinskiy/fformats/fformats.htm).
So the next time your boss asks if you can make your RPG program create a file in dBASE III format in the IFS, tell him, Certainly!
Robert Clark Plexsys Inc.
Rereading Files in CL
As a rule, a CL program can read a database file only once. After the Receive File (RCVF) command finds the end of the file, there is no way to reset the file pointer and read the file again. There is a way to reread a database file in a CL program, however. Here is what you must do:
1. Use the Number of current records (NBRCURRCD) parameter of the Retrieve Member Description (RTVMBRDR) command to determine the number of active records in the member.
2. Override the database file to SHARE(*YES). This establishes an open data path (ODP) and allows the Position Database File (POSDBF) command to function properly.
3. Use the Open Database File (OPNDBF) to establish a file ID link that can be referenced by POSDBF.
4. Count the records as you process them.
5. When the record counter matches the number of active records, you have processed the last record. Use the POSDBF command to reset the file pointer to the first record.
The short CL program in Figure 2 illustrates this technique. Be aware that this technique wont work correctly if other jobs are adding records to the file, or deleting records from the file, at the same time.
Tom Conover Warner/Chappell Music, Inc.
You Can Personalize Messages
The Override with Message File (OVRMSGF) command may be used to customize the messages you and your users see. OVRMSGF works differently from other types of file overrides. Other override commands, such as Override with Database File (OVRDBF), tell the system to use one file instead of another. OVRMSGF tells the system to give precedence to the overriding message file but to resort to the overridden file if necessary. That is, if a message ID is found in a message file I have created, the system will use that message. Otherwise, it will look for the message ID in IBMs message file.
To use your own custom messages, do the following:
1. Create a message file in your test library.
2. Use the Merge Message File (MRGMSGF) command to duplicate the messages you wish to customize.
3. Use the Work with Message File (WRKMSGF) command to modify the message file in your test library. Do not modify IBMs message files.
You need to run OVRMSGF in any job you want to customize. My initial program includes the code shown in Figure 3. The overrides remain in effect for the duration of the job because my initial program stays in the call stack until I sign off.
4. Figure 4 contains a list of some of my custom message texts. Most of them are humorous changes I have made to lighten my day. Others, like CPD8061, give me more information than, or different information from, the versions IBM supplies.
The second-level message text of CPX2423 contains the heading seen on the command entry display. I changed this to my personal slogan, Better living through fine code and hot coffee!
The message text for CPX2313 should look familiar to you. These are the commands executed from the system request menu. I usually modify the DSPJOB to WRKJOBwhich gives me a command line from almost anywhere. You may prefer to change DPSJOB to WRKJOB instead.
5. Figure 5 contains one-time sample code you can use to build your custom message file from frequently used original messages.
Jerry Jewel
Use Your PC to Shop for an AS/400
Q: My company is looking into buying a new AS/400. Is there a good Web site that explains all of the possible options and features for the system? Im looking for something that describes in detail what comes with IBMs different value paks and which software is actually included with the base product. The IBM sites seem to confuse the process rather than simplify it.
Dave Sommerville
A: Try http://www.as400.ibm.com/oee/config.htm. You can download a program called PCAS400, which will configure and price all the hardware and software IBM has available for the AS/400 market.
Jack McGuigan MIS Manager American Life Ins. Co
Common Calculations Make Good Subprocedures
If you still havent started writing RPG IV subprocedures, youre missing a great feature of the new RPG, but maybe youre just not sure where to begin.
I began by looking for common business processes. Every organization has them. Theyre calculations that you find over and over in programs. When you modify one of these routines, you end up having to change 50 programs.
For example, suppose several programs calculate a gross profit margin. You could start your adventure into subprocedures by creating a service program with one subprocedure. Youll need a function prototype (see Figure 6) that can be copied into both the service program source and into the source of the programs that use the function. Youll also need to write the subprocedure, as in Figure 7. To use the subprocedure, use code like that in Figure 8. As you identify more common routines, add them to the service program.
If youve put off using subprocedures, now you know where to begin. Get out those back issues of Midrange Computing, read about subprocedures, and have at it!
Paul Sgroi System One Solutions, Inc. Senior Programmer/Analyst
Whats NOOPT About?
Q: Ive read what the manual has to say about the NOOPT keyword in RPG IV, but its still not clear to me why or when you would use it. Can you shed some light on this?
John V. Thompson Honda New Zealand
A: Optimization by the compiler may mean that, at runtime, some values are stored in registers and restored to your program storage only at predefined points during normal program execution. Exception handling may break this normal execution sequence, and, consequently, program variables contained in registers may not be returned to their assigned storage locations. NOOPT ensures that the content of the associated data item always contains the latest value.
The ILE RPG Reference (SC09-2508, CD-ROM QB3AGZ00, section 3.4.2.22) states, Any data item defined in an OPM RPG/400 program is implicitly defined with NOOPT. So, if you are creating a prototype for an OPM program, you should specify NOOPT for all parameters defined within the prototype. This will avoid errors for any users of the prototype.
From this, I take it that, unless the called program expects the optimized behavior, there may be circumstances in which you have problems. Unless you can be sure of the implementation details of both called and caller programs and are prepared to delve into the intricacies of code optimization, it seems to me that the only way you can be sure the interface is bulletproof is to specify NOOPT. Because you usually put prototype definitions in copybooks, you want only one version of a prototype anywaypresumably the version that will work in all circumstances.
I dont have any information about QMHSNDPM other than the published interface and the fact that it is an OPM program. I sleep better at night knowing that the interface definition Im using will continue to work no matter what clever optimization is used or how QMHSNDPM does or does not behave.
I dont usually use NOOPT on bound calls to the ILE APIs (like CEE*). These ILE APIs presumably have been designed for an ILE environment, so I dont usually bother. Im not sure if this is sensible or not, but I havent had any problems so far.
The other place you need to specify NOOPT is on fields referenced in any exception handling code (like PSSR and condition handlers).
Derek Butland
A: Say you have a NOOPT variable that you want to pass by address to an OPM program. The compiler wont allow it if the parameter isnt defined as NOOPT, so by coding NOOPT on all OPM program calls, you avoid this potential problem. The code in Figure 9 illustrates the problem. The RPG IV compiler will generate error *RNF5423 (the NOOPT variable cannot be passed by reference to a parameter that did not specify NOOPT). Coding NOOPT on the prototype doesnt actually cause any different code to be generated for calls.
Barbara Morris IBM Toronto RPG Compiler Development
Use MAPVAL to Eliminate Date Confusion
The V4R2 Mapped Value (MAPVAL) keyword in DDS allows you to map a given value to another for display purposes. You could, for instance, specify that 01/01/0001 should display as *BLANK. Upon input to the program, workstation data management would convert the blank field back to 01/01/0001. Figure 10 illustrates how to use MAPVAL.
Bruce Vining IBM Rochester
Define Your Own Data Types in ILE COBOL
Its fairly common to want to duplicate all the elementary and group items below a base item and place them under a new base item. For example, in Figure 11, I have duplicated elem1 and elem2. Now, I have to remember to change both copies of elem1 if I change elem1 (and similarly for elem2). Of course, some people use COPY libraries to get around this problem, but, in complicated scenarios, you could end up with many COPY statements.
The TYPEDEF reserved word in V4R2 ILE COBOL allows us to define templates that can be used by both mygroup1 and mygroup2.
In Figure 12, both mygroup1 and mygroup2 end up with the exact same definition as before. However, if I want to change the way elem1 is defined, I have to do it only once.
TYPEDEF can even be used with data defined with the level number 77, which normally are not divided into subordinate elementary items. Variable mygroup3, like mygroup1 and mygroup2, also has data elements elem1 and elem2.
Chris Tandy IBM Toronto
Update Data Through a Join
Q: I would like to use interactive SQL to update columns in one table with values from another table. For example, if I have customer and ZIP code tables, as in Figure 13, can I set CustCity equal to ZpCity where CustZip is equal to ZpCode?
Jake Lee shih_lee@kingston
A: Few versions of SQL will allow you to update through a join. SQL/400 is no exception.
If you have a version of SQL that executes from a CL program, such as EXCSQLSTM (presented in The EXCSQLSTM Utility, MC, December 1994), you can use another method to carry out the update. I have done this numerous times. It is a somewhat simple but slow process.
Declare the file with the reference information (the file not being updated) in a CL program. Write a loop to read each record of the file. Inside the loop, put an update statement that includes the CL variables substituted into the proper places of the SQL statement. See Figure 14 for an example that solves your request.
Bill Robins
|
SKIP1:
Figure 3: Overriding message files
Figure 4: Customized messages
PGM PARM(&MSGF)
DCL VAR(&MSGF) TYPE(*CHAR) LEN(10)
/* Create message file in *CURRENT library */
CRTMSGF MSGF(*CURLIB/&MSGF) TEXT(Custom messages)
/* Copy the original messages */
/* In the SELECT parameter, list the IDs */
/* of the messages you want to modify */
MRGMSGF FROMMSGF(QSYS/QCPFMSG) TOMSGF(&MSGF) +
SELECT(CPC8061 CPF9897 CPF9898 CPI3405 +
CPX2313 CPX2423)
MRGMSGF FROMMSGF(QPDA/QEDTMSG) TOMSGF(&MSGF) +
SELECT(EDT0229 EDT0601 EDT1513 EDT1618 +
EDT1619)
MRGMSGF FROMMSGF(QPDA/QUOMSGF) TOMSGF(&MSGF) +
SELECT(PDM0018)
WRKMSGF MSGF(*CURLIB/&MSGF)
ENDPGM
Figure 5: Use this one-time CL program to build a custom message file
D GROSSMARGN PR 5P 2
D 9P 2 VALUE
D 9P 2 VALUE
|
Figure 6: The financial calculations prototypes member, FINCALXCPY
*=========================================================
* To compile:
*
* CRTRPGMOD MODULE(XXX/FINCALX) SRCFILE(XXX/QRPGLESRC)
* CRTSRVPGM SRVPGM(XXX/FINCALX) EXPORT(*ALL)
*
*=========================================================
H NOMAIN FLTDIV(*YES) EXPROPTS(*RESDECPOS)
*
/COPY XXX/QRPGLESRC,FINCALXCPY
*
PGROSSMARGN B EXPORT
D PI 5P 2
D MARGNSLS 9P 2 VALUE
D MARGNCST 9P 2 VALUE
* GET THE GROSS PROFIT MARGIN...
C IF MARGNSLS *ZERO
C RETURN %DECH(
C (((MARGNSLS - MARGNCST)/MARGNSLS)*100)
C : 5 : 2)
C ELSE
C RETURN *ZERO
C ENDIF
PGROSSMARGN E
Figure 7: The financial calculations service program source member, FINCALX
*============================================================
* To compile:
*
* CRTRPGMOD MODULE(XXX/FINCALXTST) SRCFILE(XXX/QRPGLESRC)
* CRTPGM PGM(XXX/FINCALXTST) BNDSRVPGM(XXX/FINCALX)
*
*============================================================
*
/COPY XXX/QRPGLESRC,FINCALXCPY
*
D SALES S 9P 2 INZ(10.00)
D COST S 9P 2 INZ( 5.00)
D MARGIN S 5P 2 INZ(*ZEROS)
*
C EVAL MARGIN = GROSSMARGN(SALES:COST)
*
C EVAL *INLR = *ON
Figure 8: Once the subprocedure is compiled and working, begin to retrofit it into your programs
D fld s 10a noopt
D proc pr
D parm 10a
C callp proc(fld)
Figure 9: Incorrect use of NOOPT
A R FMT01
A 6 5DATE:
A ADATE L B + 1DATFMT(*USA)
A MAPVAL((01/01/0001 *BLANK))
Figure 10: MAPVAL converts dates, times, and time stamps from one value to another
01 mygroup1.
05 elem1 PIC X .
05 elem2 PIC s9.
01 mygroup2.
05 elem1 PIC X .
05 elem2 PIC s9.
Figure 11: These two group items are defined with the same elementary items
DATA DIVISION.
WORKING-STORAGE SECTION.
01 mytemplate IS TYPEDEF.
05 elem1 PIC X.
05 elem2 PIC S9.
01 mygroup1 TYPE mytemplate.
01 mygroup2 TYPE mytemplate.
77 mygroup3 TYPE mytemplate.
PROCEDURE DIVISION.
MAIN-LOGIC.
MOVE B TO elem1 OF mygroup1.
MOVE C TO elem1 OF mygroup2.
MOVE D TO elem1 OF mygroup3.
COMPUTE elem2 OF mygroup1 = 7.
COMPUTE elem2 OF mygroup2 = 8.
COMPUTE elem2 OF mygroup3 = 9.
DISPLAY mygroup1.
DISPLAY mygroup2.
DISPLAY mygroup3.
GOBACK.
Figure 12: The TYPEDEF keyword allows group items to share common definitions
Customers ZIP Codes
CustId ZpCity CustName ZpCode CustAddr
CustCity
CustZip
Figure 13: Customer and ZIP code tables
PGM
DCLF FILE(ZIPCODES)
DCL VAR(&ZIPCHAR) TYPE(*CHAR) LEN(5)
READ:
RCVF MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(EOF))
CHGVAR VAR(&ZIPCHAR) VALUE(&ZPCODE)
EXCSQLSTM SQLSTM(Update Customers set CustCity= +
*CAT &ZPCITY *CAT where CustZip= +
*CAT &ZIPCHAR)
GOTO CMDLBL(READ)
EOF:
ENDPGM
Figure 14: This CL program updates a field in one file from a field in another one
LATEST COMMENTS
MC Press Online