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