APIs For RPG Programmers
APIs For RPG Programmers
Presented by :
Chuck Walker
The System Solutions Group, llc
API Types :
API Documentation
API Documentation
The API documentation and parameter descriptions often seem complex. But, like subfile
programming, once youve mastered an API its easy to migrate it from one program to another.
Input
Input
Char(*)
Packed (15,5)
Optional Parameter:
3
IGC Process Control
Input
Char (3)
*USE
The Execute Command (QCMDEXC) API runs a single command. It is used to run a command from within a high-level
language (HLL) program or from within a CL program where it is not known at compile time what command is to be run or
what parameters are to be used.
QCMDEXC is called from within your HLL program and the command it runs is passed to it as a parameter on the CALL
command.
After the command runs, control returns to your HLL program.
Notes:
1.
Command strings in System/38 syntax can use the QCAEXEC API. The
QCAEXEC API accepts the same parameters as QCMDEXC.
2.
3.
4.
Usage Notes
While this API is threadsafe, it should not be used to run a command that is not threadsafe in a job that has multiple threads.
Use the Display Command (DSPCMD) command to determine whether a command is threadsafe.
Error Messages
Errors can be retrieved from the program status data structure.
Message ID Error Message Text
CPF0005 E Returned command string exceeds variable provided length
CPF0006 E Errors occurred in command.
CPF3C90E Literal value cannot be changed.
CPF9872 E Program or service program &1 in library &2 ended. Reason code &3.
xxxnnnn E Any escape message issued by any command may be returned. The messages listed previously are those issued
by this API. Once the API has called the command analyzer, any message issued as an escape message may
appear.
API in existence prior to V1R3
The Unix type API documentation looks a little different. It is written with C & C++ programmers
being the primary target audience.
This program also includes use of C++ APIs from the QC2LE binding directory. I use the
System() API to execute AS400 commands instead of calling QCMDEXEC. For more
information on the C++ APIs provided in these service programs refer to the
C-Functions.pdf included with this presentation .
H DEBUG OPTION(*SRCSTMT)
H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('QC2LE': 'SSPC')
* ----------------------------------------------* PROCEDURE PROTOTYPES
* ----------------------------------------------D System
D
command
pr
10i 0 extproc('system')
*
value options(*string)
D OpenDir
D
dirName
pr
*
*
extproc('opendir')
value options(*string)
D ReadDir
D
dirPtr
pr
*
*
extproc('readdir')
value
D p_DirEnt
D dsDirEnt
D
d_Resrv1
D
d_FGenId
D
d_FileNo
D
d_RcdLen
D
d_Resrv2
D
d_Resrv3
D
d_NLSData
D
nls_ccsid
D
nls_cntry
D
nls_lang
D
nls_resrv
D
d_NameLen
D
d_FilName
s
ds
D CloseDir
D
dirPtr
pr
based(p_DirEnt)
16
10u
10u
10u
10i
8
12
10i
2
3
3
10u
640
0
0
0
0
0 overlay(d_NLSData:
overlay(d_NLSData:
overlay(d_NLSData:
overlay(d_NLSData:
0
10i 0 extproc('closedir')
*
value
1)
5)
7)
10)
Place cursor on the option line desired and press F4 for Attributes
Here is the code that processes the prompt and syntax checks the command entered:
The Program accepts an Action parameter that requests a prompt for the command or
verification on the syntax.
PGM
/*************************************************/
/**
DECLARATIONS
**/
/*************************************************/
DCL
VAR(&CMD) TYPE(*CHAR) LEN(256)
DCL
VAR(&RETCMD) TYPE(*CHAR) LEN(256)
DCL
VAR(&ACTION) TYPE(*CHAR) LEN(1)
DCL
VAR(&LEN) TYPE(*DEC) LEN(15 5)
DCL
VAR(&MSGID) TYPE(*CHAR) LEN(7)
DCL
VAR(&MSGF) TYPE(*CHAR) LEN(10)
DCL
VAR(&MSGFLIB) TYPE(*CHAR) LEN(10)
DCL
VAR(&MSGDTA) TYPE(*CHAR) LEN(132)
DCL
VAR(&MSGERR) TYPE(*CHAR) LEN(1)
DCL
VAR(&FRSTCHAR) TYPE(*CHAR) LEN(1)
/*************************************************/
/**
/**
**/
**/
/*************************************************/
IF COND(&ACTION *EQ 'P') THEN(DO)
CHGVAR VAR(&RETCMD) VALUE('?' *cat &cmd)
/*************************************************/
/** VERIFY COMMAND FORMAT ???????????????
**/
/*************************************************/
QCMDCHK will
IF COND(&ACTION *EQ 'V') THEN(DO)
syntax check the
CALL PGM(QCMDCHK) PARM(&CMD &LEN)
command entered.
MONMSG MSGID(CPF0006) EXEC(DO)
RCVMSG MSGTYPE(*DIAG) MSG(&MSGDTA) +
MSGID(&MSGID) MSGF(&MSGF) MSGFLIB(&MSGFLIB)
CHGVAR VAR(&MSGERR) VALUE('Y')
ENDDO
ENDDO
END:
ENDPGM
The following API wasnt available at the time this program was written or it could have been
used for the prompt, syntax check, and even execution.
Using the QCAPCMD Program
The Process Commands (QCAPCMD) application program interface (API)
performs command analyzer processing on command strings. You can use this API
to do the following:
* Check the syntax of a command string prior to running it.
* Prompt the command and receive the changed command string.
* Use a command from a high-level language.
* Display the help for a command.
See the APIs section of the Programming category of the iSeries Information Center
for information on the QCAPCMD API.
QUSCMDLN API
The easiest Command Line API of all is the QUSCMDLN API. This can be called from a Control
Language program or an RPG program. No binding directory is needed, no parameters are required.
Just execute a call. The results look like this:
This is the native IBM Command Line with F9 to retrieve the previous command and F4 for a prompt.
If you ever need to give users the ability to get to a command line using a Function Key this would be
the way to do it. This is generally used for programmer utilities.
There are situations where a programmer may need to write a program to generate random
numbers.
For example, some company policies may dictate that employees be drug tested on a random
selection basis.
Lets say the company has 260 employees. To try and cover all of the employees within a year
you would need to test 5 employees each week. You would probably set the Lower Limit at 1
and the Higher Limit at 260 (the number of employees). You could take the program below and
put it into a loop to generate 5 random numbers. Then having an employee list sorted by
employee number set the file pointer to the record number in the file corresponding to the
random numbers generated to generate your list for the week.
CEERAN0 takes as input an integer seed, which it updates each time to avoid repetitions in the
random number sequence, and outputs a double precision random number (if given 0 as a seed,
CEERAN0 will generate a random number based on the current system time).
The program sample illustrates how to produce random numbers.
The following example uses some predetermined fixed numbers but its easy to see how we
could get the number of active employee records from our employee master file and divide that
by 52 to get the number of employees we need each week.
Required Parameter Group:
1
seed
I/O INT4
2
random_no
Output
FLOAT8
Optional Parameter:
3
fc
Output
FEEDBACK
CEERAN0
seed
ranno
fc
PR
d
d
d
d
d
d
highno
lowno
seed
rand
range
result
s
s
s
s
s
s
10I 0
8F
12A
options(*omit)
10I
10I
10I
8F
10I
10I
0 Inz(9000000)
0 Inz(1000000)
0 inz(0)
0
0
/free
range = (highno - lowno) + 1;
CEERAN0( seed : rand: *omit );
result = %int(rand * range) + lowno;
The number
returned is in the
rand variable.
dsply result;
*INLR = *On
return
/end-free
Signal APIs
A Signal API as a mechanism by which a process may be notified of, or affected by, an event
occurring in the system. The term signal is also used to refer to the event itself.
A synchronous signal is a signal that is generated by some action attributable to a program
running within the thread, such as a system-detected error, raise(), or CEESGL. An
asynchronous signal is a signal that is generated for the process by using the kill() function
or by an asynchronous event such as terminal activity or an expired timer.
A signal is said to be delivered to a process when the specified signal-handling action for the
signal is taken. A signal is said to be accepted by a process when a signal is selected and
returned by one of the sigwait functions.
A process can send a signal to another process.
A PDF named Unix-Signal-APIs is included on the CD.
Seton
LR
QC2LE APIs
QC2LE is an IBM supplied Binding Directory that resides in QSYS. Within this binding
directory are about 25 Service Programs. These service programs have at least 250 C/C++
Unix type functions that can be used in RPG programs.
A list of these functions with their descriptions can be found in the C Functions V6R1.PDF on
the CD. You can also find the QC2LE APIs under the Unix type APIs in the API Finder.
As the RPG language has evolved and we have operation codes that give us better capabilities
with string manipulation and data type conversions. As a result many of these functions are
obsolete because we now have these built in functions in RPG. Others are low level file
handling functions that we would rarely use in RPG applications.
But, there are still some of these functions that can be very helpful in our daily development
tasks. So lets look at a few of those.
The QC2LE Binding Directory must be included in the RPG program to make these functions
available. The functions to be used must also be prototyped.
It's common to use the QCMDEXC API when you want to execute a CL command from an
RPG program. But you may find it more convenient to use a C runtime library function,
system(), to accomplish the same purpose.. You can simply pass the command string as a
parameter ,without the need to pass the length of the command string, or any other parameters
for that matter.
PR
10I 0 ExtProc('system')
*
Value OPTIONS(*STRING)
D Result
D Cmd
S
S
10I 0 Inz(0)
80
C
C
C
C
Clear
Eval
Eval
cmd
Cmd = 'OVRPRTF FILE(QPQUPRFIL) OUTQ(' +
OUTQ + ') SAVE(*YES)'
If the Result is zero the
Result = system(cmd)
command execution
was successful.
S
S
80
15
Clear
Eval
Eval
Call
Parm
Parm
CMD
CMD = 'OVRPRTF FILE(QPQUPRFIL) OUTQ(' +
OUTQ + ') SAVE(*YES)'
CMDLEN = %LEN(CMD)
'QCMDEXC'
CMD
CMDLEN
PR
D
D
D
D
D
D
D
PR
FatalError
rc
reg
compiled
pattern
reg
match
100A
1A
const
100A
1A
const
PI
s
s
ds
ds
10I 0 value
likeds(regex_t)
1N
inz(*OFF)
50A
varying
likeds(regex_t)
likeds(regmatch_t)
D rc
10I 0
/free
// -------------------------------------------------// If called with no parameters, clean everything
// up and exit the program.
// -------------------------------------------------if (%parms = 0);
regfree(reg);
compiled = *Off;
*inlr = *on;
return;
endif;
Since *INLR is
not set to on if
parms are passed
compiled will be
*ON if called
multiple times.
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* FatalError(): Send exception message with error from
*
regular expression routines.
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P FatalError
B
D FatalError
PI
D
rc
10I 0 value
D
reg
likeds(regex_t)
D QMHSNDPM
PR
ExtPgm('QMHSNDPM')
D
MessageID
7A
Const
D
QualMsgF
20A
Const
D
MsgData
512A
Const
D
MsgDtaLen
10I 0 Const
D
MsgType
10A
Const
D
CallStkEnt
10A
Const
D
CallStkCnt
10I 0 Const
D
MessageKey
4A
D
ErrorCode
8192A
options(*varsize)
D ErrorCode
DS
qualified
D BytesProv
1
4I 0 inz(0)
D BytesAvail
5
8I 0 inz(0)
D MsgKey
S
4A
D Data
s
512A
varying
D Buf
s
512A
/free
regerror(rc: reg: %addr(Buf): %size(buf));
Data = %str(%addr(buf));
QMHSNDPM(
:
:
:
:
:
:
:
:
/end-free
P
'CPF9897'
'QCPFMSG
*LIBL'
Data
%len(Data)
'*ESCAPE'
'*PGMBDY'
1
MsgKey
ErrorCode );
E
Retrieve APIs
The Retrieve APIs typically return data about an object, a file member, a job etc. They are very
similar to the RTV commands we use in our CL programs. For example :
The Retrieve Member Description (QUSRMBRD) API is similar to the RTVMBRD command.
The Retrieve Object Description (QUSROBJD) API is similar to the RTVOBJD command.
The Retrieve Library Description (QLIRLIBD) API is similar to the RTVLIBD command.
Receiver Variables and Formats
These Retrieve APIs return data into a variable length Receiver variable. The length of the
Receiver variable depends on the Format being requested.
The different formats allowed can be found in the documentation for the API through the API
Finder. Different formats include different data. The documentation also includes the different
fields within the formats and detailed descriptions of each field. Just pick the format that best
satisfies your needs. Remember, as with any other programming considerations, the less data
returned the more efficient you program is. So dont just pick the format that returns ALL data
possible, pick the one that returns the data you need.
The data structures for these Retrieve API formats can be copied into your RPG programs from
QSYSINC/QRPGLESRC. The member name needed is the same name as the API.
These members are also heavily documented so this is another good resource for detailed
information.
Lets take a look at an example of some API code on line.
A web site that has several good code examples of retrieve APIs is
http://www.think400.dk/apier_2.htm
Look at the code example for QUSRMBRD (Retrieve Member Description).
Look as well at the API documentation for this API in the IBM information center.
http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp
Use the Find by Name option for API QUSRMBRD.
Be sure to look at the parameter groups as well as the layout of Format MBRD0100.
In the code sample the CallP operation has the format, the data structure to receive the data, and
the error code data structure spelled out as parameters. This program uses incoming parameters
for the Library, Source File name and Source member.
If no errors then the last change date for the member is returned.
List APIs
Many of our Control Language commands provide an *Outfile parameter. Historically when we,
as programmers, need a list of Physical Files, Logical Files, Library Names, etc. we use the
*Outfile option and then read through the output file to programmatically process each object.
For most commands that have a *Outfile option there is also a List API that will give your
program the same information.
The advantage to using a List API is that it runs so much faster than using the *Outfile method.
So, if you have a daily job that uses the *Outfile method it may be worth converting it to use a
List API. If you are writing a one-time job then simplicity of using the *Outfile may be
preferable.
The Open List APIs are used to return a list, usually a list of particular system object types
(Device descriptions, Spool Files, Jobs, etc). Also provided by IBM are APIs to process the
objects returned in the list.
Some examples of the Open list APIs are:
QGYOLJBL
Open List of Job Log Messages
QGYOLMSG
Open List of Messages
QGYOLOBJ
Open List of Objects
QGYRPRTL
Open List of Printers
QGYOLSPL
Open List of Spooled Files
Other APIs are provided allow you to retrieve lists with the attributes of objects from the Open
List APIs. The APIs to retrieve Physical / Logical file attributes is a good example of this.
Some of the File List APIs include:
QUSLMBR
List Database File Members. Generates a list of database file
members and places the list in a user space.
QDBLDBR
List Database Relations. Provides information on how files
and members are related to a specified database file.
QUSLFLD
List Fields. Generates a list of fields within a specified file
record format name.
QUSLRCD
List Record Formats. Generates a list of record formats
contained within a specified file.
The Open List APIs dont require a user space like the other List APIs talked about below. Even
though an Open List API can return a lot of information, it returns this information into a
receiver variable. The reason for this technique is that Open List APIs return a partial list,
where you select which portion of the list you currently want to process. While your program is
processing this partial list that the API returned, the API goes out to get more information for
you to process. This sequence is referred to as asynchronous processing. So, the Open List
APIs are really geared towards or fast and efficient processing.
The other List APIs usually require an object referred to as a User Space to store the data listed.
User Spaces
The List APIs use an object called a User Space. A User Space is an object that is created on
disk but is processed with pointers like a memory object instead of a PF or LF. Think of it as a
Data Area for a list of records instead of a single value. Because it is written to disk it can also
be retrieved from one session to the next.
The Retrieve APIs and the List APIs return data into a data structure. The data structure depends on the
API and the Format being used. The code for the Data Structures needed reside as copy members in
QSYSINC / QRPGLESRC.
Although all of the details of processing User Spaces and List APIs are beyond the scope of this
presentation programming examples can be found on the CD in the Getting Started with APIs
from RPG.PDF, the RPG-APIs-Redpaper.PDF, and the Who Knew you could do that with
RPG IV.PDF as well as online at the System i Info Center.
On The CD
Type
Name
Description
Folder
ValidateEmail
Text File
Mailchk
Text File
regex_h
PDF doc
PDF doc
PDF doc
PDF doc
PDF doc
PDF doc
PDF doc
Unix-Signal-APIs.PDF
Who Knew you could do that
with RPG IV.PDF
Helpful Links
This link is to the IBM i Information Center Index page. On this page there are links to the API
Finder or the i5 OS API page where there is additional API information as well as the API
Finder links.
There is also a link to System i CL Commands, System i PDFs, and the system i CL Finder.
http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp
This is a link to the System i APIs for working with the IFS. Each API listed provides a link to
show the syntax and parameters for the API.
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=/apis/unix2
.htm
This site has a number of examples of different patterns for the regexec API.
http://www.regular-expressions.info/email.html