Interfaces Obsoleted in IDL 5.5

The following areas changed in IDL 5.5, requiring the introduction of new interfaces, and causing some old interfaces to become obsolete. These old interfaces remain in IDL and can be used by user code. However, new code should not use them, and old code might benefit from migration as part of normal maintenance:

IDL_MSG_ATTR_SYS

Note
IDL_MSG_ATTR_SYS is one of the possible attribute values that can be included in the action argument to the IDL_Message() function. Its purpose was to cause IDL_Message() to report the system error currently contained in the process errno global variable. This functionality is now available in a more general and useful form via the IDL_MessageSyscode() and IDL_MessageSyscodeFromBlock() functions, documented in Issuing Error Messages

IDL_MSG_ATTR_SYS

IIDL_Message() always issues a single-line error message that describes the problem from IDL's point of view. Often, however, there is an underlying system reason for the error that should also be displayed to give the user a complete picture of what went wrong. For example, the IDL view of the problem might be "Unable to open file", while the underlying system reason for the error is "no such directory".

The UNIX system provides a global variable named errno for communicating such system level errors. Whenever a call to a system function fails, it returns a 1, and puts an error code into errno that specifies the reason for the failure. Other functions, such as those provided by the standard C library, do not set errno. These functions do set errno.

Specifying IDL_MSG_ATTR_SYS tells IDL_Message() to check errno, and if it is non-null, to issue a second line containing the text of the system error message.

Specify IDL_MSG_ATTR_SYS only if you are calling IDL_Message() as the result of a failed UNIX system call. Otherwise, errno might contain an unrelated garbage value resulting in an incorrect error message.

The Microsoft Windows operating system has errno for compatibility with the expectations of C programmers, but typically do not set it. On these operating systems, it is possible to specify IDL_MSG_ATTR_SYS, but it has no effect.

Specifying errno Explicitly: IDL_MessageErrno()

Note
The IDL_MessageErrno() and IDL_MessageErrnoFromBlock() functions allow you to throw an error message that includes the system error from the UNIX/POSIX errno global variable. These functions have been replaced by IDL_MessageSyscode() and IDL_MessageSyscodeFromBlock() which in addition to being able to throw UNIX/Posix errors, can also throw other types of system error.

There are times when specifying the IDL_MSG_ATTR_SYS modifier code in the action argument to IDL_Message() is inadequate. This situation usually occurs when your code attempts to perform some cleanup operation when an operating system call fails before calling IDL_Message() and this cleanup code might alter the value of errno. In such cases, it is preferable to use the IDL_MessageErrno() or IDL_MessageErrnoFromBlock() functions to issue the message:

void IDL_MessageErrno(int code, int errno, int action, ...) 
void IDL_MessageErrnoFromBlock(IDL_MSG_BLOCK block, int code, int 
errno, int action, ...) 

These function differs from IDL_Message() in two ways:

  1. There is an additional argument used to specify the value of errno. See the discussion of errno in IDL_MSG_ATTR_SYS for additional information about errno and its use.
  2. The IDL_MSG_ATTR_SYS modifier code for the action argument is ignored.-

Processing Keywords With IDL_KWGetParams()

Note
Previous versions of IDL used a keyword API based around the IDL_KWGetParams() and IDL_KWCleanup() functions. This API was confusing to use (It was difficult to know when IDL_KWCleanup() was supposed to be called), and was not reentrant (requiring extensive and error prone code in some IDL system routines). The new API, using IDL_KWProcessByOffset() and IDL_KW_FREE, solve these problems and result in easier to write and maintain code.

To enable rapid conversion from the old API to the new, the new API uses most of the same data structures as the old (with the notable exception of IDL_KW_ARR_DESC, which is replaced by IDL_KW_ARR_DESC_R).

This section reproduces those parts of the documentation of the original API that differ from the current API, which is described in IDL Internals: Keyword Processing

The IDL_KW_PAR Structure

Note
IDL_KW_PAR is used with the old keyword API in largely the same manner as the current API, as described in Overview Of IDL Keyword Processing. The main difference is that the contents of the specified and value fields are the addresses of static variables, rather than offsets into a KW_RESULT structure as with the new API.

specified

The address of a C int variable that will be set to TRUE (non-zero) or FALSE (0) based on whether the routine was called with the keyword present. This field should be set to NULL ((int *) 0) if this information is not needed.

value

If the keyword is a read-only scalar, this field is a pointer to a C variable of the correct type (IDL_LONG, IDL_ULONG, IDL_LONG64, IDL_ULONG64, float, double, or IDL_STRING).

