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

24.2.2 Chaining from One Program to Another

The LIB$RUN_PROGRAM routine causes the current image to exit at the point of the call and directs the CLI, if present, to start running another program. If LIB$RUN_PROGRAM executes successfully, control passes to the second program; if not, control passes to the CLI. The calling program cannot regain control. This technique is called chaining.

This routine is provided primarily for compatibility with PDP-11 systems, on which chaining is used to extend the address space of a system. Chaining may also be useful in an operating system environment where address space is severely limited and large images are not possible. For example, you can use chaining to perform system generation on a small virtual address space because disk space is lacking.

With LIB$RUN_PROGRAM, the calling program can pass arguments to the next program in the chain only by using the common storage area. One way to do this is to direct the calling program to call LIB$PUT_COMMON to pass the information into the common area. The called program then calls LIB$GET_COMMON to retrieve the data.

In general, this practice is not recommended. There is no convenient way to specify the order and type of arguments passed into the common area, so programs that pass arguments in this way must know about the format of the data before it is passed. Fortran COMMON or BASIC MAP/COMMON areas are global OWN storage. When you use this type of storage, it is very difficult to keep your program modular and AST reentrant. Further, you cannot use LIB$RUN_PROGRAM if a CLI is present, as with image subprocesses and detached subprocesses.

Examples

The following PL/I example illustrates the use of LIB$RUN_PROGRAM. It prompts the user for the name of a program to run and calls the RTL routine to execute the specified program.


CHAIN:  ROUTINE OPTIONS (MAIN) RETURNS (FIXED BINARY (31)); 
DECLARE LIB$RUN_PROGRAM ENTRY (CHARACTER (*))  /* Address of string 
                                               /* descriptor        */ 
        RETURNS (FIXED BINARY (31));           /* Return status     */ 
%INCLUDE $STSDEF;    /* Include definition of return status values  */ 
DECLARE COMMAND CHARACTER (80); 
        GET LIST (COMMAND) OPTIONS (PROMPT('Program to run: ')); 
        STS$VALUE = LIB$RUN_PROGRAM (COMMAND); 
/* 
   If the function call is successful, the program will terminate 
   here.  Otherwise, return the error status to command level. 
*/ 
        RETURN (STS$VALUE); 
END CHAIN; 

The following COBOL program also demonstrates the use of LIB$RUN_PROGRAM. When you compile and link these two programs, the first calls LIB$RUN_PROGRAM, which activates the executable image of the second. This call results in the following screen display:


THIS MESSAGE DISPLAYED BY PROGRAM PROG2 
 
WHICH WAS RUN BY PROGRAM PROG1 
 
USING LIB$RUN_PROGRAM 


 
IDENTIFICATION DIVISION. 
PROGRAM-ID.  PROG1. 
 
ENVIRONMENT DIVISION. 
 
DATA DIVISION. 
 
WORKING-STORAGE SECTION. 
 
01    PROG-NAME    PIC X(9)     VALUE "PROG2.EXE". 
01    STAT         PIC 9(9)     COMP. 
    88  SUCCESSFUL              VALUE 1. 
 
ROUTINE DIVISION. 
 
001-MAIN. 
        CALL "LIB$RUN_PROGRAM" 
            USING BY DESCRIPTOR PROG-NAME 
            GIVING STAT. 
        IF NOT SUCCESSFUL 
            DISPLAY "ATTEMPT TO CHAIN UNSUCCESSFUL" 
            STOP RUN. 
 
IDENTIFICATION DIVISION. 
 
PROGRAM-ID.  PROG2. 
 
ENVIRONMENT DIVISION. 
 
DATA DIVISION. 
 
ROUTINE DIVISION. 
 
 
001-MAIN. 
        DISPLAY " ". 
        DISPLAY "THIS MESSAGE DISPLAYED BY PROGRAM PROG2". 
        DISPLAY " ". 
        DISPLAY "WHICH WAS RUN BY PROGRAM PROG1". 
        DISPLAY " ". 
        DISPLAY "USING LIB$RUN_PROGRAM". 
        STOP RUN. 
 

24.2.3 Executing a CLI Command

The LIB$DO_COMMAND routine stops program execution and directs the CLI to execute a command. The routine's argument is the text of the command line that you want to execute.

This routine is especially useful when you want to execute a CLI command after your program has finished executing. For example, you could set up a series of conditions, each associated with a different command. You could also use the routine to execute a SUBMIT or PRINT command to handle a file that your program creates.

Because of the following restrictions on LIB$DO_COMMAND, you should be careful when you incorporate it in your program:

