2 this file composed by Klaus Ripke from the iAPI files by Robert Janusz.
3 this is the test app "ix.c" with all the includes slurped in,
4 see // #include "isomething.c"
12 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13 iAPI software: The Example of ISIS (UNIX v.3) Database Handle
14 Copyright (C) 2000 by Robert Janusz
15 E-mail: rj@jezuici.krakow.pl
16 Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland
17 tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003.
19 This program is free software; you can redistribute it and/or
20 modify it under the terms of the GNU General Public License
21 as published by the Free Software Foundation.
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
33 // Linux gcc Compiler conventions !
40 // Global variables +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
46 #define NFIND 3 // let's keep it for future
48 #define PACKED __attribute__((packed)) // it shoud work on Linux gcc ;-)
51 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
52 iAPI software: The Type Definitions for Unix-ISIS databases
53 Copyright (C) 2000 by Robert Janusz
54 E-mail: rj@jezuici.krakow.pl
55 Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland
56 tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003.
58 This program is free software; you can redistribute it and/or
59 modify it under the terms of the GNU General Public License
60 as published by the Free Software Foundation.
62 This program is distributed in the hope that it will be useful,
63 but WITHOUT ANY WARRANTY; without even the implied warranty of
64 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
65 GNU General Public License for more details.
67 You should have received a copy of the GNU General Public License
68 along with this program; if not, write to the Free Software
69 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
72 // gcc Linux Compiler conventions !
73 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
75 // *************************** TYPE DEFINITIONS *****************************
77 // Cross Reference File XRF structure +++++++++++++++++++++++++++++++++++++++
79 typedef /* Packed */ struct // /* Packed */ and order are necessary for block reading
82 // Block nr: 1, 2...; < 0: last block
83 long int xrec [127] PACKED;
84 // References to Master File records...
85 // xrec [...] = 2048 *xrmfb [21 bit] & xrmfp [11 bit]
86 // rec. deleted log. < 0 & > 0 (restore: -xrmfb)
87 // rec. deleted phis. =-1 & = 0 (ref@MST.ctrl)
88 // rec. does not exist = 0 & = 0
89 // new rec. to invert bit 1024 = 1
90 // rec. edited to inv. (add & del post.) bit 512 = 1
94 // Master File (MST) record structures... +++++++++++++++++++++++++++++++++++
96 typedef /* Packed */ struct // The first record in Master File
98 long int ctlmfn PACKED // Always 0
99 , nxtmfn PACKED // Next Master File Number
100 , nxtmfb PACKED; // Next block in Master File, the 1st has 1
101 short int nxtmfp PACKED // Next position in the last block
102 , mftype PACKED; // 0 for user's bases; 1 for messages
103 long int reccnt PACKED // Reserved for future
104 , mfcxx1 PACKED // Reserved for future
105 , mfcxx2 PACKED // LAN, > 0: inversion, update not possible
106 , mfcxx3 PACKED; // LAN, = 1: exists exclusive user
110 typedef /* Packed */ struct // Fixed part of record header that must be...
111 { // included in the same block;
112 // the header can begin only on 0, 2, 4...498
113 long int mfn PACKED; // MFN number
114 short int mfrl PACKED; // Length of record (allways eaven)...
115 // LAN: < 0 ==> record blocked
116 long int mfbwb PACKED; // Block Pointer | If the record waits for inv...
117 short int mfbwp PACKED; // Position Pointer | ...ref. to old location
118 // mfbwb, mfbwp: = 0 at creation;
119 // after modif. = ref to the old record.
120 // xrmfp bit 1024 = 1 at creation
121 // (= waits to be inverted);
122 // xrmfp bit 512 = 1 at edit
123 // (=waits to be inv. & delete old references)
127 typedef /* Packed */ struct
129 short int base PACKED // Position of data fields in the record
130 , nvf PACKED // Number of fields in the record
131 , status PACKED; // 0 = active, 1 = deleted logicaly (- xrfb < 0)
135 typedef /* Packed */ struct
137 mstHdrFix mhf PACKED; // This header is allways in MST file block
138 mstHdrTxt mht PACKED;
142 typedef /* Packed */ struct // Index for every field in the record
143 { // dimension = 6 *nvf; base = 18 + 6 *nvf
144 short int tag PACKED // Label of the field
145 , pos PACKED // Position of the first char in data part: 0, 1...
146 , len PACKED; // Length of the field
150 // Inverted File structures +++++++++++++++++++++++++++++++++++++++++++++++++
152 // Control File (CNT) structure..............................................
154 typedef /* Packed */ struct
156 short int idtype PACKED // B*tree type; 1 = N01/L01, 2 = N02/L02
157 , ordn PACKED // = 5; a half of size of key-record in N0x
158 , ordf PACKED // = 5; a half of size of key-record in L0x
159 , n PACKED // = 15; number of buffers for nodes
160 , k PACKED // = 5; number of buffers for 1st index level (k < n)
161 , lev PACKED; // Current number of levels in index; -1: no N0x
162 long int posrx PACKED // Reference to the root in N0x
163 , nmaxpos PACKED // Next record in N0x
164 , fmaxpos PACKED; // Next record in L0x
165 short int abnormal PACKED; // 0: N0x has only the root
169 // Index of Dictionary (N0x) structures......................................
171 typedef /* Packed */ struct
173 long int pos PACKED; // Number of record
174 short int ock PACKED // Number of active keys in the record: 1, 2, 3...2*ordn
175 , it PACKED; // B*tree type
179 typedef /* Packed */ struct
181 char key [10] PACKED;
182 long int ref PACKED; // > 0: reference to next node;
183 // < 0: ref. to leaf: idx [1st].key = key
188 typedef /* Packed */ struct
190 char key [30] PACKED;
195 typedef /* Packed */ struct
197 nodeHeader hdr PACKED;
198 nodeIndex1 idx [10] PACKED; // Vector of 2*ordn elements
202 typedef /* Packed */ struct
204 nodeHeader hdr PACKED;
205 nodeIndex2 idx [10] PACKED; // Vector of 2*ordn elements
209 typedef /* Packed */ union
211 nodeBlock1 nb1 PACKED;
212 nodeBlock2 nb2 PACKED;
216 // Leaf File (L0x) structures (all index terms)..............................
218 typedef /* Packed */ struct
220 long int pos PACKED; // Number of leaf record: 1, 2...
221 short int ock PACKED // Number of active keys in the record: 1..2*ordf
222 , it PACKED; // = 1 for L01; = 2 for L02
223 long int ps PACKED; // Next record in the order: key [ock] < ps^ idx [1st].key
227 typedef /* Packed */ struct
229 char key [10] PACKED;
230 short int xxx PACKED; // *** ONLY UNIX ISIS;
231 long int infb PACKED // Reference to IFP segment *** != ISIS.MANUAL ***
236 typedef /* Packed */ struct
238 char key [30] PACKED;
239 short int xxx PACKED; // *** ONLY UNIX ISIS;
240 long int infb PACKED // Reference to IFP segment *** != ISIS.MANUAL ***
245 typedef /* Packed */ struct
247 leafHeader hdr PACKED;
248 leafKey1 idx [10] PACKED; // 2*ordf keys
252 typedef /* Packed */ struct
254 leafHeader hdr PACKED;
255 leafKey2 idx [10] PACKED; // 2*ordf keys
259 typedef /* Packed */ union
261 leafBlock1 lb1 PACKED;
262 leafBlock2 lb2 PACKED;
266 // Inverted File Posting structures..........................................
267 // ordained postings organized in segments: Index --> Master File
269 typedef /* Packed */ struct
271 long int ifblk PACKED // Number of block
272 , ifrec [127] PACKED; // Vector of long int *** != ISIS.MANUAL ***
273 // In 1st block ifrec [1st/2nd] = next pos. in IFP
277 typedef /* Packed */ struct // This header and 1st posting - always in IFP block
279 long int ifpnxtb PACKED // Pointer to the next segment: 1, 2... | = 0: last seg.
280 , ifpnxtp PACKED // 0, 1... | = 0: last seg.
281 , ifptotp PACKED // Tot. number of postings (o.k. only in the 1st segment)
282 // = Sum (segment=1, nseg; ifpsegp)
283 , ifpsegp PACKED // Number of postings in this segment
284 , ifpsegc PACKED; // Max. number of postings in this segment (<= 32768)
288 // ifpHeader & 1st ifpPosting always in the same ifpBlock
289 // Postings in Segment are always in chain of IFP blocks
291 typedef /* Packed */ struct // Stored left-->right + 0 --> 8 char
293 long int pmfn PACKED; // First 3 bytes --> Master File
294 short int ptag PACKED; // Field ident - according to File Selection Table (FST)
295 char pocc PACKED; // Number of occurence of the field
296 short int pcnt PACKED; // Counter of the termin inside the field
302 int opened; // Which files are opened (bit spec.)...
310 mstControl mctrl; // MST ctrl record
311 cntBlock cnt1, cnt2; // Inv. Files ctrl records
312 long int ibm, ipm; // IFP new Segment Bock/Pos
313 char name [72]; // Database name
317 typedef struct // This structer must be allways corelated with BaseCtrl
319 char st [31]; // Max. string to find
320 short int v; // Field to find; 0: all fields
321 short int it; // Type of B*Tree <== strlen (st)
322 leafBlock lbl; // Block L0x with index terms
323 short int ilk; // Position of term in lbl...idx
324 char *term; // The term in lbl...idx
325 long int ib, ip; // Number of block/position for IFP
326 ifpBlock ibl; // Block IFP with posting/s
327 ifpHeader ihd; // Header for Segment of postings
328 long int iiseg; // Number of posting in current Segment (index)
329 long int iitot; // Number of posting in total (index)
330 long int iall; // Number of posting in all Segments
331 char *ipst; // Ref. to last posting string [8 chars]
332 cntBlock *cntr; // BaseCtrl.cntr1/2 <== it
333 FILE *n0x; // N01 or N02 <== it, = BaseCtrl.n0x
334 FILE *l0x; // L01 or L02 <== it, = BaseCtrl.l0x
338 #define RECLENGTH 8192
342 char buf [RECLENGTH];
347 // *** MAIN DATABASE FILE RELATIONS (MST <--> XRF) ***
349 // MST |-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|...
350 // ctrl |----record----|
352 // 1 2 3 | pointer: B/P (P in [0, 2, 4... 498])
353 // XRF |-xblk-|-xblk-|-xblk-|...
354 // MFN= 1... 128... 255...
355 // Record |-->-pos->--|
356 // |-mhf-mht-|-idx[1]...idx[nvf]-|---text...---|
357 // |-------------- record buffer --------------|
359 // *** INVERTED FILE RELATIONS (N0x <--> L0x <-->IFP) ***
360 // N0x |-nbl-|-nbl-|-nbl-|-nbl-|-nbl-|-nbl-|...
361 // -->-root->-| |-->--next-->--| |->-->-| r<0
363 // L0x |--lbl--|--lbl--|--lbl--|--lbl--|--lbl--|--lbl--|...
365 // |-<--------------<-------------<-| r<0
367 // IFP |---ibl---|---ibl---|---ibl---|---ibl---|---ibl---|---ibl---|...
368 // |next |-ihd-|---Segment---| |-ihd-|---Segment---|
369 // |Seg. |-->------>------>-next->--| |||...
371 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
375 // Let's specify non int header ;-) just to keep order
377 void ShowRec (RecCtrl *rc);
378 void setQuery (BaseCtrl *bc, TableQuery *tq, char *sx, short int fld);
381 // #include "iutil.c"
382 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
383 iAPI software: The UTIL procedures for Unix-ISIS databases
384 Copyright (C) 2000 by Robert Janusz
385 E-mail: rj@jezuici.krakow.pl
386 Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland
387 tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003.
389 This program is free software; you can redistribute it and/or
390 modify it under the terms of the GNU General Public License
391 as published by the Free Software Foundation.
393 This program is distributed in the hope that it will be useful,
394 but WITHOUT ANY WARRANTY; without even the implied warranty of
395 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
396 GNU General Public License for more details.
398 You should have received a copy of the GNU General Public License
399 along with this program; if not, write to the Free Software
400 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
401 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
403 // gcc Linux Compiler conventions !
404 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
406 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
408 int ReadMem (void *ptr, FILE *f, long int nr, long int size)
409 { // Read "nr"'s block of size "size" from file "f" into "ptr"...
410 if (fseek (f, nr * size, SEEK_SET) != 0) return (-1);
411 if (fread (ptr, size, 1, f) == 0) return (-2);
415 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
417 void doUpcase (char *s, char *st, int slen)
419 for (i = 0; i < slen; i++)
420 { if (i < strlen (st)) s [i] = UpCase [(int) st [i]]; else s [i] = ' '; }
424 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
426 int sComp (char *s1, char *s2, int len)
428 for (i = 0; i < len; i++)
429 { if (s1 [i] > s2 [i]) return (1); // .gt.
430 if (s1 [i] < s2 [i]) return (-1); // .lt.
435 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
437 int bfOpen (FILE **f, BaseCtrl *bc, char *ext, char *opt)
439 if (strlen (bc->name) + strlen (ext) > 80) return (-2);
440 strcpy (st, bc->name); strcat (st, ext);
441 if ((*f = fopen (st, opt)) == NULL) return (-1);
445 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
447 int InitBase (BaseCtrl *bc)
448 // Error return: -1 base file/s; -2 inv. file/s; -3 mst. ctrl rec/s;
449 // -4 cnt param/s; -5 ifp param/s
452 if (bfOpen (&bc->mst, bc, ".MST", "rb") != 0) return (-1);
453 bc->opened += 1; // MST opened
454 if (bfOpen (&bc->xrf, bc, ".XRF", "rb") != 0) return (-1);
455 bc->opened += 2; // XRF opened
456 if (bfOpen (&bc->ifp, bc, ".CNT", "rb") != 0) return (-2);
457 if (fread (&bc->cnt1, sizeof (cntBlock), 1, bc->ifp) == 0 ||
458 fread (&bc->cnt2, sizeof (cntBlock), 1, bc->ifp) == 0) return (-2);
459 if (fclose (bc->ifp) != 0) return (-3);
460 if (bfOpen (&bc->ifp, bc, ".IFP", "rb") != 0) return (-2);
461 bc->opened += 4; // IFP opened
462 if (bfOpen (&bc->n01, bc, ".N01", "rb") != 0) return (-2);
463 bc->opened += 8; // N01 opened
464 if (bfOpen (&bc->l01, bc, ".L01", "rb") != 0) return (-2);
465 bc->opened += 16; // L01 opened
466 if (bfOpen (&bc->n02, bc, ".N02", "rb") != 0) return (-2);
467 bc->opened += 32; // N02 opened
468 if (bfOpen (&bc->l02, bc, ".L02", "rb") != 0) return (-2);
469 bc->opened += 64; // L02 opened
470 if (fread (&bc->mctrl, sizeof (mstControl), 1, bc->mst) == 0) return (-3);
471 if (bc->cnt1.ordn != 5 || bc->cnt1.ordf != 5 || bc->cnt1.n != 15 ||
472 bc->cnt1.k != 5 || bc->cnt2.ordn != 5 || bc->cnt2.ordf != 5 ||
473 bc->cnt2.n != 15 || bc->cnt2.k != 5) return (-4);
474 if (fread (&ib, sizeof (ifpBlock), 1, bc->ifp) == 0) return (-5);
475 if (ib.ifblk != 1) return (-5);
476 bc->ibm = ib.ifrec [0]; bc->ipm = ib.ifrec [1];
480 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
482 void Done (BaseCtrl *bc) // Close the database files
484 if (bc->opened && 1) fclose (bc->mst);
485 if (bc->opened && 2) fclose (bc->xrf);
486 if (bc->opened && 4) fclose (bc->ifp);
487 if (bc->opened && 8) fclose (bc->n01);
488 if (bc->opened && 16) fclose (bc->l01);
489 if (bc->opened && 32) fclose (bc->n02);
490 if (bc->opened && 64) fclose (bc->l02);
493 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
495 char UpMe (char c) // ^A = ^a etc.
497 if (c > 96) c = c - 32;
501 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
505 if (st == NULL) return;
506 for (i = 0; i < strlen (st); i++)
507 // c = tblconvert [st [i]];
508 if (st [i] == (char) 145) printf ("<"); // This is HTML <
509 else if (st [i] == (char) 146) printf (">"); // and that is >
510 else printf ("%c", st [i]);
513 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
517 st [0] = ch; st [1] = 0; outS (st);
520 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
522 void outD (double x, int n)
528 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
530 void outN (long int x) // long int -> sting @ base=10
533 // ltoa (x, st, 10); outS (st);
537 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
540 // #include "imasterf.c"
541 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
542 iAPI software: The Master File access to Unix-ISIS databases
543 Copyright (C) 2000 by Robert Janusz
544 E-mail: rj@jezuici.krakow.pl
545 Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland
546 tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003.
548 This program is free software; you can redistribute it and/or
549 modify it under the terms of the GNU General Public License
550 as published by the Free Software Foundation.
552 This program is distributed in the hope that it will be useful,
553 but WITHOUT ANY WARRANTY; without even the implied warranty of
554 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
555 GNU General Public License for more details.
557 You should have received a copy of the GNU General Public License
558 along with this program; if not, write to the Free Software
559 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
560 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
562 // gcc Linux Compiler conventions !
563 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
565 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
567 int GetRec (BaseCtrl *bc, long int mfnr, RecCtrl *rc, int bufvol)
568 { char mblk [512]; // Master File block;
569 long int xmfb, xmfp; // Pointer to Master File (last read) record
570 // xMfB < 0 : record deleted (status = 1), -xMfB --> block;
571 // xMfP = 0: deleted phisicaly
572 // = 0 & = 0: does not exist
573 // 1st block: xMfB = 1, xMfP = 0; pointer = xMfB * 2048 + xMfP
574 // ==> mst < 500 MBy;
578 mstHdrFix *hf = &rc->hdrs.mhf;
579 mstHdrTxt *ht = &rc->hdrs.mht;
582 if ((mfnr < 1) || (mfnr >= bc->mctrl.nxtmfn)) return (-2); // No record
584 // Find the address in XRF...
585 xn = mfnr - 1; xb = xn / 127;
586 if (ReadMem (&xblk, bc->xrf, xb, sizeof (xrfBlock)) != 0) return (-1);
587 xn = xblk.xrec [xn % 127]; // = address in MST
588 xmfb = xn / 2048; // Master File Block
589 xmfp = xn % 512; // Master File Position
591 // Find the record in MST...
592 if (xmfb < 1) return (1); // Record deleted
593 ret = 0; // Record o.k.
594 if (ReadMem (&mblk, bc->mst, xmfb - 1, sizeof (mblk)) != 0) return (-1);
596 // Copy headers into record buffer...
597 memcpy (b, &mblk [xmfp], sizeof (mstHdrFix));
598 if (hf->mfn != mfnr) return (-2); // Database corrupted
599 if (hf->mfrl >= bufvol) return (-3); // Buffer too small
601 // Get the rest of the record
602 xmfp += sizeof (mstHdrFix); // Posinion in block
603 xb = sizeof (mstHdrFix); // Position in buf
604 xn = labs (hf->mfrl) - xb; // Number of chars to read
605 if (xn <= 0) return (4); // No fields ??
606 for ( ; ; ) // We have some chars
607 { // Find number of chars to copy from this block
608 if (xn <= (nch = sizeof (mblk) - xmfp)) nch = xn;
609 memcpy (b + xb, &mblk [xmfp], nch);
610 xb += nch; xn -= nch; xmfp = 0;
611 if (xn <= 0) break; // Nothing more to read
612 if (fread (&mblk, sizeof (mblk), 1, bc->mst) == 0) return (-1);
615 if (ht->status != 0) ret = 1; // Record deleted logicaly
616 if (hf->mfbwb != 0 || hf->mfbwp != 0) ret = 2; // Record not inv.
617 if (hf->mfrl < 0) ret = 3; // Record blocked
621 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
623 int IsF (RecCtrl *rc, short int v, char ch, char *st)
624 { short int n, k, kk, flag;
626 mstHdrTxt *mht = &rc->hdrs.mht;
627 mstIndex *ind = (mstIndex *) &rc->buf [sizeof (RecHeaders)];
630 for (n = 0; n < mht->nvf; n++)
632 if (ind->tag == v) // there is a tag
634 if (ch == ' ') // field found
636 else // there is sub-field
638 kk = 0; k = mht->base + ind->pos;
639 while (b [k] != '^' || b [k + 1] != ch) // convention ;-)
641 if (kk >= ind->len) // out of field
647 ind += 1; // next index ref.
649 if (flag == 0) return (0); // false
650 if (st == NULL) return (1); // true
652 if (sComp (&b [mht->base + ind->pos], st, ind->len) == 0)
657 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
659 void RepF (RecCtrl *rc, char nf, ...)
661 // Repeated "nf" fields in record "rc", the left label appears only if:
662 // - begins with "\n", - there was another field and there is defined
663 // filed; the right label appears only if ther was defined field.
665 { va_list pinfo; // for ... parameter list
666 int i, c, flag, n, k, kk, v;
670 mstHdrTxt *mht = &rc->hdrs.mht;
671 mstIndex *ind = (mstIndex *) &rc->buf [sizeof (RecHeaders)];
673 for (n = 0; n < mht->nvf; n++)
675 va_start (pinfo, nf);
676 for (i = 0; i < nf; i++)
679 k = mht->base + ind->pos;
680 sl = va_arg (pinfo, char *); // left
681 v = va_arg (pinfo, short int); // field
682 c = va_arg (pinfo, char); // sub-field
684 sr = va_arg (pinfo, char *); // right
685 if (v != ind->tag) // another Tag
687 if (c != ' ') // sub-field
689 while (b [k] != '^' || UpMe (b [k + 1]) != c) // convention ;-)
694 if (flag) { k += 2; kk += 2; }
698 { // Reference to NULL = NW error !!!
699 if (sl == NULL) flag = 0;
700 else if (*sl == '\n') flag = 1; else flag = 0;
701 if (hit != 0 || flag) outS (sl);
704 while (kk < ind->len)
706 if (b [k] != '<' && b [k] != '>') // HTML special ;-)
711 while (kk < ind->len && b [k] != '^') // convention ;-)
713 if (b [k] != '<' && b [k] != '>') // HTML special ;-)
725 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
727 // #include "iinvterm.c"
728 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
729 iAPI software: The Inv. File Terms access for Unix-ISIS databases
730 Copyright (C) 2000 by Robert Janusz
731 E-mail: rj@jezuici.krakow.pl
732 Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland
733 tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003.
735 This program is free software; you can redistribute it and/or
736 modify it under the terms of the GNU General Public License
737 as published by the Free Software Foundation.
739 This program is distributed in the hope that it will be useful,
740 but WITHOUT ANY WARRANTY; without even the implied warranty of
741 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
742 GNU General Public License for more details.
744 You should have received a copy of the GNU General Public License
745 along with this program; if not, write to the Free Software
746 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
747 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
749 // gcc Linux Compiler conventions !
750 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
752 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
754 int FindFirst (TableQuery *tq)
756 short int i, j // Indexes for idx []
757 , srec, klen, sidx; // Size (rec), key length, size (idx)
758 long int r; // Reference (record number); < 0: --> L0x --> IFP
760 leafHeader *lhdr = &tq->lbl.lb1.hdr; // = ...lb2.hdr
762 nodeHeader *nhdr = &nbl.nb1.hdr; // = ...nb2.hdr
765 { klen = 10; srec = sizeof (nodeBlock1); sidx = sizeof (nodeIndex1); }
767 { klen = 30; srec = sizeof (nodeBlock2); sidx = sizeof (nodeIndex2); }
769 r = tq->cntr->posrx; // Root in N0x
772 if (ReadMem (&nbl, tq->n0x, r - 1, srec) != 0) return (-1);
774 if (nhdr->pos != r || nhdr->it != tq->it ||
775 j < 1 || j > 10) return (-3); // 10 = 2*ordn
776 ref = (char *) &nbl.nb1.idx; // Reference to first elem. of index
777 ref += sidx; // The first key is allways <= st, skip it
778 for (i = 1; i < j; i++)
779 if (sComp (ref, tq->st, klen) > 0) break;
781 ref -= sidx; // Correct value
782 r = *(long int *) (ref + klen); // We have the "ref" value
783 if (r > tq->cntr->nmaxpos) return (-3); // Out of N0x
786 // Now find the term in L0x index
788 { srec = sizeof (leafBlock1); sidx = sizeof(leafKey1); }
790 { srec = sizeof(leafBlock2); sidx = sizeof(leafKey2); }
793 if (ReadMem (&tq->lbl, tq->l0x, r - 1, srec) != 0) return (-1);
795 if (lhdr->pos != r || lhdr->it != tq->it ||
796 j < 1 || j > 10) return (-2); // 10 = 2*ordf
799 ref = (char *) &tq->lbl.lb1.idx; // Reference to first elem. of index
800 ref += sidx; // The first key is allways <= s, skip it
801 for (i = 1; i < j; i++)
802 if (sComp (ref, tq->st, klen) > 0) break;
803 else { ref += sidx; tq->ilk += 1; }
806 tq->term = ref; // We have the term address
808 ref += 12; // += 10; *** NOT UNIX
809 else ref += 32; // += 30; *** NOT UNIX
810 tq->ib = *(long int *) ref; // = infb
811 ref += sizeof (long int);
812 tq->ip = *(long int *) ref; // = infp
816 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
818 int FindNext (TableQuery *tq)
819 { int srec; // Block size
820 long int r; // Reference (record number); < 0: --> L0x --> IFP
821 leafHeader *lhdr = &tq->lbl.lb1.hdr; // = ...lb2.hdr
823 if (tq->it == 1) srec = sizeof (leafBlock1);
824 else srec = sizeof (leafBlock2);
826 tq->ilk += 1; // Next key in the index
827 if (tq->ilk >= lhdr->ock) // Out of index
828 { r = lhdr->ps; // Next L0x record in order
830 { tq->ilk -= 1; return (1); } // Nothing more, end of index
831 if (ReadMem (&tq->lbl, tq->l0x, r - 1, srec) != 0) return (-1);
832 if (lhdr->pos != r || lhdr->it != tq->it ||
833 lhdr->ock < 1 || lhdr->ock > 10) return (-2); // 10 = 2*ordf
839 { tq->term = tq->lbl.lb1.idx [srec].key;
840 tq->ib = tq->lbl.lb1.idx [srec].infb;
841 tq->ip = tq->lbl.lb1.idx [srec].infp;
844 { tq->term = tq->lbl.lb2.idx [srec].key;
845 tq->ib = tq->lbl.lb2.idx [srec].infb;
846 tq->ip = tq->lbl.lb2.idx [srec].infp;
848 return (0); // We have the new key
851 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
853 int Find (BaseCtrl *bc, TableQuery tabq [], int ifind, long int *npg
854 , RecCtrl *rc, long int recvol)
857 if (ifind <= 0 || ifind > NFIND) return (-1);
858 for (i = 0; i < ifind; i++)
859 if (FindFirst (&tabq [i]) < 0) return (-1);
861 i = Postings (bc, tabq, ifind, npg, rc, recvol);
865 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
867 int IndexPrep (BaseCtrl *bc, TableQuery *tq1, TableQuery *tq2, char *st)
868 { char sx [31]; // tqx->v contains the status of L0x index
872 for (i = 0; i < 30; i++) sx [i] = ' ';
874 for (i = 0; i < 30; i++)
875 if (i < strlen (st)) sx [i] = st [i]; else sx [i] = ' ';
878 setQuery (bc, tq2, sx, 0); // We have a long term in tq2; v := 0
879 if (FindFirst (tq2) < 0) return (-1);
882 setQuery (bc, tq1, sx, 0); // We have a short term in tq1; v := 0
883 if (FindFirst (tq1) < 0) return (-1);
885 while (sComp (tq1->term, tq1->st, 10) < 0)
886 if ((tq1->v = FindNext (tq1)) != 0) break; // At the end or error
887 if (tq1->v < 0) return (-1);
889 while (sComp (tq2->term, tq2->st, 30) < 0)
890 if ((tq2->v = FindNext (tq2)) != 0) break; // At the end or error
891 if (tq2->v < 0) return (-1);
893 return (IndexTest (tq1, tq2));
896 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
898 int IndexTest (TableQuery *tq1, TableQuery *tq2)
900 if (tq1->v == 1) // At the end of 1st
901 if (tq2->v == 1) // At the end of 2nd
902 return (0); // All done
903 else return (2); // We have only 2nd
905 if (tq2->v == 1) return (1); // We have only 1st
906 else if (sComp (tq1->term, tq2->term, 10) <= 0) return (1);
910 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
912 int IndexTerm (int i, TableQuery *tq1, TableQuery *tq2)
914 if (i == 1) tq1->v = FindNext (tq1); // The term was in 1st
915 else if (i == 2) tq2->v = FindNext (tq2); // The term was in 2nd
917 return (IndexTest (tq1, tq2));
920 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
922 void setQuery (BaseCtrl *bc, TableQuery *tq, char *sx, short int fld)
923 { // Must be activated AFTER the initialization of database
926 if (strlen (sx) <= 10)
927 { tq->it = 1; doUpcase (tq->st, sx, 10);
928 tq->cntr = &bc->cnt1; tq->n0x = bc->n01; tq->l0x = bc->l01;
931 { tq->it = 2; doUpcase (tq->st, sx, 30);
932 tq->cntr = &bc->cnt2; tq->n0x = bc->n02; tq->l0x = bc->l02;
936 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
939 // #include "ipost.c"
940 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
941 iAPI software: The Inv. File Postings access for Unix-ISIS databases
942 Copyright (C) 2000 by Robert Janusz
943 E-mail: rj@jezuici.krakow.pl
944 Address: Robert Janusz, ul. Kopernika 26, 31-501 Krakow, Poland
945 tel: (0048-12) 4294416/432 ; fax: (0048-12) 4295003.
947 This program is free software; you can redistribute it and/or
948 modify it under the terms of the GNU General Public License
949 as published by the Free Software Foundation.
951 This program is distributed in the hope that it will be useful,
952 but WITHOUT ANY WARRANTY; without even the implied warranty of
953 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
954 GNU General Public License for more details.
956 You should have received a copy of the GNU General Public License
957 along with this program; if not, write to the Free Software
958 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
959 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
961 // gcc Linux Compiler conventions !
962 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
964 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
966 int PostSeg (BaseCtrl *bc, TableQuery *tq)
968 if (ReadMem (&tq->ibl, bc->ifp, tq->ib - 1, sizeof (ifpBlock)) != 0)
970 if (labs (tq->ibl.ifblk) - tq->ib != 0) return (-2);
971 memcpy (&tq->ihd, &tq->ibl.ifrec [tq->ip], sizeof (ifpHeader));
972 tq->ip += 3; // = long int.s / (header - posting) ***!= ISIS.MANUAL ***
977 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
979 int PostNext (BaseCtrl *bc, TableQuery *tq)
981 if (tq->iitot >= tq->iall) return (1); // No more postings
982 if (tq->iiseg >= tq->ihd.ifpsegp) // No more postings in this seg.
983 { // Get next Segment...
984 tq->ib = tq->ihd.ifpnxtb; tq->ip = tq->ihd.ifpnxtp;
985 if (PostSeg (bc, tq) != 0) return (-2);
987 tq->iiseg += 1; tq->iitot += 1;
988 tq->ip += 2; // = Number of long int / posting ***!= ISIS.MANUAL ***
989 if (tq->ip > 125) // ***!= ISIS.MANUAL ***
990 { // Get next block for this segment; we HAVE TO find the right block!
991 tq->ib += 1; tq->ip = 0;
992 if (ReadMem (&tq->ibl, bc->ifp, tq->ib - 1, sizeof (ifpBlock)) != 0)
994 if (labs (tq->ibl.ifblk) != tq->ib) return (-3);
996 tq->ipst = (char *) &tq->ibl.ifrec [tq->ip];
1000 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1002 void PostMake (long int mfn, short int tag, char occ, short int pcnt
1003 , char *s, char *slen)
1005 char *p = (char *) &rnp;
1007 rnp.pmfn = mfn; rnp.ptag = tag; rnp.pocc = occ; rnp.pcnt = pcnt;
1008 if (tag == 0) *slen = 3; // Only MFN
1009 else *slen = 5; // MFN and TAG
1010 s [2] = p [0]; s [1] = p [1]; s [0] = p [2]; // = pmfn
1011 s [4] = p [4]; s [3] = p [5]; s [5] = p [6]; s [7] = p [7]; s [6] = p [8];
1014 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1016 void PostInv (ifpPosting *ifpp, void *ps)
1017 { char *p = (char *) ifpp;
1018 char *s = (char *) ps;
1020 // Posting string: |0 a |1 b |2 c |3 d |4 e |5 f |6 g |7 h | ps *s
1021 // ifpPosting: |0 c|1 b |2 a |3 0 |4 e |5 d |6 f |7 h |8 g | ifpp *p
1022 // |pmfn |ptag |pocc|pcnt |
1024 p [0] = s [2]; p [1] = s [1]; p [2] = s [0]; p [3] = 0; // = pmfn
1025 p [4] = s [4]; p [5] = s [3]; p [6] = s [5]; p [7] = s [7]; p [8] = s [6];
1028 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1031 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1033 int main (int argc, char **argv) // char *argv []
1036 printf ("ix <database>\n");
1037 printf ("<database> ::= UNIX-ISIS (v.3) MF without .MST\n");
1038 printf ("ix ver. 0.3, Copyright (C) 2000 by Robert Janusz\n");
1039 printf ("ix comes with ABSOLUTELY NO WARRANTY\n");
1040 printf ("License: GPL; see http://www.gnu.org/ for details\n");
1042 for (c = 'A'; c <= 'z'; c++) // Let's prepare it, we use API, not an example
1043 UpCase [c] = UpMe (c);
1045 if (argv [1] != NULL) {
1046 strcpy (DBpath, argv [1]); // Database; no test ! ;-) it's only an example
1053 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1062 TableQuery tabq [NFIND];
1064 strcpy (bc.name, DBpath);
1067 // ShowRec but not all...
1069 printf ("\n*** ShowRec ***\n\n");
1071 //for (nrc = 1L; nrc < bc.mctrl.nxtmfn; nrc++) {
1072 for (nrc = 10L; nrc < 20L; nrc++) {
1073 if ((j = GetRec (&bc, nrc, &rc, RECLENGTH)) == 0) {
1080 printf ("\n*** ShowIndex: %s ***\n\n", st);
1082 strcpy (st, "TEST"); // just an Inv. File term
1084 v = 0; // term counter
1085 k = IndexPrep (&bc, &tabq [0], &tabq [1], st); // prepare indexes
1087 j = 20 * k - 10; // We have the term length ;-)
1088 memcpy (&st, &tabq [k - 1].term [0], j); // keep it in st
1090 if ((v += 1) > 12) // we want 12 terms in a list
1092 printf ("->%s\n", st); // the next term
1095 printf ("%s\n", st);
1096 k = IndexTerm (k, &tabq [0], &tabq [1]); // Next term
1099 // Find a term & show records
1101 printf ("\n*** Search for: %s ***\n\n", st); // Let's use the last term
1103 setQuery (&bc, &tabq [0], st, 0); // String to search in a filed 0 = any
1105 j = Find (&bc, tabq, 1, &nrc, &rc, RECLENGTH); // 1 term to search for
1109 printf ("\nO.K.\n");
1114 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1116 void ShowRec (RecCtrl *rc)
1121 mstHdrTxt *mht = &rc->hdrs.mht;
1122 mstIndex *ind = (mstIndex *) &rc->buf [sizeof (RecHeaders)];
1124 nr = rc->hdrs.mhf.mfn; // Record header
1126 printf ("=== %li\n", nr);
1127 for (n = 0; n < mht->nvf; n++)
1128 { // Show fileds without formating
1129 printf ("*** [%li] ", (long int) ind->tag);
1130 k = mht->base + ind->pos;
1131 for (kk = 0; kk < ind->len; kk++)
1132 printf ("%c", b [k++]);
1134 ind += 1; // Next index
1139 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1141 // This procedure is prepared to do a simple AND operator after some
1142 // extensions, so it can be localy a little strange ;-)
1144 int Postings (BaseCtrl *bc, TableQuery tabq [], int ifind, long int *npg
1145 , RecCtrl *rc, long int recvol)
1151 if (ifind < 1) goto finish; // nothing to do
1153 ipg = 1L; // Index for page break
1155 { tq = &tabq [0]; // Let's think only about one term to handle (example)
1156 if (PostSeg (bc, tq) != 0) return (-1);
1157 tq->iall = tq->ihd.ifptotp; // Only 1st Segment has tot. post. number
1159 if (PostNext (bc, tq) != 0) return (-1);
1160 PostInv (&ip, tq->ipst);
1161 if (sComp (tq->st, tq->term, 20 * tq->it - 10) != 0)
1162 ipg = 0L; // the term not found
1165 if (ipg != 1L) goto finish;
1167 for ( ; ; ) // Global loop...
1173 while (ip.ptag != tq->v)
1175 if (PostNext (bc, tq) > 0) goto finish; // No more postings
1176 PostInv (&ip, tq->ipst);
1186 if (state) // We have a record to show
1188 if ((j = GetRec (bc, rn, rc, recvol)) == 0)
1191 printf ("Record state = %li\n", j);
1193 do // Shift all postings
1195 if (PostNext (bc, tq) > 0) goto finish; // No more postings
1196 PostInv (&ip, tq->ipst);
1198 while (ip.pmfn <= rn); // MFN equals
1200 else // state == 0, Shift all postings
1201 while (ip.pmfn < rn) // The last is to examin
1203 if (PostNext (bc, tq) > 0) goto finish; // No more postings
1204 PostInv (&ip, tq->ipst);
1209 return (0); // The output is finished
1212 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++