United States |
Previous | Contents | Index |
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:
#include <ssdef.h> |
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. |
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:
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); } |
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:
int SYS$SETEF(); |
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:
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 DIGITAL 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 DIGITAL 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.
Table 3-13 Possible Severity Values Value Meaning 0 Warning 1 Success 2 Error 3 Informational 4 Severe error, FATAL 5-7 Reserved 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$type_name |
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$_code |
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.
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:
globalvalue int SOR$_OPENIN; |
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); } } |
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; } } |
Previous | Next | Contents | Index |
|