FORM v5.0.1-33-gdf7fc94
minos.c
Go to the documentation of this file.
1
7/* #[ License : */
8/*
9 * Copyright (C) 1984-2026 J.A.M. Vermaseren
10 * When using this file you are requested to refer to the publication
11 * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
12 * This is considered a matter of courtesy as the development was paid
13 * for by FOM the Dutch physics granting agency and we would like to
14 * be able to track its scientific use to convince FOM of its value
15 * for the community.
16 *
17 * This file is part of FORM.
18 *
19 * FORM is free software: you can redistribute it and/or modify it under the
20 * terms of the GNU General Public License as published by the Free Software
21 * Foundation, either version 3 of the License, or (at your option) any later
22 * version.
23 *
24 * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
25 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
26 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
27 * details.
28 *
29 * You should have received a copy of the GNU General Public License along
30 * with FORM. If not, see <http://www.gnu.org/licenses/>.
31 */
32/* #] License : */
33/*
34 #[ Includes :
35
36 File contains the lowlevel routines for the management of primitive
37 database-like files. The structures are explained in the file manage.h
38 Original file for minos made by J.Vermaseren, april-1994.
39
40 Note: the minos primitives for writing are never invoked in parallel.
41*/
42
43#include "form3.h"
44#include "minos.h"
45int withoutflush = 0;
46
47/*
48 #] Includes :
49 #[ Variables :
50*/
51
52static INDEXBLOCK scratchblock;
53static NAMESBLOCK scratchnamesblock;
54
55#define CFD(y,s,type,x,j) for(x=0,j=0;j<((int)sizeof(type));j++) \
56 {x=(x<<8)+((*s++)&0x00FF);} y=x;
57#define CTD(y,s,type,x,j) x=y;for(j=sizeof(type)-1;j>=0;j--){s[j]=x&0xFF; \
58 x>>=8;} s += sizeof(type);
59
60/*
61 #] Variables :
62 #[ Utilities :
63 #[ minosread :
64*/
65
66int minosread(FILE *f,char *buffer,MLONG size)
67{
68 MLONG x;
69 while ( size > 0 ) {
70 x = fread(buffer,sizeof(char),size,f);
71 if ( x <= 0 ) return(-1);
72 buffer += x;
73 size -= x;
74 }
75 return(0);
76}
77
78/*
79 #] minosread :
80 #[ minoswrite :
81*/
82
83int minoswrite(FILE *f,char *buffer,MLONG size)
84{
85 MLONG x;
86 while ( size > 0 ) {
87 x = fwrite(buffer,sizeof(char),size,f);
88 if ( x <= 0 ) return(-1);
89 buffer += x;
90 size -= x;
91 }
92 if ( withoutflush == 0 ) fflush(f);
93 return(0);
94}
95
96/*
97 #] minoswrite :
98 #[ str_dup :
99*/
100
101char *str_dup(char *str)
102{
103 char *s, *t;
104 int i;
105 s = str;
106 while ( *s ) s++;
107 i = s - str + 1;
108 if ( ( s = (char *)Malloc1((size_t)i,"a string copy") ) == 0 ) return(0);
109 t = s;
110 while ( *str ) *t++ = *str++;
111 *t = 0;
112 return(s);
113}
114
115/*
116 #] str_dup :
117 #[ convertblock :
118*/
119
120void convertblock(INDEXBLOCK *in,INDEXBLOCK *out,int mode)
121{
122 char *s,*t;
123 MLONG i, x;
124 int j;
125 OBJECTS *obj;
126 switch ( mode ) {
127 case TODISK:
128 s = (char *)out;
129 CTD(in->flags,s,MLONG,x,j)
130 CTD(in->previousblock,s,MLONG,x,j)
131 CTD(in->position,s,MLONG,x,j)
132 for ( i = 0, obj = in->objects; i < NUMOBJECTS; i++, obj++ ) {
133 CTD(obj->position,s,MLONG,x,j)
134 CTD(obj->size,s,MLONG,x,j)
135 CTD(obj->date,s,MLONG,x,j)
136 CTD(obj->tablenumber,s,MLONG,x,j)
137 CTD(obj->uncompressed,s,MLONG,x,j)
138 CTD(obj->spare1,s,MLONG,x,j)
139 CTD(obj->spare2,s,MLONG,x,j)
140 CTD(obj->spare3,s,MLONG,x,j)
141 t = obj->element;
142 for ( j = 0; j < ELEMENTSIZE; j++ ) *s++ = *t++;
143 }
144 break;
145 case FROMDISK:
146 s = (char *)in;
147 CFD(out->flags,s,MLONG,x,j)
148 CFD(out->previousblock,s,MLONG,x,j)
149 CFD(out->position,s,MLONG,x,j)
150 for ( i = 0, obj = out->objects; i < NUMOBJECTS; i++, obj++ ) {
151 CFD(obj->position,s,MLONG,x,j)
152 CFD(obj->size,s,MLONG,x,j)
153 CFD(obj->date,s,MLONG,x,j)
154 CFD(obj->tablenumber,s,MLONG,x,j)
155 CFD(obj->uncompressed,s,MLONG,x,j)
156 CFD(obj->spare1,s,MLONG,x,j)
157 CFD(obj->spare2,s,MLONG,x,j)
158 CFD(obj->spare3,s,MLONG,x,j)
159 t = obj->element;
160 for ( j = 0; j < ELEMENTSIZE; j++ ) *t++ = *s++;
161 }
162 break;
163 }
164}
165
166/*
167 #] convertblock :
168 #[ convertnamesblock :
169*/
170
171void convertnamesblock(NAMESBLOCK *in,NAMESBLOCK *out,int mode)
172{
173 char *s;
174 MLONG x;
175 int j;
176 switch ( mode ) {
177 case TODISK:
178 s = (char *)out;
179 CTD(in->previousblock,s,MLONG,x,j)
180 CTD(in->position,s,MLONG,x,j)
181 for ( j = 0; j < NAMETABLESIZE; j++ ) out->names[j] = in->names[j];
182 break;
183 case FROMDISK:
184 s = (char *)in;
185 CFD(out->previousblock,s,MLONG,x,j)
186 CFD(out->position,s,MLONG,x,j)
187 for ( j = 0; j < NAMETABLESIZE; j++ ) out->names[j] = in->names[j];
188 break;
189 }
190}
191
192/*
193 #] convertnamesblock :
194 #[ convertiniinfo :
195*/
196
197void convertiniinfo(INIINFO *in,INIINFO *out,int mode)
198{
199 char *s;
200 MLONG i, x, *y;
201 int j;
202 switch ( mode ) {
203 case TODISK:
204 s = (char *)out; y = (MLONG *)in;
205 for ( i = sizeof(INIINFO)/sizeof(MLONG); i > 0; i-- ) {
206 CTD(*y,s,MLONG,x,j)
207 y++;
208 }
209 break;
210 case FROMDISK:
211 s = (char *)in; y = (MLONG *)out;
212 for ( i = sizeof(INIINFO)/sizeof(MLONG); i > 0; i-- ) {
213 CFD(*y,s,MLONG,x,j)
214 y++;
215 }
216 break;
217 }
218}
219
220/*
221 #] convertiniinfo :
222 #[ LocateBase :
223*/
224
225FILE *LocateBase(char **name, char **newname, char *iomode)
226{
227 FILE *handle;
228 int namesize, i;
229 UBYTE *s, *to, *u1, *u2, *indir;
230
231 if ( ( handle = fopen(*name,iomode) ) != 0 ) {
232 *newname = (char *)strDup1((UBYTE *)(*name),"LocateBase");
233 return(handle);
234 }
235 namesize = 2; s = (UBYTE *)(*name);
236 while ( *s ) { s++; namesize++; }
237 indir = AM.IncDir;
238 if ( indir ) {
239 s = indir; i = 0;
240 while ( *s ) { s++; i++; }
241 *newname = (char *)Malloc1(namesize+i,"LocateBase");
242 s = indir; to = (UBYTE *)(*newname);
243 while ( *s ) *to++ = *s++;
244 if ( to > (UBYTE *)(*newname) && to[-1] != SEPARATOR ) *to++ = SEPARATOR;
245 s = (UBYTE *)(*name);
246 while ( *s ) *to++ = *s++;
247 *to = 0;
248 if ( ( handle = fopen(*newname,iomode) ) != 0 ) {
249 return(handle);
250 }
251 M_free(*newname,"LocateBase, incdir/file");
252 }
253 if ( AM.Path ) {
254 u1 = AM.Path;
255 while ( *u1 ) {
256 u2 = u1; i = 0;
257 while ( *u1 && *u1 != ':' ) {
258 if ( *u1 == '\\' ) u1++;
259 u1++; i++;
260 }
261 *newname = (char *)Malloc1(namesize+i,"LocateBase");
262 s = u2; to = (UBYTE *)(*newname);
263 while ( s < u1 ) {
264 if ( *s == '\\' ) s++;
265 *to++ = *s++;
266 }
267 if ( to > (UBYTE *)(*newname) && to[-1] != SEPARATOR ) *to++ = SEPARATOR;
268 s = (UBYTE *)(*name);
269 while ( *s ) *to++ = *s++;
270 *to = 0;
271 if ( ( handle = fopen(*newname,iomode) ) != 0 ) {
272 return(handle);
273 }
274 M_free(*newname,"LocateBase Path/file");
275 if ( *u1 ) u1++;
276 }
277 }
278/* Error1("LocateBase: Cannot find file",*name); */
279 return(0);
280}
281
282/*
283 #] LocateBase :
284 #] Utilities :
285 #[ ReadIndex :
286*/
287
288int ReadIndex(DBASE *d)
289{
290 MLONG i;
291 INDEXBLOCK **ib;
292 NAMESBLOCK **ina;
293 MLONG position, size;
294/*
295 Allocate the pieces one by one (makes it easier to give it back)
296*/
297 if ( d->info.numberofindexblocks <= 0 ) return(0);
298 if ( sizeof(INDEXBLOCK)*d->info.numberofindexblocks > MAXINDEXSIZE ) {
299/* INTERNAL_ERROR_EXCL_START */
300 MesPrint("!>We need more than %ld bytes for the index.\n",MAXINDEXSIZE);
301 MesPrint("The file %s may not be a proper database\n",d->name);
302 return(-1);
303/* INTERNAL_ERROR_EXCL_STOP */
304 }
305 size = sizeof(INDEXBLOCK *)*d->info.numberofindexblocks;
306 if ( ( ib = (INDEXBLOCK **)Malloc1(size,"tb,index") ) == 0 ) return(-1);
307 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
308 if ( ( ib[i] = (INDEXBLOCK *)Malloc1(sizeof(INDEXBLOCK),"index block") ) == 0 ) {
309 for ( --i; i >= 0; i-- ) M_free(ib[i],"tb,indexblock");
310 M_free(ib,"tb,index");
311 return(-1);
312 }
313 }
314 size = sizeof(NAMESBLOCK *)*d->info.numberofnamesblocks;
315 if ( ( ina = (NAMESBLOCK **)Malloc1(size,"tb,indexnames") ) == 0 ) return(-1);
316 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
317 if ( ( ina[i] = (NAMESBLOCK *)Malloc1(sizeof(NAMESBLOCK),"index names block") ) == 0 ) {
318 for ( --i; i >= 0; i-- ) M_free(ina[i],"index names block");
319 M_free(ina,"tb,indexnames");
320 for ( i = 0; i < d->info.numberofindexblocks; i++ ) M_free(ib[i],"tb,indexblock");
321 M_free(ib,"tb,index");
322 return(-1);
323 }
324 }
325/*
326 Read the index blocks, from the back to the front. The links are only
327 reliable that way.
328*/
329 position = d->info.lastindexblock;
330 for ( i = d->info.numberofindexblocks - 1; i >= 0; i-- ) {
331 fseek(d->handle,position,SEEK_SET);
332 if ( minosread(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
333/* INTERNAL_ERROR_EXCL_START */
334 MesPrint("!>Error while reading file %s\n",d->name);
335thisiswrong:
336 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) M_free(ina[i],"index names block");
337 M_free(ina,"tb,indexnames");
338 for ( i = 0; i < d->info.numberofindexblocks; i++ ) M_free(ib[i],"tb,indexblock");
339 M_free(ib,"tb,index");
340 return(-1);
341/* INTERNAL_ERROR_EXCL_STOP */
342 }
343 convertblock(&scratchblock,ib[i],FROMDISK);
344 if ( ib[i]->position != position ||
345 ( ib[i]->previousblock <= 0 && i > 0 ) ) {
346/* INTERNAL_ERROR_EXCL_START */
347 MesPrint("!>File %s has inconsistent contents\n",d->name);
348 goto thisiswrong;
349/* INTERNAL_ERROR_EXCL_STOP */
350 }
351 position = ib[i]->previousblock;
352 }
353 d->info.firstindexblock = ib[0]->position;
354 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
355 ib[i]->flags &= MCLEANFLAG;
356 }
357/*
358 Read the names blocks, from the back to the front. The links are only
359 reliable that way.
360*/
361 position = d->info.lastnameblock;
362 for ( i = d->info.numberofnamesblocks - 1; i >= 0; i-- ) {
363 fseek(d->handle,position,SEEK_SET);
364 if ( minosread(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
365/* INTERNAL_ERROR_EXCL_START */
366 MesPrint("!>Error while reading file %s\n",d->name);
367 goto thisiswrong;
368/* INTERNAL_ERROR_EXCL_STOP */
369 }
370 convertnamesblock(&scratchnamesblock,ina[i],FROMDISK);
371 if ( ina[i]->position != position ||
372 ( ina[i]->previousblock <= 0 && i > 0 ) ) {
373/* INTERNAL_ERROR_EXCL_START */
374 MesPrint("!>File %s has inconsistent contents\n",d->name);
375 goto thisiswrong;
376/* INTERNAL_ERROR_EXCL_STOP */
377 }
378 position = ina[i]->previousblock;
379 }
380 d->info.firstnameblock = ina[0]->position;
381/*
382 Give the old info back to the system.
383*/
384 if ( d->iblocks ) {
385 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
386 if ( d->iblocks[i] ) M_free(d->iblocks[i],"d->iblocks[i]");
387 }
388 M_free(d->iblocks,"d->iblocks");
389 }
390 if ( d->nblocks ) {
391 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
392 if ( d->nblocks[i] ) M_free(d->nblocks[i],"d->nblocks[i]");
393 }
394 M_free(d->nblocks,"d->nblocks");
395 }
396/*
397 And substitute the new blocks
398*/
399 d->iblocks = ib;
400 d->nblocks = ina;
401 return(0);
402}
403
404/*
405 #] ReadIndex :
406 #[ WriteIndexBlock :
407*/
408
409int WriteIndexBlock(DBASE *d,MLONG num)
410{
411 if ( num >= d->info.numberofindexblocks ) {
412/* INTERNAL_ERROR_EXCL_START */
413 MesPrint("!>Illegal number specified for number of index blocks\n");
414 return(-1);
415/* INTERNAL_ERROR_EXCL_STOP */
416 }
417 fseek(d->handle,d->iblocks[num]->position,SEEK_SET);
418 convertblock(d->iblocks[num],&scratchblock,TODISK);
419 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
420/* INTERNAL_ERROR_EXCL_START */
421 MesPrint("!>Error while writing an index block in file %s\n",d->name);
422 MesPrint("File may be unreliable now\n");
423 return(-1);
424/* INTERNAL_ERROR_EXCL_STOP */
425 }
426 return(0);
427}
428
429/*
430 #] WriteIndexBlock :
431 #[ WriteNamesBlock :
432*/
433
434int WriteNamesBlock(DBASE *d,MLONG num)
435{
436 if ( num >= d->info.numberofnamesblocks ) {
437/* INTERNAL_ERROR_EXCL_START */
438 MesPrint("!>Illegal number specified for number of names blocks\n");
439 return(-1);
440/* INTERNAL_ERROR_EXCL_STOP */
441 }
442 fseek(d->handle,d->nblocks[num]->position,SEEK_SET);
443 convertnamesblock(d->nblocks[num],&scratchnamesblock,TODISK);
444 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
445/* INTERNAL_ERROR_EXCL_START */
446 MesPrint("!>Error while writing a names block in file %s\n",d->name);
447 MesPrint("File may be unreliable now\n");
448 return(-1);
449/* INTERNAL_ERROR_EXCL_STOP */
450 }
451 return(0);
452}
453
454/*
455 #] WriteNamesBlock :
456 #[ WriteIndex :
457
458 Problem here is to get the links right.
459*/
460
461int WriteIndex(DBASE *d)
462{
463 MLONG i, position;
464 if ( d->iblocks == 0 ) return(0);
465 if ( d->nblocks == 0 ) return(0);
466 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
467 if ( d->iblocks[i] == 0 ) {
468/* INTERNAL_ERROR_EXCL_START */
469 MesPrint("!>Error: unassigned index blocks. Cannot write\n");
470 return(-1);
471/* INTERNAL_ERROR_EXCL_STOP */
472 }
473 }
474 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
475 if ( d->nblocks[i] == 0 ) {
476/* INTERNAL_ERROR_EXCL_START */
477 MesPrint("!>Error: unassigned names blocks. Cannot write\n");
478 return(-1);
479/* INTERNAL_ERROR_EXCL_STOP */
480 }
481 }
482 d->info.lastindexblock = -1;
483 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
484 position = d->iblocks[i]->position;
485 if ( position <= 0 ) {
486 fseek(d->handle,0,SEEK_END);
487 position = ftell(d->handle);
488 d->iblocks[i]->position = position;
489 if ( i <= 0 ) d->iblocks[i]->previousblock = -1;
490 else d->iblocks[i]->previousblock = d->iblocks[i-1]->position;
491 }
492 else fseek(d->handle,position,SEEK_SET);
493 convertblock(d->iblocks[i],&scratchblock,TODISK);
494 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
495/* INTERNAL_ERROR_EXCL_START */
496 MesPrint("!>Error while writing index of file %s",d->name);
497 d->iblocks[i]->position = -1;
498 return(-1);
499/* INTERNAL_ERROR_EXCL_STOP */
500 }
501 d->info.lastindexblock = position;
502 }
503 d->info.lastnameblock = -1;
504 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
505 position = d->nblocks[i]->position;
506 if ( position <= 0 ) {
507 fseek(d->handle,0,SEEK_END);
508 position = ftell(d->handle);
509 d->nblocks[i]->position = position;
510 if ( i <= 0 ) d->nblocks[i]->previousblock = -1;
511 else d->nblocks[i]->previousblock = d->nblocks[i-1]->position;
512 }
513 else fseek(d->handle,position,SEEK_SET);
514 convertnamesblock(d->nblocks[i],&scratchnamesblock,TODISK);
515 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
516/* INTERNAL_ERROR_EXCL_START */
517 MesPrint("!>Error while writing index of file %s",d->name);
518 d->nblocks[i]->position = -1;
519 return(-1);
520/* INTERNAL_ERROR_EXCL_STOP */
521 }
522 d->info.lastnameblock = position;
523 }
524 return(0);
525}
526
527/*
528 #] WriteIndex :
529 #[ WriteIniInfo :
530*/
531
532int WriteIniInfo(DBASE *d)
533{
534 INIINFO inf;
535 fseek(d->handle,0,SEEK_SET);
536 convertiniinfo(&(d->info),&inf,TODISK);
537 if ( minoswrite(d->handle,(char *)(&inf),sizeof(INIINFO)) ) {
538/* INTERNAL_ERROR_EXCL_START */
539 MesPrint("!>Error while writing masterindex of file %s",d->name);
540 return(-1);
541/* INTERNAL_ERROR_EXCL_STOP */
542 }
543 return(0);
544}
545
546/*
547 #] WriteIniInfo :
548 #[ ReadIniInfo :
549*/
550
551int ReadIniInfo(DBASE *d)
552{
553 INIINFO inf;
554 fseek(d->handle,0,SEEK_SET);
555 if ( minosread(d->handle,(char *)(&inf),sizeof(INIINFO)) ) {
556/* INTERNAL_ERROR_EXCL_START */
557 MesPrint("!>Error while reading masterindex of file %s",d->name);
558 return(-1);
559/* INTERNAL_ERROR_EXCL_STOP */
560 }
561 convertiniinfo(&inf,&(d->info),FROMDISK);
562 if ( d->info.entriesinindex < 0
563 || d->info.numberofindexblocks < 0
564 || d->info.lastindexblock < 0 ) {
565/* INTERNAL_ERROR_EXCL_START */
566 MesPrint("!>The file %s is not a proper database\n",d->name);
567 return(-1);
568/* INTERNAL_ERROR_EXCL_STOP */
569 }
570 return(0);
571}
572
573/*
574 #] ReadIniInfo :
575 #[ GetDbase :
576*/
577
578DBASE *GetDbase(char *filename, MLONG rwmode)
579{
580 FILE *f;
581 DBASE *d;
582 char *newname;
583 if ( rwmode == 0 ) {
584 if ( ( f = LocateBase(&filename,&newname,"rb") ) == 0 ) {
585
586 MesPrint("&Trying to open non-existent TableBase in readonly mode: %s", filename);
587 Terminate(-1);
588 }
589 } else {
590 if ( ( f = LocateBase(&filename,&newname,"r+b") ) == 0 ) {
591
592 return(NewDbase(filename,0));
593 }
594 }
595
596/* setbuf(f,0); */
597 d = (DBASE *)From0List(&(AC.TableBaseList));
598 d->mode = 0;
599 d->tablenamessize = 0;
600 d->topnumber = 0;
601 d->tablenamefill = 0;
602 d->iblocks = 0;
603 d->nblocks = 0;
604 d->tablenames = 0;
605 d->rwmode = rwmode;
606
607 d->info.entriesinindex = 0;
608 d->info.numberofindexblocks = 0;
609 d->info.firstindexblock = 0;
610 d->info.lastindexblock = 0;
611 d->info.numberoftables = 0;
612 d->info.numberofnamesblocks = 0;
613 d->info.firstnameblock = 0;
614 d->info.lastnameblock = 0;
615
616 d->name = str_dup(filename); /* For the moment just for the error messages */
617 d->handle = f;
618 if ( ReadIniInfo(d) || ReadIndex(d) ) { M_free(d,"index-d"); fclose(f); return(0); }
619 if ( ComposeTableNames(d) < 0 ) { FreeTableBase(d); fclose(f); return(0); }
620 // free allocation from previous str_dup
621 M_free(d->name, "from str_dup");
622 d->name = str_dup(filename);
623 d->fullname = newname;
624 return(d);
625}
626
627/*
628 #] GetDbase :
629 #[ NewDbase :
630
631 Creates a new database with 'number' entries in the index.
632*/
633
634DBASE *NewDbase(char *name,MLONG number)
635{
636 FILE *f;
637 DBASE *d;
638 MLONG numblocks, numnameblocks, i;
639 char *s;
640/*----------change 10-feb-2003 */
641 int j, jj;
642 MLONG t = (MLONG)(time(0));
643/*-----------------------------*/
644 if ( number < 0 ) number = 0;
645 if ( ( f = fopen(name,"w+b") ) == 0 ) {
646 MesPrint("Could not create a new file with name %s\n",name);
647 return(0);
648 }
649 numblocks = (number+NUMOBJECTS-1)/NUMOBJECTS;
650 numnameblocks = 1;
651 if ( numblocks <= 0 ) numblocks = 1;
652 if ( numnameblocks <= 0 ) numnameblocks = 1;
653 d = (DBASE *)From0List(&(AC.TableBaseList));
654 if ( ( d->iblocks = (INDEXBLOCK **)Malloc1(numblocks*sizeof(INDEXBLOCK *),
655 "new database") ) == 0 ) {
656 NumTableBases--;
657 fclose(f);
658 return(0);
659 }
660 d->tablenames = 0;
661 d->tablenamessize = 0;
662 d->topnumber = 0;
663 d->tablenamefill = 0;
664 d->rwmode = 1;
665
666 d->mode = 0;
667 if ( ( d->nblocks = (NAMESBLOCK **)Malloc1(sizeof(NAMESBLOCK *)*numnameblocks,
668 "new database") ) == 0 ) {
669 M_free(d->iblocks,"new database");
670 NumTableBases--;
671 fclose(f);
672 return(0);
673 }
674 if ( ( f = fopen(name,"w+b") ) == 0 ) {
675 MesPrint("Could not create new file %s\n",name);
676 NumTableBases--;
677 return(0);
678 }
679/* setbuf(f,0); */
680 d->name = str_dup(name);
681 d->fullname = str_dup(name);
682 d->handle = f;
683
684 d->info.entriesinindex = number;
685 d->info.numberofindexblocks = numblocks;
686 d->info.numberofnamesblocks = numnameblocks;
687 d->info.firstindexblock = 0;
688 d->info.lastindexblock = 0;
689 d->info.numberoftables = 0;
690 d->info.firstnameblock = 0;
691 d->info.lastnameblock = 0;
692
693 if ( WriteIniInfo(d) ) {
694getout:
695/* INTERNAL_ERROR_EXCL_START */
696 fclose(f);
697 remove(d->fullname);
698 if ( d->name ) { M_free(d->name,"name tablebase"); d->name = 0; }
699 if ( d->fullname ) { M_free(d->fullname,"fullname tablebase"); d->fullname = 0; }
700 M_free(d->nblocks,"new database");
701 M_free(d->iblocks,"new database");
702 NumTableBases--;
703 return(0);
704/* INTERNAL_ERROR_EXCL_STOP */
705 }
706 for ( i = 0; i < numblocks; i++ ) {
707 if ( ( d->iblocks[i] = (INDEXBLOCK *)Malloc1(sizeof(INDEXBLOCK),
708 "index blocks of new database") ) == 0 ) {
709/* INTERNAL_ERROR_EXCL_START */
710 while ( --i >= 0 ) M_free(d->iblocks[i],"index blocks of new database");
711 goto getout;
712/* INTERNAL_ERROR_EXCL_STOP */
713 }
714 if ( i > 0 ) d->iblocks[i]->previousblock = d->iblocks[i-1]->position;
715 else d->iblocks[i]->previousblock = -1;
716 d->iblocks[i]->position = ftell(f);
717 // Initialise, to keep valgrind happy
718 d->iblocks[i]->flags = -1;
719/*----------change 10-feb-2003 */
720/*
721 Zero things properly. We don't want garbage in the file.
722*/
723 for ( j = 0; j < NUMOBJECTS; j++ ) {
724 d->iblocks[i]->objects[j].date = t;
725 d->iblocks[i]->objects[j].size = 0;
726 d->iblocks[i]->objects[j].position = -1;
727 d->iblocks[i]->objects[j].tablenumber = 0;
728 d->iblocks[i]->objects[j].uncompressed = 0;
729 d->iblocks[i]->objects[j].spare1 = 0;
730 d->iblocks[i]->objects[j].spare2 = 0;
731 d->iblocks[i]->objects[j].spare3 = 0;
732 for ( jj = 0; jj < ELEMENTSIZE; jj++ ) d->iblocks[i]->objects[j].element[jj] = 0;
733 }
734 convertblock(d->iblocks[i],&scratchblock,TODISK);
735 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
736/* INTERNAL_ERROR_EXCL_START */
737 MesPrint("!>Error while writing new index blocks\n");
738 goto getout;
739/* INTERNAL_ERROR_EXCL_STOP */
740 }
741 }
742 for ( i = 0; i < numnameblocks; i++ ) {
743 if ( ( d->nblocks[i] = (NAMESBLOCK *)Malloc1(sizeof(NAMESBLOCK),
744 "names blocks of new database") ) == 0 ) {
745 while ( --i >= 0 ) { M_free(d->nblocks[i],"names blocks of new database"); }
746 for ( i = 0; i < numblocks; i++ ) M_free(d->iblocks[i],"index blocks of new database");
747 goto getout;
748 }
749 if ( i > 0 ) d->nblocks[i]->previousblock = d->nblocks[i-1]->position;
750 else d->nblocks[i]->previousblock = -1;
751 d->nblocks[i]->position = ftell(f);
752 s = d->nblocks[i]->names;
753 for ( j = 0; j < NAMETABLESIZE; j++ ) *s++ = 0;
754 convertnamesblock(d->nblocks[i],&scratchnamesblock,TODISK);
755 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
756/* INTERNAL_ERROR_EXCL_START */
757 MesPrint("!>Error while writing new names blocks\n");
758 for ( i = 0; i < numnameblocks; i++ ) M_free(d->nblocks[i],"names blocks of new database");
759 for ( i = 0; i < numblocks; i++ ) M_free(d->iblocks[i],"index blocks of new database");
760 goto getout;
761/* INTERNAL_ERROR_EXCL_STOP */
762 }
763 }
764 d->info.firstindexblock = d->iblocks[0]->position;
765 d->info.lastindexblock = d->iblocks[numblocks-1]->position;
766 d->info.firstnameblock = d->nblocks[0]->position;
767 d->info.lastnameblock = d->nblocks[numnameblocks-1]->position;
768 if ( WriteIniInfo(d) ) {
769 for ( i = 0; i < numnameblocks; i++ ) M_free(d->nblocks[i],"names blocks of new database");
770 for ( i = 0; i < numblocks; i++ ) M_free(d->iblocks[i],"index blocks of new database");
771 goto getout;
772 }
773 return(d);
774}
775
776/*
777 #] NewDbase :
778 #[ FreeTableBase :
779*/
780
781void FreeTableBase(DBASE *d)
782{
783 int i, j, *old, *newL;
784 LIST *L;
785 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) M_free(d->nblocks[i],"nblocks[i]");
786 for ( i = 0; i < d->info.numberofindexblocks; i++ ) M_free(d->iblocks[i],"iblocks[i]");
787 M_free(d->nblocks,"nblocks");
788 M_free(d->iblocks,"iblocks");
789 if ( d->tablenames ) M_free(d->tablenames,"d->tablenames");
790 if ( d->name ) M_free(d->name,"d->name");
791 if ( d->fullname ) M_free(d->fullname,"d->fullname");
792 i = d - tablebases;
793 if ( i < ( NumTableBases - 1 ) ) {
794 L = &(AC.TableBaseList);
795 j = ( ( NumTableBases - i - 1 ) * L->size ) / sizeof(int);
796 old = (int *)d; newL = (int *)(d+1);
797 while ( --j >= 0 ) *newL++ = *old++;
798 j = L->size / sizeof(int);
799 while ( --j >= 0 ) *newL++ = 0;
800 }
801 NumTableBases--;
802 M_free(d,"tb,d");
803}
804
805/*
806 #] FreeTableBase :
807 #[ ComposeTableNames :
808
809 The nameblocks are supposed to be in memory.
810 Hence we have to go through them
811*/
812
813int ComposeTableNames(DBASE *d)
814{
815 MLONG nsize = 0;
816 int i, j, k;
817 char *s, *t, *ss;
818 d->topnumber = 0;
819 i = 0; s = d->nblocks[i]->names; j = NAMETABLESIZE;
820 while ( *s ) {
821 if ( *s ) d->topnumber++;
822 for ( k = 0; k < 2; k++ ) { /* name and argtail */
823 while ( *s ) {
824 j--;
825 if ( j <= 0 ) {
826 i++; if ( i >= d->info.numberofnamesblocks ) goto gotall;
827 s = d->nblocks[i]->names; j = NAMETABLESIZE;
828 }
829 else s++;
830 }
831 j--;
832 if ( j <= 0 ) {
833 i++; if ( i >= d->info.numberofnamesblocks ) goto gotall;
834 s = d->nblocks[i]->names; j = NAMETABLESIZE;
835 }
836 else s++;
837 }
838 }
839gotall:;
840 nsize = (d->info.numberofnamesblocks-1)*NAMETABLESIZE +
841 (s-d->nblocks[i]->names)+1;
842 if ( ( d->tablenames = (char *)Malloc1((2*nsize+30)*sizeof(char),"tablenames") )
843 == 0 ) { return(-1); }
844 t = d->tablenames;
845 d->tablenamessize = 2*nsize+30;
846 d->tablenamefill = nsize-1;
847 for ( k = 0; k < i; k++ ) {
848 ss = d->nblocks[k]->names;
849 for ( j = 0; j < NAMETABLESIZE; j++ ) *t++ = *ss++;
850 }
851 ss = d->nblocks[i]->names;
852 while ( ss < s ) *t++ = *ss++;
853 *t = 0;
854 return(0);
855}
856
857/*
858 #] ComposeTableNames :
859 #[ OpenDbase :
860*/
861
862DBASE *OpenDbase(char *filename)
863{
864 FILE *f;
865 DBASE *d;
866 char *newname;
867 if ( ( f = LocateBase(&filename,&newname,"r+b") ) == 0 ) {
868 MesPrint("Cannot open file %s\n",filename);
869 return(0);
870 }
871/* setbuf(f,0); */
872 d = (DBASE *)From0List(&(AC.TableBaseList));
873 d->name = filename; /* For the moment just for the error messages */
874 d->handle = f;
875 if ( ReadIniInfo(d) || ReadIndex(d) ) { M_free(d,"OpenDbase"); fclose(f); return(0); }
876 if ( ComposeTableNames(d) ) {
877 FreeTableBase(d);
878 fclose(f);
879 return(0);
880 }
881 d->name = str_dup(filename);
882 d->fullname = newname;
883 return(d);
884}
885
886/*
887 #] OpenDbase :
888 #[ AddTableName :
889
890 Adds a name of a table. Writes the namelist to disk.
891 Returns the number of this tablename in the database.
892 If the name was already in the table we return its value in negative.
893 Zero is an error!
894*/
895
896MLONG AddTableName(DBASE *d,char *name,TABLES T)
897{
898 char *s, *t, *tt;
899 int namesize, tailsize;
900 MLONG newsize, i, num;
901/*
902 First search for the name in what we have already
903*/
904 if ( d->tablenames ) {
905 num = 0;
906 s = d->tablenames;
907 while ( *s ) {
908 num++;
909 t = name;
910 while ( ( *s == *t ) && *t ) { s++; t++; }
911 if ( *s == *t ) { return(-num); }
912 while ( *s ) s++;
913 s++;
914 while ( *s ) s++;
915 s++;
916 }
917 }
918/*
919 This name has to be added
920*/
921 MesPrint("We add the name %s\n",name);
922 t = name;
923 while ( *t ) { t++; }
924 namesize = t-name;
925 if ( ( t = (char *)(T->argtail) ) != 0 ) {
926 while ( *t ) { t++; }
927 tailsize = t - (char *)(T->argtail);
928 }
929 else { tailsize = 0; }
930 if ( d->tablenames == 0 ) {
931 if ( ComposeTableNames(d) ) {
932 FreeTableBase(d);
933 M_free(d,"AddTableName");
934 return(0);
935 }
936 }
937 d->info.numberoftables++;
938 while ( ( d->tablenamefill+namesize+tailsize+3 > d->tablenamessize )
939 || ( d->tablenames == 0 ) ) {
940 newsize = 2*d->tablenamessize + 2*namesize + 2*tailsize + 6;
941 if ( ( t = (char *)Malloc1(newsize*sizeof(char),"AddTableName") ) == 0 )
942 return(0);
943 tt = t;
944 if ( d->tablenames ) {
945 s = d->tablenames;
946 for ( i = 0; i < d->tablenamefill; i++ ) *t++ = *s++;
947 *t = 0;
948 M_free(d->tablenames,"d->tablenames");
949 }
950 d->tablenames = tt;
951 d->tablenamessize = newsize;
952 }
953 s = d->tablenames + d->tablenamefill;
954 t = name;
955 while ( *t ) *s++ = *t++;
956 *s++ = 0;
957 t = (char *)(T->argtail);
958 while ( *t ) *s++ = *t++;
959 *s++ = 0;
960 *s = 0;
961 d->tablenamefill = s - d->tablenames;
962 d->topnumber++;
963/*
964 Now we have to synchronize
965*/
966 if ( PutTableNames(d) ) return(0);
967 return(d->topnumber);
968}
969
970/*
971 #] AddTableName :
972 #[ GetTableName :
973
974 Gets a name of a table.
975 Returns the number of this tablename in the database.
976 Zero -> error
977*/
978
979MLONG GetTableName(DBASE *d,char *name)
980{
981 char *s, *t;
982 MLONG num;
983/*
984 search for the name in what we have
985*/
986 if ( d->tablenames ) {
987 num = 0;
988 s = d->tablenames;
989 while ( *s ) {
990 num++;
991 t = name;
992 while ( ( *s == *t ) && *t ) { s++; t++; }
993 if ( *s == *t ) { return(num); }
994 while ( *s ) s++;
995 s++;
996 while ( *s ) s++;
997 s++;
998 }
999 }
1000 return(0);
1001}
1002
1003/*
1004 #] GetTableName :
1005 #[ PutTableNames :
1006
1007 Takes the names string in d->tablenames and puts it in the nblocks
1008 pieces. Writes what has been changed to disk.
1009*/
1010
1011int PutTableNames(DBASE *d)
1012{
1013 NAMESBLOCK **nnew;
1014 int i, j, firstdif;
1015 MLONG m;
1016 char *s, *t;
1017/*
1018 Determine how many blocks are needed.
1019*/
1020 MLONG numblocks = d->tablenamefill/NAMETABLESIZE + 1;
1021 if ( d->info.numberofnamesblocks < numblocks ) {
1022/*
1023 We need more blocks. First make sure of the space for nblocks.
1024*/
1025 if ( ( nnew = (NAMESBLOCK **)Malloc1(sizeof(NAMESBLOCK *)*numblocks,
1026 "new names block") ) == 0 ) {
1027 return(-1);
1028 }
1029 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
1030 nnew[i] = d->nblocks[i];
1031 }
1032 free(d->nblocks);
1033 d->nblocks = nnew;
1034 for ( ; i < numblocks; i++ ) {
1035 if ( ( d->nblocks[i] = (NAMESBLOCK *)Malloc1(sizeof(NAMESBLOCK),
1036 "additional names blocks ") ) == 0 ) {
1037 FreeTableBase(d);
1038 return(-1);
1039 }
1040 d->nblocks[i]->previousblock = -1;
1041 d->nblocks[i]->position = -1;
1042 s = d->nblocks[i]->names;
1043 for ( j = 0; j < NAMETABLESIZE; j++ ) *s++ = 0;
1044 }
1045 d->info.numberofnamesblocks = numblocks;
1046 }
1047/*
1048 Now look till where the new contents agree with the old.
1049*/
1050 firstdif = 0;
1051 i = 0; t = d->nblocks[i]->names; j = 0; s = d->tablenames;
1052 for ( m = 0; m < d->tablenamefill; m++ ) {
1053 if ( *s == *t ) {
1054 s++; t++; j++;
1055 if ( j >= NAMETABLESIZE ) {
1056 i++;
1057 t = d->nblocks[i]->names;
1058 j = 0;
1059 }
1060 }
1061 else {
1062 firstdif = i;
1063 for ( ; m < d->tablenamefill; m++ ) {
1064 *t++ = *s++; j++;
1065 if ( j >= NAMETABLESIZE ) {
1066 i++;
1067 t = d->nblocks[i]->names;
1068 j = 0;
1069 }
1070 }
1071 *t = 0;
1072 break;
1073 }
1074 }
1075 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
1076 if ( i == firstdif ) break;
1077 if ( d->nblocks[i]->position < 0 ) { firstdif = i; break; }
1078 }
1079/*
1080 Now we have to (re)write the blocks, starting at firstdif.
1081*/
1082 for ( i = firstdif; i < d->info.numberofnamesblocks; i++ ) {
1083 if ( i > 0 ) d->nblocks[i]->previousblock = d->nblocks[i-1]->position;
1084 else d->nblocks[i]->previousblock = -1;
1085 if ( d->nblocks[i]->position < 0 ) {
1086 fseek(d->handle,0,SEEK_END);
1087 d->nblocks[i]->position = ftell(d->handle);
1088 }
1089 else fseek(d->handle,d->nblocks[i]->position,SEEK_SET);
1090 convertnamesblock(d->nblocks[i],&scratchnamesblock,TODISK);
1091 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
1092/* INTERNAL_ERROR_EXCL_START */
1093 MesPrint("!>Error while writing names blocks\n");
1094 FreeTableBase(d);
1095 return(-1);
1096/* INTERNAL_ERROR_EXCL_STOP */
1097 }
1098 }
1099 d->info.lastnameblock = d->nblocks[d->info.numberofnamesblocks-1]->position;
1100 d->info.firstnameblock = d->nblocks[0]->position;
1101 return(WriteIniInfo(d));
1102}
1103
1104/*
1105 #] PutTableNames :
1106 #[ AddToIndex :
1107*/
1108
1109int AddToIndex(DBASE *d,MLONG number)
1110{
1111 MLONG i, oldnumofindexblocks = d->info.numberofindexblocks;
1112 MLONG j, newnumofindexblocks, jj;
1113 INDEXBLOCK **ib;
1114 MLONG t = (MLONG)(time(0));
1115 if ( number == 0 ) return(0);
1116 else if ( number < 0 ) {
1117 if ( d->info.entriesinindex < -number ) {
1118/* INTERNAL_ERROR_EXCL_START */
1119 MesPrint("!>There are only %ld entries in the index of file %s\n",
1120 d->info.entriesinindex,d->name);
1121 return(-1);
1122/* INTERNAL_ERROR_EXCL_STOP */
1123 }
1124 d->info.entriesinindex += number;
1125dowrite:
1126 if ( WriteIniInfo(d) ) {
1127/* INTERNAL_ERROR_EXCL_START */
1128 d->info.entriesinindex -= number;
1129 MesPrint("!>File may be corrupted\n");
1130 return(-1);
1131/* INTERNAL_ERROR_EXCL_STOP */
1132 }
1133 }
1134 else if ( d->info.entriesinindex+number <=
1135 NUMOBJECTS*d->info.numberofindexblocks ) {
1136 d->info.entriesinindex += number;
1137 goto dowrite;
1138 }
1139 else {
1140 d->info.entriesinindex += number;
1141 newnumofindexblocks = d->info.numberofindexblocks + ((number -
1142 (NUMOBJECTS*d->info.numberofindexblocks - d->info.entriesinindex))
1143 +NUMOBJECTS-1)/NUMOBJECTS;
1144 if ( ( ib = (INDEXBLOCK **)Malloc1(sizeof(INDEXBLOCK *)*newnumofindexblocks,
1145 "index") ) == 0 ) return(-1);
1146 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1147 ib[i] = d->iblocks[i];
1148 }
1149 for ( i = d->info.numberofindexblocks; i < newnumofindexblocks; i++ ) {
1150 if ( ( ib[i] = (INDEXBLOCK *)Malloc1(sizeof(INDEXBLOCK),"index block") ) == 0 ) {
1151 FreeTableBase(d);
1152 return(-1);
1153 }
1154 if ( i > 0 ) ib[i]->previousblock = ib[i-1]->position;
1155 else ib[i]->previousblock = -1;
1156/*
1157 Zero things properly. We don't want garbage in the file.
1158*/
1159 for ( j = 0; j < NUMOBJECTS; j++ ) {
1160 ib[i]->objects[j].date = t;
1161 ib[i]->objects[j].size = 0;
1162 ib[i]->objects[j].position = -1;
1163 ib[i]->objects[j].tablenumber = 0;
1164 ib[i]->objects[j].uncompressed = 0;
1165 ib[i]->objects[j].spare1 = 0;
1166 ib[i]->objects[j].spare2 = 0;
1167 ib[i]->objects[j].spare3 = 0;
1168 for ( jj = 0; jj < ELEMENTSIZE; jj++ ) ib[i]->objects[j].element[jj] = 0;
1169 }
1170 fseek(d->handle,0,SEEK_END);
1171 ib[i]->position = ftell(d->handle);
1172 convertblock(ib[i],&scratchblock,TODISK);
1173 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
1174/* INTERNAL_ERROR_EXCL_START */
1175 MesPrint("!>Error while writing new index of file %s",d->name);
1176 FreeTableBase(d);
1177 return(-1);
1178/* INTERNAL_ERROR_EXCL_STOP */
1179 }
1180 }
1181 d->info.lastindexblock = ib[newnumofindexblocks-1]->position;
1182 d->info.firstindexblock = ib[0]->position;
1183 d->info.numberofindexblocks = newnumofindexblocks;
1184 if ( WriteIniInfo(d) ) {
1185/* INTERNAL_ERROR_EXCL_START */
1186 d->info.numberofindexblocks = oldnumofindexblocks;
1187 d->info.entriesinindex -= number;
1188 MesPrint("!>File may be corrupted\n");
1189 FreeTableBase(d);
1190 return(-1);
1191/* INTERNAL_ERROR_EXCL_STOP */
1192 }
1193 M_free(d->iblocks,"AddToIndex");
1194 d->iblocks = ib;
1195 }
1196 return(0);
1197}
1198
1199/*
1200 #] AddToIndex :
1201 #[ AddObject :
1202*/
1203
1204MLONG AddObject(DBASE *d,MLONG tablenumber,char *arguments,char *rhs)
1205{
1206 MLONG number;
1207 number = d->info.entriesinindex;
1208 if ( AddToIndex(d,1) ) return(-1);
1209 if ( WriteObject(d,tablenumber,arguments,rhs,number) ) return(-1);
1210 return(number);
1211}
1212
1213/*
1214 #] AddObject :
1215 #[ FindTableNumber :
1216*/
1217
1218MLONG FindTableNumber(DBASE *d,char *name)
1219{
1220 char *s = d->tablenames, *t, *ss;
1221 MLONG num = 0;
1222 ss = d->tablenames + d->tablenamefill;
1223 while ( s < ss ) {
1224 num++;
1225 t = name;
1226 while ( *s == *t && *t ) {
1227 s++; t++;
1228 }
1229 if ( *s == 0 && *t == 0 ) return(num);
1230 while ( *s ) s++;
1231 s++;
1232/*
1233 Skip also the argument tail
1234*/
1235 while ( *s ) s++;
1236 s++;
1237 }
1238 return(-1); /* Name not found */
1239}
1240
1241/*
1242 #] FindTableNumber :
1243 #[ WriteObject :
1244*/
1245
1246int WriteObject(DBASE *d,MLONG tablenumber,char *arguments,char *rhs,MLONG number)
1247{
1248 char *s, *a;
1249#ifdef WITHZLIB
1250 char *buffer = 0;
1251 uLongf newsize = 0, oldsize = 0;
1252 uLong ssize;
1253 int error = 0;
1254#endif
1255 MLONG i, j, position, size, n;
1256 OBJECTS *obj;
1257 if ( ( d->mode & INPUTONLY ) == INPUTONLY ) {
1258 MesPrint("Not allowed to write to input\n");
1259 return(-1);
1260 }
1261 if ( number >= d->info.entriesinindex ) {
1262 MesPrint("Reference to non-existing object number %ld\n",number+1);
1263 return(0);
1264 }
1265 j = number/NUMOBJECTS;
1266 i = number%NUMOBJECTS;
1267 obj = &(d->iblocks[j]->objects[i]);
1268 a = arguments;
1269 while ( *a ) a++;
1270 a++; n = a - arguments;
1271 if ( n > ELEMENTSIZE ) {
1272 MesPrint("Table element %s has more than %ld characters.\n",arguments,
1273 (MLONG)ELEMENTSIZE);
1274 return(-1);
1275 }
1276 s = obj->element;
1277 a = arguments;
1278 while ( *a ) *s++ = *a++;
1279 *s++ = 0;
1280 while ( n < ELEMENTSIZE ) { *s++ = 0; n++; }
1281 obj->spare1 = obj->spare2 = obj->spare3 = 0;
1282
1283 fseek(d->handle,0,SEEK_END);
1284 position = ftell(d->handle);
1285 s = rhs;
1286 while ( *s ) s++;
1287 s++;
1288 size = s - rhs;
1289#ifdef WITHZLIB
1290 if ( ( d->mode & NOCOMPRESS ) == 0 ) {
1291 newsize = size + size/1000 + 20;
1292 if ( ( buffer = (char *)Malloc1(newsize*sizeof(char),"compress buffer") )
1293 == 0 ) {
1294 MesPrint("No compress used for element %s in file %s\n",arguments,d->name);
1295 }
1296 }
1297 else buffer = 0;
1298 if ( buffer ) {
1299 ssize = size;
1300#ifdef WITHZSTD
1301 // Force the use of zlib for compressed Tablebase entries, so that tablebases created
1302 // with zstd-supported FORM builds can be used by zstd-unsupported FORM builds.
1303 const int old_isUsingZSTDcompression = ZWRAP_isUsingZSTDcompression();
1304 ZWRAP_useZSTDcompression(0);
1305#endif
1306 if ( ( error = compress((Bytef *)buffer,&newsize,(Bytef *)rhs,ssize) ) != Z_OK ) {
1307/* INTERNAL_ERROR_EXCL_START */
1308 MesPrint("!>Due to error no compress used for element %s in file %s\n",arguments,d->name);
1309 MesPrint("Error = %d\n",error);
1310 M_free(buffer,"tb,WriteObject");
1311 buffer = 0;
1312/* INTERNAL_ERROR_EXCL_STOP */
1313 }
1314#ifdef WITHZSTD
1315 ZWRAP_useZSTDcompression(old_isUsingZSTDcompression);
1316#endif
1317 }
1318 if ( buffer ) {
1319 rhs = buffer;
1320 oldsize = size;
1321 size = newsize;
1322 }
1323#endif
1324 if ( minoswrite(d->handle,rhs,size) ) {
1325/* INTERNAL_ERROR_EXCL_START */
1326 MesPrint("!>Error while writing rhs\n");
1327 return(-1);
1328/* INTERNAL_ERROR_EXCL_STOP */
1329 }
1330 obj->position = position;
1331 obj->size = size;
1332 obj->date = (MLONG)(time(0));
1333 obj->tablenumber = tablenumber;
1334#ifdef WITHZLIB
1335 obj->uncompressed = oldsize;
1336 if ( buffer ) M_free(buffer,"tb,WriteObject");
1337#else
1338 obj->uncompressed = 0;
1339#endif
1340 return(WriteIndexBlock(d,j));
1341}
1342
1343/*
1344 #] WriteObject :
1345 #[ ReadObject :
1346
1347 Returns a pointer to the proper rhs
1348*/
1349
1350char *ReadObject(DBASE *d,MLONG tablenumber,char *arguments)
1351{
1352 OBJECTS *obj;
1353 MLONG i, j;
1354 char *buffer1, *s, *t;
1355#ifdef WITHZLIB
1356 char *buffer2 = 0;
1357 uLongf finallength = 0;
1358#endif
1359 if ( tablenumber > d->topnumber ) {
1360 MesPrint("Reference to non-existing table number in tablebase %s: %ld\n",
1361 d->name,tablenumber);
1362 return(0);
1363 }
1364/*
1365 Start looking for the object
1366*/
1367 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1368 for ( j = 0; j < NUMOBJECTS; j++ ) {
1369 if ( d->iblocks[i]->objects[j].tablenumber != tablenumber ) continue;
1370 s = arguments; t = d->iblocks[i]->objects[j].element;
1371 while ( *s == *t && *s ) { s++; t++; }
1372 if ( *t == 0 && *s == 0 ) goto foundelement;
1373 }
1374 }
1375 s = d->tablenames; i = 1;
1376 while ( *s ) {
1377 if ( i == tablenumber ) break;
1378 while ( *s ) s++;
1379 s++;
1380 while ( *s ) s++;
1381 s++;
1382 i++;
1383 }
1384 MesPrint("%s(%s) not found in tablebase %s\n",s,arguments,d->name);
1385 return(0);
1386
1387foundelement:;
1388 obj = &(d->iblocks[i]->objects[j]);
1389 fseek(d->handle,obj->position,SEEK_SET);
1390 if ( ( buffer1 = (char *)Malloc1(obj->size,"reading rhs buffer1") ) == 0 ) {
1391 return(0);
1392 }
1393#ifdef WITHZLIB
1394 if ( obj->uncompressed > 0 ) {
1395 if ( ( buffer2 = (char *)Malloc1(obj->uncompressed,"reading rhs buffer2") ) == 0 ) {
1396 return(0);
1397 }
1398 }
1399 else buffer2 = 0;
1400#endif
1401 if ( minosread(d->handle,buffer1,obj->size) ) {
1402/* INTERNAL_ERROR_EXCL_START */
1403 MesPrint("!>Could not read rhs %s in file %s\n",arguments,d->name);
1404 M_free(buffer1,"tb,ReadObject");
1405#ifdef WITHZLIB
1406 if ( buffer2 ) M_free(buffer2,"tb,ReadObject");
1407#endif
1408 return(0);
1409/* INTERNAL_ERROR_EXCL_STOP */
1410 }
1411#ifdef WITHZLIB
1412 if ( buffer2 == 0 ) return(buffer1);
1413 finallength = obj->uncompressed;
1414 if ( uncompress((Bytef *)buffer2,&finallength,(Bytef *)buffer1,obj->size) != Z_OK ) {
1415/* INTERNAL_ERROR_EXCL_START */
1416 MesPrint("!>Cannot uncompress element %s in file %s\n",arguments,d->name);
1417 M_free(buffer1,"tb,ReadObject"); M_free(buffer2,"tb,ReadObject");
1418 return(0);
1419/* INTERNAL_ERROR_EXCL_STOP */
1420 }
1421 M_free(buffer1,"tb,ReadObject");
1422 return(buffer2);
1423#else
1424 return(buffer1);
1425#endif
1426}
1427
1428/*
1429 #] ReadObject :
1430 #[ ReadijObject :
1431
1432 Returns a pointer to the proper rhs
1433*/
1434
1435char *ReadijObject(DBASE *d,MLONG i,MLONG j,char *arguments)
1436{
1437 OBJECTS *obj;
1438 char *buffer1;
1439#ifdef WITHZLIB
1440 char *buffer2 = 0;
1441 uLongf finallength = 0;
1442#endif
1443 obj = &(d->iblocks[i]->objects[j]);
1444 fseek(d->handle,obj->position,SEEK_SET);
1445 if ( ( buffer1 = (char *)Malloc1(obj->size,"reading rhs buffer1") ) == 0 ) {
1446 return(0);
1447 }
1448#ifdef WITHZLIB
1449 if ( obj->uncompressed > 0 ) {
1450 if ( ( buffer2 = (char *)Malloc1(obj->uncompressed,"reading rhs buffer2") ) == 0 ) {
1451 return(0);
1452 }
1453 }
1454 else buffer2 = 0;
1455#endif
1456 if ( minosread(d->handle,buffer1,obj->size) ) {
1457/* INTERNAL_ERROR_EXCL_START */
1458 MesPrint("!>Could not read rhs %s in file %s\n",arguments,d->name);
1459 if ( buffer1 ) M_free(buffer1,"rhs buffer1");
1460#ifdef WITHZLIB
1461 if ( buffer2 ) M_free(buffer2,"rhs buffer2");
1462#endif
1463 return(0);
1464/* INTERNAL_ERROR_EXCL_STOP */
1465 }
1466#ifdef WITHZLIB
1467 if ( buffer2 == 0 ) return(buffer1);
1468 finallength = obj->uncompressed;
1469 if ( uncompress((Bytef *)buffer2,&finallength,(Bytef *)buffer1,obj->size) != Z_OK ) {
1470/* INTERNAL_ERROR_EXCL_START */
1471 MesPrint("!>Cannot uncompress element %s in file %s\n",arguments,d->name);
1472 if ( buffer1 ) M_free(buffer1,"rhs buffer1");
1473 if ( buffer2 ) M_free(buffer2,"rhs buffer2");
1474 return(0);
1475/* INTERNAL_ERROR_EXCL_STOP */
1476 }
1477 M_free(buffer1,"rhs buffer1");
1478 return(buffer2);
1479#else
1480 return(buffer1);
1481#endif
1482}
1483
1484/*
1485 #] ReadijObject :
1486 #[ ExistsObject :
1487
1488 Returns 1 if Object exists
1489*/
1490
1491int ExistsObject(DBASE *d,MLONG tablenumber,char *arguments)
1492{
1493 MLONG i, j;
1494 char *s, *t;
1495 if ( tablenumber > d->topnumber ) {
1496 MesPrint("Reference to non-existing table number in tablebase %s: %ld\n",
1497 d->name,tablenumber);
1498 return(0);
1499 }
1500/*
1501 Start looking for the object
1502*/
1503 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1504 for ( j = 0; j < NUMOBJECTS; j++ ) {
1505 if ( d->iblocks[i]->objects[j].tablenumber != tablenumber ) continue;
1506 s = arguments; t = d->iblocks[i]->objects[j].element;
1507 while ( *s == *t && *s ) { s++; t++; }
1508 if ( *t == 0 && *s == 0 ) return(1);
1509 }
1510 }
1511 return(0);
1512}
1513
1514/*
1515 #] ExistsObject :
1516 #[ DeleteObject :
1517
1518 Returns 1 if Object has been deleted.
1519 We leave a hole. Actually the object is still there but has been
1520 inactivated. It can be reactivated by calling this routine again.
1521*/
1522
1523int DeleteObject(DBASE *d,MLONG tablenumber,char *arguments)
1524{
1525 MLONG i, j;
1526 char *s, *t;
1527 if ( tablenumber > d->topnumber ) {
1528 MesPrint("Reference to non-existing table number in tablebase %s: %ld\n",
1529 d->name,tablenumber);
1530 return(0);
1531 }
1532/*
1533 Start looking for the object
1534*/
1535 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1536 for ( j = 0; j < NUMOBJECTS; j++ ) {
1537 if ( d->iblocks[i]->objects[j].tablenumber != tablenumber ) continue;
1538 s = arguments; t = d->iblocks[i]->objects[j].element;
1539 while ( *s == *t && *s ) { s++; t++; }
1540 if ( *t == 0 && *s == 0 ) {
1541 d->iblocks[i]->objects[j].tablenumber =
1542 -d->iblocks[i]->objects[j].tablenumber - 1;
1543 return(1);
1544 }
1545 }
1546 }
1547 return(0);
1548}
1549
1550/*
1551 #] DeleteObject :
1552*/
int size
Definition structs.h:207
UBYTE * argtail
Definition structs.h:354
Definition minos.h:123