a99  V32.6
allegro Windows Hauptprogramm
 Alle Klassen Dateien Funktionen Variablen Typdefinitionen Aufzählungen Aufzählungswerte Makrodefinitionen
record.cpp
gehe zur Dokumentation dieser Datei
1 // RECORD.CPP (c) UB Braunschweig 1995
2 // 1995-08-19 : Datensatz, Struktur und Manipulation im Arbeitsspeicher
3 // Copyright 2011 Universitaetsbibliothek Braunschweig, more see bottom
4 
5 // (Lesen und Speichern eines Satzes sind in --> ABASE bzw. ABASEW)
6 
7 
8 #include "konfig.hpp"
9 #include "record.hpp"
10 
11 #include "abase.hpp"
12 
13 // Methoden: Kurzuebersicht (genauer in record.hpp)
14 
15 // RECORD(KONFIG *cfg, unsigned int gsp=0, int gd=0, int wsp=0)
16 // Konstruktor
17 // ~RECORD() Destruktor, enthaelt Release() zur Freigabe
18 // CHAR *Adr(CHAR *kat,int) Adresse von Feld kat (z.B. Adr("#20")
19 // CHAR *AdrSf(CHAR *ufd,int) Adresse von UnterFeld ufd (z.B. AdrSf("#96$u")
20 // int Pos(CHAR *kat,int) Pos. von kat im Array der Felder (z.B. Pos("#20")
21 // int Ins(CHAR *kat) Feld einfuegen (ersetzen, falls belegt)
22 // int Del(CHAR *kat) loeschen
23 // int PartDel(int i, int j) mehrere Felder loeschen (i,j Pos. im Array)
24 // CHAR *SrRp(CHAR *a,CHAR *b,int mde,int d,int r)
25 // Zeichenkette im Satz suchen und ersetzen
26 // CHAR *FSrRp(CHAR *a) Feldspezifisches Suchen und ersetzen
27 // int Reserve() Satz zum Bearbeiten reservieren (sperren)
28 // int Release() Satz wieder freigeben (wenn nicht gespeichert wurde)
29 // void Copy(RECORD *Rec) Inhalt aus anderem Satz kopieren
30 
31 // SubPos(CHAR *kat) hierarchischen Untersatz suchen
32 // SubDel(CHAR *kat) hierarchischen Untersatz loeschen ab kat
33 // SubDel(int pos) hierarchischen Untersatz loeschen ab pos
34 // SubCopy US kopieren
35 // SubMove US bewegen
36 // SubNxt(int) Position des naechsten Untersatzes finden, nicht-zyklisch
37 // SubPre(int) Position des vorigen US finden, zyklisch (d.h. vom ersten zum letzten)
38 
39 // void UTFcode(CHAR *ft, CHAR *gt) ft (UTF) -> gt (Internal)
40 
41 // private:
42 // int ginst(int f) String Wspace als Feld mit interner Nummer f einfuegen
43 // die interne Nr. ist die lfd. Nummer der Kat. in der CFG
44 
45 
46 unsigned int cnt; // Anzahl Zeichen, Hilfsvar.
47 CHAR *src, *dest; // Hilfsadressen source/destination beim Kopieren
48 
49 // ********** Konstruktor fuer RECORD %% DOS: NACORE.C
50 // Vorher muss ein KONFIG-Objekt cfg geschaffen werden
51 
52 RECORD::RECORD(KONFIG *cfg, unsigned int gsp, int gd, int wsp)
53 {
54  unsigned int sz; // fuer Groessenangaben
55  *Aerror = 0;
56  kfg=cfg; // damit man auf Variablen von cfg zugreifen kann
57  // und zwar auch in den anderen Memberfunktionen von RECORD
58  schema=kfg->schema;
59 
60  // Platz bereitstellen:
61  if (gd) sz=gd;
62  else sz=kfg->gdim;
63  ga= new CHAR*[sz];
64  gi=new int[sz];
65 
66  if (wsp) sz=wsp;
67  else sz=WSPACE;
68  Wspace=new CHAR [sz];
69  if (!ga || !Wspace || !gi)
70  {
71  sprintf(Aerror,"not enough record space%c",0);
72  printf("not enough record space%c",0);
73  return;
74  }
75 
76  Wsp2=Wspace+sz/2;
77  // Satzanfang: Erstes Feld beginnt intern mit Codes RS=29 und 1
78  // 29 steht fuer "Hauptsatz"
79  *Wspace=RS;
80  Wspace[1]=1;
81  Wspace[2]=0;
82 
83  if (gsp) sz=gsp;
84  else sz=kfg->gspace;
85  g=new CHAR[sz]; // Platz f.d. Satz beginnt auf Adr. g
86  if (!g)
87  {
88  sprintf(Aerror,"not enough work space%c",0);
89  printf("not enough work space%c",0);
90  return;
91  }
92  ga[0]=ga[1]=gend=g; // Initialisierung
93  *gend=EOD; // rec Ende im Arb.Sp., Code 26 End of data
94  gi[0]=gi[1]=0;
95 
96  if (!fr) // Hintergrd.Sp. ist global!! nur beim ersten Mal initialisieren
97  { // weitere RECORD-Objekte nutzen dann denselben Speicher
98  fa=new CHAR*[f_dim];
99  fi=new int[f_dim];
100  fr=new CHAR [fspace]; // $$970115 fspace, nicht f_dim
101 
102  if (!fr || !fi || !fa)
103  {
104  sprintf(Aerror,"background space: %d bytes is too much%s",fspace,0);
105  printf("background space: %d bytes is too much%s",fspace,0);
106  return;
107  }
108  fend=fa[0]=fr;
109  fi[0]=0;
110  fi[1]=0;
111  fri=0;
112  }
113 
114  cri=gri=mri=0;
115 
116  Adn=-1; // log. Datenbanknummer wird bei Zugriff gesetzt
117  rNr=0L; // default rec# = 0 = new rec
118  rNa=0L; // additional nr $$981109
119  rKx=0;
120  rKbase=(CHAR*)NULL;
121  return;
122 }
123 
124 // ***** Datenfelder im Satz finden
125 
126 // A. ***** Finde Text von Feld kat im Satz (z.B. kat="20" oder kat="#40a")
127 CHAR *RECORD::Adr(CHAR *kat,int md) // md==1: srch whole rec incl hierarchic subrecs
128 // md==0: nicht die hierarch. Untersaetze (default)
129 {
130  int i;
131  int n=0;
132  if ((i=Pos(kat,md))==-1) return (CHAR*)NULL;
133  if (*ga[i]==RS) n=2;
134  return ga[i]+n+(kfg->skt); // Anfangsadr. d. Feldtextes liefern
135 }
136 
137 // B. ***** Finde lfd. Nr. von Feld kat im Satz (z.B. kat="20" oder kat="#40a")
138 // oder auch kat="#20"
139 int RECORD::Pos(CHAR *a,int md) // md==1: srch whole rec incl subrecs
140 // md==0: not the subrecs (default)
141 {
142  int i=cri;
143  int j;
144  int n=3;
145  if (!gri) return -1; // empty $$990220 Sicherheit
146  if (*a==kfg->KC || *a=='#') ++a; // *a=='#'
147  j=strlen(a);
148  while (strncmp(a,ga[i]+n,j)) // $$990219 umgestellt
149  {
150  ++i;
151  if (i==gri) return -1;
152  if (*ga[i]==RS)
153  {
154  if (md==0) return -1;
155  n=3;
156  }
157  else n=1;
158  }
159  return i; // auf Rec->ga[i] steht dann der komplette Inhalt, z.B. #40 Shakespeare, ...
160 }
161 
162 // ***** Finde Text eines Unterfelds im Satz (z.B. b="#90a$u" : $u in #90a
163 // kopie: wenn gesetzt, dann gefundenes Subf. hierher kopieren
164 // lgth: wenn gesetzt, dann nur bis zu dieser Laenge
165 // Return: Adresse des ersten Zeichens des Unterfelds innerhalb des Satzes
166 
167 CHAR *RECORD::AdrSf(CHAR *b, CHAR *kopie, int lgth)
168 {
169  CHAR *a; a=b;
170  int l=kfg->tgl+1; // pos. d. Mehrfachcodes
171  char kk[10];
172  strncpy(kk,a,l+1); kk[l+1]=0; if(kk[l]=='$') kk[l]=0;
173  a=Adr((CHAR *)kk); // wird normales Feld in Rec gesucht?
174  if(!a) if(b[1]=='u') // Nein, #uxyz ?
175  {
176  int f=UtFindI((CHAR *)kk); // #uxy
177  if(f==-1) return 0; else a=fa[f]+kfg->skt; // auch nicht, geht nicht
178  }
179  if(!a) return 0;
180  int d=0;
181  if(b[l]=='$') d=l+1; else if(b[l+1]=='$') d=l+2;
182  char c=b[d];
183  if(d) // Unterfeldcode c suchen, falls nicht $
184  if(c!='$') // $$ : kein SubField, sondern Feldtext
185  { char s=kfg->SF;
186  while(*a) if(*a!=s || a[1]!=c) ++a; else break;
187  if(!*a) return 0; // nicht vorhanden
188  else a+=2;
189  }
190  if(kopie)
191  if(lgth) { if(strlen(a)<lgth) lgth=strlen(a); strncpy(kopie,a,lgth); kopie[lgth]=0; }
192  else strcpy(kopie,a);
193  return a;
194 }
195 
196 CHAR Ws[10000]; // Hilfsbereich f. Feldinhalt bei Ersetzung von subfields
197 
198 // $$990219 Umstellungen mit i<gri
199 
200 // *** interne Hilfsfunktion zum Einfuegen eines Feldes in den Satz
201 // Aufruf aus ::Ins()
202 // in Wspace steht Feldinhalt, z.B. #20 Titel,
203 // f ist vorher ermittelte interne lfd. Nr. des Deskriptors laut CFG
204 
205 int RECORD::ginst(int f) // Wspace holds new field, f is CFG number
206 { // ret Pos. in address array or -1
207  unsigned int k, cnt1;
208  unsigned char mfc; // mehrfachcode
209  int hr=1; // Hierarchiestufe
210  CHAR **kat; // Felddeskriptoren
211  int tgl; // tag length
212  int skt; // start kategory text
213  char SF; // Subf.code
214 
215  kat=kfg->kat; // Hilfsvariablen, nur zwecks Vereinfachung
216  tgl=kfg->tgl; // (werden aus kfg uebernommen)
217  skt=kfg->skt;
218  SF=kfg->SF;
219  CHAR *multy; // multicodes des Feldes
220  int propy; // Eigenschaftszahl des Feldes
221 
222 // weitere Hilfsvariablen
223  int j, i;
224  CHAR *wi, *w1, *wsub;
225  int gix;
226  CHAR *w, *w0;
227  w0=Wspace;
228  w=w0+2;
229  w1=w+1;
230  wsub=Ws;
231  if ((i=kat[f][tgl+3])==0) multy=(CHAR *)" &"; // all multicodes allowed
232  else multy=kat[f]+i; // addr of allowed multicodes
233 
234  if(Apgnb>'1') // '1' ist a99/alcarta // $$111223 neu
235  multy=(CHAR *)" &"; // vorlaeufig! d.h. M-Liste in der CFG ausser Kraft
236 
237  /*
238 #ifdef unix
239  multy=(CHAR *)" &"; // all multicodes allowed (UNIX)
240 #endif
241 #ifdef linux
242  multy=(CHAR *)" &"; // all multicodes allowed (LINUX)
243 #endif
244 */
245  propy=kat[f][tgl]; // prop mask is here, properties check
246  wi=w;
247  if (cri && gi[cri]>3 && f<4) return EOF; // $$060314 NEU Eing von #00 in hier. Untersatz verhindern
248  if (f<9 && *ga[cri]!=RS) wi=w0; // $$971116 NEU
249  if (wi[kfg->tgl+1]==kfg->SF) // SFcode auf Forts.Position statt 1.Textpos. $$090906
250  {
251  --wi;
252  --w1;
253  strncpy(wi,wi+1,kfg->tgl+1);
254  wi[kfg->tgl+1]=' ';
255  }
256  mfc=(w1[tgl])?w1[tgl]:' ';
257  if (*w==RS) // Satzanfang, dann steht vor #00 noch RS
258  {
259  mfc=' ';
260  hr= *w1;
261  }
262  if (strchr("£ú~",mfc)) mfc=255; // bei diesen Codes wird naechstes freies Mehrfachfeld gebildet
263  k=strlen(w);
264  if (f>2 && f<9 && *w==kfg->KC) hr=f-2;
265  if (f>2 && f<9 && hr>1) ;
266  else
267  {
268  UtRemsp(w); // remove trailing spaces
269  if ((int)k>skt && !(propy&8)) // remove surpl spaces xcept in #0.
270  {
271  CHAR *s,*d;
272  s=d=w+skt;
273  while (*d==' ') ++d; // remove leading spaces + mult whitespaces
274  while ((*s++= *d)!=0) if (isspace(*d))
275  {
276  s[-1]=' ';
277  while (isspace(*++d));
278  }
279  else ++d;
280  }
281  }
282  if (cri==gri && *w!=RS) // 1st field of new rec
283  {
284  wi=w0;
285  *wi=RS;
286  w0[1]=1; // 1 = default hierarchy
287  }
288  i=cri;
289  j=tgl+3;
290  while (i<gri && f>gi[i] && *ga[i+1]!=RS) ++i; // look for kat f
291 
292  if (i<gri && *ga[i+1]==RS && (f>gi[i] || f==gi[i] && mfc>ga[i][(*ga[i]==RS)?tgl+3:tgl+1])) ++i;
293 
294 // $$960827 : ... && i>cri ergaenzt weil #02 sofort hinter #01 kommen kann
295  if (f>2 && f<9 && gi[i-1]<f && gi[i-1]>2 && i>cri) --i; // to identify #01,..#0
296  if ((f==gi[i] && (*ga[i]!=RS || i==cri)) || (f>2 && f<9 && gi[i]<9))
297  {
298  int m;
299  unsigned char M; // fuer Mehrfachk.
300  if (i>cri) j=tgl+1; // 1st field is 1Fh 01h #00 $$950802:
301 // ergaenzt ____________
302  while (i<gri && f==gi[i] && ga[i][j] && mfc>ga[i][j])
303  {
304  ++i,j=tgl+1;
305  if (*ga[i]==RS) break;
306  }
307  if (f!=gi[i-1] && mfc==255) mfc=w1[tgl]=' ';
308  if (mfc==255) if (i>cri) // (char) $$970619 NEU
309  {
310  if (i>cri+1) M=w1[tgl]=ga[i-1][tgl+1];
311  else M=w1[tgl]=ga[i-1][tgl+3];
312  if (*multy!=' ')
313  {
314  if (M==' ') w1[tgl]=*multy;
315  else
316  {
317  m=0;
318  while (multy[m] && multy[m]!=M) ++m;
319  if (multy[m] && multy[m+1]) w1[tgl]=multy[m+1];
320  else { sprintf(Aerror,"Mehrfachcodes alle besetzt"); return EOF; } // Eingabe unzulaessig // alt: w1[tgl]=6;
321  }
322  } // $$030214 : \{}|~ not allowed!
323  else
324  {
325  if (M+1>122 && M+1<128) M=128;
326  if (M+1==92) M=92; // Backsl. nicht nehmen
327  if (M+1==59) M=63; // ;<=>? nicht nehmen
328  w1[tgl]=(M==' ')?kfg->multcode:M+1;
329  }
330  }
331  else w1[tgl]=' ';
332  if (i<gri && f==gi[i] && (!ga[i][j] || mfc==ga[i][j])) j=1;// we found it
333  else j=2;
334 
335  if (f>2 && f<10 && gi[i]<10 && gi[i]>2) j=1; // identify all #00..#06
336  }
337  else
338  {
339  j=2; // 1 found / 2 not foun
340  if (mfc==255) w1[tgl]=' ';
341  }
342  if (i>=gri) j=0; // kat not found
343  if (j==1 && i==gri-1)
344  {
345  if (*ga[i]==RS && (*ga[i+1]==RS || i+1==gri))
346  {
347  gi[i+1]=255; // we correct a rec that has 1 kat only
348  wi=w0;
349  wi[1]=hr;
350  }
351  j=3;
352  if (w[skt]==SF && w[skt+1]==SF) j=1; // case #nnf$$axyz: add $a to #nnf
353  } // relevant also after cmd_i
354  gix=gi[i];
355  if (multy[1]!='&')
356  if (w1[tgl]>' ' && !strchr(multy,w1[tgl])) // multicode check
357  {
358  if (*Aerror!=8 && *Aerror!=9) // Mehrfachcodepruefung, nicht innerhalb FLEX
359  {
360  sprintf(Aerror,uif[250],w,w1[tgl],multy);
361  return EOF;
362  }
363  }
364 // j==1 : ist Aenderung zulaessig? j==2 : ist Eingabe zulaessig?
365 
366  if (Apgnb<'4') // Property pruefung nicht bei Batchprogrammen
367  if (((j&1 && ((propy & '\06')!='\06'))) || (!(j&1) && ((propy & '\05')!='\05')))
368  {
369 // printf("\n%s\n",w);
370  sprintf(Aerror,uif[251],0); // Eingabe unzulaessig
371  return EOF;
372  }
373  switch (j) // Modus des Einmischens f.d. neue Feld
374  {
375  case 3: // das letzte Feld ist zu ersetzen
376  gri--;
377  gend=ga[gri]; // del last kat
378  // flothru
379  case 0: // append // Feld hinten anhaengen
380  // $$971210 if(f>8) : nur #00 .. #06 duerfen leer sein
381  if (!w[tgl+1] || !w[tgl+2]) if (f>8) break;
382  cnt=1+strlen(wi);
383  ga[gri]=dest=gend;
384  gend+=cnt;
385  gi[gri]=f;
386  src=wi;
387  memmove(dest,src,cnt);
388  ++gri;
389  break;
390  case 1: // delete + insert : vorhandenes Feld ersetzen
391  if (*ga[i]==RS && (*ga[i+1]==RS || i+1==gri))
392  {
393  gi[i+1]=255; // we correct a rec that has 1 kat only
394  wi=w0;
395  wi[1]=hr;
396  } // relevant also after cmd_i
397  else gix=gi[i+1];
398 // SUbf. Austausch: #nnn $$axxx$bxxx : repl. subfields $a and $b!
399  if (w[skt]==SF && w[skt+1]==SF)
400  {
401  strcpy(wsub,w+skt+1);
402  strcpy(w,ga[i]);
403  ++wsub;
404  while (1)
405  { // ga[i]=old field w=new field
406  int n=skt;
407  while (w[n])
408  {
409  if (w[n]==SF && w[n+1]==*wsub) break;
410  ++n;
411  }
412  if (w[n]) // subf found
413  {
414  int m=n+1;
415  while (w[m] && w[m]!=SF) ++m;
416  strcpy(w+n,w+m); // altes subf rausnehmen
417  } // not found: field unchanged
418  n=strlen(w)+1;
419  if (wsub[1]) strcat(w,wsub-1); //neues subf. hinten anhaengen
420  while (*wsub && *wsub!=SF) ++wsub;
421  while (w[n] && w[n]!=SF) ++n;
422  w[n]=0;
423  if (*wsub)
424  {
425  ++wsub;
426  continue;
427  }
428  break;
429  } // (1)
430  }
431 
432  PartDel(i,i+1);
433  // flothru
434  case 2: // insert : Feld zwischenfuegen
435 // if(f!=3) if(!w[tgl+1] || !w[tgl+2]) break;
436  if (f<3 || f>8) if (!w[tgl+1] || !w[tgl+2]) break; // $$971210 >8 $$040818
437  // Leere Eingabe von #xx loescht #xx
438  cnt=1+strlen(wi);
439  src=ga[i];
440  if (i==cri && *ga[cri]==RS)
441  if (*wi!=RS) src+=2;
442  dest=src+cnt;
443  cnt1=cnt;
444  cnt=gend-src;
445  memmove(dest,src,cnt);
446  cnt=cnt1;
447  j=gri;
448  while (j>i)
449  {
450  ga[j]=ga[j-1]+cnt;
451  gi[j]=gi[j-1];
452  j--;
453  }
454  if (i==cri && *ga[cri]==RS && *wi==kfg->KC) ga[i+1]+=2;
455  strcpy(src,wi); // now wi goes there
456  gi[i]=f;
457  gend+=cnt;
458  ++gri;
459  if (mri>cri) ++mri;
460  gi[i+1]=gix;
461  break;
462  } // end switch
463  if (f>2 && f<9) ga[cri][1]=hr; // hierarchy byte
464  ga[gri+1]=ga[gri]=gend; // Ende markieren
465  *gend=EOD;
466  gi[gri]=0;
467  return(i); // internal position number of field
468 }
469 
470 
471 
472 // ****************** Unicode!
473 // UTF-8 in intern wandeln, u-Befehle normalerweise in Indexparam.
474 void RECORD::UTFcode(CHAR *ft, CHAR *gt) // ft (UTF) -> gt (Internal)
475 {
476  CHAR *xt;
477  long f;
478  while (*ft)
479  if (*ft<192)
480  if (*ft<31) // sonst faellt subf code weg
481  {
482  if (*ft==10) *gt++=20; // Zeilenende -> Absatzmarke
483  if (*ft==9) *gt++=' '; // TAB -> Space
484  ++ft;
485  }
486  else *gt++=*ft++;
487  else
488  { // UTF-8 code found, u-Befehle stehen bei Adresse extra
489  // werden in exet2.cpp belegt
490  xt=Aextra+1;
491  while (*xt) // xt durcharbeiten, ft[1] suchen
492  { // xt hat Abschnitte von je 5 Byte!
493  // 0,1,2 = UTF, 3,4 = Intern, Code 255: uebergehen
494  if (*ft==*xt && ft[1]==xt[1] && (xt[2]==255 || xt[2]==ft[2]))
495  {
496  ft+=2;
497  if (xt[2]!=255) ++ft; // UTF 3 Byte
498  *gt++=xt[3]; // Ersatzzeichen steht auf xt[3]
499  if (xt[4]!=255) *gt++=xt[4]; // zweites Ersatzzeichen
500  if (gt[-1]==1) --gt; // Code 1 : Zeichen uebergehen
501  break;
502  }
503  else xt+=5;
504  }
505  if (!*xt)
506  if (*Aextra==2) // convert to HTML4 entity &#nnn;
507  {
508  *gt++='&';
509  *gt++='#';
510  if (*ft<224) // 2byte
511  {
512  f=(long)(*ft-192)*(long)64+(long)(ft[1]-128);
513  ft+=2;
514  }
515  else if (*ft<240) // 3byte
516  {
517  f=(long)(*ft-224)*(long)4096+(long)(ft[1]-128)*(long)64+(long)(ft[2]-128);
518  ft+=3;
519  }
520  else // 4byte
521  {
522  f=(long)((*ft-240)*65536) +(long)((long)(ft[1]-128)*(long)4096)+(long)((long)(ft[2]-128)*(long)64)+(long)ft[3]-(long)128;
523  ft+=4;
524  }
525  sprintf((char *)gt,"%ld",f);
526  gt=gt+strlen(gt);
527  *gt++=';';
528  }
529  else
530  {
531  *gt++=*ft++; // ... to utf-8
532  *gt++=*ft++;
533  if (gt[-2]>223) *gt++=*ft++;
534  }
535  }
536  *gt=0;
537 }
538 
539 
540 // *************** Feld einfuegen
541 // Insert field into the current record (benutzt ginst(), s.o.)
542 // fld = "#nnn text" in den Datensatz einfuegen
543 
544 int RECORD::Ins(CHAR *fld) // DOS: kat_ins()
545 // fld = "#xxftext"
546 // oder fld = "xxftext"
547 // insert this into current rec
548 {
549  int f;
550  CHAR *ft, *gt;
551  ft=fld;
552  Wspace[2]=kfg->KC;
553 // extern CHAR extra[]; // contains 4byte sequences a b c x
554  if (*Aextra>1) // UTF-8 decoding required?
555  {
556  UTFcode(ft,Wsp2); // Eingabe ist UTF, wandeln
557  ft=Wsp2;
558  UtAccent((char *)ft,(char *)ft+strlen(ft),0); // und Akzente vertauschen!
559  }
560  else
561  {
562  gt=Awx+190000; // s. allegro.hpp: CHAR Awx[256000]
563  while (*ft)
564  if (*ft<32) // 13 10 -> Code20, 9 -> Space
565  {
566  if (*ft==10) *gt++=20;
567  else if (*ft==9) *gt++=' ';
568  else if (*ft==13) ;
569  else *gt++=*ft;
570  ++ft;
571  }
572  else *gt++=*ft++;
573  *gt=0;
574  ft=Awx+190000;
575  }
576 
577  // $$971116 NEU fuer ..#01 etc.
578  if (*ft==RS)
579  {
580  strcpy(Wspace,ft);
581  f=kfg->KoVerify(ft+3);
582  }
583  else if (*ft!=kfg->KC)
584  {
585  if ((f=kfg->KoVerify(ft))!=-1)
586  strcpy(Wspace+3,ft);
587  else return -1;
588  }
589  else
590  {
591  if ((f=kfg->KoVerify(ft+1))==-1) return -1; // tag valid? -1 = no
592  strcpy(Wspace+2,ft);
593  }
594 // $$980326 4 neue Zeilen: (Kat. Loeschen / neu anhaengen )
595 
596  if (Wspace[2+kfg->skt]=='_' && Wspace[3+kfg->skt]==0)
597  {
598  Wspace[2+kfg->skt]=0;
599  return Del(Wspace+2);
600  }
601 
602  if (Wspace[2+kfg->skt]=='~')
603  {
604  Wspace[3+kfg->tgl]='~';
605  strcpy(Wspace+2+kfg->skt,Wspace+3+kfg->skt);
606  }
607 
608 
609  return ginst(f); // do the string space management
610 }
611 
612 // ************ Feld kat rausnehmen
613 int RECORD::Del(CHAR *kat) // z.B. Del("#123")
614 {
615  int ri=0;
616  ri=Pos(kat);
617  *Aerror=0;
618  if (ri==-1) return 0;
619 // strcpy(Aerror,ga[ri]);
620  PartDel(ri,ri+1);
621 // *Aerror=0;
622  return ri+1;
623 
624 }
625 
626 // ************ Mehrere Felder rausnehmen
627 // Delete part of current record
628 
629 int RECORD::PartDel(int i, int j) // alt: rdelete(int i,int j)
630 // j==-1: from i to the end
631 {
632  unsigned int k, h;
633  if (j==-1 || j>gri) j=gri; // j>gri would be dangerous
634  if (i<0) return 0;
635  if (i<j)
636  {
637  if (gi[i]>2 && gi[i]<9) ga[i][1]=1; // deleting #01..#06
638 
639  if (j==gri)
640  {
641  gri=i;
642  gend=ga[i];
643  }
644  else
645  {
646  src=ga[j];
647  dest=ga[i];
648  if (*dest==RS && *src!=RS) dest+=2, ga[j]-=2;
649  cnt=gend-src;
650  h=src-dest;
651  gend-=h;
652  memmove(dest,src,cnt);
653  k=0;
654  while ((int)(j+k)<gri)
655  {
656  ga[i+k]=ga[j+k]-h;
657  gi[i+k]=gi[j+k];
658  ++k;
659  }
660  gri-=(j-i);
661  }
662  if (cri>i) cri-=(j-i);
663  if (mri>i) mri-=(j-i);
664  *gend=EOD;
665  ga[gri]=gend;
666  gi[gri]=0;
667  }
668  return 1;
669 
670 }
671 
672 // ********** HIERARCHISCHE UNTERSAETZE **************
673 
674 // ********** hierarch. Untersatz, erstes Feld finden
675 int RECORD::SubPos(CHAR *kat) // find position of kat
676 // kat="#01 5"
677 // and make subrecord current record
678 {
679  int ri=1;
680  while (ri<gri)
681  { // Jeder hierarch. Untersatz beginnt im Arb.Sp. mit RS (29)
682  // danach folgt 02 bei #01, 03 bei #02 usw.
683  while (*ga[ri]!=RS) if (ri==gri) return -1;
684  else ++ri;
685  if (!strcmp(kat,ga[ri]+2)) return (cri=ri); // ist es dieser?
686  else ++ri;
687  }
688  return -1;
689 }
690 
691 // ************* Hierarch. Untersatz kopieren
692 // Copy a subrec from one into another (or the same) rec
693 // $$971116 Korrekturen
694 int RECORD::SubCopy(int pos, RECORD *R, int rp, int md)
695 // Copy subrec at rp in R to this rec at pos
696 // md=0: copy 1: move (delete the source subrec)
697 {
698  int h1;
699  CHAR h;
700  int cri0;
701  cri0=cri;
702  cri=pos;
703  if (*ga[pos]!=RS && cri!=gri) return 1; // move not possible
704  R->mri=rp; // mri moves if R is this same record!
705  h1=gi[cri];
706  gi[cri]=32000;
707  h= *ga[cri];
708  *ga[cri]=20;
709 
710  Ins(R->ga[R->mri]);
711  if (md)
712  {
713  rp=R->mri;
714  *R->ga[rp]=48;
715  R->PartDel(rp, rp+1);
716  }
717  else ++R->mri;
718 
719  gi[cri+1]=h1;
720  *ga[cri+1]=h;
721  while (*R->ga[mri]!=RS && R->mri<R->gri)
722  {
723  Ins(R->ga[R->mri]);
724  if (md) R->PartDel(R->mri,R->mri+1);
725  else ++R->mri;
726  }
727  cri=cri0;
728  return 1;
729 
730 }
731 
732 // ************** Hierarch. Untersatz verschieben
733 int RECORD::SubMove(int pos, RECORD *R, int rp)
734 {
735  return SubCopy(pos, R, rp, 1);
736 }
737 
738 // ************** Hierarch. Untersatz herausnehmen
739 int RECORD::SubDel(CHAR *kat) // Delete subrecord beginning at kat
740 {
741  int ri,ni;
742  ri=SubPos(kat); // z.B. kat="#01 Bd. 2"
743  if (ri==-1) return ri;
744  ni=SubNxt(ri);
745  PartDel(ri,ni);
746  return ri;
747 }
748 
749 // ************* Hierarch. Untersatz herausnehmen, der auf Pos. pos beginnt
750 int RECORD::SubDel(int pos) // Delete subrecord from position pos
751 {
752  int ri,ni;
753  ri=pos;
754  if (ri==-1) return ri;
755  ni=SubNxt(ri);
756  PartDel(ri,ni);
757  return ri;
758 }
759 
760 // ************** Pos. d. naechsten hierarch. Unters. finden
761 int RECORD::SubNxt(int ri) // find Pos of nxt subrec, not cyclic!
762 { // return -1 if it was the last
763  ++ri;
764  while (ri<gri) if (*ga[ri]==RS) break;
765  else ++ri;
766  if (ri==gri) ri=-1;
767  return ri;
768 }
769 
770 // ************** Pos. d. vorigen hierarch. Unters. finden
771 int RECORD::SubPre(int i) // find Pos of previous subrec,
772 // cyclic: for i==0, return pos of last subrec
773 { // return -1 if there is no subrecord
774  int ri=i;
775  --ri;
776  if (ri==-1) ri=gri;
777  while (ri>0) if (*ga[ri]==RS) break;
778  else --ri;
779  if (i==ri) return -1;
780  return ri;
781 }
782 
783 // %% cmd_y() und cmd_ast aus ACORE.C
784 
785 unsigned int g0;
786 
787 // ********* Search and Replace in record
788 
789 CHAR *RECORD::SrRp(CHAR *a,CHAR *b,int mde,int d,int r) // srch (+repl)
790 // CHAR *a; // start addr of srch term
791 // with *a = delimiter
792 // CHAR *b; // srch domain
793 // int mde; // mode: 0:manual 1:automatic
794 // int d; // domain: 0:group 1:rec 2:field
795 // int r; // 1: +repl 0: srch only
796 {
797  register unsigned int i, j;
798  int c, m;
799  unsigned int k, k1, n;
800  unsigned char cmc= *a; // cmd code
801  static CHAR *retadr;
802  retadr=(CHAR *)NULL;
803  CHAR *w;
804  CHAR *g; // neu $$981118
805  w=Wspace;
806  g=ga[0];
807  if (!*b) return retadr; // no domain! $$940614
808  *gend=EOD;
809  gend[1]=0; // to mark the end
810  c=1;
811  if (!d) c=EOD;
812  if (d==2) c=NL;
813  j=i=strlen(a);
814  if (j==1) return (CHAR *)NULL;
815  if (a[1]==cmc) // #__#xx text_ : insert #xx text //$$14.7.9
816  {
817  strcpy(w,a+2);
818  if (w[j-3]==cmc) w[j-3]=NL;
819 
820  strcpy(Aspace,w);
821  if ((m=kfg->KoVerify(w+1))!= -1)
822  {
823  Ins(Aspace);
824  return Aspace;
825  }
826  else return (CHAR *)NULL;
827 
828 // if((m=kfg->KoVerify(w+1))!= -1) { ginst(m); return w; }
829  }
830  k=0;
831  g0=cri;
832  if (!d) if (cri==gri)
833  {
834  cri=g0=0;
835  b=g;
836  }
837  while (j>2) if (a[--j]==cmc) ++k;
838  j=i;
839  if (k<2) a[j++]=cmc;
840  if (!k) a[j++]=cmc;
841  a[j]=NL;
842  j=i=b-g+1;
843  if (a[1]==' ' && a[2]==*a) i+=4; // single space: don't repl behind #nn
844  if (!d) j=gend-g;
845  else
846  while (g[++j]!=c && g[j]!=EOD) ; // set j to end of curr re
847 
848 // Nun von links nach rechts vergleichen und ggfls. austauschen
849  while (i<j)
850  {
851  k=1;
852  while (a[1]!=g[i] && i<j) if (g[i++]==FS)
853  {
854  ++g0;
855  if (a[1]==' ' && a[2]==*a) i+=4;
856  }
857  // replace single space only within field
858  if (++i>j)
859  {
860  i=j;
861  break;
862  }
863  n=i; // $$040416 : && g[n]
864  while (a[++k]!=cmc && (a[k]==g[n] || a[k]=='?') && a[k]!='$' && g[n]) ++n;
865  if (a[k]=='$') ++k;
866  if (a[k]==cmc) // match, repl?
867  {
868  retadr=(g+i-1);
869  if (!r) // srch only
870  {
871  return retadr; // $$980101 NEU
872  }
873  // srch+repl
874  // noch verbessern:
875  // if((c=kat[gi[g0]*3+2])!='z' && c>'@') // *KAT*
876 
877  c=CR;
878  if (c==' ') ;
879  else
880  {
881  if (c!=CR) break;
882  k1=k;
883  if (a[1]==kfg->KC) // suchbegr. beginnt mit #
884  {
885  if (a[k+1]==cmc)
886  {
887  PartDel(g0,g0+1); // _#nnn__ delete field
888  break;
889  }
890  if (a[k+1]!=kfg->KC) break;
891  else
892  {
893  m=0;
894  while ((w[m]=a[k+1+m])!=0) ++m; // _#nnn_#kkk_
895  --m;
896  w[m]=0; // i=0; if(g0==cri) i=2;
897 // $$980905 4 Zeilen: (sonst _#aaa_#bbbxyz_ falsch)
898 // if(strlen(ga[g0])>m+i)
899  --k1;
900  if (*ga[g0]==RS) k1+=2;
901  while ((w[m]=ga[g0][k1++])!=0) ++m;
902  strcpy(Aspace,w);
903  int cri0=cri;
904  cri=g0;
905  while (*ga[cri]!=RS) --cri;
906  if ((m=kfg->KoVerify(w+1))!= -1)
907  {
908  PartDel(g0,g0+1);
909  Ins(Aspace);
910  }
911 // i=j; // nur 1 pro Satz!?
912  i+=5;
913  cri=cri0; // for hierarch records! or changed field goes to main rec
914  }
915  }
916  else // normaler Suchbegr.
917  {
918  if (a[k-1]=='$')
919  {
920  n-=2;
921  k1-=3;
922  while (g[n++]!=NL) ++k1;
923  }
924  m=i-1;
925  --k; // m=start pos, k=len of srch str
926  src=g+m+k1-1; // begin shift here
927  cnt=gend-src+1; // this many byte
928  dest=g+m+strlen(a)-k-3;
929  if (src!=dest)
930  {
931  m=dest-src;
932  memmove(dest,src,cnt);
933  n=g0;
934  while ((int)++n<=gri) ga[n]+=m;
935  gend+=m;
936  *gend=EOD;
937  j+=m; // adjust len of current repl domain
938  }
939  src-=(k1-1);
940  k+=2;
941  while (a[k]!=cmc)
942  {
943  *src++=a[k++]; // transfer
944  ++i;
945  }
946  --i;
947  }
948  }
949  }
950  } // while(i<j) naechsten match suchen
951  return retadr;
952 }
953 
954 // ************ Feldspezif. Suchen und Ersetzen im Satz
955 // field specific srch&repl in current rec
956 // $$001127 : neu: md
957 
958 CHAR *RECORD::FSrRp(CHAR *a, int md) // md=0:srch 1:srch+repl
959 {
960  int crix=cri;
961  CHAR *b, *x, *r, *s;
962  x=a+1;
963  b=ga[cri];
964  r=(CHAR*)NULL;
965  while (*x!='_' && *x!=',' && *x!=NL) ++x;
966  if (*x!=NL)
967  {
968  *a= *x;
969  while ((b=SrRp(a,b,1,1,0))!=(CHAR *)NULL) // nxt occurrence of a in b
970  {
971  cri=g0;
972  s=SrRp(x,b,1,2,md); // is x in b? // $$020708 : md statt 1 !!
973  if (s!=(CHAR *)NULL) r=s;
974  ++b;
975  }
976  }
977  *a='*';
978  cri=crix;
979  return r;
980 }
981 
982 #ifdef __ABASE
983 // *********** Satz sperren und Schluessel ermitteln
984 // Beim Speichern werden die Schl. dann verglichen mit den neuen
985 // make rec available for manipulation, includes locking
986 
987 int RECORD::Reserve() // return -1 : Error
988 { // 8,9 : already locked, deleted
989  int rc=0; // 0,1 : success / no database
990 
991  if (rSt!=1) return -1; // ERROR, only record status 1 is reservable
992  if(Adn==EOF) return 1; // no database (offline mode, obsolete!
993  rc=((ABASE *)Abase[Adn])->AwRecLock(rNr); // 0: OK
994 // Der Ergebniswert steht dann in Alock (FLEX: var sL) ab V32.4, Erfolg: Alock==0
995  if (rc==0) // OK
996  {
997  rSt=2; // 2 = flag fuer "reserviert";
998 // "reserviert" gilt nur im Arb.Speicher, wird nicht in der Datenbank gespeichert!
999 // Dort wird ein Code 8 eingetragen.
1000  ((ABASE *)Abase[Adn])->AbKeys(this,0); // Schluessel berechnen
1001  }
1002  return rc;
1003 }
1004 
1005 // *********** Satz freigeben
1006 // cancel action on this rec, unlock it
1007 // Freigabe, falls gelockt (dann ist rSt==2)
1008 
1009 int RECORD::Release() // return 0 : OK, sonst Error
1010 {
1011  int rc=1;
1012  if(!rNr) return -1;
1013  if (Adn!=EOF) rc=((ABASE *)Abase[Adn])->AwRecUnlk(rNr);
1014  rKx=0;
1015  rKy[0]=rKbase; // keyspace reset
1016  rSt = 1; // Status auf 1 = normal
1017  return rc;
1018 }
1019 
1020 #endif
1021 
1022 // *************** Satz leermachen
1023 void RECORD::Empty() // reset rec as if new
1024 {
1025 // Release(); // rather not! "empty" soll nicht zú Freigabe fuehren
1026 
1027  rKx=0; rKy[0]=rKbase; // keyspace reset
1028  ga[0]=ga[1]=gend=g;
1029  *gend=EOD;
1030  gi[0]=gi[1]=0;
1031  cri=gri=mri=0;
1032 
1033  Adn=-1;
1034  rNr=0L; // default rec# = 0 : new rec
1035  rSt=1; // $$041213 sonst evtl. 9 = deleted
1036  rFi = 0; // .ALD file#
1037  return;
1038 }
1039 
1040 // ************** Satz in ein anderes SatzObjekt kopieren
1041 // Copy record Rec into this one
1042 
1044 {
1045  int i=0;
1046  gri=Rec->gri;
1047  kfg=Rec->kfg;
1048  schema=Rec->schema;
1049  memmove(ga[0],Rec->ga[0],(Rec->gend)-(Rec->ga[0])+5);
1050  while (i<=gri)
1051  {
1052  ga[i]=ga[0]+(Rec->ga[i] - Rec->ga[0]);
1053  gi[i]=(int)(Rec->gi[i]);
1054  ++i;
1055  }
1056  gend=ga[gri];
1057  Adn=Rec->Adn;
1058  if (Adn<0 || Adn>5) Adn=Rec->Adn=0; // Wenn Rec keiner Datenbank zugeordnet war
1059  return;
1060 }
1061 
1062 // ********************************
1063 
1064 RECORD::~RECORD() // Destruktor
1065 {
1066 #ifdef __ABASE // is ABASE being used? (Or no database, just RECORD)
1067 // if(rSt==2) Release(); // release it if it was reserved - rather not!
1068 #endif
1069  if (rKbase) delete[]rKbase;
1070  rKbase=(CHAR *)NULL;
1071  delete[]ga;
1072  ga=(CHAR**)NULL;
1073  delete[]gi;
1074  gi=(int*)NULL;
1075  delete[]Wspace;
1076  Wspace=(CHAR *)NULL;
1077  delete[]g;
1078  g=(CHAR *)NULL;
1079  return;
1080 }
1081 
1082 
1083 /*
1084  Copyright 2011 Universitaetsbibliothek Braunschweig
1085 
1086  Licensed under the Apache License, Version 2.0 (the "License");
1087  you may not use this file except in compliance with the License.
1088  You may obtain a copy of the License at
1089 
1090  http://www.apache.org/licenses/LICENSE-2.0
1091 
1092  Unless required by applicable law or agreed to in writing, software
1093  distributed under the License is distributed on an "AS IS" BASIS,
1094  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1095  See the License for the specific language governing permissions and
1096  limitations under the License.
1097 */
1098