fixed parsing for science direct html with more than one <a href=> per one <tr>
[webpac] / openisis / iAPI.txt
1 /*
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"
5
6         you may run this with:
7         cp iAPI.txt iAPI.c
8         gcc iAPI.c
9         ./a.out <dbpath>
10 */
11
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.
18
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.
22
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.
27
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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
32
33 // Linux gcc Compiler conventions !
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <string.h>
39
40 // Global variables +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
41
42 static
43   char DBpath [71];
44   char UpCase [256];
45
46 #define NFIND 3 // let's keep it for future
47
48 #define PACKED __attribute__((packed)) // it shoud work on Linux gcc ;-)
49
50 // #include "idef.c"
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.
57
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.
61
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.
66
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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
71
72 // gcc Linux Compiler conventions !
73 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
74
75 // *************************** TYPE DEFINITIONS *****************************
76
77 // Cross Reference File XRF structure +++++++++++++++++++++++++++++++++++++++
78
79 typedef /* Packed */ struct   // /* Packed */ and order are necessary for block reading
80   {
81     long int xpos PACKED;
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
91   }
92 xrfBlock;
93
94 // Master File (MST) record structures... +++++++++++++++++++++++++++++++++++
95
96 typedef /* Packed */ struct   // The first record in Master File
97   {
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
107   }
108 mstControl;
109
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)
124   }
125 mstHdrFix;
126
127 typedef /* Packed */ struct
128    {
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)
132    }
133 mstHdrTxt;
134
135 typedef /* Packed */ struct
136   {
137   mstHdrFix mhf PACKED;     // This header is allways in MST file block
138   mstHdrTxt mht PACKED;
139   }
140 RecHeaders;
141
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
147   }
148 mstIndex;
149
150 // Inverted File structures +++++++++++++++++++++++++++++++++++++++++++++++++
151
152 // Control File (CNT) structure..............................................
153
154 typedef /* Packed */ struct
155   {
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
166   }
167 cntBlock;
168
169 // Index of Dictionary (N0x) structures......................................
170
171 typedef /* Packed */ struct
172   {
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
176   }
177 nodeHeader;
178
179 typedef /* Packed */ struct
180   {
181   char key [10] PACKED;
182   long int ref  PACKED;  // > 0: reference to next node;
183                          // < 0: ref. to leaf: idx [1st].key = key
184                          // = 0: inactive
185   }
186 nodeIndex1;
187
188 typedef /* Packed */ struct
189   {
190   char key [30] PACKED;
191   long int ref  PACKED;
192   }
193 nodeIndex2;
194
195 typedef /* Packed */ struct
196   {
197   nodeHeader hdr      PACKED;
198   nodeIndex1 idx [10] PACKED; // Vector of 2*ordn elements
199   }
200 nodeBlock1;
201
202 typedef /* Packed */ struct
203   {
204   nodeHeader hdr      PACKED;
205   nodeIndex2 idx [10] PACKED; // Vector of 2*ordn elements
206   }
207 nodeBlock2;
208
209 typedef /* Packed */ union
210   {
211   nodeBlock1 nb1 PACKED;
212   nodeBlock2 nb2 PACKED;
213   }
214 nodeBlock;
215
216 // Leaf File (L0x) structures (all index terms)..............................
217
218 typedef /* Packed */ struct
219   {
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
224   }
225 leafHeader;
226
227 typedef /* Packed */ struct
228   {
229   char key [10]  PACKED;
230   short int xxx  PACKED; // *** ONLY UNIX ISIS; 
231   long int infb  PACKED  // Reference to IFP segment *** != ISIS.MANUAL ***
232          , infp  PACKED; 
233   }
234 leafKey1;
235
236 typedef /* Packed */ struct
237   {
238   char key [30]  PACKED;
239   short int xxx  PACKED; // *** ONLY UNIX ISIS;
240   long int infb  PACKED  // Reference to IFP segment *** != ISIS.MANUAL ***
241          , infp  PACKED;
242   }
243 leafKey2;
244
245 typedef /* Packed */ struct
246   {
247   leafHeader hdr      PACKED;
248   leafKey1   idx [10] PACKED; // 2*ordf keys
249   }
250 leafBlock1;
251
252 typedef /* Packed */ struct
253   {
254   leafHeader hdr      PACKED;
255   leafKey2   idx [10] PACKED; // 2*ordf keys
256   }
257 leafBlock2;
258
259 typedef /* Packed */ union
260   {
261   leafBlock1 lb1 PACKED;
262   leafBlock2 lb2 PACKED;
263   }
264 leafBlock;
265
266 // Inverted File Posting structures..........................................
267 // ordained postings organized in segments: Index --> Master File
268
269 typedef /* Packed */ struct
270   {
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
274   }
275 ifpBlock;
276
277 typedef /* Packed */ struct  // This header and 1st posting - always in IFP block
278   {
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)
285   }
286 ifpHeader;
287
288 // ifpHeader & 1st ifpPosting always in the same ifpBlock
289 // Postings in Segment are always in chain of IFP blocks
290
291 typedef /* Packed */ struct // Stored left-->right + 0 --> 8 char
292   {
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
297   }
298 ifpPosting;
299
300 typedef struct
301   {
302   int        opened;     // Which files are opened (bit spec.)...
303   FILE       *mst;       //  1
304   FILE       *xrf;       //  2
305   FILE       *ifp;       //  4
306   FILE       *n01;       //  8
307   FILE       *l01;       // 16
308   FILE       *n02;       // 32
309   FILE       *l02;       // 64
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
314   }
315 BaseCtrl;
316
317 typedef struct  // This structer must be allways corelated with BaseCtrl
318   {
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
335   }
336 TableQuery;
337
338 #define RECLENGTH 8192
339
340 typedef union
341   {
342   char       buf [RECLENGTH];
343   RecHeaders hdrs;
344   }
345 RecCtrl;
346
347 // *** MAIN DATABASE FILE RELATIONS (MST <--> XRF) ***
348 //      1      2      3
349 // MST |-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|-mblk-|...
350 //       ctrl                  |----record----|
351 //                        |--->|
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 --------------|
358
359 // *** INVERTED FILE RELATIONS (N0x <--> L0x <-->IFP) ***
360 // N0x |-nbl-|-nbl-|-nbl-|-nbl-|-nbl-|-nbl-|...
361 //      -->-root->-|  |-->--next-->--|   |->-->-| r<0
362 //                                              |
363 // L0x |--lbl--|--lbl--|--lbl--|--lbl--|--lbl--|--lbl--|...
364 //                                                   |
365 //                  |-<--------------<-------------<-| r<0
366 // *** POSTING ***  |
367 // IFP |---ibl---|---ibl---|---ibl---|---ibl---|---ibl---|---ibl---|...
368 //       |next      |-ihd-|---Segment---|         |-ihd-|---Segment---|
369 //       |Seg.         |-->------>------>-next->--|      |||...
370 //                                                       MFN...
371 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
372
373 // #include "idef.c"
374
375 // Let's specify non int header ;-) just to keep order
376
377 void ShowRec (RecCtrl *rc);
378 void setQuery (BaseCtrl *bc, TableQuery *tq, char *sx, short int fld);
379 void isis ();
380
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.
388
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.
392
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.
397
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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
402
403 // gcc Linux Compiler conventions !
404 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
405
406 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
407
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);
412   return (0); // O.K.
413   }
414
415 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
416
417 void doUpcase (char *s, char *st, int slen)
418   { int i;
419   for (i = 0; i < slen; i++)
420     { if (i < strlen (st)) s [i] = UpCase [(int) st [i]]; else s [i] = ' '; }
421   s [slen] = 0;
422   }
423
424 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
425
426 int sComp (char *s1, char *s2, int len)
427   { int i;
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.
431     }
432   return (0); // .eq.
433   }
434
435 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
436
437 int bfOpen (FILE **f, BaseCtrl *bc, char *ext, char *opt)
438   { char st [81];
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);
442   return (0);
443   }
444
445 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
446
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
450   { ifpBlock ib;
451   bc->opened = 0;
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];
477   return (0);
478   }
479
480 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
481
482 void Done (BaseCtrl *bc)  // Close the database files
483   {
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);
491   }
492
493 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
494
495 char UpMe (char c) // ^A = ^a etc.
496   {
497   if (c > 96) c = c - 32;
498   return (c);
499   }
500
501 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
502
503 void outS (char *st)
504   {  char i;
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]);
511    }
512
513 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
514                     
515 void outC (char ch)
516   { char st [2];
517    st [0] = ch; st [1] = 0; outS (st);
518   }
519   
520 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
521   
522 void outD (double x, int n)
523   { char s [80];
524   gcvt (x, n, s);
525   outS (s);
526   }
527                                   
528 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
529
530 void outN (long int x) // long int -> sting @ base=10
531   {
532 //  char st [33];
533 //  ltoa (x, st, 10); outS (st);
534     printf ("%li", x); 
535   }
536
537 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
538
539
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.
547
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.
551
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.
556
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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
561
562 // gcc Linux Compiler conventions !
563 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
564
565 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
566
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;
575     long int xn, xb;
576     int      ret, nch;
577     xrfBlock xblk;
578     mstHdrFix *hf = &rc->hdrs.mhf;
579     mstHdrTxt *ht = &rc->hdrs.mht;
580     char      *b  = rc->buf;
581
582   if ((mfnr < 1) || (mfnr >= bc->mctrl.nxtmfn)) return (-2); // No record
583
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
590
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);
595
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
600
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);
613     }
614
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
618   return (ret);
619   }
620
621 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
622
623 int IsF (RecCtrl *rc, short int v, char ch, char *st)
624   { short     int n, k, kk, flag;
625     char      *b   = rc->buf;
626     mstHdrTxt *mht = &rc->hdrs.mht;
627     mstIndex  *ind = (mstIndex *) &rc->buf [sizeof (RecHeaders)];
628
629   flag = 0;
630   for (n = 0; n < mht->nvf; n++)
631     {
632     if (ind->tag == v) // there is a tag
633       {
634       if (ch == ' ') // field found
635         { flag = 1; break; }
636       else // there is sub-field
637         { flag = 1;
638         kk = 0; k = mht->base + ind->pos;
639         while (b [k] != '^' || b [k + 1] != ch)  // convention ;-)
640           { k += 1; kk += 1;
641           if (kk >= ind->len) // out of field
642             return (0);
643           }
644         break;
645         }
646       }
647     ind += 1; // next index ref.
648     }
649   if (flag == 0) return (0);  // false
650   if (st == NULL) return (1); // true
651   else
652     if (sComp (&b [mht->base + ind->pos], st, ind->len) == 0)
653       return (1);
654     else return (0);
655   }
656
657 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
658
659 void RepF (RecCtrl *rc, char nf, ...)
660
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.
664
665   { va_list   pinfo; // for ... parameter list
666     int       i, c, flag, n, k, kk, v;
667     int       hit = 0;
668     char      *sl, *sr;
669     char      *b   = rc->buf;
670     mstHdrTxt *mht = &rc->hdrs.mht;
671     mstIndex  *ind = (mstIndex *) &rc->buf [sizeof (RecHeaders)];
672
673   for (n = 0; n < mht->nvf; n++)
674     {
675     va_start (pinfo, nf);
676     for (i = 0; i < nf; i++)
677       {
678       kk = 0;
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
683       c = UpMe (c);
684       sr = va_arg (pinfo, char *);    // right
685       if (v != ind->tag) // another Tag
686         break;
687       if (c != ' ') // sub-field
688         { flag = 1;
689         while (b [k] != '^' || UpMe (b [k + 1]) != c) // convention ;-)
690           { k += 1; kk += 1;
691           if (kk >= ind->len)
692             { flag = 0; break; }
693           }
694         if (flag) { k += 2; kk += 2; }
695         }
696       else flag = 1;
697       if (flag)
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);
702         hit += 1;
703         if (c == ' ')
704           while (kk < ind->len)
705             {
706             if (b [k] != '<' && b [k] != '>') // HTML special ;-)
707               outC (b [k]);
708             k += 1; kk += 1;
709             }
710         else
711           while (kk < ind->len && b [k] != '^') // convention ;-)
712             {
713             if (b [k] != '<' && b [k] != '>') // HTML special ;-)
714               outC (b [k]);
715             k += 1; kk += 1;
716             }
717         outS (sr);
718         }
719       }
720     va_end (pinfo);
721     ind += 1;
722     }
723   }
724
725 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
726
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.
734
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.
738
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.
743
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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
748
749 // gcc Linux Compiler conventions !
750 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
751
752 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
753
754 int FindFirst (TableQuery *tq)
755   {
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
759     char       *ref;
760     leafHeader *lhdr = &tq->lbl.lb1.hdr;   // = ...lb2.hdr
761     nodeBlock  nbl;
762     nodeHeader *nhdr = &nbl.nb1.hdr;       // = ...nb2.hdr
763
764   if (tq->it == 1)
765     { klen = 10; srec = sizeof (nodeBlock1); sidx = sizeof (nodeIndex1); }
766   else
767     { klen = 30; srec = sizeof (nodeBlock2); sidx = sizeof (nodeIndex2); }
768
769   r = tq->cntr->posrx;  // Root in N0x
770   while (r > 0L)
771     {
772     if (ReadMem (&nbl, tq->n0x, r - 1, srec) != 0) return (-1);
773     j = nhdr->ock;
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;
780       else ref += sidx;
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
784     }
785
786   // Now find the term in L0x index
787   if (tq->it == 1)
788     { srec = sizeof (leafBlock1); sidx = sizeof(leafKey1); }
789   else
790     { srec = sizeof(leafBlock2); sidx = sizeof(leafKey2); }
791
792   r = - r;
793   if (ReadMem (&tq->lbl, tq->l0x, r - 1, srec) != 0) return (-1);
794   j = lhdr->ock;
795   if (lhdr->pos != r || lhdr->it != tq->it ||
796      j < 1 || j > 10) return (-2);  // 10 = 2*ordf
797
798   tq->ilk = 0;
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; }
804
805   ref -= sidx;
806   tq->term = ref; // We have the term address
807   if (tq->it == 1)
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
813   return (0);     // O.K.
814   }
815
816 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
817
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
822
823   if (tq->it == 1) srec = sizeof (leafBlock1);
824   else srec = sizeof (leafBlock2);
825
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
829     if (r <= 0)
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
834     tq->ilk = 0;
835     }
836
837   srec = tq->ilk;
838   if (tq->it == 1)
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;
842     }
843   else
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;
847     }
848   return (0); // We have the new key
849   }
850
851 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
852
853 int Find (BaseCtrl *bc, TableQuery tabq [], int ifind, long int *npg
854          , RecCtrl *rc, long int recvol)
855   { int i;
856
857   if (ifind <= 0 || ifind > NFIND) return (-1);
858   for (i = 0; i < ifind; i++)
859     if (FindFirst (&tabq [i]) < 0) return (-1);
860
861   i = Postings (bc, tabq, ifind, npg, rc, recvol);
862   return (i);
863   }
864
865 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
866
867 int IndexPrep (BaseCtrl *bc, TableQuery *tq1, TableQuery *tq2, char *st)
868   { char sx [31];             // tqx->v contains the status of L0x index
869     int  i;
870
871   if (st == NULL)
872     for (i = 0; i < 30; i++) sx [i] = ' ';
873   else
874     for (i = 0; i < 30; i++)
875       if (i < strlen (st)) sx [i] = st [i]; else sx [i] = ' ';
876
877   sx [30] = 0;
878   setQuery (bc, tq2, sx, 0);  // We have a long term in tq2; v := 0
879   if (FindFirst (tq2) < 0) return (-1);
880
881   sx [10] = 0;
882   setQuery (bc, tq1, sx, 0);  // We have a short term in tq1; v := 0
883   if (FindFirst (tq1) < 0) return (-1);
884
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);
888
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);
892
893   return (IndexTest (tq1, tq2));
894   }
895
896 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
897
898 int IndexTest (TableQuery *tq1, TableQuery *tq2)
899   {
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
904   else
905     if (tq2->v == 1) return (1);  // We have only 1st
906     else if (sComp (tq1->term, tq2->term, 10) <= 0) return (1);
907          else return (2);
908   }
909
910 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
911
912 int IndexTerm (int i, TableQuery *tq1, TableQuery *tq2)
913   {
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
916        else return (-1);
917   return (IndexTest (tq1, tq2));
918   }
919
920 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
921
922 void setQuery (BaseCtrl *bc, TableQuery *tq, char *sx, short int fld)
923   { // Must be activated AFTER the initialization of database
924
925   tq->v = fld;
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;
929     }
930   else
931     { tq->it = 2; doUpcase (tq->st, sx, 30);
932       tq->cntr = &bc->cnt2; tq->n0x = bc->n02; tq->l0x = bc->l02;
933     }
934   }
935
936 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
937
938
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.
946
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.
950
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.
955
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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
960
961 // gcc Linux Compiler conventions !
962 // *** ONLY UNIX ISIS = the difference between DOS/UNIX structures
963
964 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
965
966 int PostSeg (BaseCtrl *bc, TableQuery *tq)
967   {
968   if (ReadMem (&tq->ibl, bc->ifp, tq->ib - 1, sizeof (ifpBlock)) != 0)
969     return (-1);
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 ***
973   tq->iiseg = 0;
974   return (0);
975   }
976
977 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
978
979 int PostNext (BaseCtrl *bc, TableQuery *tq)
980   {
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);
986     }
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)
993       return (-1);
994     if (labs (tq->ibl.ifblk) != tq->ib) return (-3);
995     }
996   tq->ipst = (char *) &tq->ibl.ifrec [tq->ip];
997   return (0);
998   }
999
1000 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1001
1002 void PostMake (long int mfn, short int tag, char occ, short int pcnt
1003               , char *s, char *slen)
1004   { ifpPosting rnp;
1005     char *p = (char *) &rnp;
1006
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];
1012   }
1013
1014 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1015
1016 void PostInv (ifpPosting *ifpp, void *ps)
1017   { char *p = (char *) ifpp;
1018     char *s = (char *) ps;
1019
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     |
1023
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];
1026   }
1027
1028 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1029
1030
1031 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1032
1033 int main (int argc, char **argv)  // char *argv []
1034   { char c;
1035
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");
1041
1042   for (c = 'A'; c <= 'z'; c++) // Let's prepare it, we use API, not an example
1043     UpCase [c] = UpMe (c);
1044
1045   if (argv [1] != NULL) {
1046     strcpy (DBpath, argv [1]);  // Database; no test ! ;-) it's only an example
1047     isis ();
1048   }
1049
1050   return (0);
1051   }
1052
1053 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1054
1055 void isis ()
1056   { 
1057     int        j, v, k;
1058     long int   nrc;
1059     BaseCtrl   bc;
1060     RecCtrl    rc;
1061     char       st [31];
1062     TableQuery tabq [NFIND];
1063
1064   strcpy (bc.name, DBpath);
1065   InitBase (&bc);  
1066
1067 // ShowRec but not all...
1068
1069   printf ("\n*** ShowRec ***\n\n");
1070
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) {
1074       ShowRec (&rc);
1075     }
1076   }
1077
1078 // ShowIndex
1079
1080   printf ("\n*** ShowIndex: %s ***\n\n", st);
1081
1082   strcpy (st, "TEST"); // just an Inv. File term
1083
1084   v = 0; // term counter
1085   k = IndexPrep (&bc, &tabq [0], &tabq [1], st); // prepare indexes
1086   while (k > 0) {
1087     j = 20 * k - 10; // We have the term length ;-)
1088     memcpy (&st, &tabq [k - 1].term [0], j); // keep it in st
1089     st [j] = 0;
1090     if ((v += 1) > 12)  // we want 12 terms in a list
1091       {
1092       printf ("->%s\n", st);  // the next term
1093       break;
1094       }
1095     printf ("%s\n", st);
1096     k = IndexTerm (k, &tabq [0], &tabq [1]); // Next term
1097   }
1098
1099 // Find a term & show records
1100
1101   printf ("\n*** Search for: %s ***\n\n", st);  // Let's use the last term
1102
1103   setQuery (&bc, &tabq [0], st, 0);  // String to search in a filed 0 = any
1104   
1105   j = Find (&bc, tabq, 1, &nrc, &rc, RECLENGTH); // 1 term to search for
1106
1107 // Clean all
1108
1109   printf ("\nO.K.\n");
1110
1111   Done (&bc);
1112   }
1113
1114 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1115
1116 void ShowRec (RecCtrl *rc)
1117   { long int  nr;
1118     short int n, k, kk;
1119     char      st [256];
1120     char      *b   = rc->buf;
1121     mstHdrTxt *mht = &rc->hdrs.mht;
1122     mstIndex  *ind = (mstIndex *) &rc->buf [sizeof (RecHeaders)];
1123
1124   nr = rc->hdrs.mhf.mfn; // Record header
1125
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++]);
1133     printf ("\n");
1134     ind += 1; // Next index
1135     }
1136   printf ("___\n");
1137   }
1138
1139 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1140
1141 // This procedure is prepared to do a simple AND operator after some
1142 // extensions, so it can be localy a little strange ;-)
1143
1144 int Postings (BaseCtrl *bc, TableQuery tabq [], int ifind, long int *npg
1145              , RecCtrl *rc, long int recvol)
1146   { int        j, state;
1147     long  int  ipg, rn;
1148     ifpPosting ip;
1149     TableQuery *tq;
1150
1151   if (ifind < 1) goto finish; // nothing to do
1152
1153   ipg = 1L; // Index for page break
1154
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
1158       tq->iitot = 0;
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
1163     }
1164
1165   if (ipg != 1L) goto finish;
1166
1167   for ( ; ; ) // Global loop...
1168     {
1169
1170     // Is there a field
1171       { tq = &tabq [0];
1172       if (tq->v != 0)
1173         while (ip.ptag != tq->v)
1174           {
1175           if (PostNext (bc, tq) > 0) goto finish; // No more postings
1176           PostInv (&ip, tq->ipst);
1177           }
1178       }
1179
1180     rn = ip.pmfn; 
1181     
1182     state = 1;
1183     if (ip.pmfn != rn)
1184       state = 0;
1185
1186     if (state) // We have a record to show
1187       {
1188       if ((j = GetRec (bc, rn, rc, recvol)) == 0)
1189         ShowRec (rc);
1190       else 
1191         printf ("Record state = %li\n", j); 
1192
1193         do // Shift all postings
1194           { tq = &tabq [0];
1195           if (PostNext (bc, tq) > 0) goto finish; // No more postings
1196           PostInv (&ip, tq->ipst);
1197           }
1198         while (ip.pmfn <= rn); // MFN equals
1199       }
1200     else // state == 0, Shift all postings
1201         while (ip.pmfn < rn)  // The last is to examin
1202           { tq = &tabq [0];
1203           if (PostNext (bc, tq) > 0) goto finish; // No more postings
1204           PostInv (&ip, tq->ipst);
1205           }
1206     }
1207
1208 finish:
1209   return (0); // The output is finished
1210   }
1211
1212 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1213