hp.com home products and services support and drivers solutions how to buy
cd-rom home
End of Jump to page title
HP OpenVMS systems
documentation

Jump to content


HP OpenVMS Programming Concepts Manual

HP OpenVMS Programming Concepts Manual


Previous Contents Index

9.11.1 Chaining Messages

You can use a condition handler to add condition values to an originally signaled condition code. For example, if your program calculates the standard deviation of a series of numbers and the user only enters one value, the operating system signals the condition code SS$_INTDIV when the program attempts to divide by zero. (In calculating the standard deviation, the divisor is the number of values entered minus 1.) You could use a condition handler to add a user-defined message to the original message to indicate that only one value was entered.

To display multiple messages, pass the condition values associated with the messages to the RTL routine LIB$SIGNAL. To display the message associated with an additional condition code, the handler must pass LIB$SIGNAL the condition code, the number of FAO arguments used, and the FAO arguments. To display the message associated with the originally signaled condition codes, the handler must pass LIB$SIGNAL each element of the signal array as a separate argument. Because the signal array is a variable-length array and LIB$SIGNAL cannot accept a variable number of arguments, when you write your handler you must pass LIB$SIGNAL more arguments than you think will be required. Then, during execution of the handler, zero the arguments that you do not need (LIB$SIGNAL ignores zero values), as described in the following steps:

  1. Declare an array with one element for each argument that you plan to pass LIB$SIGNAL. Fifteen elements are usually sufficient.


    INTEGER*4 NEWSIGARGS(15) 
    

  2. Transfer the condition values and FAO information from the signal array to your new array. The first element and the last two elements of the signal array do not contain FAO information and should not be transferred.
  3. Fill any remaining elements of your new array with zeros.

The following example demonstrates steps 2 and 3:


DO I = 1, 15 
 
  IF (I .LE. SIGARGS(1) - 2) THEN 
    NEWSIGARGS(I) = SIGARGS(I+1)  ! Start with SIGARGS(2) 
    ELSE 
    NEWSIGARGS(I) = 0             ! Pad with zeros 
  END IF 
 
END DO 

Because the new array is a known-length array, you can specify each element as an argument to LIB$SIGNAL.

The following condition handler ensures that the signaled condition code is SS$_INTDIV. If it is, the user-defined message ONE_VALUE is added to SS$_INTDIV, and both messages are displayed.


INTEGER FUNCTION HANDLER (SIGARGS, 
2                         MECHARGS) 
 
! Declare dummy arguments 
INTEGER SIGARGS(*), 
2       MECHARGS(*) 
! Declare new array for SIGARGS 
INTEGER NEWSIGARGS (15) 
! Declare index variable for LIB$MATCH_COND 
INTEGER INDEX 
! Declare procedures 
INTEGER LIB$MATCH_COND 
! Declare condition codes 
EXTERNAL ONE_VALUE 
INCLUDE '($SSDEF)' 
INDEX = LIB$MATCH_COND (SIGARGS(2), 
2                       SS$_INTDIV) 
IF (INDEX .GT. 0) THEN 
 
  DO I=1,15 
    IF (I .LE. SIGARGS(1) - 2) THEN 
      NEWSIGARGS(I) = SIGARGS(I+1)  ! Start with SIGARGS(2) 
    ELSE 
      NEWSIGARGS(I) = 0             ! Pad with zeros 
    END IF 
  END DO 
 
    ! Signal messages 
  CALL LIB$SIGNAL (%VAL(NEWSIGARGS(1)), 
2                  %VAL(NEWSIGARGS(2)), 
2                  %VAL(NEWSIGARGS(3)), 
2                  %VAL(NEWSIGARGS(4)), 
2                  %VAL(NEWSIGARGS(5)), 
2                  %VAL(NEWSIGARGS(6)), 
2                  %VAL(NEWSIGARGS(7)), 
2                  %VAL(NEWSIGARGS(8)), 
2                  %VAL(NEWSIGARGS(9)), 
2                  %VAL(NEWSIGARGS(10)), 
2                  %VAL(NEWSIGARGS(11)), 
2                  %VAL(NEWSIGARGS(12)), 
2                  %VAL(NEWSIGARGS(13)), 
2                  %VAL(NEWSIGARGS(14)), 
2                  %VAL(NEWSIGARGS(15)), 
2                  %VAL(%LOC(ONE_VALUE)), 
2                  %VAL(0)) 
 
  HANDLER = SS$_CONTINUE 
