SAS Companion for the OS/2 Environment |
Because the MODULExy routine invokes
an external function that works independently of the SAS System, you must
supply information about the function's arguments so that the MODULExy routine can validate them and convert them, if necessary.
For example, suppose you want to invoke a routine that requires an integer
as an argument. Because the SAS System uses floating point values for all
of its numeric arguments, the floating point value must be converted to an
integer before you invoke the external routine. The MODULExy routine looks for this attribute information in an attribute
table that the SASCBTBL fileref points to.
The attribute table is a sequential text file that contains
descriptions of the routines that you can invoke with the MODULExy function. The function of the table is to define how the
MODULExy function should interpret its supplied
arguments when it is building a parameter list to pass to the called DLL routine.
The MODULExy routines locate
the table by opening the file that the SASCBTBL fileref points to. If you
do not define this fileref, the MODULExy routines
simply call the requested DLL routine without altering the arguments.
- CAUTION:
- Using the MODULExy functions without defining
an attribute table can cause the SAS System to fail or force you to reset
your computer.
You need to use an attribute
table for all external functions that you want to invoke.
The attribute table should contain a description for
each DLL routine that you intend to call (using a ROUTINE statement) plus
descriptions of each argument that is associated with that routine (using
ARG statements).
|
Syntax of the Attribute Table |
At any point in the
attribute table file, you can
create a comment by using an asterisk (*) as the first nonblank character
of a line or after the end of a statement (following the semicolon). You must
end the comment with a semicolon.
ROUTINE Statement
The syntax of the ROUTINE statement is
ROUTINE name MINARG=minarg
MAXARG=maxarg
|
<TRANSPOSE=YES|NO>
<MODULE=DLL-name>
|
|
<RETURNS=SHORT|USHORT|LONG|ULONG
|DOUBLE|DBLPTR|CHAR<n>>
|
|
The following are descriptions of the ROUTINE
statement
attributes:
- ROUTINE name
- starts the ROUTINE statement. You need
a ROUTINE statement for every DLL function that you intend to call using the
MODULExy function. The value for name must match the routine name or ordinal that you specified
as part of the 'module' argument in the MODULExy function, where module is the
name of the DLL (if it was not specified by the MODULE attribute, it must
be described later) and the routine name or ordinal. For example, to be able
to specify
KERNEL32,GetPath
in the MODULExy function
call, the ROUTINE name should be
GetPath
.
The name argument is case
sensitive, and it is required for the ROUTINE statement.
-
MINARG=minarg
- specifies the minimum number of arguments
to expect for the DLL routine. In most cases, this value is the same as MAXARG,
but some routines do allow a varying number of arguments. This is a required
attribute.
-
MAXARG=maxarg
- specifies the maximum number of arguments
to expect for the DLL routine. This is a required attribute.
-
CALLSEQ=BYVALUE |
BYADDR
- indicates the calling sequence method that
is used by the DLL routine. Specify BYVALUE for call-by-value and BYADDR
for call-by-address. The default value is BYADDR.
FORTRAN and COBOL are call-by-address languages; C is
usually call-by-value, although a specific routine might be implemented as
call-by-address.
The MODULE routine does not require that all arguments
use the same calling method; you can identify any exceptions by using the
BYVALUE and BYADDR options in the ARG statement, described later in this section.
-
STACKORDER=R2L | L2R
- indicates the order of arguments on the
stack as expected by the DLL routine. R2L places the arguments on the stack
according to C language conventions. The last argument (right-most in the
call syntax) is pushed first, the next-to-last argument is pushed next, and
so on, so that the first argument is the first item on the stack when the
external routine executes. R2L is the default value.
L2R places the arguments on the stack in reverse order,
pushing the first argument first, the second argument next, and so on, so
that the last argument is the first item on the stack when the external routine
executes. Pascal uses this calling convention, as do some C routines.
-
STACKPOP=CALLER
| CALLED
- specifies which routine, the caller routine
or the called routine, is responsible for popping the stack (updating
the stack pointer) upon return from the routine. The default value is CALLER
(that is, the code that calls the routine). Some routines, such as those that
use the Microsoft __stdcall attribute with 32-bit compilers, require the called
routine to pop the stack.
-
TRANSPOSE=YES | NO
- specifies whether to transpose matrices
with both more than one row and more than one column before calling the DLL
routine. This attribute applies only to routines that are called from within
PROC IML with MODULEI, MODULEIC, and MODULEIN.
TRANSPOSE=YES is necessary when SAS is calling a routine
that is written in a language that does not use row-major order to store matrices.
(For example, FORTRAN uses column-major order.)
For example, consider this matrix that has three columns
and two rows:
columns
1 2 3
--------------
rows 1 | 10 11 12
2 | 13 14 15
PROC IML stores this matrix in memory sequentially as
10, 11, 12, 13, 14, 15. However, FORTRAN routines expect this matrix to be
10, 13, 11, 14, 12, 15.
The default value is NO.
-
MODULE=DLL-name
- names the executable module (the DLL) in
which the routine resides. The MODULExy function
searches the directories that are named by the PATH environment variable.
If you specify the MODULE attribute here in the ROUTINE statement, then you
do not need to include the module name in the module
argument to the MODULE function (unless the DLL routine name that you are
calling is not unique in the attribute table). The MODULE function is described
in MODULExy.
You can have multiple ROUTINE statements that use the
same MODULE name. You can also have duplicate ROUTINE names that reside in
different DLLs.
-
RETURNS=SHORT | USHORT | LONG | ULONG | DOUBLE | DBLPTR |
CHAR<n>
- specifies the type of value that the DLL
routine returns. This value will be converted as appropriate, depending on
whether you use MODULEC (which returns a character) or MODULEN (which returns
a number). The possible return value types are
- SHORT
- short integer.
- USHORT
- unsigned short integer.
- LONG
- long integer.
- ULONG
- unsigned long integer.
- DOUBLE
- double-precision floating point number.
- DBLPTR
- a pointer to a double-precision floating
point number (instead of using a floating point register). Consult the documentation
for your DLL routine to determine how it handles double-precision floating
point values.
- CHARn
- pointer to a character string up to n bytes long. The string is expected to be null-terminated,
and it will be blank-padded or truncated as appropriate. If you do not specify n, the MODULExy function uses
the maximum length of the receiving SAS character variable.
If you do not specify the RETURNS attribute, you should
invoke the routine with only the MODULE and MODULEI call routines. You get
unpredictable values if you omit the RETURNS attribute and invoke the routine
by using the MODULEN/MODULEIN or MODULEC/MODULEIC functions.
The ROUTINE statement must be followed by as many ARG
statements as you specified in the MAXARG= option. The ARG statements must
appear in the order that the arguments are specified within the MODULExy routines.
ARG Statement
The syntax
for each ARG statement is
ARG argnum NUM|CHAR <INPUT|OUTPUT|UPDATE>
<NOTREQD|REQUIRED> <BYADDR|BYVALUE> <FDSTART>
<FORMAT=format>;
|
Here are the descriptions of the ARG statement attributes:
- ARG argnum
- defines the argument number. This a required
attribute. Define the arguments in ascending order, starting with the first
routine argument (ARG 1).
-
NUM | CHAR
- defines the argument as numeric or character.
This is a required attribute.
If you specify NUM here but you pass the routine a character
argument, the argument is converted by using the standard numeric informat.
If you specify CHAR here but you pass the routine a numeric argument, the
argument is converted by using the BEST12 informat.
-
INPUT | OUTPUT | UPDATE
- indicates the argument is either input to
the routine or to an output argument, or both. If you specify INPUT, the
argument is converted and passed to the DLL routine. If you specify OUTPUT,
the argument is not converted, but it is updated with an outgoing
value from the DLL routine. If you specify UPDATE, the argument is not only
converted and passed to the DLL routine but also updated with an outgoing
value from the routine.
You can specify OUTPUT and UPDATE only with variable
arguments (that is, you cannot specify constants or expressions).
-
NOTREQD | REQUIRED
- indicates if the argument is required.
If you specify NOTREQD, then MODULExy can omit
the argument. If other arguments follow the omitted argument, indicate the
omitted argument by including an extra comma as a place holder. For example,
to omit the second argument to routine XYZ, you would specify:
call module('XYZ',1,,3);
- CAUTION:
- Be careful when you use NOTREQD; the DLL routine must
not attempt to access the argument if it is not supplied in the call to MODULExy. If the routine does attempt to access it, your system is likely
to fail.
The REQUIRED attribute indicates that the argument is
required and cannot be omitted. REQUIRED is the default value.
-
BYADDR | BYVALUE
- indicates the argument is passed by reference
or by value.
BYADDR is the default value unless CALLSEQ=BYVALUE was
specified in the ROUTINE statement, in which case BYVALUE is the default.
Specify BYADDR when you are using a call-by-value routine that also has arguments
to be passed by address.
-
FDSTART
- indicates that the argument begins a block
of values that is grouped into a structure whose pointer is passed as a single
argument. Note that all subsequent arguments are treated as part of that
structure until the MODULExy function encounters
another FDSTART argument.
-
FORMAT=format
- names the format that presents the argument
to the DLL routine. Any formats that are supplied by SAS Institute, PROC
FORMAT-style formats, or SAS/TOOLKIT formats are valid. Note that this format
must have a corresponding valid informat if you specified the UPDATE or OUTPUT
attribute for the argument.
The FORMAT= attribute is not required, but is recommended,
since format specification is the primary purpose of the ARG statements in
the attribute table.
- CAUTION:
- Using an incorrect format can produce invalid results
or can cause a system failure.
|
The Importance of the Attribute Table |
MODULExy routines
rely heavily on the accuracy of the information in the attribute table. If
this information is incorrect, unpredictable results can occur (including
a system failure).
Consider an example routine
xyz
that expects two arguments: an
integer and a pointer. The integer is a code that indicates what action takes
place. For example, action 1 means that a 20-byte character string is written
into the area that is pointed to by the second argument, the pointer.
Now suppose that you call
xyz
by using the MODULE routine but
that you also indicate in the attribute table that the receiving character
argument is only 10 characters long:
routine xyz minarg=2 maxarg=2;
arg 1 input num byvalue format=ib4.;
arg 2 output char format=$char10.;
Regardless of the value that was
given by the LENGTH statement for the second argument to MODULE, MODULE passes
a pointer to a 10-byte area to the
xyz
routine. If
xyz
writes 20
bytes at that location, the 10 bytes of memory that follow the string that
was provided by MODULE are overwritten, causing unpredictable results:
data _null_;
length x $20;
call module('xyz',1,x);
run;
The call executes, depending on which 10 bytes were overwritten.
However, this might also cause you to lose data or cause your system to fail.
Also, note that the PEEK and PEEKC functions rely on
the validity of the pointers you supply. If the pointers are invalid, it is
possible that the SAS System could fail. For example, this code would cause
a failure:
data _null_;
length c $10;
/* trying to copy from address 0!!!*/
c = peekc(0,10);
run;
Be sure that your pointers are valid and that they are
32-bit pointers when you use PEEK and PEEKC.
Copyright 1999 by SAS Institute Inc., Cary, NC, USA. All rights reserved.