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

23.19 Formatting Output Strings

When you are preparing output strings for a program, you may need to insert variable information into a string prior to output, or you may need to convert a numeric value to an ASCII string. The Formatted ASCII Output (SYS$FAO) system service performs these functions.

Input to the SYS$FAO system service consists of the following:

The following example shows a call to the SYS$FAO system service to format an output string for a SYS$QIOW macro. Complete details on how to use SYS$FAO, with additional examples, are provided in the description of the SYS$FAO system service in the HP OpenVMS System Services Reference Manual.


 
 
#include <descrip.h> 
#include <lib$routines.h> 
#include <ssdef.h> 
#include <starlet.h> 
#include <stdio.h> 
#include <stsdef.h> 
 
main() { 
 
        unsigned int status, faolen; 
        char faobuf[80]; 
        $DESCRIPTOR(faostr,"FILE !AS DOES NOT EXIST");    (1)
        $DESCRIPTOR(outbuf, faobuf);                      (2)
        $DESCRIPTOR(filespec,"DISK$USER:MYFILE.DAT");     (3)
 
        status = SYS$FAO( &faostr, &outlen, &outbuf, &filespec );  (4)
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL(status); 
   .
   .
   .
        status = SYS$QIOW( ...faobuf, outlen, ... ); (5)
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL(status); 
   .
   .
   .
} 

  1. FAOSTR provides the FAO control string. !AS is an example of an FAO directive: it requires an input parameter that specifies the address of a character string descriptor. When SYS$FAO is called to format this control string, !AS will be substituted with the string whose descriptor address is specified.
  2. FAODESC is a character string descriptor for the output buffer; SYS$FAO writes the string into the buffer, and writes the length of the final formatted string in the low-order word of FAOLEN. (A longword is reserved so that it can be used for an input argument to the SYS$QIOW macro.)
  3. FILESPEC is a character string descriptor defining an input string for the FAO directive !AS.
  4. The call to SYS$FAO specifies the control string, the output buffer and length fields, and the parameter P1, which is the address of the string descriptor for the string to be substituted.
  5. When SYS$FAO completes successfully, SYS$QIOW writes the following output string:


    FILE DISK$USER:MYFILE.DAT DOES NOT EXIST 
    

23.20 Mailboxes

Mailboxes are virtual devices that can be used for communication among processes. You accomplish actual data transfer by using OpenVMS RMS or I/O services. When the Create Mailbox and Assign Channel (SYS$CREMBX) system service creates a mailbox, it also assigns a channel to it for use by the creating process. Other processes can then assign channels to the mailbox using either the SYS$CREMBX or SYS$ASSIGN system service.

The SYS$CREMBX system service creates the mailbox. The SYS$CREMBX system service identifies a mailbox by a user-specified logical name and assigns it an equivalence name. The equivalence name is a physical device name in the format MBAn, where n is a unit number. The equivalence name has the terminal attribute.

When another process assigns a channel to the mailbox with the SYS$CREMBX or SYS$ASSIGN system service, it can identify the mailbox by its logical name. The service automatically translates the logical name. The process can obtain the MBAn name either by translating the logical name (with the SYS$TRNLNM system service), or by calling the Get Device/Volume Information (SYS$GETDVI) system service to obtain the unit number and the physical device name.

On VAX systems, channels assigned to mailboxes can be either bidirectional or unidirectional. Bidirectional channels (read/write) allow both SYS$QIO read and SYS$QIO write requests to be issued to the channel. Unidirectional channels (read-only or write-only) allow only a read request or a write request to the channel. The unidirectional channels and unidirectional $QIO function modifiers provide for greater synchronization between users of the mailbox.

On VAX systems, the Create Mailbox and Assign Channel (SYS$CREMBX) and Assign I/O Channel (SYS$ASSIGN) system services use the flags argument to enable unidirectional channels. If the flags argument is not specified or is zero, then the channel assigned to the mailbox is bidirectional (read/write). For more information, see the discussion and programming examples in the mailbox driver chapter in the HP OpenVMS I/O User's Reference Manual. Chapter 3 of this manual also discusses the use of mailboxes.

