FORM v5.0.0-35-g6318119
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 return(0);
626 }
627 d->tablenames = 0;
628 d->tablenamessize = 0;
629 d->topnumber = 0;
630 d->tablenamefill = 0;
631 d->rwmode = 1;
632
633 d->mode = 0;
634 if ( ( d->nblocks = (NAMESBLOCK **)Malloc1(sizeof(NAMESBLOCK *)*numnameblocks,
635 "new database") ) == 0 ) {
636 M_free(d->iblocks,"new database");
637 NumTableBases--;
638 return(0);
639 }
640 if ( ( f = fopen(name,"w+b") ) == 0 ) {
641 MesPrint("Could not create new file %s\n",name);
642 NumTableBases--;
643 return(0);
644 }
645/* setbuf(f,0); */
646 d->name = str_dup(name);
647 d->fullname = str_dup(name);
648 d->handle = f;
649
650 d->info.entriesinindex = number;
651 d->info.numberofindexblocks = numblocks;
652 d->info.numberofnamesblocks = numnameblocks;
653 d->info.firstindexblock = 0;
654 d->info.lastindexblock = 0;
655 d->info.numberoftables = 0;
656 d->info.firstnameblock = 0;
657 d->info.lastnameblock = 0;
658
659 if ( WriteIniInfo(d) ) {
660getout:
661 fclose(f);
662 remove(d->fullname);
663 if ( d->name ) { M_free(d->name,"name tablebase"); d->name = 0; }
664 if ( d->fullname ) { M_free(d->fullname,"fullname tablebase"); d->fullname = 0; }
665 M_free(d->nblocks,"new database");
666 M_free(d->iblocks,"new database");
667 NumTableBases--;
668 return(0);
669 }
670 for ( i = 0; i < numblocks; i++ ) {
671 if ( ( d->iblocks[i] = (INDEXBLOCK *)Malloc1(sizeof(INDEXBLOCK),
672 "index blocks of new database") ) == 0 ) {
673 while ( --i >= 0 ) M_free(d->iblocks[i],"index blocks of new database");
674 goto getout;
675 }
676 if ( i > 0 ) d->iblocks[i]->previousblock = d->iblocks[i-1]->position;
677 else d->iblocks[i]->previousblock = -1;
678 d->iblocks[i]->position = ftell(f);
679 // Initialise, to keep valgrind happy
680 d->iblocks[i]->flags = -1;
681/*----------change 10-feb-2003 */
682/*
683 Zero things properly. We don't want garbage in the file.
684*/
685 for ( j = 0; j < NUMOBJECTS; j++ ) {
686 d->iblocks[i]->objects[j].date = t;
687 d->iblocks[i]->objects[j].size = 0;
688 d->iblocks[i]->objects[j].position = -1;
689 d->iblocks[i]->objects[j].tablenumber = 0;
690 d->iblocks[i]->objects[j].uncompressed = 0;
691 d->iblocks[i]->objects[j].spare1 = 0;
692 d->iblocks[i]->objects[j].spare2 = 0;
693 d->iblocks[i]->objects[j].spare3 = 0;
694 for ( jj = 0; jj < ELEMENTSIZE; jj++ ) d->iblocks[i]->objects[j].element[jj] = 0;
695 }
696 convertblock(d->iblocks[i],&scratchblock,TODISK);
697 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
698 MesPrint("Error while writing new index blocks\n");
699 goto getout;
700 }
701 }
702 for ( i = 0; i < numnameblocks; i++ ) {
703 if ( ( d->nblocks[i] = (NAMESBLOCK *)Malloc1(sizeof(NAMESBLOCK),
704 "names blocks of new database") ) == 0 ) {
705 while ( --i >= 0 ) { M_free(d->nblocks[i],"names blocks of new database"); }
706 for ( i = 0; i < numblocks; i++ ) M_free(d->iblocks[i],"index blocks of new database");
707 goto getout;
708 }
709 if ( i > 0 ) d->nblocks[i]->previousblock = d->nblocks[i-1]->position;
710 else d->nblocks[i]->previousblock = -1;
711 d->nblocks[i]->position = ftell(f);
712 s = d->nblocks[i]->names;
713 for ( j = 0; j < NAMETABLESIZE; j++ ) *s++ = 0;
714 convertnamesblock(d->nblocks[i],&scratchnamesblock,TODISK);
715 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
716 MesPrint("Error while writing new names blocks\n");
717 for ( i = 0; i < numnameblocks; i++ ) M_free(d->nblocks[i],"names blocks of new database");
718 for ( i = 0; i < numblocks; i++ ) M_free(d->iblocks[i],"index blocks of new database");
719 goto getout;
720 }
721 }
722 d->info.firstindexblock = d->iblocks[0]->position;
723 d->info.lastindexblock = d->iblocks[numblocks-1]->position;
724 d->info.firstnameblock = d->nblocks[0]->position;
725 d->info.lastnameblock = d->nblocks[numnameblocks-1]->position;
726 if ( WriteIniInfo(d) ) {
727 for ( i = 0; i < numnameblocks; i++ ) M_free(d->nblocks[i],"names blocks of new database");
728 for ( i = 0; i < numblocks; i++ ) M_free(d->iblocks[i],"index blocks of new database");
729 goto getout;
730 }
731 return(d);
732}
733
734/*
735 #] NewDbase :
736 #[ FreeTableBase :
737*/
738
739void FreeTableBase(DBASE *d)
740{
741 int i, j, *old, *newL;
742 LIST *L;
743 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) M_free(d->nblocks[i],"nblocks[i]");
744 for ( i = 0; i < d->info.numberofindexblocks; i++ ) M_free(d->iblocks[i],"iblocks[i]");
745 M_free(d->nblocks,"nblocks");
746 M_free(d->iblocks,"iblocks");
747 if ( d->tablenames ) M_free(d->tablenames,"d->tablenames");
748 if ( d->name ) M_free(d->name,"d->name");
749 if ( d->fullname ) M_free(d->fullname,"d->fullname");
750 i = d - tablebases;
751 if ( i < ( NumTableBases - 1 ) ) {
752 L = &(AC.TableBaseList);
753 j = ( ( NumTableBases - i - 1 ) * L->size ) / sizeof(int);
754 old = (int *)d; newL = (int *)(d+1);
755 while ( --j >= 0 ) *newL++ = *old++;
756 j = L->size / sizeof(int);
757 while ( --j >= 0 ) *newL++ = 0;
758 }
759 NumTableBases--;
760 M_free(d,"tb,d");
761}
762
763/*
764 #] FreeTableBase :
765 #[ ComposeTableNames :
766
767 The nameblocks are supposed to be in memory.
768 Hence we have to go through them
769*/
770
771int ComposeTableNames(DBASE *d)
772{
773 MLONG nsize = 0;
774 int i, j, k;
775 char *s, *t, *ss;
776 d->topnumber = 0;
777 i = 0; s = d->nblocks[i]->names; j = NAMETABLESIZE;
778 while ( *s ) {
779 if ( *s ) d->topnumber++;
780 for ( k = 0; k < 2; k++ ) { /* name and argtail */
781 while ( *s ) {
782 j--;
783 if ( j <= 0 ) {
784 i++; if ( i >= d->info.numberofnamesblocks ) goto gotall;
785 s = d->nblocks[i]->names; j = NAMETABLESIZE;
786 }
787 else s++;
788 }
789 j--;
790 if ( j <= 0 ) {
791 i++; if ( i >= d->info.numberofnamesblocks ) goto gotall;
792 s = d->nblocks[i]->names; j = NAMETABLESIZE;
793 }
794 else s++;
795 }
796 }
797gotall:;
798 nsize = (d->info.numberofnamesblocks-1)*NAMETABLESIZE +
799 (s-d->nblocks[i]->names)+1;
800 if ( ( d->tablenames = (char *)Malloc1((2*nsize+30)*sizeof(char),"tablenames") )
801 == 0 ) { return(-1); }
802 t = d->tablenames;
803 d->tablenamessize = 2*nsize+30;
804 d->tablenamefill = nsize-1;
805 for ( k = 0; k < i; k++ ) {
806 ss = d->nblocks[k]->names;
807 for ( j = 0; j < NAMETABLESIZE; j++ ) *t++ = *ss++;
808 }
809 ss = d->nblocks[i]->names;
810 while ( ss < s ) *t++ = *ss++;
811 *t = 0;
812 return(0);
813}
814
815/*
816 #] ComposeTableNames :
817 #[ OpenDbase :
818*/
819
820DBASE *OpenDbase(char *filename)
821{
822 FILE *f;
823 DBASE *d;
824 char *newname;
825 if ( ( f = LocateBase(&filename,&newname,"r+b") ) == 0 ) {
826 MesPrint("Cannot open file %s\n",filename);
827 return(0);
828 }
829/* setbuf(f,0); */
830 d = (DBASE *)From0List(&(AC.TableBaseList));
831 d->name = filename; /* For the moment just for the error messages */
832 d->handle = f;
833 if ( ReadIniInfo(d) || ReadIndex(d) ) { M_free(d,"OpenDbase"); fclose(f); return(0); }
834 if ( ComposeTableNames(d) ) {
835 FreeTableBase(d);
836 fclose(f);
837 return(0);
838 }
839 d->name = str_dup(filename);
840 d->fullname = newname;
841 return(d);
842}
843
844/*
845 #] OpenDbase :
846 #[ AddTableName :
847
848 Adds a name of a table. Writes the namelist to disk.
849 Returns the number of this tablename in the database.
850 If the name was already in the table we return its value in negative.
851 Zero is an error!
852*/
853
854MLONG AddTableName(DBASE *d,char *name,TABLES T)
855{
856 char *s, *t, *tt;
857 int namesize, tailsize;
858 MLONG newsize, i, num;
859/*
860 First search for the name in what we have already
861*/
862 if ( d->tablenames ) {
863 num = 0;
864 s = d->tablenames;
865 while ( *s ) {
866 num++;
867 t = name;
868 while ( ( *s == *t ) && *t ) { s++; t++; }
869 if ( *s == *t ) { return(-num); }
870 while ( *s ) s++;
871 s++;
872 while ( *s ) s++;
873 s++;
874 }
875 }
876/*
877 This name has to be added
878*/
879 MesPrint("We add the name %s\n",name);
880 t = name;
881 while ( *t ) { t++; }
882 namesize = t-name;
883 if ( ( t = (char *)(T->argtail) ) != 0 ) {
884 while ( *t ) { t++; }
885 tailsize = t - (char *)(T->argtail);
886 }
887 else { tailsize = 0; }
888 if ( d->tablenames == 0 ) {
889 if ( ComposeTableNames(d) ) {
890 FreeTableBase(d);
891 M_free(d,"AddTableName");
892 return(0);
893 }
894 }
895 d->info.numberoftables++;
896 while ( ( d->tablenamefill+namesize+tailsize+3 > d->tablenamessize )
897 || ( d->tablenames == 0 ) ) {
898 newsize = 2*d->tablenamessize + 2*namesize + 2*tailsize + 6;
899 if ( ( t = (char *)Malloc1(newsize*sizeof(char),"AddTableName") ) == 0 )
900 return(0);
901 tt = t;
902 if ( d->tablenames ) {
903 s = d->tablenames;
904 for ( i = 0; i < d->tablenamefill; i++ ) *t++ = *s++;
905 *t = 0;
906 M_free(d->tablenames,"d->tablenames");
907 }
908 d->tablenames = tt;
909 d->tablenamessize = newsize;
910 }
911 s = d->tablenames + d->tablenamefill;
912 t = name;
913 while ( *t ) *s++ = *t++;
914 *s++ = 0;
915 t = (char *)(T->argtail);
916 while ( *t ) *s++ = *t++;
917 *s++ = 0;
918 *s = 0;
919 d->tablenamefill = s - d->tablenames;
920 d->topnumber++;
921/*
922 Now we have to synchronize
923*/
924 if ( PutTableNames(d) ) return(0);
925 return(d->topnumber);
926}
927
928/*
929 #] AddTableName :
930 #[ GetTableName :
931
932 Gets a name of a table.
933 Returns the number of this tablename in the database.
934 Zero -> error
935*/
936
937MLONG GetTableName(DBASE *d,char *name)
938{
939 char *s, *t;
940 MLONG num;
941/*
942 search for the name in what we have
943*/
944 if ( d->tablenames ) {
945 num = 0;
946 s = d->tablenames;
947 while ( *s ) {
948 num++;
949 t = name;
950 while ( ( *s == *t ) && *t ) { s++; t++; }
951 if ( *s == *t ) { return(num); }
952 while ( *s ) s++;
953 s++;
954 while ( *s ) s++;
955 s++;
956 }
957 }
958 return(0);
959}
960
961/*
962 #] GetTableName :
963 #[ PutTableNames :
964
965 Takes the names string in d->tablenames and puts it in the nblocks
966 pieces. Writes what has been changed to disk.
967*/
968
969int PutTableNames(DBASE *d)
970{
971 NAMESBLOCK **nnew;
972 int i, j, firstdif;
973 MLONG m;
974 char *s, *t;
975/*
976 Determine how many blocks are needed.
977*/
978 MLONG numblocks = d->tablenamefill/NAMETABLESIZE + 1;
979 if ( d->info.numberofnamesblocks < numblocks ) {
980/*
981 We need more blocks. First make sure of the space for nblocks.
982*/
983 if ( ( nnew = (NAMESBLOCK **)Malloc1(sizeof(NAMESBLOCK *)*numblocks,
984 "new names block") ) == 0 ) {
985 return(-1);
986 }
987 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
988 nnew[i] = d->nblocks[i];
989 }
990 free(d->nblocks);
991 d->nblocks = nnew;
992 for ( ; i < numblocks; i++ ) {
993 if ( ( d->nblocks[i] = (NAMESBLOCK *)Malloc1(sizeof(NAMESBLOCK),
994 "additional names blocks ") ) == 0 ) {
995 FreeTableBase(d);
996 return(-1);
997 }
998 d->nblocks[i]->previousblock = -1;
999 d->nblocks[i]->position = -1;
1000 s = d->nblocks[i]->names;
1001 for ( j = 0; j < NAMETABLESIZE; j++ ) *s++ = 0;
1002 }
1003 d->info.numberofnamesblocks = numblocks;
1004 }
1005/*
1006 Now look till where the new contents agree with the old.
1007*/
1008 firstdif = 0;
1009 i = 0; t = d->nblocks[i]->names; j = 0; s = d->tablenames;
1010 for ( m = 0; m < d->tablenamefill; m++ ) {
1011 if ( *s == *t ) {
1012 s++; t++; j++;
1013 if ( j >= NAMETABLESIZE ) {
1014 i++;
1015 t = d->nblocks[i]->names;
1016 j = 0;
1017 }
1018 }
1019 else {
1020 firstdif = i;
1021 for ( ; m < d->tablenamefill; m++ ) {
1022 *t++ = *s++; j++;
1023 if ( j >= NAMETABLESIZE ) {
1024 i++;
1025 t = d->nblocks[i]->names;
1026 j = 0;
1027 }
1028 }
1029 *t = 0;
1030 break;
1031 }
1032 }
1033 for ( i = 0; i < d->info.numberofnamesblocks; i++ ) {
1034 if ( i == firstdif ) break;
1035 if ( d->nblocks[i]->position < 0 ) { firstdif = i; break; }
1036 }
1037/*
1038 Now we have to (re)write the blocks, starting at firstdif.
1039*/
1040 for ( i = firstdif; i < d->info.numberofnamesblocks; i++ ) {
1041 if ( i > 0 ) d->nblocks[i]->previousblock = d->nblocks[i-1]->position;
1042 else d->nblocks[i]->previousblock = -1;
1043 if ( d->nblocks[i]->position < 0 ) {
1044 fseek(d->handle,0,SEEK_END);
1045 d->nblocks[i]->position = ftell(d->handle);
1046 }
1047 else fseek(d->handle,d->nblocks[i]->position,SEEK_SET);
1048 convertnamesblock(d->nblocks[i],&scratchnamesblock,TODISK);
1049 if ( minoswrite(d->handle,(char *)(&scratchnamesblock),sizeof(NAMESBLOCK)) ) {
1050 MesPrint("Error while writing names blocks\n");
1051 FreeTableBase(d);
1052 return(-1);
1053 }
1054 }
1055 d->info.lastnameblock = d->nblocks[d->info.numberofnamesblocks-1]->position;
1056 d->info.firstnameblock = d->nblocks[0]->position;
1057 return(WriteIniInfo(d));
1058}
1059
1060/*
1061 #] PutTableNames :
1062 #[ AddToIndex :
1063*/
1064
1065int AddToIndex(DBASE *d,MLONG number)
1066{
1067 MLONG i, oldnumofindexblocks = d->info.numberofindexblocks;
1068 MLONG j, newnumofindexblocks, jj;
1069 INDEXBLOCK **ib;
1070 MLONG t = (MLONG)(time(0));
1071 if ( number == 0 ) return(0);
1072 else if ( number < 0 ) {
1073 if ( d->info.entriesinindex < -number ) {
1074 MesPrint("There are only %ld entries in the index of file %s\n",
1075 d->info.entriesinindex,d->name);
1076 return(-1);
1077 }
1078 d->info.entriesinindex += number;
1079dowrite:
1080 if ( WriteIniInfo(d) ) {
1081 d->info.entriesinindex -= number;
1082 MesPrint("File may be corrupted\n");
1083 return(-1);
1084 }
1085 }
1086 else if ( d->info.entriesinindex+number <=
1087 NUMOBJECTS*d->info.numberofindexblocks ) {
1088 d->info.entriesinindex += number;
1089 goto dowrite;
1090 }
1091 else {
1092 d->info.entriesinindex += number;
1093 newnumofindexblocks = d->info.numberofindexblocks + ((number -
1094 (NUMOBJECTS*d->info.numberofindexblocks - d->info.entriesinindex))
1095 +NUMOBJECTS-1)/NUMOBJECTS;
1096 if ( ( ib = (INDEXBLOCK **)Malloc1(sizeof(INDEXBLOCK *)*newnumofindexblocks,
1097 "index") ) == 0 ) return(-1);
1098 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1099 ib[i] = d->iblocks[i];
1100 }
1101 for ( i = d->info.numberofindexblocks; i < newnumofindexblocks; i++ ) {
1102 if ( ( ib[i] = (INDEXBLOCK *)Malloc1(sizeof(INDEXBLOCK),"index block") ) == 0 ) {
1103 FreeTableBase(d);
1104 return(-1);
1105 }
1106 if ( i > 0 ) ib[i]->previousblock = ib[i-1]->position;
1107 else ib[i]->previousblock = -1;
1108/*
1109 Zero things properly. We don't want garbage in the file.
1110*/
1111 for ( j = 0; j < NUMOBJECTS; j++ ) {
1112 ib[i]->objects[j].date = t;
1113 ib[i]->objects[j].size = 0;
1114 ib[i]->objects[j].position = -1;
1115 ib[i]->objects[j].tablenumber = 0;
1116 ib[i]->objects[j].uncompressed = 0;
1117 ib[i]->objects[j].spare1 = 0;
1118 ib[i]->objects[j].spare2 = 0;
1119 ib[i]->objects[j].spare3 = 0;
1120 for ( jj = 0; jj < ELEMENTSIZE; jj++ ) ib[i]->objects[j].element[jj] = 0;
1121 }
1122 fseek(d->handle,0,SEEK_END);
1123 ib[i]->position = ftell(d->handle);
1124 convertblock(ib[i],&scratchblock,TODISK);
1125 if ( minoswrite(d->handle,(char *)(&scratchblock),sizeof(INDEXBLOCK)) ) {
1126 MesPrint("Error while writing new index of file %s",d->name);
1127 FreeTableBase(d);
1128 return(-1);
1129 }
1130 }
1131 d->info.lastindexblock = ib[newnumofindexblocks-1]->position;
1132 d->info.firstindexblock = ib[0]->position;
1133 d->info.numberofindexblocks = newnumofindexblocks;
1134 if ( WriteIniInfo(d) ) {
1135 d->info.numberofindexblocks = oldnumofindexblocks;
1136 d->info.entriesinindex -= number;
1137 MesPrint("File may be corrupted\n");
1138 FreeTableBase(d);
1139 return(-1);
1140 }
1141 M_free(d->iblocks,"AddToIndex");
1142 d->iblocks = ib;
1143 }
1144 return(0);
1145}
1146
1147/*
1148 #] AddToIndex :
1149 #[ AddObject :
1150*/
1151
1152MLONG AddObject(DBASE *d,MLONG tablenumber,char *arguments,char *rhs)
1153{
1154 MLONG number;
1155 number = d->info.entriesinindex;
1156 if ( AddToIndex(d,1) ) return(-1);
1157 if ( WriteObject(d,tablenumber,arguments,rhs,number) ) return(-1);
1158 return(number);
1159}
1160
1161/*
1162 #] AddObject :
1163 #[ FindTableNumber :
1164*/
1165
1166MLONG FindTableNumber(DBASE *d,char *name)
1167{
1168 char *s = d->tablenames, *t, *ss;
1169 MLONG num = 0;
1170 ss = d->tablenames + d->tablenamefill;
1171 while ( s < ss ) {
1172 num++;
1173 t = name;
1174 while ( *s == *t && *t ) {
1175 s++; t++;
1176 }
1177 if ( *s == 0 && *t == 0 ) return(num);
1178 while ( *s ) s++;
1179 s++;
1180/*
1181 Skip also the argument tail
1182*/
1183 while ( *s ) s++;
1184 s++;
1185 }
1186 return(-1); /* Name not found */
1187}
1188
1189/*
1190 #] FindTableNumber :
1191 #[ WriteObject :
1192*/
1193
1194int WriteObject(DBASE *d,MLONG tablenumber,char *arguments,char *rhs,MLONG number)
1195{
1196 char *s, *a;
1197#ifdef WITHZLIB
1198 char *buffer = 0;
1199 uLongf newsize = 0, oldsize = 0;
1200 uLong ssize;
1201 int error = 0;
1202#endif
1203 MLONG i, j, position, size, n;
1204 OBJECTS *obj;
1205 if ( ( d->mode & INPUTONLY ) == INPUTONLY ) {
1206 MesPrint("Not allowed to write to input\n");
1207 return(-1);
1208 }
1209 if ( number >= d->info.entriesinindex ) {
1210 MesPrint("Reference to non-existing object number %ld\n",number+1);
1211 return(0);
1212 }
1213 j = number/NUMOBJECTS;
1214 i = number%NUMOBJECTS;
1215 obj = &(d->iblocks[j]->objects[i]);
1216 a = arguments;
1217 while ( *a ) a++;
1218 a++; n = a - arguments;
1219 if ( n > ELEMENTSIZE ) {
1220 MesPrint("Table element %s has more than %ld characters.\n",arguments,
1221 (MLONG)ELEMENTSIZE);
1222 return(-1);
1223 }
1224 s = obj->element;
1225 a = arguments;
1226 while ( *a ) *s++ = *a++;
1227 *s++ = 0;
1228 while ( n < ELEMENTSIZE ) { *s++ = 0; n++; }
1229 obj->spare1 = obj->spare2 = obj->spare3 = 0;
1230
1231 fseek(d->handle,0,SEEK_END);
1232 position = ftell(d->handle);
1233 s = rhs;
1234 while ( *s ) s++;
1235 s++;
1236 size = s - rhs;
1237#ifdef WITHZLIB
1238 if ( ( d->mode & NOCOMPRESS ) == 0 ) {
1239 newsize = size + size/1000 + 20;
1240 if ( ( buffer = (char *)Malloc1(newsize*sizeof(char),"compress buffer") )
1241 == 0 ) {
1242 MesPrint("No compress used for element %s in file %s\n",arguments,d->name);
1243 }
1244 }
1245 else buffer = 0;
1246 if ( buffer ) {
1247 ssize = size;
1248#ifdef WITHZSTD
1249 // Force the use of zlib for compressed Tablebase entries, so that tablebases created
1250 // with zstd-supported FORM builds can be used by zstd-unsupported FORM builds.
1251 const int old_isUsingZSTDcompression = ZWRAP_isUsingZSTDcompression();
1252 ZWRAP_useZSTDcompression(0);
1253#endif
1254 if ( ( error = compress((Bytef *)buffer,&newsize,(Bytef *)rhs,ssize) ) != Z_OK ) {
1255 MesPrint("Error = %d\n",error);
1256 MesPrint("Due to error no compress used for element %s in file %s\n",arguments,d->name);
1257 M_free(buffer,"tb,WriteObject");
1258 buffer = 0;
1259 }
1260#ifdef WITHZSTD
1261 ZWRAP_useZSTDcompression(old_isUsingZSTDcompression);
1262#endif
1263 }
1264 if ( buffer ) {
1265 rhs = buffer;
1266 oldsize = size;
1267 size = newsize;
1268 }
1269#endif
1270 if ( minoswrite(d->handle,rhs,size) ) {
1271 MesPrint("Error while writing rhs\n");
1272 return(-1);
1273 }
1274 obj->position = position;
1275 obj->size = size;
1276 obj->date = (MLONG)(time(0));
1277 obj->tablenumber = tablenumber;
1278#ifdef WITHZLIB
1279 obj->uncompressed = oldsize;
1280 if ( buffer ) M_free(buffer,"tb,WriteObject");
1281#else
1282 obj->uncompressed = 0;
1283#endif
1284 return(WriteIndexBlock(d,j));
1285}
1286
1287/*
1288 #] WriteObject :
1289 #[ ReadObject :
1290
1291 Returns a pointer to the proper rhs
1292*/
1293
1294char *ReadObject(DBASE *d,MLONG tablenumber,char *arguments)
1295{
1296 OBJECTS *obj;
1297 MLONG i, j;
1298 char *buffer1, *s, *t;
1299#ifdef WITHZLIB
1300 char *buffer2 = 0;
1301 uLongf finallength = 0;
1302#endif
1303 if ( tablenumber > d->topnumber ) {
1304 MesPrint("Reference to non-existing table number in tablebase %s: %ld\n",
1305 d->name,tablenumber);
1306 return(0);
1307 }
1308/*
1309 Start looking for the object
1310*/
1311 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1312 for ( j = 0; j < NUMOBJECTS; j++ ) {
1313 if ( d->iblocks[i]->objects[j].tablenumber != tablenumber ) continue;
1314 s = arguments; t = d->iblocks[i]->objects[j].element;
1315 while ( *s == *t && *s ) { s++; t++; }
1316 if ( *t == 0 && *s == 0 ) goto foundelement;
1317 }
1318 }
1319 s = d->tablenames; i = 1;
1320 while ( *s ) {
1321 if ( i == tablenumber ) break;
1322 while ( *s ) s++;
1323 s++;
1324 while ( *s ) s++;
1325 s++;
1326 i++;
1327 }
1328 MesPrint("%s(%s) not found in tablebase %s\n",s,arguments,d->name);
1329 return(0);
1330
1331foundelement:;
1332 obj = &(d->iblocks[i]->objects[j]);
1333 fseek(d->handle,obj->position,SEEK_SET);
1334 if ( ( buffer1 = (char *)Malloc1(obj->size,"reading rhs buffer1") ) == 0 ) {
1335 return(0);
1336 }
1337#ifdef WITHZLIB
1338 if ( obj->uncompressed > 0 ) {
1339 if ( ( buffer2 = (char *)Malloc1(obj->uncompressed,"reading rhs buffer2") ) == 0 ) {
1340 return(0);
1341 }
1342 }
1343 else buffer2 = 0;
1344#endif
1345 if ( minosread(d->handle,buffer1,obj->size) ) {
1346 MesPrint("Could not read rhs %s in file %s\n",arguments,d->name);
1347 M_free(buffer1,"tb,ReadObject");
1348#ifdef WITHZLIB
1349 if ( buffer2 ) M_free(buffer2,"tb,ReadObject");
1350#endif
1351 return(0);
1352 }
1353#ifdef WITHZLIB
1354 if ( buffer2 == 0 ) return(buffer1);
1355 finallength = obj->uncompressed;
1356 if ( uncompress((Bytef *)buffer2,&finallength,(Bytef *)buffer1,obj->size) != Z_OK ) {
1357 MesPrint("Cannot uncompress element %s in file %s\n",arguments,d->name);
1358 M_free(buffer1,"tb,ReadObject"); M_free(buffer2,"tb,ReadObject");
1359 return(0);
1360 }
1361 M_free(buffer1,"tb,ReadObject");
1362 return(buffer2);
1363#else
1364 return(buffer1);
1365#endif
1366}
1367
1368/*
1369 #] ReadObject :
1370 #[ ReadijObject :
1371
1372 Returns a pointer to the proper rhs
1373*/
1374
1375char *ReadijObject(DBASE *d,MLONG i,MLONG j,char *arguments)
1376{
1377 OBJECTS *obj;
1378 char *buffer1;
1379#ifdef WITHZLIB
1380 char *buffer2 = 0;
1381 uLongf finallength = 0;
1382#endif
1383 obj = &(d->iblocks[i]->objects[j]);
1384 fseek(d->handle,obj->position,SEEK_SET);
1385 if ( ( buffer1 = (char *)Malloc1(obj->size,"reading rhs buffer1") ) == 0 ) {
1386 return(0);
1387 }
1388#ifdef WITHZLIB
1389 if ( obj->uncompressed > 0 ) {
1390 if ( ( buffer2 = (char *)Malloc1(obj->uncompressed,"reading rhs buffer2") ) == 0 ) {
1391 return(0);
1392 }
1393 }
1394 else buffer2 = 0;
1395#endif
1396 if ( minosread(d->handle,buffer1,obj->size) ) {
1397 MesPrint("Could not read rhs %s in file %s\n",arguments,d->name);
1398 if ( buffer1 ) M_free(buffer1,"rhs buffer1");
1399#ifdef WITHZLIB
1400 if ( buffer2 ) M_free(buffer2,"rhs buffer2");
1401#endif
1402 return(0);
1403 }
1404#ifdef WITHZLIB
1405 if ( buffer2 == 0 ) return(buffer1);
1406 finallength = obj->uncompressed;
1407 if ( uncompress((Bytef *)buffer2,&finallength,(Bytef *)buffer1,obj->size) != Z_OK ) {
1408 MesPrint("Cannot uncompress element %s in file %s\n",arguments,d->name);
1409 if ( buffer1 ) M_free(buffer1,"rhs buffer1");
1410 if ( buffer2 ) M_free(buffer2,"rhs buffer2");
1411 return(0);
1412 }
1413 M_free(buffer1,"rhs buffer1");
1414 return(buffer2);
1415#else
1416 return(buffer1);
1417#endif
1418}
1419
1420/*
1421 #] ReadijObject :
1422 #[ ExistsObject :
1423
1424 Returns 1 if Object exists
1425*/
1426
1427int ExistsObject(DBASE *d,MLONG tablenumber,char *arguments)
1428{
1429 MLONG i, j;
1430 char *s, *t;
1431 if ( tablenumber > d->topnumber ) {
1432 MesPrint("Reference to non-existing table number in tablebase %s: %ld\n",
1433 d->name,tablenumber);
1434 return(0);
1435 }
1436/*
1437 Start looking for the object
1438*/
1439 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1440 for ( j = 0; j < NUMOBJECTS; j++ ) {
1441 if ( d->iblocks[i]->objects[j].tablenumber != tablenumber ) continue;
1442 s = arguments; t = d->iblocks[i]->objects[j].element;
1443 while ( *s == *t && *s ) { s++; t++; }
1444 if ( *t == 0 && *s == 0 ) return(1);
1445 }
1446 }
1447 return(0);
1448}
1449
1450/*
1451 #] ExistsObject :
1452 #[ DeleteObject :
1453
1454 Returns 1 if Object has been deleted.
1455 We leave a hole. Actually the object is still there but has been
1456 inactivated. It can be reactivated by calling this routine again.
1457*/
1458
1459int DeleteObject(DBASE *d,MLONG tablenumber,char *arguments)
1460{
1461 MLONG i, j;
1462 char *s, *t;
1463 if ( tablenumber > d->topnumber ) {
1464 MesPrint("Reference to non-existing table number in tablebase %s: %ld\n",
1465 d->name,tablenumber);
1466 return(0);
1467 }
1468/*
1469 Start looking for the object
1470*/
1471 for ( i = 0; i < d->info.numberofindexblocks; i++ ) {
1472 for ( j = 0; j < NUMOBJECTS; j++ ) {
1473 if ( d->iblocks[i]->objects[j].tablenumber != tablenumber ) continue;
1474 s = arguments; t = d->iblocks[i]->objects[j].element;
1475 while ( *s == *t && *s ) { s++; t++; }
1476 if ( *t == 0 && *s == 0 ) {
1477 d->iblocks[i]->objects[j].tablenumber =
1478 -d->iblocks[i]->objects[j].tablenumber - 1;
1479 return(1);
1480 }
1481 }
1482 }
1483 return(0);
1484}
1485
1486/*
1487 #] DeleteObject :
1488*/
int size
Definition structs.h:207
UBYTE * argtail
Definition structs.h:354
Definition minos.h:123