[OpenVMS documentation]
[Site home] [Send comments] [Help with this site] [How to order documentation] [OpenVMS site] [Compaq site]
Updated: 11 December 1998

OpenVMS Record Management Services Reference Manual


Previous Contents Index

B.3.1 Creating, Accessing, and Deaccessing a File

The Create service constructs a new file according to the attributes you specify in the FAB for the file, whereas the Open service makes an existing file available for processing by your program. Both of these services, invoked by the $CREATE and $OPEN macros respectively, allocate resources within the system to establish access (a path) to a file. You must open or create a file to perform most file operations and any record operations on that file. Applications designed for shared access must declare the type of sharing at this time. The user specifies the various types of shared access by setting bits in the file access control (FAB$B_FAC) and share (FAB$B_SHR) fields in the appropriate FAB.

RMS provides several file-processing options for the Create service. The create-if option (FAB$V_CIF option in the FAB$L_FOP field) requests that the file be created only if it does not exist. If the file does exist in the specified directory, the file is opened, not created. The Open and Create services both establish access to the desired file, but the Create service additionally allocates disk space and performs functions related to allocation.

When you are finished processing a file, you invoke the Close service ($CLOSE macro) to close the file, disconnect all record streams associated with the file, and free all resources allocated to the file. If you do not explicitly invoke the Close service when the program image exits, RMS attempts an implicit close. All resources associated with open files are returned when the files are deaccessed at image rundown time. However, process permanent files are not implicitly closed when an image exits. These are special files that the current CLI opens outside the context of a normal image.

B.3.2 Example of Opening and Creating Files

Example B-2 illustrates the use of the Open, Create, Connect, Get, Put, and Close services to access and copy records from one file to another. Note that the arguments to the $FAB and $RAB macros are listed vertically on separate lines for ease in reading them. However, the argument list must be contiguous and a common programming error is omission of required delimiters and continuation characters when the arguments are listed in this manner.

Example B-2 Use of the Create, Open, and Close Services

        .TITLE  COPYFILE 
; 
; This program copies the input file to the output file. 
; 
        .PSECT  DATA,WRT,NOEXE 
INFAB:  $FAB    FNM = <INFILE:>,-       ; Primary input file name 
                DNM = <.INV>            ; Default input file type 
INRAB:  $RAB    FAB = INFAB,-           ; Pointer to FAB 
                ROP = RAH,-             ; Read-ahead option 
                UBF = REC_BUFF,-        ; Record buffer 
                USZ = REC_SIZE          ; and size 
OUTFAB: $FAB    FNM = <OUTFILE:>,-      ; Primary output file name 
                DNM = <.INV>,-          ; Default output file name 
                FOP = CTG,-             ; Make contiguous file 
                FAC = <PUT>,-           ; Open for PUT operations 
                SHR = <NIL>,-           ; Exclusive file access 
                MRS = REC_SIZE,-        ; Maximum record size 
                RAT = CR                ; Implied carriage control 
 
OUTRAB: $RAB    FAB = OUTFAB,-          ; Pointer to FAB 
                ROP = WBH,-             ; Write-behind option 
                RBF = REC_BUFF          ; Output uses same buffer 
                                        ; as input 
 
; 
REC_SIZE = 132                          ; Maximum record size 
REC_BUFF: 
        .BLKB   REC_SIZE                ; Record buffer 
 
        .PSECT  CODE,NOWRT,EXE 
; 
; Initialization - Open input and output files and connect streams 
; 
        .ENTRY  COPYFILE,^M<R6>         ; Save R6 
        $OPEN   FAB=INFAB               ; Open input file 
        BLBC    R0,EXIT1                ; Quit on error 
        $CONNECT   RAB=INRAB            ; Connect to input 
        BLBC    R0,EXIT2                ; Quit on error 
        MOVL    INFAB+FAB$L_ALQ,-       ; Set proper size for output 
                OUTFAB+FAB$L_ALQ 
        $CREATE FAB=OUTFAB              ; Create output file 
        BLBC    R0,EXIT3                ; Quit on error 
        $CONNECT        RAB=OUTRAB      ; Connect to output 
        BLBS    R0,READ                 ; Branch to READ loop 
        BRB     EXIT4                   ; Trap error 
EXIT1:  MOVAL   INFAB,R6                ; Error: Keep FAB address 
        BRB     F_ERR                   ; Signal file error 
