[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

OpenVMS Record Management Services Reference Manual


Previous Contents Index

B.3.4 Processing File Specifications

The file name and file specification services, Parse and Search, are used for relatively complex operations such as processing wildcard characters.

Before you can perform operations on a file, you must establish a path to the file. You do this by specifying the file specification string address and size (FAB$L_FNA and FAB$B_FNS) fields (and possibly the default file specification string address and size fields) of the FAB to describe an ASCII string within the program. In this ASCII string, you can have a concatenation of the network node name; a logical or device name; the directory name; and the file name, type, and version number.

If a logical name is used, RMS translates the logical name into its equivalent file specification before it applies defaults to any missing components of the file specification. If the logical name is a search list logical name, RMS translates each element of the search list into an equivalent file specification before it applies defaults to that element. When using the Search service, a file specification that may contain a search list logical name must be handled as if wildcard characters were present in the file specification.

The Parse service is required prior to the Search service in order to examine the file specification for wildcard characters or a search list. If the file is found, the Parse service sets a NAM or NAML block bit that RMS uses internally and sets an appropriate value in the wildcard character context that is used as input by the Search service. The Parse service is invoked once, then the Search service is repetitively invoked as many times as there are files that match the original file specification.

If a wildcard is present, the Search service attempts to find all files that match the file specification. If an asterisk (*) is in the directory field, all directories on the specified device are searched for files that match the remaining file specification components. As with the use of wildcard characters, when a search list logical name is present, a single Parse service and multiple Search services return all files that match the file specification. With search lists, however, all list elements are searched for matching file specifications in the specified order without regard to uniqueness between the resulting file specifications. Search lists can be used in place of (or in addition to) wildcard characters to specify a more efficient search order, which can mean different combinations for the device, directory, file name, file type, and version number parts of a file specification. Search lists can also contain wildcard characters, if needed.

In summary, the Parse and Search services use a search list logical name very much like a wildcard. Unlike the case of opening a file, in which the first instance where the file is found successfully ends the use of additional search list file specifications, the Parse and Search services use all search list file specifications.

Example B-4 shows how the $PARSE and $SEARCH macros can be used in wildcard processing.

Example B-4 Wildcard Processing Using Parse and Search Services

        .TITLE  WILD
;
;  Program to accept wildcard characters in input (partial) file
;  specification and display full file specification.
;
        $NAMDEF                         ; NAM block definitions

        .PSECT  DATA,NOEXE,WRT
NAM_BLK:
        $NAM    RSA=RES_STR,-           ; Result buffer address
                RSS=NAM$C_MAXRSS,-      ; Result buffer size
                ESA=EXP_STR,-           ; Expanded buffer address
                ESS=NAM$C_MAXRSS        ; Expanded buffer size
FAB_BLK:
        $FAB    FOP=NAM,-               ; Use NAM block option
                NAM=NAM_BLK,-           ; Pointer to NAM block
                FNA=INP_STR             ; Addr of file name string

EXP_STR:                                ; Expanded string buffer
        .BLKB   NAM$C_MAXRSS
RES_STR:                                ; Resultant string buffer
        .BLKB   NAM$C_MAXRSS
RES_STR_D:                              ; Resultant string descriptor
        .BLKL   1
        .LONG   RES_STR
INP_STR:                                ; Input string buffer
        .BLKB   NAM$C_MAXRSS
INP_STR_D:                              ; Input string descriptor
        .LONG   NAM$C_MAXRSS
        .LONG   INP_STR
INP_STR_LEN:                            ; Input string length
        .BLKL   1
PROMPT_D:                               ; User prompt string
        .ASCID  /Please enter the file specification: /

        .PSECT  CODE,EXE,NOWRT
        .ENTRY  WILD,^M<>
        PUSHAB  INP_STR_LEN             ; Address for string length
        PUSHAB  PROMPT_D                ; Prompt string descriptor
        PUSHAB  INP_STR_D               ; String buffer descriptor
        CALLS   #3,G^LIB$GET_INPUT      ; Get input string value
        BLBC    R0,EXIT                 ; Quit on error
;
; Store user input string and perform initial parse to
; set up RMS context for subsequent search.
;
        MOVB    INP_STR_LEN, -          ; Set string size
                FAB_BLK+FAB$B_FNS
        $PARSE  FAB=FAB_BLK             ; Parse the file spec
        BLBC    R0,F_ERR                ; Quit and signal on error
;
; Search until all possibilities are exhausted.
;
SEARCH_LOOP:
        $SEARCH FAB=FAB_BLK             ; Find next file
        BLBC    R0,SRCHERR              ; Any more?
;
; Print out the resultant string from the search operation
;
        MOVZBL  NAM_BLK+NAM$B_RSL, -
                RES_STR_D               ; Set string length
        PUSHAB  RES_STR_D               ; String descriptor
        CALLS   #1,G^LIB$PUT_OUTPUT     ; Output the result
        BLBC    R0,EXIT                 ; Quit on error
        BRB     SEARCH_LOOP             ; Go for more
SRCHERR:                                ; If error is "No more files",
        CMPL    R0,#RMS$_NMF            ; this is normal completion
        BEQL    S_EXIT                  ; of the search loop.
F_ERR:  PUSHL   FAB_BLK+FAB$L_STV       ; Push STV and STS on stack
        PUSHL   FAB_BLK+FAB$L_STS       ; in reverse order
        CALLS   #2, G^LIB$SIGNAL        ; Signal error
S_EXIT: MOVL    #1,R0                   ; Suppress "No More Files"
EXIT:   RET
        .END WILD

This program is designed to locate all files corresponding to a partial file specification input. The program prompts the user for an input string, which can consist of a partial file specification, using the wildcard characters and/or any type of logical name, including a search list logical name. In many respects, this program emulates the DCL command DIRECTORY, which is discussed in the OpenVMS DCL Dictionary.

The program illustrates the use of the $PARSE and $SEARCH file name processing macros. Here is the program statement that invokes the Parse service for parsing the file name string:


$PARSE FAB=FAB_BLK

Before invoking the Parse service ($PARSE macro), the program moves the input string length to the file name string (FAB$B_FNS) field. If the Parse service returns an error completion status, the program branches to the F_ERR error routine.

Assuming no error, the program searches the disk directories specified by the expanded string area address field in the NAM block (NAM$L_ESA) until all possible files conforming to the partial file specification input are found. Here is the program line that invokes the Search service:


$SEARCH FAB=FAB_BLK

A status test is performed immediately after the $SEARCH macro. If an error is detected, the program branches to the SRCHERR label. If a no-more-files condition is detected, RMS returns the RMS$_NMF message to indicate that all files that match the specification have been found. (This error, however, is not signaled.)

This program contains two run-time library routines: LIB$GET_INPUT and LIB$PUT_OUTPUT. The LIB$GET_INPUT routine inputs a record from the current controlling input device, specified by SYS$INPUT, using the Get service. The LIB$PUT_OUTPUT routine outputs a record (line) to the current controlling output device, specified by SYS$OUTPUT, using the Put service. Both routines are discussed in greater detail in the OpenVMS RTL Library (LIB$) Manual.

B.3.5 Connecting and Disconnecting Record Streams

To associate or disassociate a file with one or more record streams, RMS provides the Connect and Disconnect services, which are invoked using the $CONNECT and $DISCONNECT macros.

Before reading and writing file records, the program must open (or create) the input and output files and then connect the files to the appropriate record streams by executing the $OPEN (or $CREATE) macro followed by the $CONNECT macro.

Closing a file implicitly disconnects the record stream. Use the Disconnect service to explicitly disconnect a record stream that is not to be used immediately. This keeps the file open but releases various data structures for use by other processes until your program needs the record stream.

Example B-5 shows a program in which a user-entered reply determines which key path is selected to access the indexed file created in Example B-3. The user-entered value determines the value specified for the RAB$B_KRF field. The RAB$B_KRF value is set before the connect operation occurs because this field is input to the Connect service.

Example B-5 Use of the Connect Service and Multiple Keys

       .TITLE   MULTIKEY
;
REC_SIZE=128
        .PSECT  DATA NOEXE,LONG
;                                                         ** RMS DATA **
MODFAB: $FAB    FNM=<DATA_OUTPUT.DAT>,-        ; FAB file spec.
                FAC=<GET>,-                    ; Get access needed
                SHR=<GET, UPD, PUT>,-          ; Allow Get, Update, Put
                MRS=REC_SIZE                   ; Specify record size
MODRAB: $RAB    FAB=MODFAB,-                   ; RAB; indicate FAB
                MBF=3,-                        ; Use 3 buffers
                UBF=REC_MODBUF,-               ; Specify buffer
                USZ=REC_SIZE,-
                KRF=0                          ; Primary is default key
REC_START:      .LONG    REC_SIZE              ; Record buffer
                .ADDRESS REC_MODBUF
REC_MODBUF:     .BLKB    REC_SIZE
;                                              TERMINAL I/O DATA **
MPRO0:  .ASCID  /  /
MPRO1:  .ASCID  /Enter list order: 1-by name, 2-by city, 3-by state, 9-end  :/
ENTRYERR:       .ASCID  /* * Value entered must be 1, 2, 3, or 9. * */
;
REGANS:         .LONG    1
                .ADDRESS REGBUF
REGBUF:         .BLKB    1
;
DONE:   .ASCID /Press RETURN to continue/
;
        .PSECT  CODE
START:  .WORD   ^M<>
INPUT:  PUSHAL  MPRO0                   ; Get input
        PUSHAL  MPRO1                   ; Display prompt
        PUSHAL  REGANS
        CALLS   #3, G^LIB$GET_INPUT
        BLBC    R0,FINIBR
        CMPB    #^A/1/,REGBUF           ; Test value of menu answer
        BEQLU   PRIM                    ; 1 means primary
        CMPB    #^A/2/,REGBUF           ; Continue testing
        BEQLU   ALT1                    ; 2 means first alternate
        CMPB    #^A/3/,REGBUF           ; Continue testing
        BEQLU   ALT2                    ; 3 means second alternate
        CMPB    #^A/9/,REGBUF           ; Continue testing
        BEQLU   FINIBR                  ; 9 means end program
BADANS: PUSHAL  ENTRYERR                ; otherwise, display error message
        CALLS   #1, G^LIB$PUT_OUTPUT
        BLBC    R0,FINIBR
        BRB     INPUT                   ; Entry error; retry
FINIBR: BRW FINI                    ; branch extender
PRIM:   MOVB    #0,MODRAB+RAB$B_KRF     ; Set key of reference in RAB
        BRB     OPEN
ALT1:   MOVB    #1,MODRAB+RAB$B_KRF     ; Set key of reference in RAB
        BRB     OPEN
ALT2:   MOVB    #2,MODRAB+RAB$B_KRF     ; Set key of reference in RAB
OPEN:   $OPEN   FAB=MODFAB              ; Open file
        BLBS    R0,CONN
        BRW     ERROR_OPEN
CONN:   $CONNECT RAB=MODRAB             ; Connect record stream
        BLBS    R0,NEXT
        BRW     ERROR
NEXT:   $GET    RAB=MODRAB              ; Get record
        CMPL    #RMS$_EOF,R0            ; Test if EOF
        BEQLU   CLEAN
        BLBC    R0,ERROR
        MOVZWL  RAB$W_USZ+MODRAB,REC_START ; Set ASCII descriptor length
        PUSHAL  REC_START                  ; Display each record
        CALLS   #1, G^LIB$PUT_OUTPUT
        BLBS    R0,NEXT
        BRB     FINI                    ; Repeat until EOF
CLEAN:  $CLOSE  FAB=MODFAB              ; Close file
        BLBC    R0,ERROR_OPEN
        PUSHAL  MPRO0
        CALLS   #1, G^LIB$PUT_OUTPUT
        BLBC    R0,FINI
        PUSHAL  DONE
        PUSHAL  REGANS
        CALLS   #2, G^LIB$GET_INPUT
        BLBC    R0,FINI
        BRW     INPUT
;
ERROR_OPEN:
        PUSHL   MODFAB+FAB$L_STV             ; Error opening
        PUSHL   MODFAB+FAB$L_STS             ; file. Signal error
        CALLS   #2, G^LIB$SIGNAL             ; using LIB$SIGNAL.
        BRB     FINI                         ; End program
ERROR:  PUSHL   MODRAB+RAB$L_STV             ; Record-related error
        PUSHL   MODRAB+RAB$L_STS
        CALLS   #2, G^LIB$SIGNAL             ; Signal error, then
        $CLOSE  FAB=MODFAB                   ; close file
FINI:   RET
        .END    START

Here the SHR argument limits access to processes that perform the Get service, Put service, and Update service. If you anticipate no file modifications as your program accesses the file, you can improve performance by having the SHR argument limit access to processes that use the Get service (SHR=GET).

Errors are signaled according to the recommended practice of using the FAB$L_STS and FAB$L_STV fields for file errors and RAB$L_STS and RAB$L_STV fields for record errors.

B.3.6 Other File-Processing Operations

Other file services include the Display, Erase, Extend, Remove, and Rename services, which can be invoked using the $DISPLAY, $ERASE, $EXTEND, $REMOVE, and $RENAME macros, respectively.

Example B-6 illustrates the use of the Rename service to rename a file from directory [USER] named NAMES.DAT to directory [USER.HISTORY] named OLD_NAMES.DAT.

Example B-6 Use of the Rename Service

        .TITLE  RENAME
;
;  Program that renames a file into a different directory and
;  displays the resultant string.
;
        .PSECT  DATA,NOEXE,WRT
;
;  Define old FAB, old NAM, new FAB, new NAM, and buffers
;
OLD_FAB:                                ; Define old file FAB
        $FAB    FNM=<[USER]NAMES.DAT>,-
                NAM=OLD_NAM             ; Pointer to NAM block
OLD_NAM:                                ; Define old file NAM
        $NAM    ESA=EXP_OLD,-           ; Equivalence string
                ESS=NAM$C_MAXRSS,-      ; address and size
                RSA=RES_OLD,-           ; Resultant string
                RSS=NAM$C_MAXRSS        ; address and size
NEW_FAB:                                ; Define new file FAB
        $FAB    FNM=<[USER.HISTORY]OLD_NAMES.DAT>,-
                NAM=NEW_NAM             ; Pointer to NAM block
NEW_NAM:
        $NAM    ESA=EXP_NEW,-           ; Equivalence string
                ESS=NAM$C_MAXRSS,-      ; address and size
                RSA=RES_NEW,-           ; Resultant string
                RSS=NAM$C_MAXRSS        ; address and size

EXP_OLD:                                ; Old file equivalence
        .BLKB   NAM$C_MAXRSS            ; string buffer
EXP_NEW:                                ; New file equivalence
        .BLKB   NAM$C_MAXRSS            ; string buffer
RES_OLD:                                ; Old file resultant
        .BLKB   NAM$C_MAXRSS            ; string buffer
RES_OLD_D:                              ; String descriptor
        .BLKL   1
        .LONG   RES_OLD
RES_NEW:                                ; New file resultant
        .BLKB   NAM$C_MAXRSS            ; string buffer
RES_NEW_D:                              ; String descriptor
        .BLKL   1
        .LONG   RES_NEW
;
MESS:   .ASCID /has been successfully relocated to /
;
        .PSECT  CODE,EXE,NOWRT
        .ENTRY  RENAME,^M<>
                                        ;  Rename file
;
        $RENAME OLDFAB=OLD_FAB, NEWFAB=NEW_FAB
        BLBC    R0,ERROR
                                        ; Set up descriptors
;
        MOVZBL  OLD_NAM+NAM$B_RSL,RES_OLD_D
        MOVZBL  NEW_NAM+NAM$B_RSL,RES_NEW_D
;
        PUSHAL  RES_OLD_D               ; Push resultant name,
        CALLS   #1,G^LIB$PUT_OUTPUT     ; display old file spec.
        BLBC    R0,TERM_ERROR           ; Branch on error
        PUSHAL  MESS                    ; Push message on stack,
        CALLS   #1,G^LIB$PUT_OUTPUT     ; display message
        BLBC    R0,TERM_ERROR           ; Branch on error
        PUSHAL  RES_NEW_D               ; Push resultant name,
        CALLS   #1,G^LIB$PUT_OUTPUT     ; display new file spec.
        BLBS    R0,DONE                 ; Branch on success
TERM_ERROR:
        PUSHL   R0                      ; Signal output error
        CALLS   #1,G^LIB$SIGNAL         ; from R0
        BRB     DONE
ERROR:  PUSHL   OLD_FAB+FAB$L_STV       ; Push STV and STS on
        PUSHL   OLD_FAB+FAB$L_STS       ; stack (reverse order)
        CALLS   #2,G^LIB$SIGNAL         ; Signal error
DONE:   RET
        .END RENAME

This program uses the Rename service to change both the directory and the name of the object file, which is being replaced by a new file (created by a separate program). If the Rename service executes correctly, the resultant file specification of the old file, the message defined by the ASCII descriptor following the label MESS, and the resultant file specification of the new file are displayed as verification that the Rename service successfully completed.

B.3.7 Retrieving and Inserting Records

The record-processing services provided by RMS insert records into a file and retrieve records from a file. These services are the Find, Get, and Put services, which can be invoked by the $FIND, $GET, and $PUT macros, respectively.

Example B-7 illustrates the use of the $GET and $PUT macros. It connects the input and output record streams, reads a record from an indexed file, and writes the record to a relative file. The program illustrates the use of the key string buffer, the key string descriptor, and the key string length when reading indexed records, and it includes the use of a user prompt string.

Example B-7 Use of the Get and Put Services

        .TITLE  LOOKUP
;
; This program looks up records in the input file and
; writes the records to the output file.

        .PSECT  DATA,WRT,NOEXE
INFAB:  $FAB    FNM = <INFILE:>,-       ; Input file logical name
                SHR = <GET,PUT,UPD,DEL> ; Allow read/write sharing
INRAB:  $RAB    FAB = INFAB,-           ; Pointer to FAB
                KBF = INP_STR,-         ; Key buffer
                KRF = 0,-               ; Primary key
                RAC = KEY,-             ; Keyed access
                ROP = WAT,-             ; Wait for record
                UBF = REC_BUFF,-        ; Record buffer
                USZ = REC_SIZE          ; and size
OUTFAB: $FAB    FNM = <OUTFILE:>,-      ; Output file logical name
                BKS = 3,-               ; 3 blocks per bucket
                MRS = REC_SIZE,-        ; Maximum record size
                ORG = REL,-             ; Relative file
                RAT = CR                ; Implied carriage control
OUTRAB: $RAB    FAB = OUTFAB,-          ; Pointer to FAB
                RBF = REC_BUFF          ; Output uses same buffer
                                        ; as input
REC_SIZE = 132                          ; Maximum size records
REC_BUFF:
        .BLKB   REC_SIZE                ; Record buffer
INP_STR:                                ; Key string buffer
        .BLKB   REC_SIZE
INP_STR_D:                              ; Key string descriptor
        .LONG   REC_SIZE
        .LONG   INP_STR
INP_STR_LEN:                            ; Key string length
        .BLKL   1
PROMPT_D:                               ; User prompt string
        .ASCID  /Please input key value: /
        .PSECT  CODE,NOWRT,EXE
;
; Initialization - Open input and output files and connect streams
;
        .ENTRY  LOOKUP,^M<>             ; No registers to save
        $OPEN   FAB=INFAB               ; Open input file
        BLBC    R0,EXIT1                ; Quit on error
        $CONNECT        RAB=INRAB       ; Connect to input
        BLBC    R0,EXIT2                ; Quit on error
        $CREATE FAB=OUTFAB              ; Create output file
        BLBC    R0,EXIT3                ; Quit on error
        $CONNECT        RAB=OUTRAB      ; Connect to output
        BLBC    R0,EXIT4                ; Quit on error
        BRB     READ                    ; Skip error branching
EXIT1:  MOVAL   INFAB, R6               ; Keep INFAB address
        BRW     F_ERR                   ; Signal FAB error
EXIT2:  MOVAL   INRAB, R6               ; Keep INRAB address
        BRW     R_ERR                   ; Signal RAB error
EXIT3:  MOVAL   OUTFAB, R6              ; Keep OUTFAB address
        BRB     F_ERR                   ; Signal FAB error
EXIT4:  MOVAL   OUTRAB, R6              ; Keep OUTRAB address
        BRB     R_ERR                   ; Signal RAB error
;
; Loop to copy records
;
READ:
        PUSHAB  INP_STR_LEN             ; Address for string length
        PUSHAB  PROMPT_D                ; Prompt string descriptor
        PUSHAB  INP_STR_D               ; String buffer descriptor
        CALLS   #3,G^LIB$GET_INPUT      ; Get input string value
        BLBS    R0,GET                  ; Quit on error or end-of-file
        CMPL    R0,#RMS$_EOF            ; Was error end-of-file?
        BEQL    DONE                    ; Successful completion
        BRB     EXIT                    ; Error otherwise
GET:    MOVB    INP_STR_LEN, -          ; Set key size
                INRAB+RAB$B_KSZ
        $GET    RAB=INRAB               ; Get a record
        BLBS    R0,PUT                  ; Put if successful
        CMPL    R0,#RMS$_RNF            ; No such record?
        BEQL    READ                    ; Try again
        BRB     EXIT2                   ; Error otherwise
PUT:    MOVW    INRAB+RAB$W_RSZ, -      ; Set the record size
                OUTRAB+RAB$W_RSZ        ; for output
        $PUT    RAB=OUTRAB              ; Write the record
        BLBC    R0,EXIT4                ; Quit on error
        BRB     READ                    ; Go back for more
;
; Close files and exit
;
F_ERR:  PUSHL   FAB$L_STV(R6)           ; Push STV and STS on
        PUSHL   FAB$L_STS(R6)           ; stack in reverse order
        CALLS   #2, G^LIB$SIGNAL        ; Signal message
        BRB     EXIT
R_ERR:  PUSHL   RAB$L_STV(R6)           ; Push STV and STS on
        PUSHL   RAB$L_STS(R6)           ; stack in reverse order
        CALLS   #2, G^LIB$SIGNAL        ; Signal message
DONE:   $CLOSE  FAB=INFAB               ; Close input
        $CLOSE  FAB=OUTFAB              ; and output
EXIT:   RET                             ; Return with status in R0
        .END    LOOKUP

This program writes records from an existing indexed input file into a newly created relative output file.

The program configures the file-sharing field (FAB$B_SHR) in the input FAB to permit sharing of the file by processes that use the Get, Put, Update, and Delete services.

The output FAB sets the bucket size field (FAB$B_BKS) at 3 blocks per bucket, limits the record size in the output file to 132 bytes, specifies the relative file organization, and specifies an implicit carriage control when the file output is directed to a terminal.

The RAB for the input file establishes the key data, sets the WAIT record option, and defines the record buffer. The output RAB locates the record buffer. The rest of the first program section assigns values and allocates space to various program variables. After the program opens and creates the two files and connects the record streams, it executes a series of instructions at label READ that input the required key values and the user prompt. Then the program uses the $GET and $PUT macros to invoke the respective services for retrieving and inserting the records. The $GET macro uses the INRAB and the $PUT macro uses the OUTRAB, as shown in the following program statements:


$GET   RAB=INRAB

$PUT   RAB=OUTRAB

Each time the program reads or writes a record, it performs a status check. If the status check is successful, the program branches back to the READ label for the next record. If any of the status checks indicate an error, the program branches to the appropriate error handler before exiting.

When the program completes the record transfers, it branches to the DONE label to close the record and exit.


Previous Next Contents Index