Compaq C
Compaq C User's Guide for OpenVMS Systems
3.7.5 Symbol Definitions
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 Compaq C, a header file is included as follows:
To obtain a list of all Compaq C header files, see Section 1.3.1.2.
3.7.6 Condition Values
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.
3.7.7 Checking System Service Return Values
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 Compaq C, you can
do this by including the
<ssdef.h>
header file; Example 3-19 shows how this is done.
Example 3-19 Checking System Service Return
Values |
/* 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.
|
3.8 Variable-Length Argument Lists in System Services
Most system services and other external procedures require a specific
number of arguments, but some accept a variable number of optional
arguments. Because Compaq C function declarations do not show the
number of parameters expected by external functions unless a function
prototype is used, the way you call an external function from a
Compaq C program depends on the semantics of the called function.
You must supply the number of arguments that the external function
expects. The rules are as follows:
- When optional arguments occur between required arguments, they
cannot be omitted. If omitting such an argument is necessary---for
example, to select a default action---the argument must be written as a
zero.
- When optional arguments occur at the end of an argument list, the
format of the function reference depends on the action of the called
function as follows:
- If the called function checks the number of arguments passed, you
can omit optional trailing arguments from the function reference.
System services generally do not check the length of the argument list.
- If the called function does not check the number of arguments
passed, all arguments must be present in the function reference.
For example, the function STR$CONCAT, in the Common Run-Time Library,
concatenates from 2 to 254 strings into a single string. It has the
following call format:
ret = STR$CONCAT(dst, src1,
src2[, src3,...src254]);
|
For more information about the STR$CONCAT function, see the
VMS Run-Time Library Routines Volume.
The identifier dst is the destination for the concatenated
string, and src1, src2, ...src254 are the
source strings. All arguments are passed by descriptor. All but the
first two source strings are optional. The function checks to see how
many arguments are present in the call; if fewer than three (the
destination and two sources) are present, the function returns an error
status value. Example 3-20 shows a call to the STR$CONCAT function
from Compaq C.
Example 3-20 Using Variable-Length Argument
Lists |
/* This example shows a call to STR$CONCAT. */
#include <stdio.h>
#include <descrip.h>
#include <ssdef.h>
int STR$CONCAT();
int main(void)
{
int ret; /* Return status of *
* STR$CONCAT */
/* Destination array of *
* concatenated strings */
char dest[21];
/* Create compile-time *
* descriptors: */
$DESCRIPTOR(dst, dest);
static $DESCRIPTOR(src1, "abcdefghij");
static $DESCRIPTOR(src2, "klmnopqrst");
/* Concatenate strings */
ret = STR$CONCAT(&dst, &src1, &src2);
/* Test return status value */
if (ret != SS$_NORMAL)
fprintf(stderr,"Failed to concatenate strings.\n"),
exit(ret);
/* Process string */
else
dest[20] = '\0',
printf("Resultant string: %s\n",dest);
}
|
3.9 Return Status Values
The status values from OpenVMS system service procedures are
returned in general register R0. This return status value indicates the
success or failure of the operation performed by the called procedure.
In Compaq C, passing a return status value in R0 is equivalent to
a function returning
int
.
To obtain a return status value from any system procedure, declare the
procedure as a function, as shown in the following example:
After declaring a procedure in this way, you can invoke the procedure
as a function and obtain a return status value. In Compaq C, such
a declaration is needed only as program documentation; SYS$SETEF can be
called without explicit declaration and will be interpreted by default
as a function returning
int
.
This section describes the following topics:
- The format of a return status value, that is, the meaning of
particular bits within the value
- The way to manipulate return status values
- The recommended techniques for testing a return status value for
success or failure or for a specific condition
3.9.1 Format of Return Status Values
All OpenVMS system procedures and programs use a longword
value to communicate return status information. When a Compaq C
main function executing under the control of the DCL interpreter
executes a
return
statement to return control to the command level, the command
interpreter uses the return status value to conditionally display a
message on the current output device.
To provide a unique means of identifying every return condition in the
system, bit fields within the value are defined as shown in
Figure 3-5.
Figure 3-5 Bit Fields Within a Return Status Value
The following list describes the division of this bit field:
control bits (31-28)
Define special action(s) to be taken. At present, only bit 28 is used.
When set, it inhibits the printing of the message associated with the
return status value at image exit. Bits 29 through 31 are reserved for
future use by Compaq and must be 0.
facility number (27-16)
A unique value assigned to the system component, or facility, that is
returning the status value. Within this field, bit 27 has a special
significance. If bit 27 is clear, the facility is a Compaq facility:
the remaining value in the facility number field is a number assigned
by the operating system. If bit 27 is set, the number indicates a
customer-defined facility.
message number (15-3)
An identification number that specifically describes the return status
or condition. Within this field, bit 15 has a special significance. If
bit 15 is set, the message number is unique to the facility issuing the
message. If bit 15 is clear, the message is issued by more than one
system facility.
severity (2-0)
A numeric value indicating the severity of the return status.
Table 3-13 shows the possible values in these three bits, and their
meanings.
Odd values indicate success (an informational condition is considered a
successful status) and even values indicate failures (a warning is
considered an unsuccessful status).
The following names are associated with these fields:
control bits
bit 28 (inhibit message)
|
CONTROLINHIB_MSG
|
facility number
bit 27 (customer facility)
|
FAC_NOCUST_DEF
|
message number
bit 15 (facility specific)
|
MSG_NOFAC_SP
|
severity
bit 0 (success)
|
SEVERITYSUCCESS
|
When testing return values in a Compaq C program, either you can
test only for successful completion of a procedure or you can test for
specific return status values.
3.9.2 Manipulating Return Status Values
You can construct a structure or union that describes a return status
value, but this method of manipulating return status values is not
recommended. A status value is usually constructed or checked using
bitwise operators. Compaq C provides the
<stsdef.h>
header file, which contains preprocessor definitions to make this job
easier. All the preprocessor symbols are named according to the
following OpenVMS naming convention:
STS
Identifies standard return status values.
type
One of the following characters denoting the type of the constant:
K
|
Represents a constant value
|
M
|
Represents a bit mask
|
S
|
Represents the bit size of a field
|
V
|
Defines the bit offset to the field
|
name
An abbreviation for the field name.
For example, the following constants are defined in
<stsdef.h>
for the facility number field, FAC_NO, which spans bits 16 through 27:
/* Size of field in bits */
#define STS$S_FAC_NO 12
/* Bit offset to the *
* beginning of the field */
#define STS$V_FAC_NO 16
/* Bit mask of the field */
#define STS$M_FAC_NO 0xFFF0000
|
Figure 3-6 shows how the status value is represented internally.
Figure 3-6 Internal Representation of a Status Value
Use the following expression to extract the facility number from a
particular status value contained in the variable named status:
(status & STS$M_FAC_NO) >> STS$V_FAC_NO
|
In the previous example, the parentheses are required for the
expression to be evaluated properly; the relative precedence of the
bitwise AND operator (&) is lower than the precedence of the binary
shift operator (>>).
3.9.3 Testing for Success or Failure
To test a return status value for success or failure, you need only
test the success bit. A value of true in this bit indicates that the
return value is a successful value.
Example 3-21 shows a program that checks the success bit.
Example 3-21 Testing for Success |
/* This program shows how to test the success bit. */
#include <stdio.h>
#include <descrip.h>
#include <stsdef.h>
#include <starlet.h>
#include <stdlib.h>
int main(void)
{
int status;
$DESCRIPTOR(name, "student");
status = sys$setprn(&name);
if (status & STS$M_SUCCESS)
/* Success code */
fprintf(stderr, "Successful completion");
else
/* Failure code */
fprintf(stderr, "Failed to set process name.\n");
exit(status);
}
|
The failure code in Example 3-21 causes the printing of a
program-specific message indicating the condition that caused the
program to terminate. The error status is passed to the DCL by the
exit
function, which then interprets the status value.
3.9.4 Testing for Specific Return Status Values
Each numeric return status value defined by the system has a symbolic
name associated with it. The names of these values are defined as
system global symbols, and you can access their values by referring to
their symbolic names.
The global symbol names for OpenVMS return status values have
the following format:
facility
An abbreviation or acronym for the system facility that defined the
global symbol.
code
A mnemonic for the specific status value.
Table 3-14 shows some examples of facility codes used in global
symbol names.
Table 3-14 Facility Codes
Facility |
Description |
SS
|
System services; these status codes are listed in the OpenVMS System Services Reference Manual.
|
RMS
|
File system procedures; these status codes are listed in the
OpenVMS Record Management Services Reference Manual.
|
SOR
|
SORT procedures; these status codes are listed in the VMS Sort/Merge Utility Manual.
|
The definitions of the global symbol names for the facilities listed
are located in the default Compaq C object module libraries, so
they are automatically located when you link a Compaq C program
that references them.
When you write a Compaq C program that calls system procedures and
you want to test for specific return status values using the symbol
names, you must perform the following tasks:
- Determine, from the documentation of the procedure, the status
values that can be returned, and choose the values for which you want
to provide specific tests.
- Declare the symbolic name for each value of interest. The
<ssdef.h>
and
<rmsdef.h>
header files define the system service and RMS return status values,
respectively. If you are checking return status values from other
facilities, such as the SORT utility, you must explicitly declare the
return values as
globalvalue int
. Consider the following example:
globalvalue int SOR$_OPENIN;
|
- Reference the symbols in your program.
Example 3-22 shows a program that checks for specific return status
values defined in the
<ssdef.h>
header file.
Example 3-22 Testing for Specific Return
Status Values |
/* This program checks for specific return status values. */
#include <ssdef.h>
#include <stdio.h>
#include <descrip.h>
$DESCRIPTOR(message,"\07**Lunch_time**\07");
int main(void)
{
int status = SYS$BRDCST(&message,0);
if (status != SS$_NORMAL)
{
if (status == SS$_NOPRIV)
fprintf(stderr, "Can't broadcast; requires OPER \
privilege.");
else
fprintf(stderr, "Can't broadcast; some fatal \
error.");
exit(status);
}
}
|
3.10 Examples of Calling System Routines
This section provides complete examples of calling system routines from
Compaq C. Example 3-23 shows the three mechanisms for passing
arguments to system services and also shows how to test for status
return codes. Example 3-24 shows various ways of testing for
successful $QIO completion. Example 3-25 shows how to use time
conversion and set timer routines.
In addition to the examples provided here, the VMS Run-Time Library Routines Volume and the
OpenVMS System Services Reference Manual also provide examples for selected routines. See these
manuals for help on using a specific system routine.
Example 3-23 Passing Arguments to System
Services |
/* GETMSG.C
This program is an example showing the three mechanisms
for passing arguments to system services. It also
shows how to test for specific status return
codes from a system service call. */
#include <stdio.h>
#include <descrip.h>
#include <ssdef.h>
int main(void)
{
int message_id;
short message_len;
char text[133];
$DESCRIPTOR(message_text, text);
register status;
while (printf("\nEnter a message number <Ctrl/Z to quit>: "),
scanf("%d", &message_id) != EOF)
{
/* Retrieve message associated with the number. */
status = SYS$GETMSG(message_id, &message_len,
&message_text, 15, 0);
/* Check for status conditions. */
if (status == SS$_NORMAL)
printf("\n%.*s\n", message_len, text);
else if (status == SS$_BUFFEROVF)
printf("\nBUFFER OVERFLOW -- Text is: %.*s\n",
message_len, text);
else if (status == SS$_MSGNOTFND)
printf("\nMESSAGE NOT FOUND.\n");
else
{
printf("\nUnexpected error in $GETMSG call.\n");
LIB$STOP(status);
}
}
}
|
Example 3-24 Determining$QIO Completion |
/* ASYNCH.C
This program shows various ways to determine
$QIO completion. It also shows the use of an
IOSB to obtain information about the I/O operation. */
#include <iodef.h>
#include <ssdef.h>
#include <descrip.h>
typedef struct
{
short cond_value;
short count;
int info;
} io_statblk;
main(void)
{
char text_string[] = "This was written by the $QIO.";
register status;
short chan;
io_statblk status_block;
int AST_PROC();
$DESCRIPTOR (terminal, "SYS$COMMAND");
/* Assign I/O channel. */
if (((status = SYS$ASSIGN (&terminal, &chan,0,0)) & 1) != 1)
LIB$STOP (status);
/* Queue the I/O. */
if (((status = SYS$QIO (1, chan, IO$_WRITEVBLK, &status_block,
AST_PROC, &status_block, text_string,
strlen(text_string),0,32,0,0)) & 1) != 1)
LIB$STOP (status);
/* Wait for the I/O operation to complete. */
if (((status = SYS$SYNCH (1, &status_block)) & 1) != 1)
LIB$STOP (status);
if ((status_block.cond_value &1) != 1)
LIB$STOP(status_block.cond_value);
printf ("\nThe I/O operation and AST procedure are done.");
}
AST_PROC (io_statblk, *write_status)
io_statblk *write_status;
/* This function is called as an AST procedure. It uses
the AST parameter passed to it by $QIO to determine
how many characters were written to the terminal. */
{
printf("\nNumber of characters output is %d", write_status->count);
printf("\nI/O completion status is %d", write_status->cond_value);
}
|
Example 3-25 Using Time Routines |
/* ALARM.C
This program shows the use of time conversion
and set timer routines. */
#include <stdio.h>
#include <descrip.h>
#include <ssdef.h>
main(void)
{
#define event_flag 2
#define timer_id 3
typedef int quadword[2];
quadword delay_int;
$DESCRIPTOR(offset, "0 ::15.00");
char cur_time[24];
$DESCRIPTOR(cur_time_desc, cur_time);
int i;
unsigned state;
register status;
/* Convert offset from ASCII to binary format. */
if (((status=SYS$BINTIM(&offset, delay_int)) &1) != 1)
LIB$STOP(status);
/* Output current time. */
if (((status=LIB$DATE_TIME(&cur_time_desc)) &1) != 1)
LIB$STOP(status);
cur_time[23] = '\0';
printf("The current time is : %s\n", cur_time);
/* Set the timer to expire in 15 seconds. */
if (((status=SYS$SETIMR(event_flag, &delay_int,
0, timer_id)) &1) != 1)
LIB$STOP(status);
/* Count to 1000000. */
printf("beginning count....\n");
for (i=0; i<=1000000; i++)
;
/* Check if the timer expired. */
switch (status = SYS$READEF(event_flag, &state))
{
case SS$_WASCLR : /* Cancel timer */
if (((status=SYS$CANTIM(timer_id, 0)) &1) != 1)
LIB$STOP(status);
printf("Count completed before timer expired.\n");
printf("Timer canceled.\n");
break;
case SS$_WASSET : printf("Timer expired before count completed.\n");
break;
default : LIB$STOP(status);
break;
}
}
|
|
|