EXIT2:  MOVAL   INRAB,R6                ; Keep RAB address 
        BRB     R_ERR                   ; Signal record error 
EXIT3:  MOVAL   OUTFAB,R6               ; Keep FAB address 
        BRB     F_ERR                   ; Signal record error 
EXIT4:  MOVAL   OUTRAB,R6               ; If error, retain RAB addr. 
        BRB     R_ERR                   ; Signal record error 
; 
; Copy records loop 
; 
READ:   $GET    RAB=INRAB               ; Get a record 
        BLBS    R0,WRITE                ; Write the record 
        CMPL    R0,#RMS$_EOF            ; Was error end-of-file? 
        BEQL    DONE                    ; Successful completion 
        BRB     EXIT2                   ; Error otherwise 
WRITE:  MOVW    INRAB+RAB$W_RSZ, -      ; Input RAB sets record 
                OUTRAB+RAB$W_RSZ        ; size for output RAB 
        $PUT    RAB=OUTRAB              ; Write the record 
        BLBC    R0,EXIT4                ; Quit on error 
        BRB     READ                    ; Go back for more 
; 
; Close files, signal any errors, and exit 
; 
F_ERR:  PUSHL   FAB$L_STV(R6)           ; Push STV and STS of FAB 
        PUSHL   FAB$L_STS(R6)           ; on the stack 
        CALLS   #2, G^LIB$SIGNAL        ; Signal error 
        BRB     EXIT 
R_ERR:  PUSHL   RAB$L_STV(R6)           ; Push STV and STS of RAB 
        PUSHL   RAB$L_STS(R6)           ; on the stack 
        CALLS   #2, G^LIB$SIGNAL        ; Signal error 
DONE:   $CLOSE  FAB=INFAB               ; Close input 
        $CLOSE  FAB=OUTFAB              ; and output 
EXIT:   RET                             ; Return with status in R0 
        .END    COPYFILE 

This example illustrates how you can use the sequential file organization to create a new file by copying records from an existing file. The newly created file and the source file have variable-length records.

This example assumes that an external program has identified the input file as a search list logical name using this statement:


$ ASSIGN [INV]30JUN85,[INV.OLD]30JUN85 INFILE: 
This directs RMS to look for the input file in directory [INV] first, and if it does not find the file, it should look in directory [INV.OLD].

The program also specifies the default file type .INV for the input file using this statement:


DNM=<.INV>              ; Default input file name 

Next the program configures the RAB used for the input file (labeled INRAB). The first argument links the RAB to the associated FAB (INFAB) and this is the only required argument to a RAB. The rest of the arguments specify the read-ahead option (described in later text) and the record buffer for the input file. The Get service uses the user record buffer address (UBF) field and the user record buffer size (USZ) field as inputs to specify the record buffer and the record size, respectively.

Note

When you invoke the Get service, RMS takes control of the record buffer and may modify it. RMS returns the record size and only guarantees the contents from where it accessed the record to the completion of the record.

The program then configures the FAB for the output file. The first argument uses the FNM field to equate the file name to the externally defined logical name OUTFILE. After the program specifies the default file specification extension for the output file, it specifies three additional FAB fields.

First it directs RMS to allocate contiguous space for the output file by setting the CTG bit in the FAB$L_FOP field of the FAB.

Next the program uses a program-defined variable to store the value 132 in the MRS field:


MRS=REC_SIZE 
REC_SIZE= 132 
The program then specifies that each record is to be preceded by a line feed and followed by a carriage return whenever the record is output to a line printer or terminal:


RAT=CR 

Because the program alternately reads and then writes each record, the input file and the output file may share the same buffer. However, because the Put service does not have access to the UBF and UBZ fields, the output RAB defines the buffer using the RBF and the RSZ fields.

Note that the UBF, USZ, and RBF values are set prior to run time, but that the RSZ value is set at run time, just prior to invocation of the Put service. This is done because the input file contains variable-length records and the Put service relies on the Get service to supply each record's size by way of the RSZ field, an INRAB output field.

The following statement from the sample program illustrates this feature:


WRITE:  MOVW    INRAB+RAB$W_RSZ, -      ; Input RAB sets record 
                OUTRAB+RAB$W_RSZ        ; size for output RAB 

The run-time processing macros for the input file consist of a $OPEN, a $CONNECT, a $GET, and a $CLOSE macro. Because the input file already exists, the program accesses it with a $OPEN macro. The sole argument to this macro identifies the FAB to the Open service:


