The basic steps for calling routines are the same whether you are calling a routine written in DEC C, a routine written in some other OpenVMS language, a system service, or an OpenVMS Run-Time Library (RTL) routine. The following sections outline the procedures for calling non-DEC C routines.
Before calling an external routine, you must first determine whether the call should be a procedure call or a function call. Call a routine as a procedure if it does not return a value. Call a routine as a function if it returns any type of value.
To call an external routine or system routine, you need to declare it as an external function and to declare the names, data types, and passing mechanisms of its arguments. Arguments can be either required or optional.
Include the following information in a routine declaration:
The following example shows how to declare an external routine and its arguments:
char func_name (int x, char y);
After declaring an external routine, you can invoke it. To invoke a function, you must specify the name of the routine being invoked and all arguments required for that routine. Make sure the data types for the actual arguments you are passing coincide with those of the parameters you declared earlier, and with those declared in the routine. The following example shows how to invoke the function declared in Section 3.7.2:
ret_status = func_name(1,'a');
All system routine arguments are described in terms of the following information:
OpenVMS usages are data structures that are layered on the standard OpenVMS data types. For example, the OpenVMS usage mask_longword signifies an unsigned longword integer that is used as a bit mask, and the OpenVMS usage floating_ point represents any OpenVMS floating-point data type. Table 3-12 lists all the OpenVMS usages and the DEC C types you need to implement them.
OpenVMS Data Type | DEC C Declaration |
---|---|
access_bit_names | user-defined[1] |
access_mode | unsigned char |
address | int *pointer[2,4] |
address_ range | int *array [2] [2,3,4] |
arg_list | user-defined[1] |
ast_procedure | pointer to a function[2] |
boolean | unsigned long int |
byte_signed | char |
byte_unsigned | unsigned char |
channel | unsigned short int |
char_string | char array[n][3,5] |
complex_number | user-defined[1] |
cond_value | unsigned long int |
context | unsigned long int |
date_time | user- defined[1] |
device_name | char array[n][3,5] |
ef_cluster_ name | char array[n][3,5] |
ef_ number | unsigned long int |
exit_handler_block | user-defined[1] |
fab | #include fab from text library struct FAB |
file_protection | unsigned short int, or user-defined[1] |
floating_point | float or double |
function_code | unsigned long int or user-defined[1] |
identifier | int *pointer[2,4] |
io_status_ block | user-defined[1] |
item_ list_2 | user-defined[1] |
item_list_3 | user-defined[1] |
item_list_pair | user-defined[1] |
item_quota_list | user-defined[1] |
lock_id | unsigned long int |
lock_status_block | user- defined[1] |
lock_value_block | user-defined[1] |
logical_ name | char array[n][3,5] |
longword_signed | long int |
longword_unsigned | unsigned long int |
mask_byte | unsigned char |
mask_longword | unsigned long int |
mask_quadword | user- defined[1] |
mask_word | unsigned short int |
null_arg | unsigned long int |
octaword_ signed | user-defined[1] |
octaword_unsigned | user-defined[1] |
page_protection | unsigned long int |
procedure | pointer to function[2] |
process_id | unsigned long int |
process_ name | char array[n][3,5] |
quadword_signed | user-defined[1] |
quadword_unsigned | user- defined[1] |
rights_holder | user-defined[1] |
rights_id | unsigned long int |
rab | #include rab struct RAB |
section_id | user- defined[1] |
section_name | char array[n][3,5] |
system_access_ id | user-defined[1] |
time_ name | char array[n][3,5] |
uic | unsigned long int |
user_arg | user-defined[1] |
varying_arg | user-defined[1] |
vector_byte_signed | char array[n][3,5] |
vector_byte_unsigned | unsigned char array[n][3,5] |
vector_longword_ signed | long int array[n][3,5] |
vector_longword_unsigned | unsigned long int array[n][3,5] |
vector_ quadword_signed | user-defined[1] |
vector_quadword_unsigned | user- defined[1] |
vector_word_signed | short int array[n][3,5] |
vector_word_ unsigned | unsigned short int array[n][3,5] |
word_signed | short int |
word_unsigned | unsigned short int |
[1] The declaration of a user-defined data structure depends on how the data will be used. Such data structures can be declared in a variety of ways, each of which is more suitable to specific applications. [2] The term pointer refers to several declarations involving pointers. Pointers are declared with special syntax and are associated with the data type of the object being pointed to. This object is often user-defined. [3] The term array denotes the syntax of a DEC C array declaration. [4] The data type specified can be changed to any valid DEC C data type. [5] The size of the array must be substituted for n. |
If a system routine argument is optional, it will be indicated in the format section of the routine description in one of two ways, as follows:
If the comma appears outside the brackets, you must pass a 0 by value to indicate the place of the omitted argument. If the comma appears inside the brackets, you can omit the argument if it is the last argument in the list.
Many system routines depend on values that are defined in separate symbol definition files. OpenVMS RTL routines require you to include symbol definitions when you are calling a Screen Management facility routine or a routine that is a jacket to a system service. A jacket routine provides an interface to the corresponding system service. For example, the routine LIB$SYS_ASCTIM is a jacket routine for the $ASCTIM system service.
If you are calling a system service, you must include the <ssdef.h> header file to check the status. Many system services require other symbol definitions as well. To determine whether you need to include other symbol definitions for the system service you want to use, see the documentation for that particular system service. If the documentation states that values are defined in a macro, you must include those symbol definitions in your program.
For example, the description for the flags parameter in the SYS$MGBLSC (Map Global Section) system service states that "Symbolic names for the flag bits are defined by the $SECDEF macro." Therefore, when you call SYS$MGBLSC you must include the definitions provided in the $SECDEF macro by including the <secdef.h> header file.
In DEC C, a header file is included as follows:
#include <ssdef.h>
To obtain a list of all DEC C header files, see Section 1.3.1.2.
Many system routines return a condition value that indicates success or failure; this value can be either returned or signaled. If a condition value is returned, then you must check the returned value to determine whether the call to the system routine was successful. Otherwise, the condition value is signaled to your program instead of being written to a storage location.
Condition values indicating success appear first in the list of condition values for a particular routine, and success codes have odd values. A success code that is common to many system routines is the condition value SS$_NORMAL, which indicates that the routine completed normally and successfully. If the condition value is returned, then you can test for SS$_NORMAL as follows:
if (ret_status != SS$_NORMAL) LIB$STOP();
Because all success codes have odd values, you can check a return status for any success code. For example, you can cause execution to continue only if a success code is returned by including the following statements in your program:
if ((ret_status & 1) != 0) LIB$STOP (ret_status);
In general, you can check a return status for a particular success or failure code or you can test the condition value returned against all success codes or all failure codes.
It is customary in OpenVMS programming to compare the return status of a system service with a global symbol, not with the literal value associated with a particular return status. Consequently, a high-level language program should define the possible return status values for a service as symbolic constants. In DEC C, you can do this by including the <ssdef.h> header file; Example 3-19 shows how this is done.
/* This program shows how to compare the status of a system * * service with a global symbol. */ /* Define system service * * status values */ #include <ssdef.h> #include <stdio.h> /* Declaration of the * * service (not required) */ int SYS$SETEF(); int main(void) { /* To hold the status of * * SYS$SETEF */ int efstatus; /* Argument values for * * SYS$SETEF */ enum cluster0 { completion, breakdown, beginning } event; . . . event = completion; /* Set the event flag */ efstatus = SYS$SETEF(event); /* Test the return status */ if (efstatus == SS$_WASSET) fprintf (stderr,"Flag was already set\n"); else if (efstatus == SS$_WASCLR) fprintf(stderr, "Flag was previously clear\n"); else fprintf(stderr, "Could not set completion event flag.\n \ Possible programming error.\n"); exit(efstatus); }
The system service return status values (SS$_WASSET and SS$_WASCLR) in Example 3-19 are defined by the <ssdef.h> header file.
Error handling in Example 3-19 is typical of programs running on OpenVMS systems. Using the following statements, the example program attempts to provide a program-specific error message and then passes the offending error status to the caller:
else fprintf(stderr, "Could not set completion event flag.\n \ Possible programming error.\n"); exit(efstatus);
If you execute the program with DCL, it interprets any status value the program returns. DCL prints a standard error message on the terminal to provide you with more information about the failure. For example, if the program encounters the SS$_ILLEFC return status, DCL displays the following messages:
Could not set completion event flag. Possible programming error. %SYSTEM-F-ILLEFC, illegal event flag cluster.