Skip to Main Content United States    
PRODUCTS SUPPORT SOLUTIONS SERVICES
COMPAQ SOFTWARE
Compaq C

Compaq C
User's Guide for OpenVMS Systems


Previous Contents Index

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:


#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. 

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:


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:

  • 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.

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.

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:

  1. 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.
  2. 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; 
    

  3. 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; 
 } 
} 


Previous Next Contents Index
Buy Online or Call 1.800.888.0220      privacy statement and legal notices 
STORES CONTACT US SEARCH PRODUCTS SOLUTIONS OPTIONS DEVELOPERS