You are on page 1of 29

APIs for RPG Programmers

What are APIs ?


Why Use APIs ?
Where to find the APIs Available
API Documentation
Working with IFS APIs
Working with Command Line APIs
Generating a Random Number
Signal APIs
QC2LE APIs
Retrieve APIs
List APIs
On the CD
Helpful Links

Presented by : Chuck Walker


The System Solutions Group, llc
What are APIs ?
By definition, an API (Application Programming Interface) is a program or procedure that
performs specific functions for the calling program. The functions performed by an API may be
system or machine type functions, database operations, calculation functions, data conversion
functions, information retrieval functions, or object manipulation functions.

In a nutshell APIs provide a method for our applications written in a High Level Language to
interface with another program, a database, the operating system, or to provide some other
functionality without needing to be concerned with the logic or even the language the API uses.

The term Application Programming Interface (API) can be applied in many different types of
procedures and functions. APIs are programs that are written to be accessed by other programs.
They are not usually called from a command line, although a few can be. They take input from
parameters and their output is returned in parameters.

Many APIs provide our programs with system information or allow us to perform system
functions from within an application program. Others may provide information from within our
application system or perform complex tasks for our application.
If we write programs or service programs with functions that validate a product code, validate a
customer number, or calculate and return a price, these could be considered APIs. So we
actually write our own APIs everyday.

In this presentation we are going to focus on the APIs that are supplied by IBM for System i that
can help us in our daily development tasks or provide functionality that we can’t accomplish
reliably in our HLL programs. The most commonly used IBM supplied APIs are probably
Execute Command (QCMDEXC), Send Data Queue (QSNDDTAQ) and Receive Data Queue
(RCVDTAQ). You have used APIs if you have ever issued a call to any of these.

APIs where introduced to the AS400 with V1 R3. Although some existed before then they weren’t
called APIs. They where referred to as IBM Supplied Programs. QCMDEXC as one of these early
APIs. With V1 R3 they started calling them APIs. At that time there were about 600 APIs.
Around the time V5 R2 was released there where over 1,500 APIs. Today there are over 2,500.
IBM has enhanced the existing APIs as well as introducing new ones in every release sinve V1 R3.

API Types :
 Original Program Model (OPM)
 Integrated Language Environment (ILE)
 UNIX-Type
ILE (Integrated Language Environment) APIs and UNIX APIs are typically procedure calls or function
calls within Service programs that are prototyped within your RPG program. Some need a Binding
directory added to the RPG program. Some are in QSYSINC and no additional Binding directory is
needed.
OPM APIs (Original Program Model) are usually executed through a standard static Call command or
operation code. These can be called from OPM programs or ILE programs.
Why Use APIs ?

In many cases APIs can allow access to system functions at a more detailed level than available
with CL commands. Many APIs allow us to gather information for processing within RPG
programs that we historically have used only in our Control Language programs.

IBM supplied APIs almost always outperform HLL programs, including Control Language
programs that perform the same tasks. This is because APIs have access to and use Machine
Interface (MI) instructions which are much more efficient than HLL instructions.

APIs can also allow access to system information and functions that are not available through
Control Language commands or RPG Operation Codes or Built in Functions. Some processing
can only be done using APIs. For example, accessing data in directories in the IFS can only be
done using APIs.

IBM supplies many APIs covering a wide range of functionality. We might as well take
advantage of the programming they have already done. If there is an API that does the job, why
reinvent the wheel? Using APIs can improve the productivity of our system as well as our
developers.

The more I use APIs in my RPG programs the less need I have for writing Control Language
Programs.
Where to Find the APIs Available
IBM provides over 2,500 Procedures and programs to your interface with the operating system
as well as performing complicated math and string functions.

IBM provides an API Finder at the following web site.


http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp

From here select the API Finder link.

API Documentation
API Documentation

The API documentation and parameter descriptions often seem complex. But, like subfile
programming, once you’ve mastered an API it’s easy to migrate it from one program to another.

Parameter Data Type Notes:


Documentation for Parameter attributes are language neutral. Because of this a direct translation of the data type and length
of parameters is not always possible.