$OPEN  FAB=INFAB 

Next, the program connects a record stream to the input file by calling the Connect service and specifying INRAB as the appropriate RAB:


$CONNECT  RAB=INRAB 

Note that upon completion of each service call, the program tests the condition value in R0 returned by the service before proceeding to the next call. If the call fails, the program exits with the appropriate control block address in R6.

After creating the output file and establishing its record stream, the program begins a processing loop in which the Get service reads a record from the input file and the Put service writes the record to the output file. When all file records are copied, as indicated by the detection of the end of the file, the program exits to label DONE, which closes both files.

The Close service disconnects the record stream for all RABs connected to the specified FAB. In a multistream environment (more than one RAB can be connected to a single FAB), a program may disconnect individual record streams using the Disconnect service.

B.3.3 Example of Creating a Multiple-Key Indexed File

Example B-3 creates an indexed file on a remote node from a sequential file on the local node. The indexed file contains three keys: a segmented primary key and two simple alternate keys. The segmented primary key includes the customer's last name, the first letter of the customer's first name, and the customer's middle initial.

Example B-3 Use of the Create Service for an Indexed File

        .TITLE  CREATEIDX - CREATE INDEXED FILE 
        .IDENT  /V001/ 
; 
; This program creates an indexed file with three keys from a 
; sequential file containing a name and address list. The record 
; format of the input file is shown below: 
; 
;       First Name      Column  00-10 
;       Middle Initial  Column  11-11 
;       Last Name       Column  12-26 
;       Street          Column  27-46 
;       City            Column  47-58 
;       State           Column  59-60 
;       Zip Code        Column  61-65 
;       Reserved for 
;         new data      Column  66-end of record 
; 
; The input and output files are specified by the logical names SRC 
; and DST, respectively. For example: 
; 
;       $ DEFINE SRC DBB1:[TEST]INPUT.DAT 
;       $ DEFINE DST TRNTO::DRA4:[RMS.FILES]OUTPUT.DAT 
;       $ RUN CREATEIDX 
; 
;******************************************************************** 
 
        .SBTTL  Control block and buffer storage 
        .PSECT  DATA            NOEXE,LONG 
; 
; Define the source file FAB and RAB control blocks. 
; 
SRC_FAB: 
        $FAB    FAC=<GET>,-             ; File access for GET only 
                FOP=<SQO>,-             ; DAP file transfer mode 
 
                FNM=<SRC:>              ; Name of input file 
SRC_RAB: 
        $RAB    FAB=SRC_FAB,-           ; Address of associated FAB 
                RAC=SEQ,-               ; Sequential record access 
                UBF=BUFFER,-            ; Buffer address 
                USZ=BUFFER_SIZE         ; Buffer size 
 
; 
; Define the destination file FAB and RAB control blocks. 
; 
DST_FAB: 
        $FAB    FAC=<PUT>,-             ; File access for PUT only 
                FOP=CTG,-               ; Allocate contiguous 
                SHR = <NIL>,-           ; Exclusive file access 
                FNM=<DST:>,-            ; Name of output file 
                MRS=128,-               ; Maximum record size 
                RFM=VAR,-               ; Variable length records 
                RAT=<CR>,-              ; Implied carriage control 
                ORG=IDX,-               ; Indexed file organization 
                XAB=DST_KEY0            ; Address of start of XAB chain 
DST_RAB: 
        $RAB    FAB=DST_FAB,-           ; Address of associated FAB 
                MBF=3,-                 ; Use 3 buffers 
                RAC=KEY,-               ; Random record writes 
                RBF=BUFFER,-            ; Buffer address 
                ROP=LOA,-               ; Specify initial fill size 
                RSZ=BUFFER_SIZE         ; Buffer size 
; 
; Define a key definition XAB for the primary key. 
; 
DST_KEY0:                               ; Primary key is Name 
        $XABKEY REF=0,-                 ; Key reference number 
                DAN=0,-                 ; Define data XABALL 
                DFL=1536,-              ; Define data fill of 75% 
                FLG=<DUP>,-             ; Allow duplicate keys 
                DTP=DSTG,-              ; Descending sort order 
                IAN=1,-                 ; Define index XABALL 
                IFL=1536,-              ; Initial index fill 75% 
                PROLOG=3,-              ; Request prolog 3 
                POS=<12,0,11>,-         ; Key segment positions 
                SIZ=<15,1,1>,-          ; Key segment lengths 
                NXT=DST_KEY1            ; Address of next XAB in chain 
