API - Getting Started With APIs From RPG
API - Getting Started With APIs From RPG
Presented by
Scott Klement
http://www.scottklement.com
What’s an API?
For example...
Let’s say you’re reading a program, and you see code like the
following:
CHGVAR VAR(%BIN(&RCVVARLEN)) VALUE(1000)
In this case, you may not be sure what QDCRDEVD does, but you know it’s
name. In that case, you want to be able to type the name and get
information about the API.
The API finder is for searching for an API. It’s the “Google” for
OS/400 API information. 7
API Finder (2 of 2)
8
Found it… Now What?
Either the API finder has found a link to the API you were looking for, or
you’ve found it by browsing the categories.
The next step is to click that link and read the documentation for the API
itself.
These
Parameters are
Required, (must
always be
passed.)
These aren’t
required, but if you
pass one, you have
to pass them all.
Same here,PLUS in
order to pass group
2, you must also pass
group 1.10
QMHSNDPM Example (1 of 2)
D QMHSNDPM PR EXTPGM('QMHSNDPM')
D MsgID 7A const
D MsgFile 20A const
D MsgData 32767A const options(*varsize)
D MsgDtaLen 10I 0 const
D MsgType 10A const Use CONST for “Input”
D StackEntry 10A const parameters.
D StackCount 10I 0 const
D MsgKey 4A BINARY(4) is always
D ErrorCode 32767A options(*varsize) “10I 0” in RPG IV.
D ErrorCode ds
D BytesProv 10I 0 inz(0) More about data
D BytesAvail 10I 0 inz(0) types later.
D Msg s 200A
D MsgKey s 4A
/free
Msg = 'This is a test. Don''t read this.';
*INLR = *ON; 11
/end-free
QMHSNDPM Example (2 of 2)
12
Data Types
The data types that are listed for each API are usually pretty self explanatory.
Examples:
• CHAR(20) = character field, 20 long (20A in RPG)
• PACKED(15,5) = packed, 15 digits w/5 decimal places (15P 5 in RPG)
• POINTER(SPP) = Pointer. (Data type * in RPG – more info later!)
However, there are two data types that seem to cause a lot of confusion:
• BINARY(4) = 4 byte binary integer. (10I 0 in RPG)
• BINARY(4), UNSIGNED = 4 byte unsigned binary integer (10U 0 in RPG)
• CHAR(*) = Character field with a special length, not VARYING (Declare this
as a long character field with options(*VARSIZE) on the prototype.)
NOTE: In RPG, we declare our numeric fields by the number of digits we can store in them. So a “9P
0” field is 5 bytes long, but stores a 9 digit number. A “10I 0” field is a binary integer that’s 4 bytes
long, but stores a 10 digit number. NEVER USE THE “B” DATA TYPE, IT’S NOT A TRUE BINARY
INTEGER. THE I AND U DATA TYPES ARE, AND THEY RUN MUCH FASTER, TOO.
13
API Description
On the API’s page, after the Parameter Summary.
Description of
what the API
does.
14
Detailed Parameter Descriptions
On the API’s page, after the Authorities and Locks
There are
detailed
descriptions of
all of the APIs
parameters.
This is what
usually takes up
most of the
space on each
API’s page.
15
Sometimes
there are
additional notes
about why an
error might be
caused.
16
API Error Handling (1/2)
Offset
Dec Hex Use Type Field
0 0 Input Binary(4) Bytes Provided
4 4 Output Binary(4) Bytes Available
8 8 Output Char(7) Exception ID
15 F Output Char(1) Reserved
16 10 Output Char(*) Exception Data
• This structure is passed in a parameter to the API.
• Bytes Provided should tell the API how big the DS is. (That way, you can control the
size of the Exception Data field!) You must set this before calling the API. Don’t
leave it blank! (x’40404040’ = 1,077,952,576)
• Bytes Available tells you how much error data the API sent back.
• You can leave off the fields on the end, as long as Bytes Provided is correct.
• You can set Bytes Provided to zero if you’d like the API to send you an *ESCAPE
message when it fails.
NOTE: The CEE APIs, and the Unix-type APIs have separate
mechanisms for error handling that I do not cover here. They are
documented in the Information Center, however. 17
If you assume the API will always succeed do this. Then, if something weird does
happen, the program will halt and there’ll be good diagnostic info in the job log.
If you want to handle errors in your code, use this syntax instead. Nothing will go to the
job log, it’s up to you to handle errors:
D ErrorCode ds
D BytesProv 10I 0 inz(%size(ErrorCode)) The use of %SIZE is a
D BytesAvail 10I 0 inz(0) good idea. Let the
D MsgId 7A compiler do the work,
D 1A and help you when
D MsgData 1024A you need to make
. changes.
.
CALLP QMHSNDPM( …other parms here… : ErrorCode);
DEVD0600
When an API can return different types of data, or can return it in many different
formats (or would like to be able to do that at some point in the future!) it requests a
format.
Let’s say you’re writing an interactive program, and you want to know the IP address of
your user’s PC.
To find this out, you’ll need to retrieve information about the Display Device that he’s
using. This is done with the “Retrieve Device Description (QDCRDEVD)” API.
This API returns all sorts of information about a device. There are hundreds of fields
that it can return!
It returns different information, depending on what sort of device you’d like information
about. A tape device (*TAP) has very different information than a display device
(*DSP)! 19
20
Formats in the Manual (2/3)
To find the
possible format
names, scroll
down to the
detailed
information for
the required
parameter
group. This is
what you’ll find:
21
22
Formats & Data Structures
D QDCRDEVD PR ExtPgm('QDCRDEVD')
D RcvVar 32767A options(*varsize)
D RcvVarLen 10I 0 const
D Format 8A const
D Device 10A const
D ErrorCode 32767A options(*varsize)
D ErrorCode ds
D BytesProv 10I 0 inz(%size(ErrorCode))
D BytesAvail 10I 0 inz(0)
D MsgId 7A
D 1A
D MsgDta 1024A
D MyData ds
D IP_Address 15A overlay(MyData:878)
/free
OFFSET = Distance (in bytes) between the start of the data, and the point where the
field starts.
In other words, it’s a count of bytes from the start.
The first field is always at offset 0 because it’s at the start.
Sometimes, the offset of data that it returns won’t be at a fixed position. Instead, it’ll
pass you a variable that contains the offset of the field!
• A list of repeating fields is returned. (such as a list of jobs on the system, list of
objects in a library, etc.)
The best way to deal with variable offsets is with pointer logic.
Never, ever hard-code an offset when an API passes it to you in a parameter!
24
API Docs w/Var Offsets (1/2)
This is from format
JOBI0750 of the
Retrieve Job
Information
(QUSRJOBI) API.
It’s for retrieving
the library list for a
given job.
25
The offset from the previous slide tells us where the first library is.
The second library will be immediately after the first.
The Length of One Library Array Entry field tells us where the
second one starts. (As well as the third, and fourth, and so on.)
26
Introduction to Pointers
The best way to handle variable offsets is with pointer logic.
POINTER = A variable that stores an address in the system’s main storage (or,
“memory”).
Just as a packed (or zoned) field is a variable designed to hold a decimal number, and
a date field is designed to hold a date, and a time field is designed to hold a time, a
pointer field is designed to hold an address in your system’s memory.
What can you do with pointer fields?
• Set them to *NULL (“this pointer doesn’t currently have an address in it.”)
• Store the address of another variable in them.
• Ask the system to reserve (or “allocate”) memory, then store the address of that
memory in them.
• Add an offset to them (calculate the address X number of bytes later in memory)
• Subtract one pointer from another to calculate the offset between them.
• Base a variable on them
Based Variables
• Memory isn’t automatically reserved to store their values.
• Instead, you control the place in memory where they reside.
• You can change it on the fly by changing the pointer. 27
/free
Field1 = ‘Mashville’;
p_Field2 = %addr(Field1);
Field2 = ‘N’;
p_Field2 = %addr(Field1) + 5;
Field1 = ‘Strawbeary’;
p_Field2 = p_Field2 + 2;
Field2 = ‘r’;
p_Field2 = %addr(Field3) + (%size(Field3) – 1);
Field2 = x’0D’;
S
20
M
N a s h v i l l e
t
19 18
r
LY
a
PO
17 16
w
- O
b
T
15
e
S
FF
14
a
r
13 12
r
Mr. Happy Pointer
y
11 10 9 8 7 6 5 4 3 2 1 29
So how do you
read variable
offsets returned by
an API using
pointers?
30
API Variable Offset Example (1/3)
FQSYSPRT O F 80 PRINTER
D QUSRJOBI PR ExtPgm('QUSRJOBI')
D RcvVar 32767A options(*varsize)
D RcvVarLen 10I 0 const
D Format 8A const
D QualJob 26A const
D InternalId 16A const
D ErrorCode 32767A options(*varsize: *nopass)
D Reset 1A options(*nopass)
D MyData ds based(p_MyData)
D OffsetUsrLibl 10I 0 overlay(MyData: 89)
D NumUsrLibl 10I 0 overlay(MyData: 93)
D EntryLen 10I 0 overlay(MyData: 97)
D LibEntry ds based(p_LibEntry)
D LibName 10A
D Text 50A
D ASPNo 10I 0
D AspName 10A
31
D DataSize s 10I 0
D x s 10I 0
/free
DataSize = 1024 * 1024;
p_MyData = %alloc(DataSize);
dealloc p_MyData;
*inlr = *on;
/end-free
OQSYSPRT E PrintLib
O LibName 10
O Text 62
32
API Variable Offset Example (3/3)
*...+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...
LIBSCK Scott Klement, Testing Library
LIBFGI Library for Finished Goods Inventory
LIBSHP Library for most shipping programs
LIBSAL Library containing all sales related progs
LIBACC Library for Accounting Programs, Menus, Etc
QGPL General Purpose Library
QTEMP
Bottom
F3=Exit F12=Cancel F19=Left F20=Right F24=More keys
33
User Spaces
USER SPACE = A disk object that acts very much like a memory allocation.
34
List APIs
Many of the APIs that need to return a list of something (jobs, libraries, objects,
modules, etc.) are called “List APIs”.
Characteristics:
• Accept a user space library/name to store the results in.
• The generated user space always starts with a “generic header”
• Generic header contains offset, count and entry size information needed to read the
list.
• The format of the list entries will vary depending on the API.
For example, you might want to get a list of the interactive jobs that are active on the
system. So you’d look for an API that does that.
• APIs by Category
• Work Management (deals with how the system processes it’s workload)
• List Jobs (QUSLJOB) sounds good!
35
API to create a
FQSYSPRT O F 80 PRINTER user space.
D QUSCRTUS PR ExtPgm('QUSCRTUS')
D UserSpace 20A CONST
D ExtAttrib 10A CONST
D InitialSize 10I 0 CONST
D InitialVal 1A CONST
D PublicAuth 10A CONST
D Text 50A CONST
D Replace 10A CONST options(*nopass)
D ErrorCode 32767A options(*varsize:*nopass)
D QUSDLTUS PR ExtPgm('QUSDLTUS')
D UserSpace 20A CONST
D ErrorCode 32767A options(*varsize) API to delete a
user space object
(when we’re done.)
36
List API Example (2/4)
D QUSLJOB PR ExtPgm('QUSLJOB')
D UserSpace 20A CONST
D Format 8A CONST API to list jobs into
D QualJob 26A CONST a user space.
D Status 10A CONST
D ErrorCode 32767A options(*varsize:*nopass)
D ErrorCode ds
D BytesProv 10I 0 inz(0) API Error Code
D BytesAvail 10I 0 inz(0)
D Entry ds based(p_Entry)
D JobName 10A
D JobUser 10A Data structure for
D JobNbr 6A format JOBL0100
D IntJobId 16A
D Status 10A
D Type 1A
D SubType 1A
D x s 10I 0
D offset s 10I 0 37
QUSDLTUS('JOBLIST QTEMP'
: ErrorCode );
Delete the user
*INLR = *ON; space and end the
/end-free program. 38
List API Example (4/4)
Output specs to
OQSYSPRT E print job
O JobName 10 identifiers.
O JobUser 21
O JobNbr 28
*...+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...
QPADEV0001 BIZUJAME 239996
DSP01 KLEMSCOT 241320
ROGER KLEMROGE 242304
SYSCON QSECOFR 242331
DSP07 MARYZ 242326
S9S1 CHERYL 242223
39
More Information
Getting Started with APIs (Scott Klement: System iNetwork Programming Tips)
http://systeminetwork.com/article/getting-started-apis
Getting Started with APIs, Part 2
http://systeminetwork.com/article/club-tech-iseries-programming-tips-newsletter-49
Getting Started with APIs. Follow up to Part 2
http://systeminetwork.com/article/follow-getting-started-apis-part-2
Getting Started with APIs, Part 3
http://systeminetwork.com/article/getting-started-apis-part-3
Getting Started with APIs, Part 4
http://systeminetwork.com/article/getting-started-apis-part-4
APIs by Example (Carsten Flensburg, Gary Guthrie: System iNetwork Pgm Tips)
(ongoing series) http://systeminetwork.com/archivesearch
Working with APIs, Part 1 (Paul Morris: System iNEWS, Dec 2003)
http://www.systeminetwork.com/article.cfm?id=17570
Working with APIs, Part 2 (Paul Morris: System iNEWS, Apr 2004)
http://www.systeminetwork.com/article.cfm?id=18150
Thank you!
41