/**************************************** * Computer Algebra System SINGULAR * ****************************************/ //**************************************************************************/ // // $Id: ndbm.cc,v 1.10 1998-06-02 15:30:00 Singular Exp $ // //**************************************************************************/ // 'ndbm.cc' containes all low-level functions to manipulate dbm-files // for the original Copyright of this file and 'ndbm.h' see below . // // some minor change where needed to compile and run under MacOS/MPW // //**************************************************************************/ #include "mod2.h" #ifdef HAVE_DBM /* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)ndbm.c 5.3 (Berkeley) 3/9/86"; #endif LIBC_SCCS and not lint //**************************************************************************/ #include #ifdef __MWERKS__ # define bcopy(a,b,c) memmove(b,a,c) # define EPERM 1 # define ENOMEM 23 # define ENOSPC 28 # define L_SET SEEK_SET #ifdef macintosh # include # include # include "fcntl.h" # include # include //# include #else # include # include #endif #else # include # include # include # include # include # include # include # include #endif #ifndef HAVE_BCOPY # define bcopy(a,b,c) memmove(b,a,c) #endif /* not HAVE_BCOPY */ #include "ndbm.h" #define BYTESIZ 8 #undef setbit static void dbm_access(register DBM *db, long hash); static int getbit(register DBM *db); static void setbit(register DBM *db); static datum makdatum(char buf[PBLKSIZ], int n); static int finddatum(char buf[PBLKSIZ], datum item); static long hashinc(register DBM *db, long hash); static long dcalchash(datum item); static int delitem(char buf[PBLKSIZ], int n); static int additem(char buf[PBLKSIZ], datum item, datum item1); #if defined(__MWERKS__) && ! defined(macintosh) #define errno (_GetThreadLocalData()->errno) #else extern int errno; #endif DBM * dbm_open(char *file, int flags, int mode) { struct stat statb; register DBM *db; if ((db = (DBM *)malloc(sizeof *db)) == 0) { errno = ENOMEM; return ((DBM *)0); } #ifdef macintosh // It seems that the compile has some problems to commit the flags properly // O_RDWR | O_CREAT = 0x102 change to 0x200. We don't know why. // setting flags to O_RDWR | O_CREAT solved our problem. :-( flags = O_RDWR | O_CREAT; #endif /* macintosh */ #ifdef MSDOS // default mode of open is ascii, we need binary mode. flags |= O_BINARY; #endif db->dbm_flags = (flags & 03) == O_RDONLY ? _DBM_RDONLY : 0; if ((flags & 03) == O_WRONLY) flags = (flags & ~03) | O_RDWR; strcpy(db->dbm_pagbuf, file); strcat(db->dbm_pagbuf, ".pag"); #ifdef __MWERKS__ db->dbm_pagf = open(db->dbm_pagbuf, flags); #else /* not __MWERKS__ */ db->dbm_pagf = open(db->dbm_pagbuf, flags, mode); #endif /* __MWERKS__ */ if (db->dbm_pagf < 0) goto bad; strcpy(db->dbm_pagbuf, file); strcat(db->dbm_pagbuf, ".dir"); #ifdef __MWERKS__ db->dbm_dirf = open(db->dbm_pagbuf, flags); #else /* not __MWERKS__ */ db->dbm_dirf = open(db->dbm_pagbuf, flags, mode); #endif /* __MWERKS__ */ if (db->dbm_dirf < 0) goto bad1; fstat(db->dbm_dirf, &statb); db->dbm_maxbno = statb.st_size*BYTESIZ-1; db->dbm_pagbno = db->dbm_dirbno = -1; return (db); bad1: (void) close(db->dbm_pagf); bad: free((char *)db); return ((DBM *)0); } void dbm_close(DBM *db) { (void) close(db->dbm_dirf); (void) close(db->dbm_pagf); free((char *)db); } long dbm_forder(register DBM *db, datum key) { long hash; hash = dcalchash(key); for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { db->dbm_blkno = hash & db->dbm_hmask; db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; if (getbit(db) == 0) break; } return (db->dbm_blkno); } datum dbm_fetch(register DBM *db, datum key) { register i; datum item; if (dbm_error(db)) goto err; dbm_access(db, dcalchash(key)); if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { item = makdatum(db->dbm_pagbuf, i+1); if (item.dptr != NULL) return (item); } err: item.dptr = NULL; item.dsize = 0; return (item); } int dbm_delete(register DBM *db, datum key) { register i; datum item; if (dbm_error(db)) return (-1); if (dbm_rdonly(db)) { errno = EPERM; return (-1); } dbm_access(db, dcalchash(key)); if ((i = finddatum(db->dbm_pagbuf, key)) < 0) return (-1); if (!delitem(db->dbm_pagbuf, i)) goto err; db->dbm_pagbno = db->dbm_blkno; (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { err: db->dbm_flags |= _DBM_IOERR; return (-1); } return (0); } int dbm_store(register DBM *db, datum key, datum dat, int replace) { register i; int ret; datum item, item1; char ovfbuf[PBLKSIZ]; if (dbm_error(db)) return (-1); if (dbm_rdonly(db)) { errno = EPERM; return (-1); } loop: dbm_access(db, dcalchash(key)); if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { if (!replace) return (1); if (!delitem(db->dbm_pagbuf, i)) { db->dbm_flags |= _DBM_IOERR; return (-1); } } if (!additem(db->dbm_pagbuf, key, dat)) goto split; db->dbm_pagbno = db->dbm_blkno; (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); if ( (ret=write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ)) != PBLKSIZ) { db->dbm_flags |= _DBM_IOERR; return (-1); } return (0); split: if (key.dsize+dat.dsize+3*sizeof(short) >= PBLKSIZ) { db->dbm_flags |= _DBM_IOERR; errno = ENOSPC; return (-1); } memset(ovfbuf, 0, PBLKSIZ); for (i=0;;) { item = makdatum(db->dbm_pagbuf, i); if (item.dptr == NULL) break; if (dcalchash(item) & (db->dbm_hmask+1)) { item1 = makdatum(db->dbm_pagbuf, i+1); if (item1.dptr == NULL) { fprintf(stderr, "ndbm: split not paired\n"); db->dbm_flags |= _DBM_IOERR; break; } if (!additem(ovfbuf, item, item1) || !delitem(db->dbm_pagbuf, i)) { db->dbm_flags |= _DBM_IOERR; return (-1); } continue; } i += 2; } db->dbm_pagbno = db->dbm_blkno; (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { db->dbm_flags |= _DBM_IOERR; return (-1); } (void) lseek(db->dbm_pagf, (db->dbm_blkno+db->dbm_hmask+1)*PBLKSIZ, L_SET); if (write(db->dbm_pagf, ovfbuf, PBLKSIZ) != PBLKSIZ) { db->dbm_flags |= _DBM_IOERR; return (-1); } setbit(db); goto loop; } datum dbm_firstkey(DBM *db) { db->dbm_blkptr = 0L; db->dbm_keyptr = 0; return (dbm_nextkey(db)); } datum dbm_nextkey(register DBM *db) { struct stat statb; datum item; if (dbm_error(db) || fstat(db->dbm_pagf, &statb) < 0) goto err; statb.st_size /= PBLKSIZ; for (;;) { if (db->dbm_blkptr != db->dbm_pagbno) { db->dbm_pagbno = db->dbm_blkptr; (void) lseek(db->dbm_pagf, db->dbm_blkptr*PBLKSIZ, L_SET); if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) memset(db->dbm_pagbuf, 0, PBLKSIZ); #ifdef DEBUG else if (chkblk(db->dbm_pagbuf) < 0) db->dbm_flags |= _DBM_IOERR; #endif } if (((short *)db->dbm_pagbuf)[0] != 0) { item = makdatum(db->dbm_pagbuf, db->dbm_keyptr); if (item.dptr != NULL) { db->dbm_keyptr += 2; return (item); } db->dbm_keyptr = 0; } if (++db->dbm_blkptr >= statb.st_size) break; } err: item.dptr = NULL; item.dsize = 0; return (item); } static void dbm_access(register DBM *db, long hash) { for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { db->dbm_blkno = hash & db->dbm_hmask; db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; if (getbit(db) == 0) break; } if (db->dbm_blkno != db->dbm_pagbno) { db->dbm_pagbno = db->dbm_blkno; (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) memset(db->dbm_pagbuf, 0, PBLKSIZ); #ifdef DEBUG else if (chkblk(db->dbm_pagbuf) < 0) db->dbm_flags |= _DBM_IOERR; #endif } } static int getbit(register DBM *db) { long bn; register b, i, n; if (db->dbm_bitno > db->dbm_maxbno) return (0); n = db->dbm_bitno % BYTESIZ; bn = db->dbm_bitno / BYTESIZ; i = bn % DBLKSIZ; b = bn / DBLKSIZ; if (b != db->dbm_dirbno) { db->dbm_dirbno = b; (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) memset(db->dbm_dirbuf, 0, DBLKSIZ); } return (db->dbm_dirbuf[i] & (1<dbm_bitno > db->dbm_maxbno) db->dbm_maxbno = db->dbm_bitno; n = db->dbm_bitno % BYTESIZ; bn = db->dbm_bitno / BYTESIZ; i = bn % DBLKSIZ; b = bn / DBLKSIZ; if (b != db->dbm_dirbno) { db->dbm_dirbno = b; (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) memset(db->dbm_dirbuf, 0, DBLKSIZ); } db->dbm_dirbuf[i] |= 1<dbm_dirbno = b; (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); if (write(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) db->dbm_flags |= _DBM_IOERR; } static datum makdatum(char buf[PBLKSIZ], int n) { register short *sp; register t; datum item; sp = (short *)buf; if ((unsigned)n >= (unsigned)sp[0]) { item.dptr = NULL; item.dsize = 0; return (item); } t = PBLKSIZ; if (n > 0) t = sp[n]; item.dptr = buf+sp[n+1]; item.dsize = t - sp[n+1]; return (item); } static int finddatum(char buf[PBLKSIZ], datum item) { register short *sp; register int i, n, j; sp = (short *)buf; n = PBLKSIZ; for (i=0, j=sp[0]; idbm_hmask; bit = db->dbm_hmask+1; for (;;) { bit >>= 1; if (bit == 0) return (0L); if ((hash & bit) == 0) return (hash | bit); hash &= ~bit; } } static long dcalchash(datum item) { register int s, c, j; register char *cp; register long hashl; register int hashi; hashl = 0; hashi = 0; for (cp = item.dptr, s=item.dsize; --s >= 0; ) { c = *cp++; for (j=0; j>= 4; } } return (hashl); } /* * Delete pairs of items (n & n+1). */ static int delitem(char buf[PBLKSIZ], int n) { register short *sp, *sp1; register int i1, i2; sp = (short *)buf; i2 = sp[0]; if ((unsigned)n >= (unsigned)i2 || (n & 1)) return (0); if (n == i2-2) { sp[0] -= 2; return (1); } i1 = PBLKSIZ; if (n > 0) i1 = sp[n]; i1 -= sp[n+2]; if (i1 > 0) { i2 = sp[i2]; bcopy(&buf[i2], &buf[i2 + i1], sp[n+2] - i2); } sp[0] -= 2; for (sp1 = sp + sp[0], sp += n+1; sp <= sp1; sp++) sp[0] = sp[2] + i1; return (1); } /* * Add pairs of items (item & item1). */ static int additem(char buf[PBLKSIZ], datum item, datum item1) { register short *sp; register i1, i2, tmp; sp = (short *)buf; i1 = PBLKSIZ; i2 = sp[0]; if (i2 > 0) i1 = sp[i2]; i1 -= item.dsize + item1.dsize; tmp = (i2+3) * sizeof(short); if (i1 <= tmp) return (0); sp[0] += 2; sp[++i2] = i1 + item1.dsize; bcopy(item.dptr, &buf[i1 + item1.dsize], item.dsize); sp[++i2] = i1; bcopy(item1.dptr, &buf[i1], item1.dsize); return (1); } #ifdef DEBUG static chkblk(char buf[PBLKSIZ]) { register short *sp; register t, i; sp = (short *)buf; t = PBLKSIZ; for (i=0; i t) return (-1); t = sp[i+1]; } if (t < (sp[0]+1)*sizeof(short)) return (-1); return (0); } #endif #endif /* HAVE_DBM */