Some of the descriptions are straight forward and can be translated directly.
CHAR(10) = 10A in RPG
PACKED(15,5) = 15P 5 in RPG

Some others are not straightforward.


A definition of CHAR(*) indicates that the length of the parameter string varies. Whenever you see a parameter with this
attribute you will likely see an additional parameter that defines the length of the parameter string used. An example of this is
the QCMDEXC API.

There are a couple of parameter data types that cause the most confusion.

BINARY(4), which does not translate to 4B 0 in RPG. BINARY(4) indicates a 4 byte binary integer, whereas 4B 0 in RPG
indicates a 2 byte binary field that contains four digits. In RPG this should be defined as (10I 0).

BINARY(4), UNSIGNED is a 4 byte unsigned binary integer (10U 0 in RPG)

Don’t use the “B” data type in RPG. It’s not a true Binary Integer . The I and U data types are. The B data type is a leftover
data type from RPG III when there wasn’t an Integer data type. So, just avoid using the B data type altogether, in spite of the
fact that much of the data center documentation still uses them.

The API Documentation is typically presented in 4 different sections.


• Parameter Summary Area
• API Description, Locks & Authority Info
• Parameter Detail Information
• Error Information
Execute Command (QCMDEXC) API

Required Parameter Group:


1 Command String Input Char(*)
2 Length of Command String Input Packed (15,5)

Optional Parameter:
3 IGC Process Control Input Char (3)

Default Public Authority: *USE


Threadsafe: *YES

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. The Process Commands (QCAPCMD) API also provides similar functions.

3. If the command to be executed is a proxy command, the QCMDEXC API will


resolve to the target command. If the target command is also a proxy, the
process repeats until either a non-proxy command is found, or the proxy chain
becomes greater than the allowed maximum.
Once a non-proxy command is found, the resolved command will replace the
proxy command in the command string to be executed.

4. Proxy commands will be resolved before the command exit points


QIBM_QCA_CHG_COMMAND and QIBM_QCA_RTV_COMMAND are
called.

Authorities and Locks


Any Command
*USE

Required Parameter Group


Command string
INPUT;CHAR(*)
The command you want to run entered as a character string. If the command contains blanks, it must be enclosed in
apostrophes. The maximum length of the character string is 32,702 characters; delimiters (the apostrophes enclosing the
string) are not counted as part of the string.

Length of command string


INPUT;PACKED(15,5)
The maximum length being passed. If the command string is passed as a quoted string, the command length is exactly the
length of the quoted string. If the command string is passed in a variable, the command length is the length of the variable. It
is not necessary to reduce the command length to the actual length of the command string in the variable, although it is
permissible to do so.
Optional Parameter Group
IGC process control
INPUT;CHAR(3)
The IGC process control instructs the system to accept double-byte data. The only value supported is IGC. IGC must be
entered using all uppercase letters.

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.

System() — Execute a Command


Format
#include <stdlib.h>
int system(const char *string);
Language Level: ANSI
Threadsafe: Yes. However, the CL command processor and all CL commands are NOT threadsafe. Use this function with
caution.

Description
The system() function passes the given string to the CL command processor for processing.

Return Value
If passed a non-NULL pointer to a string, the system() function passes the argument to the CL command processor. The
system() function returns zero if the command is successful. If passed a NULL pointer to a string, system() returns -1, and the
command processor is not called. If the command fails, system() returns 1. If the system() function fails, the global variable
_EXCP_MSGID in <stddef.h> is set with the exception message ID. The exception message ID set within the
_EXCP_MSGID variable is in job CCSID.

Example that uses system()


