463 lines
17 KiB
HTML
463 lines
17 KiB
HTML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE html
|
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html lang="en-us" xml:lang="en-us">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<meta name="security" content="public" />
|
|
<meta name="Robots" content="index,follow" />
|
|
<meta http-equiv="PICS-Label" content='(PICS-1.1 "http://www.icra.org/ratingsv02.html" l gen true r (cz 1 lz 1 nz 1 oz 1 vz 1) "http://www.rsac.org/ratingsv01.html" l gen true r (n 0 s 0 v 0 l 0) "http://www.classify.org/safesurf/" l gen true r (SS~~000 1))' />
|
|
<meta name="DC.Type" content="reference" />
|
|
<meta name="DC.Title" content="Examples: Call ILE procedures" />
|
|
<meta name="abstract" content="The code examples in this topic show i5/OS PASE code making a call to an ILE procedure that is part of a service program and the compiler commands that create the programs." />
|
|
<meta name="description" content="The code examples in this topic show i5/OS PASE code making a call to an ILE procedure that is part of a service program and the compiler commands that create the programs." />
|
|
<meta name="DC.Relation" scheme="URI" content="rzalfcallile.htm" />
|
|
<meta name="copyright" content="(C) Copyright IBM Corporation 2000, 2006" />
|
|
<meta name="DC.Rights.Owner" content="(C) Copyright IBM Corporation 2000, 2006" />
|
|
<meta name="DC.Format" content="XHTML" />
|
|
<meta name="DC.Identifier" content="rzalfcallileexamp" />
|
|
<meta name="DC.Language" content="en-us" />
|
|
<!-- All rights reserved. Licensed Materials Property of IBM -->
|
|
<!-- US Government Users Restricted Rights -->
|
|
<!-- Use, duplication or disclosure restricted by -->
|
|
<!-- GSA ADP Schedule Contract with IBM Corp. -->
|
|
<link rel="stylesheet" type="text/css" href="./ibmdita.css" />
|
|
<link rel="stylesheet" type="text/css" href="./ic.css" />
|
|
<title>Examples: Call ILE procedures</title>
|
|
</head>
|
|
<body id="rzalfcallileexamp"><a name="rzalfcallileexamp"><!-- --></a>
|
|
<!-- Java sync-link --><script language="Javascript" src="../rzahg/synch.js" type="text/javascript"></script>
|
|
<h1 class="topictitle1">Examples: Call ILE procedures</h1>
|
|
<div><p>The code examples in this topic show i5/OS™ PASE code making a call to an ILE
|
|
procedure that is part of a service program and the compiler commands that
|
|
create the programs.</p>
|
|
<div class="section"><p>There are two procedures within the following
|
|
code examples that show <a href="#rzalfcallileexamp__e1"><span class="keyword">i5/OS</span> PASE code</a> making a
|
|
call to an <a href="#rzalfcallileexamp__e2">ILE procedure
|
|
that is part of a service program</a>, and the <a href="#rzalfcallileexamp__e3">compiler commands that create the programs</a>. Each procedure
|
|
demonstrates different ways of working with an ILE procedure, but both procedures
|
|
call the same ILE procedure. The first procedure demonstrates building your
|
|
data structures for the _ILECALL API using <span class="keyword">i5/OS</span> PASE
|
|
system-provided methods. The second procedure then builds the argument list
|
|
manually.</p>
|
|
<div class="note"><span class="notetitle">Note:</span> By using the code examples, you agree
|
|
to the terms of the <a href="codedisclaimer.htm">Code license and disclaimer information</a>.</div>
|
|
</div>
|
|
<div class="example" id="rzalfcallileexamp__e1"><a name="rzalfcallileexamp__e1"><!-- --></a><h4 class="sectiontitle">Example 1: <span class="keyword">i5/OS</span> PASE
|
|
C code</h4><p>Interspersed in the following example code are comments that
|
|
explain the code. Make sure to read these comments as you enter or review
|
|
the example.</p>
|
|
<pre>/* Name: PASEtoILE.c
|
|
*
|
|
* You must use compiler options -qalign=natural and -qldbl128
|
|
* to force relative 16-byte alignment of type long double
|
|
* (used inside type ILEpointer)
|
|
*
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include "as400_types.h"
|
|
#include "as400_protos.h"
|
|
|
|
/*
|
|
* init_pid saves the process id (PID) of the process that
|
|
* extracted the ILEpointer addressed by ILEtarget.
|
|
* init_pid is initialized to a value that is not a
|
|
* valid PID to force initialization on the first
|
|
* reference after the exec() of this program
|
|
*
|
|
* If your code uses pthread interfaces, you can
|
|
* alternatively provide a handler registered using
|
|
* pthread_atfork() to re-initialize ILE procedure
|
|
* pointers in the child process and use a pointer or
|
|
* flag in static storage to force reinitialization
|
|
* after exec()
|
|
*/
|
|
|
|
pid_t init_pid = -1;
|
|
ILEpointer*ILEtarget; /* pointer to ILE procedure */
|
|
|
|
/*
|
|
* ROUND_QUAD finds a 16-byte aligned memory
|
|
* location at or beyond a specified address
|
|
*/
|
|
|
|
#define ROUND_QUAD(x) (((size_t)(x) + 0xf) & ~0xf)
|
|
|
|
/*
|
|
* do_init loads an ILE service program and extracts an
|
|
* ILEpointer to a procedure that is exported by that
|
|
* service program.
|
|
*/
|
|
|
|
void do_init()
|
|
{
|
|
static char ILEtarget_buf[sizeof(ILEpointer) + 15];
|
|
int actmark;
|
|
int rc;
|
|
|
|
/* _ILELOAD() loads the service program */
|
|
actmark = _ILELOAD("SHUPE/ILEPASE", ILELOAD_LIBOBJ);
|
|
if (actmark == -1)
|
|
abort();
|
|
|
|
/*
|
|
* xlc does not guarantee 16-byte alignment for
|
|
* static variables of any type, so we find an
|
|
* aligned area in an oversized buffer. _ILESYM()
|
|
* extracts an ILE procedure pointer from the
|
|
* service program activation
|
|
*/
|
|
|
|
ILEtarget = (ILEpointer*)ROUND_QUAD(ILEtarget_buf);
|
|
rc = _ILESYM(ILEtarget, actmark, "ileProcedure");
|
|
if (rc == -1)
|
|
abort();
|
|
|
|
/*
|
|
* Save the current PID in static storage so we
|
|
* can determine when to re-initialize (after fork)
|
|
*/
|
|
init_pid = getpid();
|
|
}
|
|
|
|
/*
|
|
* "aggregate" is an example of a structure or union
|
|
* data type that is passed as a by-value argument.
|
|
*/
|
|
typedef struct {
|
|
char filler[5];
|
|
} aggregate;
|
|
|
|
/*
|
|
* "result_type" and "signature" define the function
|
|
* result type and the sequence and type of all
|
|
* arguments needed for the ILE procedure identified
|
|
* by ILEtarget
|
|
*
|
|
* NOTE: The fact that this argument list contains
|
|
* fixed-point arguments shorter than 4 bytes or
|
|
* floating-point arguments shorter than 8 bytes
|
|
* implies that the target ILE C procedure is compiled
|
|
* with #pragma argument(ileProcedureName, nowiden)
|
|
*
|
|
* Without this pragma, standard C linkage for ILE
|
|
* requires 1-byte and 2-byte integer arguments to be
|
|
* widened to 4-bytes and requires 4-byte floating-point
|
|
* arguments to be widened to 8-bytes
|
|
*/
|
|
static result_type_tresult_type = RESULT_INT32;
|
|
static arg_type_tsignature[] =
|
|
{
|
|
ARG_INT32,
|
|
ARG_MEMPTR,
|
|
ARG_FLOAT64,
|
|
ARG_UINT8, /* requires #pragma nowiden in ILE code */
|
|
sizeof(aggregate),
|
|
ARG_INT16,
|
|
ARG_END
|
|
};
|
|
|
|
/*
|
|
* wrapper_1 accepts the same arguments and returns
|
|
* the same result as the ILE procedure it calls. This
|
|
* example does not require a customized or declared structure
|
|
* for the ILE argument list. This wrapper uses malloc
|
|
* to obtain storage. If an exception or signal occurs,
|
|
* the storage may not be freed. If your program needs
|
|
* to prevent such a storage leak, a signal handler
|
|
* must be built to handle it, or you can use the methods
|
|
* in wrapper_2.
|
|
*/
|
|
int wrapper_1(int arg1, void *arg2, double arg3,
|
|
char arg4, aggregate arg5, short arg6)
|
|
{
|
|
int result;
|
|
/*
|
|
* xlc does not guarantee 16-byte alignment for
|
|
* automatic (stack) variables of any type, but
|
|
* PASE malloc() always returns 16-byte aligned storage.
|
|
* size_ILEarglist() determines how much storage is
|
|
* needed, based on entries in the signature array
|
|
*/
|
|
ILEarglist_base *ILEarglist;
|
|
ILEarglist = (ILEarglist_base*)malloc( size_ILEarglist(signature) );
|
|
|
|
/*
|
|
* build_ILEarglist() copies argument values into the ILE
|
|
* argument list buffer, based on entries in the signature
|
|
* array.
|
|
*/
|
|
build_ILEarglist(ILEarglist,
|
|
&arg1,
|
|
signature);
|
|
|
|
/*
|
|
* Use a saved PID value to check if the ILEpointer
|
|
* is set. ILE procedure pointers inherited by the
|
|
* child process of a fork() are not usable because
|
|
* they point to an ILE activation group in the parent
|
|
* process
|
|
*/
|
|
if (getpid() != init_pid)
|
|
do_init();
|
|
|
|
/*
|
|
* _ILECALL calls the ILE procedure. If an exception or signal
|
|
* occurs, the heap allocation is orphaned (storage leak)
|
|
*/
|
|
_ILECALL(ILEtarget,
|
|
ILEarglist,
|
|
signature,
|
|
result_type);
|
|
result = ILEarglist->result.s_int32.r_int32;
|
|
if (result == 1) {
|
|
printf("The results of the simple wrapper is: %s\n", (char *)arg2);
|
|
}
|
|
else if (result == 0) printf("ILE received other than 1 or 2 for version.\n");
|
|
else printf("The db file never opened.\n");
|
|
free(ILEarglist);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* ILEarglistSt defines the structure of the ILE argument list.
|
|
* xlc provides 16-byte (relative) alignment of ILEpointer
|
|
* member fields because ILEpointer contains a 128-bit long
|
|
* double member. Explicit pad fields are only needed in
|
|
* front of structure and union types that do not naturally
|
|
* fall on ILE-mandated boundaries
|
|
*/
|
|
typedef struct {
|
|
ILEarglist_base base;
|
|
int32 arg1;
|
|
/* implicit 12-byte pad provided by compiler */
|
|
ILEpointer arg2;
|
|
float64 arg3;
|
|
uint8 arg4;
|
|
char filler[7]; /* pad to 8-byte alignment */
|
|
aggregate arg5; /* 5-byte aggregate (8-byte align) */
|
|
/* implicit 1-byte pad provided by compiler */
|
|
int16 arg6;
|
|
} ILEarglistSt;
|
|
|
|
/*
|
|
* wrapper_2 accepts the same arguments and returns
|
|
* the same result as the ILE procedure it calls. This
|
|
* method uses a customized or declared structure for the
|
|
* ILE argument list to improve execution efficiency and
|
|
* avoid heap storage leaks if an exception or signal occurs
|
|
*/
|
|
int wrapper_2(int arg1, void *arg2, double arg3,
|
|
char arg4, aggregate arg5, short arg6)
|
|
{
|
|
/*
|
|
* xlc does not guarantee 16-byte alignment for
|
|
* automatic (stack) variables of any type, so we
|
|
* find an aligned area in an oversized buffer
|
|
*/
|
|
char ILEarglist_buf[sizeof(ILEarglistSt) + 15];
|
|
ILEarglistSt *ILEarglist = (ILEarglistSt*)ROUND_QUAD(ILEarglist_buf);
|
|
/*
|
|
* Assignment statements are faster than calling
|
|
* build_ILEarglist()
|
|
*/
|
|
ILEarglist->arg1 = arg1;
|
|
ILEarglist->arg2.s.addr = (address64_t)arg2;
|
|
ILEarglist->arg3 = arg3;
|
|
ILEarglist->arg4 = arg4;
|
|
ILEarglist->arg5 = arg5;
|
|
ILEarglist->arg6 = arg6;
|
|
/*
|
|
* Use a saved PID value to check if the ILEpointer
|
|
* is set. ILE procedure pointers inherited by the
|
|
* child process of a fork() are not usable because
|
|
* they point to an ILE activation group in the parent
|
|
* process
|
|
*/
|
|
if (getpid() != init_pid)
|
|
do_init();
|
|
/*
|
|
* _ILECALL calls the ILE procedure. The stack may
|
|
* be unwound, but no heap storage is orphaned if
|
|
* an exception or signal occurs
|
|
*/
|
|
_ILECALL(ILEtarget,
|
|
&ILEarglist->base,
|
|
signature,
|
|
result_type);
|
|
if (ILEarglist->base.result.s_int32.r_int32 == 1)
|
|
printf("The results of best_wrapper function is: %s\n", arg2);
|
|
else if ( ILEarglist->base.result.s_int32.r_int32 == 0)
|
|
printf("ILE received other than 1 or 2 for version.\n");
|
|
else printf("The db file never opened.\n");
|
|
return ILEarglist->base.result.s_int32.r_int32;
|
|
}
|
|
void main () {
|
|
int version,
|
|
result2;
|
|
char dbText[ 25 ];
|
|
double dblNumber = 5.999;
|
|
char justChar = 'a';
|
|
short shrtNumber = 3;
|
|
aggregate agg;
|
|
strcpy( dbText, "none" );
|
|
|
|
for (version =1; version <= 2; version
|
|
++) {if(version="=" 1) {
|
|
result2="simple_wrapper(version," dbText, dblNumber, justChar, agg, shrtNumber);
|
|
} else {
|
|
result2="best_wrapper(version," dbText, dblNumber, justChar, agg, shrtNumber);
|
|
}
|
|
}
|
|
}</pre>
|
|
</div>
|
|
<div class="example" id="rzalfcallileexamp__e2"><a name="rzalfcallileexamp__e2"><!-- --></a><h4 class="sectiontitle">Example 2: ILE C code</h4><p>You
|
|
now write the ILE C code for this example on your <span class="keyword">i5/OS</span> system.
|
|
You need a source physical file in your library in which to write the code.
|
|
Again, in the ILE example, comments are interspersed. These comments are critical
|
|
to understanding the code. You should review them as you enter or review the
|
|
source.</p>
|
|
<pre>#include <stdio.h>
|
|
#include <math.h>
|
|
#include <recio.h>
|
|
#include <iconv.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
typedef struct {
|
|
char filler[5];
|
|
} aggregate;
|
|
|
|
#pragma mapinc("datafile","SHUPE/PASEDATA(*all)","both",,,"")
|
|
#include "datafile"
|
|
#pragma argument(ileProcedure, nowiden) /* not necessary */
|
|
|
|
/*
|
|
* The arguments and function result for this ILE procedure
|
|
* must be equivalent to the values presented to _ILECALL
|
|
* function in the i5/OS PASE program
|
|
*/
|
|
int ileProcedure(int arg1,
|
|
char *arg2,
|
|
double arg3,
|
|
char arg4[2],
|
|
aggregate arg5,
|
|
short arg6)
|
|
{
|
|
char fromcode[33];
|
|
char tocode[33];
|
|
iconv_t cd; /* conversion descriptor */
|
|
char *src;
|
|
char *tgt;
|
|
size_t srcLen;
|
|
size_t tgtLen;
|
|
int result;
|
|
|
|
/*
|
|
* Open a conversion descriptor to convert CCSID 37
|
|
* (EBCDIC) to CCSID 819 (ASCII), that is used for
|
|
* any character data returned to the caller
|
|
*/
|
|
memset(fromcode, 0, sizeof(fromcode));
|
|
strcpy(fromcode, "IBMCCSID000370000000");
|
|
memset(tocode, 0, sizeof(tocode));
|
|
strcpy(tocode, "IBMCCSID00819");
|
|
cd = iconv_open(tocode, fromcode);
|
|
if (cd.return_value == -1)
|
|
{
|
|
printf("iconv_open failed\n");
|
|
return -1;
|
|
}
|
|
/*
|
|
* If arg1 equals one, return constant text (converted
|
|
* to ASCII) in the buffer addressed by arg2. For any
|
|
* other arg1 value, open a file and read some text,
|
|
* then return that text (converted to ASCII) in the
|
|
* buffer addressed by arg2
|
|
*/
|
|
if (arg1 == 1)
|
|
{
|
|
src = "Sample 1 output text";
|
|
srcLen = strlen(src) + 1;
|
|
tgt = arg2; /* iconv output to arg2 buffer */
|
|
tgtLen = srcLen;
|
|
iconv(cd, &src, &srcLen, &tgt, &tgtLen);
|
|
|
|
result = 1;
|
|
}
|
|
else
|
|
{
|
|
FILE *fp;
|
|
fp = fopen("SHUPE/PASEDATA", "r");
|
|
if (!fp) /* if file open error */
|
|
{
|
|
printf("fopen(\"SHUPE/PASEDATA\", \"r\") failed, "
|
|
"errno = %i\n", errno);
|
|
result = 2;
|
|
}
|
|
else
|
|
{
|
|
char buf[25];
|
|
char *string;
|
|
errno = 0;
|
|
string = fgets(buf, sizeof(buf), fp);
|
|
if (!string)
|
|
{
|
|
printf("fgets() EOF or error, errno = %i\n", errno);
|
|
buf[0] = 0; /* null-terminate empty buffer */
|
|
}
|
|
src = buf;
|
|
srcLen = strlen(buf) + 1;
|
|
tgt = arg2; /* iconv output to arg2 buffer */
|
|
tgtLen = srcLen;
|
|
iconv(cd, &src, &srcLen, &tgt, &tgtLen);
|
|
|
|
fclose(fp);
|
|
}
|
|
result = 1;
|
|
}
|
|
/*
|
|
* Close the conversion descriptor, and return the
|
|
* result value determined above
|
|
*/
|
|
iconv_close(cd);
|
|
return result;
|
|
}</pre>
|
|
</div>
|
|
<div class="example" id="rzalfcallileexamp__e3"><a name="rzalfcallileexamp__e3"><!-- --></a><h4 class="sectiontitle">Example 3: Compiler commands to
|
|
create the programs</h4><p>When you compile your <span class="keyword">i5/OS</span> PASE
|
|
program, you must use compiler options <tt>-qalign=natural</tt> and <tt>-qldbl128</tt> to
|
|
force relative 16-byte alignment of type long double, which is used inside
|
|
type ILEpointer. This alignment is required by ILE in <span class="keyword">i5/OS</span>.
|
|
For option <tt>-bI:</tt>, you should enter the path name in which you saved
|
|
as400_libc.exp:</p>
|
|
<pre>xlc -o PASEtoILE -qldbl128 -qalign=natural
|
|
-bI:/afs/rich.xyz.com/usr1/shupe/PASE/as400_libc.exp
|
|
PASEtoILE.c</pre>
|
|
<p>When you compile your ILE C module and service
|
|
program, compile them with the teraspace option. Otherwise, <span class="keyword">i5/OS</span> PASE
|
|
cannot interact with them:</p>
|
|
<pre>CRTCMOD MODULE(MYLIB/MYMODULE)
|
|
SRCFILE(MYLIB/SRCPF)
|
|
TERASPACE(*YES *TSIFC)
|
|
|
|
CRTSRVPGM SRVPGM(MYLIB/MYSRVPGM)
|
|
MODULE(MYLIB/MOMODULE)</pre>
|
|
<p>Finally, you must compile your
|
|
DDS and propagate at least one record of data:</p>
|
|
<pre>CRTPF FILE(MYLIB/MYDATAFILE)
|
|
SRCFILE(MYLIB/SRCDDSF)
|
|
SRCMBR(MYMEMBERNAME)</pre>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="familylinks">
|
|
<div class="parentlink"><strong>Parent topic:</strong> <a href="rzalfcallile.htm" title="You can follow the instructions in this topic to prepare and call ILE procedures from your i5/OS PASE programs.">Call ILE procedures</a></div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html> |