United States |
Previous | Contents | Index |
RMS provides a number of functions that create and manipulate files. These functions use RMS data structures to define the characteristics of a file and its records. The data structures are used as indirect arguments to the function call.
The RMS data structures are grouped into four main categories, as follows:
RMS uses these data structures to perform file and record operations. Table 2-1 lists some of the common functions.
Category | Function | Description |
---|---|---|
File
Processing |
sys$create | Creates and opens a new file of any organization. |
sys$open | Opens an existing file and initiates file processing. | |
sys$close | Terminates file processing and closes the file. | |
sys$erase | Deletes a file. | |
Record
Processing |
sys$connect | Associates a file access block with a record access block to establish a record access stream; a call to this function is required before any other record-processing function can be used. |
sys$get | Retrieves a record from a file. | |
sys$put | Writes a new record to a file. | |
sys$update | Rewrites an existing record to a file. | |
sys$delete | Deletes a record from a file. | |
sys$rewind | Positions the record pointer to the first record in the file. | |
sys$disconnect | Disconnects a record access stream. |
All RMS functions are directly accessible from Compaq C programs. The syntax for any RMS function has the following form:
int sys$name(struct rms_structure *pointer); |
In this syntax, name is the name of the RMS function (such as OPEN or CREATE); rms_structure is the name of the structure being used by the function.
The file-processing functions require a pointer to a file access block as an argument; the record-processing functions require a pointer to a record access block as an argument. Since sys$create is a file-processing function, its syntax is as follows:
int sys$create(struct FAB *fab); |
These syntax descriptions do not show all the options available when you invoke an RMS function. For a complete description of the RMS calling sequence, see the OpenVMS Record Management Services Reference Manual.
Finally, all the RMS functions return an integer status value. The
format of RMS status values follows the standard format described in
Chapter 3. Since RMS functions return a 32-bit integer, you do not
need to declare the type of an RMS function return before you use it.
2.5 Writing Compaq C Programs Using RMS
The Compaq C Run-Time Library (RTL) supplies a number of header files that describe the RMS data structures and status codes. Table 2-2 describes these header files.
Header File | Structure Tag(s) | Description |
---|---|---|
<fab.h> | FAB | Defines the file access block structure. |
<rab.h> | RAB | Defines the record access block structure. |
<nam.h> | NAM | Defines the name block structure. |
<xab.h> | XAB | Defines all the extended attribute block structures. |
<rmsdef.h> | -- | Defines the completion status codes that RMS returns after every file- or record-processing operation. |
<rms.h> | all tags | Includes all the previous header files. |
Most Compaq C programmers include the <rms.h> header file, which includes all the other header files.
These header files define all the data structures as structure tag names. However, they perform no allocation or initialization of the structures; these header files describe only a template for the structures. To use the structures, you must create storage for them and initialize all the structure members as required by RMS. Note that these include files are part of Compaq C for OpenVMS systems. RMS is part of the OpenVMS environment and may contain other included header files not described here.
To assist in the initialization process, the Compaq C RTL provides initialized RMS data structure variables. You can copy these variables to your uninitialized structure definitions with a structure assignment. You can choose to take the default values for each of the structure members, or you can tailor the contents of the structures to fit your requirements. In either case, you must use the structure types to allocate storage for the structure and to define the members of the structure.
The initialized variables supply the RMS default values for each member in the structure; they specify none of the optional parameters. To determine what default values are supplied by the initialized variables, see the OpenVMS Record Management Services Reference Manual.
Table 2-3 lists the initialized RMS data structure variables and the structures that they initialize.
Variable | Structure Type | Initialize Structure |
---|---|---|
cc$rms_fab | struct FAB | File access block |
cc$rms_rab | struct RAB | Record access block |
cc$rms_nam | struct NAM | Name block |
cc$rms_xaball | struct XABALL | Allocation extended attribute block |
cc$rms_xabdat | struct XABDAT | Date and time extended attribute block |
cc$rms_xabfhc | struct XABFHC | File header characteristics extended attribute block |
cc$rms_xabkey | struct XABKEY | Indexed file key extended attribute block |
cc$rms_xabpro | struct XABPRO | Protection extended attribute block |
cc$rms_xabrdt | struct XABRDT | Revision date and time extended attribute block |
cc$rms_xabsum | struct XABSUM | Summary extended attribute block |
cc$rms_xabtrm | struct XABTRM | Terminal extended attribute block |
The declarations of these structures are contained in the appropriate header file.
The names of the structure members conform to the following RMS naming convention:
typ$s_fld |
The identifier typ is the abbreviation for the structure, the
letter s is the size of the member (such as l for longword or
b for byte), and the identifier fld is the member name, such
as sts for the completion status code. The dollar sign ($) is a
character used in OpenVMS system logical names. See the
OpenVMS Record Management Services Reference Manual for a description of the members in each structure.
2.5.1 Initializing File Access Blocks
The file access block defines the attributes of the file. To initialize a file access block, assign the values in the initialized data structure cc$rms_fab to the address of the file access block defined in your program. Consider the following example:
/* This example shows how to initialize a file access block. */ #include <rms.h> /* Declare all RMS data structs */ struct FAB fblock; /* Define a file access block */ main() { fblock = cc$rms_fab; /* Initialize the structure */ . . . } |
Any of these RMS structures may be dynamically allocated. For example, another way to allocate a file access block is as follows:
/* This program shows how to dynamically allocate RMS structures. */ #include <rms.h> /* Declare all RMS data structs */ main() { /* Allocate dynamic storage */ struct FAB *fptr = malloc(sizeof (struct FAB)); *fptr = cc$rms_fab; /* Initialize the structure */ . . . } |
To change the default values supplied by a data structure variable, you must reinitialize the members of the structure individually. You initialize a member by giving the offset of the member and assigning a value to it. Consider the following example:
fblock.fab$l_xab = &primary_key; |
This statement assigns the address of the extended attribute block named
primary_key
to the
fab$l_xab
member of the file access block named
fblock
.
2.5.2 Initializing Record Access Blocks
The record access block specifies how records are processed. You initialize a record access block the same way you initialize a file access block. For example:
/* This example shows how to initialize a file access block. */ #include <rms.h> struct FAB fblock; struct RAB rblock; /* Define a record access block */ main() { fblock = cc$rms_fab; /* Initialize the structure */ rblock = cc$rms_rab; /* Initialize the FAB member */ rblock.rab$l_fab = &fblock; . . . } |
There is only one extended attribute block structure (XAB), but there are seven ways to initialize it. The extended attribute blocks define additional file attributes that are not defined elsewhere. For example, the key extended attribute block is used to define the keys of an indexed file.
All extended attribute blocks are chained off a file access block in the following manner:
You go through the same steps to declare extended attribute blocks as you would to declare the other RMS data structures:
The following example declares two extended attribute block structures. They are initialized as key extended attribute blocks with the cc$rms_xabkey data structure variable. The xab$l_nxt member of the primary key is initialized with the address of the alternate_key extended attribute block.
/* This example shows how to initialize the extended * * attribute block. */ #include <rms.h> struct XABKEY primary_key,alternate_key; main() { primary_key = cc$rms_xabkey; alternate_key = cc$rms_xabkey; primary_key.xab$l_nxt = &alternate_key; . . . } |
The name block contains default file name values, such as the directory or device specification, file name, or file type. If you do not specify one of the parts of the file specification when you open the file, RMS uses the values in the name block to complete the file specification and places the complete file specification in an array.
You create and initialize name blocks in the same manner used to initialize the other RMS data structures. Consider the following example:
/* This example shows how to initialize a name block. */ #include <rms.h> struct NAM nam; struct FAB fab; main() { fab = cc$rms_fab; nam = cc$rms_nam; /* Define an array for the * * expanded file specification */ char expanded_name[NAM$C_MAXRSS]; /* Initialize the appropriate * * members */ fab.fab$l_nam = &nam; nam.nam$l_esa = &expanded_name; nam.nam$b_ess = sizeof expanded_name; . . . } |
The example program in this section uses RMS functions to maintain a simple employee file. The file is an indexed file with two keys: social security number and last name. The fields in the record are character strings defined in a structure with the tag record.
The records have the carriage-return attribute. Individual fields in each record are padded with blanks for two reasons. First, because RMS requires that the key fields be a fixed length and occur in a fixed position in each record, key fields must be padded in some way. The example program pads short fields; its use of the space character for padding is arbitrary. Second, the choice of blank padding (as opposed to null padding) allows the file to be printed or typed without conversion. Note that both the position and size of the key are attributes of the file, not of each I/O that gets done.
The program does not perform range or bounds checking. Only the error checking that shows the mapping of Compaq C to RMS is performed. Any other errors are considered fatal.
The program is divided into the following sections:
To run this program, perform the following steps:
$ CC RMSEXP[Return] |
$ LINK RMSEXP [Return] |
$ RMSEXP :== $device:[directory]RMSEXP[Return] |
$ RMSEXP filename[Return] |
The complete listing of the sample program follows. The listing is broken into sections and shown in Examples 2-1 through 2-9. Notes on each section are keyed to the numbers in the listing.
Example 2-1 shows the external data declarations and definitions.
Example 2-1 External Data Declarations and Definitions |
---|
/* This segment of RMSEXP.C contains external data * * definitions. */ (1)#include <rms.h> #include <stdio.h> #include <ssdef.h> #include <string.h> #include <stdlib.h> #include <starlet.h> (2)#define DEFAULT_FILE_EXT ".dat" #define RECORD_SIZE (sizeof record) #define SIZE_SSN 15 #define SIZE_LNAME 25 #define SIZE_FNAME 25 #define SIZE_COMMENTS 15 #define KEY_SIZE \ (SIZE_SSN > SIZE_LNAME ? SIZE_SSN: SIZE_LNAME) (3)struct FAB fab; struct RAB rab; struct XABKEY primary_key,alternate_key; (4)struct { char ssn[SIZE_SSN], last_name[SIZE_LNAME]; char first_name[SIZE_FNAME], comments[SIZE_COMMENTS]; } record; (5)char response[BUFSIZ],*filename; (6)int rms_status; void open_file(void); void type_options(void); void pad_record(void); void error_exit(char *); void add_employee(void); void delete_employee(void); void type_employees(void); void print_employees(void); void update_employee(void); void initialize(char *); |
Key to Example 2-1:
The main function, shown in Example 2-2, controls the general flow of the program.
Example 2-2 Main Program Section |
---|
/* This segment of RMSEXP.C contains the main function * * and controls the flow of the program. */ (1)main(int argc, char **argv) { (2) if (argc < 1 || argc > 2) printf("RMSEXP - incorrect number of arguments"); else { printf("RMSEXP - Personnel Database \ Manipulation Example\n"); (3) filename = (argc == 2 ? *++argv : "personnel.dat"); (4) initialize(filename); (5) open_file(); for(;;) { (6) printf("\nEnter option (A,D,P,T,U) or \ ? for help :"); gets(response); if (feof(stdin)) break; printf("\n\n"); (7) switch(response[0]) { case 'a': case 'A': add_employee(); break; case 'd': case 'D': delete_employee(); break; case 'p': case 'P': print_employees(); break; case 't': case 'T': type_employees(); break; case 'u': case 'U': update_employee(); break; default: printf("RMSEXP - \ Unknown Operation.\n"); case '?': case '\0': type_options(); } } (8) rms_status = sys$close(&fab); (9) if (rms_status != RMS$_NORMAL) error_exit("$CLOSE"); } } |
Key to Example 2-2:
Previous | Next | Contents | Index |
|