Issues and Examples: UNIX

Interactive IDL

Under UNIX, IDL_Main() implements IDL as seen by the interactive user. In the interactive version of IDL as shipped by ITT Visual Information Solutions, the actual main() function simply decodes its arguments to determine which options to specify and then calls IDL_Main() to do the rest. IDL_Main() calls exit() and does not return to its caller.

int IDL_Main(int init_options, int argc, char *argv[]); 

where:

init_options

The options value to be passed to IDL_Initialize() via the init_data argument to that function.

argc, argv

From main(). Arguments that correspond to options specified via the init_options argument should be removed and converted to init_options flags prior to calling this routine.

Compiling Programs That Call IDL

A complete discussion of the issues that arise when compiling and linking C programs is beyond the scope of this manual. The following is a brief list of basic concepts to consider when building programs that call IDL.

Example: Calling IDL From C

The program in the following figure is a simplified Unix-only version of calltest.c, found in the callable subdirectory of the external subdirectory of the IDL distribution. It demonstrates how to import data from a C program into IDL, execute IDL statements, and obtain data from IDL variables. It performs the following actions:

  1. Create an array of 10 floating point values with each element set to the value of its index. This is equivalent to the IDL command FINDGEN(10).
  2. Initialize Callable IDL.
  3. Import the floating point array into IDL as a variable named TMP.
  4. Have IDL print the value of TMP.
  5. Execute a short sequence of IDL statements from a string array:
  6. tmp2 = total(tmp) 
    print,'IDL total is ',tmp2 
    plot, tmp 
    
  7. Set TMP to zero, causing IDL to release the pointer to the floating point array.
  8. Obtain a pointer to the data contained in TMP2. From examining the IDL statements executed to this point, we know that TMP2 is a scalar floating point value.
  9. From our C program, print the value of the IDL TMP2 variable.
  10. Execute a small widget program. Pressing the button allows the program to end:
  11. a = widget_base() 
    b = widget_button(a, value='Press When Done',xsize=300, 
                      ysize=200) 
    widget_control, /realize, a 
    dummy = widget_event(a) 
    widget_control, /destroy, a 
     

    See Compilation and Linking Statements for details on compiling and linking this program.

    Each line is numbered to make discussion easier. The line numbers are not part of the actual program.

Table 16-3: Calling IDL from C on UNIX

C
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
#include <stdio.h>  
#include "idl_export.h" 
  
static void free_callback(UCHAR *addr) 
{ 
   printf("IDL released(%u)\n", addr);  
} 
  
int main(int argc, char **argv)  
{ 
  IDL_INIT_DATA init_data; 
  float f[10];  
  int i;  
  IDL_VPTR v;  
  IDL_MEMINT dim[IDL_MAX_ARRAY_DIM];  
  static char *cmds[] = { "tmp2 = total(tmp)",  
    "print,'IDL total is ',tmp2", "plot,tmp" };  
  static char *cmds2[] = { "a = widget_base()",  
    "b = widget_button(a, value='Press When Done', xsize=300, 
    ysize=200)", "widget_control,/realize, a",  
    "dummy = widget_event(a)",  
    "widget_control,/destroy, a" };  
  
  
  for (i=0; i < 10; i++) f[i] = (float) i; 
  init_data.options = IDL_INIT_CLARGS; 
  init_data.clargs.argc = argc; 
  init_data.clargs.argv = argv; 
  if (IDL_Initialize(&init_data)) {  
    dim[0] = 10;  
    printf("ARRAY ADDRESS(%u)\n", f);  
    if (v=IDL_ImportNamedArray("TMP", 1, dim, IDL_TYP_FLOAT, 
                 (UCHAR *) f, free_callback, (void *) 0)) {  
    (void) IDL_ExecuteStr("print, tmp");  
    (void) IDL_Execute(sizeof(cmds)/sizeof(char *), cmds);  
    (void) IDL_ExecuteStr("print, 'Free the user memory'");  
    (void) IDL_ExecuteStr("tmp = 0");  
    if (v = IDL_FindNamedVariable("tmp2", IDL_FALSE))  
      printf("Program total is %f\n", v->value.f);  
    (void) IDL_Execute(sizeof(cmds2)/sizeof(char *), cmds2);  
    IDL_Cleanup(IDL_FALSE);   /* Don't return */ 
  }  
  
 return 1;  
} 

