#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#ifndef __STDC__
extern int errno;
#endif
#include <dbz.h>
#ifdef FUNNYSEEKS
#include <unistd.h>
#else
#define SEEK_SET 0
#endif
#ifdef OVERFLOW
#include <limits.h>
#endif
static int dbzversion = 3;
#ifdef INDEX_SIZE
#define DEFSIZE INDEX_SIZE
#endif
#define SOF (sizeof(off_t))
#define VACANT ((off_t)0)
#define BIAS(o) ((o)+1)
#define UNBIAS(o) ((o)-1)
static off_t tagbits;
static off_t taghere;
static off_t tagboth;
#define HASTAG(o) ((o)&taghere)
#define TAG(o) ((o)&tagbits)
#define NOTAG(o) ((o)&~tagboth)
#define CANTAG(o) (((o)&tagboth) == 0)
#define MKTAG(v) (((v)<<conf.tagshift)&tagbits)
#ifndef DEFSIZE
#define DEFSIZE 120011
#endif
#ifdef OLDBNEWS
#define DEFCASE '0'
#define NOBUFFER
#endif
#ifdef BNEWS
#define DEFCASE '='
#define NOBUFFER
#endif
#ifndef DEFCASE
#define DEFCASE 'C'
#endif
#ifndef NOTAGS
#define TAGENB 0x80
#define TAGMASK 0x7f
#define TAGSHIFT 24
#else
#define TAGENB 0
#define TAGMASK 0
#define TAGSHIFT 0
#endif
struct dbzconfig {
int olddbz;
off_t tsize;
# ifndef NMEMORY
# define NMEMORY 10
# endif
# define NUSEDS (1+NMEMORY)
off_t used[NUSEDS];
int valuesize;
int bytemap[SOF];
char casemap;
char fieldsep;
off_t tagenb;
off_t tagmask;
int tagshift;
};
static struct dbzconfig conf;
static int getconf();
static long getno();
static int putconf();
static void mybytemap();
static off_t bytemap();
#ifdef INCORE
static int incore = 1;
#else
static int incore = 0;
#endif
#ifndef NPAGBUF
#define NPAGBUF 16
#endif
#ifndef NOBUFFER
#ifdef _IOFBF
static off_t pagbuf[NPAGBUF];
#endif
#endif
#ifndef SHISTBUF
#define SHISTBUF 64
#endif
#ifdef _IOFBF
static char basebuf[SHISTBUF];
#endif
struct searcher {
off_t place;
int tabno;
int run;
# ifndef MAXRUN
# define MAXRUN 100
# endif
long hash;
off_t tag;
int seen;
int aborted;
};
static void start();
#define FRESH ((struct searcher *)NULL)
static off_t search();
#define NOTFOUND ((off_t)-1)
static int okayvalue();
static int set();
static struct searcher srch;
static struct searcher *prevp;
static int mybmap[SOF];
static int bytesame;
#define MAPIN(o) ((bytesame) ? (o) : bytemap((o), conf.bytemap, mybmap))
#define MAPOUT(o) ((bytesame) ? (o) : bytemap((o), mybmap, conf.bytemap))
static int debug;
#ifdef DBZDEBUG
#define DEBUG(args) if (debug) { (void) printf args ; }
#else
#define DEBUG(args) ;
#endif
extern char *malloc();
extern char *calloc();
extern void free();
extern int atoi();
extern long atol();
static long hash();
static void crcinit();
static char *cipoint();
static char *mapcase();
static int isprime();
static FILE *latebase();
static char dir[] = ".dir";
static char pag[] = ".pag";
static char *enstring();
static FILE *basef;
static char *basefname;
static FILE *dirf;
static int dirronly;
static FILE *pagf = NULL;
static off_t pagpos;
static int pagronly;
static off_t *corepag;
static FILE *bufpagf;
static off_t *getcore();
static int putcore();
static int written;
int
dbzfresh(name, size, fs, cmap, tagmask)
char *name;
long size;
int fs;
int cmap;
off_t tagmask;
{
register char *fn;
struct dbzconfig c;
register off_t m;
register FILE *f;
if (pagf != NULL) {
DEBUG(("dbzfresh: database already open\n"));
return(-1);
}
if (size != 0 && size < 2) {
DEBUG(("dbzfresh: preposterous size (%ld)\n", size));
return(-1);
}
if (getconf((FILE *)NULL, (FILE *)NULL, &c) < 0)
return(-1);
if (size != 0)
c.tsize = size;
c.fieldsep = fs;
switch (cmap) {
case 0:
case '0':
case 'B':
c.casemap = '0';
break;
case '=':
case 'b':
c.casemap = '=';
break;
case 'C':
c.casemap = 'C';
break;
case '?':
c.casemap = DEFCASE;
break;
default:
DEBUG(("dbzfresh case map `%c' unknown\n", cmap));
return(-1);
break;
}
switch (tagmask) {
case 0:
break;
case 1:
c.tagshift = 0;
c.tagmask = 0;
c.tagenb = 0;
break;
default:
m = tagmask;
c.tagshift = 0;
while (!(m&01)) {
m >>= 1;
c.tagshift++;
}
c.tagmask = m;
c.tagenb = (m << 1) & ~m;
break;
}
fn = enstring(name, dir);
if (fn == NULL)
return(-1);
f = fopen(fn, "w");
free(fn);
if (f == NULL) {
DEBUG(("dbzfresh: unable to write config\n"));
return(-1);
}
if (putconf(f, &c) < 0) {
(void) fclose(f);
return(-1);
}
if (fclose(f) == EOF) {
DEBUG(("dbzfresh: fclose failure\n"));
return(-1);
}
fn = enstring(name, pag);
if (fn == NULL)
return(-1);
f = fopen(fn, "w");
free(fn);
if (f == NULL) {
DEBUG(("dbzfresh: unable to create/truncate .pag file\n"));
return(-1);
} else
(void) fclose(f);
return(dbminit(name));
}
long
dbzsize(contents)
long contents;
{
register long n;
if (contents <= 0) {
DEBUG(("dbzsize: preposterous input (%ld)\n", contents));
return(DEFSIZE);
}
n = (contents/2)*3;
if (!(n&01))
n++;
DEBUG(("dbzsize: tentative size %ld\n", n));
while (!isprime(n))
n += 2;
DEBUG(("dbzsize: final size %ld\n", n));
return(n);
}
static int
isprime(x)
register long x;
{
static int quick[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 0 };
register int *ip;
register long div;
register long stop;
for (ip = quick; (div = *ip) != 0; ip++)
if (x%div == 0) {
DEBUG(("isprime: quick result on %ld\n", (long)x));
return(0);
}
for (stop = x; x/stop < stop; stop >>= 1)
continue;
stop <<= 1;
for (div = *--ip; div < stop; div += 2)
if (x%div == 0)
return(0);
return(1);
}
int
dbzagain(name, oldname)
char *name;
char *oldname;
{
register char *fn;
struct dbzconfig c;
register int i;
register long top;
register FILE *f;
register int newtable;
register off_t newsize;
if (pagf != NULL) {
DEBUG(("dbzagain: database already open\n"));
return(-1);
}
fn = enstring(oldname, dir);
if (fn == NULL)
return(-1);
f = fopen(fn, "r");
free(fn);
if (f == NULL) {
DEBUG(("dbzagain: cannot open old .dir file\n"));
return(-1);
}
i = getconf(f, (FILE *)NULL, &c);
(void) fclose(f);
if (i < 0) {
DEBUG(("dbzagain: getconf failed\n"));
return(-1);
}
top = 0;
newtable = 0;
for (i = 0; i < NUSEDS; i++) {
if (top < c.used[i])
top = c.used[i];
if (c.used[i] == 0)
newtable = 1;
}
if (top == 0) {
DEBUG(("dbzagain: old table has no contents!\n"));
newtable = 1;
}
for (i = NUSEDS-1; i > 0; i--)
c.used[i] = c.used[i-1];
c.used[0] = 0;
newsize = dbzsize(top);
if (!newtable || newsize > c.tsize)
c.tsize = newsize;
fn = enstring(name, dir);
if (fn == NULL)
return(-1);
f = fopen(fn, "w");
free(fn);
if (f == NULL) {
DEBUG(("dbzagain: unable to write new .dir\n"));
return(-1);
}
i = putconf(f, &c);
(void) fclose(f);
if (i < 0) {
DEBUG(("dbzagain: putconf failed\n"));
return(-1);
}
fn = enstring(name, pag);
if (fn == NULL)
return(-1);
f = fopen(fn, "w");
free(fn);
if (f == NULL) {
DEBUG(("dbzagain: unable to create/truncate .pag file\n"));
return(-1);
} else
(void) fclose(f);
return(dbminit(name));
}
int
dbminit(name)
char *name;
{
register int i;
register size_t s;
register char *dirfname;
register char *pagfname;
if (pagf != NULL) {
DEBUG(("dbminit: dbminit already called once\n"));
errno = 0;
return(-1);
}
dirfname = enstring(name, dir);
if (dirfname == NULL)
return(-1);
dirf = fopen(dirfname, "r+");
if (dirf == NULL) {
dirf = fopen(dirfname, "r");
dirronly = 1;
} else
dirronly = 0;
free(dirfname);
if (dirf == NULL) {
DEBUG(("dbminit: can't open .dir file\n"));
return(-1);
}
pagfname = enstring(name, pag);
if (pagfname == NULL) {
(void) fclose(dirf);
return(-1);
}
pagf = fopen(pagfname, "r+b");
if (pagf == NULL) {
pagf = fopen(pagfname, "rb");
if (pagf == NULL) {
DEBUG(("dbminit: .pag open failed\n"));
(void) fclose(dirf);
free(pagfname);
return(-1);
}
pagronly = 1;
} else if (dirronly)
pagronly = 1;
else
pagronly = 0;
#ifdef NOBUFFER
(void) setbuf(pagf, (char *)NULL);
#else
#ifdef _IOFBF
(void) setvbuf(pagf, (char *)pagbuf, _IOFBF, sizeof(pagbuf));
#endif
#endif
pagpos = -1;
basef = fopen(name, "r");
if (basef == NULL) {
DEBUG(("dbminit: basefile open failed\n"));
basefname = enstring(name, "");
if (basefname == NULL) {
(void) fclose(pagf);
(void) fclose(dirf);
free(pagfname);
pagf = NULL;
return(-1);
}
} else
basefname = NULL;
#ifdef _IOFBF
if (basef != NULL)
(void) setvbuf(basef, basebuf, _IOFBF, sizeof(basebuf));
#endif
if (getconf(dirf, pagf, &conf) < 0) {
DEBUG(("dbminit: getconf failure\n"));
(void) fclose(basef);
(void) fclose(pagf);
(void) fclose(dirf);
free(pagfname);
pagf = NULL;
errno = EDOM;
return(-1);
}
tagbits = conf.tagmask << conf.tagshift;
taghere = conf.tagenb << conf.tagshift;
tagboth = tagbits | taghere;
mybytemap(mybmap);
bytesame = 1;
for (i = 0; i < SOF; i++)
if (mybmap[i] != conf.bytemap[i])
bytesame = 0;
s = (size_t)conf.tsize * SOF;
if (incore && (off_t)(s/SOF) == conf.tsize) {
bufpagf = fopen(pagfname, (pagronly) ? "rb" : "r+b");
if (bufpagf != NULL)
corepag = getcore(bufpagf);
} else {
bufpagf = NULL;
corepag = NULL;
}
free(pagfname);
crcinit();
written = 0;
prevp = FRESH;
DEBUG(("dbminit: succeeded\n"));
return(0);
}
static char *
enstring(s1, s2)
char *s1;
char *s2;
{
register char *p;
p = malloc((size_t)strlen(s1) + (size_t)strlen(s2) + 1);
if (p != NULL) {
(void) strcpy(p, s1);
(void) strcat(p, s2);
} else {
DEBUG(("enstring(%s, %s) out of memory\n", s1, s2));
}
return(p);
}
int
dbmclose()
{
register int ret = 0;
if (pagf == NULL) {
DEBUG(("dbmclose: not opened!\n"));
return(-1);
}
if (fclose(pagf) == EOF) {
DEBUG(("dbmclose: fclose(pagf) failed\n"));
ret = -1;
}
pagf = basef;
if (dbzsync() < 0)
ret = -1;
if (bufpagf != NULL && fclose(bufpagf) == EOF) {
DEBUG(("dbmclose: fclose(bufpagf) failed\n"));
ret = -1;
}
if (corepag != NULL)
free((char *)corepag);
corepag = NULL;
if (fclose(basef) == EOF) {
DEBUG(("dbmclose: fclose(basef) failed\n"));
ret = -1;
}
if (basefname != NULL)
free(basefname);
basef = NULL;
pagf = NULL;
if (fclose(dirf) == EOF) {
DEBUG(("dbmclose: fclose(dirf) failed\n"));
ret = -1;
}
DEBUG(("dbmclose: %s\n", (ret == 0) ? "succeeded" : "failed"));
return(ret);
}
int
dbzsync()
{
register int ret = 0;
if (pagf == NULL) {
DEBUG(("dbzsync: not opened!\n"));
return(-1);
}
if (!written)
return(0);
if (corepag != NULL) {
if (putcore(corepag, bufpagf) < 0) {
DEBUG(("dbzsync: putcore failed\n"));
ret = -1;
}
}
if (!conf.olddbz)
if (putconf(dirf, &conf) < 0)
ret = -1;
DEBUG(("dbzsync: %s\n", (ret == 0) ? "succeeded" : "failed"));
return(ret);
}
int
dbzcancel()
{
if (pagf == NULL) {
DEBUG(("dbzcancel: not opened!\n"));
return(-1);
}
written = 0;
return(0);
}
datum
dbzfetch(key)
datum key;
{
char buffer[DBZMAXKEY + 1];
datum mappedkey;
register size_t keysize;
DEBUG(("dbzfetch: (%s)\n", key.dptr));
keysize = key.dsize;
if (keysize >= DBZMAXKEY) {
keysize = DBZMAXKEY;
DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY));
}
mappedkey.dptr = mapcase(buffer, key.dptr, keysize);
buffer[keysize] = '\0';
mappedkey.dsize = keysize;
return(fetch(mappedkey));
}
datum
fetch(key)
datum key;
{
char buffer[DBZMAXKEY + 1];
static off_t key_ptr;
datum output;
register size_t keysize;
register size_t cmplen;
register char *sepp;
DEBUG(("fetch: (%s)\n", key.dptr));
output.dptr = NULL;
output.dsize = 0;
prevp = FRESH;
keysize = key.dsize;
if (keysize >= DBZMAXKEY) {
keysize = DBZMAXKEY;
DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY));
}
if (pagf == NULL) {
DEBUG(("fetch: database not open!\n"));
return(output);
} else if (basef == NULL) {
basef = latebase();
if (basef == NULL)
return(output);
}
cmplen = keysize;
sepp = &conf.fieldsep;
if (key.dptr[keysize-1] == '\0') {
cmplen--;
sepp = &buffer[keysize-1];
}
start(&srch, &key, FRESH);
while ((key_ptr = search(&srch)) != NOTFOUND) {
DEBUG(("got 0x%lx\n", key_ptr));
if (fseek(basef, key_ptr, SEEK_SET) != 0) {
DEBUG(("fetch: seek failed\n"));
return(output);
}
if (fread(buffer, 1, keysize, basef) != keysize) {
DEBUG(("fetch: read failed\n"));
return(output);
}
buffer[keysize] = '\0';
(void) mapcase(buffer, buffer, keysize);
DEBUG(("fetch: buffer (%s) looking for (%s) size = %d\n",
buffer, key.dptr, keysize));
if (memcmp(key.dptr, buffer, cmplen) == 0 &&
(*sepp == conf.fieldsep || *sepp == '\0')) {
output.dptr = (char *)&key_ptr;
output.dsize = SOF;
DEBUG(("fetch: successful\n"));
return(output);
}
}
DEBUG(("fetch: failed\n"));
prevp = &srch;
return(output);
}
static FILE *
latebase()
{
register FILE *it;
if (basefname == NULL) {
DEBUG(("latebase: name foulup\n"));
return(NULL);
}
it = fopen(basefname, "r");
if (it == NULL) {
DEBUG(("latebase: still can't open base\n"));
} else {
DEBUG(("latebase: late open succeeded\n"));
free(basefname);
basefname = NULL;
#ifdef _IOFBF
(void) setvbuf(it, basebuf, _IOFBF, sizeof(basebuf));
#endif
}
return(it);
}
int
dbzstore(key, data)
datum key;
datum data;
{
char buffer[DBZMAXKEY + 1];
datum mappedkey;
register size_t keysize;
DEBUG(("dbzstore: (%s)\n", key.dptr));
keysize = key.dsize;
if (keysize >= DBZMAXKEY) {
DEBUG(("dbzstore: key size too big (%d)\n", key.dsize));
return(-1);
}
mappedkey.dptr = mapcase(buffer, key.dptr, keysize);
buffer[keysize] = '\0';
mappedkey.dsize = keysize;
return(store(mappedkey, data));
}
int
store(key, data)
datum key;
datum data;
{
off_t value;
if (pagf == NULL) {
DEBUG(("store: database not open!\n"));
return(-1);
} else if (basef == NULL) {
basef = latebase();
if (basef == NULL)
return(-1);
}
if (pagronly) {
DEBUG(("store: database open read-only\n"));
return(-1);
}
if (data.dsize != SOF) {
DEBUG(("store: value size wrong (%d)\n", data.dsize));
return(-1);
}
if (key.dsize >= DBZMAXKEY) {
DEBUG(("store: key size too big (%d)\n", key.dsize));
return(-1);
}
(void) memcpy((char *)&value, data.dptr, SOF);
DEBUG(("store: (%s, %ld)\n", key.dptr, (long)value));
if (!okayvalue(value)) {
DEBUG(("store: reserved bit or overflow in 0x%lx\n", value));
return(-1);
}
start(&srch, &key, prevp);
while (search(&srch) != NOTFOUND)
continue;
prevp = FRESH;
conf.used[0]++;
DEBUG(("store: used count %ld\n", conf.used[0]));
written = 1;
return(set(&srch, value));
}
int
dbzincore(value)
int value;
{
register int old = incore;
incore = value;
return(old);
}
static int
getconf(df, pf, cp)
register FILE *df;
register FILE *pf;
register struct dbzconfig *cp;
{
register int c;
register int i;
int err = 0;
c = (df != NULL) ? getc(df) : EOF;
if (c == EOF) {
cp->olddbz = 0;
if (df != NULL && pf != NULL && getc(pf) != EOF)
cp->olddbz = 1;
cp->tsize = DEFSIZE;
cp->fieldsep = '\t';
for (i = 0; i < NUSEDS; i++)
cp->used[i] = 0;
cp->valuesize = SOF;
mybytemap(cp->bytemap);
cp->casemap = DEFCASE;
cp->tagenb = TAGENB;
cp->tagmask = TAGMASK;
cp->tagshift = TAGSHIFT;
DEBUG(("getconf: defaults (%ld, %c, (0x%lx/0x%lx<<%d))\n",
cp->tsize, cp->casemap, cp->tagenb,
cp->tagmask, cp->tagshift));
return(0);
}
(void) ungetc(c, df);
if (getc(df) != 'd' || getc(df) != 'b' || getc(df) != 'z')
err = -1;
if (getno(df, &err) != dbzversion)
err = -1;
cp->tsize = getno(df, &err);
cp->fieldsep = getno(df, &err);
while ((c = getc(df)) == ' ')
continue;
cp->casemap = c;
cp->tagenb = getno(df, &err);
cp->tagmask = getno(df, &err);
cp->tagshift = getno(df, &err);
cp->valuesize = getno(df, &err);
if (cp->valuesize != SOF) {
DEBUG(("getconf: wrong off_t size (%d)\n", cp->valuesize));
err = -1;
cp->valuesize = SOF;
}
for (i = 0; i < cp->valuesize; i++)
cp->bytemap[i] = getno(df, &err);
if (getc(df) != '\n')
err = -1;
DEBUG(("size %ld, sep %d, cmap %c, tags 0x%lx/0x%lx<<%d, ", cp->tsize,
cp->fieldsep, cp->casemap, cp->tagenb, cp->tagmask,
cp->tagshift));
DEBUG(("bytemap (%d)", cp->valuesize));
for (i = 0; i < cp->valuesize; i++) {
DEBUG((" %d", cp->bytemap[i]));
}
DEBUG(("\n"));
for (i = 0; i < NUSEDS; i++)
cp->used[i] = getno(df, &err);
if (getc(df) != '\n')
err = -1;
DEBUG(("used %ld %ld %ld...\n", cp->used[0], cp->used[1], cp->used[2]));
if (err < 0) {
DEBUG(("getconf error\n"));
return(-1);
}
return(0);
}
static long
getno(f, ep)
FILE *f;
int *ep;
{
register char *p;
# define MAXN 50
char getbuf[MAXN];
register int c;
while ((c = getc(f)) == ' ')
continue;
if (c == EOF || c == '\n') {
DEBUG(("getno: missing number\n"));
*ep = -1;
return(0);
}
p = getbuf;
*p++ = c;
while ((c = getc(f)) != EOF && c != '\n' && c != ' ')
if (p < &getbuf[MAXN-1])
*p++ = c;
if (c == EOF) {
DEBUG(("getno: EOF\n"));
*ep = -1;
} else
(void) ungetc(c, f);
*p = '\0';
if (strspn(getbuf, "-1234567890") != strlen(getbuf)) {
DEBUG(("getno: `%s' non-numeric\n", getbuf));
*ep = -1;
}
return(atol(getbuf));
}
static int
putconf(f, cp)
register FILE *f;
register struct dbzconfig *cp;
{
register int i;
register int ret = 0;
if (fseek(f, 0, SEEK_SET) != 0) {
DEBUG(("fseek failure in putconf\n"));
ret = -1;
}
fprintf(f, "dbz %d %ld %d %c %ld %ld %d %d", dbzversion,
(long)cp->tsize,
cp->fieldsep, cp->casemap, (long)cp->tagenb,
(long)cp->tagmask, cp->tagshift,
cp->valuesize);
for (i = 0; i < cp->valuesize; i++)
fprintf(f, " %d", cp->bytemap[i]);
fprintf(f, "\n");
for (i = 0; i < NUSEDS; i++)
fprintf(f, "%ld%c",
(long)cp->used[i], (i < NUSEDS-1) ? ' ' : '\n');
(void) fflush(f);
if (ferror(f))
ret = -1;
DEBUG(("putconf status %d\n", ret));
return(ret);
}
static off_t *
getcore(f)
FILE *f;
{
register off_t *p;
register size_t i;
register size_t nread;
register char *it;
it = malloc((size_t)conf.tsize * SOF);
if (it == NULL) {
DEBUG(("getcore: malloc failed\n"));
return(NULL);
}
nread = fread(it, SOF, (size_t)conf.tsize, f);
if (ferror(f)) {
DEBUG(("getcore: read failed\n"));
free(it);
return(NULL);
}
p = (off_t *)it + nread;
i = (size_t)conf.tsize - nread;
while (i-- > 0)
*p++ = VACANT;
return((off_t *)it);
}
static int
putcore(tab, f)
off_t *tab;
FILE *f;
{
if (fseek(f, 0, SEEK_SET) != 0) {
DEBUG(("fseek failure in putcore\n"));
return(-1);
}
(void) fwrite((char *)tab, SOF, (size_t)conf.tsize, f);
(void) fflush(f);
return((ferror(f)) ? -1 : 0);
}
static void
start(sp, kp, osp)
register struct searcher *sp;
register datum *kp;
register struct searcher *osp;
{
register long h;
h = hash(kp->dptr, kp->dsize);
if (osp != FRESH && osp->hash == h) {
if (sp != osp)
*sp = *osp;
DEBUG(("search restarted\n"));
} else {
sp->hash = h;
sp->tag = MKTAG(h / conf.tsize);
DEBUG(("tag 0x%lx\n", sp->tag));
sp->place = h % conf.tsize;
sp->tabno = 0;
sp->run = (conf.olddbz) ? conf.tsize : MAXRUN;
sp->aborted = 0;
}
sp->seen = 0;
}
static off_t
search(sp)
register struct searcher *sp;
{
register off_t dest;
register off_t value;
off_t val;
register off_t place;
if (sp->aborted)
return(NOTFOUND);
for (;;) {
place = sp->place;
if (sp->seen) {
if (--sp->run <= 0) {
sp->tabno++;
sp->run = MAXRUN;
}
place = (place+1)%conf.tsize + sp->tabno*conf.tsize;
sp->place = place;
} else
sp->seen = 1;
DEBUG(("search @ %ld\n", place));
if (corepag != NULL && place < conf.tsize) {
DEBUG(("search: in core\n"));
value = MAPIN(corepag[place]);
} else {
dest = place * SOF;
if (pagpos != dest) {
if (fseek(pagf, dest, SEEK_SET) != 0) {
DEBUG(("search: seek failed\n"));
pagpos = -1;
sp->aborted = 1;
return(NOTFOUND);
}
pagpos = dest;
}
if (fread((char *)&val, sizeof(val), 1, pagf) == 1)
value = MAPIN(val);
else if (ferror(pagf)) {
DEBUG(("search: read failed\n"));
pagpos = -1;
sp->aborted = 1;
return(NOTFOUND);
} else
value = VACANT;
pagpos += sizeof(val);
}
if (value == VACANT) {
DEBUG(("search: empty slot\n"));
return(NOTFOUND);
};
value = UNBIAS(value);
DEBUG(("got 0x%lx\n", value));
if (!HASTAG(value)) {
DEBUG(("tagless\n"));
return(value);
} else if (TAG(value) == sp->tag) {
DEBUG(("match\n"));
return(NOTAG(value));
} else {
DEBUG(("mismatch 0x%lx\n", TAG(value)));
}
}
}
static int
okayvalue(value)
off_t value;
{
if (HASTAG(value))
return(0);
#ifdef OVERFLOW
if (value == LONG_MAX)
return(0);
#endif
return(1);
}
static int
set(sp, value)
register struct searcher *sp;
off_t value;
{
register off_t place = sp->place;
register off_t v = value;
if (sp->aborted)
return(-1);
if (CANTAG(v) && !conf.olddbz) {
v |= sp->tag | taghere;
if (v != UNBIAS(VACANT))
#ifdef OVERFLOW
if (v != LONG_MAX)
#endif
value = v;
}
DEBUG(("tagged value is 0x%lx\n", value));
value = BIAS(value);
value = MAPOUT(value);
if (corepag != NULL && place < conf.tsize) {
corepag[place] = value;
DEBUG(("set: incore\n"));
return(0);
}
pagpos = -1;
if (fseek(pagf, place * SOF, SEEK_SET) != 0) {
DEBUG(("set: seek failed\n"));
sp->aborted = 1;
return(-1);
}
if (fwrite((char *)&value, SOF, 1, pagf) != 1) {
DEBUG(("set: write failed\n"));
sp->aborted = 1;
return(-1);
}
if (fflush(pagf) == EOF) {
DEBUG(("set: fflush failed\n"));
sp->aborted = 1;
return(-1);
}
DEBUG(("set: succeeded\n"));
return(0);
}
static void
mybytemap(map)
int map[];
{
union {
off_t o;
char c[SOF];
} u;
register int *mp = &map[SOF];
register int ntodo;
register int i;
u.o = 1;
for (ntodo = (int)SOF; ntodo > 0; ntodo--) {
for (i = 0; i < SOF; i++)
if (u.c[i] != 0)
break;
if (i == SOF) {
DEBUG(("mybytemap: nonexistent byte %d!!!\n", ntodo));
for (i = 0; i < SOF; i++)
map[i] = i;
return;
}
DEBUG(("mybytemap: byte %d\n", i));
*--mp = i;
while (u.c[i] != 0)
u.o <<= 1;
}
}
static off_t
bytemap(ino, map1, map2)
off_t ino;
int *map1;
int *map2;
{
union oc {
off_t o;
char c[SOF];
};
union oc in;
union oc out;
register int i;
in.o = ino;
for (i = 0; i < SOF; i++)
out.c[map2[i]] = in.c[map1[i]];
return(out.o);
}
#define POLY 0x48000000L
static long CrcTable[128];
static void
crcinit()
{
register int i, j;
register long sum;
for (i = 0; i < 128; ++i) {
sum = 0L;
for (j = 7 - 1; j >= 0; --j)
if (i & (1 << j))
sum ^= POLY >> j;
CrcTable[i] = sum;
}
DEBUG(("crcinit: done\n"));
}
static long
hash(name, size)
register char *name;
register int size;
{
register long sum = 0L;
while (size--) {
sum = (sum >> 7) ^ CrcTable[(sum ^ (*name++)) & 0x7f];
}
DEBUG(("hash: returns (%ld)\n", sum));
return(sum);
}
#define OFFSET 128
#define TOLOW(c) (cmap[(c)+OFFSET])
#define CISTREQN(a, b, n) \
(TOLOW((a)[0]) == TOLOW((b)[0]) && casencmp(a, b, n) == 0)
#define MAPSIZE (256+OFFSET)
static char cmap[MAPSIZE];
static int mprimed = 0;
static void
mapprime()
{
register char *lp;
register char *up;
register int c;
register int i;
static char lower[] = "abcdefghijklmnopqrstuvwxyz";
static char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (lp = lower, up = upper; *lp != '\0'; lp++, up++) {
c = *lp;
cmap[c+OFFSET] = c;
cmap[*up+OFFSET] = c;
}
for (i = 0; i < MAPSIZE; i++)
if (cmap[i] == '\0')
cmap[i] = (char)(i-OFFSET);
mprimed = 1;
}
static int
casencmp(s1, s2, len)
char *s1;
char *s2;
int len;
{
register char *p1;
register char *p2;
register int n;
if (!mprimed)
mapprime();
p1 = s1;
p2 = s2;
n = len;
while (--n >= 0 && *p1 != '\0' && TOLOW(*p1) == TOLOW(*p2)) {
p1++;
p2++;
}
if (n < 0)
return(0);
if (*p1 == '\0' && *p2 == '\0')
return(0);
else if (*p1 == '\0')
return(-1);
else if (*p2 == '\0')
return(1);
else
return(TOLOW(*p1) - TOLOW(*p2));
}
static char *
mapcase(dst, src, siz)
char *dst;
char *src;
size_t siz;
{
register char *s;
register char *d;
register char *c;
register char *e;
c = cipoint(src, siz);
if (c == NULL)
return(src);
if (!mprimed)
mapprime();
s = src;
e = s + siz;
d = dst;
while (s < c)
*d++ = *s++;
while (s < e)
*d++ = TOLOW(*s++);
return(dst);
}
static char *
cipoint(s, siz)
char *s;
size_t siz;
{
register char *p;
static char post[] = "postmaster";
static int plen = sizeof(post)-1;
switch (conf.casemap) {
case '0':
return(NULL);
break;
case 'C':
p = memchr(s, '@', siz);
if (p == NULL)
return(NULL);
else if (p - (s+1) == plen && CISTREQN(s+1, post, plen)) {
return(s);
} else
return(p);
break;
case '=':
return(s);
break;
}
DEBUG(("cipoint: unknown case mapping `%c'\n", conf.casemap));
return(NULL);
}
int
dbzdebug(value)
int value;
{
#ifdef DBZDEBUG
register int old = debug;
debug = value;
return(old);
#else
return(-1);
#endif
}