Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

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

1. 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).
2. The CLI sets up an argument list and calls the next routine in the initialization list (debugger, LIB$INITIALIZE, main program, or main routine).
3. 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.
4. 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.
5. 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.
6. 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).
7. 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.

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_085.HTML