In the case of a read-only array, value is a pointer to an IDL_KW_ARR_DESC, which is discussed in The IDL_KW_ARR_DESC Structure. In the case of an output variable (i.e., the IDL_KW_OUT flag is set), this field should point to an IDL_VPTR that will be filled by IDL_KWGetParams() with the address of the keyword argument.

The IDL_KW_ARR_DESC Structure

Note
The IDL_KW_ARR_DESC structure was superseded by IDL_KW_ARR_DESC_R in the current API. The reason for this change is that the n field of IDL_KW_ARR_DESC is modified by the call to IDL_KWGetParams(), requiring the IDL_KW_ARR_DESC structure to be defined in static memory, and rendering it non-reentrant.

When a keyword is specified to be a read-only array (i.e., the IDL_KW_ARRAY flag is set), the value field of the IDL_KW_PAR struct should be set to point to an IDL_KW_ARR_DESC structure. This structure is defined as:

typedef struct { 
  char *data; 
  IDL_MEMINT nmin; 
  IDL_MEMINT nmax; 
  IDL_MEMINT n; 
} IDL_KW_ARR_DESC; 

where:

data

The address of a C array to receive the data. This array must be of the C type mapped into by the type field of the IDL_KW_PAR struct. For example, IDL_TYP_LONG maps into a C IDL_LONG. There must be nmax elements in the array.

nmin

The minimum number of elements allowed.

nmax

The maximum number of elements allowed.

n

The number of elements actually present. Unlike the other fields, this field is set by IDL_KWGetParams().

Processing Keywords

The IDL_KWGetParams() function is used to process keywords. IDL_KWGetParams() performs the following actions on behalf of the calling system routine:

IDL_KWGetParams() has the form:

int IDL_KWGetParams(int argc, IDL_VPTR *argv,char *argk, 
        IDL_KW_PAR *kw_list, IDL_VPTR plain_args[], int mask) 

where:

argc

The number of arguments passed to the caller. This is the first parameter to all system routines.

argv

The array of IDL_VPTR to arguments that was passed to the caller. This is the second parameter to all system routines.

argk

The pointer to the keyword list that was passed to the caller. This is the third parameter to all system routines that accept keyword arguments.

kw_list

An array of IDL_KW_PAR structures (seeOverview Of IDL Keyword Processing, and The IDL_KW_PAR Structure) that specifies the acceptable keywords for this routine. This array is terminated by setting the keyword field of the final struct to NULL ((char *) 0).

plain_args

An array of IDL_VPTR into which the IDL_VPTRs of the positional arguments will be copied. This array must have enough elements to hold the maximum possible number of positional arguments, as defined in IDL_SYSFUN_DEF2. See Registering Routines.

mask

Mask enable. This variable is ANDed with the mask field of each IDL_KW_PAR struct in the array given by kw_list. If the result is non-zero, the keyword is accepted as a valid keyword for the called system routine. If the result is zero, the keyword is ignored.

Speeding Keyword Processing

As mentioned above, the kw_list argument to IDL_KWGetParams() is a null terminated list of IDL_KW_PAR structures. The time required to scan each item of the keyword array and zero the required fields (those fields specified, and value fields with IDL_KW_ZERO set), can become significant, especially when more than a few keyword array elements (e.g., 5 to 10 elements) are present.

To speed things up, specify IDL_KW_FAST_SCAN as the first keyword array element. If IDL_KW_FAST_SCAN is the first keyword array element, the keyword array is compiled by IDL_KWGetParams() into a more efficient form the first time it is used. Subsequent calls use this efficient version, greatly speeding keyword processing. Usage of IDL_KW_FAST_SCAN is optional, and is not worthwhile for small lists. For longer lists, however, the improvement in speed is noticeable. For example, the following list does not use fast scanning:

static IDL_KW_PAR  kw_pars[] = { 
  { "DOUBLE", IDL_TYP_DOUBLE, 1, 0, &d_there, CHARA(d) }, 
  { "FLOAT", IDL_TYP_FLOAT, 1, IDL_KW_ZERO, 0, CHARA(f) }, 
  { NULL } 
}; 

To use fast scanning, it would be written as:

static IDL_KW_PAR  kw_pars[] = { 
  IDL_KW_FAST_SCAN, 
  { "DOUBLE", IDL_TYP_DOUBLE, 1, 0, &d_there, CHARA(d) }, 
  {"FLOAT", IDL_TYP_FLOAT, 1, IDL_KW_ZERO, 0, CHARA(f) }, 
  { NULL } 
}; 

Cleaning Up

