|
OpenVMS Programming Concepts Manual
32.10 Using Logical Names and Logical Name Table System Services in Programs
The following sections describe by programming examples how to use
SYS$CRELNM, SYS$CRELNT, SYS$DELLNM, and SYS$TRNLNM system services.
32.10.1 Using SYS$CRELNM to Create a Logical Name
To perform an assignment in a program, you must provide
character-string descriptors for the name strings, select the table to
contain the logical name, and use the SYS$CRELNM system service as
shown in the following example. In either case, the result is the same:
the logical name DISK is equated to the physical device name DUA2 in
table LNM$JOB.
#include <stdio.h>
#include <lnmdef.h>
#include <descrip.h>
#include <string.h>
#include <ssdef.h>
/* Define an item descriptor */
struct itm {
unsigned short buflen, item_code;
void *bufaddr;
void *retlenaddr;
};
/* Declare an item list */
struct {
struct itm items2];
unsigned int terminator;
}itm_lst;
main() {
static char eqvnam[] = "DUA2:";
unsigned int status, lnmattr;
$DESCRIPTOR(logdesc,"DISK");
$DESCRIPTOR(tabdesc,"LNM$JOB");
lnmattr = LNM$M_TERMINAL;
/* Initialize the item list */
itm_lst.items[0].buflen = 4;
itm_lst.items[0].item_code = LNM$_ATTRIBUTES;
itm_lst.items[0].bufaddr = &lnmattr;
itm_lst.items[0].retlenaddr = 0;
itm_lst.items[1].buflen = strlen(eqvnam);
itm_lst.items[1].item_code = LNM$_STRING;
itm_lst.items[1].bufaddr = eqvnam;
itm_lst.items[1].retlenaddr = 0;
itm_lst.terminator = 0;
/* Create the logical name */
status = SYS$CRELNM(0, /* attr - attributes */
&tabdesc, /* tabnam - logical table name */
&logdesc, /* lognam - logical name */
0, /* acmode - access mode 0 means use the */
/* access mode of the caller=user mode */
&itm_lst); /* itmlst - item list */
if((status & 1) != 1)
LIB$SIGNAL(status);
}
|
Note that the translation attribute is specified as terminal. This
attribute indicates that iterative translation of the logical name DISK
ends when the equivalence string DUA2 is returned. In addition, because
the acmode argument was not specified, the access mode
of the logical name DISK is the access mode from which the image
requested the SYS$CRELNM service.
The following example shows how a process-private logical name with
multiple equivalence names can be created in user mode by an image:
#include <stdio.h>
#include <lnmdef.h>
#include <ssdef.h>
#include <descrip.h>
/* Define an item descriptor */
struct lst {
unsigned short buflen, item_code;
void *bufaddr;
void *retlenaddr;
};
/* Declare an item list */
struct {
struct lst items[2];
unsigned int terminator;
}item_lst;
/* Equivalence name strings */
static char eqvnam1[] = "XYZ";
static char eqvnam2[] = "DEF";
main() {
unsigned int status;
$DESCRIPTOR(logdesc,"ABC");
$DESCRIPTOR(tabdesc,"LNM$PROCESS");
item_lst.items[0].buflen = strlen(eqvnam1);
item_lst.items[0].item_code = LNM$_STRING;
item_lst.items[0].bufaddr = eqvnam1;
item_lst.items[0].retlenaddr = 0;
item_lst.items[1].buflen = strlen(eqvnam2);
item_lst.items[1].item_code = LNM$_STRING;
item_lst.items[1].bufaddr = eqvnam2;
item_lst.items[1].retlenaddr = 0;
item_lst.terminator = 0;
/* Create a logical name */
status = SYS$CRELNM( 0, /* attr - attributes of logical name */
&tabdesc, /* tabnam - name of logical name table */
&logdesc, /* lognam - name of logical name */
0, /* acmode - access mode 0 means use the */
/* access mode of the caller=user mode */
&item_lst); /* itm_lst - item list */
if((status & 1) != 1)
LIB$SIGNAL(status);
}
|
In the preceding example, logical name ABC was created and represents a
search list with two equivalence strings, XYZ and DEF. Each time the
LNM$_STRING item code of the itmlst argument is
invoked, an index value is assigned to the next equivalence string. The
newly created logical name and its equivalence string are contained in
the process logical name table LNM$PROCESS_TABLE.
The following example illustrates the creation of a logical name in
supervisor mode through DCL:
$ DEFINE/SUPERVISOR_MODE/TABLE=LNM$PROCESS ABC XYZ,DEF
|
In the preceeding example, supervisor mode and /TABLE=LNM$PROCESS are
the defaults (default mode and default table) for the DEFINE command.
32.10.2 Using SYS$CRELNT to Create Logical Name Tables
The Create Logical Name Table (SYS$CRELNT) system service creates
logical name tables. Logical name tables can be created in any access
mode depending on the privileges of the calling process. A
user-specified logical name that identifies a process-private created
logical name table is stored in the process directory table
LNM$PROCESS_DIRECTORY. The name of a shareable table is stored in the
system directory table LNM$SYSTEM_DIRECTORY.
The following example illustrates a call to the SYS$CRELNT system
service:
#include <stdio.h>
#include <ssdef.h>
#include <lnmdef.h>
#include <descrip.h>
main() {
unsigned int status, tab_attr=LNM$M_CONFINE, tab_quota=5000;
$DESCRIPTOR(tabdesc,"LOG_TABLE");
$DESCRIPTOR(pardesc,"LNM$PROCESS_TABLE");
/* Create the logical name table */
status = SYS$CRELNT(&tab_attr, /* attr - table attributes */
0, /* resnam - logical table name */
0, /* reslen - length of table name */
&tab_quota, /* quota - max no. of bytes allocated */
/* for names in this table */
0, /* promsk - protection mask */
&tabdesc, /* tabnam - name of new table */
&pardesc, /* partab - name of parent table */
0); /* acmode - access mode */
if((status & 1) != 1) {
LIB$SIGNAL(status);
}
|
In this example, a user-defined table LOG_TABLE is created with an
explicit quota of 5000 bytes. The name of the newly created table is an
entry in the process-private directory LNM$PROCESS_DIRECTORY. The quota
of 5000 bytes is deducted from the parent table LNM$PROCESS_TABLE.
Because the CONFINE attribute is associated with the logical name
table, the table cannot be copied from the process to its spawned
processes.
32.10.3 Using SYS$DELLNM to Delete Logical Names
The Delete Logical Name (SYS$DELLNM) system service deletes entries
from a logical name table. When you write a call to the SYS$DELLNM
system service, you can specify a single logical name to delete, or you
can specify that you want to delete all logical names from a particular
table. For example, the following call deletes the process logical name
TERMINAL from the job logical name table:
#include <stdio.h>
#include <lnmdef.h>
#include <ssdef.h>
#include <descrip.h>
main() {
unsigned int status;
$DESCRIPTOR(logdesc,"DISK");
$DESCRIPTOR(tabdesc,"LNM$JOB");
/* Delete the logical name */
status = SYS$DELLNM(&tabdesc, /* tabnam - logical table name */
&logdesc, /* lognam - logical name */
0); /* acmode - access mode */
if ((status & 1) != 1)
LIB$SIGNAL(status);
}
|
For information about access modes and the deletion of logical names,
see Chapter 20 and Appendix E.
32.10.4 Using SYS$TRNLNM to Translate Logical Names
The Translate Logical Name (SYS$TRNLNM) system service translates a
logical name to its equivalence string. In addition, SYS$TRNLNM returns
information about the logical name and equivalence string.
The system service call to SYS$TRNLNM specifies the tables to search
for the logical name. The tabnam argument can be
either the name of a logical name table or a logical name that
translates to a list of one or more logical name tables.
Because logical names can have many equivalence strings, you can
specify which equivalence string you want to receive.
A number of system services that require a device name accept a logical
name and translate the logical name iteratively until a physical device
name is found (or until the system default number of logical name
translations has been performed, typically 10). These services
implicitly use the logical name table name LNM$FILE_DEV. For more
information about LNM$FILE_DEV, refer to Section 32.1.4.
The following system services perform iterative logical name
translation automatically:
- Allocate Device (SYS$ALLOC)
- Assign I/O Channel (SYS$ASSIGN)
- Broadcast (SYS$BRDCST)
- Create Mailbox (SYS$CREMBX)
- Deallocate Device (SYS$DALLOC)
- Dismount Volume (SYS$DISMOU)
- Get Device/Volume Information (SYS$GETDVI)
- Mount Volume (SYS$MOUNT)
In many cases, however, a program must perform the logical name
translation to obtain the equivalence name for a logical name outside
the context of a device name or file specification. In that case, you
must supply the name of the table or tables to be searched. The
SYS$TRNLNM system service searches the user-specified logical name
tables for a specified logical name and returns the equivalence name.
In addition, SYS$TRNLNM returns attributes that are specified
optionally for the logical name and equivalence string.
The following example shows a call to the SYS$TRNLNM system service to
translate the logical name ABC:
#include <stdio.h>
#include <lnmdef.h>
#include <descrip.h>
#include <ssdef.h>
/* Define an item descriptor */
struct itm {
unsigned short buflen, item_code;
void *bufaddr;
void *retlenaddr;
};
/* Declare an item list */
struct {
struct itm items[2];
unsigned int terminator;
}trnlst;
main() {
char eqvbuf1[LNM$C_NAMLENGTH], eqvbuf2[LNM$C_NAMLENGTH];
unsigned int status, trnattr=LNM$M_CASE_BLIND;
unsigned int eqvdesc1, eqvdesc2;
$DESCRIPTOR(logdesc,"ABC");
$DESCRIPTOR(tabdesc,"LNM$FILE_DEV");
/* Assign values to the item list */
trnlst.items[0].buflen = LNM$C_NAMLENGTH;
trnlst.items[0].item_code = LNM$_STRING;
trnlst.items[0].bufaddr = eqvbuf1;
trnlst.items[0].retlenaddr = &eqvdesc1;
trnlst.items[1].buflen = LNM$C_NAMLENGTH;
trnlst.items[1].item_code = LNM$_STRING;
trnlst.items[1].bufaddr = eqvbuf2;
trnlst.items[1].retlenaddr = &eqvdesc2;
trnlst.terminator = 0;
/* Translate the logical name */
status = SYS$TRNLNM(&trnattr, /* attr - attributes */
&tabdesc, /* tabnam - table name */
&logdesc, /* lognam - logical name */
0, /* acmode - access mode */
&trnlst); /* itmlst - item list */
if((status & 1) != 1)
LIB$SIGNAL(status);
}
|
This call to the SYS$TRNLNM system service results in the translation
of the logical name ABC. In addition, LNM$FILE_DEV is specified in the
tabnam argument as the search list that SYS$TRNLNM is
to use to find the logical name ABC. The logical name ABC was assigned
two equivalence strings. The LNM$_STRING item code in the
itmlst argument directs SYS$TRNLNM to look for an
equivalence string at the current index value. Note that the
LNM$_STRING item code is invoked twice. The equivalence strings are
placed in the two output buffers, EQVBUF1 and EQVBUF2, described by
TRNLIST.
The attribute LNM$M_CASE_BLIND governs the translation process. The
SYS$TRNLNM system service searches for the equivalence strings without
regard to uppercase or lowercase letters. The SYS$TRNLNM system service
matches any of the following character strings: ABC, aBC, AbC, abc, and
so forth.
The output equivalence name string length is written into the first
word of the character string descriptor. This descriptor can then be
used as input to another system service.
32.10.5 Using SYS$CRELNM, SYS$TRNLNM, and SYS$DELLNM in a Program Example
In the following example, the Fortran program CALC.FOR creates a
spawned subprocess to perform an iterative calculation. The logical
name REP_NUMBER specifies the number of times that REPEAT should
perform the calculation. Because the two processes are part of the same
job, REP_NUMBER is placed in the job logical name table LNM$JOB. (Note
that logical name table names are case sensitive. Specifically, LNM$JOB
is a system-defined logical name that refers to the job logical name
table; lnm$job is not.)
PROGRAM CALC
! Status variable and system routines
INCLUDE '($LNMDEF)'
INCLUDE '($SYSSRVNAM)'
INTEGER*4 STATUS
INTEGER*2 NAME_LEN,
2 NAME_CODE
INTEGER*4 NAME_ADDR,
2 RET_ADDR /0/,
2 END_LIST /0/
COMMON /LIST/ NAME_LEN,
2 NAME_CODE,
2 NAME_ADDR,
2 RET_ADDR,
2 END_LIST
CHARACTER*3 REPETITIONS_STR
INTEGER REPETITIONS
EXTERNAL CLI$M_NOLOGNAM,
2 CLI$M_NOCLISYM,
2 CLI$M_NOKEYPAD,
2 CLI$M_NOWAIT
NAME_LEN = 3
NAME_CODE = (LNM$_STRING)
NAME_ADDR = %LOC(REPETITIONS_STR)
STATUS = SYS$CRELNM (,'LNM$JOB','REP_NUMBER',,NAME_LEN)
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
MASK = %LOC (CLI$M_NOLOGNAM) .OR.
2 %LOC (CLI$M_NOCLISYM) .OR.
2 %LOC (CLI$M_NOKEYPAD) .OR.
2 %LOC (CLI$M_NOWAIT)
STATUS = LIB$GET_EF (FLAG)
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
STATUS = LIB$SPAWN ('RUN REPEAT',,,MASK,,,,FLAG)
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
END
PROGRAM REPEAT
INTEGER STATUS,
2 SYS$TRNLNM,SYS$DELLNM
INTEGER*4 REITERATE,
2 REPEAT_STR_LEN
CHARACTER*3 REPEAT_STR
! Item list for SYS$TRNLNM
INTEGER*2 NAME_LEN,
2 NAME_CODE
INTEGER*4 NAME_ADDR,
2 RET_ADDR,
2 END_LIST /0/
COMMON /LIST/ NAME_LEN,
2 NAME_CODE,
2 NAME_ADDR,
2 RET_ADDR,
2 END_LIST
NAME_LEN = 3
NAME_CODE = (LNM$_STRING)
NAME_ADDR = %LOC(REPEAT_STR)
RET_ADDR = %LOC(REPEAT_STR_LEN)
STATUS = SYS$TRNLNM (,
2 'LNM$JOB', ! Logical name table
2 'REP_NUMBER',, ! Logical name
2 NAME_LEN) ! List requesting equivalence string
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
READ (UNIT = REPEAT_STR,
2 FMT = '(I3)') REITERATE
DO I = 1, REITERATE
END DO
STATUS = SYS$DELLNM ('LNM$JOB', ! Logical name table
2 'REP_NUMBER',) ! Logical name
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
END
|
Chapter 33 Image Initialization
This chapter describes the system declaration mechanism, including
LIB$INITIALIZE, which performs calls to any initialization routine
declared for the image by the user. However, use of LIB$INITIALIZE is
discouraged and should be used only when no other method is suitable.
This chapter contains the following sections:
Section 33.1 describes the steps to perform image initialization.
Section 33.2 describes the argument list that is passed from the
command interpreter, the debugger, or LIB$INITIALIZE to the main
program.
Section 33.3 describes how a library or user program can declare an
initialization routine.
Section 33.4 describes how the LIB$INITIALIZE dispatcher calls the
initialization routine in a list.
Section 33.5 describes the options available to an initialization
routine.
Section 33.6 illustrates with a code example several functions of an
initialization routine on both VAX and Alpha systems.
33.1 Initializing an Image
In most cases, both user and library routines are self-initializing.
This means that they can process information with no special action
required by the calling program. Initialization is automatic in two
situations:
- When the routine's statically allocated data storage is initialized
at compile or link time
- When a statically allocated flag is tested and set on each call so
that initialization occurs only on the first call
Any special initialization, such as a call to other routines or to
system services, can be performed on the first call before the main
program is initialized. For example, you can establish a new
environment to alter the way errors are handled or the way messages are
printed.
Such special initialization is required only rarely; however, when it
is required, the caller of the routine does not need to make an
explicit initialization call. The run-time library provides a system
declaration mechanism that performs all such initialization calls
before the main program is called. Thus, special initialization is
invisible to later callers of the routine.
On VAX systems, before the main program or main routine is called, a
number of system initialization routines are called as specified by a
1-, 2-, or 3-longword initialization list set up by the linker.
On Alpha systems, before the main program or main routine is called, a
number of system initialization routines are called as specified by a
1-, 2-, or 3-quadword initialization list set up by the linker.
On VAX systems, the initialization list consists of the following (in
order):
- The addresses of the debugger (if present)
- The LIB$INITIALIZE routine (if present)
- The entry point of the main program or main routine
On Alpha systems, the initialization list consists of the following (in
order):
- The procedure value addresses of the debugger (if present)
- The LIB$INITIALIZE routine (if present)
- The entry point of the main program or main routine
The following initialization steps take place:
- The image activator maps the user program into the address space of
the process and sets up useful information, such as the program name.
Then it starts the command language interpreter (CLI).
- The CLI sets up an argument list and calls the next routine in the
initialization list (debugger, LIB$INITIALIZE, main program, or main
routine).
- On VAX systems, the debugger, if present, initializes itself and
calls the next routine in the initialization list (LIB$INITIALIZE, main
program, or main routine).
On Alpha systems, the CLI calls the
debugger, if present, to set the initial breakpoints. Then the CLI
calls the next entry in the vector.
- The LIB$INITIALIZE library routine, if present, calls each library
and user initialization routine declared using the system
LIB$INITIALIZE mechanism. Then it calls the main program or main
routine.
- The main program or main routine executes and, at the user's
discretion, accesses its argument list to scan the command or to obtain
information about the image. The main program or main routine can then
call other routines.
- Eventually, the main program or main routine terminates by
executing a return instruction (RET) with R0 set to a standard
completion code to indicate success or failure, where bit <0>
equals 1 (success) or 0 (failure).
- The completion code is returned to LIB$INITIALIZE (if present), the
debugger (if present), and, finally, to the CLI, which issues a
SYS$EXIT system service with the completion status as an argument. Any
declared exit handlers are called at this point.
Note
Main programs should not call the SYS$EXIT system service directly. If
they do, other programs cannot call them as routines.
|
Figure 33-1 and Figure 33-2 illustrate the sequence of calls and
returns in a typical image initialization. Each box is a routine
activation as represented on the image stack. The top of the stack is
at the top of the figure. Each upward arrow represents the result of a
call instruction that creates a routine activation on the stack to
which control is being transferred. Each downward arrow represents the
result of a RET (return) instruction. A RET instruction removes the
routine activation from the stack and causes control to be transferred
downward to the next box.
A user program can alter the image initialization sequence by making a
program section (PSECT) contribution to PSECT LIB$INITIALIZE and by
declaring EXTERNAL LIB$INITIALIZE. This adds the optional
initialization steps shown in Figure 33-1 and Figure 33-2 labeled
"Program Section Contribution to LIB$INITIALIZE." (A program
section is a portion of a program with a given protection and set of
storage management attributes. Program sections that have the same
attributes are gathered together by the linker to form an image
section.) If the initialization routine also performs a coroutine call
back to LIB$INITIALIZE, the optional steps labeled "Coroutine Call
Back to LIB$INITIALIZE" in Figure 33-1 and Figure 33-2 are
added to the image initialization sequence.
On VAX systems, Figure 33-1 shows the call instruction calling the
debugger, if present, and the debugger then directly calling
LIB$INITIALIZE and the main program.
Figure 33-1 Sequence of Events During Image Initialization on
VAX Systems
On Alpha systems, Figure 33-2 shows the call instruction calling the
debugger, if present, to set a breakpoint at the main program's entry
point.
Figure 33-2 Sequence of Events During Image Initialization on
Alpha Systems
33.2 Initializing an Argument List
The following argument list is passed from the CLI, the debugger, or
LIB$INITIALIZE to the main program. This argument list is the same for
each routine activation.
(start ,cli-coroutine [,image-info])
|
The start argument is the address of the entry in the
initialization vector that is used to perform the call.
The cli-coroutine argument is the address of a CLI
coroutine to obtain command arguments. For more information, see the
OpenVMS Utility Routines Manual.
The image-info argument is useful image information,
such as the program name.
The debugger or LIB$INITIALIZE, or both, can call the next routine in
the initialization chain using the following coding sequence:
.
.
.
ADDL #4, 4(AP) ; Step to next initialization list entry
MOVL @4(AP), R0 ; R0 = next address to call
CALLG (AP), (R0) ; Call next initialization routine
.
.
.
|
This coding sequence modifies the contents of an argument list entry.
Thus, the sequence does not follow the OpenVMS calling standard.
However, the argument list can be expanded in the future without
requiring any change either to the debugger or to LIB$INITIALIZE.
|