/*--------------------------------------------------------------------+ | | | Copyright (c) 1995, SAS Institute Inc. | | Unpublished - All Rights Reserved | | | | S A S / C S A M P L E | | | | Name: LOADMAC | | | | Language: C | | | | EntryPoint: MAIN | | | | Entry Type: Standard C Entry Linkage (via main) | | | | Files Note: 'prefix' is the installation defined high level | | qualifier for the SAS/C product. | | | | Function: Dynamically load and call an assembler routine to | | sum a list of variables and return the sum to the | | caller. | | | | Purpose: Demonstrate SAS/C assembler communications by | | - dynamic loading of assembler programs via loadm | | - using the __ref to build a call-by-reference | | parameter list | | - converting remote function pointers to local | | function pointers | | | | MVS - | | Source: prefix.SAMPLE.ASM(LOADMAC) | | | | Compile/Link/Go: prefix.SAMPLE.AUX(LOADMAJ) | | | | CMS - | | | | Source: SAMPLASM MACLIB (LOADMAC) | | | | Assemble: global maclib lcuser | | hlasm loadmaa | | | | Load: lked loadmaa (libe dynamc name loadmaa | | | | Compile: global maclib lc370 | | lc370 loadmac | | | | Load: global txtlib lc370std lc370bas | | load loadmac(nomap rmode 24 amode 24 | | | | Genmod: genmod loadmac | | | | Execute: loadmac | | | | Notes: | | - LOADMAC sets runtime options in the source. | | | +--------------------------------------------------------------------*/ #include #include #include #define MODNAME "LOADMAA" /* The following demonstrates how to specify runtime options in */ /* in source code. They are not required for the proper executiuon */ /* of the LOADMA sample. */ extern int _options = _VERSION + _BTRACE + _USAGE + _WARNING; int main() { /*--------------------------------------------------------*/ /* Function pointer for the address returned by loadm. */ /* Note: by default this is a remote function pointer. */ /*--------------------------------------------------------*/ int (*fp) (); /* C Function Pointer */ /*--------------------------------------------------------*/ /* Function pointer for the assembler program that will */ /* be dynamically loaded. This is a 'local' pointer to */ /* a program to be called with standard VL-type plist */ /* that is call-by-REFerence. */ /* */ /* Use of the __ref keyword tells the compiler to build */ /* a plist with pointers to the formal arguments. */ /* */ /*--------------------------------------------------------*/ __local __ref int (*asmfp)(); /*--------------------------------------------------------*/ /* Variables */ /*--------------------------------------------------------*/ int retcode = 0; int h = 1; int i = 2; int j = 3; int k = 4; int sum = 0; int check_sum; /*--------------------------------------------------------*/ /* Load the assembler program dynamically via loadm, */ /* loadm returns a remote C function pointer. If */ /* the load fails for any reason, a NULL pointer is */ /* returned. */ /* */ /* Note: Under MVS the modules to be loaded must reside */ /* in STEPLIB, task library, or the system link */ /* list. Under CMS, modules to be loaded may */ /* reside in DYNAMC LOADLIB or in other locations */ /* defined by use of the addsrch routine of SAS/C. */ /*--------------------------------------------------------*/ loadm(MODNAME, &fp); if (fp == NULL) /* Was loadm successful ? */ { printf("\n\n loadm failed for module %s!!", MODNAME); exit(16); }; /*--------------------------------------------------------*/ /* The function pointer returned by loadm is a remote */ /* function pointer which can only be used with calls */ /* to other C modules. LOADMAA is an assembler module, */ /* this requires the remote function pointer be converted */ /* to a local function pointer for the call to LOADMAA. */ /* An assignment with casting converts the remote */ /* function pointer to a local function pointer. */ /*--------------------------------------------------------*/ asmfp = (__ref int (*)()) fp; /* Convert remote(to local */ /*--------------------------------------------------------*/ /* Call the assembler routine via the local funciton */ /* pointer with 2 arugments. */ /*--------------------------------------------------------*/ sum = (asmfp)(h,i); /* Summary number 1 */ printf("\n\nVariable Length with 2 arguments, " "the sum of %d and %d is %d\n", h, i, sum); check_sum = h+i; /*--------------------------------------------------------*/ /* See how things went and set return code accordingly. */ /*--------------------------------------------------------*/ if (sum == check_sum) /* Verify Sum is corrrect.*/ { printf("\nSum of %d was correct.\n", sum); retcode = 0; } else { printf("\nSum of %d was NOT CORRECT!.\n", sum); printf("It should have been %d!\n",check_sum); retcode = 12; }; /*--------------------------------------------------------*/ /* Call the assembler routine via the local funciton */ /* pointer with 4 arugments. */ /*--------------------------------------------------------*/ sum = (asmfp)(h,i,j,k); /* Summary number 2 */ printf("\n\nVariable Length with 4 arguments, " "the sum of %i, %i, %i and %i is %i\n", h, i, j, k, sum); check_sum = h+i+j+k; /*--------------------------------------------------------*/ /* See how things went and set return code accordingly */ /* if there is an error. */ /*--------------------------------------------------------*/ if (sum == check_sum) /* Verify Sum is corrrect.*/ {printf("\nSum of %d was correct.\n", sum);} else { printf("\nSum of %d was NOT CORRECT!.\n", sum); printf("It should have been %d!\n",check_sum); retcode = 12; }; /*--------------------------------------------------------*/ /* Unload the assembler function using the remote */ /* C function pointer. */ /*--------------------------------------------------------*/ unloadm(fp); exit(retcode); }