PROTO Procedure

C Helper Functions and CALL Routines

What Are C Helper Functions and CALL Routines?

Several helper functions and CALL routines are provided with the package to handle C-language constructs in PROC FCMP. Most C-language constructs must be defined in a catalog package that is created by PROC PROTO before the constructs can be referenced or used by PROC FCMP. The ISNULL function and the STRUCTINDEX and SETNULL CALL routines have been added to extend the SAS language to handle C-language constructs that do not naturally fit into the SAS language.
The following C helper functions and CALL routines are available:
C Helper Functions and CALL Routines
C Helper Function or CALL Routine
Description
Determines whether a pointer element of a structure is NULL
Sets a pointer element of a structure to NULL
Enables you to access each structure element in an array of structures

ISNULL C Helper Function

The ISNULL function determines whether a pointer element of a structure is NULL. The function has the following form:
double ISNULL (pointer-element);
where pointer-element refers to the pointer element.
In the following example, the LINKLIST structure and the GET_LIST function are defined by using PROC PROTO. The GET_LIST function is an external C routine that generates a linked list with as many elements as requested:
struct linklist{
   double value;
   struct linklist * next;
};

struct linklist * get_list(int);
The following example shows how to use the ISNULL helper function to loop over the linked list that is created by the GET_LIST function:
struct linklist list;

list = get_list(3);
put list.value=;

do while (^isnull(list.next));
   list = list.next;
   put list.value=;
end;
   
The program writes the following results to the SAS log:
LIST.value=0
LIST.value=1
LIST.value=2

SETNULL C Helper CALL Routine

The SETNULL CALL routine sets a pointer element of a structure to NULL. It has the following form:
CALL SETNULL(pointer-element);
Pointer-element is a pointer to a structure.
When you specify a variable that has a pointer value (a structure entry), then SETNULL sets the pointer to null:
call setnull(12.next);
The following example assumes that the same LINKLIST structure that is described in ISNULL C Helper Function is defined using PROC PROTO. The SETNULL CALL routine can be used to set the next element to null:
proc proto;
   struct linklist list;
   call setnull(list.next);
run;

STRUCTINDEX C Helper CALL Routine

The STRUCTINDEX CALL routine enables you to access each structure element in an array of structures. When a structure contains an array of structures, you can access each structure element of the array by using the STRUCTINDEX CALL routine. The STRUCTINDEX CALL routine has the following form:
CALL STRUCTINDEX(struct_array, index, struct_element);
Struct_array specifies an array; index is a 1–based index as used in SAS arrays; and struct_element points to an element in the arrays.
In the first part of this example, the following structures and function are defined using PROC PROTO:
struct point{
   short s;
   int i;
   long l;
   double d;
};

struct point_array {
   int            length;
   struct point * p;
   char           name[32];
};

struct point * struct_array(int);
In the second part of this example, the PROC FCMP code segment shows how to use the STRUCTUREINDEX CALL routine to get and set each POINT structure element of an array called P in the POINT_ARRAY structure:
struct point_array pntarray;
struct point pnt;

   /* Call struct_array to allocate an array of 2 POINT structures. */
pntarray.p = struct_array(2);
pntarray.plen = 2;
pntarray.name = "My funny structure";

   /* Get each element using the STRUCTINDEX CALL routine and set values. */
do i = 1 to 2;
   call structindex(pntarray.p, i, pnt);
   put "Before setting the" i "element: " pnt=;
   pnt.s = 1;
   pnt.i = 2;
   pnt.l = 3;
   pnt.d = 4.5;
   put "After setting the" i "element: " pnt=;
end;

run;
The program writes the following results to the SAS log.
Output from the STRUCTINDEX CALL Routine
Before setting the 1 element: PNT {s=0, i=0, l=0, d=0}
After setting the 1 element: PNT {s=1, i=2, l=3, d=4.5}
Before setting the 2 element: PNT {s=0, i=0, l=0, d=0}
After setting the 2 element: PNT {s=1, i=2, l=3, d=4.5}