/*
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 <dbpath>
*/
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
// 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 <database>\n");
printf ("<database> ::= 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
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++