Following is commentary on this program, by line number:

25

C equivalent to IDL command "F = FINDGEN(10)"

26–28

Prepare initialization data.

29

Initialize IDL

30–33

Import C array F into IDL as a FLTARR vector named TMP with 10 elements. Note use of the callback argument free_callback. This function will be called when IDL is finished with the array F, giving us a chance to properly clean up at that time.

34

Have IDL print the value of TMP.

35

Execute the commands contained in the C string array cmds defined on lines 16–17. These commands create a new IDL variable named TMP2 containing the sum of the elements of TMP, print its value, and plot the vector.

36–37

Set TMP to a new value. This will cause IDL to release the user supplied memory from lines 30–33 and call free_callback.

38–39

From C, get a reference to the IDL variable TMP2 and print its value. This should agree with the value printed by IDL on line 35. It is important to realize that the pointer to the variable or anything it points at can only be used until the next call to execute an IDL statement. After that, the pointer and the contents of the referenced IDL_VARIABLE may become invalid as a result of IDL's execution.

40

Run the simple IDL widget program contained in the array C string array cmds2 defined on lines 18–22.

41

Shut down IDL. The IDL_FALSE argument instructs IDL_Cleanup() to exit the process, so this call should not return.

44

This line should never be reached. If it is, return the UNIX failing status.

Example: Calling an IDL Math Function

This example demonstrates how to write a simple C wrapper function that allows calling IDL commands simply from another language. We implement a function named call_idl_fft() that calls the IDL FFT function operating on data imported from our C program. It returns TRUE on success, FALSE for failure:

int call_idl_fft(IDL_COMPLEX *data, int n, int direction); 

data

A pointer to a linear array of complex data to be processed.

n

The number of data points contained in the array data.

dir

The direction of the FFT transform to take. Specify -1 for a forward transform, 1 for the reverse

The program is shown in the following figure. Each line is numbered to make discussion easier. These numbers are not part of the actual program.

Table 16-4: call_idl_fft()

C
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
#include <stdio.h>  
#include "idl_export.h" 
  
  
int call_idl_fft(IDL_COMPLEX *data, IDL_MEMINT n, int dir)  
{  
  int r;  
  IDL_MEMINT dim[IDL_MAX_ARRAY_DIM];  
  char buf[64];  
  
  dim[0] = n;  
  if (IDL_ImportNamedArray("TMP_FFT_DATA", 1, dim, 
      IDL_TYP_COMPLEX, (UCHAR *) data, 0, 0)) {  
    (void) IDL_ExecuteStr("MESSAGE, /RESET");  
    sprintf(buf,"TMP_FFT_DATA=FFT(TMP_FFT_DATA,/OVERWRITE)" 
           ,dir);  
    r = !IDL_ExecuteStr(buf);  
    (void) IDL_ExecuteStr("TMP_FFT_DATA=0");  
  } else {  
    r = FALSE;  
  }  
  
  return r;  
}  
  
main(int argc, char **argv)  
{  
#define NUM_PNTS 10  
  IDL_COMPLEX data[NUM_PNTS];  
  IDL_INIT_DATA init_data; 
  int i;  
  
  for (i = 0; i < NUM_PNTS; i++) data[i].r = data[i].i = i; 
  init_data.options = IDL_INIT_CLARGS; 
  init_data.clargs.argc = argc; 
  init_data.clargs.argv = argv; 
  if (IDL_Initialize(&init_data)) {  
    call_idl_fft(data, NUM_PNTS, -1);  
    call_idl_fft(data, NUM_PNTS, 1);  
    for (i = 0; i < NUM_PNTS; i++) 
      printf("(%f, %f)\n", data[i].r, data[i].i);  
    IDL_Cleanup(IDL_FALSE);  
  }  
  
  return 1;  
} 

