/* this file composed by Klaus Ripke from the iAPI files by Robert Janusz. this is the test app "ix.c" with all the includes slurped in, see // #include "isomething.c" you may run this with: cp iAPI.txt iAPI.c gcc iAPI.c ./a.out */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ iAPI software: The Example of ISIS (UNIX v.3) Database Handle Copyright (C) 2000 by Robert Janusz E-mail: rj@jezuici.krakow.pl Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ // Linux gcc Compiler conventions ! #include #include #include #include // Global variables +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ static char DBpath [71]; char UpCase [256]; #define NFIND 3 // let's keep it for future #define PACKED __attribute__((packed)) // it shoud work on Linux gcc ;-) // #include "idef.c" /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ iAPI software: The Type Definitions for Unix-ISIS databases Copyright (C) 2000 by Robert Janusz E-mail: rj@jezuici.krakow.pl Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ // gcc Linux Compiler conventions ! // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures // *************************** TYPE DEFINITIONS ***************************** // Cross Reference File XRF structure +++++++++++++++++++++++++++++++++++++++ typedef /* Packed */ struct // /* Packed */ and order are necessary for block reading { long int xpos PACKED; // Block nr: 1, 2...; < 0: last block long int xrec [127] PACKED; // References to Master File records... // xrec [...] = 2048 *xrmfb [21 bit] & xrmfp [11 bit] // rec. deleted log. < 0 & > 0 (restore: -xrmfb) // rec. deleted phis. =-1 & = 0 (ref@MST.ctrl) // rec. does not exist = 0 & = 0 // new rec. to invert bit 1024 = 1 // rec. edited to inv. (add & del post.) bit 512 = 1 } xrfBlock; // Master File (MST) record structures... +++++++++++++++++++++++++++++++++++ typedef /* Packed */ struct // The first record in Master File { long int ctlmfn PACKED // Always 0 , nxtmfn PACKED // Next Master File Number , nxtmfb PACKED; // Next block in Master File, the 1st has 1 short int nxtmfp PACKED // Next position in the last block , mftype PACKED; // 0 for user's bases; 1 for messages long int reccnt PACKED // Reserved for future , mfcxx1 PACKED // Reserved for future , mfcxx2 PACKED // LAN, > 0: inversion, update not possible , mfcxx3 PACKED; // LAN, = 1: exists exclusive user } mstControl; typedef /* Packed */ struct // Fixed part of record header that must be... { // included in the same block; // the header can begin only on 0, 2, 4...498 long int mfn PACKED; // MFN number short int mfrl PACKED; // Length of record (allways eaven)... // LAN: < 0 ==> record blocked long int mfbwb PACKED; // Block Pointer | If the record waits for inv... short int mfbwp PACKED; // Position Pointer | ...ref. to old location // mfbwb, mfbwp: = 0 at creation; // after modif. = ref to the old record. // xrmfp bit 1024 = 1 at creation // (= waits to be inverted); // xrmfp bit 512 = 1 at edit // (=waits to be inv. & delete old references) } mstHdrFix; typedef /* Packed */ struct { short int base PACKED // Position of data fields in the record , nvf PACKED // Number of fields in the record , status PACKED; // 0 = active, 1 = deleted logicaly (- xrfb < 0) } mstHdrTxt; typedef /* Packed */ struct { mstHdrFix mhf PACKED; // This header is allways in MST file block mstHdrTxt mht PACKED; } RecHeaders; typedef /* Packed */ struct // Index for every field in the record { // dimension = 6 *nvf; base = 18 + 6 *nvf short int tag PACKED // Label of the field , pos PACKED // Position of the first char in data part: 0, 1... , len PACKED; // Length of the field } mstIndex; // Inverted File structures +++++++++++++++++++++++++++++++++++++++++++++++++ // Control File (CNT) structure.............................................. typedef /* Packed */ struct { short int idtype PACKED // B*tree type; 1 = N01/L01, 2 = N02/L02 , ordn PACKED // = 5; a half of size of key-record in N0x , ordf PACKED // = 5; a half of size of key-record in L0x , n PACKED // = 15; number of buffers for nodes , k PACKED // = 5; number of buffers for 1st index level (k < n) , lev PACKED; // Current number of levels in index; -1: no N0x long int posrx PACKED // Reference to the root in N0x , nmaxpos PACKED // Next record in N0x , fmaxpos PACKED; // Next record in L0x short int abnormal PACKED; // 0: N0x has only the root } cntBlock; // Index of Dictionary (N0x) structures...................................... typedef /* Packed */ struct { long int pos PACKED; // Number of record short int ock PACKED // Number of active keys in the record: 1, 2, 3...2*ordn , it PACKED; // B*tree type } nodeHeader; typedef /* Packed */ struct { char key [10] PACKED; long int ref PACKED; // > 0: reference to next node; // < 0: ref. to leaf: idx [1st].key = key // = 0: inactive } nodeIndex1; typedef /* Packed */ struct { char key [30] PACKED; long int ref PACKED; } nodeIndex2; typedef /* Packed */ struct { nodeHeader hdr PACKED; nodeIndex1 idx [10] PACKED; // Vector of 2*ordn elements } nodeBlock1; typedef /* Packed */ struct { nodeHeader hdr PACKED; nodeIndex2 idx [10] PACKED; // Vector of 2*ordn elements } nodeBlock2; typedef /* Packed */ union { nodeBlock1 nb1 PACKED; nodeBlock2 nb2 PACKED; } nodeBlock; // Leaf File (L0x) structures (all index terms).............................. typedef /* Packed */ struct { long int pos PACKED; // Number of leaf record: 1, 2... short int ock PACKED // Number of active keys in the record: 1..2*ordf , it PACKED; // = 1 for L01; = 2 for L02 long int ps PACKED; // Next record in the order: key [ock] < ps^ idx [1st].key } leafHeader; typedef /* Packed */ struct { char key [10] PACKED; short int xxx PACKED; // *** ONLY UNIX ISIS; long int infb PACKED // Reference to IFP segment *** != ISIS.MANUAL *** , infp PACKED; } leafKey1; typedef /* Packed */ struct { char key [30] PACKED; short int xxx PACKED; // *** ONLY UNIX ISIS; long int infb PACKED // Reference to IFP segment *** != ISIS.MANUAL *** , infp PACKED; } leafKey2; typedef /* Packed */ struct { leafHeader hdr PACKED; leafKey1 idx [10] PACKED; // 2*ordf keys } leafBlock1; typedef /* Packed */ struct { leafHeader hdr PACKED; leafKey2 idx [10] PACKED; // 2*ordf keys } leafBlock2; typedef /* Packed */ union { leafBlock1 lb1 PACKED; leafBlock2 lb2 PACKED; } leafBlock; // Inverted File Posting structures.......................................... // ordained postings organized in segments: Index --> Master File typedef /* Packed */ struct { long int ifblk PACKED // Number of block , ifrec [127] PACKED; // Vector of long int *** != ISIS.MANUAL *** // In 1st block ifrec [1st/2nd] = next pos. in IFP } ifpBlock; typedef /* Packed */ struct // This header and 1st posting - always in IFP block { long int ifpnxtb PACKED // Pointer to the next segment: 1, 2... | = 0: last seg. , ifpnxtp PACKED // 0, 1... | = 0: last seg. , ifptotp PACKED // Tot. number of postings (o.k. only in the 1st segment) // = Sum (segment=1, nseg; ifpsegp) , ifpsegp PACKED // Number of postings in this segment , ifpsegc PACKED; // Max. number of postings in this segment (<= 32768) } ifpHeader; // ifpHeader & 1st ifpPosting always in the same ifpBlock // Postings in Segment are always in chain of IFP blocks typedef /* Packed */ struct // Stored left-->right + 0 --> 8 char { long int pmfn PACKED; // First 3 bytes --> Master File short int ptag PACKED; // Field ident - according to File Selection Table (FST) char pocc PACKED; // Number of occurence of the field short int pcnt PACKED; // Counter of the termin inside the field } ifpPosting; typedef struct { int opened; // Which files are opened (bit spec.)... FILE *mst; // 1 FILE *xrf; // 2 FILE *ifp; // 4 FILE *n01; // 8 FILE *l01; // 16 FILE *n02; // 32 FILE *l02; // 64 mstControl mctrl; // MST ctrl record cntBlock cnt1, cnt2; // Inv. Files ctrl records long int ibm, ipm; // IFP new Segment Bock/Pos char name [72]; // Database name } BaseCtrl; typedef struct // This structer must be allways corelated with BaseCtrl { char st [31]; // Max. string to find short int v; // Field to find; 0: all fields short int it; // Type of B*Tree <== strlen (st) leafBlock lbl; // Block L0x with index terms short int ilk; // Position of term in lbl...idx char *term; // The term in lbl...idx long int ib, ip; // Number of block/position for IFP ifpBlock ibl; // Block IFP with posting/s ifpHeader ihd; // Header for Segment of postings long int iiseg; // Number of posting in current Segment (index) long int iitot; // Number of posting in total (index) long int iall; // Number of posting in all Segments char *ipst; // Ref. to last posting string [8 chars] cntBlock *cntr; // BaseCtrl.cntr1/2 <== it FILE *n0x; // N01 or N02 <== it, = BaseCtrl.n0x FILE *l0x; // L01 or L02 <== it, = BaseCtrl.l0x } TableQuery; #define RECLENGTH 8192 typedef union { char buf [RECLENGTH]; RecHeaders hdrs; } RecCtrl; // *** MAIN DATABASE FILE RELATIONS (MST <--> XRF) *** // 1 2 3 // MST |-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|... // ctrl |----record----| // |--->| // 1 2 3 | pointer: B/P (P in [0, 2, 4... 498]) // XRF |-xblk-|-xblk-|-xblk-|... // MFN= 1... 128... 255... // Record |-->-pos->--| // |-mhf-mht-|-idx[1]...idx[nvf]-|---text...---| // |-------------- record buffer --------------| // *** INVERTED FILE RELATIONS (N0x <--> L0x <-->IFP) *** // N0x |-nbl-|-nbl-|-nbl-|-nbl-|-nbl-|-nbl-|... // -->-root->-| |-->--next-->--| |->-->-| r<0 // | // L0x |--lbl--|--lbl--|--lbl--|--lbl--|--lbl--|--lbl--|... // | // |-<--------------<-------------<-| r<0 // *** POSTING *** | // IFP |---ibl---|---ibl---|---ibl---|---ibl---|---ibl---|---ibl---|... // |next |-ihd-|---Segment---| |-ihd-|---Segment---| // |Seg. |-->------>------>-next->--| |||... // MFN... // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // #include "idef.c" // Let's specify non int header ;-) just to keep order void ShowRec (RecCtrl *rc); void setQuery (BaseCtrl *bc, TableQuery *tq, char *sx, short int fld); void isis (); // #include "iutil.c" /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ iAPI software: The UTIL procedures for Unix-ISIS databases Copyright (C) 2000 by Robert Janusz E-mail: rj@jezuici.krakow.pl Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ // gcc Linux Compiler conventions ! // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int ReadMem (void *ptr, FILE *f, long int nr, long int size) { // Read "nr"'s block of size "size" from file "f" into "ptr"... if (fseek (f, nr * size, SEEK_SET) != 0) return (-1); if (fread (ptr, size, 1, f) == 0) return (-2); return (0); // O.K. } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void doUpcase (char *s, char *st, int slen) { int i; for (i = 0; i < slen; i++) { if (i < strlen (st)) s [i] = UpCase [(int) st [i]]; else s [i] = ' '; } s [slen] = 0; } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int sComp (char *s1, char *s2, int len) { int i; for (i = 0; i < len; i++) { if (s1 [i] > s2 [i]) return (1); // .gt. if (s1 [i] < s2 [i]) return (-1); // .lt. } return (0); // .eq. } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int bfOpen (FILE **f, BaseCtrl *bc, char *ext, char *opt) { char st [81]; if (strlen (bc->name) + strlen (ext) > 80) return (-2); strcpy (st, bc->name); strcat (st, ext); if ((*f = fopen (st, opt)) == NULL) return (-1); return (0); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int InitBase (BaseCtrl *bc) // Error return: -1 base file/s; -2 inv. file/s; -3 mst. ctrl rec/s; // -4 cnt param/s; -5 ifp param/s { ifpBlock ib; bc->opened = 0; if (bfOpen (&bc->mst, bc, ".MST", "rb") != 0) return (-1); bc->opened += 1; // MST opened if (bfOpen (&bc->xrf, bc, ".XRF", "rb") != 0) return (-1); bc->opened += 2; // XRF opened if (bfOpen (&bc->ifp, bc, ".CNT", "rb") != 0) return (-2); if (fread (&bc->cnt1, sizeof (cntBlock), 1, bc->ifp) == 0 || fread (&bc->cnt2, sizeof (cntBlock), 1, bc->ifp) == 0) return (-2); if (fclose (bc->ifp) != 0) return (-3); if (bfOpen (&bc->ifp, bc, ".IFP", "rb") != 0) return (-2); bc->opened += 4; // IFP opened if (bfOpen (&bc->n01, bc, ".N01", "rb") != 0) return (-2); bc->opened += 8; // N01 opened if (bfOpen (&bc->l01, bc, ".L01", "rb") != 0) return (-2); bc->opened += 16; // L01 opened if (bfOpen (&bc->n02, bc, ".N02", "rb") != 0) return (-2); bc->opened += 32; // N02 opened if (bfOpen (&bc->l02, bc, ".L02", "rb") != 0) return (-2); bc->opened += 64; // L02 opened if (fread (&bc->mctrl, sizeof (mstControl), 1, bc->mst) == 0) return (-3); if (bc->cnt1.ordn != 5 || bc->cnt1.ordf != 5 || bc->cnt1.n != 15 || bc->cnt1.k != 5 || bc->cnt2.ordn != 5 || bc->cnt2.ordf != 5 || bc->cnt2.n != 15 || bc->cnt2.k != 5) return (-4); if (fread (&ib, sizeof (ifpBlock), 1, bc->ifp) == 0) return (-5); if (ib.ifblk != 1) return (-5); bc->ibm = ib.ifrec [0]; bc->ipm = ib.ifrec [1]; return (0); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void Done (BaseCtrl *bc) // Close the database files { if (bc->opened && 1) fclose (bc->mst); if (bc->opened && 2) fclose (bc->xrf); if (bc->opened && 4) fclose (bc->ifp); if (bc->opened && 8) fclose (bc->n01); if (bc->opened && 16) fclose (bc->l01); if (bc->opened && 32) fclose (bc->n02); if (bc->opened && 64) fclose (bc->l02); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ char UpMe (char c) // ^A = ^a etc. { if (c > 96) c = c - 32; return (c); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void outS (char *st) { char i; if (st == NULL) return; for (i = 0; i < strlen (st); i++) // c = tblconvert [st [i]]; if (st [i] == (char) 145) printf ("<"); // This is HTML < else if (st [i] == (char) 146) printf (">"); // and that is > else printf ("%c", st [i]); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void outC (char ch) { char st [2]; st [0] = ch; st [1] = 0; outS (st); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void outD (double x, int n) { char s [80]; gcvt (x, n, s); outS (s); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void outN (long int x) // long int -> sting @ base=10 { // char st [33]; // ltoa (x, st, 10); outS (st); printf ("%li", x); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // #include "imasterf.c" /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ iAPI software: The Master File access to Unix-ISIS databases Copyright (C) 2000 by Robert Janusz E-mail: rj@jezuici.krakow.pl Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ // gcc Linux Compiler conventions ! // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int GetRec (BaseCtrl *bc, long int mfnr, RecCtrl *rc, int bufvol) { char mblk [512]; // Master File block; long int xmfb, xmfp; // Pointer to Master File (last read) record // xMfB < 0 : record deleted (status = 1), -xMfB --> block; // xMfP = 0: deleted phisicaly // = 0 & = 0: does not exist // 1st block: xMfB = 1, xMfP = 0; pointer = xMfB * 2048 + xMfP // ==> mst < 500 MBy; long int xn, xb; int ret, nch; xrfBlock xblk; mstHdrFix *hf = &rc->hdrs.mhf; mstHdrTxt *ht = &rc->hdrs.mht; char *b = rc->buf; if ((mfnr < 1) || (mfnr >= bc->mctrl.nxtmfn)) return (-2); // No record // Find the address in XRF... xn = mfnr - 1; xb = xn / 127; if (ReadMem (&xblk, bc->xrf, xb, sizeof (xrfBlock)) != 0) return (-1); xn = xblk.xrec [xn % 127]; // = address in MST xmfb = xn / 2048; // Master File Block xmfp = xn % 512; // Master File Position // Find the record in MST... if (xmfb < 1) return (1); // Record deleted ret = 0; // Record o.k. if (ReadMem (&mblk, bc->mst, xmfb - 1, sizeof (mblk)) != 0) return (-1); // Copy headers into record buffer... memcpy (b, &mblk [xmfp], sizeof (mstHdrFix)); if (hf->mfn != mfnr) return (-2); // Database corrupted if (hf->mfrl >= bufvol) return (-3); // Buffer too small // Get the rest of the record xmfp += sizeof (mstHdrFix); // Posinion in block xb = sizeof (mstHdrFix); // Position in buf xn = labs (hf->mfrl) - xb; // Number of chars to read if (xn <= 0) return (4); // No fields ?? for ( ; ; ) // We have some chars { // Find number of chars to copy from this block if (xn <= (nch = sizeof (mblk) - xmfp)) nch = xn; memcpy (b + xb, &mblk [xmfp], nch); xb += nch; xn -= nch; xmfp = 0; if (xn <= 0) break; // Nothing more to read if (fread (&mblk, sizeof (mblk), 1, bc->mst) == 0) return (-1); } if (ht->status != 0) ret = 1; // Record deleted logicaly if (hf->mfbwb != 0 || hf->mfbwp != 0) ret = 2; // Record not inv. if (hf->mfrl < 0) ret = 3; // Record blocked return (ret); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int IsF (RecCtrl *rc, short int v, char ch, char *st) { short int n, k, kk, flag; char *b = rc->buf; mstHdrTxt *mht = &rc->hdrs.mht; mstIndex *ind = (mstIndex *) &rc->buf [sizeof (RecHeaders)]; flag = 0; for (n = 0; n < mht->nvf; n++) { if (ind->tag == v) // there is a tag { if (ch == ' ') // field found { flag = 1; break; } else // there is sub-field { flag = 1; kk = 0; k = mht->base + ind->pos; while (b [k] != '^' || b [k + 1] != ch) // convention ;-) { k += 1; kk += 1; if (kk >= ind->len) // out of field return (0); } break; } } ind += 1; // next index ref. } if (flag == 0) return (0); // false if (st == NULL) return (1); // true else if (sComp (&b [mht->base + ind->pos], st, ind->len) == 0) return (1); else return (0); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void RepF (RecCtrl *rc, char nf, ...) // Repeated "nf" fields in record "rc", the left label appears only if: // - begins with "\n", - there was another field and there is defined // filed; the right label appears only if ther was defined field. { va_list pinfo; // for ... parameter list int i, c, flag, n, k, kk, v; int hit = 0; char *sl, *sr; char *b = rc->buf; mstHdrTxt *mht = &rc->hdrs.mht; mstIndex *ind = (mstIndex *) &rc->buf [sizeof (RecHeaders)]; for (n = 0; n < mht->nvf; n++) { va_start (pinfo, nf); for (i = 0; i < nf; i++) { kk = 0; k = mht->base + ind->pos; sl = va_arg (pinfo, char *); // left v = va_arg (pinfo, short int); // field c = va_arg (pinfo, char); // sub-field c = UpMe (c); sr = va_arg (pinfo, char *); // right if (v != ind->tag) // another Tag break; if (c != ' ') // sub-field { flag = 1; while (b [k] != '^' || UpMe (b [k + 1]) != c) // convention ;-) { k += 1; kk += 1; if (kk >= ind->len) { flag = 0; break; } } if (flag) { k += 2; kk += 2; } } else flag = 1; if (flag) { // Reference to NULL = NW error !!! if (sl == NULL) flag = 0; else if (*sl == '\n') flag = 1; else flag = 0; if (hit != 0 || flag) outS (sl); hit += 1; if (c == ' ') while (kk < ind->len) { if (b [k] != '<' && b [k] != '>') // HTML special ;-) outC (b [k]); k += 1; kk += 1; } else while (kk < ind->len && b [k] != '^') // convention ;-) { if (b [k] != '<' && b [k] != '>') // HTML special ;-) outC (b [k]); k += 1; kk += 1; } outS (sr); } } va_end (pinfo); ind += 1; } } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // #include "iinvterm.c" /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ iAPI software: The Inv. File Terms access for Unix-ISIS databases Copyright (C) 2000 by Robert Janusz E-mail: rj@jezuici.krakow.pl Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ // gcc Linux Compiler conventions ! // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int FindFirst (TableQuery *tq) { short int i, j // Indexes for idx [] , srec, klen, sidx; // Size (rec), key length, size (idx) long int r; // Reference (record number); < 0: --> L0x --> IFP char *ref; leafHeader *lhdr = &tq->lbl.lb1.hdr; // = ...lb2.hdr nodeBlock nbl; nodeHeader *nhdr = &nbl.nb1.hdr; // = ...nb2.hdr if (tq->it == 1) { klen = 10; srec = sizeof (nodeBlock1); sidx = sizeof (nodeIndex1); } else { klen = 30; srec = sizeof (nodeBlock2); sidx = sizeof (nodeIndex2); } r = tq->cntr->posrx; // Root in N0x while (r > 0L) { if (ReadMem (&nbl, tq->n0x, r - 1, srec) != 0) return (-1); j = nhdr->ock; if (nhdr->pos != r || nhdr->it != tq->it || j < 1 || j > 10) return (-3); // 10 = 2*ordn ref = (char *) &nbl.nb1.idx; // Reference to first elem. of index ref += sidx; // The first key is allways <= st, skip it for (i = 1; i < j; i++) if (sComp (ref, tq->st, klen) > 0) break; else ref += sidx; ref -= sidx; // Correct value r = *(long int *) (ref + klen); // We have the "ref" value if (r > tq->cntr->nmaxpos) return (-3); // Out of N0x } // Now find the term in L0x index if (tq->it == 1) { srec = sizeof (leafBlock1); sidx = sizeof(leafKey1); } else { srec = sizeof(leafBlock2); sidx = sizeof(leafKey2); } r = - r; if (ReadMem (&tq->lbl, tq->l0x, r - 1, srec) != 0) return (-1); j = lhdr->ock; if (lhdr->pos != r || lhdr->it != tq->it || j < 1 || j > 10) return (-2); // 10 = 2*ordf tq->ilk = 0; ref = (char *) &tq->lbl.lb1.idx; // Reference to first elem. of index ref += sidx; // The first key is allways <= s, skip it for (i = 1; i < j; i++) if (sComp (ref, tq->st, klen) > 0) break; else { ref += sidx; tq->ilk += 1; } ref -= sidx; tq->term = ref; // We have the term address if (tq->it == 1) ref += 12; // += 10; *** NOT UNIX else ref += 32; // += 30; *** NOT UNIX tq->ib = *(long int *) ref; // = infb ref += sizeof (long int); tq->ip = *(long int *) ref; // = infp return (0); // O.K. } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int FindNext (TableQuery *tq) { int srec; // Block size long int r; // Reference (record number); < 0: --> L0x --> IFP leafHeader *lhdr = &tq->lbl.lb1.hdr; // = ...lb2.hdr if (tq->it == 1) srec = sizeof (leafBlock1); else srec = sizeof (leafBlock2); tq->ilk += 1; // Next key in the index if (tq->ilk >= lhdr->ock) // Out of index { r = lhdr->ps; // Next L0x record in order if (r <= 0) { tq->ilk -= 1; return (1); } // Nothing more, end of index if (ReadMem (&tq->lbl, tq->l0x, r - 1, srec) != 0) return (-1); if (lhdr->pos != r || lhdr->it != tq->it || lhdr->ock < 1 || lhdr->ock > 10) return (-2); // 10 = 2*ordf tq->ilk = 0; } srec = tq->ilk; if (tq->it == 1) { tq->term = tq->lbl.lb1.idx [srec].key; tq->ib = tq->lbl.lb1.idx [srec].infb; tq->ip = tq->lbl.lb1.idx [srec].infp; } else { tq->term = tq->lbl.lb2.idx [srec].key; tq->ib = tq->lbl.lb2.idx [srec].infb; tq->ip = tq->lbl.lb2.idx [srec].infp; } return (0); // We have the new key } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int Find (BaseCtrl *bc, TableQuery tabq [], int ifind, long int *npg , RecCtrl *rc, long int recvol) { int i; if (ifind <= 0 || ifind > NFIND) return (-1); for (i = 0; i < ifind; i++) if (FindFirst (&tabq [i]) < 0) return (-1); i = Postings (bc, tabq, ifind, npg, rc, recvol); return (i); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int IndexPrep (BaseCtrl *bc, TableQuery *tq1, TableQuery *tq2, char *st) { char sx [31]; // tqx->v contains the status of L0x index int i; if (st == NULL) for (i = 0; i < 30; i++) sx [i] = ' '; else for (i = 0; i < 30; i++) if (i < strlen (st)) sx [i] = st [i]; else sx [i] = ' '; sx [30] = 0; setQuery (bc, tq2, sx, 0); // We have a long term in tq2; v := 0 if (FindFirst (tq2) < 0) return (-1); sx [10] = 0; setQuery (bc, tq1, sx, 0); // We have a short term in tq1; v := 0 if (FindFirst (tq1) < 0) return (-1); while (sComp (tq1->term, tq1->st, 10) < 0) if ((tq1->v = FindNext (tq1)) != 0) break; // At the end or error if (tq1->v < 0) return (-1); while (sComp (tq2->term, tq2->st, 30) < 0) if ((tq2->v = FindNext (tq2)) != 0) break; // At the end or error if (tq2->v < 0) return (-1); return (IndexTest (tq1, tq2)); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int IndexTest (TableQuery *tq1, TableQuery *tq2) { if (tq1->v == 1) // At the end of 1st if (tq2->v == 1) // At the end of 2nd return (0); // All done else return (2); // We have only 2nd else if (tq2->v == 1) return (1); // We have only 1st else if (sComp (tq1->term, tq2->term, 10) <= 0) return (1); else return (2); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int IndexTerm (int i, TableQuery *tq1, TableQuery *tq2) { if (i == 1) tq1->v = FindNext (tq1); // The term was in 1st else if (i == 2) tq2->v = FindNext (tq2); // The term was in 2nd else return (-1); return (IndexTest (tq1, tq2)); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void setQuery (BaseCtrl *bc, TableQuery *tq, char *sx, short int fld) { // Must be activated AFTER the initialization of database tq->v = fld; if (strlen (sx) <= 10) { tq->it = 1; doUpcase (tq->st, sx, 10); tq->cntr = &bc->cnt1; tq->n0x = bc->n01; tq->l0x = bc->l01; } else { tq->it = 2; doUpcase (tq->st, sx, 30); tq->cntr = &bc->cnt2; tq->n0x = bc->n02; tq->l0x = bc->l02; } } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // #include "ipost.c" /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ iAPI software: The Inv. File Postings access for Unix-ISIS databases Copyright (C) 2000 by Robert Janusz E-mail: rj@jezuici.krakow.pl Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ // gcc Linux Compiler conventions ! // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int PostSeg (BaseCtrl *bc, TableQuery *tq) { if (ReadMem (&tq->ibl, bc->ifp, tq->ib - 1, sizeof (ifpBlock)) != 0) return (-1); if (labs (tq->ibl.ifblk) - tq->ib != 0) return (-2); memcpy (&tq->ihd, &tq->ibl.ifrec [tq->ip], sizeof (ifpHeader)); tq->ip += 3; // = long int.s / (header - posting) ***!= ISIS.MANUAL *** tq->iiseg = 0; return (0); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int PostNext (BaseCtrl *bc, TableQuery *tq) { if (tq->iitot >= tq->iall) return (1); // No more postings if (tq->iiseg >= tq->ihd.ifpsegp) // No more postings in this seg. { // Get next Segment... tq->ib = tq->ihd.ifpnxtb; tq->ip = tq->ihd.ifpnxtp; if (PostSeg (bc, tq) != 0) return (-2); } tq->iiseg += 1; tq->iitot += 1; tq->ip += 2; // = Number of long int / posting ***!= ISIS.MANUAL *** if (tq->ip > 125) // ***!= ISIS.MANUAL *** { // Get next block for this segment; we HAVE TO find the right block! tq->ib += 1; tq->ip = 0; if (ReadMem (&tq->ibl, bc->ifp, tq->ib - 1, sizeof (ifpBlock)) != 0) return (-1); if (labs (tq->ibl.ifblk) != tq->ib) return (-3); } tq->ipst = (char *) &tq->ibl.ifrec [tq->ip]; return (0); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void PostMake (long int mfn, short int tag, char occ, short int pcnt , char *s, char *slen) { ifpPosting rnp; char *p = (char *) &rnp; rnp.pmfn = mfn; rnp.ptag = tag; rnp.pocc = occ; rnp.pcnt = pcnt; if (tag == 0) *slen = 3; // Only MFN else *slen = 5; // MFN and TAG s [2] = p [0]; s [1] = p [1]; s [0] = p [2]; // = pmfn s [4] = p [4]; s [3] = p [5]; s [5] = p [6]; s [7] = p [7]; s [6] = p [8]; } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void PostInv (ifpPosting *ifpp, void *ps) { char *p = (char *) ifpp; char *s = (char *) ps; // Posting string: |0 a |1 b |2 c |3 d |4 e |5 f |6 g |7 h | ps *s // ifpPosting: |0 c|1 b |2 a |3 0 |4 e |5 d |6 f |7 h |8 g | ifpp *p // |pmfn |ptag |pocc|pcnt | p [0] = s [2]; p [1] = s [1]; p [2] = s [0]; p [3] = 0; // = pmfn p [4] = s [4]; p [5] = s [3]; p [6] = s [5]; p [7] = s [7]; p [8] = s [6]; } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int main (int argc, char **argv) // char *argv [] { char c; printf ("ix \n"); printf (" ::= UNIX-ISIS (v.3) MF without .MST\n"); printf ("ix ver. 0.3, Copyright (C) 2000 by Robert Janusz\n"); printf ("ix comes with ABSOLUTELY NO WARRANTY\n"); printf ("License: GPL; see http://www.gnu.org/ for details\n"); for (c = 'A'; c <= 'z'; c++) // Let's prepare it, we use API, not an example UpCase [c] = UpMe (c); if (argv [1] != NULL) { strcpy (DBpath, argv [1]); // Database; no test ! ;-) it's only an example isis (); } return (0); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void isis () { int j, v, k; long int nrc; BaseCtrl bc; RecCtrl rc; char st [31]; TableQuery tabq [NFIND]; strcpy (bc.name, DBpath); InitBase (&bc); // ShowRec but not all... printf ("\n*** ShowRec ***\n\n"); //for (nrc = 1L; nrc < bc.mctrl.nxtmfn; nrc++) { for (nrc = 10L; nrc < 20L; nrc++) { if ((j = GetRec (&bc, nrc, &rc, RECLENGTH)) == 0) { ShowRec (&rc); } } // ShowIndex printf ("\n*** ShowIndex: %s ***\n\n", st); strcpy (st, "TEST"); // just an Inv. File term v = 0; // term counter k = IndexPrep (&bc, &tabq [0], &tabq [1], st); // prepare indexes while (k > 0) { j = 20 * k - 10; // We have the term length ;-) memcpy (&st, &tabq [k - 1].term [0], j); // keep it in st st [j] = 0; if ((v += 1) > 12) // we want 12 terms in a list { printf ("->%s\n", st); // the next term break; } printf ("%s\n", st); k = IndexTerm (k, &tabq [0], &tabq [1]); // Next term } // Find a term & show records printf ("\n*** Search for: %s ***\n\n", st); // Let's use the last term setQuery (&bc, &tabq [0], st, 0); // String to search in a filed 0 = any j = Find (&bc, tabq, 1, &nrc, &rc, RECLENGTH); // 1 term to search for // Clean all printf ("\nO.K.\n"); Done (&bc); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void ShowRec (RecCtrl *rc) { long int nr; short int n, k, kk; char st [256]; char *b = rc->buf; mstHdrTxt *mht = &rc->hdrs.mht; mstIndex *ind = (mstIndex *) &rc->buf [sizeof (RecHeaders)]; nr = rc->hdrs.mhf.mfn; // Record header printf ("=== %li\n", nr); for (n = 0; n < mht->nvf; n++) { // Show fileds without formating printf ("*** [%li] ", (long int) ind->tag); k = mht->base + ind->pos; for (kk = 0; kk < ind->len; kk++) printf ("%c", b [k++]); printf ("\n"); ind += 1; // Next index } printf ("___\n"); } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // This procedure is prepared to do a simple AND operator after some // extensions, so it can be localy a little strange ;-) int Postings (BaseCtrl *bc, TableQuery tabq [], int ifind, long int *npg , RecCtrl *rc, long int recvol) { int j, state; long int ipg, rn; ifpPosting ip; TableQuery *tq; if (ifind < 1) goto finish; // nothing to do ipg = 1L; // Index for page break { tq = &tabq [0]; // Let's think only about one term to handle (example) if (PostSeg (bc, tq) != 0) return (-1); tq->iall = tq->ihd.ifptotp; // Only 1st Segment has tot. post. number tq->iitot = 0; if (PostNext (bc, tq) != 0) return (-1); PostInv (&ip, tq->ipst); if (sComp (tq->st, tq->term, 20 * tq->it - 10) != 0) ipg = 0L; // the term not found } if (ipg != 1L) goto finish; for ( ; ; ) // Global loop... { // Is there a field { tq = &tabq [0]; if (tq->v != 0) while (ip.ptag != tq->v) { if (PostNext (bc, tq) > 0) goto finish; // No more postings PostInv (&ip, tq->ipst); } } rn = ip.pmfn; state = 1; if (ip.pmfn != rn) state = 0; if (state) // We have a record to show { if ((j = GetRec (bc, rn, rc, recvol)) == 0) ShowRec (rc); else printf ("Record state = %li\n", j); do // Shift all postings { tq = &tabq [0]; if (PostNext (bc, tq) > 0) goto finish; // No more postings PostInv (&ip, tq->ipst); } while (ip.pmfn <= rn); // MFN equals } else // state == 0, Shift all postings while (ip.pmfn < rn) // The last is to examin { tq = &tabq [0]; if (PostNext (bc, tq) > 0) goto finish; // No more postings PostInv (&ip, tq->ipst); } } finish: return (0); // The output is finished } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++