#include <stdlib.h>
int main(void) {
int result;
/* A data area is created, displayed and deleted: */
result = system("CRTDTAARA QTEMP/TEST TYPE(*CHAR) VALUE(’Test’)");
result = system("DSPDTAARA TEST");
result = system("DLTDTAARA TEST");
Working with IFS APIs
Processing all of the files in an IFS folder
This program uses IFS C++ API’s included in the QSYSINCLUDE objects. All you have to do
is prototype and use them. No additional binding directories are needed. For more information
on these API’s see
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=/apis/unix2.htm

This program also includes use of C++ API’s from the QC2LE binding directory. I use the
System() API to execute AS400 commands instead of calling QCMDEXEC. For more
information on the C++ API’s 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 pr 10i 0 extproc('system')


D command * value options(*string)

D OpenDir pr * extproc('opendir')
D dirName * value options(*string)

D ReadDir pr * extproc('readdir')
D dirPtr * value

D p_DirEnt s *
D dsDirEnt ds based(p_DirEnt)
D d_Resrv1 16
D d_FGenId 10u 0
D d_FileNo 10u 0
D d_RcdLen 10u 0
D d_Resrv2 10i 0
D d_Resrv3 8
D d_NLSData 12
D nls_ccsid 10i 0 overlay(d_NLSData: 1)
D nls_cntry 2 overlay(d_NLSData: 5)
D nls_lang 3 overlay(d_NLSData: 7)
D nls_resrv 3 overlay(d_NLSData: 10)
D d_NameLen 10u 0
D d_FilName 640

D CloseDir pr 10i 0 extproc('closedir')


D dirPtr * value
// Open the designated IFS directory
/free

p_Dir = OpenDir(rptPath);
if p_Dir <> *null;

// Read and process each file found in the directory


p_DirEnt = readdir(p_Dir);
dow p_DirEnt <> *null;

if %subst(d_filName: 1: d_NameLen) <> '.' and


%subst(d_filName: 1: d_NameLen) <> '..';

file = %subst(d_FilName: 1: d_NameLen);


dec = %scan('.': file: 1);

if dec > 0;
extn = %subst(file: dec+1: d_NameLen-dec);
if extn = *blanks;
%subst(file: dec: 1) = ' ';
endif;
else;
extn = *blanks;
endif;

// Process zipped file Unzip or just copy…..


Uppercase(extn);
zipFile = %trim(rptPath) + file;
if %trimr(extn) = 'ZIP';
command = ('JAVA CLASS(JvUnZip) PARM(' + apos +
%trimr(zipFile) + apos + ' ' + apos +
%trimr(xmlPath) + apos + ') CLASSPATH(' +
apos + clsPath + apos + ')');
result = System(%trimr(command));

// Process unzipped station report file by copying it


// directly into the XML directory
elseif %trimr(extn) = 'XML';
command = ('CPY OBJ(' + apos + %trimr(zipFile) +
apos + ') TODIR(' + apos + %trimr(xmlPath) +
apos + ') DTAFMT(*TEXT) OWNER(*KEEP)');
result = System(%trimr(command));
EndIf;
EndIf;
EndDo;
EndIf;
Working with Command Line APIs

The following example of a menu system that allows menu option setup capabilities that uses
IBM supplied APIs to prompt for and syntax check commands entered for the menu options.

We will look at prompting for command entry as well as syntax checking commands entered.

This screen represents an image of a menu system in production.


Menu Option Maintenance Screen :

Place cursor on the option line desired and press F4 for Attributes

Option Attribute Maintenance screen :


Key In SBMJOB & strike <F4>
Key in a command and press F4 the same as you would at a command line or in a CL program.
The result is a prompt for SBMJOB.

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 PARM(&CMD &LEN &ACTION &MSGERR &MSGDTA)

/*************************************************/
/** 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)

/*************************************************/
/** PROMPT FOR COMMAND ????????????? **/
/** THEN CHECK THE COMMAND FOR VALIDITY. **/
/*************************************************/

IF COND(&ACTION *EQ 'P') THEN(DO)


CHGVAR VAR(&RETCMD) VALUE('?' *cat &cmd) The Prompt screen is
executed by simply
putting a ? in front of
CALL PGM(QCMDCHK) PARM(&RETCMD 256) the command.
MONMSG MSGID(CPF6801)
CHGVAR VAR(&FRSTCHAR) VALUE(%SUBSTRING(&RETCMD 1 1))
IF COND(FRSTCHAR *NE '?') THEN(DO)
CHGVAR VAR(&CMD) VALUE(&RETCMD)
ENDDO
ENDDO

/*************************************************/
/** 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 wasn’t 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.
Generate a Random Number within a range
CEERANO() Function

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.

Let’s 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 it’s 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

Service Program Name: QLEMF


Default Public Authority: *USE
Threadsafe: Yes
RPGLE Sample Source Code for Random Number Generation

H DFTACTGRP(*NO) ACTGRP('QILE’)

d CEERAN0 PR
d seed 10I 0
d ranno 8F
d fc 12A options(*omit)

d highno s 10I 0 Inz(9000000)


d lowno s 10I 0 Inz(1000000)
d seed s 10I 0 inz(0)
d rand s 8F
d range s 10I 0
d result s 10I 0

/free
range = (highno - lowno) + 1; The number
CEERAN0( seed : rand: *omit ); returned is in the
result = %int(rand * range) + lowno; rand variable.

dsply result;

*INLR = *On
return
/end-free

In this case the fc value will be the Feedback value.

Feedback Codes and Conditions


CEE0000 The API completed successfully
Severity: 00
CEE2523 UTC not available to generate random seed from system time
Severity: 10
CEE2524 Seed value for &1 is not valid
Severity: 30
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.

Suspend Processing for a Time Interval


Sleep() Function
It’s not uncommon for a program to delay further processing until an event occurs or to simply
need to wait a few seconds for a submitted process to finish. In our CLP programs we use the
DLYJOB (Delay Job) command. I have seen programmers write a CLP that does nothing but
execute a DLYJOB by number of seconds passed in a parameter and then call the CLP from the
RPG program. Although this works it is a much better idea to use the built in Sleep() function.

The sleep() API was introduced in V4 R2. The Signal APIs, including the Sleep() API are IBM
supplied APIs that are available whenever a program is compiled. Therefore no additional
binding directories need to be included in your RPG program. But, it does need to be
prototyped.
A sample RPG program using Sleep() :
HOPTION(*NODEBUGIO:*SRCSTMT)
H DFTACTGRP(*NO)
**********************************************************************
*
* Sleep Parameters
*
D Sleep PR 10I 0 ExtProc('sleep')
D Seconds 10U 0 Value
*
D Secd S 10U 0
*
*
*
**********************************************************************
*
*---------------------------------------------------------------------
* Calculation Specifications
*---------------------------------------------------------------------
*
*
*
* Wait for a number of seconds
*
C Eval Secd = 60
C CallP Sleep(Secd)

C 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 let’s 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.
Executing a system command with the system() Function

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.

OVRPRTF using the System() Function


H Bnddir('QC2LE')
H Dftactgrp(*No)

D system PR 10I 0 ExtProc('system')


D Command * Value OPTIONS(*STRING)

D Result S 10I 0 Inz(0)


D Cmd S 80

C Clear cmd
C Eval Cmd = 'OVRPRTF FILE(QPQUPRFIL) OUTQ(' +
C OUTQ + ') SAVE(*YES)'
C Eval Result = system(cmd) If the Result is zero the
command execution
was successful.

OVRPRTF using QCMDEXC


D CMD S 80
D CMDLEN S 15 0

C Clear CMD
C Eval CMD = 'OVRPRTF FILE(QPQUPRFIL) OUTQ(' +
C OUTQ + ') SAVE(*YES)'
c Eval CMDLEN = %LEN(CMD)
C Call 'QCMDEXC'
C Parm CMD
C Parm CMDLEN
Validating Regular Expressions with the regexec() Function

The REGEXEC() Function is used to validate a regular expression or value based on a


predetermined pattern. The RegComp() function Compiles the expression pattern into memory.
Then the REGEXEC() Function compares the expression to the compiled pattern.

This function can be used to verify the format of e-mail addresses, zip codes, credit card
numbers, and more.

The following example is a program written by Scott Klement to validate an email address that
uses not only the regexec() function but the regcomp() and regfree() functions as well.
In this example Scott includes some an error checking routine and uses the QMHSNDPM API
to generate an error message.

To Compile:
* CRTBNDRPG MAILCHK SRCFILE(xxx/QRPGLESRC) DBGVIEW(*LIST)
*
* To Run:
* CALL PGM(MAILCHK) PARM(&EMAILADDR &VALID)
*
* Note: Don't call from the command line, it'll only
* pass 32 characters! Call from another program,
* and pass a variable that's 100 chars long for
* the first parameter!
*
* To reset program (clear variables, free compiled copy
* of regular expression, etc.) call with no parameters:
*
* CALL PGM(MAILCHK)
*
*
H DFTACTGRP(*NO) BNDDIR('QC2LE')

/copy REGEX_H

D MAILCHK PR
D EmailAddr 100A const
D valid 1A
D MAILCHK PI
D EmailAddr 100A const
D valid 1A

D FatalError PR
D rc 10I 0 value
D reg likeds(regex_t)
D compiled s 1N inz(*OFF)
D pattern s 50A varying
D reg ds likeds(regex_t)
D match ds likeds(regmatch_t)
D rc s 10I 0

/free

// --------------------------------------------------
// If called with no parameters, clean everything
// up and exit the program.
// --------------------------------------------------
When done call the pgm
if (%parms = 0);
one last time with no
regfree(reg); parms to free thee
compiled = *Off; compiled pattern from
*inlr = *on; memory.
return;
endif;

// --------------------------------------------------
// Compile the regular expression
// (This is only done once, on the first call.)
//
// For more info about this E-mail address expresion
// see:
// http://www.regular-expressions.info/email.html
// --------------------------------------------------

if (not Compiled);
pattern = '^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$'; This is where the
pattern is
rc = regcomp( reg compiled into
: Pattern memory
: REG_EXTENDED + REG_ICASE + REG_NOSUB );
if rc <> 0;
FatalError(rc:reg);
Since *INLR is
endif;
not set to on if
compiled = *on; parms are passed
endif; compiled will be
*ON if called
// -------------------------------------------------- multiple times.
// Check the e-mail address against the regular
// expression.
// --------------------------------------------------
if (regexec( reg
: %trim(EmailAddr) regexec returns a
: 0 true or false
: match value.
: 0 ) = 0);
valid = *on;
else;
valid = *off;
endif;

return;

/end-free
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* 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( 'CPF9897'
: 'QCPFMSG *LIBL'
: Data
: %len(Data)
: '*ESCAPE'
: '*PGMBDY'
: 1
: MsgKey
: ErrorCode );
/end-free
P E

The RegFree() function frees the compiled expression from memory.


The RegComp() function Compiles the expression pattern
REG_EXTENDED parameter is used except for the very simple expressions like
comparing characters.
REG_ICASE is a parameter that instructs the function to ignore case.
REG_NOSUB instructs the function to report only Success or Failure, not what was
matched.

A copy of this program and the REGEX_H file are on the CD in a folder named validateEmail.

More info can be found at http://www.regular-expressions.info/email.html


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 don’t 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.

Let’s 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 don’t 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.

A user space is created by, of course, an API (QUSCRTUS) .

A User Space always starts with a Generic Header.

A User Space may be setup to grow as the list grows.

User Spaces are processed using pointers much the same way memory objects are.

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 A Folder containing files used in the regexc() function


example. (Below)
Text File Mailchk A copy in text format of the MailChk program used in the
regexec() function example.
Text File regex_h The Header copy member needed for this example.

PDF doc APIs for RPG A copy of this presentation document.


Programmers.PDF
PDF doc C Functions V6R1.PDF A copy of the C & C++ documentation for Unix Type APIs.
PDF doc Getting Started with APIs A copy of the API presentation document by Scott Klement.
from RPG.PDF
PDF doc Datbase_And_File_APIs.PDF IBM e-book on Database and File APIs – V5 R4
PDF doc RPG-APIs-Redpaper.PDF IBM Redpaper on APIs.

PDF doc Unix-Signal-APIs.PDF IBM Redbook on Unix Signal APIs


PDF doc Who Knew you could do that IBM Redbook on RPG IV.
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

These sites has many programming examples of API usage.


http://www.think400.dk/apier.htm
http://www.thomasbishop.com/servlet/sql.tipListInq?cat=API

You might also like