a99  V32.6
allegro Windows Hauptprogramm
 Alle Klassen Dateien Funktionen Variablen Typdefinitionen Aufzählungen Aufzählungswerte Makrodefinitionen
index.cpp
gehe zur Dokumentation dieser Datei
1 // Klasse INDEX (c) UB Braunschweig 1995
2 // 1995-08-19 : Index einer Datenbank
3 // INDEX.CPP abgeleitet aus %% DOS-Programm index.exe
4 
5 // Copyright 2011 Universitätsbibliothek Braunschweig, more see bottom
6 
7 // Basiert auf der Klasse EXET = Export-Parameterdatei
8 
9 #include "index.hpp" // darin Dokumentation der Funktionen
10 // darin auch Einbindung der ai-Dateien f.d. Index-Kernfunktionen
11 
12 // FUNKTIONEN, die von aussen benutzbar sind, Kurzuebersicht
13 
14 // InOpen() : Indexdatei oeffnen
15 // InSwix() : Umschalten auf andere Indexdatei
16 // InSTL() : STLget(): Kurzzeile zur Satznr holen
17 // InFindEnt() : ADXfnd() : einzelnen Indexeintrag finden
18 // InGetSet() : ADXget() : Erg.Menge bilden (Einzel-Suchbef., nicht log. Komb.!)
19 // InRemDupl() : Duplikate aus Erg.Menge beseitigen, incl. Sort. nach Satznr.
20 // InExpand() : Erg.Menge expandieren (mit SR-Schl.)
21 // TBLopen() : .TBL oeffnen
22 // InV14Repl() : V14-Aufloesung im Satz ausfuehren (frueher refer() )
23 // InKeyCalc() : Schl. eines Satzes errechnen, mit oder ohne Speichern
24 // InIDecode() : Nutzereingabe gem. .API umcodieren (#-1 anwenden usw.)
25 // InRsort() : Erg.Menge sortieren
26 // InRestrict() : Restriktion auf Erg.Menge anwenden
27 // InRestri() : Restr. auf einzelnen Satz anwenden
28 // InMaxRecNr() : MaxRecordNr() : hoechste Satznr. ermitteln
29 // InIsStop() : Ist das Wort ein Stoppwort?
30 // InRecn2Str() : Satznr. in String wandeln
31 // InStr2Recn() : String in Satznr. wandeln
32 
33 
34 // HINWEIS: Die Klasse enthaelt nur einfache Suchfunktionen!
35 // Komplexe Funktionen, z.B. mit boolescher Logik, koennen darauf aufbauen.
36 // Als Beispiel gibt es das Modul rpnfind.cpp, das in a99 und acon
37 // Verwendung findet. Der Vorteil ist, dass man es weglassen kann und durch
38 // etwas eigenes ersetzen, statt es zwangslaeufig mit einbinden zu muessen.
39 
40 #ifndef UNIX
41 #include <share.h>
42 #endif
43 
44 #define okn Rcu->rKx // compatibility with old DOS program code
45 #define oldkeys Rcu->rKy
46 #define okf Rcu->rKf // compatibility (old key flags)
47 
48 // KONSTRUKTOR
49 // directory , APIname, KONFIG, access flag
50 //z.B. INDEX("C:\ALLEGRO\DEMO\","CAT", "AXY", 3)
51 
52 
54 
55 int Adn1=0; // number of secondary index file MultiX
56 
57 
58 // KONSTRUKTOR
59 
60 INDEX::INDEX(char *dbdir, char *dbn, KONFIG *kfg,int acc,
61  int iMult, char *inxName, char *inxParam)
62  : EXET(inxParam?inxParam:dbn,kfg,1,dbdir) // Ableitung von Indexparameterdatei
63  // d.h. EXET::EXET() wird zuerst aufgerufen!
64 {
65  int i;
66  if (*Aerror!=0) return; // the EXET constructor had trouble!
67  if (acc==-1) return; // Aufruf mit -1: Index wird nicht geoeffnet
68  accf=acc; // access flag
69  aix='d'; // MultiX
70 
71 #ifndef UNIX
72  if (acc)
73  filmod=O_RDWR | O_CREAT | O_BINARY;
74  else
75  filmod=O_RDONLY | O_BINARY;
76 #else
77  if (acc)
78  filmod=O_RDWR | O_CREAT;
79  else
80  filmod=O_RDONLY;
81 #endif
82  mult=iMult; // shared mode as default!
83  shflag=0;
84 #ifdef UNIX
85  if (mult) shflag=O_DENYNONE;
86 #else
87  if (mult) shflag=SH_DENYNO;
88 #endif
89 
90  rr=new RECORD(kfg,300,20,20); //$$960422
91  rr->Adn=0;
92  // strcpy(dbDir,dbdir);
93  strcpy(dbN,dbn); // make names available to members
94 // printf("\nsvTable[35]=%d",svTable[35]); //test
95  svTable=svTab;
96  if (inxName!=NULL) strcpy(dbDx,inxName);
97  else sprintf(dbDx,"%s%s.%cdx%c",dbDir,dbN,kfg->schema,0); // dbn.adx
98 
99  if (!aiFlag) // first time INDEX is called:
100 // make room for 5 database indexes:
101  if ((i=NewAIX(6,65,16))!=0 && i!=125) // aindex initialization
102  { // 179 = Fehler beim Initialisieren
103  sprintf(Aerror,uif[179],aiG_fhln,errno,0);
104  return;
105  }
106  aiFlag=1; // global!
107  Adn=activeNr(accf); // log. Nr. f. diese Datenbank festlegen
108  // falls zur Laufzeit mehrere ABASE-Objekte gebraucht werden
109  // muss jedes eine andere interne log. Nr. haben
110  if (Adn==-1)
111  {
112  sprintf(Aerror,"More than 5 not possible%c",0);
113  return;
114  }
115  i=InOpen(5);
116  if (i==1) i=InOpen(5); // NEW $$000612
117  if (i==-1) return; // error msg in Aerror!
118  if (stll) dbSt=Tblopen(".stl"); // stll = length of short titles
119  if (dbSt==EOF)
120  { // Datei %s kann nicht geoeffnet werden
121  sprintf(Aerror,uif[187],".stl",0);
122  }
123  if (resl)
124  {
125  dbre=Tblopen(".res"); // resl = length of restrictions
126  if (dbre==EOF) // Datei %s kann nicht geoeffnet werden
127  sprintf(Aerror,uif[187],".res",0);
128  }
129 }
130 
131 // open .ADX file: %% DOS: opnfil() in npresto3.c
132 
133 int INDEX::InOpen(int n) // try n times
134 {
135  int mu=aiPERM;
136  int m=n;
137  if (mult) mu=mu|aiMULTI; // Mehrplatzmodus
138  if (!accf) mu=mu|aiRDONL; // nur Lesen
139  while (m) // try m times:
140  {
141  if (aiOPEN(Adn*15,(CHAR*)dbDx,mu)) // logical numbers are 0, 15, 30, 45, 60
142  {
143  if (errno==ENOENT) // keine solche Datei <errno.h>
144  {
145  m=0;
146  break;
147  }
148  SyPause(1);
149  --m;
150  }
151  else return 0; // success
152 
153  } // no success - no index file exists: create the index file!
154  if (!Adn && aix=='d') // wenn Adn>0 oder aix!='d', dann gibt es schon einen Index (MultiX),
155  // d.h. hier darf dann nicht gemacht werden
156  {
157  if (aiNewInx(0,dbDx,keymax,12,1024,0))
158  {
159  sprintf(Aerror,uif[167],aiG_fhln,dbDx,errno);
160  return -1; // create fails
161  } // aiNewInx error %d" 13 10
162  int i=0;
163  while (i<12) aiNewReg(0,keymax,++i);
164  i=0;
165  aiCLOSE(0,0);
166  return 1; // new index file created
167  }
168  if (n>1 && !m)
169  {
170  sprintf(Aerror,uif[167],aiG_fhln,dbDx, errno);
171  // Fehler %d %s bei Index-Datei %s, error %d"
172  }
173  return -1; // no success at all
174 }
175 
176 // $$2007-02-15 NEU : switch to .AkX (MultiX). ret Adn: OK / -1: not OK
177 /*
178 int INDEX::InSwix(char k) // Version mit 2 offenen Indexfiles - klappt nicht
179 { char *ad; ad=dbDx+strlen(dbDx)-2;
180  if(k=='d') { Adn=0; aix=*ad='d'; return 1; }
181  if(k==aix) { Adn=Adn1; return 1; } // same as before
182  if(Adn1!=0) aiCLOSE(Adn1*15,0); // neue Adn muss nur beim ersten mal vergeben werden
183  else Adn1=activeNr(accf); // Wenn schon Adn>0, dann ist auch eine zweite Indexdatei offen, also schliessen
184  *ad=k; Adn=Adn1; // Adn ist die Nummer der jeweils aktiven Indexdatei, beim Start immer 0
185  if(InOpen(5)==-1) { Adn=0; sprintf(Aerror,uif[194],k,dbDx); aix=*ad='d'; return -1; }
186  aix=k; *Aerror=0;
187  return Adn;
188 }
189 */
190 
191 int INDEX::InSwix(char k) // Version mit close/open - langsamer, aber klappt
192 {
193  char *ad;
194  if (k==aix) return Adn; // dieselbe Nr. - dieser Index ist bereits offen
195  aiCLOSE(Adn*15,0);
196  ad=dbDx+strlen(dbDx)-2;
197  aix=*ad=k;
198  if (InOpen(5)==-1)
199  {
200  sprintf(Aerror,uif[194],k,dbDx);
201  aix=*ad='d';
202  InOpen(5);
203  return -1;
204  }
205  *Aerror=0;
206  return Adn;
207 
208 }
209 
210 // Get 1 line from STL
211 int INDEX::InSTL(RECNR recn, CHAR *found, int md)
212 {
213  if (!stll) return 0; // there's no STL file
214  lseek(dbSt,recn*(RECNR)stll,0); // get shortline of recn
215  if ((read(dbSt,(char *)found,stll))==EOF) return 0;
216  found[stll]=0;
217  if (md) E3Coding(found); // ASCII->ANSI
218  return 1;
219 }
220 
221 
222 char fval[260]; // Hilfsvar.
223 
224 // Index-Zugriffsfunktionen
225 
226 // Finde einen Registereintrag:
227 
228 RECNR INDEX::InFindEnt(int reg, char *value, char *found, int modus, RECNR recn)
229 // modus: -2 : key < value
230 // -1 : key <= value
231 // 0 : key == value (wenn recn>0L : auch Satznummer==recn)
232 // 1 : key >= value, aber Anfangsteil von value==key
233 // 2 : key >= value
234 // 3 : key > value
235 // 4 : key > value, aber Anfangsteil von value==key
236 // %% aiEntGe(), aiEntEq()
237 // result: key found is written into found
238 // return: first rec# if there was a match
239 // 0L : nothing (index empty or no match)
240 {
241  RECNR xx; // recn
242  int i;
243  strcpy(fval,value);
244  while(*fval==32) strcpy(fval,fval+1);
245  i=strlen(fval)-1;
246 
247 // if(fval[i]=='?') { modus=1; fval[i]=0; } // Trunkierung XXX noch aendern?
248 
249  InIDecode(reg,fval); // Umcodierung von fval
250  i=strlen(fval); // kann sich veraendert haben!
251  --reg; // Reg.1 ist intern 0...
252  svTable=svTab; // make this address global, for aindex!
253  if (i<keymax)
254  {
255  while (i<=keymax) fval[i++]=NL;
256  }
257  if (modus>=0) InRecn2Str(recn,(CHAR *)(fval+keymax-4)); // recn to fval+keymax-4 for aindex
258  switch (modus)
259  {
260  case -2: // <
261  while(*fval==32) strcpy(fval,fval+1);
262  return aiEntLt(reg+Adn*15,(CHAR*)fval,(CHAR*)found);
263 
264  case -1: // <=
265  return aiEntLe(reg+Adn*15,(CHAR*)fval,(CHAR*)found);
266 
267  case 0: // equal
268  if (recn) return aiEntEq(reg+Adn*15,(CHAR*)fval);
269 
270  case 1: // >=
271  xx=aiEntGe(reg+Adn*15,(CHAR*)fval,(CHAR*)found);
272  if (!strncmp(fval,found,strlen(fval))) return xx;
273  else return 0L;
274 
275  case 2: // >=
276  return aiEntGe(reg+Adn*15,(CHAR*)fval,(CHAR*)found);
277 
278  case 3: // > really next key
279  fval[strlen(fval)+1]=0;
280  fval[strlen(fval)]=1; // $$970214 sonst geht ALPHA nicht
281 
282 // fval[keymax-5]=127; // make sure the next key > fval is found
283 
284  case 4: // > next entry
285  while(*fval==32) strcpy(fval,fval+1);
286  return aiEntGt(reg+Adn*15,(CHAR*)fval,(CHAR*)found);
287 
288  default:
289  return 0L;
290  }
291 
292 }
293 
294 // Version zur Bildung von Ergebnismengen
295 // Eine Erg.Menge ist nichts als ein Array von Satznummern: RECNR res[]
296 
297 // Auch: Kombination UND/ODER/NICHT mit einer vorherigen Erg.Menge
298 // Hinw.: Hoehere Funkt. f. komplexe Suchen: rpnfind.cpp bzw. avfind.cpp (acon)
299 
300 // Beispiele:
301 // xxx->InGetSet(3,"wort"); wie oft kommt "wort" im Reg. 3 vor?
302 // xxx->InGetSet(3,"wort",1); wie oft kommt "wort?" im Reg. 3 vor?
303 // get results: $$970831 neue Algorithmen fuer AND OR NOT
304 // 2 neue Aufrufparameter: pr und op (optional!)
305 
306 char val[260], fnd[260], bis[260];
307 
308 RECNR INDEX::InGetSet(int reg, char *value, int modus, RECNR maxr,
309  RECNR *res, CHAR *restri, unsigned int pr, char op)
310 // reg: 1..11, Registernr.
311 // value: zu suchende Zeichenfolge
312 // modus: 0 : key == value
313 // 1 : key >= value, aber Anfangsteil von value==key (Truncation)
314 // 2 : dasselbe, aber nicht sortieren
315 // maxr: max number of results
316 // res[]: list of rec numbers
317 // restri: qualifier, rpoXXX
318 // pr: number of results from previous commands
319 // d.h. pr Nummern sind schon in res[]
320 // op: operator : A O N; O works like 0
321 
322 // return: number of entries, -1 if nothing, 0 if too many (!)
323 // rec numbers are in res[0], res[1], ...
324 {
325  RECNR xx; // recn
326  RECNR lMaxRecN=InMaxRecNr(); // maximale Satznummer d. Datenb.
327  RECNR nr=pr; // number of hits $$970922 nr=pr statt nr=0
328  int sm=1; // Satznummern aufzeichnen, 0: nicht aufz.
329  int bm=-1; // binary mode: 1=number found, -1=not found
330  int iExceed=0;// Flag, dass nr=maxr
331  if (!res) sm=0,maxr=8000000L; // statt 264000, $$070702
332  // wenn keine Nummernliste, dann Anzahl unwichtig, hoechstens f. Performance
333  svTable=svTab; // make this address global, for aindex!
334 
335  strcpy(val,value);
336  *bis=0;
337 
338  char *b=strstr(val,"---"); // Von/Bis-Suche?
339  if (b)
340  {
341  modus=1;
342  *b=0;
343  strcpy(bis,b+3);
344  if (!*bis) *bis=254;
345  else InIDecode(reg,bis);
346  }
347 
348  InIDecode(reg,val); // umcodieren per .API Sprungmarke #-1...#-9
349  pad((CHAR *)val,modus);
350  --reg; // Reg.1 ist intern 0...
351 
352 // int i=strlen(val);
353 // if(i<keymax) { while(i<keymax+4) val[i++]=NL; } //padding
354 
355  if (op=='O') op=0; // because OR is default
356  switch (modus)
357  {
358  case 0: // equal Exakte Suche nach val
359  if (!(xx=aiEntGe(reg+Adn*15,(CHAR*)val,(CHAR*)fnd))) return -1; // nix gefunden
360  if (strcmp(val,fnd))
361  { // ungleich, also nix gefunden
362  switch (op) // $$971111 ve: altes Ergebnis retten
363  {
364  case 'A':
365  return 0; // ausser bei UND-Verknuepfung
366  default:
367  return nr;
368  }
369  }
370  if (restri) xx=InRestri(xx,restri);
371  if (xx)
372  {
373  if (pr) bm=bfind(xx, res,0,pr);
374  if (bm==-1)
375  {
376  if (!op && sm) res[nr]=xx;
377  ++nr;
378  }
379  }
380 
381  while (1)
382  /* // Version aiEntGt, langsam
383  { xx=aiEntGt(reg+Adn*15,fnd,val);
384  if(!xx) break;
385  if(strcmp(val,fnd)) break; // ungleich
386  else if(xx>lMaxRecN)continue; // Plausibilitaetstest: Ungueltige Satznummer
387  if(sm) res[nr]=xx;
388  ++nr;
389  if(nr==maxr){ iExceed=1;break;}
390  }
391  */
392 
393  { // Version aiEntNxS, schnell (aber nur bei Einzelplatz sicher!)
394  xx=aiEntNxS(reg+Adn*15,(CHAR*)fnd);
395  if (!xx) break;
396  if (restri) if (!(xx=InRestri(xx,restri))) continue;
397  if (strcmp(fnd,val)) break;
398  if (xx>lMaxRecN) continue; // Plausibilitaetstest: Ungueltige Satznummer
399  if (pr) bm=bfind(xx, res,0,pr);
400  if (bm==-1)
401  {
402  if (!op && sm) res[nr]=xx;
403  ++nr;
404  }
405  if (nr>maxr && !op)
406  {
407  iExceed=1; // $$040418 !op
408  break;
409  }
410 
411  }
412  break;
413 
414  default: // >= Trunkierte Suche (Anfangsteil = val)
415  {
416  int l=strlen(val);
417  if (!(xx=aiEntGe(reg+Adn*15,(CHAR*)val,(CHAR*)fnd))) return -1; // nix gefunden
418  if ((!b && strncmp(val,fnd,l)) || (b && strcmp(bis,fnd)<=0))
419  { // ungleich...
420  switch (op)
421  { // $$971111 ve: altes Ergebnis retten
422  case 'A':
423  return 0; // ausser bei UND-Verknuepfung
424  default:
425  return nr;
426  }
427  }
428 
429  if (restri) xx=InRestri(xx,restri);
430  if (xx)
431  {
432  if (pr) bm=bfind(xx, res,0,pr);
433  if (bm==-1)
434  {
435  if (!op && sm) res[nr]=xx;
436  ++nr;
437  }
438  }
439  if (nr>maxr && !op)
440  {
441  iExceed=1; // Maximum ueberschritten $$040418 !op
442  break;
443  }
444  {
445  bm=-1;
446  while (1)
447  /* VERSION aiEntGt langsam, aber bei Mehrplatz sicher
448  {
449  xx=aiEntGt(reg+Adn*15,fnd,val);
450  if(!xx) break;
451  if(restri) if(!(xx=InRestri(xx,restri))) continue; // Restr. nicht erfuellt
452  if(strncmp(fnd,val,l)) break;
453  else if(xx>lMaxRecN)continue; // Ungueltige Satznummer
454  if(sm) res[nr]=xx;
455  ++nr;
456  if(nr==maxr) { iExceed=1;break;}
457  }
458  */
459 
460 // Ende Version aiEntGt
461 // VERSION aiEntNxS schnell, aber bei Mehrplatz unsicher
462  {
463  xx=aiEntNxS(reg+Adn*15,(CHAR*)val); // naechster Schluessel
464  if (!xx ) break; // Register zu ende
465  if (restri) if (!(xx=InRestri(xx,restri))) continue; // Restr. nicht erfuellt
466  if (!b && strncmp(fnd,val,l)) break; // gefundener Wert ungleich
467  else if (b && strcmp(val,bis)>=0) break;
468  if (xx>lMaxRecN)
469  continue; // Plausibilitaetstest: Ungueltige Satznr., geloeschter Satz, Schrott
470  if (pr) bm=bfind(xx, res,0,pr); // Nummer markieren, wenn schon vorh.
471  if (bm==-1)
472  {
473  if (!op && sm) res[nr]=xx; // $$981107 Klammer korrig.
474  ++nr;
475  }
476  if (nr==maxr && !op)
477  {
478  pr=InRemDupl(res,nr,modus);
479  if ((long)pr<nr-3L)
480  {
481  nr=pr;
482  continue;
483  }
484  iExceed=1;
485  break;
486  } // Maximum ueberschritten $$040418 !op
487  }
488 // Ende Version aiEntNxS */
489  }
490  break;
491  }
492  if (iExceed) break; // $$040531 fehlte
493  }
494 
495  RECNR k, j, i;
496  if (sm)
497  {
498  i=k=0;
499  j=1;
500 // $$970210 : sizeof(RECNR) statt (RECNR*)
501  if (op=='A')
502  {
503  j=0;
504  while (j<(long)pr)
505  {
506  if (res[j] & 0x80000000) res[i++]=res[j] & 0x7FFFFFFF;
507  ++j;
508  }
509  k=i;
510  }
511  if (op=='N')
512  {
513  j=0;
514  while (j<(long)pr)
515  {
516  if (!(res[j] & 0x80000000)) res[i++]=res[j];
517  ++j;
518  }
519  k=i;
520  } // reset the flags:
521  i=0;
522  if (pr) while (i<(long)pr)
523  {
524  res[i] = res[i] & 0x7FFFFFFF;
525  ++i;
526  }
527  }
528  else k=nr; // $$970922 else k=nr und sm:
529 
530  if (!op && sm) // normale Suche oder OR
531  {
532  k=InRemDupl(res,nr,modus);
533  }
534  if (sm && res && k<maxr)memset(res+k,0,(maxr-k)*sizeof(RECNR)); // nicht benoetigter Rest auf 0 setzen
535  return (iExceed? -1: k); // Rueckgabe -1, wenn maxr-Treffer erreicht
536 }
537 
538 // Duplikate aus einer Erg.Menge beseitigen (ident. Satznummern)
539 
540 long int INDEX::InRemDupl(RECNR *res,RECNR nr,int modus)
541 {
542  RECNR k, j;
543 
544  if (modus!=2)
545  qsort(&res[0],nr,sizeof(RECNR),&UtComplong); // Sortieren nach Satznummern
546  k=0;
547  j=1;
548  while (j<nr) // Doppelte Nummern beseitigen
549  {
550  while (res[k]==res[j]) ++j;
551  if (j<nr) res[++k]=res[j++];
552  }
553  ++k;
554  if (j>nr) --k;
555  return k;
556 }
557 
558 // $$970227 NEU SR-Funktion
559 // Ergebnismenge expandieren (satzuebergreifende Suche)
560 // maxr = max size of result set
561 // results = result set array
562 // rex = current size of res set
563 // qua = Qualifier, optional (default 0)
564 // return number of results (>= rex)
565 
566 int INDEX::InExpand(int maxr, RECNR *results, int rex,char qua)
567 {
568  int i=0;
569  int k=rex;
570  int m;
571  RECNR r0, r1;
572  CHAR idxval[260], Newkey[260];
573  if (!rex) return 0;
574  while (i<k) // SR-Schluessel suchen
575  {
576  if (rex>maxr) break;
577  sprintf((char *)idxval,"|%ld%c%c",results[i++],qua,0);
578  pad(idxval);
579  r0=r1=aiEntGe(i7+Adn*15,idxval,Newkey); // i7=nr of SR index
580  if (!strcmp(idxval,Newkey))
581  while (1)
582  {
583  if (r0) results[rex++]=r0;
584  else break;
585  if (rex>maxr) break;
586  while ((r1=aiEntNxS(i7+Adn*15,Newkey))==r0);
587  r0=r1;
588  if (strcmp(idxval,Newkey)) break;
589  }
590  }
591  if (rex>maxr) return 0; // too many results
592  if (rex>k) // Sortieren, Duplikate raus
593  {
594  m=0;
595  qsort(&results[0],rex,sizeof(RECNR),UtComplong); // and sort them
596  i=1;
597  while (i<rex)
598  {
599  while (results[m]==results[i]) ++i;
600  if (i<rex) results[++m]=results[i++];
601  }
602  if (i>rex) --m;
603  rex=m+1;
604  results[rex]=0L; // $$020528 vorher weiter oben!
605  }
606  return rex;
607 }
608 
609 
610 // Open .TBL .STL or .RES file
611 
612 int INDEX::Tblopen(char *fileType,int iWriteAccess) // fileType=".tbl" ...
613 {
614 // iWriteAccess (default ='\07') erlaubt das OEffnen der TBL im Readonly-Modus unabh. von accf
615  int i;
616 // ixpath noch prog. XXXX
617 // extern char ixpath[];
618 // if(!Adb && Type[1]=='s' && *ixpath) strcpy(dbtbl,ixpath);
619 // else strcpy(dbtbl,path);
620  char dbTN[PATH_SIZE]; // table name
621 
622  iWriteAccess=accf & iWriteAccess;
623  strcpy(dbTN,dbDir);
624  strcat(dbTN,dbN);
625  strcat(dbTN,fileType);
626 #ifndef UNIX
627  if (!iWriteAccess) return sopen(dbTN,(O_RDONLY | O_BINARY) & ~O_CREAT,shflag); // RDONLY
628  else if ((i=sopen(dbTN,filmod & ~O_CREAT,shflag))==EOF) // it exists?
629  i=sopen(dbTN,filmod,shflag,S_IREAD|S_IWRITE); // no, CREATE
630 #else
631  if (!iWriteAccess) return open(dbTN,(O_RDONLY & ~O_CREAT) | shflag); // RDONLY
632  else if ((i=open(dbTN,(filmod & ~O_CREAT) | shflag))==EOF) // it exists?
633  i=open(dbTN,filmod | shflag,S_IREAD|S_IWRITE); // no, CREATE
634 #endif
635  if (i==EOF) sprintf(Aerror,"%s cannot be opened%c",dbTN,0);
636  return i;
637 }
638 
639 // Compare two strings
640 int INDEX::compk(const void *a1, const void *a2)
641 {
642  return ai_scmpar((unsigned char*)a1,(unsigned char*)a2);
643 }
644 
645 
646 // Hilfsvar.
647 CHAR nwkey[260], olkey[260];
648 
649 // V14-Referenzen aufloesen: z.B. _s4054714 -> Shakespeare, William
650 
651 void INDEX::refReplace(CHAR *adr, int i4, int i8) // V14 : adr enthaelt Referenz, aufloesen
652 { // i8 = Endecode, sonst wird nur alnum gewertet
653  int k,j=0;
654  CHAR a, *c, *key, *w;
655  w=fend+1; // als Hilfsspeicher! fuer den Ergebnis-String, adr -> w
656  c=adr; // z.B. a="#40 _12345_XYZ"
657  // oder "#3000 !123456789!Name, Vorname"
658  // oder "#31 _1234; _2345; _3456"
659  // ist mit Modus i4 nach w zu ueberfuehren
660  if (*c==RS) c+=2; // $$941021 Satz beginnt hier
661  strncpy(w,c,kfg->skt); // _ auf der Indikatorposition erlaubt!
662  j=kfg->skt;
663  c+=j;
664  while (*c) // c laeuft als Zeiger in adr, Inhalt -> w
665  {
666  while (*c && (w[j++]=*c++)!=i5) ; // adr -> w, bis i5 gefunden wird
667  if (!*c) break; // jetzt ist z.B. c=12345_XYZ
668  k=0; // ic=1 wenn i5=__ gesetzt, d.h. _kuerzel_ statt nur _kuerzel
669  if (ic)
670  {
671  while (c[k] && c[k]!=i5) ++k;
672  *nwkey=i5;
673  nwkey[1]=0;
674  if (!c[k]) --k;
675  }
676  else
677  {
678  *nwkey=0; // bis ein nicht-alnum-Zeichen kommt
679  while (isalnum(c[k])) ++k;
680  }
681  if (!k)
682  {
683  w[j++]=*c++; // $$991221 NEU falls hinter _ nichts steht
684  continue;
685  }
686  a=c[k];
687  if (a) c[k++]=0; // mit 0 abschliessen, d.h. jetzt c=kuerzel, c+k=XYZ
688 
689  if (a==' ' && ic) a=i5; // Wenn auf Kuerzel ' ' folgt, durch i5 ersetzen (nur bei i5=__ wirksam
690  strcat(nwkey,c);
691  strcat(nwkey,"="); // c -> newkey, und nach c suchen:
692  if (ic) nwkey[strlen(nwkey)-1]=i5;
693  if (a) c[k-1]=a; // die 0 wieder durch das Zeichen ersetzen, das da stand
694 // find 1st key greater/equal nwkey
695  if (!aiEntGe(i6+Adn*15,(CHAR*)nwkey,(CHAR*)olkey)) continue; // nicht gefunden
696 // if(ic) key=(CHAR *)strchr((char *)olkey+1,i5);
697 // else
698  key=(CHAR *)strchr((char *)olkey,'='); // key= "=|iabc" oder "=abc"
699  if (!key++) continue;
700 // if(ic) ++key; // i5=__ : _ auch hinter dem Schl.
701  if (!a) ++k; // sonst _tuc -> Tucholsky, wenn hinter _tuc nichts mehr steht (a==0)
702  if (ic) ++k; // wenn i5=__, dann noch ein Zeichen mehr vergleichen
703  if (strncmp(nwkey,olkey,k)) continue; // gefund. Schl. ungleich
704 // if(a==i5) ++k; // i5 Hinter dem text wegnehmen im Fall !nnnn!
705  if (!a) --k; // rueckgaengig
706  if (i4 & 4)
707  {
708  strcpy(w+j,c); // i4 & 4: Klartext hinter _nn_ belassen
709  j+=k;
710  if (a && (i4 & 4)) --j;
711  }
712  if (i4<2) --j; // sonst Modus i4=1 falsch
713  c+=(k-1);
714  if (!a) ++c; // jetzt c=XYZ
715  if (*c==i5) ++c; // i5 Hinter dem text wegnehmen im Fall !nnnn!
716  if (*key=='|') key+=2; // Ersetz.schl beginnt mit |x (nur f. 2nd run bei INDEX.EXE)
717 // if(i4 == 6) w[j++]=i5;
718  if (i4 & 4) if (w[j-1]!=i5) w[j++]=i5;
719  if (i4 == 4) if (*c && *c==i5) ++c;
720  if (i4 & 1) ;
721  else if (*c) *c=0; // i4=1,3,5: XYZ soll bleiben
722  while (*key) w[j++]=*key++; // abc nach w kopieren
723 // if(*c && !isspace(*c)) w[j++]=' '; // kommt noch was nach, Space dazwischen
724  }
725  w[j]=0;
726  return;
727 }
728 
729 // Hauptfunktion für V14:
730 // Referenzen im ganzen Satz finden und aufloesen
731 
732 void INDEX::InV14Repl(RECORD *rec, int i4)
733 {
734  CHAR *X, *Y;
735  int i=rec->cri,cri0=rec->cri;
736  if (!i5) return;
737  if (i4==-1) return;
738  Rcu=rec; // Rcu global f.d. Klasse
739  aiEntPr(i6+Adn*15,(CHAR*)pend+1); // aktuellen Schl. von Reg. i6 hier parken!
740 
741  InSwix('d'); // vorsichtshalber
742 
743  int K;
744  while (i<Rcu->gri) // Kategorien einzeln durcharbeiten
745  {
746  if (*Rcu->ga[i]==RS) Rcu->cri=i;
747  if (strchr(Rcu->ga[i],i5)) // kommt i5 in ga[i] vor?
748  { // sonst nichts zu tun
749  X=Rcu->ga[i]+kfg->tgl+1;
750  Y=fend+1+kfg->tgl+1;
751  if (*X=='~') *X=11;
752  refReplace(Rcu->ga[i],i4,ia); // sucht und ersetzt V14-Schluessel in ga[i]
753  if (strcmp(Rcu->ga[i],fend+1))
754  {
755  K=Rcu->Ins(fend+1); // ga[i] mit aufgeloesten Schluesseln jetzt bei fend+1
756  }
757  else K=i;
758  if (*X==11) *X=Rcu->ga[K][tgl+1]='~';
759 
760  } // fend+1 als Hilfsspeicher!
761  ++i;
762  if (Rcu->ga[i][1]==1) break;
763  }
764  Rcu->cri=cri0;
765  aiEntEq(i6+Adn*15,(CHAR*)pend+1); // pointer in Reg. i6 zurücksetzen!
766  aiEntNx(i6+Adn*15,(CHAR*)pend+1);
767  return;
768 }
769 
770 
771 // Schluessel des Satzes berechnen; store==1: mit Speichern
773 // produce all keys %% idx_out()
774 // return: number of keys produced, -1 = out of memory
775 // in Rec->oldkeys sind Rec->rKx "alte" Schluessel, die vor dem Aendern gueltig waren
776 // wenn einer davon bei der Neuberechnung nicht mehr entsteht, ist er zu loeschen
777 {
778  int k;
779  int cri0;
780 // aus exet.hpp werden gebraucht:
781 // extern int rkflag, rkp1, rkp2, xpy, xbl;
782 // extern int mn, prfl, xrm[], xkS[], xkT[], xks, xkt, xrp[], xpx[];
783 // extern CHAR *xrk, *xrK[], xkE[][50], *ch1, *ch2;
784 // extern char *xke, *xpb, *xk1;
785 
786  int kycnt; // Schl.zaehler
787  CHAR idxval[260], nwkey[260]; // hilfsvar
788  int i;
789  RECNR r0; // $$970227
790 
791  rec=Rcu=Rec; // make available
792  cri0=cri;
793  rkflag=1;
794  cri=rkp1=rkp2=0; // reset pos in xrk
795  gri=Rec->gri;
796  ga=Rec->ga;
797  gi=Rec->gi;
798  gend=Rec->gend;
799  curr_level=1; // $$20020221 sonst a99 aLFA hierarch Saetze Problem
800  xpy=1;
801  xrk=xrK-2;
802  xks=xkS;
803  xkt=xkT;
804  xke=xkE;
805  xpb=(CHAR *)"\00";
806  xbl=0;
807  if (aix!='d') InSwix('d'); // MultiX
808 
809  InV14Repl(Rec,xi4); // V14 : Referenzen aufloesen
810  if (Rcu->rKbase==0) // erste Benutzung
811  {
812 // Rcu->rKbase=(CHAR *)malloc(10000*sizeof(CHAR));
813  Rcu->rKbase=new CHAR[32000];
814  Rcu->rKx=0;
815  Rcu->rKy[0]=Rcu->rKbase; // keyspace init
816  }
817  if (Rcu->rKbase==0) // kein Platz
818  {
819  sprintf(Aerror,"no room for keys%c",0);
820  return -1;
821  }
822  if (!store)
823  {
824  Rcu->rKx=0; // keyspace init
825  Rcu->rKy[0]=Rcu->rKbase;
826  }
827  if (xrp[0]) replace(1,0); // glob. Ersetzungen Indexparam.
828 
829  do // alle Schl. erstellen
830  {
831  ch2=0;
832  xk1=xk;
833  kycnt=0; // keycount
834  h_test(); // ersten ak-Bef. ausfuehren (in exet.cpp)
835  do
836  {
837  kycnt+=keyprod(store,0);
838  k=(h_test()); // next key
839  }
840  while (k && okn<1000) ;
841  if (!kycnt && xrd) keyprod(store,1); // there was no key, make one anyway
842  if (okn==1000)
843  {
844  sprintf(Aerror,"mehr als 1000 Schl.%c",0);
845  --okn;
846  }
847  }
848  while (crif()!=gri);
849  k=0;
850 
851  InSwix('d'); // MultiX, .adx einschalten
852  if (okn && store) // now delete keys that are no longer valid
853  while (k<okn) // their okf is 1
854  {
855  if (okf[k])
856  {
857  strcpy(idxval,oldkeys[k]);
858  pad(idxval,0);
859  if (*idxval=='\\') // $$970227 SR
860  {
861  i=idxval[2]-'1';
862  InSwix('d'); // MultiX
863  r0=aiEntGe(i+Adn*15,(CHAR*)idxval+3,(CHAR*)nwkey);
864  if (r0)
865  {
866  sprintf((char *)idxval,"|%ld%c",r0,0);
867  pad(idxval);
868  aiEntLo(i7+Adn*15,idxval,Rcu->rNr); // del key "|i7|NrMainRec
869  }
870  }
871  else if (idxval[1]!='0')
872  if (*idxval=='|')
873  {
874  if (aix!='d') InSwix('d'); // MultiX
875  aiEntLo(idxval[1]-'1'+Adn*15,(CHAR*)idxval+2,Rcu->rNr);
876  }
877  else if (*idxval=='~')
878  {
879  InSwix(idxval[1]);
880  aiEntLo(idxval[2]-'1'+Adn*15,(CHAR*)idxval+3,Rcu->rNr);
881  }
882  }
883  ++k;
884  }
885  InSwix('d'); // MultiX
886  if (!store)
887  {
888 // XXX noch korrigieren: compk!!! statt compstr; klappt noch nicht!!
889 // qsort(&oldkeys[0],okn,sizeof(char *),&compstr); // and sort them
890  }
891  cri=cri0;
892  return kycnt;
893 }
894 
895 
896 CHAR sks[260], *key;
897 
898 extern char rG[]; // $$051015 wg. manip.Bef. J, exet.cpp
899 
900 // Hilfsfunktion f. InKeyCalc:
901 // Schluessel des Satzes berechnen und speichern, dabei ungueltige ermitteln und loeschen
902 int INDEX::keyprod(int store, int fmd)
903 // store=1: store it 0: don't
904 { // extern int crc, crl, lop;
905  int i=0, j=0, m=0;
906  int k=0; // static CHAR *key;
907  RECNR r0; // $$970227 SR
908  CHAR *ckey;
909  int kycnt=0;
910  unsigned char NN = kfg->NN; // non-stop char, normally NN=@
911  akey=ct[0];
912  key=ct[ML];
913  crc=crl=lop=0;
914  ckey=key+2; // MultiX
915  *akey=*ckey=NL;
916  if (!ch1) return 0;
917  if (!format(fmd)) return 0; // now produce the nxt key (writes to ct[0])
918  while (*akey) // there may be multiple keys separated by code 8
919  {
920  i=j=m=0; // $$000506 i=j= sonst Problem mit NN
921  while (*akey && *akey!=8 && m<254) key[m++]=*akey++; // copy akey->key until code 8
922  bkey=ckey; // MultiX
923  if (m==254) while (*akey && *akey!=8) ++akey; // kann sehr lang sein!
924  while (*akey==8) ++akey; //970128 while statt if
925  if (!m || (m==2 && *key=='|') || (m==3 && *key=='~')) continue; // empty key // m==3 MultiX
926  key[m]=NL; // $$970227 '\\' NEU SR
927  if (*key!='|' && *key!=i5 && *key!='\\' && *key!='~') // $$050522 multix
928  {
929  memmove(bkey,key,keymax-2);
930  *key='|';
931  key[1]=(rG[1]>1)?rG[1]:'1';
932  }
933  // $$051015 rG
934  if (key[1]!='0') key[keymax-2]=NL; // $$000218 sonst stll = keymax
935  rempunc(key);
936  if (*key=='~') ++bkey; // MultiX
937  if (!ntn || ntfind(0,nt1-1)) // not a stop word?
938  {
939  // eliminate the non-stop character:
940  while ((key[i]=key[j])!=NL) if (key[j]==NN) ++j;
941  else ++i,++j;
942  // pad the end with nulls:
943  pad(key,0);
944  if (!*key || strchr((char *)xisep2,(int)*bkey)) // $$970406 NEU:
945  if (key[1]>'0') continue; // we don't want such keys
946  if (store)
947  {
948  if (!checkey(key)) continue; // we have this key already for this rec
949  // we don't have it yet: add it to the index
950 
951  if (*key=='\\') // $$970227 SR
952  {
953  InSwix('d'); // MultiX
954  k=key[2]-'1';
955  r0=aiEntGe(k+Adn*15,key+3,nwkey);
956  if (!r0) continue;
957  sprintf((char *)key,"|%ld%c",r0,0);
958  pad(key);
959  aiEntIn(i7+Adn*15,key,Rcu->rNr,0); // prod key "|i7|MainRecNr
960  continue;
961  }
962 
963  if (*key=='|' && key[1]=='0') // |0 : STL entry
964  {
965  if (!stll) continue; // no .STL
966  lseek(dbSt,(Rcu->rNr)*(long)stll,0); // write bkey to .STL
967  write(dbSt,bkey,stll);
968  }
969  else if (*key=='|' && key[1]=='/') // |/ : RES entry
970  { // $$970219 resl
971  if (!resl) continue; // no .RES
972  lseek(dbre,Rcu->rNr*(long)resl,0); // write bkey to .RES
973  write(dbre,bkey,resl);
974  }
975  else if (*key==i5) // Stammschluessel aendern!
976  { // _0|ixxx oder _1|ixxx
977  RECNR Recn;
978  int j,i=0;
979  char md=key[1];
980  while (i<okn) if (*oldkeys[i]==i5 && oldkeys[i][3]==key[3]) break;
981  else ++i;
982  if (i>=okn-1) continue; // $$000119
983  okf[i]=0;
984  strcpy(nwkey,oldkeys[i]+4);
985  pad(nwkey,0);
986  j=strlen(nwkey); // lg d. alten schl.
987  k=strlen(bkey+2);
988  if (Rcu->rSt) // not for new records, where rSt==0
989 
990  while (1)
991  {
992  if (i==okn) break;
993  Recn=aiEntGe(key[3]-'1'+Adn*15,(CHAR*)nwkey,(CHAR*)olkey);
994  if (!Recn) break; // nix mehr gefunden
995  // $$940818 folgende 2 Zeilen
996  if (md=='0')
997  {
998  if (strcmp(nwkey,olkey)) break; // nicht gleich
999  }
1000  else if (strncmp(nwkey,olkey,j)) break;
1001  if (k>j && !strncmp(olkey,bkey+2,k)) break; // sonst endlosschleife
1002  aiEntLo(key[3]-'1'+Adn*15,(CHAR*)olkey,Recn);
1003  strcpy(sks,bkey+2);
1004  pad(sks,0);
1005  if (md=='1') strcat(sks,olkey+j);
1006  aiEntIn(key[3]-'1'+Adn*15,(CHAR*)sks,Recn,0);
1007  }
1008  } // now this is a regular key in need of storing
1009  else // *key = | or ~ (MultiX)
1010  {
1011  switch (*key)
1012  {
1013  case '|':
1014  {
1015  if (aix!='d') InSwix('d');
1016  if (key[1]<'1' || key[1]>';') key[1]=';'; // $$070403 keine Ziffer hinter |
1017  aiEntIn(key[1]-'1'+Adn*15,(CHAR*)bkey,Rcu->rNr,0);
1018  break;
1019  }
1020  case '~':
1021  {
1022  if (aix!=key[1]) InSwix(key[1]);
1023  aiEntIn(key[2]-'1'+Adn*15,(CHAR*)bkey,Rcu->rNr,0);
1024  break;
1025  }
1026  }
1027  }
1028  ++kycnt;
1029  }
1030  else // store == 0, just save the keys in oldkeys[]
1031  {
1032  k=0; // check it
1033  while (k<okn) if (*key==*oldkeys[k]) if (!strcmp(key,oldkeys[k])) break;
1034  else ++k;
1035  else ++k;
1036  if (k<okn) continue;
1037  strcpy(oldkeys[okn],key); // it's new
1038  okf[okn++]=1;
1039  ++kycnt;
1040  oldkeys[okn]=oldkeys[okn-1]+strlen(oldkeys[okn-1])+1;
1041  }
1042  }
1043  }
1044 
1045  return kycnt;
1046 }
1047 
1048 
1049 // Interne Funktionen dieser Klasse
1050 
1051 void INDEX::pad(CHAR *a, int md) // fill end with 0s
1052 // md=0: Leerzeichen am Ende wegnehmen
1053 {
1054  int i=strlen(a)-1;
1055  if (!md) while (isspace(a[i]) && i>-1) a[i--]=NL;
1056  while (i<keymax+2) a[++i]=0;
1057  return;
1058 }
1059 
1060 int INDEX::checkey(CHAR *key) // is this new key really new ?
1061 {
1062  register int i=0;
1063  while (i<okn) // mit den "alten" Schluesseln vergleichen
1064  {
1065  if (!strcmp(key,oldkeys[i]))
1066  {
1067  okf[i]=0; // not new, mark old one as used again
1068  return 0;
1069  }
1070  else ++i;
1071  }
1072 
1073  strcpy(oldkeys[okn],key); // add it to old key list to prevent dupes
1074  okf[okn++]=0; // mark 0, otherwise it'll be deleted !
1075  oldkeys[okn]=oldkeys[okn-1]+strlen(oldkeys[okn-1])+1;
1076  return 1; // yes
1077 }
1078 
1079 
1080 
1081 int flg=0;
1082 
1083 char ffnd[260];
1084 
1085 char labl[]="1";
1086 
1087 
1088 void INDEX::InIDecode(int& reg, char *val) // umcodieren per Sprungmarke #-1...
1089 {
1090 // RECORD *rr=new RECORD(kfg,100,20,20); //$$960422
1091 // if(*Aerror) ecod=0; // RECORD konnte nicht angelegt werden!
1092  // dann keine Umcodierung!!
1093 
1094  if (rr && !flg)
1095  {
1096  rr->Ins((CHAR *)"u2 A");
1097  rr->Ins((CHAR *)"u1 A"); // damit der Satz rr nicht leer ist!
1098  flg=1;
1099  }
1100  if (rr && ecod && *val!='_')
1101  {
1102  int rp=xrp[0];
1103  xrp[0]=0;
1104  *labl=reg+'0';
1105  strcpy(ffnd," ");
1106  strcpy(ffnd+kfg->skt,val);
1107  ch1=(CHAR *)ffnd;
1108 // rRcu->Adn=0; // wg. Nachladung!
1109  Exp(rr,1,(CHAR *)labl); // exportiert val nach ct[0]
1110  xrp[0]=rp;
1111  }
1112  else
1113  {
1114  if (*val=='_') strcpy(ct[0],val+1);
1115  else
1116  { // delete rr;
1117  return; //$$960422
1118  }
1119  }
1120  // ct[0] leer, wenn *labl nicht gefunden!
1121  if (*ct[0]) // $$980610 ve: Abschneiden der Umcodierung xy -> |1xy
1122  {
1123  if (*val!='_' && *ct[0]=='|' && *(ct[0]+2))
1124  {
1125  if (*(ct[0]+1)>'0' && *(ct[0]+1)<=':')
1126  reg=*(ct[0]+1)-'0'; // Register koennte sich veraendert haben
1127  strcpy(val,ct[0]+2);
1128  }
1129  else strcpy(val,ct[0]);
1130  }
1131 
1132  // delete rr; //$$960422
1133 
1134  return;
1135 
1136 }
1137 
1138 // Ergebnismenge sortieren
1139 
1140 // $$990120: Erweiterungen zum Korrekten Sortieren der CFG-Zeilen
1141 
1142 // mit Hilfe der p- bzw. q-Befehle der .API
1143 
1144 void INDEX::InRsort(RECNR *results,int anz,int pos, int size, int mode)
1145 
1146 {
1147 // Adresse adr muss auf einen Platz fuer 10000 CHAR-Adressen zeigen
1148  CHAR **adr, *ca;
1149  CHAR *a0;
1150  RECNR r; // zum Umrechnen von Satznummern in strings
1151  CHAR *ax1, ax[256]; // zum einlesen aus .STL
1152  int i, j, k, m;
1153  CHAR cx;
1154  CHAR *ptx;
1155  int pix; // $$000628 NEU
1156  int J=0;
1157 
1158 // Abschnitte aus .STL werden in adr[] eingelesen
1159  if (ptb[0][129]==4) // p-Tabelle, wird ü umcodiert? Dann diese
1160  {
1161  pix=0;
1162  ptx=ptb[0];
1163  }
1164  else // sonst q-Tabelle
1165  {
1166  pix=1; // p or q commands?
1167  ptx=ptb[1];
1168  }
1169  *Aerror=0;
1170  adr= new CHAR*[anz+2]; // zur Sicherheit +2
1171 // adr=(CHAR **)malloc((anz+1)*sizeof(CHAR*));
1172  if (adr==0)
1173  {
1174  sprintf(Aerror,"Menge %ld zu gross zum Sortieren%c",(anz+1),0);
1175  return;
1176  }
1177  if (!size) size=stll-pos;
1178 // if((size+4)*anz>65536) size=65536/anz - 4; $$980619 ve:Grenze auskomm. da anz >16000
1179  size=__min(size,72); // $$990309 wg. Vergr. von stll
1180  a0=adr[0] = new CHAR[(size+4)*(anz+2)]; // zur Sicherheit +2
1181  if (adr[0]==0)
1182  {
1183  sprintf(Aerror,"Menge %ld zu gross zum Sortieren%c",anz*(size+4),0);
1184  delete [] adr; // free(adr);
1185  adr=(CHAR**)NULL;
1186  return;
1187  }
1188  ca=a0;
1189  while (J<anz)
1190  {
1191  r=results[J];
1192  ax1=adr[J]=ca;
1193  lseek(dbSt,r*stll+pos,0);
1194  read(dbSt,ax,size+10);
1195  ax[size+10]=0;
1196  { // Umcodierung, abgeleitet aus rcode() in EXET.CPP
1197  i=j=0;
1198  while (1) // now eliminate codes 1..3 (non-sort and such)
1199  {
1200  while ((cx=ax[i++])!=NL && ptx[cx]>7) ax1[j++]=ptx[cx];
1201  if (cx==NL)
1202  {
1203  ax1[j]=NL; // exit from while(1)
1204  break;
1205  }
1206  --i;
1207  switch (ptx[cx])
1208  {
1209  case NL: // p x 0 : global stop
1210  if (j) ax1[j++]=0;
1211  break;
1212  case 1: // p x 1 : elim x
1213  break;
1214  case 2: // p x 2 : elim x and following char
1215  if (ax[i+1]) i++; /* $$930818 sonst Absturz, wenn das Zeichen genau
1216  am Ende der Kategorie steht */
1217  break;
1218  case 3: // p x 3 : same, repl both by ' '
1219  if (ax[i+1]) i++; /* $$930818 sonst Absturz, wenn das Zeichen genau
1220  am Ende der Kategorie steht */
1221  ax1[j++]=' ';
1222  break;
1223  case 4: // p x "abc" : string replacements, z.B. ü = ue
1224  m=0;
1225  if (!pix) k=10000+Gns*300+ax[i];
1226  else k=20000+Gns*300+ax[i]; // which tble?
1227  while (m<phi && pi[m]!=k) ++m;
1228  if (m==phi) break;
1229  k=0;
1230  while ((ax1[j++]=pa[m][k++])!=NL) ;
1231  --j; // the terminating 0 !
1232  break;
1233  case 5: // p x 5 : don't decode this and the following (CHINESE !)
1234  ax1[j++]=cx;
1235  if (ax[i+1]) ax1[j++]=ax[++i]; // $$930803 sonst crash
1236  break;
1237  default: // 6 and 7 : print ersatz tables, done at last stage
1238  ax1[j++]=ax[i];
1239  break;
1240  }
1241  ++i;
1242  } // end while(1)
1243  }
1244  ca[size]=0;
1245  ca+=size;
1246  InRecn2Str(r,ca);
1247  ca+=4;
1248  ++J;
1249  }
1250 
1251 // strings sortieren:
1252  if (!mode) qsort(adr[0],(unsigned int)anz,size+4,&UtCompstr);
1253  else qsort(adr[0],(unsigned int)anz,size+4,&UtComprstr);
1254 // Nummern wieder nach results kopieren:
1255  j=0;
1256  while (j<anz)
1257  {
1258  /*
1259  results[j]=((long)adr[j][size])*zx
1260  +((long)adr[j][size+1])*yx
1261  +((long)adr[j][size+2])*256L
1262  +(long)adr[j][size+3];
1263  */
1264  results[j]=InStr2Recn(adr[j]+size);
1265  ++j;
1266  }
1267 
1268 //free(adr); free(a0);
1269  delete [] adr;
1270  delete [] a0;
1271  adr=(CHAR**)NULL;
1272  a0=(CHAR*)NULL;
1273  return;
1274 
1275 }
1276 
1277 // Erg.Menge durchsehen, welche Saetze der gesetzten Restriktion genuegen
1278 
1279 int INDEX::InRestrict(int rnum,RECNR *result,CHAR *restri,char Cool)
1280 // rnum = number of results
1281 // result = result set
1282 // restri = rpovalue r=r/s p=position o ="<>!="
1283 // RETURN: number of results statisfying restri ( <= rnum)
1284 {
1285  int i=0, j=0;
1286  int resp=restri[1]-1; // position
1287  CHAR *resv=restri+3; // value
1288  if (*resv=='=')resv++; // $$19980904 ve:"<=" und ">="Relation
1289  int vlen=strlen(resv); // length of value
1290  CHAR w[72];
1291  if (!rnum || !*restri) return rnum;
1292  if (*restri=='s' && !dbSt) return rnum; // no STL
1293  if (*restri=='r' && !dbre) return rnum; // no RES
1294 
1295  while (i<rnum)
1296  {
1297  if (*restri=='s')
1298  { /* get relevant part of shortline of nxt rec */
1299  lseek(dbSt,(long)result[i]*(long)stll+(long)resp,0);
1300  read(dbSt,w,vlen);
1301  w[vlen]=0;
1302  }
1303  else
1304  { /* get restrict of nxt rec */
1305  lseek(dbre,(long)result[i]*(long)resl+(long)resp,0);
1306  read(dbre,w,vlen);
1307  w[vlen]=0;
1308  }
1309  j=0;
1310  switch (restri[2]) // operator
1311  {
1312  case '<':
1313  switch (restri[3])
1314  {// $$19980904 ve:"<=" Relation
1315  case'=':
1316  if (strcmp(w,resv)>0) j=1;
1317  break;
1318  default:
1319  if (strcmp(w,resv)>=0) j=1;
1320  break;
1321  }
1322  break;
1323 
1324  case '=':
1325  if (strncmp(w,resv,vlen)) j=1;
1326  break;
1327 
1328  case '!':
1329  if (!strncmp(w,resv,vlen)) j=1;
1330  break;
1331 
1332  case '>':
1333  switch (restri[3])
1334  {// $$19980904 ve:">="Relation
1335  case'=':
1336  if (strncmp(w,resv,vlen)<0) j=1;
1337  break;
1338 
1339  default:
1340  if (strncmp(w,resv,vlen)<=0) j=1;
1341  break;
1342  }
1343  break;
1344  }
1345  switch (Cool)
1346  { // $$980311 ve: NOT-Verknuepfung
1347  case 'N': // NOT-Operator
1348  if (!j) result[i]=0L; // i does satisfy restriction
1349  break;
1350  default: // AND-Operator
1351  if (j) result[i]=0L; // i doesn't satisfy restriction
1352  break;
1353  }
1354  ++i;
1355  }
1356  i=j=0; // eliminate zeros from results
1357  while (i<rnum)
1358  {
1359  if (result[i]) result[j++]=result[i];
1360  ++i;
1361  }
1362  result[j]=0L;
1363  return j;
1364 }
1365 
1366 // genuegt Satz rn der eingestellten Restriktion?
1368 // rn = a rec number
1369 // restri = rpovalue r=r/s p=position o ="<>!="
1370 // RETURN: rn if restriction satisfied, 0 else
1371 {
1372  int j=0;
1373  int resp=restri[1]-1; // position
1374  CHAR *resv=restri+3; // value
1375  if (*resv=='=')resv++; // $$19980904 ve:"<=" und ">="Relation
1376  int vlen=strlen(resv); // length of value
1377  CHAR w[72];
1378 
1379  if (!rn || !*restri) return rn;
1380  if (*restri=='s' && !dbSt) return rn; // no STL
1381  if (*restri=='r' && !dbre) return rn; // no RES
1382  if (*restri=='s')
1383  { /* get relevant part of shortline of nxt rec */
1384  lseek(dbSt,(long)rn*(long)stll+(long)resp,0);
1385  read(dbSt,w,vlen);
1386  w[vlen]=0;
1387  }
1388  else
1389  { // get restrict of nxt rec
1390  lseek(dbre,(long)rn*(long)resl+(long)resp,0);
1391  read(dbre,w,vlen);
1392  w[vlen]=0;
1393  }
1394  j=0;
1395  switch (restri[2]) // operator
1396  {
1397  case '<':
1398  switch (restri[3])
1399  {// $$19980904 ve:"<=" Relation
1400  case'=':
1401  if (strcmp(w,resv)>0) j=1;
1402  break;
1403 
1404  default:
1405  if (strcmp(w,resv)>=0) j=1;
1406  break;
1407  }
1408  break;
1409 
1410  case '=':
1411  if (strncmp(w,resv,vlen)) j=1;
1412  break;
1413 
1414  case '!':
1415  if (!strncmp(w,resv,vlen)) j=1;
1416  break;
1417 
1418  case '>':
1419  switch (restri[3])
1420  {// $$19980904 ve:">="Relation
1421  case'=':
1422  if (strncmp(w,resv,vlen)<0) j=1;
1423  break;
1424  default:
1425  if (strncmp(w,resv,vlen)<=0) j=1;
1426  break;
1427  }
1428  break;
1429  }
1430  if (j) rn=(RECNR)0; // i doesn't satisfy restriction
1431  return rn;
1432 }
1433 
1434 // $$980622 ve: Maximale Satznummer der TBL-Datei bestimmen
1435 
1437 {
1438 
1439  int dbTb; // handle of .TBL file
1440  RECNR rof=0L;
1441 
1442  dbTb=Tblopen(".tbl",0); // Oeffnen im Readonly-Modus
1443  if (dbTb!=EOF)rof=(lseek(dbTb,0L,2)-2L)/4L;
1444  close(dbTb);
1445  return rof;
1446 }
1447 
1448 int INDEX::InIsStop(CHAR *s) // is s a stopword? ret 1 if yes
1449 {
1450  if (!ntn) return 0; // no stopwords defined
1451  bkey=s;
1452  return(1-ntfind(0,nt1-1)); // in exet3.cpp (recursive)
1453 }
1454 
1455 
1456 
1457 
1458 // copy record number hi/lo to a string address
1459 
1461 {
1462  a[0]=(CHAR)(rp/16777216L);
1463  rp=rp%16777216L;
1464  a[1]=(CHAR)(rp/65536L);
1465  rp=rp%65536L;
1466  a[2]=(CHAR)(rp/256L);
1467  a[3]=(CHAR)(rp%256L);
1468  return;
1469 }
1470 
1471 // copy record number hi/lo from string address to long
1472 
1474 {
1475  RECNR r;
1476  r= ((RECNR)ca[0])*16777216L
1477  +((RECNR)ca[1])*65536L
1478  +((RECNR)ca[2])*256L
1479  +(RECNR)ca[3];
1480  return r;
1481 }
1482 
1483 
1484 
1485 // Jedes ABASE-Obj. muss zur Laufzeit eine eigene log. Nr. haben, 0...4
1486 
1487 int INDEX::activeNr(int accf) // get a free number and set access flag
1488 {
1489  int i=0;
1490  while (i<5 && Active[i]!=-1) ++i;
1491  if (i==5) return -1;
1492  Active[i]=accf;
1493  Adn=i; // global active database number
1494  return i; // free number
1495 }
1496 
1497 void INDEX::inactiveNr(int nr) // log.Nr. wieder freigeben
1498 {
1499  Active[nr]=-1;
1500  Abase[nr]=NULL;
1501  return;
1502 }
1503 
1504 
1505 INDEX::~INDEX() // Destruktor
1506 
1507 {
1508  aiCLOSE(Adn*15,filmod);
1509  if (stll) close(dbSt); // $$970129 NEU 2 Zeilen
1510  inactiveNr(Adn);
1511  return;
1512 }
1513 
1514 // $$970831 NEU : binaere Suche nach einer Satznummer in Erg.Menge
1515 
1516 // wenn gefunden, wird die Nummer markiert, d.h. das hoechste Bit gesetzt
1517 
1518 int INDEX::bfind(RECNR r, RECNR *rs, unsigned int a, unsigned int b)
1519 // binary srch for r in result set rs, between a and b-1
1520 // result set at rs must be sorted!
1521 // return: >=0 : match -1 : no match
1522 // operates recursively!
1523 
1524 {
1525  unsigned int az;
1526  if (r> (rs[b-1] & 0x7FFFFFFF)) return -1;
1527  if (b==a+1)
1528  {
1529  if (r==(rs[a] & 0x7FFFFFFF))
1530  {
1531  rs[a]=0x80000000 | rs[a];
1532  return a;
1533  }
1534  else return -1;
1535  }
1536  az=a+(b-a)/2;
1537  if (r==(rs[az] & 0x7FFFFFFF))
1538  {
1539  rs[az]=0x80000000 | rs[az];
1540  return az;
1541  }
1542  if (r <(rs[az] & 0x7FFFFFFF)) return bfind(r,rs,a,az);
1543  return bfind(r,rs,az,b); // recursive
1544 }
1545 
1546 /*
1547  Copyright 2011 Universitätsbibliothek Braunschweig
1548 
1549  Licensed under the Apache License, Version 2.0 (the "License");
1550  you may not use this file except in compliance with the License.
1551  You may obtain a copy of the License at
1552 
1553  http://www.apache.org/licenses/LICENSE-2.0
1554 
1555  Unless required by applicable law or agreed to in writing, software
1556  distributed under the License is distributed on an "AS IS" BASIS,
1557  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1558  See the License for the specific language governing permissions and
1559  limitations under the License.
1560 */
1561