Following is commentary on the above program, by line number:

7

The variable r holds the result from the function.

8

dim is used to import the data into IDL as an array.

9

A temporary buffer to format the IDL FFT command.

11–13

Import data into IDL as the variable TMP_FFT_DATA. We don't set up a free_callback because we will explicitly force IDL to release the pointer after the call to FFT.

14

Set the !ERROR_STATE system variable back to the "success" state so previous errors don't confuse our results.

15–16

Format an FFT command to IDL into buf. Note the use of the OVERWRITE keyword. This tells the IDL FFT function to place the results into the input variable rather than creating a separate output variable. Hence, the results end up in our data array without the need to obtain a pointer to the results and copy them out.

17

Have IDL execute the FFT statement. IDL_ExecuteStr() returns the value of !ERROR_STATE.CODE, which should be zero for success and non-zero in case of error. Hence, negating the result of IDL_ExecuteStr() yields the status value we require for the result of this function.

18

Set TMP_FFT_DATA to 0 within IDL. This causes IDL to release the data pointer imported previously.

20

If the call to IDL_ImportNamedArray() fails, we must report failure.

26

In order to test the call_idl_fft() function, this main program calls it twice. Taking numerical error into account the end result should be equal to the original data.

33

Set the real and imaginary part of each element to the index value.

34-36

Prepare initialization data.

37

Initialize Callable IDL.

38

Call call_idl_fft() to perform a forward transform.

39

Call call_idl_fft() to perform a reverse transform.

40–41

Print the results.

42

Shut down IDL and exit the process.

45

This line should never be reached. If it is, return the UNIX failing status.

Example: Calling IDL from Fortran

The program shown in the following figure (CALLTEST, found in the callable subdirectory of the external subdirectory of the IDL distribution) demonstrates how to import data from a Fortran program into IDL, execute IDL statements, and obtain data from IDL variables. See Compilation and Linking Statements for details on compiling and linking this program. The source code for this file can be found in the file calltest.f, located in the callable subdirectory of the external subdirectory of the IDL distribution.

Each line is numbered to make discussion easier. The line numbers are not part of the actual program:

Table 16-5: Calling IDL from Fortran On UNIX 

f77
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
C----------------------------------------------------------------- 
C    Routine to print a floating point value from an IDL variable. 
  
 SUBROUTINE PRINT_FLOAT(VPTR) 
  
C    Declare a Fortran Record type that has a compatible form with 
C    the IDL C struct IDL_VARIABLE for a floating point value. 
C    Note this structure contains a union which is the size of  
C    the largest data type. This structure has been padded to 
C    support the union. Fortran records are not part of 
C    F77, but most compilers have this option. 
  
 STRUCTURE /IDL_VARIABLE/ 
           CHARACTER*1 TYPE  
           CHARACTER*1 FLAGS  
           INTEGER*4 PAD       !Pad for largest data type  
           REAL*4 VALUE_F 
 END STRUCTURE  
  
 RECORD /IDL_VARIABLE/ VPTR 
  
 WRITE(*, 10) VPTR.VALUE_F 
  10 FORMAT('Program total is: ', F6.2) 
  
 RETURN 
  
 END 

29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
C----------------------------------------------------------------- 
C   This function will be called when IDL is finished with the  
C   array F.   
  
        SUBROUTINE FREE_CALLBACK(ADDR) 
  
           INTEGER*4 ADDR 
  
           WRITE(*,20) LOC(ADDR) 
  20    FORMAT ('IDL Released:', I12) 
  
           RETURN 
  
        END 
  
C----------------------------------------------------------------- 
C  This program demonstrates how to import data from a Fortran 
C  program into IDL, execute IDL statements and obtain data 
C  from IDL variables. 
  
  
PROGRAM CALLTEST 
  