The IDL_KWCleanup() function is necessary if the keywords allowed by a system routine include any input-only keywords of type IDL_TYP_STRING, or if the IDL_KW_VIN flag is used by any of the keyword IDL_KW_PAR structures. Such keywords can cause keyword processing to allocate temporary variables that must be cleaned up after they've outlived their usefulness. Call IDL_KWCleanup() as follows:

void IDL_KWCleanup(int fcn) 

where fcn specifies the operation to be performed, and must be one of the following values:

IDL_KW_MARK

Mark the stack by placing the statement:

IDL_KWCleanup(IDL_KW_MARK); 

above the call to IDL_KWGetParams(). In addition, you will need to make a call with IDL_KW_CLEAN at the end.

IDL_KW_CLEAN

Clean up from the last call to IDL_KWGetParams() by placing the line:

IDL_KWCleanup(IDL_KW_CLEAN); 

just above the return statement.

Keyword Examples

The following C function implements KEYWORD_DEMO, a system procedure intended to demonstrate how to write the keyword processing code for a routine. It prints the values of its keywords, changes the value of READWRITE to 42 if it is present, and returns. Each line is numbered to make discussion easier. These numbers are not part of the actual program.

Note
The following code is designed to demonstrate keyword processing in a simple, uncluttered example. In actual code, you would not use the printf mechanism used on lines 35-39.

Figure 0-1: Obsolete Example 

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 
#include <stdio.h> 
#include <idl_export.h> 
  
void keyword_demo(int argc, IDL_VPTR *argv, char *argk) 
{ 
  int i; 
  IDL_ALLTYPES newval; 
  
  static int d_there, s_there, arr_there; 
  static IDL_LONG l; 
  static float f; 
  static double d; 
  static IDL_STRING s; 
  static IDL_LONG arr_data[10];  
  static IDL_KW_ARRAY_DESC arr_d = {(char *) arr_data,3,10,0}; 
  static IDL_VPTR var; 
  
  static IDL_KW_PAR kw_pars[] = { IDL_KW_FAST_SCAN, 
    { "ARRAY", IDL_TYP_LONG, 1, IDL_KW_ARRAY, &arr_there, 
      IDL_CHARA(arr_d) }, 
    { "DOUBLE", IDL_TYP_DOUBLE, 1, 0, &d_there, IDL_CHARA(d) }, 
    { "FLOAT", IDL_TYP_FLOAT, 1, IDL_KW_ZERO, 0, IDL_CHARA(f) }, 
    { "LONG", IDL_TYP_LONG, 1, IDL_KW_ZERO|IDL_KW_VALUE|15, 0, 
       IDL_CHARA(l) }, 
    { "READWRITE", IDL_TYP_UNDEF, 1, IDL_KW_OUT|IDL_KW_ZERO,  
       0, IDL_CHARA(var) }, 
    { "STRING",TYP_STRING, 1, 0, &s_there, IDL_CHARA(s) }, 
    { NULL } 
  }; 
  
IDL_KWCleanup(IDL_KW_MARK); 
  
(void) IDL_KWGetParams(argc, argv, argk, kw_pars, NULL, 1); 
  
printf("LONG: <%spresent>\n", l ? "": "not "); 
printf("FLOAT: %f\n", f); 
printf("DOUBLE: <%spresent>\n", d_there ? "": "not ");  
printf("STRING: %s\n", s_there ? IDL_STRING_STR(&s) : "<not present>"); 
printf("ARRAY: "); 

C
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
if (arr_there) 
  for (i = 0; i < arr_d.n; i++) 
    printf(" %d", arr_data[i]); 
else 
  printf("<not present>"); 
printf("\n"); 
  
printf("READWRITE: "); 
if (var) { 
  IDL_Print(1, &var, (char *) 0); 
  newval.l = 42; 
  IDL_StoreScalar(var, TYP_LONG, &newval); 
} else { 
  printf("<not present>"); 
} 
printf("\n"); 
  
IDL_KWCleanup(IDL_KW_CLEAN); 
} 

Executing this routine from the IDL command line, by entering:

KEYWORD_DEMO 

gives the output:

LONG: <not present> 
FLOAT: 0.000000 
DOUBLE: <not present> 
STRING: <not present> 
ARRAY: <not present> 
READWRITE: <not present> 

Executing it again with keywords specified:

A = 56 
KEYWORD_DEMO, /LONG, FLOAT=2, DOUBLE=34,$ 
  STRING="hello", ARRAY=FINDGEN(10), READWRITE=A 
PRINT, 'Final Value of A: ', A 

gives the output:

