[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]
/* * Define routines for handling indices * * int bki_create_context ( void *bkfctx, void **context ); * int bki_delete_context ( void *ctx ); * int bki_find_index ( void *ctx, char *pattern, int pat_type, * char name[256], int *type, int *count); * int bki_find_index_end ( void *ctx ) * * int bki_open_index ( void *ctx, char *name ); * int bki_read_index ( void *ctx, char name[256] ); * int bki_close_index ( void *ctx ); */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ssdef.h> #include "bookreader_recdef.h" #include "bookfile_io.h" #include "bookfile_index.h" /* validate prototypes */ struct index_context { void *bkf; /* bkf_open context for doing I/O */ bkrdr_recptr root; /* pointer to root part for file */ bkrdr_recptr cur; /* Current open index page */ int cur_alloc; /* Allocation size of cur */ int offset; /* Current read offset in cur */ int find_context; /* Offset for find_index */ }; typedef struct index_context *bkictx; static bkrdr_recptr lookup_index ( bkictx ctx, char *name ); /* fwd ref */ static int strmatchwild ( char *cand, char *pattern ); int bki_create_context ( void *bkf, void **context ) { bkictx ctx; int status, page_length, length; /* * allocate context block. */ ctx = (bkictx) malloc ( sizeof(struct index_context) ); if ( !ctx ) return SS$_INSFMEM; ctx->bkf = bkf; ctx->cur_alloc = 0; ctx->offset = 0; ctx->find_context = 0; /* * Make local copy of pointer to root part of file (part 0). We assume * bkf_read returns address of a static structure for part 0. */ status = bkf_read_page ( bkf, 0, &page_length, &ctx->root, &length ); *context = (void *) ctx; return status; } int bki_delete_context ( void *context ) { bkictx ctx; /* * Deallocate any structures and sub-structures allocated. */ ctx = (bkictx) context; if ( ctx->cur_alloc > 0 ) { free ( ctx->cur ); ctx->cur_alloc = 0; } free ( ctx ); return 1; } /*****************************************************************************/ /* Scan indexes listed in the root part for index with matching name(s). */ int bki_find_index ( void *context, char *pattern, int pat_type, char name[256], int *type, int *count ) { bkictx ctx; bkrdr_recptr root, subrec; int status, has_wild, i; ctx = (bkictx) context; root = ctx->root; /* * See if find_index is in progress. */ if ( ctx->find_context == 0 ) { /* * Start new search, Examine for wildcards. */ for ( i = has_wild = 0; pattern[i]; i++ ) if ( pattern[i] == '*' || pattern[i] == '%' ) { has_wild = 1; break; } if ( pat_type == -1 ) has_wild = 1; if ( has_wild ) { /* Set find_context to offset of first sub-record */ ctx->find_context = sizeof(root->first); } else { /* Do direct match */ subrec = lookup_index ( ctx, name ); if ( !subrec ) return 0; *type = subrec->table.keyid; *count = subrec->table.count; strncpy ( name, subrec->table.title, subrec->table.tit_len ); return 1; } } /* * Continue search. */ for ( i = ctx->find_context; i < root->gen.length; i += subrec->gen.length ) { subrec = (bkrdr_recptr) &root->reloff[i]; if ( subrec->gen.length <= 0 ) break; /* invalid subrec */ /* * Test only the table header records. */ if ( subrec->gen.type == BKSBREC_TABLE ) { if ( pat_type >= 0 ) /* make sure type matches */ if ( pat_type != subrec->table.keyid ) continue; if ( 0 == strmatchwild ( subrec->table.title, pattern ) ) { *type = subrec->table.keyid; *count = subrec->table.count; strncpy ( name, subrec->table.title, subrec->table.tit_len ); name[subrec->table.tit_len] = '\0'; ctx->find_context = i + subrec->gen.length; return 1; } } } /* * No more entires. */ ctx->find_context = i; return 2; } /* * Return pointer to matching index record. */ static bkrdr_recptr lookup_index ( bkictx ctx, char *name ) { bkrdr_recptr subrec, root; int i, namlen; root = ctx->root; namlen = strlen ( name ) + 1; /* * Scan subrecords of root. */ for ( i = sizeof(root->first); i < root->gen.length; i+= subrec->gen.length ) { subrec = (bkrdr_recptr) &root->reloff[i]; if ( subrec->gen.length <= 0 ) break; /* * Check table records found for matching name. */ if ( subrec->gen.type == BKSBREC_TABLE ) { if ( subrec->table.tit_len == namlen ) if ( 0==strncmp(subrec->table.title, name, namlen)) return subrec; } } return (bkrdr_recptr) 0; } /**************************************************************************/ /* Reset find context. */ int bki_find_index_end ( void *context ) { bkictx ctx; ctx = (bkictx) context; ctx->find_context = 0; return 1; } /************************************************************************/ /* Emulate VMS wildcard matching routine for c strings. Algorithm obtained * by decoding VAX version of STR$MATCH_WILD. A successful match returns * 0 to correspond with success status of tu_strncmp() routine. */ #define WC_FAIL 1 #define WC_MATCH 0 static int strmatchwild ( char *cand, char *pattern ) { char *save_cand, *save_pattern; /* * Main loop, check each character in pattern string. */ for ( save_cand = (char *) 0; *pattern; pattern++ ) { if ( *pattern == '*' ) { /* * Wildcard character, if it is last character in pattern we know * we have match. */ if ( pattern[1] == '\0' ) return WC_MATCH; /* * checkpoint the current position of * both strings so we can resume at the succeeding candidate * string character if substring starting at current position * fails. */ save_cand = cand; save_pattern = pattern; } else if ( *cand++ != *pattern ) if ( *pattern != '%' ) { /* * Characters did not match, if no '*'s in preceding pattern, * then strings do not match. */ if ( !save_cand ) return WC_FAIL; /* * Resume search at next candidate character, updating * the candidate checkpoint position. If no more characters, * then strings do not match. */ if ( *save_cand++ == '\0' ) return WC_FAIL; cand = save_cand; pattern = save_pattern; } } /* * If pattern matched to this point, we succeed if candidate also at end. */ if ( *cand == '\0' ) return WC_MATCH; return WC_FAIL; } /**************************************************************************/ int bki_open_index ( void *context, char *name ) { bkictx ctx; bkrdr_recptr tblrec, ndxrec; int status, page_length, length; /* * Lookup index. */ ctx = (bkictx) context; tblrec = lookup_index ( ctx, name ); if ( !tblrec ) return 0; /* * read page and make copy. */ status = bkf_read_page ( ctx->bkf, tblrec->table.part, &page_length, &ndxrec, &length ); if ( (status&1) == 0 ) return status; if ( ndxrec->gen.type != BKREC_INDEX ) return SS$_BUGCHECK; if ( ctx->cur_alloc <= page_length ) { /* Allocate buffer */ if ( ctx->cur_alloc > 0 ) { ctx->cur_alloc = 0; free ( ctx->cur ); } ctx->cur = (bkrdr_recptr) malloc ( page_length + 15000 ); if ( !ctx->cur ) return SS$_INSFMEM; ctx->cur_alloc = page_length + 15000; } memcpy ( ctx->cur, ndxrec, page_length ); ndxrec = ctx->cur; /* * Initalize offset. */ ctx->offset = sizeof(ndxrec->gen); return 1; } int bki_close_index ( void *context ) { bkictx ctx; ctx = (bkictx) context; ctx->offset = 0; return 1; /* nothing to do */ } /****************************************************************************/ /* Read table index entry and current offset and return data to caller. */ int bki_read_index ( void *context, short hdr[9], /* Index entry attributes + hor,ver of name */ unsigned char attr[4], /* Fontno, x, y, length of name */ char name[256], /* Entry name */ char **desc, /* Display descricption. */ long *value ) /* Section number or special value */ { bkictx ctx; bkrdr_recptr ndxrec, subrec; struct text_rec *trec; int status, offset, i, j, sublen, namlen; long *vptr; /* * Recover context and do consitency checks. */ ctx = (bkictx) context; offset = ctx->offset; if ( offset <= 0 ) return SS$_BADPARAM; ndxrec = ctx->cur; if ( offset >= ndxrec->gen.length ) return SS$_NOMOREFILES; /* * Look at record record at current offset, update offset used for * next read. */ subrec = (bkrdr_recptr) &ndxrec->reloff[offset]; if ( subrec->gen.type != BKSBREC_IXTXT ) return SS$_BUGCHECK; ctx->offset = offset + subrec->gen.length; /* * Copy fixed portion of ixtxt record to caller's arguments and initialize * variable portion to null values. */ for ( i = 0; i < 7; i++ ) hdr[i] = subrec->ixtxt.ixhdr[i]; hdr[7] = hdr[8] = 0; namlen = 0; name[0] = '\0'; *desc = ""; *value = 0; attr[0] = attr[1] = attr[2] = attr[3] = 0; /* * Scan text subrecords. */ for ( i = sizeof(subrec->ixtxt); i < subrec->gen.length; i += sublen ) { trec = (struct text_rec *) &subrec->reloff[i]; sublen = trec->reclen; switch ( trec->type ) { case 1: break; case 2: case 3: /* * Contcatenate strings. Save attributes on first string only. */ j = sublen - sizeof(struct text_rec) + sizeof(trec->data); if ( namlen == 0 ) { hdr[7] = trec->hor; hdr[8] = trec->ver; attr[0] = trec->fontno; attr[1] = trec->x; attr[2] = trec->y; } if ( (namlen + j) < 254 ) { if ( namlen != 0 ) name[namlen++] = '\0'; /* fake word boundary */ memcpy ( &name[namlen], trec->data, j ); namlen += j; name[namlen] = '\0'; } attr[3] = namlen; break; default: /* * Assume this is description following name. */ *desc = &subrec->reloff[i]; vptr = (long *) &subrec->reloff[i+strlen(*desc)+1]; *value = *vptr; sublen = 0; i = subrec->gen.length; /* force loop exit */ break; } } return 1; }