FORM v5.0.1-23-g7a8f756
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 MesPrint("We need more than %ld bytes for the index.\n",MAXINDEXSIZE);
300 MesPrint("The file %s may not be a proper database\n",d->name);
301 return(-1);
302 }
303 size = sizeof(INDEXBLOCK *)*d->info.numberofindexblocks;
304 if ( ( ib = (INDEXBLOCK **)Malloc1(size,"tb,index") ) == 0 ) return(-1);
305 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
306 if ( ( ib[i] = (INDEXBLOCK *)Malloc1(sizeof(INDEXBLOCK),"index block") ) == 0 ) {
307 for ( --i; i >= 0; i-- ) M_free(ib[i],"tb,indexblock");
308 M_free(ib,"tb,index");
309 return(-1);
310 }
311 }
312 size = sizeof(NAMESBLOCK *)*d->info.numberofnamesblocks;
313 if ( ( ina = (NAMESBLOCK **)Malloc1(size,"tb,indexnames") ) == 0 ) return(-1);
314 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
315 if ( ( ina[i] = (NAMESBLOCK *)Malloc1(sizeof(NAMESBLOCK),"index names block") ) == 0 ) {
316 for ( --i; i >= 0; i-- ) M_free(ina[i],"index names block");
317 M_free(ina,"tb,indexnames");
318 for ( i = 0; i < d->info.numberofindexblocks; i++ ) M_free(ib[i],"tb,indexblock");
319 M_free(ib,"tb,index");
320 return(-1);
321 }
322 }
323/*
324 Read the index blocks, from the back to the front. The links are only
325 reliable that way.
326*/
327 position = d->info.lastindexblock;
328 for ( i = d->info.numberofindexblocks - 1; i >= 0; i-- ) {
329 fseek(d->handle,position,SEEK_SET);
330 if ( minosread(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
331 MesPrint("Error while reading file %s\n",d->name);
332thisiswrong:
333 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) M_free(ina[i],"index names block");
334 M_free(ina,"tb,indexnames");
335 for ( i = 0; i < d->info.numberofindexblocks; i++ ) M_free(ib[i],"tb,indexblock");
336 M_free(ib,"tb,index");
337 return(-1);
338 }
339 convertblock(&scratchblock,ib[i],FROMDISK);
340 if ( ib[i]->position != position ||
341 ( ib[i]->previousblock <= 0 && i > 0 ) ) {
342 MesPrint("File %s has inconsistent contents\n",d->name);
343 goto thisiswrong;
344 }
345 position = ib[i]->previousblock;
346 }
347 d->info.firstindexblock = ib[0]->position;
348 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
349 ib[i]->flags &= MCLEANFLAG;
350 }
351/*
352 Read the names blocks, from the back to the front. The links are only
353 reliable that way.
354*/
355 position = d->info.lastnameblock;
356 for ( i = d->info.numberofnamesblocks - 1; i >= 0; i-- ) {
357 fseek(d->handle,position,SEEK_SET);
358 if ( minosread(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
359 MesPrint("Error while reading file %s\n",d->name);
360 goto thisiswrong;
361 }
362 convertnamesblock(&scratchnamesblock,ina[i],FROMDISK);
363 if ( ina[i]->position != position ||
364 ( ina[i]->previousblock <= 0 && i > 0 ) ) {
365 MesPrint("File %s has inconsistent contents\n",d->name);
366 goto thisiswrong;
367 }
368 position = ina[i]->previousblock;
369 }
370 d->info.firstnameblock = ina[0]->position;
371/*
372 Give the old info back to the system.
373*/
374 if ( d->iblocks ) {
375 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
376 if ( d->iblocks[i] ) M_free(d->iblocks[i],"d->iblocks[i]");
377 }
378 M_free(d->iblocks,"d->iblocks");
379 }
380 if ( d->nblocks ) {
381 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
382 if ( d->nblocks[i] ) M_free(d->nblocks[i],"d->nblocks[i]");
383 }
384 M_free(d->nblocks,"d->nblocks");
385 }
386/*
387 And substitute the new blocks
388*/
389 d->iblocks = ib;
390 d->nblocks = ina;
391 return(0);
392}
393
394/*
395 #] ReadIndex :
396 #[ WriteIndexBlock :
397*/
398
399int WriteIndexBlock(DBASE *d,MLONG num)
400{
401 if ( num >= d->info.numberofindexblocks ) {
402 MesPrint("Illegal number specified for number of index blocks\n");
403 return(-1);
404 }
405 fseek(d->handle,d->iblocks[num]->position,SEEK_SET);
406 convertblock(d->iblocks[num],&scratchblock,TODISK);
407 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
408 MesPrint("Error while writing an index block in file %s\n",d->name);
409 MesPrint("File may be unreliable now\n");
410 return(-1);
411 }
412 return(0);
413}
414
415/*
416 #] WriteIndexBlock :
417 #[ WriteNamesBlock :
418*/
419
420int WriteNamesBlock(DBASE *d,MLONG num)
421{
422 if ( num >= d->info.numberofnamesblocks ) {
423 MesPrint("Illegal number specified for number of names blocks\n");
424 return(-1);
425 }
426 fseek(d->handle,d->nblocks[num]->position,SEEK_SET);
427 convertnamesblock(d->nblocks[num],&scratchnamesblock,TODISK);
428 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
429 MesPrint("Error while writing a names block in file %s\n",d->name);
430 MesPrint("File may be unreliable now\n");
431 return(-1);
432 }
433 return(0);
434}
435
436/*
437 #] WriteNamesBlock :
438 #[ WriteIndex :
439
440 Problem here is to get the links right.
441*/
442
443int WriteIndex(DBASE *d)
444{
445 MLONG i, position;
446 if ( d->iblocks == 0 ) return(0);
447 if ( d->nblocks == 0 ) return(0);
448 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
449 if ( d->iblocks[i] == 0 ) {
450 MesPrint("Error: unassigned index blocks. Cannot write\n");
451 return(-1);
452 }
453 }
454 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
455 if ( d->nblocks[i] == 0 ) {
456 MesPrint("Error: unassigned names blocks. Cannot write\n");
457 return(-1);
458 }
459 }
460 d->info.lastindexblock = -1;
461 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
462 position = d->iblocks[i]->position;
463 if ( position <= 0 ) {
464 fseek(d->handle,0,SEEK_END);
465 position = ftell(d->handle);
466 d->iblocks[i]->position = position;
467 if ( i <= 0 ) d->iblocks[i]->previousblock = -1;
468 else d->iblocks[i]->previousblock = d->iblocks[i-1]->position;
469 }
470 else fseek(d->handle,position,SEEK_SET);
471 convertblock(d->iblocks[i],&scratchblock,TODISK);
472 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
473 MesPrint("Error while writing index of file %s",d->name);
474 d->iblocks[i]->position = -1;
475 return(-1);
476 }
477 d->info.lastindexblock = position;
478 }
479 d->info.lastnameblock = -1;
480 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
481 position = d->nblocks[i]->position;
482 if ( position <= 0 ) {
483 fseek(d->handle,0,SEEK_END);
484 position = ftell(d->handle);
485 d->nblocks[i]->position = position;
486 if ( i <= 0 ) d->nblocks[i]->previousblock = -1;
487 else d->nblocks[i]->previousblock = d->nblocks[i-1]->position;
488 }
489 else fseek(d->handle,position,SEEK_SET);
490 convertnamesblock(d->nblocks[i],&scratchnamesblock,TODISK);
491 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
492 MesPrint("Error while writing index of file %s",d->name);
493 d->nblocks[i]->position = -1;
494 return(-1);
495 }
496 d->info.lastnameblock = position;
497 }
498 return(0);
499}
500
501/*
502 #] WriteIndex :
503 #[ WriteIniInfo :
504*/
505
506int WriteIniInfo(DBASE *d)
507{
508 INIINFO inf;
509 fseek(d->handle,0,SEEK_SET);
510 convertiniinfo(&(d->info),&inf,TODISK);
511 if ( minoswrite(d->handle,(char *)(&inf),sizeof(INIINFO)) ) {
512 MesPrint("Error while writing masterindex of file %s",d->name);
513 return(-1);
514 }
515 return(0);
516}
517
518/*
519 #] WriteIniInfo :
520 #[ ReadIniInfo :
521*/
522
523int ReadIniInfo(DBASE *d)
524{
525 INIINFO inf;
526 fseek(d->handle,0,SEEK_SET);
527 if ( minosread(d->handle,(char *)(&inf),sizeof(INIINFO)) ) {
528 MesPrint("Error while reading masterindex of file %s",d->name);
529 return(-1);
530 }
531 convertiniinfo(&inf,&(d->info),FROMDISK);
532 if ( d->info.entriesinindex < 0
533 || d->info.numberofindexblocks < 0
534 || d->info.lastindexblock < 0 ) {
535 MesPrint("The file %s is not a proper database\n",d->name);
536 return(-1);
537 }
538 return(0);
539}
540
541/*
542 #] ReadIniInfo :
543 #[ GetDbase :
544*/
545
546DBASE *GetDbase(char *filename, MLONG rwmode)
547{
548 FILE *f;
549 DBASE *d;
550 char *newname;
551 if ( rwmode == 0 ) {
552 if ( ( f = LocateBase(&filename,&newname,"rb") ) == 0 ) {
553
554 MesPrint("&Trying to open non-existent TableBase in readonly mode: %s", filename);
555 Terminate(-1);
556 }
557 } else {
558 if ( ( f = LocateBase(&filename,&newname,"r+b") ) == 0 ) {
559
560 return(NewDbase(filename,0));
561 }
562 }
563
564/* setbuf(f,0); */
565 d = (DBASE *)From0List(&(AC.TableBaseList));
566 d->mode = 0;
567 d->tablenamessize = 0;
568 d->topnumber = 0;
569 d->tablenamefill = 0;
570 d->iblocks = 0;
571 d->nblocks = 0;
572 d->tablenames = 0;
573 d->rwmode = rwmode;
574
575 d->info.entriesinindex = 0;
576 d->info.numberofindexblocks = 0;
577 d->info.firstindexblock = 0;
578 d->info.lastindexblock = 0;
579 d->info.numberoftables = 0;
580 d->info.numberofnamesblocks = 0;
581 d->info.firstnameblock = 0;
582 d->info.lastnameblock = 0;
583
584 d->name = str_dup(filename); /* For the moment just for the error messages */
585 d->handle = f;
586 if ( ReadIniInfo(d) || ReadIndex(d) ) { M_free(d,"index-d"); fclose(f); return(0); }
587 if ( ComposeTableNames(d) < 0 ) { FreeTableBase(d); fclose(f); return(0); }
588 // free allocation from previous str_dup
589 M_free(d->name, "from str_dup");
590 d->name = str_dup(filename);
591 d->fullname = newname;
592 return(d);
593}
594
595/*
596 #] GetDbase :
597 #[ NewDbase :
598
599 Creates a new database with 'number' entries in the index.
600*/
601
602DBASE *NewDbase(char *name,MLONG number)
603{
604 FILE *f;
605 DBASE *d;
606 MLONG numblocks, numnameblocks, i;
607 char *s;
608/*----------change 10-feb-2003 */
609 int j, jj;
610 MLONG t = (MLONG)(time(0));
611/*-----------------------------*/
612 if ( number < 0 ) number = 0;
613 if ( ( f = fopen(name,"w+b") ) == 0 ) {
614 MesPrint("Could not create a new file with name %s\n",name);
615 return(0);
616 }
617 numblocks = (number+NUMOBJECTS-1)/NUMOBJECTS;
618 numnameblocks = 1;
619 if ( numblocks <= 0 ) numblocks = 1;
620 if ( numnameblocks <= 0 ) numnameblocks = 1;
621 d = (DBASE *)From0List(&(AC.TableBaseList));
622 if ( ( d->iblocks = (INDEXBLOCK **)Malloc1(numblocks*sizeof(INDEXBLOCK *),
623 "new database") ) == 0 ) {
624 NumTableBases--;
625 fclose(f);
626 return(0);
627 }
628 d->tablenames = 0;
629 d->tablenamessize = 0;
630 d->topnumber = 0;
631 d->tablenamefill = 0;
632 d->rwmode = 1;
633
634 d->mode = 0;
635 if ( ( d->nblocks = (NAMESBLOCK **)Malloc1(sizeof(NAMESBLOCK *)*numnameblocks,
636 "new database") ) == 0 ) {
637 M_free(d->iblocks,"new database");
638 NumTableBases--;
639 fclose(f);
640 return(0);
641 }
642 if ( ( f = fopen(name,"w+b") ) == 0 ) {
643 MesPrint("Could not create new file %s\n",name);
644 NumTableBases--;
645 return(0);
646 }
647/* setbuf(f,0); */
648 d->name = str_dup(name);
649 d->fullname = str_dup(name);
650 d->handle = f;
651
652 d->info.entriesinindex = number;
653 d->info.numberofindexblocks = numblocks;
654 d->info.numberofnamesblocks = numnameblocks;
655 d->info.firstindexblock = 0;
656 d->info.lastindexblock = 0;
657 d->info.numberoftables = 0;
658 d->info.firstnameblock = 0;
659 d->info.lastnameblock = 0;
660
661 if ( WriteIniInfo(d) ) {
662getout:
663 fclose(f);
664 remove(d->fullname);
665 if ( d->name ) { M_free(d->name,"name tablebase"); d->name = 0; }
666 if ( d->fullname ) { M_free(d->fullname,"fullname tablebase"); d->fullname = 0; }
667 M_free(d->nblocks,"new database");
668 M_free(d->iblocks,"new database");
669 NumTableBases--;
670 return(0);
671 }
672 for ( i = 0; i < numblocks; i++ ) {
673 if ( ( d->iblocks[i] = (INDEXBLOCK *)Malloc1(sizeof(INDEXBLOCK),
674 "index blocks of new database") ) == 0 ) {
675 while ( --i >= 0 ) M_free(d->iblocks[i],"index blocks of new database");
676 goto getout;
677 }
678 if ( i > 0 ) d->iblocks[i]->previousblock = d->iblocks[i-1]->position;
679 else d->iblocks[i]->previousblock = -1;
680 d->iblocks[i]->position = ftell(f);
681 // Initialise, to keep valgrind happy
682 d->iblocks[i]->flags = -1;
683/*----------change 10-feb-2003 */
684/*
685 Zero things properly. We don't want garbage in the file.
686*/
687 for ( j = 0; j < NUMOBJECTS; j++ ) {
688 d->iblocks[i]->objects[j].date = t;
689 d->iblocks[i]->objects[j].size = 0;
690 d->iblocks[i]->objects[j].position = -1;
691 d->iblocks[i]->objects[j].tablenumber = 0;
692 d->iblocks[i]->objects[j].uncompressed = 0;
693 d->iblocks[i]->objects[j].spare1 = 0;
694 d->iblocks[i]->objects[j].spare2 = 0;
695 d->iblocks[i]->objects[j].spare3 = 0;
696 for ( jj = 0; jj < ELEMENTSIZE; jj++ ) d->iblocks[i]->objects[j].element[jj] = 0;
697 }
698 convertblock(d->iblocks[i],&scratchblock,TODISK);
699 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
700 MesPrint("Error while writing new index blocks\n");
701 goto getout;
702 }
703 }
704 for ( i = 0; i < numnameblocks; i++ ) {
705 if ( ( d->nblocks[i] = (NAMESBLOCK *)Malloc1(sizeof(NAMESBLOCK),
706 "names blocks of new database") ) == 0 ) {
707 while ( --i >= 0 ) { M_free(d->nblocks[i],"names blocks of new database"); }
708 for ( i = 0; i < numblocks; i++ ) M_free(d->iblocks[i],"index blocks of new database");
709 goto getout;
710 }
711 if ( i > 0 ) d->nblocks[i]->previousblock = d->nblocks[i-1]->position;
712 else d->nblocks[i]->previousblock = -1;
713 d->nblocks[i]->position = ftell(f);
714 s = d->nblocks[i]->names;
715 for ( j = 0; j < NAMETABLESIZE; j++ ) *s++ = 0;
716 convertnamesblock(d->nblocks[i],&scratchnamesblock,TODISK);
717 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
718 MesPrint("Error while writing new names blocks\n");
719 for ( i = 0; i < numnameblocks; i++ ) M_free(d->nblocks[i],"names blocks of new database");
720 for ( i = 0; i < numblocks; i++ ) M_free(d->iblocks[i],"index blocks of new database");
721 goto getout;
722 }
723 }
724 d->info.firstindexblock = d->iblocks[0]->position;
725 d->info.lastindexblock = d->iblocks[numblocks-1]->position;
726 d->info.firstnameblock = d->nblocks[0]->position;
727 d->info.lastnameblock = d->nblocks[numnameblocks-1]->position;
728 if ( WriteIniInfo(d) ) {
729 for ( i = 0; i < numnameblocks; i++ ) M_free(d->nblocks[i],"names blocks of new database");
730 for ( i = 0; i < numblocks; i++ ) M_free(d->iblocks[i],"index blocks of new database");
731 goto getout;
732 }
733 return(d);
734}
735
736/*
737 #] NewDbase :
738 #[ FreeTableBase :
739*/
740
741void FreeTableBase(DBASE *d)
742{
743 int i, j, *old, *newL;
744 LIST *L;
745 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) M_free(d->nblocks[i],"nblocks[i]");
746 for ( i = 0; i < d->info.numberofindexblocks; i++ ) M_free(d->iblocks[i],"iblocks[i]");
747 M_free(d->nblocks,"nblocks");
748 M_free(d->iblocks,"iblocks");
749 if ( d->tablenames ) M_free(d->tablenames,"d->tablenames");
750 if ( d->name ) M_free(d->name,"d->name");
751 if ( d->fullname ) M_free(d->fullname,"d->fullname");
752 i = d - tablebases;
753 if ( i < ( NumTableBases - 1 ) ) {
754 L = &(AC.TableBaseList);
755 j = ( ( NumTableBases - i - 1 ) * L->size ) / sizeof(int);
756 old = (int *)d; newL = (int *)(d+1);
757 while ( --j >= 0 ) *newL++ = *old++;
758 j = L->size / sizeof(int);
759 while ( --j >= 0 ) *newL++ = 0;
760 }
761 NumTableBases--;
762 M_free(d,"tb,d");
763}
764
765/*
766 #] FreeTableBase :
767 #[ ComposeTableNames :
768
769 The nameblocks are supposed to be in memory.
770 Hence we have to go through them
771*/
772
773int ComposeTableNames(DBASE *d)
774{
775 MLONG nsize = 0;
776 int i, j, k;
777 char *s, *t, *ss;
778 d->topnumber = 0;
779 i = 0; s = d->nblocks[i]->names; j = NAMETABLESIZE;
780 while ( *s ) {
781 if ( *s ) d->topnumber++;
782 for ( k = 0; k < 2; k++ ) { /* name and argtail */
783 while ( *s ) {
784 j--;
785 if ( j <= 0 ) {
786 i++; if ( i >= d->info.numberofnamesblocks ) goto gotall;
787 s = d->nblocks[i]->names; j = NAMETABLESIZE;
788 }
789 else s++;
790 }
791 j--;
792 if ( j <= 0 ) {
793 i++; if ( i >= d->info.numberofnamesblocks ) goto gotall;
794 s = d->nblocks[i]->names; j = NAMETABLESIZE;
795 }
796 else s++;
797 }
798 }
799gotall:;
800 nsize = (d->info.numberofnamesblocks-1)*NAMETABLESIZE +
801 (s-d->nblocks[i]->names)+1;
802 if ( ( d->tablenames = (char *)Malloc1((2*nsize+30)*sizeof(char),"tablenames") )
803 == 0 ) { return(-1); }
804 t = d->tablenames;
805 d->tablenamessize = 2*nsize+30;
806 d->tablenamefill = nsize-1;
807 for ( k = 0; k < i; k++ ) {
808 ss = d->nblocks[k]->names;
809 for ( j = 0; j < NAMETABLESIZE; j++ ) *t++ = *ss++;
810 }
811 ss = d->nblocks[i]->names;
812 while ( ss < s ) *t++ = *ss++;
813 *t = 0;
814 return(0);
815}
816
817/*
818 #] ComposeTableNames :
819 #[ OpenDbase :
820*/
821
822DBASE *OpenDbase(char *filename)
823{
824 FILE *f;
825 DBASE *d;
826 char *newname;
827 if ( ( f = LocateBase(&filename,&newname,"r+b") ) == 0 ) {
828 MesPrint("Cannot open file %s\n",filename);
829 return(0);
830 }
831/* setbuf(f,0); */
832 d = (DBASE *)From0List(&(AC.TableBaseList));
833 d->name = filename; /* For the moment just for the error messages */
834 d->handle = f;
835 if ( ReadIniInfo(d) || ReadIndex(d) ) { M_free(d,"OpenDbase"); fclose(f); return(0); }
836 if ( ComposeTableNames(d) ) {
837 FreeTableBase(d);
838 fclose(f);
839 return(0);
840 }
841 d->name = str_dup(filename);
842 d->fullname = newname;
843 return(d);
844}
845
846/*
847 #] OpenDbase :
848 #[ AddTableName :
849
850 Adds a name of a table. Writes the namelist to disk.
851 Returns the number of this tablename in the database.
852 If the name was already in the table we return its value in negative.
853 Zero is an error!
854*/
855
856MLONG AddTableName(DBASE *d,char *name,TABLES T)
857{
858 char *s, *t, *tt;
859 int namesize, tailsize;
860 MLONG newsize, i, num;
861/*
862 First search for the name in what we have already
863*/
864 if ( d->tablenames ) {
865 num = 0;
866 s = d->tablenames;
867 while ( *s ) {
868 num++;
869 t = name;
870 while ( ( *s == *t ) && *t ) { s++; t++; }
871 if ( *s == *t ) { return(-num); }
872 while ( *s ) s++;
873 s++;
874 while ( *s ) s++;
875 s++;
876 }
877 }
878/*
879 This name has to be added
880*/
881 MesPrint("We add the name %s\n",name);
882 t = name;
883 while ( *t ) { t++; }
884 namesize = t-name;
885 if ( ( t = (char *)(T->argtail) ) != 0 ) {
886 while ( *t ) { t++; }
887 tailsize = t - (char *)(T->argtail);
888 }
889 else { tailsize = 0; }
890 if ( d->tablenames == 0 ) {
891 if ( ComposeTableNames(d) ) {
892 FreeTableBase(d);
893 M_free(d,"AddTableName");
894 return(0);
895 }
896 }
897 d->info.numberoftables++;
898 while ( ( d->tablenamefill+namesize+tailsize+3 > d->tablenamessize )
899 || ( d->tablenames == 0 ) ) {
900 newsize = 2*d->tablenamessize + 2*namesize + 2*tailsize + 6;
901 if ( ( t = (char *)Malloc1(newsize*sizeof(char),"AddTableName") ) == 0 )
902 return(0);
903 tt = t;
904 if ( d->tablenames ) {
905 s = d->tablenames;
906 for ( i = 0; i < d->tablenamefill; i++ ) *t++ = *s++;
907 *t = 0;
908 M_free(d->tablenames,"d->tablenames");
909 }
910 d->tablenames = tt;
911 d->tablenamessize = newsize;
912 }
913 s = d->tablenames + d->tablenamefill;
914 t = name;
915 while ( *t ) *s++ = *t++;
916 *s++ = 0;
917 t = (char *)(T->argtail);
918 while ( *t ) *s++ = *t++;
919 *s++ = 0;
920 *s = 0;
921 d->tablenamefill = s - d->tablenames;
922 d->topnumber++;
923/*
924 Now we have to synchronize
925*/
926 if ( PutTableNames(d) ) return(0);
927 return(d->topnumber);
928}
929
930/*
931 #] AddTableName :
932 #[ GetTableName :
933
934 Gets a name of a table.
935 Returns the number of this tablename in the database.
936 Zero -> error
937*/
938
939MLONG GetTableName(DBASE *d,char *name)
940{
941 char *s, *t;
942 MLONG num;
943/*
944 search for the name in what we have
945*/
946 if ( d->tablenames ) {
947 num = 0;
948 s = d->tablenames;
949 while ( *s ) {
950 num++;
951 t = name;
952 while ( ( *s == *t ) && *t ) { s++; t++; }
953 if ( *s == *t ) { return(num); }
954 while ( *s ) s++;
955 s++;
956 while ( *s ) s++;
957 s++;
958 }
959 }
960 return(0);
961}
962
963/*
964 #] GetTableName :
965 #[ PutTableNames :
966
967 Takes the names string in d->tablenames and puts it in the nblocks
968 pieces. Writes what has been changed to disk.
969*/
970
971int PutTableNames(DBASE *d)
972{
973 NAMESBLOCK **nnew;
974 int i, j, firstdif;
975 MLONG m;
976 char *s, *t;
977/*
978 Determine how many blocks are needed.
979*/
980 MLONG numblocks = d->tablenamefill/NAMETABLESIZE + 1;
981 if ( d->info.numberofnamesblocks < numblocks ) {
982/*
983 We need more blocks. First make sure of the space for nblocks.
984*/
985 if ( ( nnew = (NAMESBLOCK **)Malloc1(sizeof(NAMESBLOCK *)*numblocks,
986 "new names block") ) == 0 ) {
987 return(-1);
988 }
989 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
990 nnew[i] = d->nblocks[i];
991 }
992 free(d->nblocks);
993 d->nblocks = nnew;
994 for ( ; i < numblocks; i++ ) {
995 if ( ( d->nblocks[i] = (NAMESBLOCK *)Malloc1(sizeof(NAMESBLOCK),
996 "additional names blocks ") ) == 0 ) {
997 FreeTableBase(d);
998 return(-1);
999 }
1000 d->nblocks[i]->previousblock = -1;
1001 d->nblocks[i]->position = -1;
1002 s = d->nblocks[i]->names;
1003 for ( j = 0; j < NAMETABLESIZE; j++ ) *s++ = 0;
1004 }
1005 d->info.numberofnamesblocks = numblocks;
1006 }
1007/*
1008 Now look till where the new contents agree with the old.
1009*/
1010 firstdif = 0;
1011 i = 0; t = d->nblocks[i]->names; j = 0; s = d->tablenames;
1012 for ( m = 0; m < d->tablenamefill; m++ ) {
1013 if ( *s == *t ) {
1014 s++; t++; j++;
1015 if ( j >= NAMETABLESIZE ) {
1016 i++;
1017 t = d->nblocks[i]->names;
1018 j = 0;
1019 }
1020 }
1021 else {
1022 firstdif = i;
1023 for ( ; m < d->tablenamefill; m++ ) {
1024 *t++ = *s++; j++;
1025 if ( j >= NAMETABLESIZE ) {
1026 i++;
1027 t = d->nblocks[i]->names;
1028 j = 0;
1029 }
1030 }
1031 *t = 0;
1032 break;
1033 }
1034 }
1035 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
1036 if ( i == firstdif ) break;
1037 if ( d->nblocks[i]->position < 0 ) { firstdif = i; break; }
1038 }
1039/*
1040 Now we have to (re)write the blocks, starting at firstdif.
1041*/
1042 for ( i = firstdif; i < d->info.numberofnamesblocks; i++ ) {
1043 if ( i > 0 ) d->nblocks[i]->previousblock = d->nblocks[i-1]->position;
1044 else d->nblocks[i]->previousblock = -1;
1045 if ( d->nblocks[i]->position < 0 ) {
1046 fseek(d->handle,0,SEEK_END);
1047 d->nblocks[i]->position = ftell(d->handle);
1048 }
1049 else fseek(d->handle,d->nblocks[i]->position,SEEK_SET);
1050 convertnamesblock(d->nblocks[i],&scratchnamesblock,TODISK);
1051 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
1052 MesPrint("Error while writing names blocks\n");
1053 FreeTableBase(d);
1054 return(-1);
1055 }
1056 }
1057 d->info.lastnameblock = d->nblocks[d->info.numberofnamesblocks-1]->position;
1058 d->info.firstnameblock = d->nblocks[0]->position;
1059 return(WriteIniInfo(d));
1060}
1061
1062/*
1063 #] PutTableNames :
1064 #[ AddToIndex :
1065*/
1066
1067int AddToIndex(DBASE *d,MLONG number)
1068{
1069 MLONG i, oldnumofindexblocks = d->info.numberofindexblocks;
1070 MLONG j, newnumofindexblocks, jj;
1071 INDEXBLOCK **ib;
1072 MLONG t = (MLONG)(time(0));
1073 if ( number == 0 ) return(0);
1074 else if ( number < 0 ) {
1075 if ( d->info.entriesinindex < -number ) {
1076 MesPrint("There are only %ld entries in the index of file %s\n",
1077 d->info.entriesinindex,d->name);
1078 return(-1);
1079 }
1080 d->info.entriesinindex += number;
1081dowrite:
1082 if ( WriteIniInfo(d) ) {
1083 d->info.entriesinindex -= number;
1084 MesPrint("File may be corrupted\n");
1085 return(-1);
1086 }
1087 }
1088 else if ( d->info.entriesinindex+number <=
1089 NUMOBJECTS*d->info.numberofindexblocks ) {
1090 d->info.entriesinindex += number;
1091 goto dowrite;
1092 }
1093 else {
1094 d->info.entriesinindex += number;
1095 newnumofindexblocks = d->info.numberofindexblocks + ((number -
1096 (NUMOBJECTS*d->info.numberofindexblocks - d->info.entriesinindex))
1097 +NUMOBJECTS-1)/NUMOBJECTS;
1098 if ( ( ib = (INDEXBLOCK **)Malloc1(sizeof(INDEXBLOCK *)*newnumofindexblocks,
1099 "index") ) == 0 ) return(-1);
1100 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1101 ib[i] = d->iblocks[i];
1102 }
1103 for ( i = d->info.numberofindexblocks; i < newnumofindexblocks; i++ ) {
1104 if ( ( ib[i] = (INDEXBLOCK *)Malloc1(sizeof(INDEXBLOCK),"index block") ) == 0 ) {
1105 FreeTableBase(d);
1106 return(-1);
1107 }
1108 if ( i > 0 ) ib[i]->previousblock = ib[i-1]->position;
1109 else ib[i]->previousblock = -1;
1110/*
1111 Zero things properly. We don't want garbage in the file.
1112*/
1113 for ( j = 0; j < NUMOBJECTS; j++ ) {
1114 ib[i]->objects[j].date = t;
1115 ib[i]->objects[j].size = 0;
1116 ib[i]->objects[j].position = -1;
1117 ib[i]->objects[j].tablenumber = 0;
1118 ib[i]->objects[j].uncompressed = 0;
1119 ib[i]->objects[j].spare1 = 0;
1120 ib[i]->objects[j].spare2 = 0;
1121 ib[i]->objects[j].spare3 = 0;
1122 for ( jj = 0; jj < ELEMENTSIZE; jj++ ) ib[i]->objects[j].element[jj] = 0;
1123 }
1124 fseek(d->handle,0,SEEK_END);
1125 ib[i]->position = ftell(d->handle);
1126 convertblock(ib[i],&scratchblock,TODISK);
1127 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
1128 MesPrint("Error while writing new index of file %s",d->name);
1129 FreeTableBase(d);
1130 return(-1);
1131 }
1132 }
1133 d->info.lastindexblock = ib[newnumofindexblocks-1]->position;
1134 d->info.firstindexblock = ib[0]->position;
1135 d->info.numberofindexblocks = newnumofindexblocks;
1136 if ( WriteIniInfo(d) ) {
1137 d->info.numberofindexblocks = oldnumofindexblocks;
1138 d->info.entriesinindex -= number;
1139 MesPrint("File may be corrupted\n");
1140 FreeTableBase(d);
1141 return(-1);
1142 }
1143 M_free(d->iblocks,"AddToIndex");
1144 d->iblocks = ib;
1145 }
1146 return(0);
1147}
1148
1149/*
1150 #] AddToIndex :
1151 #[ AddObject :
1152*/
1153
1154MLONG AddObject(DBASE *d,MLONG tablenumber,char *arguments,char *rhs)
1155{
1156 MLONG number;
1157 number = d->info.entriesinindex;
1158 if ( AddToIndex(d,1) ) return(-1);
1159 if ( WriteObject(d,tablenumber,arguments,rhs,number) ) return(-1);
1160 return(number);
1161}
1162
1163/*
1164 #] AddObject :
1165 #[ FindTableNumber :
1166*/
1167
1168MLONG FindTableNumber(DBASE *d,char *name)
1169{
1170 char *s = d->tablenames, *t, *ss;
1171 MLONG num = 0;
1172 ss = d->tablenames + d->tablenamefill;
1173 while ( s < ss ) {
1174 num++;
1175 t = name;
1176 while ( *s == *t && *t ) {
1177 s++; t++;
1178 }
1179 if ( *s == 0 && *t == 0 ) return(num);
1180 while ( *s ) s++;
1181 s++;
1182/*
1183 Skip also the argument tail
1184*/
1185 while ( *s ) s++;
1186 s++;
1187 }
1188 return(-1); /* Name not found */
1189}
1190
1191/*
1192 #] FindTableNumber :
1193 #[ WriteObject :
1194*/
1195
1196int WriteObject(DBASE *d,MLONG tablenumber,char *arguments,char *rhs,MLONG number)
1197{
1198 char *s, *a;
1199#ifdef WITHZLIB
1200 char *buffer = 0;
1201 uLongf newsize = 0, oldsize = 0;
1202 uLong ssize;
1203 int error = 0;
1204#endif
1205 MLONG i, j, position, size, n;
1206 OBJECTS *obj;
1207 if ( ( d->mode & INPUTONLY ) == INPUTONLY ) {
1208 MesPrint("Not allowed to write to input\n");
1209 return(-1);
1210 }
1211 if ( number >= d->info.entriesinindex ) {
1212 MesPrint("Reference to non-existing object number %ld\n",number+1);
1213 return(0);
1214 }
1215 j = number/NUMOBJECTS;
1216 i = number%NUMOBJECTS;
1217 obj = &(d->iblocks[j]->objects[i]);
1218 a = arguments;
1219 while ( *a ) a++;
1220 a++; n = a - arguments;
1221 if ( n > ELEMENTSIZE ) {
1222 MesPrint("Table element %s has more than %ld characters.\n",arguments,
1223 (MLONG)ELEMENTSIZE);
1224 return(-1);
1225 }
1226 s = obj->element;
1227 a = arguments;
1228 while ( *a ) *s++ = *a++;
1229 *s++ = 0;
1230 while ( n < ELEMENTSIZE ) { *s++ = 0; n++; }
1231 obj->spare1 = obj->spare2 = obj->spare3 = 0;
1232
1233 fseek(d->handle,0,SEEK_END);
1234 position = ftell(d->handle);
1235 s = rhs;
1236 while ( *s ) s++;
1237 s++;
1238 size = s - rhs;
1239#ifdef WITHZLIB
1240 if ( ( d->mode & NOCOMPRESS ) == 0 ) {
1241 newsize = size + size/1000 + 20;
1242 if ( ( buffer = (char *)Malloc1(newsize*sizeof(char),"compress buffer") )
1243 == 0 ) {
1244 MesPrint("No compress used for element %s in file %s\n",arguments,d->name);
1245 }
1246 }
1247 else buffer = 0;
1248 if ( buffer ) {
1249 ssize = size;
1250#ifdef WITHZSTD
1251 // Force the use of zlib for compressed Tablebase entries, so that tablebases created
1252 // with zstd-supported FORM builds can be used by zstd-unsupported FORM builds.
1253 const int old_isUsingZSTDcompression = ZWRAP_isUsingZSTDcompression();
1254 ZWRAP_useZSTDcompression(0);
1255#endif
1256 if ( ( error = compress((Bytef *)buffer,&newsize,(Bytef *)rhs,ssize) ) != Z_OK ) {
1257 MesPrint("Error = %d\n",error);
1258 MesPrint("Due to error no compress used for element %s in file %s\n",arguments,d->name);
1259 M_free(buffer,"tb,WriteObject");
1260 buffer = 0;
1261 }
1262#ifdef WITHZSTD
1263 ZWRAP_useZSTDcompression(old_isUsingZSTDcompression);
1264#endif
1265 }
1266 if ( buffer ) {
1267 rhs = buffer;
1268 oldsize = size;
1269 size = newsize;
1270 }
1271#endif
1272 if ( minoswrite(d->handle,rhs,size) ) {
1273 MesPrint("Error while writing rhs\n");
1274 return(-1);
1275 }
1276 obj->position = position;
1277 obj->size = size;
1278 obj->date = (MLONG)(time(0));
1279 obj->tablenumber = tablenumber;
1280#ifdef WITHZLIB
1281 obj->uncompressed = oldsize;
1282 if ( buffer ) M_free(buffer,"tb,WriteObject");
1283#else
1284 obj->uncompressed = 0;
1285#endif
1286 return(WriteIndexBlock(d,j));
1287}
1288
1289/*
1290 #] WriteObject :
1291 #[ ReadObject :
1292
1293 Returns a pointer to the proper rhs
1294*/
1295
1296char *ReadObject(DBASE *d,MLONG tablenumber,char *arguments)
1297{
1298 OBJECTS *obj;
1299 MLONG i, j;
1300 char *buffer1, *s, *t;
1301#ifdef WITHZLIB
1302 char *buffer2 = 0;
1303 uLongf finallength = 0;
1304#endif
1305 if ( tablenumber > d->topnumber ) {
1306 MesPrint("Reference to non-existing table number in tablebase %s: %ld\n",
1307 d->name,tablenumber);
1308 return(0);
1309 }
1310/*
1311 Start looking for the object
1312*/
1313 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1314 for ( j = 0; j < NUMOBJECTS; j++ ) {
1315 if ( d->iblocks[i]->objects[j].tablenumber != tablenumber ) continue;
1316 s = arguments; t = d->iblocks[i]->objects[j].element;
1317 while ( *s == *t && *s ) { s++; t++; }
1318 if ( *t == 0 && *s == 0 ) goto foundelement;
1319 }
1320 }
1321 s = d->tablenames; i = 1;
1322 while ( *s ) {
1323 if ( i == tablenumber ) break;
1324 while ( *s ) s++;
1325 s++;
1326 while ( *s ) s++;
1327 s++;
1328 i++;
1329 }
1330 MesPrint("%s(%s) not found in tablebase %s\n",s,arguments,d->name);
1331 return(0);
1332
1333foundelement:;
1334 obj = &(d->iblocks[i]->objects[j]);
1335 fseek(d->handle,obj->position,SEEK_SET);
1336 if ( ( buffer1 = (char *)Malloc1(obj->size,"reading rhs buffer1") ) == 0 ) {
1337 return(0);
1338 }
1339#ifdef WITHZLIB
1340 if ( obj->uncompressed > 0 ) {
1341 if ( ( buffer2 = (char *)Malloc1(obj->uncompressed,"reading rhs buffer2") ) == 0 ) {
1342 return(0);
1343 }
1344 }
1345 else buffer2 = 0;
1346#endif
1347 if ( minosread(d->handle,buffer1,obj->size) ) {
1348 MesPrint("Could not read rhs %s in file %s\n",arguments,d->name);
1349 M_free(buffer1,"tb,ReadObject");
1350#ifdef WITHZLIB
1351 if ( buffer2 ) M_free(buffer2,"tb,ReadObject");
1352#endif
1353 return(0);
1354 }
1355#ifdef WITHZLIB
1356 if ( buffer2 == 0 ) return(buffer1);
1357 finallength = obj->uncompressed;
1358 if ( uncompress((Bytef *)buffer2,&finallength,(Bytef *)buffer1,obj->size) != Z_OK ) {
1359 MesPrint("Cannot uncompress element %s in file %s\n",arguments,d->name);
1360 M_free(buffer1,"tb,ReadObject"); M_free(buffer2,"tb,ReadObject");
1361 return(0);
1362 }
1363 M_free(buffer1,"tb,ReadObject");
1364 return(buffer2);
1365#else
1366 return(buffer1);
1367#endif
1368}
1369
1370/*
1371 #] ReadObject :
1372 #[ ReadijObject :
1373
1374 Returns a pointer to the proper rhs
1375*/
1376
1377char *ReadijObject(DBASE *d,MLONG i,MLONG j,char *arguments)
1378{
1379 OBJECTS *obj;
1380 char *buffer1;
1381#ifdef WITHZLIB
1382 char *buffer2 = 0;
1383 uLongf finallength = 0;
1384#endif
1385 obj = &(d->iblocks[i]->objects[j]);
1386 fseek(d->handle,obj->position,SEEK_SET);
1387 if ( ( buffer1 = (char *)Malloc1(obj->size,"reading rhs buffer1") ) == 0 ) {
1388 return(0);
1389 }
1390#ifdef WITHZLIB
1391 if ( obj->uncompressed > 0 ) {
1392 if ( ( buffer2 = (char *)Malloc1(obj->uncompressed,"reading rhs buffer2") ) == 0 ) {
1393 return(0);
1394 }
1395 }
1396 else buffer2 = 0;
1397#endif
1398 if ( minosread(d->handle,buffer1,obj->size) ) {
1399 MesPrint("Could not read rhs %s in file %s\n",arguments,d->name);
1400 if ( buffer1 ) M_free(buffer1,"rhs buffer1");
1401#ifdef WITHZLIB
1402 if ( buffer2 ) M_free(buffer2,"rhs buffer2");
1403#endif
1404 return(0);
1405 }
1406#ifdef WITHZLIB
1407 if ( buffer2 == 0 ) return(buffer1);
1408 finallength = obj->uncompressed;
1409 if ( uncompress((Bytef *)buffer2,&finallength,(Bytef *)buffer1,obj->size) != Z_OK ) {
1410 MesPrint("Cannot uncompress element %s in file %s\n",arguments,d->name);
1411 if ( buffer1 ) M_free(buffer1,"rhs buffer1");
1412 if ( buffer2 ) M_free(buffer2,"rhs buffer2");
1413 return(0);
1414 }
1415 M_free(buffer1,"rhs buffer1");
1416 return(buffer2);
1417#else
1418 return(buffer1);
1419#endif
1420}
1421
1422/*
1423 #] ReadijObject :
1424 #[ ExistsObject :
1425
1426 Returns 1 if Object exists
1427*/
1428
1429int ExistsObject(DBASE *d,MLONG tablenumber,char *arguments)
1430{
1431 MLONG i, j;
1432 char *s, *t;
1433 if ( tablenumber > d->topnumber ) {
1434 MesPrint("Reference to non-existing table number in tablebase %s: %ld\n",
1435 d->name,tablenumber);
1436 return(0);
1437 }
1438/*
1439 Start looking for the object
1440*/
1441 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1442 for ( j = 0; j < NUMOBJECTS; j++ ) {
1443 if ( d->iblocks[i]->objects[j].tablenumber != tablenumber ) continue;
1444 s = arguments; t = d->iblocks[i]->objects[j].element;
1445 while ( *s == *t && *s ) { s++; t++; }
1446 if ( *t == 0 && *s == 0 ) return(1);
1447 }
1448 }
1449 return(0);
1450}
1451
1452/*
1453 #] ExistsObject :
1454 #[ DeleteObject :
1455
1456 Returns 1 if Object has been deleted.
1457 We leave a hole. Actually the object is still there but has been
1458 inactivated. It can be reactivated by calling this routine again.
1459*/
1460
1461int DeleteObject(DBASE *d,MLONG tablenumber,char *arguments)
1462{
1463 MLONG i, j;
1464 char *s, *t;
1465 if ( tablenumber > d->topnumber ) {
1466 MesPrint("Reference to non-existing table number in tablebase %s: %ld\n",
1467 d->name,tablenumber);
1468 return(0);
1469 }
1470/*
1471 Start looking for the object
1472*/
1473 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1474 for ( j = 0; j < NUMOBJECTS; j++ ) {
1475 if ( d->iblocks[i]->objects[j].tablenumber != tablenumber ) continue;
1476 s = arguments; t = d->iblocks[i]->objects[j].element;
1477 while ( *s == *t && *s ) { s++; t++; }
1478 if ( *t == 0 && *s == 0 ) {
1479 d->iblocks[i]->objects[j].tablenumber =
1480 -d->iblocks[i]->objects[j].tablenumber - 1;
1481 return(1);
1482 }
1483 }
1484 }
1485 return(0);
1486}
1487
1488/*
1489 #] DeleteObject :
1490*/
int size
Definition structs.h:207
UBYTE * argtail
Definition structs.h:354
Definition minos.h:123