1. 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
2. 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 cant 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
werent 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.
3. 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.
4. 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
5. 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. 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) Dont use the B data type in RPG. Its
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 wasnt 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
6. 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.
7. 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
8. 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 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 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 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");
9. Working with IFS APIs Processing all of the files in an IFS
folder This program uses IFS C++ APIs 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 APIs see
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=/apis/unix2.htm
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 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
10. // 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;
11. 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.
12. Menu Option Maintenance Screen : Place cursor on the option
line desired and press F4 for Attributes Option Attribute
Maintenance screen :
13. Key In SBMJOB & strike 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.
**/
14. /*************************************************/ IF
COND(&ACTION *EQ 'P') THEN(DO) CHGVAR VAR(&RETCMD)
VALUE('?' *cat &cmd) CALL PGM(QCMDCHK) PARM(&RETCMD 256)
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 ??????????????? **/
/*************************************************/ IF
COND(&ACTION *EQ 'V') THEN(DO) CALL PGM(QCMDCHK) PARM(&CMD
&LEN) 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. QCMDCHK will syntax check the
command entered. The Prompt screen is executed by simply putting a
? in front of the command.
15. 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.
16. 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.
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 Service Program Name: QLEMF Default Public
Authority: *USE Threadsafe: Yes
17. 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; CEERAN0( seed :
rand: *omit ); result = %int(rand * range) + lowno; 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 The number returned is
in the rand variable.
18. 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 Its 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.
19. 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
20. 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.
21. 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) 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 If the Result is zero the command execution was
successful.
22. 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)
23. D rc s 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; //
-------------------------------------------------- // 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}$'; rc =
regcomp( reg : Pattern : REG_EXTENDED + REG_ICASE + REG_NOSUB ); if
rc 0; FatalError(rc:reg); endif; compiled = *on; endif; //
-------------------------------------------------- // Check the
e-mail address against the regular // expression. //
-------------------------------------------------- if (regexec( reg
: %trim(EmailAddr) : 0 : match : 0 ) = 0); valid = *on; else; valid
= *off; endif; return; /end-free This is where the pattern is
compiled into memory When done call the pgm one last time with no
parms to free thee compiled pattern from memory. regexec returns a
true or false value. Since *INLR is not set to on if parms are
passed compiled will be *ON if called multiple times.
24.
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *
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
25. 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.
26. 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.
27. 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.
28. 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 Programmers.PDF A copy of this presentation document. PDF doc C
Functions V6R1.PDF A copy of the C & C++ documentation for Unix
Type APIs. PDF doc Getting Started with APIs from RPG.PDF A copy of
the API presentation document by Scott Klement. 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 with RPG IV.PDF IBM Redbook on RPG IV.
29. 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