You can also use LIB$DO_COMMAND to execute a DCL command file. To do this, include the at sign (@) along with a command file specification as the input argument to the routine.

Some DCL CLI$ routines perform the functions of LIB$DO_COMMAND. See the HP OpenVMS DCL Dictionary for more information.

Example

The following PL/I example prompts the user for a DCL command to execute after the program exits:


EXECUTE: ROUTINE OPTIONS (MAIN) RETURNS (FIXED BINARY (31)); 
 
DECLARE LIB$DO_COMMAND ENTRY (CHARACTER (*))  /* Pass DCL command  */ 
                                              /*  by descriptor    */ 
         RETURNS (FIXED BINARY (31));         /* Return status     */ 
%INCLUDE $STSDEF;    /* Include definition of return status values */ 
 
DECLARE COMMAND CHARACTER (80); 
 
        GET LIST (COMMAND) OPTIONS (PROMPT('DCL command to execute: ')); 
        STS$VALUE = LIB$DO_COMMAND (COMMAND); 
/* 
   If the call to LIB$DO_COMMAND is successful, the program will terminate 
   here.  Otherwise, it will return the error status to command level. 
*/ 
 
        RETURN (STS$VALUE); 
 
END EXECUTE; 

This example displays the following prompt:


DCL command to execute: 

What you type after this prompt determines the action of LIB$DO_COMMAND. LIB$DO_COMMAND executes any command that is entered as a valid string according to the syntax of PL/I. If the command you enter is incomplete, you are prompted for the rest of the command. For example, if you enter the SHOW command, you receive the following prompt:


$_Show what?:

24.2.4 Using Symbols and Logical Names

The RTL provides a number of routines that give you access to the CLI callback facility. These routines allow a program to "call back" to the CLI to perform functions that normally are performed by CLI commands. These routines perform the following functions:
LIB$GET_SYMBOL Returns the value of a CLI symbol as a string.

Optionally, this routine also returns the length of the returned value and a value indicating whether the symbol was found in the local or global symbol table. This routine executes only when the current CLI is DCL.

LIB$SET_SYMBOL Causes the CLI to define or redefine a CLI symbol.

The optional argument specifies whether the symbol is to be defined in the local or global symbol table; the default is local. This routine executes only when the current CLI is DCL.

LIB$DELETE_SYMBOL Causes the CLI to delete a symbol.

An optional argument specifies the local or global symbol table. If the argument is omitted, the symbol is deleted from the local symbol table. This routine executes only when the current CLI is DCL.

LIB$SET_LOGICAL Defines or redefines a supervisor-mode process logical name.

Supervisor-mode logical names are not deleted when an image exits. This routine is equivalent to the DCL command DEFINE. LIB$SET_LOGICAL allows the calling program to define a supervisor-mode process logical name without itself executing in supervisor mode.

LIB$DELETE_LOGICAL Deletes a supervisor-mode process logical name.

This routine is equivalent to the DCL command DEASSIGN. LIB$DELETE_LOGICAL does not require the calling program to be executing in supervisor mode to delete a supervisor-mode logical name.

For information about using logical names, see Chapter 34.

24.2.5 Disabling and Enabling Control Characters

Two run-time library routines, LIB$ENABLE_CTRL and LIB$DISABLE_CTRL, allow you to call the CLI to enable or disable control characters. These routines take a longword bit mask argument that specifies the control characters to be disabled or enabled. Acceptable values for this argument are LIB$M_CLI_CTRLY and LIB$M_CLI_CTRLT.
LIB$DISABLE_CTRL Disables CLI interception of control characters.

This routine performs the same function as the DCL command SET NOCONTROL= n, where n is T or Y.

It prevents the currently active CLI from intercepting the control character specified during an interactive session.

For example, you might use LIB$DISABLE_CTRL to disable CLI interception of Ctrl/Y. Normally, Ctrl/Y interrupts the current command, command procedure, or image. If LIB$DISABLE_CTRL is called with LIB$M_CLI_CTRLY specified as the control character to be disabled, Ctrl/Y is treated like Ctrl/U followed by a carriage return.

LIB$ENABLE_CTRL Enables CLI interception of control characters.

This routine performs the same function as the DCL command SET CONTROL= n, where n is T or Y.

LIB$ENABLE_CTRL restores the normal operation of Ctrl/Y or Ctrl/T.

24.2.6 Creating and Connecting to a Subprocess