Mailboxes are either temporary or permanent. You need the user privileges TMPMBX and PRMMBX to create temporary and permanent mailboxes, respectively.

For a temporary mailbox, the SYS$CREMBX service enters the logical name and equivalence name in the logical name table LNM$TEMPORARY_MAILBOX. This logical name table name usually specifies the LNM$JOB logical name table name. The system deletes a temporary mailbox when no more channels are assigned to it.

For a permanent mailbox, the SYS$CREMBX service enters the logical name and equivalence name in the logical name table LNM$PERMANENT_MAILBOX. This logical name table name usually specifies the LNM$SYSTEM logical name table name. Permanent mailboxes continue to exist until they are specifically marked for deletion with the Delete Mailbox (SYS$DELMBX) system service.

The following example shows how processes can communicate by means of a mailbox:


 
/* Process ORION */ 
 
#include <descrip.h> 
#include <iodef.h> 
#include <lib$routines.h> 
#include <ssdef.h> 
#include <starlet.h> 
#include <stdio.h> 
#define MBXBUFSIZ 128 
#define MBXBUFQUO 384 
 
/* I/O status block */ 
struct { 
                unsigned short iostat, iolen; 
                unsigned int remainder; 
}mbxiosb; 
 
 
main() { 
        void *p1, mbxast(); 
        char mbuffer[MBXBUFSIZ], prmflg=0; 
        unsigned short mbxchan, mbxiosb; 
        unsigned int status, outlen; 
        unsigned int mbuflen=MBXBUFSIZ, bufquo=MBXBUFQUO, promsk=0; 
        $DESCRIPTOR(mblognam,"GROUP100_MAILBOX"); 
 
/* Create a mailbox */ 
        status = SYS$CREMBX( prmflg,         /* Permanent or temporary */  (1)
                             &mbxchan,       /* chan - channel number */ 
                             mbuflen,        /* maxmsg - buffer length */ 
                             bufquo,         /* bufquo - quota */ 
                             promsk,         /* promsk - protection mask */ 
                             0,              /* acmode - access mode */ 
                             &mblognam,      /* lognam - mailbox logical name */ 
                             0);             /* flags -  options */ 
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL(status); 
   .
   .
   .
/* Request I/O */ 
        status = SYS$QIO(0,               /* efn - event flag */   (2)
                          mbxchan,        /* chan - channel number */ 
                          IO$_READVBLK,   /* func - function modifier */ 
                          &mbxiosb,       /* iosb - I/O status block */ 
                          &mbxast,        /* astadr - AST routine */ 
                          &mbuffer,       /* p1 - output buffer */ 
                          mbuflen);       /* p2 - length of buffer */ 
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL(status); 
   .
   .
   .
 
} 
 
void mbxast(void) {                                               (3)
 
        if (mbxiosb.iostat != SS$_NORMAL) 
 
        status = SYS$QIOW(..., &mbuffer, &outlen,...) 
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL(status); 
 
        return; 
} 
 
 
/* Process Cygnus */ 
 
#include <descrip.h> 
#include <iodef.h> 
#include <lib$routines.h> 
#include <ssdef.h> 
#include <starlet.h> 
#include <stdio.h> 
#include <stsdef.h> 
#define MBXBUFSIZ 128 
 