LONG: <present> 
FLOAT: 2.000000 
DOUBLE: <present> 
STRING: hello 
ARRAY: 0 1 2 3 4 5 6 7 8 9 
READWRITE:      56 
Final Value of A:           42 

Those features of this procedure that are interesting in terms of keyword processing are, by line number:

7

The IDL_StoreScalar() function used on line 51 requires the scalar to be provided in an IDL_ALLTYPES struct.

9

These variables are used to determine if a given keyword is present. Note that all the keyword-related variables are declared static. This is necessary so that the C compiler can build the IDL_KW_PAR structure at compile time.

10 – 13

C variables to receive the scalar read-only keyword values.

14

C array to be used for the ARRAY read-only array keyword.

15

The array descriptor used for ARRAY. arr_data is the address where the array contents should be copied. The minimum number of elements allowed is 3, the maximum is 10. The value set in the last field (0) is not important, because the keyword processing routine never reads its value. Instead, it puts the number of elements actually seen there.

16

The READWRITE keyword uses the IDL_KW_OUT flag, so the routine receives an IDL_VPTR instead of a processed value.

18

The keyword definition array. Notice that all of the keywords are ordered lexically (ASCII) and that there is a NULL entry at the end (line 28). Also, all of the mask fields are set to 1, as is the mask argument to IDL_KWGetParams() on line 33. This means that all of the keywords in the list are to be considered valid in this routine.

The IDL_KW_FAST_SCAN macro is used to define the first keyword array element, speeding the processing of a long IDL_KW_PAR list.

19 – 20

ARRAY is defined to be a read-only array keyword of IDL_TYP_LONG. The arr_there variable will be set to non-zero if the keyword is present. In that case, the array contents will be placed in the variable arr_data and the number of elements will be placed into arr_d.n.

21

DOUBLE is a scalar keyword of IDL_TYP_DOUBLE. It uses the variable d_there to know if the keyword is present.

22

FLOAT is an IDL_TYP_FLOAT scalar keyword. It does not use the specified field of the IDL_KW_PAR struct to get notification of whether the keyword is present. Instead, it uses the IDL_KW_ZERO flag to make sure that the variable f is always zeroed. If the keyword is present, the value will be written into f, otherwise it will remain 0. The important point is that the routine can't tell the difference between the keyword being absent, or being present with a user-supplied value of zero. If this distinction doesn't matter, such as when the keyword is to serve as an on/off toggle, use this method. If it does matter, use the specified field as demonstrated with the DOUBLE keyword, above.

23 – 24

LONG is a scalar keyword of IDL_TYP_LONG. It sets the IDL_KW_ZERO flag to get the variable l zeroed prior to keyword parsing. The use of the IDL_KW_VALUE flag indicates that if the keyword is present, the value 15 (the lower 12 bits of the flags field) will be ORed into the variable l.

25 – 26

The IDL_KW_OUT flag indicates that the routine wants gets the IDL_VPTR for READWRITE if it is present. Since IDL_KW_ZERO is also set, the variable var will be zero unless the keyword is present. The specification of IDL_TYP_UNDEF here indicates that there is no type conversion or processing applied to IDL_KW_OUT keywords.

27

This keyword is included here to force the need for IDL_KWCleanup() on line 58.

28

Every array of IDL_KW_PAR structs must end with a NULL entry.

31

Mark the stack in preparation for the IDL_KWCleanup() call on line 58.

33

Do the keyword processing. The first three arguments are simply the arguments the interpreter passed to the routine. The plain_args argument is set to NULL because this routine is registered as not accepting any plain arguments. Since no plain arguments will be present, the return value from IDL_KWGetParams() is discarded.

35

The l variable will be 0 if LONG is not present, and 1 if it is.

36

The f variable will always have some usable value, but if it is zero there is no way to know if the keyword was actually specified or not.

37 – 38

These keywords use the variables from the specified field of their IDL_KW_PAR struct to determine if they were specified or not. Use of the IDL_STRING_STR macro is described in Accessing IDL_STRING Values.

39– 45

Accessing the ARRAY keyword is simple. The arr_there variable indicates if the keyword is present, and arr_d.n gives the number of elements.

47 – 55

Since the READWRITE keyword is accessed via the argument's IDL_VPTR, we use the IDL_Print() function to print its value. This has the same effect as using the user-level PRINT procedure when running IDL. See Output of IDL Variables. Then, we change its value to 42 using IDL_StoreScalar().

Again, please note that we use this mechanism in order to create a simple example. You will probably want to avoid the use of this type of output (printf and IDL_PRINT()) in your own code.

57

The use of IDL_KWCleanup() is necessitated by the existence of the STRING keyword, which is of IDL_TYP_STRING.