[0001] [0002] [0003] [0004] [0005] [0006] [0007] [0008] [0009] [0010] [0011] [0012] [0013] [0014] [0015] [0016] [0017] [0018] [0019] [0020] [0021] [0022] [0023] [0024] [0025] [0026] [0027] [0028] [0029] [0030] [0031] [0032] [0033] [0034] [0035] [0036] [0037] [0038] [0039] [0040] [0041] [0042] [0043] [0044] [0045] [0046] [0047] [0048] [0049] [0050] [0051] [0052] [0053] [0054] [0055] [0056] [0057] [0058] [0059] [0060] [0061] [0062] [0063] [0064] [0065] [0066] [0067] [0068] [0069] [0070] [0071] [0072] [0073] [0074] [0075] [0076] [0077] [0078] [0079] [0080] [0081] [0082] [0083] [0084] [0085] [0086] [0087] [0088] [0089] [0090] [0091] [0092] [0093] [0094] [0095] [0096] [0097] [0098] [0099] [0100] [0101] [0102] [0103] [0104] [0105] [0106] [0107] [0108] [0109] [0110] [0111] [0112] [0113] [0114] [0115] [0116] [0117] [0118] [0119] [0120] [0121] [0122] [0123] [0124] [0125] [0126] [0127] [0128] [0129] [0130] [0131] [0132] [0133] [0134] [0135] [0136] [0137] [0138] [0139] [0140] [0141] [0142] [0143] [0144] [0145] [0146] [0147] [0148] [0149] [0150] [0151] [0152] [0153] [0154] [0155] [0156] [0157] [0158] [0159] [0160] [0161] [0162] [0163] [0164] [0165] [0166] [0167] [0168] [0169] [0170] [0171] [0172] [0173] [0174] [0175] [0176] [0177] [0178] [0179] [0180] [0181] [0182] [0183] [0184] [0185] [0186] [0187] [0188] [0189] [0190] [0191] [0192] [0193] [0194] [0195] [0196] [0197] [0198] [0199] [0200] [0201] [0202] [0203] [0204] [0205] [0206] [0207] [0208] [0209] [0210] [0211] [0212] [0213] [0214] [0215] [0216] [0217] [0218] [0219] [0220] [0221] [0222] [0223] [0224] [0225] [0226] [0227] [0228] [0229] [0230] [0231] [0232] [0233] [0234] [0235] [0236] [0237] [0238] [0239] [0240] [0241] [0242] [0243] [0244] [0245] [0246] [0247] [0248] [0249] [0250] [0251] [0252] [0253] [0254] [0255] [0256] [0257] [0258] [0259] [0260] [0261] [0262] [0263] [0264] [0265] [0266] [0267] [0268] [0269] [0270] [0271] [0272] [0273] [0274] [0275] [0276] [0277] [0278] [0279] [0280] [0281] [0282] [0283] [0284] [0285] [0286] [0287] [0288] [0289] [0290] [0291] [0292] [0293] [0294] [0295] [0296] [0297] [0298] [0299] [0300] [0301] [0302] [0303] [0304] [0305] [0306] [0307] [0308] [0309] [0310] [0311] [0312] [0313] [0314] [0315] [0316] [0317] [0318] [0319] [0320] [0321] [0322] [0323] [0324] [0325] [0326] [0327] [0328] [0329] [0330] [0331] [0332] [0333] [0334] [0335] [0336] [0337] [0338] [0339] [0340] [0341] [0342] [0343] [0344] [0345] [0346] [0347] [0348] [0349] [0350] [0351] [0352] [0353] [0354] [0355] [0356] [0357] [0358] [0359] [0360] [0361] [0362] [0363] [0364] [0365] [0366] [0367] [0368] [0369] [0370] [0371] [0372] [0373] [0374] [0375] [0376] [0377] [0378] [0379] [0380] [0381] [0382] [0383] [0384] [0385] [0386] [0387] [0388] [0389] [0390] [0391] [0392] [0393] [0394] [0395] [0396] [0397] [0398] [0399] [0400] [0401] [0402] [0403] [0404] [0405] [0406] [0407] [0408] [0409] [0410] [0411] [0412] [0413]
/* * Low-level routines for accessing bookreader files via RMS. Records * are read via rfa address. * * int bkf_open ( char *fname, char *defname, void **retctx ); * int bkf_close ( void *ctx ); * char *bkf_last_error ( void *ctx ); * int bkf_read ( void *ctx, file_address *rfa, *bufaddr, *length ); * int bkf_read_page ( void *ctx, id, *page_length, *bufaddr, *length ); * int bkf_lookup_section ( void *ctx, int sect-id, int *part ); * int bkf_lookup_first_section ( void *ctx, int sect-id, int *part, int *fsec ); * * Function values returned are VMS condition codes. specifying a * null pointer for rfa causes a sequential read. * * Author: David Jones * Date: 10-SEP-1995 */ #include <stdlib.h> #include <stdio.h> #include <ssdef.h> #include <rms.h> #include <fscndef.h> #include <string.h> #include "bookreader_recdef.h" #include "bookfile_io.h" /* verify prototypes */ int sys$open(), sys$connect(), sys$close(), sys$get(); struct rfa_context { struct FAB fab; struct RAB rab; struct XABFHC xabfhc; /* for setting network block count */ struct XABITM xabitm; /* for setting mode */ struct { short length, code; long *bufaddr, *retlen, term; } xab_itemlist; long network_block_count; int high_id; /* highest allowed id */ int superbuf_alloc; bkrdr_recptr root; /* master info rec for file (1st) */ bkrdr_recptr lrec; /* page id -> file_address mapping */ bkrdr_recptr superbuf; /* Buffer for assembling large recs */ long *secmap; /* Section id -> page id mapping */ long *first_sec; /* First section id for page */ char *ubuf; /* buffer for I/O operations */ int partcount, sectcount; /* Local, aligned copy of root page */ /* cells */ char last_error[128]; /* text describing error */ }; typedef struct rfa_context *rfactx; /* * Since opens don't have a valid context, last error for NULL ctx is global. */ static char *last_open_error = ""; char *bkf_last_error ( void *vctx ) { rfactx ctx; if ( vctx ) { ctx = (rfactx) vctx; return ctx->last_error; } else return last_open_error; } /****************************************************************************/ /* Utility routine to allocate new buffer and copy contents of existing * buffer to it */ static bkrdr_recptr duplicate_record ( bkrdr_recptr source, int length ) { bkrdr_recptr new; new = (bkrdr_recptr) malloc ( length ); if ( new ) memcpy ( new, source, length ); return new; } /****************************************************************************/ /* Close bookreader file and deallocate context structures. */ int bkf_close ( void *vctx ) { rfactx ctx; int status; ctx = (rfactx) vctx; if ( !ctx ) return SS$_BADPARAM; status = sys$close ( &ctx->fab ); if ( ctx->root ) free ( ctx->root ); if ( ctx->lrec ) free ( ctx->lrec ); if ( ctx->secmap ) free ( ctx->secmap ); if ( ctx->ubuf ) free ( ctx->ubuf ); if ( ctx->superbuf_alloc > 0 ) free ( ctx->superbuf ); free ( ctx ); return status; } /****************************************************************************/ /* Open bookreader file and initialize context structures. * Arguments: * fname Name of bookreader file. * defname Default file specification, if NULL, will use * decw$book:.decw$book. * retctx Address of opaque pointer. */ int bkf_open ( char *fname, char *defname, void **retctx ) { rfactx ctx; bkrdr_recptr currec; int status, length; char default_name[128]; /* * Allocate and initialize context structures. */ last_open_error = ""; /* clear previous error */ *retctx = (void *) 0; ctx = (rfactx) malloc ( sizeof(struct rfa_context) ); if ( !ctx ) return 0; ctx->fab = cc$rms_fab; ctx->rab = cc$rms_rab; ctx->xabfhc = cc$rms_xabfhc; ctx->network_block_count = 127; ctx->high_id = 0; ctx->partcount = 0; ctx->sectcount = 0; ctx->superbuf_alloc = 0; ctx->root = (bkrdr_recptr) 0; ctx->lrec = (bkrdr_recptr) 0; ctx->ubuf = (char *) 0; ctx->fab.fab$l_fna = fname; ctx->fab.fab$b_fns = strlen(fname); if ( defname ) { ctx->fab.fab$l_dna = defname; ctx->fab.fab$b_dns = strlen ( defname ); } else { strcpy ( default_name, "DECW$BOOK:.DECW$BOOK" ); ctx->fab.fab$l_dna = default_name; ctx->fab.fab$b_dns = strlen(default_name); } ctx->fab.fab$b_shr = FAB$M_SHRGET; ctx->fab.fab$l_xab = (char *) &ctx->xabfhc; ctx->fab.fab$b_rtv = -1; /* retrieval window size */ ctx->xabfhc.xab$l_nxt = (char *) &ctx->xabitm; memset ( &ctx->xabitm, 0, sizeof(ctx->xabitm) ); ctx->xabitm.xab$b_cod = XAB$C_ITM; ctx->xabitm.xab$b_bln = XAB$K_ITMLEN; ctx->xabitm.xab$l_itemlist = (char *) &ctx->xab_itemlist; ctx->xabitm.xab$b_mode = XAB$K_SETMODE; ctx->xab_itemlist.length = sizeof(ctx->network_block_count); ctx->xab_itemlist.code = XAB$_NET_BLOCK_COUNT; ctx->xab_itemlist.bufaddr = &ctx->network_block_count; ctx->xab_itemlist.retlen = (long *) 0; ctx->xab_itemlist.term = 0; ctx->rab.rab$l_fab = &ctx->fab; ctx->rab.rab$b_rac = RAB$C_RFA; ctx->rab.rab$l_rop = RAB$M_LOC | RAB$M_RAH; /* locate mode and read-ahead*/ ctx->rab.rab$b_mbc = 127; /* multi-block count */ /* * Open file and connect record stream. */ status = sys$open ( &ctx->fab ); if ( (status&1) == 1 ) { if ( ctx->xabfhc.xab$w_lrl == 0 ) { ctx->rab.rab$w_usz = 32767; } else { ctx->rab.rab$w_usz = ctx->xabfhc.xab$w_lrl; } status = sys$connect ( &ctx->rab ); if ( (status&1) == 0 ) { last_open_error = "Error in SYS$CONNECT call"; sys$close ( &ctx->fab ); free ( ctx ); ctx = (rfactx) 0; } } else { last_open_error = "Error in SYS$OPEN call"; free ( ctx ); ctx = (rfactx) 0; } *retctx = (void *) ctx; if ( !ctx ) return status; /* * The FHC XAB on the open retrieved the longest record length (LRL) of * the file. Allocate a buffer. */ ctx->secmap = (long *) 0; ctx->ubuf = malloc ( ctx->rab.rab$w_usz ); /* * Read the initial page, this if first record in file so read sequentially. */ status = bkf_read ( (void *) ctx, BKF_NEXT_REC, &currec, &length ); if ( (status&1) == 1 ) { ctx->root = duplicate_record ( currec, length ); if ( !ctx->root ) return SS$_INSFMEM; ctx->partcount = ctx->root->first.partcount; ctx->sectcount = ctx->root->first.sectioncount; /* * Do sanity checks on root record and read last record. */ status = bkf_read ( (void *) ctx, &ctx->root->first.lastptr, &currec, &length ); if ( (status&1) == 1 ) { ctx->lrec = duplicate_record ( currec, length ); /* * Do sanity checks of last record and set page id limit. */ ctx->high_id = ((length - 6) / sizeof(ctx->lrec->last.dir[1])) - 1; } } return status; } /****************************************************************************/ /* Read RMS record from bookreader file. */ int bkf_read ( void *vctx, struct file_address *rfa, bkrdr_recptr *bufaddr, int *length ) { int status; rfactx ctx; ctx = (rfactx) vctx; if ( rfa ) { /* direct read to specified rfa */ ctx->rab.rab$b_rac = RAB$C_RFA; ctx->rab.rab$w_rfa[0] = rfa->wrd[0]; ctx->rab.rab$w_rfa[1] = rfa->wrd[1]; ctx->rab.rab$w_rfa[2] = rfa->wrd[2]; } else { /* Read sequentially */ ctx->rab.rab$b_rac = RAB$C_SEQ; } ctx->rab.rab$l_ubf = (char *) ctx->ubuf; status = sys$get ( &ctx->rab ); if ( (status&1) ) { *bufaddr = (bkrdr_recptr) ctx->rab.rab$l_rbf; *length = ctx->rab.rab$w_rsz; } else { *bufaddr = (bkrdr_recptr) ""; *length = 0; } return status; } /************************************************************************/ int bkf_read_page ( void *vctx, int id, int *page_length, bkrdr_recptr *bufaddr, int *length ) { int status, i; rfactx ctx; ctx = (rfactx) vctx; /* * Do limit checks on requested ID. */ if ( id < 0 || id > ctx->high_id ) { strcpy ( ctx->last_error, "Bad page number" ); return SS$_BADPARAM; } /* * Locate record from directory in the lrec. */ *page_length = ctx->lrec->last.dir[id].size; if ( id == 0 ) { /* We already have a copy of the root page, return it */ status = 1; *length = *page_length; *bufaddr = ctx->root; } else { /* * Read initial record. */ status = bkf_read ( vctx, &ctx->lrec->last.dir[id].rfa, bufaddr, length ); if ( (status&1) == 0 ) return status; /* * If page is larger than requested, assemble into large buffer. */ if ( *length < *page_length ) { /* * Allocate oversize buffer to accomodate whole thing. */ if ( ctx->superbuf_alloc < *page_length ) { if ( ctx->superbuf_alloc > 0 ) { free ( ctx->superbuf ); ctx->superbuf_alloc = 0; } ctx->superbuf = malloc ( *page_length + 15000 ); if ( !ctx->superbuf ) return SS$_INSFMEM; ctx->superbuf_alloc = *page_length + 15000; } /* * Copy peices into superbuf. */ memcpy ( ctx->superbuf->raw, (*bufaddr)->raw, *length ); for ( i = *length; i < *page_length; i += *length ) { /* * Last 10 chars of superbuf record should be rfa next record. * Just assume sequential read will do. */ status = bkf_read ( vctx, BKF_NEXT_REC, bufaddr, length ); if ( (status&1) == 0 ) return status; if ( ((*bufaddr)->gen.type == BKREC_CONT_END) || ((*bufaddr)->gen.type == BKREC_CONT_MID) ) { /* * Adjust state to trim tail off of superbuf and header * off of bufaddr. */ i = i - 10; *length = *length - 6; } else { break; /* unexpected record type */ } memcpy ( &ctx->superbuf->raw[i], (*bufaddr)->raw+6, *length ); } /* * update values. */ *bufaddr = ctx->superbuf; *length = ctx->superbuf->gen.length = *page_length; } } return status; } /***************************************************************************/ /* Convert section number to part number. */ int bkf_lookup_section ( void *vctx, int sect_id, int *part ) { int status, i, j, start, startpage, page, length, page_length; rfactx ctx; bkrdr_recptr tmp; ctx = (rfactx) vctx; if ( sect_id > ctx->sectcount ) return SS$_BADPARAM; if ( sect_id < 0 ) return SS$_BADPARAM; if ( !ctx->secmap ) { /* do initial load */ status = bkf_read_page ( vctx, ctx->root->first.index_page, &page_length, &tmp, &length ); if ( (status&1) == 0 ) return status; if ( tmp->gen.type != BKREC_SECMAP ) return SS$_BUGCHECK; i = (length - sizeof(tmp->gen)) / sizeof(tmp->secmap.map[1]); if ( i-1 != ctx->sectcount ) return SS$_BUGCHECK; /* * build our own secmap aligned. Negative numbers in map * are offset to entry for first section on that page. */ ctx->secmap = (long *) malloc ((i+ctx->partcount+1) * sizeof(long)); if ( !ctx->secmap ) return SS$_INSFMEM; ctx->first_sec = &ctx->secmap[i]; /* first sections */ for ( j = 0; j <= ctx->partcount; j++ ) ctx->first_sec[j] = -1; for ( j = 0; j < i; j++ ) { page = tmp->secmap.map[j]; #ifdef DEBUG printf("/bki/ secmap[%d] = %d\n", j, page ); #endif ctx->secmap[j] = page; if ( page < 0 || page > ctx->partcount ) { printf("secmap[%d] = %d is out of range\n", j, page ); return SS$_BUGCHECK; } else if ( ctx->first_sec[page] < 0 ) { ctx->first_sec[page] = j; /* first section of page */ } } } *part = ctx->secmap[sect_id]; return 1; } int bkf_lookup_first_section ( void *vctx, int sect_id, int *part, int *first ) { int status, page; rfactx ctx; ctx = (rfactx) vctx; if ( sect_id > ctx->sectcount ) return SS$_BADPARAM; if ( sect_id < 0 ) return SS$_BADPARAM; if ( !ctx->secmap ) { /* do initial load */ status = bkf_lookup_section ( vctx, sect_id, part ); if ( (status&1) == 0 ) return status; } page = ctx->secmap[sect_id]; *first = ctx->first_sec[page]; *part = page; return 1; } int bkf_lookup_part_section ( void *vctx, int part_id, int *first ) { int status, dummy; rfactx ctx; ctx = (rfactx) vctx; if ( part_id > ctx->partcount ) return SS$_BADPARAM; if ( part_id < 0 ) return SS$_BADPARAM; if ( !ctx->secmap ) { /* do initial load */ status = bkf_lookup_section ( vctx, 1, &dummy ); if ( (status&1) == 0 ) return status; } *first = ctx->first_sec[part_id]; return 1; }