ELSE 
  HANDLER = SS$_RESIGNAL 
 
END IF 
 
END 

A signal argument list may contain one or more condition values and FAO arguments. Each condition value and its FAO arguments is "chained" to the next condition value and its FAO arguments. You can use chained messages to provide more specific information about the exception condition being signaled, along with a general message.

The following message source file defines the exception condition PROG__FAIGETMEM:


 
     .FACILITY     PROG,1 /PREFIX=PROG__ 
 
     .SEVERITY     FATAL 
     .BASE     100 
 
     FAIGETMEM   <failed to get !UL bytes of memory>/FAO_COUNT=1 
 
     .END 

This source file sets up the exception message as follows:

9.11.2 Logging Error Messages to a File

You can write a condition handler to obtain a copy of a system error message text and write the message into an auxiliary file, such as a listing file. In this way, you can receive identical messages at the terminal (or batch log file) and in the auxiliary file.

To log messages, you must write a condition handler and an action subroutine. Your handler calls the Put Message (SYS$PUTMSG) system service explicitly. The operation of SYS$PUTMSG is described in Section 9.11. The handler passes to SYS$PUTMSG the signal argument vector and the address of the action subroutine. SYS$PUTMSG passes to the action subroutine the address of a string descriptor that contains the length and address of the formatted message. The action subroutine can scan the message or copy it into a log file, or both.

It is important to keep the display messages centralized and consistent. Thus, you should use only SYS$PUTMSG to display or log system error messages. Further, because the system default handlers call SYS$PUTMSG to display error messages, your handlers should avoid displaying the error messages. You can do this in two ways:

Figure 9-16 shows the sequence of events involved in calling SYS$PUTMSG to log an error message to a file.

Figure 9-16 Using a Condition Handler to Log an Error Message


9.11.2.1 Creating a Running Log of Messages Using SYS$PUTMSG

To keep a running log (that is, a log that is resumed each time your program is invoked) of the messages displayed by your program, use SYS$PUTMSG. Create a condition handler that invokes SYS$PUTMSG regardless of the signaled condition code. When you invoke SYS$PUTMSG, specify a function that writes the formatted message to your log file and then returns with a function value of 0. Have the condition handler resignal the condition code. One of the arguments of SYS$PUTMSG allows you to specify a user-defined function that SYS$PUTMSG invokes after formatting the message and before displaying the message. SYS$PUTMSG passes the formatted message to the specified function. If the function returns with a function value of 0, SYS$PUTMSG does not display the message; if the function returns with a value of 1, SYS$PUTMSG displays the message. The HP OpenVMS System Services Reference Manual contains complete specifications for SYS$PUTMSG.

9.11.2.2 Suppressing the Display of Messages in the Running Log

To keep a running log of messages, you might have your main program open a file for the error log, write the date, and then establish a condition handler to write all signaled messages to the error log. Each time a condition is signaled, a condition handler like the one in the following example invokes SYS$PUTMSG and specifies a function that writes the message to the log file and returns with a function value of 0. SYS$PUTMSG writes the message to the log file but does not display the message. After SYS$PUTMSG writes the message to the log file, the condition handler resignals to continue program execution. (The condition handler uses LIB$GET_COMMON to read the unit number of the file from the per-process common block.)

ERR.FOR


INTEGER FUNCTION ERRLOG (SIGARGS, 
2                        MECHARGS) 
! Writes the message to file opened on the 
! logical unit named in the per-process common block 
! Define the dummy arguments 
INTEGER SIGARGS(*), 
2       MECHARGS(*) 
INCLUDE '($SSDEF)' 
 
EXTERNAL PUT_LINE 
INTEGER PUT_LINE 
! Pass signal array and PUT_LINE routine to SYS$PUTMSG 
SIGARGS(1) = SIGARGS(1) - 2   ! Subtract PC/PSL from signal array 
CALL SYS$PUTMSG (SIGARGS, 
2                PUT_LINE, ) 
SIGARGS(1) = SIGARGS(1) + 2   ! Replace PC/PSL 
 
ERRLOG = SS$_RESIGNAL 
 
END 

PUT_LINE.FOR