C  Some Fortran compilers require external defs. for IDL routines: 
        EXTERNAL IDL_Init !$pragma C(IDL_Init) 
        EXTERNAL IDL_Cleanup !$pragma C(IDL_Cleanup) 
        EXTERNAL IDL_Execute !$pragma C(IDL_Execute) 
        EXTERNAL IDL_ExecuteStr !$pragma C(IDL_ExecuteStr) 
        EXTERNAL IDL_ImportNamedArray !$pragma C(IDL_ImportNamedArray) 
        EXTERNAL IDL_FindNamedVariable !$pragma C(IDL_FindNamedVariable) 
  
C  Define arguments for IDL_Init routine 
        INTEGER*4 ARGC 
        INTEGER*4 ARGV(1) 
        DATA ARGC, ARGV(1) /2 * 0/ 
  

f77
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
102 
103 
104 
105 
106 
C  Define IDL Definitions for IDL_ImportNamedArray 
  
        PARAMETER (IDL_MAX_ARRAY_DIM = 8) 
        PARAMETER (IDL_TYP_FLOAT = 4) 
  
        REAL*4 F(10) 
        INTEGER*4 DIM(IDL_MAX_ARRAY_DIM) 
        DATA DIM /10, 7*0/ 
        INTEGER*4 FUNC_PTR     !Address of function  
        INTEGER*4 VAR_PTR      !Address of IDL variable 
        EXTERNAL FREE_CALLBACK !Declare ext routine for use as arg 
  
        PARAMETER (MAXLEN=80)  
        PARAMETER (N=10) 
  
C  Define commands to be executed by IDL 
  
        CHARACTER*(MAXLEN) CMDS(3) 
        DATA CMDS /"tmp2 = total(tmp)", 
     &            "print, 'IDL total is ', tmp2", 
     &            "plot, tmp"/ 
        INTEGER*4 CMD_ARGV(10) 
  
C  Define widget commands to be executed by IDL 
  
        CHARACTER*(MAXLEN) WIDGET_CMDS(5) 
        DATA  WIDGET_CMDS /"a = widget_base()", 
   &    "b = widget_button(a,val='Press When Done',xs=300,ys=200)", 
   &    "widget_control, /realize, a", 
   &    "dummy = widget_event(a)",  
   &    "widget_control, /destroy, a"/ 
  
        INTEGER*4 ISTAT  
  
C  Null Terminate command strings and store the address 
C  for each command string in CMD_ARGV  
  
        DO I = 1, 3   
           CMDS(I)(MAXLEN:MAXLEN) = CHAR(0) 
           CMD_ARGV(I) = LOC(CMDS(I)) 
        ENDDO 
  
f77
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
C  Initialize floating point array, equivalent to IDL FINDGEN(10) 
  
        DO I = 1, N 
           F(I) = FLOAT(I-1) 
        ENDDO 
  
C  Print address of F  
  
 WRITE(*,30) LOC(F) 
   30 FORMAT('ARRAY ADDRESS:', I12) 
  
C  Initialize Callable IDL 
  
        ISTAT = IDL_Init(%VAL(0), ARGC, ARGV(1)) 
  
        IF (ISTAT .EQ. 1) THEN  
  
C  Import the floating point array into IDL as a variable named TMP  
  
        CALL IDL_ImportNamedArray('TMP'//CHAR(0), %VAL(1), DIM,  
    &       %VAL(IDL_TYP_FLOAT), F, FREE_CALLBACK, %VAL(0)) 
  