You can use LIB$SPAWN and LIB$ATTACH together to spawn a subprocess and attach the terminal to that subprocess. These routines execute correctly only if the current CLI is DCL. For more information on the SPAWN and ATTACH commands, see the HP OpenVMS DCL Dictionary. For more information on creating processes, see Chapter 2.
LIB$SPAWN Spawns a subprocess.

This routine is equivalent to the DCL command SPAWN. It requests the CLI to spawn a subprocess for executing CLI commands.

LIB$ATTACH Attaches the terminal to another process.

This routine is equivalent to the DCL command ATTACH. It requests the CLI to detach the terminal from the current process and reattach it to a different process.

24.3 Access to VAX Machine Instructions

The VAX instruction set was designed for efficient use by high-level languages and, therefore, contains many functions that are directly useful in your programs. However, some of these functions cannot be used directly by high-level languages.

The run-time library provides routines that allow your high-level language program to use most VAX machine instructions that are otherwise unavailable. On Alpha machines, these routines execute a series of Alpha instructions that emulate the operation of the VAX instructions. In most cases, these routines simply execute the instruction, using the arguments you provide. Some routines that accept string arguments, however, provide some additional functions that make them easier to use.

These routines fall into the following categories:

The VAX Architecture Reference Manual describes the VAX instruction set in detail.

24.3.1 Variable-Length Bit Field Instruction Routines

The variable-length bit field is a VAX data type used to store small integers packed together in a larger data structure. It is often used to store single flag bits.

The run-time library contains five routines for performing operations on variable-length bit fields. These routines give higher-level languages that do not have the inherent ability to manipulate bit fields direct access to the bit field instructions in the VAX instruction set. Further, if a program calls a routine written in a different language to perform some function that also involves bit manipulation, the called routine can include a call to the run-time library to perform the bit manipulation.

Table 24-3 lists the run-time library variable-length bit field routines.

Table 24-3 Variable-Length Bit Field Routines
Entry Point Function
LIB$EXTV Extracts a field from the specified variable-length bit field and returns it in sign-extended longword form.
LIB$EXTZV Extracts a field from the specified variable-length bit field and returns it in zero-extended longword form.
LIB$FFC Searches the specified field for the first clear bit. If it finds one, it returns SS$_NORMAL and the bit position ( find-pos argument) of the clear bit. If not, it returns a failure status and sets the find-pos argument to the start position plus the size.
LIB$FFS Searches the specified field for the first set bit. If it finds one, it returns SS$_NORMAL and the bit position ( find-pos argument) of the set bit. If not, it returns a failure status and sets the find-pos argument to the start position plus the size.
LIB$INSV Replaces the specified field with bits 0 through [ size -1] of the source ( src argument). If the size argument is 0, nothing is inserted.

Three scalar attributes define a variable bit field:

Figure 24-1 shows the format of a variable-length bit field. The shaded area indicates the field.

Figure 24-1 Format of a Variable-Length Bit Field


Bit fields are zero-origin, which means that the routine regards the first bit in the field as being the zero position. For more detailed information about VAX bit numbering and data formats, see the VAX Architecture Reference Manual.

The attributes of the bit field are passed to an RTL routine in the form of three arguments in the following order:

pos

Operating system usage: longword_signed
type: longword integer (signed)
access: read only
mechanism: by reference
Bit position relative to the base address. The pos argument is the address of a signed longword integer that contains this bit position.

size

Operating system usage: byte_unsigned
type: byte (unsigned)
access: read only
mechanism: by reference
Size of the bit field. The size argument is the address of an unsigned byte that contains this size.

base

Operating system usage: longword_unsigned
type: longword (unsigned)
access: read only
mechanism: by reference
Base address. The base argument contains the address of the base address.

Example

The following BASIC example illustrates three RTL routines. It opens the terminal as a file and specifies HEX> as the prompt. This prompt allows you to obtain input from the terminal without the question mark that VAX BASIC normally adds to the prompt in an INPUT statement. The program calls OTS$CVT_TZ_L to convert the character string input to a longword. It then calls LIB$EXTZV once for each position in the longword to extract the bit in that position. Because LIB$EXTVZ is called with a function reference within the PRINT statement, the bits are displayed.


10      EXTERNAL LONG FUNCTION 
                OTS$CVT_TZ_L,           ! Convert hex text to LONG 
                LIB$EXTZV               ! Extract zero-ended bit field 
 