main() { 
 
        unsigned short int mailchan; 
        unsigned int status, outlen; 
        char outbuf[MBXBUFSIZ]; 
        $DESCRIPTOR(mailbox,"GROUP100_MAILBOX"); 
 
        status = SYS$ASSIGN(&mailbox, &mailchan, 0, 0, 0);            (4)
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL(status); 
   .
   .
   .
 
        status = SYS$QIOW(0, mailchan, 0, 0, 0, 0, &outbuf, outlen, 0, 0, 0, 0) 
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL(status); 
   .
   .
   .
 
} 
 

  1. Process ORION creates the mailbox and receives the channel number at MBXCHAN.
    The prmflg argument indicates that the mailbox is a temporary mailbox. The logical name is entered in the LNM$TEMPORARY_MAILBOX logical name table.
    The maxmsg argument limits the size of messages that the mailbox can receive. Note that the size indicated in this example is the same size as the buffer (MBUFFER) provided for the SYS$QIO request. A buffer for mailbox I/O must be at least as large as the size specified in the maxmsg argument.
    When a process creates a temporary mailbox, the amount of system memory allocated for buffering messages is subtracted from the process's buffer quota. Use the bufquo argument to specify how much of the process quota should be used for mailbox message buffering.
    Mailboxes are protected devices. By specifying a protection mask with the promsk argument, you can restrict access to the mailbox. (In this example, all bits in the mask are clear, indicating unlimited read and write access.)
  2. After creating the mailbox, process ORION calls the SYS$QIO system service, requesting that it be notified when I/O completes (that is, when the mailbox receives a message) by means of an AST interrupt. The process can continue executing, but the AST service routine at MBXAST will interrupt and begin executing when a message is received.
  3. When a message is sent to the mailbox (by CYGNUS), the AST is delivered and ORION responds to the message. Process ORION gets the length of the message from the first word of the I/O status block at MBXIOSB and places it in the longword OUTLEN so it can pass the length to SYS$QIOW_S.
  4. Process CYGNUS assigns a channel to the mailbox, specifying the logical name the process ORION gave the mailbox. The SYS$QIOW system service writes a message from the output buffer provided at OUTBUF.
    Note that on a write operation to a mailbox, the I/O is not complete until the message is read, unless you specify the IO$M_NOW function modifier. Therefore, if SYS$QIOW (without the IO$M_NOW function modifier) is used to write the message, the process will not continue executing until another process reads the message.

23.20.1 Mailbox Name

The lognam argument to the SYS$CREMBX service specifies a descriptor that points to a character string for the mailbox name.

Translation of the lognam argument proceeds as follows:

  1. The current name string is prefixed with MBX$ and the result is subject to logical name translation.
  2. If the result is a logical name, step 1 is repeated until translation does not succeed or until the number of translations performed exceeds the number specified by the SYSGEN parameter LNM$C_MAXDEPTH.
  3. The MBX$ prefix is stripped from the current name string that could not be translated. This current string is made a logical name with an equivalence name MBAn (n is a number assigned by the system).

For example, assume that you have made the following logical name assignment:


$ DEFINE MBX$CHKPNT CHKPNT_001

Assume also that your program contains the following statements:


        $DESCRIPTOR(mbxdesc,"CHKPNT"); 
   .
   .
   .
        status = SYS$CREMBX(...,&mbxdesc,...); 

The following logical name translation takes place:

  1. MBX$ is prefixed to CHKPNT.
  2. MBX$CHKPNT is translated to CHKPNT_001.

Because further translation is unsuccessful, the logical name CHKPNT_001 is created with the equivalence name MBAn (n is a number assigned by the system).

There are two exceptions to the logical name translation method discussed in this section:

23.20.2 System Mailboxes

The system uses mailboxes for communication among system processes. All system mailbox messages contain, in the first word of the message, a constant that identifies the sender of the message. These constants have symbolic names (defined in the $MSGDEF macro) in the following format:

MSG$_sender

The symbolic names included in the $MSGDEF macro and their meanings are as follows:
Symbolic Name Meaning
MSG$_TRMUNSOLIC Unsolicited terminal data
MSG$_CRUNSOLIC Unsolicited card reader data
MSG$_ABORT Network partner aborted link
MSG$_CONFIRM Network connect confirm
MSG$_CONNECT Network inbound connect initiate
MSG$_DISCON Network partner disconnected
MSG$_EXIT Network partner exited prematurely
MSG$_INTMSG Network interrupt message; unsolicited data
MSG$_PATHLOST Network path lost to partner
MSG$_PROTOCOL Network protocol error
MSG$_REJECT Network connect reject
MSG$_THIRDPARTY Network third-party disconnect
MSG$_TIMEOUT Network connect timeout
MSG$_NETSHUT Network shutting down
MSG$_NODEACC Node has become accessible
MSG$_NODEINACC Node has become inaccessible
MSG$_EVTAVL Events available to DECnet Event Logger
MSG$_EVTRCVCHG Event receiver database change
MSG$_INCDAT Unsolicited incoming data available
MSG$_RESET Request to reset the virtual circuit
MSG$_LINUP PVC line up
MSG$_LINDWN PVC line down
MSG$_EVTXMTCHG Event transmitter database change