INTEGER FUNCTION PUT_LINE (LINE) 
! Writes the formatted message in LINE to 
! the file opened on the logical unit named 
! in the per-process common block 
! Dummy argument 
CHARACTER*(*) LINE 
! Logical unit number 
CHARACTER*4 LOGICAL_UNIT 
INTEGER UNIT_NUM 
! Indicates that SYS$PUTMSG is not to display the message 
PUT_LINE = 0 
! Get logical unit number and change to integer 
STATUS = LIB$GET_COMMON (LOGICAL_UNIT) 
READ (UNIT = LOGICAL_UNIT, 
2     FMT = '(I4)') UNIT_NUMBER 
! The main program opens the error log 
WRITE (UNIT = UNIT_NUMBER, 
2      FMT = '(A)') LINE 
 
END 

9.11.3 Using the Message Utility to Signal and Display User-Defined Messages

Section 9.11 explains how the OpenVMS Condition Handling facility displays messages. The signal argument list passed to LIB$SIGNAL or LIB$STOP can be seen as one or more message sequences. Each message sequence consists of a condition value, an FAO count, which specifies the number of FAO arguments to come, and the FAO arguments themselves. (The FAO count is omitted in the case of system and RMS messages.) The message text definition itself is actually a SYS$FAO control string, which may contain embedded $FAO directives. The HP OpenVMS System Services Reference Manual describes the Formatted ASCII Output (SYS$FAO) system service in detail.

The Message utility is provided for compiling message sequences specific to your application. When you have defined an exception condition and used the Message utility to associate a message with that exception condition, your program can call LIB$SIGNAL or LIB$STOP to signal the exception condition. You signal a message that is defined in a message source file by calling LIB$SIGNAL or LIB$STOP, as for any software-detected exception condition. Then the system default condition handlers display your error message in the standard operating system format.

To use the Message utility, follow these steps:

  1. Create a source file that specifies the information used in messages, message codes, and message symbols.
  2. Use the MESSAGE command to compile this source file.
  3. Link the resulting object module, either by itself or with another object module containing a program.
  4. Run your program so that the messages are accessed, either directly or through the use of pointers.

See also the description of the Message utility in the HP OpenVMS Command Definition, Librarian, and Message Utilities Manual.

9.11.3.1 Creating the Message Source File

A message source file contains definition statements and directives. The following message source file defines the error messages generated by the sample INCOME program:

INCMSG.MSG


 .FACILITY INCOME, 1 /PREFIX=INCOME__ 
 
 .SEVERITY WARNING 
     LINELOST   "Statistics on last line lost due to Ctrl/Z" 
 
 .SEVERITY SEVERE 
     BADFIXVAL  "Bad value on /FIX" 
     CTRLZ      "Ctrl/Z entered on terminal" 
     FORIOERR   "Fortran I/O error" 
     INSFIXVAL  "Insufficient values on /FIX" 
     MAXSTATS   "Maximum number of statistics already entered" 
     NOACTION   "No action qualifier specified" 
     NOHOUSE    "No such house number" 
     NOSTATS    "No statistics to report" 
 
 .END 

The default file type of a message source file is .MSG. For a complete description of the Message utility, see the HP OpenVMS Command Definition, Librarian, and Message Utilities Manual.

9.11.3.1.1 Specifying the Facility

To specify the name and number of the facility for which you are defining the error messages, use the .FACILITY directive. For instance, the following .FACILITY directive specifies the facility (program) INCOME and a facility number of 1:


 .FACILITY INCOME, 1 

In addition to identifying the program associated with the error messages, the .FACILITY directive specifies the facility prefix that is added to each condition name to create the symbolic name used to reference the message. By default, the prefix is the facility name followed by an underscore. For example, a condition name BADFIXVAL defined following the previous .FACILITY directive is referenced as INCOME_BADFIXVAL. You can specify a prefix other than the specified program name by specifying the /PREFIX qualifier of the .FACILITY directive.

By convention, system-defined condition values are identified by the facility name, followed by a dollar sign ($), an underscore (_), and the condition name. User-defined condition values are identified by the facility name, followed by two underscores (_ _), and the condition name. To include two underscores in the symbolic name, use the /PREFIX qualifier to specify the prefix:


 .FACILITY INCOME, 1 /PREFIX=INCOME__ 

A condition name BADFIXVAL defined following this .FACILITY directive is referenced as INCOME__BADFIXVAL.

The facility number, which must be between 1 and 2047, is part of the condition code that identifies the error message. To prevent different programs from generating the same condition values, the facility number must be unique. A good way to ensure uniqueness is to have the system manager keep a list of programs and their facility numbers in a file.

All messages defined after a .FACILITY directive are associated with the specified program. Specify either an .END directive or another .FACILITY directive to end the list of messages for that program. HP recommends that you have one .FACILITY directive per message file.

