a99  V32.6
allegro Windows Hauptprogramm
 Alle Klassen Dateien Funktionen Variablen Typdefinitionen Aufzählungen Aufzählungswerte Makrodefinitionen
abasew.cpp
gehe zur Dokumentation dieser Datei
1 // abasew.cpp Nur einbinden, wenn Schreibfunktionen gewuenscht, sonst nur abase.cpp
2 // 1996-04-03 Saetze schreiben, loeschen, TBL sperren, freigeben
3 // Klasse ABASE , Modul ABASEW (c) UB Braunschweig 1996
4 
5 // Copyright 2011 Universitätsbibliothek Braunschweig, more see bottom
6 
7 // ii : NEU $$991117 wg. "Aufbohrung"
8 
9 
10 #ifdef WIN32
11 #include <windows.h> // nur fuer Sleep(1000)
12 #define _handle _file
13 #include <sys\locking.h> // ---- MICROSOFT ----
14 #endif
15 
16 #include "abase.hpp"
17 #include "exet.hpp"
18 
19 // FUNKTIONEN (public)
20 // AwPut() : Satz wegspeichern
21 // AwDel() : Satz loeschen
22 // AwTlock() : TBL sperren
23 // AwTunlock() : freigeben
24 // AwRecLock() : Datensatz sperren
25 // AwRecUnlk() : freigeben
26 
27 // Clsix() und Opnix() : Index schliessen und oeffnen (zwecks flush)
28 // timestamp() : Zeitstempel und Nummernvergabe
29 
30 
31 // ************************************************
32 // Datensatz wegschreiben incl. aller Nebenarbeiten
33 // write RECORD to file, do indexing etc.
34 
35 int ABASE::AwPut(RECORD *record, int wmodus) // %% write_out()
36 // wmodus = 0 : full operation, index and all (default)
37 // 1 : same, with message to Aerror
38 // 2 : no indexing
39 // 4 : no LOGging
40 // these arguments can be ORed: 6 : no index, no LOG
41 // return: EOF ==-1, file not good / no rights
42 // 0 rec was not properly prepared / TBL locked
43 // gri OK, gri=number of fields of this rec (>0)
44 {
45 
46  int i=0, errCode;
47 
48  if (!accf)
49  {
50  sprintf(Aerror,"no rights%c",0); // no rights
51  return EOF;
52  }
53 
54  Rcu=record; // current record
55 
56  if (Rcu->rNr > 0L)
57  if (Adn!=Rcu->Adn) // dann ist was faul am Datensatz
58  {
59  sprintf(Aerror,"Wrong database%c",0);
60  return EOF;
61  }
62  else ;
63  else Rcu->Adn=Adn; // rNr==0: rec is new
64 
65 // zur Bequemlichkeit
66  cri=Rcu->cri;
67  ga=Rcu->ga;
68  gri=Rcu->gri;
69  gend=Rcu->gend;
70  gi=Rcu->gi;
71 
72  char ix=aix; // MultiX, default 'd' for .adx
73 
74  wrfl=0; // Nr of keys written
75 
76  if (aix!='d') InSwix('d'); // MultiX: auf .adx schalten
77 
78 // lock .TBL file
79  if (mult) if (!AwTlock())
80  {
81  sprintf(Aerror,uif[175]); // "bitte warten"
82  return 0;
83  }
84 
85 // timestamp muss innerhalb der locking-Prozedur stattfinden,
86 // sonst Vergabe gleicher Nummern moeglich !!!
87 
88  { // preprocessing record before save
89 
90 // extern CHAR *ch1, *ch2, ct[][ML]; // exet.cpp, Indexparam.
91  *ct[ML]=0;
92 
93  ch2=(CHAR *)"#u2 ssss";
94 
95  Exp(Rcu,1,(CHAR *)"\02"); // vorletzte PV vor dem Speichern
96 
97  ch2=(CHAR *)nil;
98 
99  if (*ct[ML])
100  {
101  sprintf(Aerror,"%s:\n%s",uif[28],ct[ML]);
102  if (mult) AwTunlock();
103  return -1;
104  }
105  }
106  timestamp(1); // einschl. Nummernvergabe // $$050708 vorher weiter oben, NNNN hier neu:
107 
108  ch2=(CHAR *)"#u2 NNNN";
109 
110  Exp(Rcu,1,(CHAR *)"\02"); // letzte PV vor dem Speichern
111 
112 
113  gri=Rcu->gri; // Zahl der Felder u. Satzlaenge evtl. veraendert durch PV
114  gend=Rcu->gend;
115 
116  while (i<gri) if (ga[++i][1]==1) break; // where's the end of our rec?
117  gri=i; // Nachgeladene stehen evtl. dahinter, beginnen mit 1
118  i=1;
119  gend=ga[gri]; // here
120  alth=gend-ga[0]-gri-2; // determine actual length of rec
121  while (i<gri) if (*ga[i++]==RS) --alth; // -1 char per subrec
122 
123  oldrecn=0L; // 1 wenn alter Satz umgespeichert wird
124 
125  if (!Rcu->rFi) Rcu->rFi=inputFi; // file# for new rec
126  writeFi=Rcu->rFi; // which file to write to
127 
128  if (!Rcu->rNr) i=new_rec(); // look for a place to store it
129  else i=old_rec(); // and do the .TBL-work for the addresses
130 
131  if (i<1)
132  {
133  if (!*Aerror) // $$970922 NEU
134  sprintf(Aerror,"Write File trouble%c",0);
135  return 0;
136  } // trouble with a file
137 
138  // now fwr is open for writing
139 
140  errCode = wrout(fwr, wmodus, 0 ); // serve .ALD : write rec to file
141 
142  fclose( fwr ); // and force it to disk
143 
144  if (errCode == EOF)
145  {
146  sprintf(Aerror,"Write problem%c",0);
147  return (0);
148  }
149 
150 // .LOG zuerst bedienen, denn durch Indexieren wird der Satz evtl.
151 // veraendert (V14-Aufloesung!)
152 
153  alth=0; // reset actual length
154 
155  if (logflg && !(wmodus & 4))
156  {
157  logfile=fopen(dbLog, "a+b"); // .LOG oeffnen zum Anhaengen.
158 
159  if (logfile) // $$011020
160  {
161  wrout(logfile, 0 ,1); // Satz schreiben
162  fclose( logfile ); // Schliessen
163  }
164  else sprintf(Aerror,"LOG-file %s nicht zugaenglich!",dbLog);
165  }
166 
167 // Indexieren
168  if (!(wmodus & 2)) // serve .ADX --> INDEX.CPP
169  {
170  int i,j;
171  i=cri;
172  cri=0;
173  j=InKeyCalc(Rcu,1); // produce and store keys
174  cri=i;
175  if (j==-1) sprintf(Aerror,"E write error in index file\n"); //$$961127
176  else wrfl+=j;
177  }
178  if (wrfl)
179  {
180  Clsix(); // to force all index stuff out
181  InSwix('d'); // MultiX: zu .ADX schalten
182  Opnix();
183  ix_reset(); // go back to last position, to prevent scroll trouble
184  } // in case of index operations
185 
186  if (mult) AwTunlock(); // unlock .TBL darf nicht zu frueh sein! $$000523
187 
188 // Rcu->rSt=1; //$$980206 ve: Freigabe des Satzes muss stattfinden
189 
190  if (wmodus & 1) sprintf(Aerror,uif[174],wrfl); // %d Schluessel geaendert" 13 10
191 // ++count;
192 
193  if (i5 || xrp[0])
194  {
195  AbGet(Rcu->rNr, Rcu, 0); // V14 : Satz neu einlesen
196  }
197 
198  if (ix!='d') InSwix(ix); // MultiX
199 
200  return 1;
201 } // Ende AwPut()
202 
203 
204 // ****************************************
205 int ABASE::AwTlock() // lock the .TBL file
206  // return 1:OK, 0:geht nicht
207 {
208  CHAR w[2];
209  int tt=10;
210 BEGIN:
211  while (tt) // wait loop : until .TBL free
212  {
213  lseek(dbTb,0L,0);
214  read(dbTb,w,1);
215  if (*w<1) break;
216  close(dbTb);
217  dbTb=Tblopen(".tbl");
218  --tt;
219 #ifdef WIN32
220  Sleep(1000);
221 #else
222  sleep(1); //wait 1 second
223 #endif
224  }
225  if (!tt) { Alock=1; return 0; } // may be locked permanently !!
226  lseek(dbTb,0L,0);
227 
228 #ifdef WIN32
229  if ( _locking( dbTb, LK_NBLCK, 1L ) != -1 )
230  {
231 #else
232  if ( lock( dbTb, 0L, 1L ) == 0 )
233  {
234 #endif
235  lseek(dbTb,0L,0);
236  read(dbTb,w,1); // $$990729 NEU wg. "racing condition"
237  if (*w!=0)
238  {
239 #ifdef WIN32
240  _locking( dbTb, LK_UNLCK, 1L );
241 #else
242  unlock( dbTb, 0L, 1L );
243 #endif
244  tt=10;
245  goto BEGIN;
246  }
247  lseek(dbTb,0L,0);
248  *w=1;
249  write(dbTb,w,1);
250 #ifdef WIN32
251  lseek(dbTb,0L,0);
252  _locking( dbTb, LK_UNLCK, 1L );
253 #else
254  unlock( dbTb, 0L, 1L );
255 #endif
256  }
257  else { Alock=1; return 0; } // Keine Locksperre möglich
258 // close(dbTb); // and force it out
259 // dbTb=Tblopen(".tbl");
260  if (mult)
261  {
262  aiCLOSE(Adn*15,filmod); // force all index stuff out in mult mode
263  InOpen(255);
264  }
265  Alock=0; // fuer OK
266  return 1;
267  } // ENDE AwTlock()
268 
269 // ***************************************
270 
271 void ABASE::AwTunlock() // unlock .TBL
272 { // Alock auf 0 setzen, wenn Erfolg, sonst 1
273  CHAR w[2];
274  int i;
275  int z=10;
276 
277 while(z)
278 {
279  --z;
280  lseek(dbTb,0L,0);
281 #ifdef WIN32
282  while ( _locking( dbTb, LK_NBLCK, 1L ) == -1 )
283 #else
284  while ( lock( dbTb, 0L, 1L ) == -1 ) // u.U. mehrere Versuche noetig!
285 #endif
286  for (i=0 ; i==1000 ; ++i) ; // kurze Verzoegerung vor naechstem Versuch
287 
288  *w=0;
289  i=write(dbTb,w,1);
290  if (i==-1) continue;
291  break;
292 }
293 #ifdef WIN32
294  lseek(dbTb,0L,0);
295  _locking( dbTb, LK_UNLCK, 1L );
296 #else
297  unlock( dbTb, 0L, 1L );
298 #endif
299 
300  close(dbTb);
301  dbTb=Tblopen(".tbl");
302 if(!z) Alock=1; else Alock=0;
303  return;
304  } // ENDE AwTunlock()
305 
306 
307 // ******************
308 int ABASE::old_rec() // Datensatz nach Bearb. wieder wegschreiben
309 {
310  int i;
311  oldrecn=Rcu->rNr;
312  if (alth>Rcu->rLg-2) // not enough room
313  {
314  int optn=opt_N;
315  if (opt_N==1) opt_N=2; // $$980313 if... NEU
316  i=alth;
317  alth=0;
318  oldrad=Rcu->rOf;
319  oldrlg=Rcu->rLg;
320  oldfn=Rcu->rFi;
321  //Rcu->rLg=0L; XXX?
322  alth=i;
323  i=new_rec();
324  opt_N=optn;
325  return i;
326  }
327  alth= Rcu->rLg-alth - 2;
328  if (alth<0) alth=0; // for fill
329 
330  fwr = Openf(writeFi);
331  if (!fwr)
332  {
333  sprintf(Aerror,"file error: %s_%d",dbN,writeFi);
334  return EOF;
335  }
336 
337  fseek(fwr,Rcu->rOf,0);
338  return 1;
339 } // Ende old_rec()
340 
341 
342 // *********************
343 int ABASE::new_rec(void) // Vorbereitungen zum Schreiben eines NEUEN Satzes
344 // UND Datei fwr zum Schreiben oeffnen
345 {
346  RECNR recn;
347  char nwkey[259], idxval[259];
348  int c0=0, cl=0;
349  --alth;
350  strcpy((char*)nwkey,"//"); // gibt's ungueltige Saetze?
351  if (!opt_N) *nwkey='`'; // $$951025 -N0 : verhindert Suche nach "//..." im Reg.1
352  UtKitoa5(alth+3,(CHAR *)nwkey+2); // wir brauchen einen Satz von mind. dieser Laenge
353  pad((CHAR *)nwkey);
354  recn=aiEntGe(0+Adn*15,(CHAR*)nwkey,(CHAR*)idxval); // gibt es ungueltige Saetze?
355  while (*idxval=='/' && idxval[1]=='/') // ja
356  {
357  cl=atoi((char*)idxval+2);
358  if (cl>alth+10+alth/20) break; // avoid too much needless srching
359  c0=cl;
360  AbGet(recn, Rcu, 2); // get rFi + rOf into R
361  writeFi=Rcu->rFi;
362  if (opt_N==2 && ((oldrecn && oldfn!=writeFi) || (!oldrecn && inputFi!=writeFi)))
363  {
364  c0=0; // don't use other file
365  memmove(nwkey,idxval,keymax); // sonst Ueberschreibfehler
366  // durch falsche Ergebnisse?
367  recn=aiEntGt(0+Adn*15,(CHAR*)nwkey,(CHAR*)idxval); // das ist sicherer als aiEntNx
368  }
369  else break; // got one
370  }
371 
372  if (alth+2<c0) // we got one that's gonna fit
373  { // without being too large
374 
375  fwr = Openf(writeFi);
376  if (!fwr)
377  {
378  sprintf(Aerror,"file error: %s_%d",dbN,writeFi);
379  return 0;
380  }
381 
382  Rcu->rLg = cl;
383  fseek(fwr,Rcu->rOf,0); // and go to its position
384  alth=Rcu->rLg-alth-3; // for fill
385 // qq(); // queue XXX noch notwendig?
386 
387  aiEntLo(0+Adn*15,(CHAR*)idxval,recn); // delete its empty key
388  ++wrfl;
389 
390  if (oldrecn) // swap numbers of old and new recs
391  { // write rad to tbl-position of recn
392  tbl_out(writeFi,recn,oldrad+1L);
393  UtKitoa5(oldrlg,(CHAR *)idxval+2);
394  pad((CHAR *)idxval); // recn now has a different length
395  aiEntIn(0+Adn*15,(CHAR*)idxval,recn,0);
396  ++wrfl;
397  fseek(fwr,oldrad,0);
398  fputc(9,fwr);
399  ald_out(fwr,recn);
400  // mark the old position as cleared
401  Rcu->rNr=oldrecn;
402  }
403  fseek(fwr,Rcu->rOf,0);
404  tbl_out(writeFi,oldrecn,Rcu->rOf+1L);
405  return 1;
406  }
407 // Kein passender Leersatz, dann an das Ende der Neudatei schreiben
408 
409  {
410  int i;
411  strcpy((char*)nwkey,"/[0");
412  recn=aiEntGe(0+Adn*15,(CHAR*)nwkey,(CHAR*)idxval); // any unused numbers ?
413  if (recn) if (!strncmp((CHAR*)nwkey,(CHAR*)idxval,3))
414  i=aiEntLo(Adn*15,(CHAR*)idxval,recn);
415  else recn=0L;
416  // yes, delete from index
417  if (!recn || i) recn=(lseek(dbTb,0L,2)-2L)/4L + 1L; // else assign new rec#
418  }
419 
420 
421  if (recn<1L)
422  {
423  sprintf(Aerror,"error in .TBL%c",0);
424  return 0;
425  }
426 
427  if (oldrecn)
428  {
429  writeFi=oldfn;
430  fwr=Openf(writeFi);
431  if (!fwr)
432  {
433  sprintf(Aerror,"file error: %d",writeFi);
434  return 0;
435  }
436 
437  fseek(fwr,oldrad,0); // go to old position
438  fputc(9,fwr);
439 
440  ald_out(fwr,recn); // mark as cleared
441 
442  tbl_out(writeFi,recn,oldrad+1L); // assign new rec# to old pos
443 
444  strcpy((char*)idxval,"//");
445  UtKitoa5(oldrlg,(CHAR *)idxval+2); // provide empty key
446  pad((CHAR *)idxval);
447  aiEntIn(0+Adn*15,(CHAR*)idxval,recn,0); // and add to index
448  ++wrfl;
449  Rcu->rNr=oldrecn; // now use old rec# to proceed
450  } // store new/updated rec to new file:
451  else
452  {
453  Rcu->rKx=0; // new rec - no old keys!
454  Rcu->rNr = recn; // $$960523 sonst Satznr 0 !
455  Rcu->rFi=writeFi=inputFi; // $$000526 Rcu->rFi= sonst falsche Nr in LOG
456  if ((fwr=Openf(writeFi))==(FILE *)0)
457  {
458  {
459  int i=20000; // short sleep
460  while (i--);
461  }
462  if ((fwr=Openf(writeFi))==(FILE *)0)
463  {
464  sprintf(Aerror,uif[187],writeFi);
465  // Datei %d kann nicht ge”ffnet werden
466  return 0;
467  }
468  }
469  }
470  Rcu->rLg=alth+2+kfg->lz+1; // this is the new rec len
471  // we need it in case of immediate call to editor
472  // right after saving
473  // $$ii hier Anzahl der noetigen Fuellbytes bestimmen (Aufbohrung)
474 
475  if (ii)
476  {
477  int zz=(Rcu->rLg+5)%ii;
478  if (zz) zz=ii-zz;
479  alth=kfg->lz+zz;
480  }
481  else alth=kfg->lz;
482  // $$ii now alth = number of fillers
483 
484 // XXX noch zu machen: ??
485 // qq(); // queue
486 
487  while (1) // wg. 16MB Grenze
488  {
489  if (fwr)
490  {
491  fseek(fwr,0L,2); // goto file end
492  Rcu->rOf=ftell(fwr);
493  if (Rcu->rOf<filmax) break;
494 #ifndef UNIX
495  if (fwr->_handle!='\xFF') fclose( fwr );
496 #else
497 #ifdef LINUX
498  if (fwr->_fileno!='\xFF') fclose ( fwr );
499 #else
500  if (fwr->_file!='\xFF') fclose( fwr );
501 #endif
502 #endif
503  }
504  if (inputFi==writeFi) ++inputFi;
505  Rcu->rFi=++writeFi;
506  if (writeFi==256)
507  {
508  sprintf(Aerror,"no file can be opened: %d",writeFi);
509  return 0;
510  }
511  fwr = Openf(writeFi); // open nxt file
512  }
513 
514  tbl_out(writeFi,Rcu->rNr,Rcu->rOf+1L);
515  return 1;
516 }
517 // Ende new_rec()
518 
519 
520 // **** Hilfsfunkt. write rec starting at cri to file fwr
521 
522 int ABASE::wrout(FILE *dataStream, int wmodus, int wf )
523 {
524  int j;
525  CHAR *o;
526 #ifndef UNIX
527  if (dataStream->_handle == '\xFF') // Geschlossen. // MS
528 #else
529 #ifdef LINUX
530  if (dataStream->_fileno == '\xFF') // Geschlossen. // LINUX
531 #else
532  if (dataStream->_file == '\xFF') // Geschlossen. // SUN
533 #endif
534 #endif
535  {
536  sprintf(Aerror,"File not open%c",0);
537  return (EOF);
538  }
539 
540 // Soll es die .LOG-Datei sein:
541 
542  if (wf==1 && !oldrecn)
543  {
544  fputc( 8, dataStream ); // 8 heisst: neuerSatz
545  // dann Dateinummer statt Satznr
546  ald_out( dataStream, (RECNR)Rcu->rFi );
547  }
548  else
549  { // Fuer .ALD-Datei :
550  // Schreibstelle pruefen: Satzanfang?
551  j = fgetc( dataStream );
552  if (j!=1 && j!=8 && j!=9 && j!=EOF)
553  return EOF;
554 
555  if (j!=EOF) // 1 byte zurueck
556  fseek( dataStream, -1L, 1 );
557  if (Rcu->rSt==9) // geloeschter Satz wird in .LOG geschrieben
558  fputc( 9, dataStream );
559  else
560  fputc( 1, dataStream ); // korrigierter Satz
561 
562  ald_out( dataStream, Rcu->rNr);
563  }
564 
565 // Ab hier fuer beide Faelle:
566 
567  j = cri;
568 
569  do
570  {
571  if (j==cri) o=ga[j]+2;
572  else
573  {
574  o=ga[j]+1; // begin with hierarchy byte
575  if (*o==1) break; // nxt main rec begins, stop do-loop here
576  if (fputc((int)*o++, dataStream)==EOF)
577  {
578  sprintf(Aerror,"File error%c",0);
579  return EOF;
580  }
581  }
582  if (*o==RS) o+=2; // Vorsichtsmassnahme
583  while (*o!=RS && j<gri) // RS = 29 = internal rec separator
584  {
585  ++o; // omit #
586  while (*o!=FS)
587  fputc((int)*o++, dataStream );
588 
589  if (fputc(FS, dataStream) == EOF)
590  {
591  sprintf(Aerror,"Dateifehler%c",0);
592  }
593  ++j;
594  ++o;
595  }
596  }
597  while (j<gri); // volume follows? write it
598 
599  if (wmodus)
600  {
601  sprintf(Aerror,uif[176],writeFi);
602  // Speicherung in Datei %d, "
603  sprintf(Aerror+strlen(Aerror),uif[177],alth);
604  // %d Zeichen frei" 13 10
605  }
606  if (alth>0) // $$951008 alth-- !
607  {
608  while (alth>1)
609  {
610  fputc( kfg->FIL, dataStream );
611  --alth;
612  }
613  fputc( NL, dataStream );
614  }
615 
616  fputc(13, dataStream );
617  fputc(10, dataStream );
618 
619  return 0;
620 }
621 // Ende wrout()
622 
623 
624 // **************************************
625 // Datensatz loeschen, incl. Register etc.
626 
627 int ABASE::AwDel(RECNR recn, int md, RECORD *rec) // clear a rec, i.e. make space available
628 /* md = 2 : nur Loeschkontrolle, Result -1 : keine Loeschung
629  3 : Kontrolle + Loeschung = default
630  1 : Loeschung ohne Kontrolle
631  return: 0=record error, 1=ok, -1=loeschkontrolle/keine Berechtigung
632  -2=no rights
633  -3=rec doesnt exist
634  -4=LOG not possible
635 */
636 {
637  char w[259], nwkey[259];
638  int rc=0;
639  int k=0;
640  int l=xl;
641  xl=120;
642  xfl=52;
643  int i;
644  RECNR r0; // $$970227 SR
645  char ix=aix; // MultiX
646  if (!accf)
647  {
648  strcpy(Aerror,"no rights"); // no rights
649  return -2;
650  }
651 
652 
653 // Satz holen:
654  if (rec==(RECORD *)0) Rcu=new RECORD(kfg);
655  else Rcu=rec;
656  if (AbGet(recn, Rcu,0)<1)
657  {
658  sprintf(Aerror,"record %ld doesn't exist, can't erase %c",recn,0);
659  if (!rec) delete Rcu;
660  return -3;
661  }
662 
663  cri=Rcu->cri;
664  gri=Rcu->gri; // needed by wrout()
665  ga=Rcu->ga;
666  gend=Rcu->gend;
667  gi=Rcu->gi;
668  if (ix!='d') InSwix('d');
669  if (!s_del(recn,md))
670  {
671  if (!rec) delete Rcu;
672  return -1;
673  }
674 // Loeschkontrolle:
675  if (md & 2)
676  {
677 
678  Exp(Rcu,1,(CHAR *)"-"); // Abschnitt #-- in .API ausfuehren
679  xl=l;
680  xfl=0; // "zeilenlaenge" ruecksetzen
681  while (*ct[k]=='|') // mehrere Bedingungen moeglich
682  { // Ergebnisse stehen in ct[0], ct[1]...
683  int i=strlen((char*)ct[k]+2);
684  aiEntGe(ct[k][1]-'1'+Adn*15,(CHAR*)ct[k]+2,(CHAR*)w);
685  if (!strncmp((char *)ct[k++]+2,w,i))
686  {
687  rc=-1; // match
688  break;
689  }
690  }
691  }
692  xl=l;
693  xfl=0; // "zeilenlaenge" ruecksetzen
694  if (rc==-1 && !*Aerror) strcpy(Aerror,uif[131]);
695  if (rc)
696  {
697  if (!rec) delete Rcu; // Aerror contains message
698  return rc;
699  }
700  if (md==2)
701  {
702  if (!rec) delete Rcu;
703  return 0;
704  }
705 // .LOG-Datei schreiben
706  if (logflg)
707  { // lock TBL to prevent simultaneous write to logfile
708  if (mult)
709  if (!AwTlock())
710  {
711  sprintf(Aerror,uif[175]);
712  if (!rec) delete Rcu;
713  return 0;
714  } // "bitte warten"
715 
716  logfile = fopen( dbLog, "a+b" ); // .LOG Oeffnen
717  if (!logfile)
718  {
719  sprintf(Aerror,"K: LOG file '%s' is not available. ",dbLog);
720  if (mult) AwTunlock();
721  if (!rec) delete Rcu;
722  return -4;
723  }
724  fseek( logfile, 0L, 2 );
725  timestamp(0); // NEU 20080225
726  gri=Rcu->gri; // these may have changed in timestamp()
727  gend=Rcu->gend;
728  Rcu->rSt = 9;
729  oldrecn=Rcu->rNr; // Signal fuer wrout()
730  alth=0; // no fillers in .LOG $$951008
731  wrout( logfile, 0, 1 );
732  fclose( logfile );
733  if (mult) AwTunlock();
734  }
735 
736 // jetzt kommt erst das Loeschen:
737 
738  fwr = Openf(Rcu->rFi);
739 
740  fseek(fwr,Rcu->rOf,0);
741  fputc(9,fwr); // write 9 for 1 as 1st byte
742 
743  fclose( fwr ); // and force it to disk
744 
745 
746 // Index-Behandlung:
747 
748 // write the old keys to rKy[] :
749 
750  if (InKeyCalc(Rcu,0)==-1)
751  {
752  if (!rec) delete Rcu; // -1: out of memory
753  return 0;
754  }
755 
756  {
757  int i=0;
758  while (++i<Rcu->rKx) // mark identical keys 0 in rKf[]
759  {
760  if (!strcmp(Rcu->rKy[i],Rcu->rKy[i-1])) Rcu->rKf[i]=0;
761  }
762  }
763  k=0;
764  while (k<Rcu->rKx) // delete the keys now
765  {
766  if (Rcu->rKf[k] && *w!='\\')
767  {
768  strcpy(w,Rcu->rKy[k]);
769  pad((CHAR *)w);
770  if (w[1]!='0')
771  if (*w=='|') // MultiX
772  {
773  if (aix!='d') InSwix('d');
774  aiEntLo(w[1]-'1'+Adn*15,(CHAR*)w+2,recn);
775 // fprintf(delf,"%s.\n",(char *)w); //TEST
776  }
777  else
778  {
779  if (aix!=w[1]) InSwix(w[1]);
780  aiEntLo(w[2]-'1'+Adn*15,(CHAR*)w+3,recn);
781  }
782  ++wrfl;
783  }
784  if (*w=='\\') // $$970227 SR-Schl.
785  {
786  InSwix('d'); // MultiX
787  i=w[2]-'1';
788  r0=aiEntGe(i+Adn*15,(CHAR*)w+3,(CHAR*)nwkey);
789  if (r0)
790  {
791  sprintf(w,"|%ld%c",r0,0);
792  pad((CHAR*)w);
793  aiEntLo(i7+Adn*15,(CHAR*)w,recn); // del key "|i7|NrMainRec
794  }
795  }
796 // else if(w[1]!='0') aiEntLo(w[1]-'1'+Adn*15,(CHAR*)w+2,recn);
797  ++k;
798  }
799  strcpy(w,"//");
800  UtKitoa5(Rcu->rLg,(CHAR *)w+2); // Loeschschluessel fabrizieren
801  pad((CHAR *)w);
802 
803  InSwix('d'); // MultiX
804  aiEntIn(Adn*15,(CHAR*)w,Rcu->rNr,0);
805 // XXX Tunlock hier noetig?
806 // if(mult) Tunlock();
807 
808  if (wrfl)
809  {
810  aiCLOSE(Adn*15,filmod); // to force it all out
811  InOpen(255); // in case of index operations
812  ix_reset(); // go back to last index position
813  }
814  {
815  sprintf(Aerror,uif[183],wrfl,Rcu->rLg); // %d Schluessel geloescht, %d Bytes freigegeben
816  }
817  if (!rec) delete Rcu;
818 // fclose(delf); //test
819  return 1;
820 }
821 
822 // ********************************
823 // Satzadresse in die TBL schreiben
824 
825 void ABASE::tbl_out(int fln,RECNR rn,long rd) // write rec addr to tbl
826 // fln file#
827 // rn, rd; rec#, rec addr
828 {
829  static CHAR c1[5];
830  static RECNR r, r1, r2, r3;
831  if (rn<1L) return; // Sicherheit
832  if (!accf) return; // no rights
833 
834  lseek(dbTb,(rn-1L)*4L+2L,0);
835 // $$ii
836  if (ii>1 && rd>1L) rd=(rd-1L)/(long)ii;
837 
838 
839  r1=rd/65536L;
840  r=rd%65536L;
841  r2=r/256L;
842  r3=r%256L;
843  c1[0]=(char)fln;
844  c1[1]=(char)r1;
845  c1[2]=(char)r2;
846  c1[3]=(char)r3;
847  fln=write(dbTb,c1,4);
848 
849  close(dbTb); // make sure it goes to disk
850  dbTb=Tblopen(".tbl");
851  return;
852 }
853 
854 
855 // **********************************************
856 // Hilfsfkt. 4Byte Satznr an den Anfang des Satzes schreiben
857 void ABASE::ald_out(FILE *fwr, RECNR rn) // write 4byte rec# to data file
858 {
859  CHAR c[4];
860  UtRecn4(rn,c); // convert rec# to 4 bytes
861  fputc(c[0],fwr);
862  fputc(c[1],fwr);
863  fputc(c[2],fwr);
864  fputc(c[3],fwr);
865  return;
866 }
867 
868 
869 // **********************************************
870 // Hilfsfnkt. zum physischen Wegschreiben des Index
871 void ABASE::Opnix() // **** Open index file
872 {
873  InOpen(255); // in INDEX.CPP
874 }
875 
876 // **** Adn = log. Nr. der Datenbank, 0..4
877 void ABASE::Clsix() // Close index - flush
878 {
879  aiCLOSE(Adn*15,filmod); // to force all index stuff out
880 }
881 
882 
883 
884 // ****************************
885 // Zeitstempel + Nummernvergabe
886 void ABASE::timestamp(int md)
887 {
888  // md==1 : mit Nummernvergabe, 0:ohne (default)
889  // 1. Datumsstempel
890  // Rcu->rNr>0L : old rec after editing, update dat_e
891  // ==0L : new rec is to be stored, add dat_n
892  // 2. Nummernvergabe mittels dat_g und ind_g
893  // Nummernvergabe soll nicht nur bei neuen Saetzen
894  // gemacht werden, sondern immer wenn '?' vorkommt
895 
896  int k,l,m, indn, ok=0;
897  char a[36], kat_g[6];
898  char w[100];
899  *a=NL;
900  indn=*kfg->ind_g-'1'; // default is indn==8, for index 9
901 
902  if(!Rcu->rNr) // new record: delete kfg->dat_e (Aenderungsdatum)
903  {
904  if (!*kfg->dat_n) ;
905  else
906  {
907  *a='#';
908  strcpy(a+1,kfg->dat_n);
909  }
910  if (!*kfg->dat_e) ;
911  else
912  {
913  k=Rcu->Pos((CHAR *)kfg->dat_e);
914  Rcu->PartDel(k,k+1);
915  }
916  // kfg->dat_g contains: "|jXYZ?xyz"
917  // to generate XYZnnnnxyz in index j
918  // (arbitrary characters XYZ and xyz
919  }
920  else
921  {
922  if (!*kfg->dat_e) ;
923  else
924  {
925  *a='#';
926  strcpy(a+1,kfg->dat_e);
927  }
928  }
929 
930  strcat(a," ");
931  SyTime((CHAR *)a+kfg->skt);
932 // a[kfg->skt+kfg->DL]=0; // DL=Datumslaenge $$20120118 nicht mehr kuerzen!
933 
934 // Hier den Zeitstempel noch ergaenzen um interne Satznr u. sct $$120116
935  // nur damit er eindeutig wird!
936 // bei geaenderten Saetzen noch interne Nr und Zaehler anhaengen
937  if(Rcu->rNr) sprintf(a+strlen(a),"-%ld/%ld%c",Rcu->rNr,sct++,0);
938  if (*Optor) // Operator anhaengen als $o
939  {
940  sprintf(a+strlen(a),"%co%s%c",kfg->SF,Optor,0);
941  }
942 
943  Rcu->Ins((CHAR *)a); // Datumsfeld -> Satz
944 
945  // Nummernvergabe
946 
947  // Kategorie cg pruefen, of '?' drin vorkommt, dann Nummer ermitteln
948  if (md && *kfg->dat_g!='w') // dat_g definiert? dann beginnts nicht mit w
949  {
950  char *g, *h;
951  long nr;
952  char number[256],lastnr[256];
953  g=(char *)Rcu->Adr((CHAR *)kfg->dat_g); // Feld im aktuellen Satz belegt? g=text
954  if (g) // kfg->dat_g = "[|i][#nnn][abc][?][xyz]"
955  // |i : write number to index i
956  // #nnn : store it in field #nnn
957  // abc : use this as prefix
958  // ? : place number here, do nothing
959  // if there is no '?'
960  {
961  if (*g=='|')
962  {
963  indn=g[1]-'1';
964  g+=2;
965  }
966 
967  // kommt in dat_g ein ? vor:
968  if ((h=strchr(g,'?'))) ;
969  else return; // no '?'
970  }
971  else // Nummernfeld cg noch nicht belegt, dann ci auswerten : ciRabc?kABC
972  {
973  g=kfg->ind_g+1; // z.B. g = a?5
974  h=strchr(g,'?');
975  }
976  if (*g=='#') // beginnt Feld cg mit #? Dann soll Nummer in anderes Feld
977  {
978  ok=1;
979  strncpy(kat_g,g+1,kfg->skt-1);
980  kat_g[kfg->skt-1]=0;
981  g+=kfg->skt;
982  }
983  else strcpy(kat_g,kfg->dat_g); // kat_g = Feld, wo die Nummer hin soll
984  m=k=h-g; // h-g = Laenge des prefix, z.B . 1 bei g=a?5
985  strcpy(number,g); // number = "abc ?"
986  if (InMaxRecNr()>0L) // NEW $$000612 bei leerer Datenbank sonst Haenger
987  {
988  int nn;
989  nn=aiEntLt(indn+Adn*15,(CHAR*)number,(CHAR*)lastnr); // lastnr = "abc nnnn"
990  while (aiG_fhln && !nn) // $$000523 sonst Doppelvergabe moeglich!
991  { // $$001107 : uerr_code statt !uerr_code
992 #ifdef WIN32
993  Sleep(1000);
994 #else
995  sleep(1); //wait 1 second
996 #endif
997  nn=aiEntLt(indn+Adn*15,(CHAR*)number,(CHAR*)lastnr); // lastnr = "abc nnnn"
998  }
999  }
1000  else strcpy(lastnr,"00000000000000");
1001 // printf("lastnr=%s, g=%s, m=%d\n",lastnr,g,m);
1002  if(!strncmp(lastnr,g,m)) // prefix identisch?
1003  nr=atol(lastnr+k)+1L; // dann +1
1004  else nr=1L; // sonst Wert 1
1005  if (isdigit(h[1])) // bei h+1 (hinter ?) steht Laenge der Nummer
1006  {
1007  l=h[1]-'0';
1008  ++m;
1009  }
1010  else l=0; // keine Ziffer, dann 6stellig
1011 // sprintf(w,"teststring in w"); // raetselhaft, ohne dies geht's nicht!
1012 // printf("\nkat_g=%s, k=%d, g=%s, l=%d, nr=%ld, m=%d, g+m+1=%s\n",kat_g,k,g,l,nr,m,g+m+1);
1013  sprintf(w,"#%s %.*s%0*ld%s%c",kat_g,k,g,l,nr,g+m+1,'\0');
1014 // printf("\n w=%s\n",w);
1015  Rcu->Ins((CHAR *)w); // delete #kfg->dat_g
1016  if (ok)
1017  {
1018  ok=Rcu->Pos((CHAR *)kfg->dat_g);
1019  Rcu->PartDel(ok,ok+1);
1020  }
1021  }
1022  return;
1023 }
1024 
1025 // *************************** Satzsperre setzen bzw. checken
1026 // 1. Satz sperren: (mo == 0, default, 1:nur checken)
1027 // Return: 0 = OK, hat geklappt
1028 // -1 = geht nicht (TBL gesperrt)
1029 // -2 = .TBL-Eintrag falsch
1030 // -3 = .ALD-Datei oeffnet nicht
1031 // -4 = Falsches Byte am Satzbeginn
1032 // -6 = Keine Schreibberechtigung
1033 // -8 = Satznummer <0 oder zu gross
1034 // 1 = Satz ist nicht gesperrt (nur bei mo==1)
1035 // 8 = Satz ist schon gesperrt
1036 // 9 = Satz ist geloescht
1037 // Diese Zahl wird ausserdem in Aerror geschrieben: z.B. "Stat -3"
1038 // Im Job dann so: set lock #1 \ if yes jump ... \ var sL\if "-1" ... usw.
1039 
1040 // 2. Abfragen (md == 1)
1041 // Return: 1 = hat geklappt
1042 // 0 = nicht gekl.
1043 // Im Job am besten so: if Lock #1 \ if yes ... \ var sL \if "-2" ...
1044 // Der Wert sL steht in der glob. Variablen Alock
1045 
1046 
1047 int ABASE::AwRecLock(RECNR recn, int mo)
1048 // mo : modus operandi
1049 // =0: default, Satz mit Nr. recn sperren (Satz selbst muss nicht geladen sein!)
1050 // =1: nur Sperre pruefen, dann return 1:ist gesperrt, 0:alles andere
1051 {
1052  int hALD;
1053  CHAR w[2];
1054  int Fi;
1055  long rof; // offset
1056  int tt=10; // max tt Sekunden warten
1057  Alock=0;
1058 // printf("recn=%ld\n",recn);
1059  if (!recn) return 0; // Satz 0 geht nicht; Neusatz! Kein Fehler
1060  if (recn<0L) { Alock=-8; return -8; } // Satz <0 geht nicht; Fehler
1061 
1062 // printf("locking tbl\n");
1063 
1064  if(!mo) if(!AwTlock()) { Alock=-1; return -1; } // TBL kann nicht gesperrt werden
1065 
1066 // printf("TBL is locked\n");
1067 
1068  do
1069  {
1070  if ((Fi=AbRecAdr(recn, rof))<1) { if (!mo) AwTunlock(); Alock=-2; return -2; }
1071  if ((hALD = OpenALD(Fi))==EOF) { if (!mo) AwTunlock(); Alock=-3; return -3; }
1072  lseek(hALD ,rof,0);
1073  read(hALD ,w,1); // erstes Byte des Satzes lesen
1074 
1075  sprintf(Aerror,"Stat %d",*w); // das Byte in Aerror hinterlegen
1076  Alock=*w; // Den Wert des Statusbytes kopieren (in FLEX mit var sL auswerten)
1077  switch (*w)
1078  {
1079 
1080  case 1: // ok, record is not locked
1081  if(mo) return 1; // if Lock: no
1082  tt=-2;
1083  break;
1084 
1085  case 8: // record is already locked
1086  close(hALD);
1087  if(mo) return 8; // if Lock: yes
1088 #ifdef WIN32
1089  Sleep(1000);
1090 #else
1091  sleep(1); //wait 1 second
1092 #endif
1093  break;
1094 
1095  case 9: // record is deleted, not lockable
1096  close(hALD);
1097  if(mo) return 0;
1098  AwTunlock();
1099  return 9;
1100 
1101  default: // unexpected byte
1102  close(hALD);
1103  { if(!mo) AwTunlock(); Alock=-4; return -4; } // $$20120503 statt -1
1104  }
1105 // if(tt) fprintf(stderr,"Satz %ld gesperrt, bitte warten oder freigeben, *w=%c, tt=%d\n",recn,*w,tt);
1106  }
1107  while (*w==8 && (tt--)>0); // wait loop : until record will be free
1108  Alock=*w;
1109  AwTunlock();
1110 //printf("UNLOCK: Alock=%d, tt=%d\n",Alock,tt);
1111  if (tt<1 && *w==8) { close(hALD); return 8; } // is still locked
1112 //printf("Now do the actual locking\n");
1113 
1114  lseek(hALD,rof,0);
1115 
1116 // $$980206 ve: Funktion um das Datei-Locking ergaenzt
1117 // $$091125 ev: wieder raus damit, unnoetig
1118  /*
1119  #ifdef WIN32
1120  if( _locking( hALD, LK_NBLCK, 1L ) != -1 )
1121  { // }
1122  #else
1123  if( lock( hALD,rof, 1L ) != -1 )
1124  {
1125  #endif
1126  */
1127  *w=8;
1128  tt=write(hALD,w,1); // 8 means 'locked'
1129  /*
1130  #ifdef WIN32
1131  lseek(hALD,rof,0);
1132  _locking( hALD, LK_UNLCK, 1L );
1133  #else
1134  unlock( hALD, rof, 1L );
1135  #endif
1136  }
1137  else { close(hALD); return 8; } // Keine Locksperre möglich
1138  */
1139  close( hALD );
1140 // printf("unlock: Alock=%d, tt=%d\n",Alock,tt);
1141  if(tt<1) { Alock=-3; return -3; } // no write
1142  if(Alock==9) return 9;
1143  Alock=0;
1144 // printf("unLock: Alock=%d, tt=%d\n",Alock,tt);
1145  return 0; // ok
1146 } // ENDE AwReckLock()
1147 
1148 
1149 
1150 // ************** UnLock : Satzfreigabe
1151 // $$980206 ve: Funktion um das Datei-Locking ergaenzt
1152 // $$091125 ev: wieder raus damit
1153 // return <0 bei Dateifehlern, 0 == OK, anderer Wert, falls nicht gesperrt
1154 
1155 int ABASE::AwRecUnlk(RECNR recn) // unlock current rec
1156 {
1157 
1158  int hALD;
1159  CHAR w[2];
1160  int Fi;
1161  long rof; // offset
1162  if (recn<1L) { Alock=-1; return -1; } // Satz 0 geht nicht;
1163  if ((Fi=AbRecAdr(recn, rof))<1) { Alock=-2; return -2; }
1164  if ((hALD = OpenALD(Fi))==EOF) { Alock=-3; return -3; }
1165  lseek(hALD ,rof,0);
1166  read(hALD ,w,1);
1167 // $$001022 : NUR schreiben, wenn da 8 steht!
1168  if (*w!=8)
1169  {
1170  close(hALD);
1171  Alock=*w;
1172  return (int)*w;
1173  }
1174  // was not locked or is deleted
1175  lseek(hALD,rof,0);
1176  /*
1177  #ifdef WIN32
1178  if( _locking( hALD, LK_NBLCK, 1L ) != -1 ) {
1179  #else
1180  if( lock( hALD,rof, 1L ) != -1 ) {
1181  #endif
1182  */
1183  *w=1;
1184  if(write(hALD,w,1)<1) { Alock=-1; return -1; } // 1 means 'unlocked'
1185  /*
1186  #ifdef WIN32
1187  lseek(hALD,rof,0);
1188  _locking( hALD, LK_UNLCK, 1L );
1189  #else
1190  unlock( hALD, rof, 1L );
1191  #endif
1192  }
1193  else { close(hALD); return -1; } // Keine Locksperre möglich
1194  */
1195  close( hALD );
1196  Alock=0;
1197  return 0; // ok
1198 }
1199 
1200 // Open a database file for read/write access
1201 
1202 FILE *ABASE::Openf(int fnr) // open file_fnr.ALD
1203 {
1204  FILE *wrf; // $$970922 NEU: wenn r+b nicht geht: w+b versuchen
1205  sprintf(dbFNum,"%d.%cld%c",fnr,kfg->schema,0);
1206  wrf=fopen(dbFn,"r+b");
1207  if (!wrf) wrf=fopen(dbFn,"w+b");
1208  return wrf;
1209 }
1210 
1211 
1212 // $$980206 ve: neue Funktion: .ALD als Handle oeffnen (fuer Datei-Locking)
1213 
1214 int ABASE::OpenALD(int fnr)
1215 {
1216  int i=EOF;
1217  sprintf(dbFNum,"%d.%cld%c",fnr,kfg->schema,0);
1218 #ifndef UNIX
1219  i=sopen(dbFn,filmod,shflag,S_IREAD|S_IWRITE); // lesen + schreiben
1220 #else
1221  i=open(dbFn,filmod | shflag,S_IREAD|S_IWRITE); // lesen +schreiben
1222 #endif
1223  if (i==EOF) sprintf(Aerror,"%s cannot be opened%c",dbFn,0);
1224  return i;
1225 }
1226 
1227 /*
1228  Copyright 2011 Universitätsbibliothek Braunschweig
1229 
1230  Licensed under the Apache License, Version 2.0 (the "License");
1231  you may not use this file except in compliance with the License.
1232  You may obtain a copy of the License at
1233 
1234  http://www.apache.org/licenses/LICENSE-2.0
1235 
1236  Unless required by applicable law or agreed to in writing, software
1237  distributed under the License is distributed on an "AS IS" BASIS,
1238  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1239  See the License for the specific language governing permissions and
1240  limitations under the License.
1241 */
1242