The remainder of the message contains variable information, depending on the system component that is sending the message.

The format of the variable information for each message type is documented with the system function that uses the mailbox.

23.20.3 Mailboxes for Process Termination Messages

When a process creates another process, it can specify the unit number of a mailbox as an argument to the Create Process ($CREPRC) system service. When you delete the created process, the system sends a message to the specified termination mailbox.

You cannot use a mailbox in memory shared by multiple processors as a process termination mailbox.

23.21 Example of Using I/O Services

In the following Fortran example, the first program, SEND.FOR, creates a mailbox named MAIL_BOX, writes data to it, and then indicates the end of the data by writing an end-of-file message.

The second program, RECEIVE.FOR, creates a mailbox with the same logical name, MAIL_BOX. It reads the messages from the mailbox into an array. It stops the read operations when a read operation generates an end-of-file message and the second longword of the I/O status block is nonzero. By checking that the I/O status block is nonzero, the second program confirms that the writing process sent the end-of-file message.

The processes use common event flag number 64 to ensure that SEND.FOR does not exit until RECEIVE.FOR has established a channel to the mailbox. (If RECEIVE.FOR executes first, an error occurs because SYS$ASSIGN cannot find the mailbox.)


 
                          SEND.FOR 
INTEGER STATUS 
 
! Name and channel number for mailbox 
CHARACTER*(*) MBX_NAME 
PARAMETER (MBX_NAME = 'MAIL_BOX') 
INTEGER*2 MBX_CHAN 
 
! Mailbox message 
CHARACTER*80 MBX_MESSAGE 
INTEGER LEN 
 
CHARACTER*80 MESSAGES (255) 
INTEGER MESSAGE_LEN (255) 
INTEGER MAX_MESSAGE 
PARAMETER (MAX_MESSAGE = 255) 
 
! I/O function codes and status block 
INCLUDE '($IODEF)' 
INTEGER*4 WRITE_CODE 
INTEGER*2 IOSTAT, 
2         MSG_LEN 
INTEGER READER_PID 
COMMON /IOBLOCK/ IOSTAT, 
2                MSG_LEN, 
2                READER_PID 
 
! System routines 
INTEGER SYS$CREMBX, 
2       SYS$ASCEFC, 
2       SYS$WAITFR, 
2       SYS$QIOW 
 
! Create the mailbox. 
STATUS = SYS$CREMBX (, 
2                    MBX_CHAN, 
2                    ,,,, 
2                    MBX_NAME) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
 
! Fill MESSAGES array 
                                . 
                                . 
                                . 
! Write the messages. 
DO I = 1, MAX_MESSAGE 
  WRITE_CODE = IO$_WRITEVBLK .OR. IO$M_NOW 
  MBX_MESSAGE = MESSAGES(I) 
  LEN = MESSAGE_LEN(I) 
  STATUS = SYS$QIOW (, 
2                    %VAL(MBX_CHAN),     ! Channel 
2                    %VAL(WRITE_CODE),   ! I/O code 
2                    IOSTAT,             ! Status block 
2                    ,, 
2                    %REF(MBX_MESSAGE),  ! P1 
2                    %VAL(LEN),,,,)      ! P2 
  IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
  IF (.NOT. IOSTAT) CALL LIB$SIGNAL (%VAL(STATUS)) 
END DO 
 
