ibm-information-center/dist/eclipse/plugins/i5OS.ic.rzalf_5.4.0.1/rzalfcallileexamp.htm

463 lines
17 KiB
HTML
Raw Normal View History

2024-04-02 14:02:31 +00:00
<?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 &lt;stdlib.h&gt;
#include &lt;malloc.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;stdio.h&gt;
#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) &amp; ~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,
&amp;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-&gt;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-&gt;arg1 = arg1;
ILEarglist-&gt;arg2.s.addr = (address64_t)arg2;
ILEarglist-&gt;arg3 = arg3;
ILEarglist-&gt;arg4 = arg4;
ILEarglist-&gt;arg5 = arg5;
ILEarglist-&gt;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,
&amp;ILEarglist-&gt;base,
signature,
result_type);
if (ILEarglist-&gt;base.result.s_int32.r_int32 == 1)
printf("The results of best_wrapper function is: %s\n", arg2);
else if ( ILEarglist-&gt;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-&gt;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 &lt;= 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 &lt;stdio.h&gt;
#include &lt;math.h&gt;
#include &lt;recio.h&gt;
#include &lt;iconv.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;errno.h&gt;
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, &amp;src, &amp;srcLen, &amp;tgt, &amp;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, &amp;src, &amp;srcLen, &amp;tgt, &amp;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>