C  Have IDL print the value of tmp 
  
        CALL IDL_ExecuteStr('print, tmp'//CHAR(0)) 
  
C  Execute a short sequence of IDL statements from a string array  
  
        CALL IDL_Execute(%VAL(3), CMD_ARGV) 
  
C  Set tmp to zero, causing IDL to release the pointer to the 
C  floating point array. 
  
        CALL IDL_ExecuteStr('tmp = 0'//CHAR(0)) 
  
C  Obtain the address of the IDL variable containing the 
C  the floating point data  
  
        VAR_PTR = IDL_FindNamedVariable('tmp2'//CHAR(0), %VAL(0))  
  
C  Call a Fortran routine to print the value of the IDL tmp2 variable  
        CALL PRINT_FLOAT(%VAL(VAR_PTR)) 
  
f77
150 
151 
152 
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167 
168 
C  Null Terminate command strings and store the address 
C  for each command string in CMD_ARGV  
  
        DO I = 1, 5   
           WIDGET_CMDS(I)(MAXLEN:MAXLEN) = CHAR(0) 
           CMD_ARGV(I) = LOC(WIDGET_CMDS(I)) 
        ENDDO 
  
C  Execute a small widget program. Pressing the button allows 
C  the program to end  
  
        CALL IDL_Execute(%VAL(5), CMD_ARGV) 
  
C  Shut down IDL 
        CALL IDL_Cleanup(%VAL(0)) 
  
      ENDIF 
  
   END 

1-27

In order to print variables returned from IDL, we must define a Fortran structure type for IDL_VARIABLE. This subroutine creates the IDL_VARIABLE structure and defines a way to print the floating-point value returned in the an IDL variable.

14-17

Define a Fortran structure equivalent to the floating-point portion of the C IDL_VARIABLE structure. Since we know our value is a floating-point number, only the floating-point portion of the structure is implemented. The structure is padded for the largest data type contained in the union. With some Fortran compilers, the combination of UNION and MAP can be used to implement the ALLTYPES union portion of the IDL_VARIABLE structure.

29-42

This subroutine is called when IDL releases the user-supplied memory.

44-164

This is the main Fortran program.

51-57

External definitions for IDL internal routines. These definitions may not be necessary with some Fortran compilers.

59-62

Define the argc and argv arguments required by IDL_Init().

66-67

Define constants equivalent to C IDL constants for the maximum array dimensions and type float.

69-77

Define parameters necessary for IDL_ImportNamedArray().

79-85

Define an array of IDL commands to be executed.

87-96

Define an array of IDL widget commands to be executed.

98-104

Null-terminate each of the command strings and store the address of each command to pass to IDL.

106-110

Initialize the floating-point array. This is the Fortran equivalent to the IDL command F=FINDGEN(10).

117-121

Initialize IDL.

125-126

Import the Fortran array F in the IDL as a 10-element FLTARR vector named TMP. Note the use of the callback argument FREE_CALLBACK(), which will be called when IDL is finished with the array F, giving us a chance to clean up at that time.

134

Execute the commands contained in the character array CMDS defined on lines 71-77. The address for each command is stored in the corresponding array element of CMD_ARGV.

139

Set the TMP variable to a new value. This causes IDL to release the user-supplied memory and call FREE_CALLBACK().

144

Get a reference to the IDL variable TMP2.

147

Call the routine PRINT_FLOAT to print the value of TMP2. This should agree with the value printed by line 130. Note that the address of the IDL variable TMP2, and its contents, can only be used until the next call to execute an IDL statement, since IDL may change the value of the referenced IDL_VARIABLE.

150-161

Execute the commands contained in the character array WIDGET_CMDS defined on lines 79-88.

163-168

Shut down IDL. The 0 argument instructs IDL_CLEANUP() to exit the process, so this call should not return.

Compilation and Linking Statements

Compilation and linking procedures used when calling IDL on a UNIX system are described in the file calltest_unix.txt in the callable subdirectory of the external subdirectory of the main IDL directory. Note that different UNIX systems have different compilation and link statements. Note also that the name of the entry point in the object may be different than that shown here, because compilers may add leading or trailing underscores to the name of the source routine.

Note
The Makefile in the architecture-specific subdirectory of the bin subdirectory of the IDL distribution contains a make rule for building the calltest application.