! Write end of file 
WRITE_CODE = IO$_WRITEOF .OR. IO$M_NOW 
STATUS = SYS$QIOW (, 
2                  %VAL(MBX_CHAN),     ! Channel 
2                  %VAL(WRITE_CODE),   ! End of file code 
2                  IOSTAT,             ! Status block 
2                  ,,,,,,,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
IF (.NOT. IOSTAT) CALL LIB$SIGNAL (%VAL(IOSTAT)) 
                                . 
                                . 
                                . 
! Make sure cooperating process can read the information 
! by waiting for it to assign a channel to the mailbox. 
 
STATUS = SYS$ASCEFC (%VAL(64), 
2                    'CLUSTER',,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
STATUS = SYS$WAITFR (%VAL(64)) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
 
END 
 
 
                        RECEIVE.FOR 
INTEGER STATUS 
 
INCLUDE '($IODEF)' 
INCLUDE '($SSDEF)' 
 
! Name and channel number for mailbox 
CHARACTER*(*) MBX_NAME 
PARAMETER (MBX_NAME = 'MAIL_BOX') 
INTEGER*2 MBX_CHAN 
 
! QIO function code 
INTEGER READ_CODE 
 
! Mailbox message 
CHARACTER*80 MBX_MESSAGE 
INTEGER*4    LEN 
 
! Message arrays 
CHARACTER*80 MESSAGES (255) 
INTEGER*4    MESSAGE_LEN (255) 
 
! I/O status block 
INTEGER*2 IOSTAT, 
2         MSG_LEN 
INTEGER READER_PID 
COMMON /IOBLOCK/ IOSTAT, 
2                MSG_LEN, 
2                READER_PID 
! System routines 
INTEGER SYS$ASSIGN, 
2       SYS$ASCEFC, 
2       SYS$SETEF, 
2       SYS$QIOW 
 
! Create the mailbox and let the other process know 
STATUS = SYS$ASSIGN (MBX_NAME, 
2                    MBX_CHAN,,,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
STATUS = SYS$ASCEFC (%VAL(64), 
2                    'CLUSTER',,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
STATUS = SYS$SETEF (%VAL(64)) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
 
! Read first message 
READ_CODE = IO$_READVBLK .OR. IO$M_NOW 
LEN = 80 
STATUS = SYS$QIOW (, 
2                  %VAL(MBX_CHAN),     ! Channel 
2                  %VAL(READ_CODE),    ! Function code 
2                  IOSTAT,             ! Status block 
2                  ,, 
2                  %REF(MBX_MESSAGE),  ! P1 
2                  %VAL(LEN),,,,)      ! P2 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
IF ((.NOT. IOSTAT) .AND. 
2  (IOSTAT .NE. SS$_ENDOFFILE)) THEN 
  CALL LIB$SIGNAL (%VAL(IOSTAT)) 
ELSE IF (IOSTAT .NE. SS$_ENDOFFILE) THEN 
  I = 1 
  MESSAGES(I) = MBX_MESSAGE 
  MESSAGE_LEN(I) = MSG_LEN 
END IF 
 
! Read messages until cooperating process writes end-of-file 
DO WHILE (.NOT. ((IOSTAT .EQ. SS$_ENDOFFILE) .AND. 
2                (READER_PID .NE. 0))) 
 
  STATUS = SYS$QIOW (, 
2                    %VAL(MBX_CHAN),     ! Channel 
2                    %VAL(READ_CODE),    ! Function code 
2                    IOSTAT,             ! Status block 
2                    ,, 
2                    %REF(MBX_MESSAGE),  ! P1 
2                    %VAL(LEN),,,,)      ! P2 
 
   IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) 
   IF ((.NOT. IOSTAT) .AND. 
2     (IOSTAT .NE. SS$_ENDOFFILE)) THEN 
     CALL LIB$SIGNAL (%VAL(IOSTAT)) 
  ELSE IF (IOSTAT .NE. SS$_ENDOFFILE) THEN 
    I = I + 1 
    MESSAGES(I) = MBX_MESSAGE 
    MESSAGE_LEN(I) = MSG_LEN 
   END IF 
 
END DO 
                                . 
                                . 
                                . 


Previous Next Contents Index