20      OPEN "TT:" FOR INPUT AS FILE #1%     ! Open terminal as a file 
        INPUT #1%, "HEX>"; HEXIN$            ! Prompt for input 
        STAT%=OTS$CVT_TZ_L(HEXIN$, BINARY%)   ! Convert to longword 
        IF (STAT% AND 1%) <> 1%               ! Failed? 
        THEN 
                PRINT "Conversion failed, decimal status ";STAT% 
                GO TO 20                      ! Try again 
        ELSE 
                PRINT HEXIN$, 
                PRINT STR$(LIB$EXTZV(N%, 1%, BINARY%)); 
                        FOR N%=31% to 0% STEP -1% 

24.3.2 Integer and Floating-Point Routines

Integer and floating-point routines give a high-level language program access to the corresponding machine instructions. For a complete description of these instructions, see the VAX Architecture Reference Manual. Table 24-4 lists the integer and floating-point routines once up front.

Table 24-4 Integer and Floating-Point Routines
Entry Point Function
LIB$EMUL Multiplies integers with extended precision
LIB$EDIV Divides integers with extended precision

24.3.3 Queue Access Routines

A queue is a doubly linked list. A run-time library routine specifies a queue entry by its address. Two longwords, a forward link and a backward link, define the location of the entry in relation to the preceding and succeeding entries. A self-relative queue is a queue in which the links between entries are displacements; the two longwords represent the displacements of the current entry's predecessor and successor. The VAX instructions INSQHI, INSQTI, REMQHI, and REMQTI allow you to insert and remove an entry at the head or tail of a self-relative queue. Each queue instruction has a corresponding RTL routine.

The self-relative queue instructions are interlocked and cannot be interrupted, so that other processes cannot insert or remove queue entries while the current program is doing so. Because the operation requires changing two pointers at the same time, a high-level language cannot perform this operation without calling the RTL queue access routines.

When you use these routines, cooperating processes can communicate without further synchronization and without danger of being interrupted, either on a single processor or in a multiprocessor environment. The queue access routines are also useful in an AST environment; they allow you to add or remove an entry from a queue without being interrupted by an asynchronous system trap.

The remove queue instructions (REMQHI or REMQTI) return the address of the removed entry. Some languages, such as BASIC, COBOL, and Fortran, do not provide a mechanism for accessing an address returned from a routine. Further, BASIC and COBOL do not allow routines to be arguments.

Table 24-5 lists the queue access routines.

Table 24-5 Queue Access Routines
Entry Point Function
LIB$INSQHI Inserts queue entry at head
LIB$INSQTI Inserts queue entry at tail
LIB$REMQHI Removes queue entry at head
LIB$REMQTI Removes queue entry at tail

Examples

LIB$INSQHI

In BASIC and Fortran, queues can be quadword aligned in a named COMMON block by using a linker option file to specify alignment of program sections. The LIB$GET_VM routine returns memory that is quadword aligned. Therefore, you should use LIB$GET_VM to allocate the virtual memory for a queue. For instance, to create a COMMON block called QUEUES, use the LINK command with the FILE/OPTIONS qualifier, where FILE.OPT is a linker option file containing the line:


PSECT = QUEUES, QUAD 

A Fortran application using processor-shared memory follows:


INTEGER*4 FUNCTION INSERT_Q (QENTRY) 
COMMON/QUEUES/QHEADER 
INTEGER*4 QENTRY(10), QHEADER(2) 
INSERT_Q = LIB$INSQHI (QENTRY, QHEADER) 
RETURN 
END 

A BASIC application using processor-shared memory follows:


     COM (QUEUES) QENTRY%(9), QHEADER%(1) 
     EXTERNAL INTEGER FUNCTION LIB$INSQHI 
     IF LIB$INSQHI (QENTRY%() BY REF, QHEADER%() BY REF) AND 1% 
          THEN GOTO 1000 
             . 
             . 
             . 
1000 REM  INSERTED OK 

LIB$REMQHI

In Fortran, the address of the removed queue entry can be passed to another routine as an array using the %VAL built-in function.

In the following example, queue entries are 10 longwords, including the two longword pointers at the beginning of each entry:


COMMON/QUEUES/QHEADER 
INTEGER*4 QHEADER(2), ISTAT 
ISTAT = LIB$REMQHI (QHEADER, ADDR) 
IF (ISTAT) THEN 
        CALL PROC (%VAL (ADDR)) ! Process removed entry 
        GO TO ... 
ELSE IF (ISTAT .EQ. %LOC(LIB$_QUEWASEMP)) THEN 
                GO TO ...       ! Queue was empty 
                ELSE IF 
                        ...     ! Secondary interlock failed 
END IF 
   .
   .
   .
END 
SUBROUTINE PROC (QENTRY) 
INTEGER*4 QENTRY(10) 
   .
   .
   .
RETURN 
END 


Previous Next Contents Index