|
|
HP C
|
Previous | Contents | Index |
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 HP 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:
Example 2-3 shows the function that initializes the RMS data structures. See the RMS documentation for more information about the file access block, record access block, and extended attribute block structure members.
Example 2-3 Function Initializing RMS Data Structures |
---|
/* This segment of RMSEXP.C contains the function that * * initializes the RMS data structures. */ void initialize(char *fn) { (1) fab = cc$rms_fab; /* Initialize FAB */ fab.fab$b_bks = 4; fab.fab$l_dna = DEFAULT_FILE_EXT; fab.fab$b_dns = sizeof DEFAULT_FILE_EXT -1; fab.fab$b_fac = FAB$M_DEL | FAB$M_GET | FAB$M_PUT | FAB$M_UPD; fab.fab$l_fna = fn; fab.fab$b_fns = strlen(fn); (2) fab.fab$l_fop = FAB$M_CIF; fab.fab$w_mrs = RECORD_SIZE; fab.fab$b_org = FAB$C_IDX; (3) fab.fab$b_rat = FAB$M_CR; fab.fab$b_rfm = FAB$C_FIX; fab.fab$b_shr = FAB$M_NIL; fab.fab$l_xab = &primary_key; (4) rab = cc$rms_rab; /* Initialize RAB */ rab.rab$l_fab = &fab; (5) primary_key = cc$rms_xabkey; /* Initialize Primary * * Key XAB */ primary_key.xab$b_dtp = XAB$C_STG; primary_key.xab$b_flg = 0; (6) primary_key.xab$w_pos0 = (char *) &record.ssn - (char *) &record; primary_key.xab$b_ref = 0; primary_key.xab$b_siz0 = SIZE_SSN; primary_key.xab$l_nxt = &alternate_key; primary_key.xab$l_knm = "Employee Social Security \ Number "; (7) alternate_key = cc$rms_xabkey; /* Initialize Alternate * * Key XAB */ alternate_key.xab$b_dtp = XAB$C_STG; (8) alternate_key.xab$b_flg = XAB$M_DUP | XAB$M_CHG; alternate_key.xab$w_pos0 = (char *) &record.last_name - (char *) &record; alternate_key.xab$b_ref = 1; alternate_key.xab$b_siz0 = SIZE_LNAME; (9) alternate_key.xab$l_knm = "Employee Last Name \ "; } |
Key to Example 2-3:
RMS constants shown here are in the form xxx$M_yyy (for example, RAB$M_FIX) or xxx$C_yyy (for example, RAB$C_FIX). The OpenVMS RMS documentation cites the constants in the form xxx$V_yyy (for example, rab$v_fix), the difference being:
Using a $V type constant the same way as a $M type constant is a common problem. |
Example 2-4 shows the internal functions for the program.
Example 2-4 Internal Functions |
---|
/* This segment of RMSEXP.C contains the functions that * * control the data manipulation of the program. */ void open_file(void) { (1) rms_status = sys$create(&fab); if (rms_status != RMS$_NORMAL && rms_status != RMS$_CREATED) error_exit("$OPEN"); if (rms_status == RMS$_CREATED) printf("[Created new data file.]\n"); (2) rms_status = sys$connect(&rab); if (rms_status != RMS$_NORMAL) error_exit("$CONNECT"); } (3)void type_options(void) { printf("Enter one of the following:\n\n"); printf("A Add an employee.\n"); printf("D Delete an employee specified by SSN.\n"); printf("P Print employee(s) by ascending SSN on \ line printer.\n"); printf("T Type employee(s) by ascending last name \ on terminal.\n"); printf("U Update employee specified by SSN.\n\n"); printf("? Type this text.\n"); printf("^Z Exit this program.\n\n"); } (4)void pad_record(void) { int i; for(i = strlen(record.ssn); i < SIZE_SSN; i++) record.ssn[i] = ' '; for(i = strlen(record.last_name); i < SIZE_LNAME; i++) record.last_name[i] = ' '; for(i = strlen(record.first_name); i < SIZE_FNAME; i++) record.first_name[i] = ' '; for(i = strlen(record.comments);i < SIZE_COMMENTS; i++) record.comments[i] = ' '; } /* This subroutine is the fatal error-handling routine. */ (5)void error_exit(char *operation) { printf("RMSEXP - file %s failed (%s)\n", operation, filename); exit(rms_status); } |
Key to Example 2-4:
Example 2-5 shows the function that adds a record to the file. This function is called when ' a ' or ' A ' is entered in response to the menu.
Example 2-5 Utility Function: Adding Records |
---|
/* This segment of RMSEXP.C contains the function that * * adds a record to the file. */ void add_employee(void) { (1) do { printf("(ADD) Enter Social Security Number:"); gets(response); } while(strlen(response) == 0); strncpy(record.ssn,response,SIZE_SSN); do { printf("(ADD) Enter Last Name:"); gets(response); } while(strlen(response) == 0); strncpy(record.last_name,response,SIZE_LNAME); do { printf("(ADD) Enter First Name:"); gets(response); } while(strlen(response) == 0); strncpy(record.first_name,response,SIZE_FNAME); do { printf("(ADD) Enter Comments:"); gets(response); } while(strlen(response) == 0); strncpy(record.comments,response,SIZE_COMMENTS); (2) pad_record(); (3) rab.rab$b_rac = RAB$C_KEY; rab.rab$l_rbf = (char *) &record; rab.rab$w_rsz = RECORD_SIZE; (4) rms_status = sys$put(&rab); (5) if (rms_status != RMS$_NORMAL && rms_status != RMS$_DUP && rms_status != RMS$_OK_DUP) error_exit("$PUT"); else if (rms_status == RMS$_NORMAL || rms_status == RMS$_OK_DUP) printf("[Record added successfully.]\n"); else printf("RMSEXP - Existing employee with same SSN, \ not added.\n"); } |
Key to Example 2-5:
Previous | Next | Contents | Index |
|