; 
; Define key definition XABs for the alternate keys. 
; 
DST_KEY1:                               ; 1st alternate key is City 
        $XABKEY REF=1,-                 ; Key reference number 
                DAN=2,-                 ; Data level (SIDR) XABALL 
                IAN=2,-                 ; Index XABALL 
                IFL=768,-               ; Initial index fill 75% 
                POS=47,-                ; Starting key position 
                SIZ=12,-                ; Key size 
                FLG=<CHG,DUP>,-         ; Duplicates and changes 
                NXT=DST_KEY2            ; Address of next XAB in chain 
DST_KEY2:                               ; 2nd alternate key is State 
        $XABKEY REF=2,-                 ; Key reference number 
                DAN=2,-                 ; Data level (SIDR) XABALL 
                IAN=2,-                 ; Index XABALL 
                IFL=768,-               ; Initial index fill 75% 
                POS=59,-                ; Starting key position 
                FLG=<CHG,DUP>,-         ; Duplicates and changes 
                SIZ=2,-                 ; Key size 
                NXT=DST_ALL0            ; Designate next XAB 
 
; 
;  Define allocation control XABs to define multiple areas 
; 
DST_ALL0: 
        $XABALL AID=0,-                 ; Data area definition 
                ALQ=328,-               ; Allocation quantity and 
                AOP=<CBT>,-             ; contiguous best try 
                BKZ=4,-                 ; Bucket size of 4 blocks 
                DEQ=112,-               ; Default extension quantity 
                NXT=DST_ALL1            ; Designate next XAB 
DST_ALL1: 
        $XABALL AID=1,-                 ; Primary key index area 
                ALQ=8,-                 ; Allocation quantity and 
                AOP=<CBT>,-             ; contiguous best try 
                BKZ=4,-                 ; Bucket size of 4 blocks 
                DEQ=4,-                 ; Default extension quantity 
                NXT=DST_ALL2            ; Designate next XAB 
DST_ALL2: 
        $XABALL AID=2,-                 ; Alternate key data area 
                ALQ=112,-               ; Allocation quantity and 
                AOP=<CBT>,-             ; contiguous best try 
                BKZ=2,-                 ; Bucket size of 2 blocks 
                DEQ=38,-                ; Default extension quantity 
                NXT=0                   ; No more XABs 
; 
; Allocate buffer to the size of the largest record being read. 
; 
BUFFER: .BLKB   66                      ; Buffer for input and output 
        BUFFER_SIZE=.-BUFFER            ; Buffer size 
 
;********************************************************************* 
 
        .SBTTL  Mainline 
        .PSECT  CODE            NOWRT,BYTE 
; 
; Start of program 
; 
        .ENTRY  CREATEIDX,^M<R6>        ; Entry point 
; 
; Open the source and destination files. 
; 
        $OPEN    FAB=SRC_FAB            ; Open input file 
        BLBC     R0,EXIT1               ; Branch on failure 
        $CONNECT RAB=SRC_RAB            ; Connect input record stream 
        BLBC     R0,EXIT2               ; Branch on failure 
        $CREATE  FAB=DST_FAB            ; Create output file 
        BLBC     R0,EXIT3               ; Branch on failure 
        $CONNECT RAB=DST_RAB            ; Connect output record stream 
        BLBC     R0,EXIT4               ; Branch on failure 
        BRB      LOOP                   ; Bypass signaling code 
EXIT1:  MOVAL    SRC_FAB,R6             ; Keep FAB address 
        BRB      F_ERR                  ; Signal error 
EXIT2:  MOVAL    SRC_RAB,R6             ; Keep RAB address 
        BRB      R_ERR                  ; Signal error 
EXIT3:  MOVAL    DST_FAB,R6             ; Keep FAB address 
        BRB      F_ERR                  ; Signal error 
EXIT4:  MOVAL    DST_RAB,R6             ; Keep RAB address 
        BRB      R_ERR                  ; Signal error 
 
