Accessing External Shared Images from SAS |
Example 1: Updating a Character String Argument |
This example uses the tmpnam routine that is part of HP's C Run-Time Library under the OpenVMS environment. The tmpnam routine generates a unique filename that can safely be used as a temporary filename.
The C source code for VMSLIB.C is the following:
#include <stdio.h> /* Declares prototype: char * tmpnam(char *s); */ #include <string.h> vmstmpnam(char *s) { tmpnam(s); printf("tmpnam(%d) = %s\n",sizeof(s),s); return(0); }
The following code shows how the C source code could be compiled and linked using a DCL Command file, such as VMSLIB.COM.
$ cc/decc/obj=vmslib.o/arch=generic/name=(short,as_is)/pointer=64=argv vmslib.c $ open/write optfile vmslib.opt $ write optfile "CASE_SENSITIVE=YES" $ write optfile "SYMBOL_VECTOR=(vmstmpnam=PROCEDURE)" $ write optfile "vmslib.o" $ close optfile $ link/exe=vmslib.exe/share/bpage=13/map/cross/full vmslib.opt/opt
The following SAS source code can be used to create the SASCBTBL attribute table and call the routine from within the DATA step.
filename sascbtbl 'sas$worklib:temp.dat'; data _null_ file sascbtbl; input; put _infile_; datalines4; routine vmstmpnam minarg=1 maxarg=1 module=vmslib; arg 1 char update byaddr format=$cstr255.; ;;;; data _null_; length tempname $255; retain tempname " "; tret = modulec('vmstmpnam',tempname); put tempname = ; run;
The SAS log output would be the following:
Log Output for Updating a Character String Argument
tempname=aaa_ebba32
The POSIX standard for the maximum number of characters in a pathname is defined in <limits.h> to be 255 characters. Consequently, this example uses 254 characters as the length of the generated filename, tempname, with one character reserved for the null-terminator. The $CSTR255. informat ensures that the null-terminator and all subsequent characters are replaced by trailing blanks when control returns to the DATA step.
Example 2: Passing Arguments by Value |
This example calls the access routine that is part of HP's C Run-Time Library under OpenVMS. The access routine checks for the existence and accessibility of a file based on the bit pattern contained in the mode argument. A return value of 0 indicates a successful completion and the requested access is permitted. A return value of -1 indicates a failure, and the requested access is not permitted.
Because the mode argument is passed by value, this example includes the BYVALUE option for arg 2 in the attribute table. If both arguments were pass by value, you could use the CALLSEQ=BYVALUE attribute in the ROUTINE statement, and it would not be necessary to specify the BYVALUE option in arg 2.
The C source code for the VMSLIB.C is:
#include <unistd.h> #include <stdlib.h> #include <stdio.h> /* The header file <unistd.h> declares the access prototype and defines the bit patterns for mode as: int access(const char *file_spec,int mode); #define F_OK 0 ... File existence #define X_OK 1 ... Execute access #define W_OK 2 ... Write access #define R_OK 4 ... Read access A logical OR of these values will test for more than one bit pattern. */ int vmsaccess(const char *file_spec,int mode) { int rc; if ((rc=access(file_spec,mode)) == -1) perror("vmsaccess"); return(rc); }
The following example shows how the C source code is compiled and linked using a DCL Command file, such as VMSLIB.COM:
$ cc/decc/obj=vmslib.o/arch=generic/name=(short,as_is)/pointer=64=argv vmslib.c $ open/write optfile vmslib.opt $ write optfile "CASE_SENSITIVE=YES" $ write optfile "SYMBOL_VECTOR=(vmsaccess=PROCEDURE)" $ write optfile "vmslib.o" $ close optfile $ link/exe=vmslib.exe/share/bpage=13/map/cross/full vmslib.opt/opt
The following SAS source code can be used to create the SASCBTBL attribute table and call the routine from within the DATA step.
filename sascbtbl 'sas$worklib:temp.dat'; data _null_; file sascbtbl; input; put _infile_; datalines4; routine vmsaccess minarg=2 maxarg=2 returns=short module=vmslib; arg 1 char input byaddr format=$cstr200.; arg 2 num input byvalue format=ib4.; ;;;; data _null_; length path $200.; /* A test file's permissions have been modified to the following: set protection vmstest.com/prot=(system:r,owner:r,group:r,world:r) */ path='sys$login:vmstest.com'; /* User is testing for Write and Execute permissions (W_OK | E_OK) */ rc = modulen( "*ie", 'vmsaccess', path, 3 ); put rc = ; run;
The SAS log output would be the following:
rc=-1This return code means that one of the following conditions was true: This return code means that requested access is not permitted.
The SAS source code is changed to check for Read permission,
rc = modulen( "*ie", 'vmsaccess', path, 4);
then the SAS log output is the following:
Log Output for Successful Completion
rc=0
Example 3: Invoking a Shared Image Routine from PROC IML |
This example shows how to pass a matrix as an argument within PROC IML. The example creates a 4x5 matrix. Each cell is set to 10x+y+3, where x is the row number and y is the column number. For example, the cell at row 1 column 2 is set to (10*1)+2+3, or 15.
The example invokes several routines from the theoretical TRYMOD shared image. It uses the changd routine to add 100x+10y to each element, where x is the C row number (0 through 3) and y is the C column number (0 through 4). The first argument to changd specifies the extra amount to sum. The changdx routine works just like changd , except that it expects a transposed matrix. The changi routine works like changd except that it expects a matrix of integers. The changix routine works like changdx except that integers are expected.
Note: A maximum of three arguments can be sent when invoking a shared image routine from PROC IML.
In this example, all four matrices x1, x2, y1, and y2 should become set to the same values after their respective MODULEIN calls. Here are the attribute table entries:
routine changd module=trymod returns=long; arg 1 input num format=rb8. byvalue; arg 2 update num format=rb8.; routine changdx module=trymod returns=long transpose=yes; arg 1 input num format=rb8. byvalue; arg 2 update num format=rb8.; routine changi module=trymod returns=long; arg 1 input num format=ib4. byvalue; arg 2 update num format=ib4.; routine changix module=trymod returns=long transpose=yes; arg 1 input num format=ib4. byvalue; arg 2 update num format=ib4.;
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('changd',6,x1); rc = modulein('changdx',6,x2); rc = modulein('changi',6,y1); rc = modulein('changix',6,y2); print x1 x2 y1 y2; run;
The following are the results of the PRINT statement:
Invoking a Shared Image Routine from PROC IML
X1 20 31 42 53 64 130 141 152 163 174 240 251 262 273 284 350 361 372 383 394 X2 20 31 42 53 64 130 141 152 163 174 240 251 262 273 284 350 361 372 383 394 Y1 20 31 42 53 64 130 141 152 163 174 240 251 262 273 284 350 361 372 383 394 Y2 20 31 42 53 64 130 141 152 163 174 240 251 262 273 284 350 361 372 383 394
Copyright © 2009 by SAS Institute Inc., Cary, NC, USA. All rights reserved.