$ file libc.so libc.so: ELF 32–bit MSB dynamic lib SPARC Version 1, dynamically linked, not stripped $ file ./libc.so ./libc.so: ELF 64–bit MSB dynamic lib SPARCV9 Version 1, dynamically linked, not stripped
/usr/lib/pa20_64
$ ln -s /usr/lib/pa20_64/libc.sl /tmp/libclnk
useptr
routine in the useptr
shared library on a 64-bit operating system. static struct MYTABLE { int value1; int value2; int value3; } mytable = {1,2,3}; useptr(toset) char **toset; { *toset = (char *)&mytable }
routine useptr minarg=1 maxarg=1; arg 1 char update format=$char20.;
data _null_; length ptrval $20 thedata $12; call module('*i','useptr',ptrval); thedata=peekclong(ptrval,12); /* Converts hexadecimal data to character data */ put thedata=$hex24.; /* Converts hexadecimal positive binary values to fixed or floating point value */ ptrval=hex40.; run;
thedata=000000010000000200000003 ptrval=800003FFFF0C
* routines XYZ and BBB in FIRST.Shared Library; routine XYZ minarg=1 maxarg=1 module=FIRST; arg 1 num input; routine BBB minarg=1 maxarg=1 module=FIRST; arg 1 num input; * routines ABC and DDD in SECOND.Shared Library; routine ABC minarg=1 maxarg=1 module=SECOND; arg 1 num input; routine DDD minarg=1 maxarg=1 module=SECOND; arg 1 num input;
filename sascbtbl 'myattr.tbl'; data _null_; do i=1 to 50; /* FIRST.Shared Library is loaded only once */ value = modulen('XYZ',i); /* SECOND.Shared Library is loaded only once */ value2 = modulen('ABC',value); put i= value= value2=; end; run;
uname
routine, which is part of the /usr/lib/pa20_64/libc.sl
int uname(struct utsname *name);In C, the
utsname
structure is defined
with the following members: #define UTSLEN 9 #define SNLEN 15 char sysname[UTSLEN]; char nodename[UTSLEN]; char release[UTSLEN]; char version[UTSLEN]; char machine[UTSLEN]; char idnumber[SNLEN];
* attribute table entry; routine uname minarg=6 maxarg=6 returns=short module=libc; arg 1 char output byaddr fdstart format=$cstr9.; arg 2 char output format=$cstr9.; arg 3 char output format=$cstr9.; arg 4 char output format=$cstr9.; arg 5 char output format=$cstr9.; arg 6 char output format=$cstr15.;The following example shows the SAS source code to call the
uname
routine from within the DATA step: x 'if [ ! -L ./libc ]; then ln -s /usr/lib/pa20_64/libc.sl ./libc ; fi' ; x 'setenv LD_LIBRARY_PATH .:/usr/lib:/lib:/usr/lib/pa20_64' data _null_; length sysname $9 nodename $9 release $9 version $9 machine $9 idnumber $15. retain sysname nodename release version machine idnumber “ “; rc=modulen('uname', sysname, nodename, release, version, machine, idnumber) put rc = ; put sysname = ; put nodename = ; put release = ; put version = ; put machine = ; put idnumber = ; run;
* attribute table entry for ABC; routine abc minarg=2 maxarg=2; arg 1 input format=ib4.; arg 2 output format=ib4.;Here is the DATA step with the MODULE calls:
data _null_; x=5; /* passing a variable as the */ /* second argument - OK */ call module('abc',1,x); /* passing a constant as the */ /* second argument - INVALID */ call module('abc',1,2); /* passing an expression as the */ /* second argument - INVALID */ call module('abc',1,x+1); run;
x
is updated by the value that the abc
routine returns for the second argument. The second call to MODULE
is not correct because a constant is passed. MODULE issues a warning
indicating you have passed a constant, and passes a temporary area
instead. The third call to MODULE is not correct because an arithmetic
expression is passed, which causes a temporary location from the DATA
step to be used, and the returned value to be lost.
* attribute table entry; routine abc minarg=1 maxarg=1; arg 1 input char format=$cstr10.;
data _null_; rc = module('abc','my string'); run;
my string
before passing it to the abc
routine. Adding
a null terminator to the character string and then passing the string
to the abc
routine is equivalent to the following
attribute entry: * attribute table entry; routine abc minarg=1 maxarg=1; arg 1 input char format=$char10.;
data _null_; rc = module('abc','my string'||'00'x); run;
long xyz(a,b) long a; double b; { static char c = 'Y'; if (a == 'X') return(1); else if (b == c) return(2); else return(3); }
xyz
routine expects two arguments, a long and a double.
If the long is an x
, the actual value
of the long is 88 in decimal. This result happens because an ASCII X
is stored as hexadecimal 58, and this value is promoted
to a long, represented as 0x00000058 (or 88 decimal). If the value
of a
is x
, or 88, then a 1 is returned. If the second argument, a double,
is y
(which is interpreted as 89),
then 2 is returned.
xyz
then
in the C language, you would invoke them as follows: x = xyz('X',(double)'Z'); y = xyz('Q',(double)'Y');The characters are invoked in this way because the
x
and Q
values are automatically promoted to integers (which
are the same as longs for the sake of this example), and the integer
values corresponding to Z
and Y
are cast to doubles.
xyz
using the MODULEN function, your attribute table
must reflect the fact that you want to pass characters: routine xyz minarg=2 maxarg=2 returns=long; arg 1 input char byvalue format=$byval4.; arg 2 input char byvalue format=$byval8.;Note that it is important that the BYVALUE option appears in the ARG statement as well. Otherwise, MODULEN assumes that you want to pass a pointer to the routine, instead of a value.
i
in the control
string parameter to MODULE, SAS prints several informational messages
to the log. You can use these messages to determine whether you have
passed incorrect arguments or coded the attribute table incorrectly.
changi
routine (which
is stored in theoretical TRYMOD.so). In the example, MODULEIN passes
the constant 6 and the matrix x2, which is a 4x5 matrix to be converted
to an integer matrix. The attribute table for changi
is as follows: routine changi module=trymod returns=long; arg 1 input num format=ib4. byvalue; arg 2 update num format=ib4.;The following IML step invokes MODULEIN:
proc iml; x1 = J(4,5,0); do i=1 to 4; do j=1 to 5; x1[i,j] = i*10+j+3; end; end; y1= x1; x2 = x1; y2 = y1; rc = modulein('*i','changi',6,x2); ....The
'*i'
control string
causes the lines shown in the following output to be written in the
log.
---PARM LIST FOR MODULEIN ROUTINE--- CHR PARM 1 885E0AA8 2A69 (*i) CHR PARM 2 885E0AD0 6368616E6769 (changi) NUM PARM 3 885E0AE0 0000000000001840 NUM PARM 4 885E07F0 0000000000002C400000000000002E40000000000000304000000000000031400000000000003240 000000000000384000000000000039400000000000003A400000000000003B400000000000003C40 0000000000004140000000000080414000000000 ---ROUTINE changi LOADED AT ADDRESS 886119B8 (PARMLIST AT 886033A0)--- PARM 1 06000000 <CALL-BY-VALUE> PARM 2 88604720 0E0000000F00000010000000110000001200000018000000190000001A0000001B0000001C000000 22000000230000002400000025000000260000002C0000002D0000002E0000002F00000030000000 ---VALUES UPON RETURN FROM changi ROUTINE--- PARM 1 06000000 <CALL-BY-VALUE> PARM 2 88604720 140000001F0000002A0000003500000040000000820000008D00000098000000A3000000AE000000 F0000000FB00000006010000110100001C0100005E01000069010000740100007F0100008A010000 ---VALUES UPON RETURN FROM MODULEIN ROUTINE--- NUM PARM 3 885E0AE00000000000001840 NUM PARM 4 885E07F0 00000000000034400000000000003F4000000000000045400000000000804A400000000000005040 00000000004060400000000000A06140000000000000634000000000006064400000000000C06540 0000000000006E400000000000606F4000000000
*i
option prints the entire argument. Be careful if you use this option
with large matrices, because the log might become quite large.