; 
; Transfer records until end-of-file is reached. 
; 
LOOP:   $GET    RAB=SRC_RAB            ; Read next rec from input file 
        BLBS    R0,PUT                 ; Branch on success 
        CMPL    R0,#RMS$_EOF           ; Was it end-of-file (EOF)? 
        BNEQ    EXIT2                  ; Branch if not EOF error 
        BRB     CLOSE                  ; Close and exit if EOF 
PUT:    $PUT    RAB=DST_RAB            ; Write 66-byte record to output 
        BLBS    R0,LOOP                ; On success, continue loop 
        BRB     EXIT4                  ; On error, signal and exit 
; 
; Close the source and destination files. 
; 
F_ERR:  PUSHL   FAB$L_STV(R6)           ; Push STV and STS fields 
        PUSHL   FAB$L_STS(R6)           ; on stack 
        CALLS   #2, G^LIB$SIGNAL        ; Signal file error 
        BRB     EXIT                    ; Exit 
R_ERR:  PUSHL   RAB$L_STV(R6)           ; Push STV and STS fields 
        PUSHL   RAB$L_STS(R6)           ; on stack 
        CALLS   #2, G^LIB$SIGNAL        ; Signal file error 
CLOSE:  $CLOSE  FAB=DST_FAB             ; Close output file 
        $CLOSE  FAB=SRC_FAB             ; Close input file 
EXIT:   $EXIT_S                         ; Exit 
        .END    CREATEIDX               ; Specify starting address 

This example program creates an indexed file with a primary key and two alternate keys that are defined by appropriate key definition control blocks (XABKEY). For efficiency, the file is divided into areas consisting of a data area and an index area for each key using multiple allocation control blocks (XABALL).

In each XABKEY, the DAN and IAN arguments (XAB$B_DAN and XAB$B_IAN fields) indicate the area identification number (AID) of the corresponding XABALL. By setting the RAB$V_LOA bit in RAB field RAB$L_ROP, the program directs RMS to use the DFL and IFL arguments (XAB$W_DFL and XAB$W_IFL fields) to determine the maximum initial fill size (in bytes) for data and index buckets (each bucket contains the number of blocks specified in the XABALL BKZ argument, XAB$B_BKZ field).

These are the XABKEY and XABALL control blocks for the primary key (the NAME key) in this example:


DST_KEY0:                               ; Primary key is Name 
        $XABKEY REF=0,-                 ; Key reference number 
                DAN=0,-                 ; Define data XABALL 
                DFL=1536,-              ; Define data fill of 75% 
                FLG=<DUP>,-             ; Allow duplicate keys 
                DTP=DSTG,-              ; Descending sort order 
                IAN=1,-                 ; Define index XABALL 
                IFL=1536,-              ; Initial index fill 75% 
                PROLOG=3,-              ; Request prolog 3 
   .
   .
   .
DST_ALL0: 
        $XABALL AID=0,-              ; Data area definition 
                ALQ=328,-            ; Allocation quantity and 
                AOP=<CBT>,-          ; contiguous best try 
                BKZ=4,-              ; Bucket size of 4 blocks 
                DEQ=112,-            ; Default extension quantity 
                NXT=DST_ALL1         ; Designate next XAB 
DST_ALL1: 
        $XABALL AID=1,-              ; Primary key index area 
                ALQ=8,-              ; Allocation quantity and 
                AOP=<CBT>,-          ; contiguous best try 
                BKZ=4,-              ; Bucket size of 4 blocks 
                DEQ=4,-              ; Default extension quantity 
                NXT=DST_ALL2         ; Designate next XAB 
The allocation information was obtained using the File Definition Language (FDL) editor which is especially useful when you are creating large indexed files. The DCL commands CREATE/FDL and CONVERT can be used to create files by using an FDL file produced by the Edit/FDL utility, without any programming. Instead of using the multiple XABs for the key definition and area allocations in this program, a simpler approach is to use the FDL file produced by the Edit/FDL utility by invoking the FDL routines FDL$PARSE and FDL$RELEASE (for more information on these routines, see the OpenVMS Utility Routines Manual).

Fixed-length records are copied from the sequential input file on the local node to the indexed file on the remote node. Each variable-length output record is initially 66 bytes long and may be extended to a maximum of 128 bytes.


Previous Next Contents Index

[Site home] [Send comments] [Help with this site] [How to order documentation] [OpenVMS site] [Compaq site]
[OpenVMS documentation]

Copyright © Compaq Computer Corporation 1998. All rights reserved.

Legal
4523PRO_038.HTML