9.11.3.1.2 Specifying the Severity

Use the .SEVERITY directive and one of the following keywords to specify the severity of one or more condition values:

Success
Informational
Warning
Error
Severe or fatal

All condition values defined after a .SEVERITY directive have the specified severity (unless you use the /SEVERITY qualifier with the message definition statement to change the severity of one particular condition code). Specify an .END directive or another .SEVERITY directive to end the group of errors with the specified severity. Note that when the .END directive is used to end the list of messages for a .SEVERITY directive, it also ends the list of messages for the previous .FACILITY directive. The following example defines one condition code with a severity of warning and two condition values with a severity of severe. The optional spacing between the lines and at the beginning of the lines is used for clarity.


 .SEVERITY WARNING 
      LINELOST  "Statistics on last line lost due to Ctrl/Z" 
 
 .SEVERITY SEVERE 
      BADFIXVAL "Bad value on /FIX" 
      INSFIXVAL "Insufficient values on /FIX" 
 
 .END 

9.11.3.1.3 Specifying Condition Names and Messages

To define a condition code and message, specify the condition name and the message text. The condition name, when combined with the facility prefix, can contain up to 31 characters. The message text can be up to 255 characters but only one line long. Use quotation marks (" ") or angle brackets (<>) to enclose the text of the message. For example, the following line from INCMSG.MSG defines the condition code INCOME__BADFIXVAL:


BADFIXVAL  "Bad value on /FIX" 

9.11.3.1.4 Specifying Variables in the Message Text

To include variables in the message text, specify formatted ASCII output (FAO) directives. For details, see the description of the Message utility in the HP OpenVMS Command Definition, Librarian, and Message Utilities Manual. Specify the /FAO_COUNT qualifier after either the condition name or the message text to indicate the number of FAO directives that you used. The following example includes an integer variable in the message text:


NONUMBER <No such house number:  !UL.  Try again.>/FAO_COUNT=1 

The FAO directive !UL converts a longword to decimal notation. To include a character string variable in the message, you could use the FAO directive !AS, as shown in the following example:


NOFILE <No such file:  !AS.  Try again.>/FAO_COUNT=1 

If the message text contains FAO directives, you must specify the appropriate variables when you signal the condition code (see Section 9.11.4).

9.11.3.1.5 Compiling and Linking the Messages

Use the DCL command MESSAGE to compile a message source file into an object module. The following command compiles the message source file INCMSG.MSG into an object module named INCMSG in the file INCMSG.OBJ:


$ MESSAGE INCMSG

To specify an object file name that is different from the source file name, use the /OBJECT qualifier of the MESSAGE command. To specify an object module name that is different from the source file name, use the .TITLE directive in the message source file.

9.11.3.1.6 Linking the Message Object Module

The message object module must be linked with your program so the system can reference the messages. To simplify linking a program with the message object module, include the message object module in the program's object library. For example, to include the message module in INCOME's object library, enter the following:


$ LIBRARY INCOME.OLB INCMSG.OBJ

9.11.3.1.7 Accessing the Message Object Module from Multiple Programs

Including the message module in the program's object library does not allow other programs-access to the module's condition values and messages. To allow several programs access to a message module, create a default message library as follows:

  1. Create the message library---Create an object module library and enter all of the message object modules into it.
  2. Make the message library a default library---Equate the complete file specification of the object module library with the logical name LNK$LIBRARY. (If LNK$LIBRARY is already assigned a library name, you can create LNK$LIBRARY_1, LNK$LIBRARY_2, and so on.) By default, the linker searches any libraries equated with the LNK$LIBRARY logical names.

The following example creates the message library MESSAGLIB.OLB, enters the message object module INCMSG.OBJ into it, and makes MESSAGLIB.OLB a default library:


$ LIBRARY/CREATE MESSAGLIB
$ LIBRARY/INSERT MESSAGLIB INCMSG
$ DEFINE LNK$LIBRARY SYS$DISK:MESSAGLIB

9.11.3.1.8 Modifying a Message Source Module

To modify a message in the message library, modify and recompile the message source file, and then replace the module in the object module library. To access the modified messages, a program must relink against the object module library (or the message object module). The following command enters the module INCMSG into the message library MESSAGLIB; if MESSAGLIB already contains an INCMSG module, it is replaced:


$ LIBRARY/REPLACE MESSAGLIB INCMSG


Previous Next Contents Index