Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / libio / dbz / dbz.c
1 /*
2
3 dbz.c  V3.2
4
5 Copyright 1988 Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us)
6 You can use this code in any manner, as long as you leave my name on it
7 and don't hold me responsible for any problems with it.
8
9 Hacked on by gdb@ninja.UUCP (David Butler); Sun Jun  5 00:27:08 CDT 1988
10
11 Various improvments + INCORE by moraes@ai.toronto.edu (Mark Moraes)
12
13 Major reworking by Henry Spencer as part of the C News project.
14
15 These routines replace dbm as used by the usenet news software
16 (it's not a full dbm replacement by any means).  It's fast and
17 simple.  It contains no AT&T code.
18
19 In general, dbz's files are 1/20 the size of dbm's.  Lookup performance
20 is somewhat better, while file creation is spectacularly faster, especially
21 if the incore facility is used.
22
23 */
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #ifndef __STDC__
31 extern int errno;
32 #endif
33 #include <dbz.h>
34
35 /*
36  * #ifdef index.  "LIA" = "leave it alone unless you know what you're doing".
37  *
38  * FUNNYSEEKS   SEEK_SET is not 0, get it from <unistd.h>
39  * INDEX_SIZE   backward compatibility with old dbz; avoid using this
40  * NMEMORY      number of days of memory for use in sizing new table (LIA)
41  * INCORE       backward compatibility with old dbz; use dbzincore() instead
42  * DBZDEBUG     enable debugging
43  * DEFSIZE      default table size (not as critical as in old dbz)
44  * OLDBNEWS     default case mapping as in old B News; set NOBUFFER
45  * BNEWS        default case mapping as in current B News; set NOBUFFER
46  * DEFCASE      default case-map algorithm selector
47  * NOTAGS       fseek offsets are strange, do not do tagging (see below)
48  * NPAGBUF      size of .pag buffer, in longs (LIA)
49  * SHISTBUF     size of ASCII-file buffer, in bytes (LIA)
50  * MAXRUN       length of run which shifts to next table (see below) (LIA)
51  * OVERFLOW     long-int arithmetic overflow must be avoided, will trap
52  * NOBUFFER     do not buffer hash-table i/o, B News locking is defective
53  */
54
55 #ifdef FUNNYSEEKS
56 #include <unistd.h>
57 #else
58 #define SEEK_SET        0
59 #endif
60 #ifdef OVERFLOW
61 #include <limits.h>
62 #endif
63
64 static int dbzversion = 3;      /* for validating .dir file format */
65
66 /*
67  * The dbz database exploits the fact that when news stores a <key,value>
68  * tuple, the `value' part is a seek offset into a text file, pointing to
69  * a copy of the `key' part.  This avoids the need to store a copy of
70  * the key in the dbz files.  However, the text file *must* exist and be
71  * consistent with the dbz files, or things will fail.
72  *
73  * The basic format of the database is a simple hash table containing the
74  * values.  A value is stored by indexing into the table using a hash value
75  * computed from the key; collisions are resolved by linear probing (just
76  * search forward for an empty slot, wrapping around to the beginning of
77  * the table if necessary).  Linear probing is a performance disaster when
78  * the table starts to get full, so a complication is introduced.  The
79  * database is actually one *or more* tables, stored sequentially in the
80  * .pag file, and the length of linear-probe sequences is limited.  The
81  * search (for an existing item or an empty slot) always starts in the
82  * first table, and whenever MAXRUN probes have been done in table N,
83  * probing continues in table N+1.  This behaves reasonably well even in
84  * cases of massive overflow.  There are some other small complications
85  * added, see comments below.
86  *
87  * The table size is fixed for any particular database, but is determined
88  * dynamically when a database is rebuilt.  The strategy is to try to pick
89  * the size so the first table will be no more than 2/3 full, that being
90  * slightly before the point where performance starts to degrade.  (It is
91  * desirable to be a bit conservative because the overflow strategy tends
92  * to produce files with holes in them, which is a nuisance.)
93  */
94
95 /*
96  * The following is for backward compatibility.
97  */
98 #ifdef INDEX_SIZE
99 #define DEFSIZE INDEX_SIZE
100 #endif
101
102 /*
103  * ANSI C says the offset argument to fseek is a long, not an off_t, for some
104  * reason.  Let's use off_t anyway.
105  */
106 #define SOF     (sizeof(off_t))
107
108 /*
109  * We assume that unused areas of a binary file are zeros, and that the
110  * bit pattern of `(off_t)0' is all zeros.  The alternative is rather
111  * painful file initialization.  Note that okayvalue(), if OVERFLOW is
112  * defined, knows what value of an offset would cause overflow.
113  */
114 #define VACANT          ((off_t)0)
115 #define BIAS(o)         ((o)+1)         /* make any valid off_t non-VACANT */
116 #define UNBIAS(o)       ((o)-1)         /* reverse BIAS() effect */
117
118 /*
119  * In a Unix implementation, or indeed any in which an off_t is a byte
120  * count, there are a bunch of high bits free in an off_t.  There is a
121  * use for them.  Checking a possible hit by looking it up in the base
122  * file is relatively expensive, and the cost can be dramatically reduced
123  * by using some of those high bits to tag the value with a few more bits
124  * of the key's hash.  This detects most false hits without the overhead of
125  * seek+read+strcmp.  We use the top bit to indicate whether the value is
126  * tagged or not, and don't tag a value which is using the tag bits itself.
127  * We're in trouble if the off_t representation wants to use the top bit.
128  * The actual bitmasks and offset come from the configuration stuff,
129  * which permits fiddling with them as necessary, and also suppressing
130  * them completely (by defining the masks to 0).  We build pre-shifted
131  * versions of the masks for efficiency.
132  */
133 static off_t tagbits;           /* pre-shifted tag mask */
134 static off_t taghere;           /* pre-shifted tag-enable bit */
135 static off_t tagboth;           /* tagbits|taghere */
136 #define HASTAG(o)       ((o)&taghere)
137 #define TAG(o)          ((o)&tagbits)
138 #define NOTAG(o)        ((o)&~tagboth)
139 #define CANTAG(o)       (((o)&tagboth) == 0)
140 #define MKTAG(v)        (((v)<<conf.tagshift)&tagbits)
141
142 /*
143  * A new, from-scratch database, not built as a rebuild of an old one,
144  * needs to know table size, casemap algorithm, and tagging.  Normally
145  * the user supplies this info, but there have to be defaults.
146  */
147 #ifndef DEFSIZE
148 #define DEFSIZE 120011          /* 300007 might be better */
149 #endif
150 #ifdef OLDBNEWS
151 #define DEFCASE '0'             /* B2.10 -- no mapping */
152 #define NOBUFFER                /* B News locking is defective */
153 #endif
154 #ifdef BNEWS
155 #define DEFCASE '='             /* B2.11 -- all mapped */
156 #define NOBUFFER                /* B News locking is defective */
157 #endif
158 #ifndef DEFCASE                 /* C News compatibility is the default */
159 #define DEFCASE 'C'             /* C News -- RFC822 mapping */
160 #endif
161 #ifndef NOTAGS
162 #define TAGENB  0x80            /* tag enable is top bit, tag is next 7 */
163 #define TAGMASK 0x7f
164 #define TAGSHIFT        24
165 #else
166 #define TAGENB  0               /* no tags */
167 #define TAGMASK 0
168 #define TAGSHIFT        0
169 #endif
170
171 /*
172  * We read configuration info from the .dir file into this structure,
173  * so we can avoid wired-in assumptions for an existing database.
174  *
175  * Among the info is a record of recent peak usages, so that a new table
176  * size can be chosen intelligently when rebuilding.  10 is a good
177  * number of usages to keep, since news displays marked fluctuations
178  * in volume on a 7-day cycle.
179  */
180 struct dbzconfig {
181         int olddbz;             /* .dir file empty but .pag not? */
182         off_t tsize;            /* table size */
183 #       ifndef NMEMORY
184 #       define  NMEMORY 10      /* # days of use info to remember */
185 #       endif
186 #       define  NUSEDS  (1+NMEMORY)
187         off_t used[NUSEDS];     /* entries used today, yesterday, ... */
188         int valuesize;          /* size of table values, == SOF */
189         int bytemap[SOF];       /* byte-order map */
190         char casemap;           /* case-mapping algorithm (see cipoint()) */
191         char fieldsep;          /* field separator in base file, if any */
192         off_t tagenb;           /* unshifted tag-enable bit */
193         off_t tagmask;          /* unshifted tag mask */
194         int tagshift;           /* shift count for tagmask and tagenb */
195 };
196 static struct dbzconfig conf;
197 static int getconf();
198 static long getno();
199 static int putconf();
200 static void mybytemap();
201 static off_t bytemap();
202
203 /* 
204  * For a program that makes many, many references to the database, it
205  * is a large performance win to keep the table in core, if it will fit.
206  * Note that this does hurt robustness in the event of crashes, and
207  * dbmclose() *must* be called to flush the in-core database to disk.
208  * The code is prepared to deal with the possibility that there isn't
209  * enough memory.  There *is* an assumption that a size_t is big enough
210  * to hold the size (in bytes) of one table, so dbminit() tries to figure
211  * out whether this is possible first.
212  *
213  * The preferred way to ask for an in-core table is to do dbzincore(1)
214  * before dbminit().  The default is not to do it, although -DINCORE
215  * overrides this for backward compatibility with old dbz.
216  *
217  * We keep only the first table in core.  This greatly simplifies the
218  * code, and bounds memory demand.  Furthermore, doing this is a large
219  * performance win even in the event of massive overflow.
220  */
221 #ifdef INCORE
222 static int incore = 1;
223 #else
224 static int incore = 0;
225 #endif
226
227 /*
228  * Stdio buffer for .pag reads.  Buffering more than about 16 does not help
229  * significantly at the densities we try to maintain, and the much larger
230  * buffers that most stdios default to are much more expensive to fill.
231  * With small buffers, stdio is performance-competitive with raw read(),
232  * and it's much more portable.
233  */
234 #ifndef NPAGBUF
235 #define NPAGBUF 16
236 #endif
237 #ifndef NOBUFFER
238 #ifdef _IOFBF
239 static off_t pagbuf[NPAGBUF];   /* only needed if !NOBUFFER && _IOFBF */
240 #endif
241 #endif
242
243 /*
244  * Stdio buffer for base-file reads.  Message-IDs (all news ever needs to
245  * read) are essentially never longer than 64 bytes, and the typical stdio
246  * buffer is so much larger that it is much more expensive to fill.
247  */
248 #ifndef SHISTBUF
249 #define SHISTBUF        64
250 #endif
251 #ifdef _IOFBF
252 static char basebuf[SHISTBUF];          /* only needed if _IOFBF exists */
253 #endif
254
255 /*
256  * Data structure for recording info about searches.
257  */
258 struct searcher {
259         off_t place;            /* current location in file */
260         int tabno;              /* which table we're in */
261         int run;                /* how long we'll stay in this table */
262 #               ifndef MAXRUN
263 #               define  MAXRUN  100
264 #               endif
265         long hash;              /* the key's hash code (for optimization) */
266         off_t tag;              /* tag we are looking for */
267         int seen;               /* have we examined current location? */
268         int aborted;            /* has i/o error aborted search? */
269 };
270 static void start();
271 #define FRESH   ((struct searcher *)NULL)
272 static off_t search();
273 #define NOTFOUND        ((off_t)-1)
274 static int okayvalue();
275 static int set();
276
277 /*
278  * Arguably the searcher struct for a given routine ought to be local to
279  * it, but a fetch() is very often immediately followed by a store(), and
280  * in some circumstances it is a useful performance win to remember where
281  * the fetch() completed.  So we use a global struct and remember whether
282  * it is current.
283  */
284 static struct searcher srch;
285 static struct searcher *prevp;  /* &srch or FRESH */
286
287 /* byte-ordering stuff */
288 static int mybmap[SOF];                 /* my byte order (see mybytemap()) */
289 static int bytesame;                    /* is database order same as mine? */
290 #define MAPIN(o)        ((bytesame) ? (o) : bytemap((o), conf.bytemap, mybmap))
291 #define MAPOUT(o)       ((bytesame) ? (o) : bytemap((o), mybmap, conf.bytemap))
292
293 /*
294  * The double parentheses needed to make this work are ugly, but the
295  * alternative (under most compilers) is to pack around 2K of unused
296  * strings -- there's just no way to get rid of them.
297  */
298 static int debug;                       /* controlled by dbzdebug() */
299 #ifdef DBZDEBUG
300 #define DEBUG(args) if (debug) { (void) printf args ; }
301 #else
302 #define DEBUG(args)     ;
303 #endif
304
305 /* externals used */
306 extern char *malloc();
307 extern char *calloc();
308 extern void free();             /* ANSI C; some old implementations say int */
309 extern int atoi();
310 extern long atol();
311
312 /* misc. forwards */
313 static long hash();
314 static void crcinit();
315 static char *cipoint();
316 static char *mapcase();
317 static int isprime();
318 static FILE *latebase();
319
320 /* file-naming stuff */
321 static char dir[] = ".dir";
322 static char pag[] = ".pag";
323 static char *enstring();
324
325 /* central data structures */
326 static FILE *basef;             /* descriptor for base file */
327 static char *basefname;         /* name for not-yet-opened base file */
328 static FILE *dirf;              /* descriptor for .dir file */
329 static int dirronly;            /* dirf open read-only? */
330 static FILE *pagf = NULL;       /* descriptor for .pag file */
331 static off_t pagpos;            /* posn in pagf; only search may set != -1 */
332 static int pagronly;            /* pagf open read-only? */
333 static off_t *corepag;          /* incore version of .pag file, if any */
334 static FILE *bufpagf;           /* well-buffered pagf, for incore rewrite */
335 static off_t *getcore();
336 static int putcore();
337 static int written;             /* has a store() been done? */
338
339 /*
340  - dbzfresh - set up a new database, no historical info
341  */
342 int                             /* 0 success, -1 failure */
343 dbzfresh(name, size, fs, cmap, tagmask)
344 char *name;                     /* base name; .dir and .pag must exist */
345 long size;                      /* table size (0 means default) */
346 int fs;                         /* field-separator character in base file */
347 int cmap;                       /* case-map algorithm (0 means default) */
348 off_t tagmask;                  /* 0 default, 1 no tags */
349 {
350         register char *fn;
351         struct dbzconfig c;
352         register off_t m;
353         register FILE *f;
354
355         if (pagf != NULL) {
356                 DEBUG(("dbzfresh: database already open\n"));
357                 return(-1);
358         }
359         if (size != 0 && size < 2) {
360                 DEBUG(("dbzfresh: preposterous size (%ld)\n", size));
361                 return(-1);
362         }
363
364         /* get default configuration */
365         if (getconf((FILE *)NULL, (FILE *)NULL, &c) < 0)
366                 return(-1);     /* "can't happen" */
367
368         /* and mess with it as specified */
369         if (size != 0)
370                 c.tsize = size;
371         c.fieldsep = fs;
372         switch (cmap) {
373         case 0:
374         case '0':
375         case 'B':               /* 2.10 compat */
376                 c.casemap = '0';        /* '\0' nicer, but '0' printable! */
377                 break;
378         case '=':
379         case 'b':               /* 2.11 compat */
380                 c.casemap = '=';
381                 break;
382         case 'C':
383                 c.casemap = 'C';
384                 break;
385         case '?':
386                 c.casemap = DEFCASE;
387                 break;
388         default:
389                 DEBUG(("dbzfresh case map `%c' unknown\n", cmap));
390                 return(-1);
391                 break;
392         }
393         switch (tagmask) {
394         case 0:                 /* default */
395                 break;
396         case 1:                 /* no tags */
397                 c.tagshift = 0;
398                 c.tagmask = 0;
399                 c.tagenb = 0;
400                 break;
401         default:
402                 m = tagmask;
403                 c.tagshift = 0;
404                 while (!(m&01)) {
405                         m >>= 1;
406                         c.tagshift++;
407                 }
408                 c.tagmask = m;
409                 c.tagenb = (m << 1) & ~m;
410                 break;
411         }
412
413         /* write it out */
414         fn = enstring(name, dir);
415         if (fn == NULL)
416                 return(-1);
417         f = fopen(fn, "w");
418         free(fn);
419         if (f == NULL) {
420                 DEBUG(("dbzfresh: unable to write config\n"));
421                 return(-1);
422         }
423         if (putconf(f, &c) < 0) {
424                 (void) fclose(f);
425                 return(-1);
426         }
427         if (fclose(f) == EOF) {
428                 DEBUG(("dbzfresh: fclose failure\n"));
429                 return(-1);
430         }
431
432         /* create/truncate .pag */
433         fn = enstring(name, pag);
434         if (fn == NULL)
435                 return(-1);
436         f = fopen(fn, "w");
437         free(fn);
438         if (f == NULL) {
439                 DEBUG(("dbzfresh: unable to create/truncate .pag file\n"));
440                 return(-1);
441         } else
442                 (void) fclose(f);
443
444         /* and punt to dbminit for the hard work */
445         return(dbminit(name));
446 }
447
448 /*
449  - dbzsize - what's a good table size to hold this many entries?
450  */
451 long
452 dbzsize(contents)
453 long contents;                  /* 0 means what's the default */
454 {
455         register long n;
456
457         if (contents <= 0) {    /* foulup or default inquiry */
458                 DEBUG(("dbzsize: preposterous input (%ld)\n", contents));
459                 return(DEFSIZE);
460         }
461         n = (contents/2)*3;     /* try to keep table at most 2/3 full */
462         if (!(n&01))            /* make it odd */
463                 n++;
464         DEBUG(("dbzsize: tentative size %ld\n", n));
465         while (!isprime(n))     /* and look for a prime */
466                 n += 2;
467         DEBUG(("dbzsize: final size %ld\n", n));
468
469         return(n);
470 }
471
472 /*
473  - isprime - is a number prime?
474  *
475  * This is not a terribly efficient approach.
476  */
477 static int                      /* predicate */
478 isprime(x)
479 register long x;
480 {
481         static int quick[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 0 };
482         register int *ip;
483         register long div;
484         register long stop;
485
486         /* hit the first few primes quickly to eliminate easy ones */
487         /* this incidentally prevents ridiculously small tables */
488         for (ip = quick; (div = *ip) != 0; ip++)
489                 if (x%div == 0) {
490                         DEBUG(("isprime: quick result on %ld\n", (long)x));
491                         return(0);
492                 }
493
494         /* approximate square root of x */
495         for (stop = x; x/stop < stop; stop >>= 1)
496                 continue;
497         stop <<= 1;
498
499         /* try odd numbers up to stop */
500         for (div = *--ip; div < stop; div += 2)
501                 if (x%div == 0)
502                         return(0);
503
504         return(1);
505 }
506
507 /*
508  - dbzagain - set up a new database to be a rebuild of an old one
509  */
510 int                             /* 0 success, -1 failure */
511 dbzagain(name, oldname)
512 char *name;                     /* base name; .dir and .pag must exist */
513 char *oldname;                  /* base name; all must exist */
514 {
515         register char *fn;
516         struct dbzconfig c;
517         register int i;
518         register long top;
519         register FILE *f;
520         register int newtable;
521         register off_t newsize;
522
523         if (pagf != NULL) {
524                 DEBUG(("dbzagain: database already open\n"));
525                 return(-1);
526         }
527
528         /* pick up the old configuration */
529         fn = enstring(oldname, dir);
530         if (fn == NULL)
531                 return(-1);
532         f = fopen(fn, "r");
533         free(fn);
534         if (f == NULL) {
535                 DEBUG(("dbzagain: cannot open old .dir file\n"));
536                 return(-1);
537         }
538         i = getconf(f, (FILE *)NULL, &c);
539         (void) fclose(f);
540         if (i < 0) {
541                 DEBUG(("dbzagain: getconf failed\n"));
542                 return(-1);
543         }
544
545         /* tinker with it */
546         top = 0;
547         newtable = 0;
548         for (i = 0; i < NUSEDS; i++) {
549                 if (top < c.used[i])
550                         top = c.used[i];
551                 if (c.used[i] == 0)
552                         newtable = 1;   /* hasn't got full usage history yet */
553         }
554         if (top == 0) {
555                 DEBUG(("dbzagain: old table has no contents!\n"));
556                 newtable = 1;
557         }
558         for (i = NUSEDS-1; i > 0; i--)
559                 c.used[i] = c.used[i-1];
560         c.used[0] = 0;
561         newsize = dbzsize(top);
562         if (!newtable || newsize > c.tsize)     /* don't shrink new table */
563                 c.tsize = newsize;
564
565         /* write it out */
566         fn = enstring(name, dir);
567         if (fn == NULL)
568                 return(-1);
569         f = fopen(fn, "w");
570         free(fn);
571         if (f == NULL) {
572                 DEBUG(("dbzagain: unable to write new .dir\n"));
573                 return(-1);
574         }
575         i = putconf(f, &c);
576         (void) fclose(f);
577         if (i < 0) {
578                 DEBUG(("dbzagain: putconf failed\n"));
579                 return(-1);
580         }
581
582         /* create/truncate .pag */
583         fn = enstring(name, pag);
584         if (fn == NULL)
585                 return(-1);
586         f = fopen(fn, "w");
587         free(fn);
588         if (f == NULL) {
589                 DEBUG(("dbzagain: unable to create/truncate .pag file\n"));
590                 return(-1);
591         } else
592                 (void) fclose(f);
593
594         /* and let dbminit do the work */
595         return(dbminit(name));
596 }
597
598 /*
599  - dbminit - open a database, creating it (using defaults) if necessary
600  *
601  * We try to leave errno set plausibly, to the extent that underlying
602  * functions permit this, since many people consult it if dbminit() fails.
603  */
604 int                             /* 0 success, -1 failure */
605 dbminit(name)
606 char *name;
607 {
608         register int i;
609         register size_t s;
610         register char *dirfname;
611         register char *pagfname;
612
613         if (pagf != NULL) {
614                 DEBUG(("dbminit: dbminit already called once\n"));
615                 errno = 0;
616                 return(-1);
617         }
618
619         /* open the .dir file */
620         dirfname = enstring(name, dir);
621         if (dirfname == NULL)
622                 return(-1);
623         dirf = fopen(dirfname, "r+");
624         if (dirf == NULL) {
625                 dirf = fopen(dirfname, "r");
626                 dirronly = 1;
627         } else
628                 dirronly = 0;
629         free(dirfname);
630         if (dirf == NULL) {
631                 DEBUG(("dbminit: can't open .dir file\n"));
632                 return(-1);
633         }
634
635         /* open the .pag file */
636         pagfname = enstring(name, pag);
637         if (pagfname == NULL) {
638                 (void) fclose(dirf);
639                 return(-1);
640         }
641         pagf = fopen(pagfname, "r+b");
642         if (pagf == NULL) {
643                 pagf = fopen(pagfname, "rb");
644                 if (pagf == NULL) {
645                         DEBUG(("dbminit: .pag open failed\n"));
646                         (void) fclose(dirf);
647                         free(pagfname);
648                         return(-1);
649                 }
650                 pagronly = 1;
651         } else if (dirronly)
652                 pagronly = 1;
653         else
654                 pagronly = 0;
655 #ifdef NOBUFFER
656         /*
657          * B News does not do adequate locking on its database accesses.
658          * Why it doesn't get into trouble using dbm is a mystery.  In any
659          * case, doing unbuffered i/o does not cure the problem, but does
660          * enormously reduce its incidence.
661          */
662         (void) setbuf(pagf, (char *)NULL);
663 #else
664 #ifdef _IOFBF
665         (void) setvbuf(pagf, (char *)pagbuf, _IOFBF, sizeof(pagbuf));
666 #endif
667 #endif
668         pagpos = -1;
669         /* don't free pagfname, need it below */
670
671         /* open the base file */
672         basef = fopen(name, "r");
673         if (basef == NULL) {
674                 DEBUG(("dbminit: basefile open failed\n"));
675                 basefname = enstring(name, "");
676                 if (basefname == NULL) {
677                         (void) fclose(pagf);
678                         (void) fclose(dirf);
679                         free(pagfname);
680                         pagf = NULL;
681                         return(-1);
682                 }
683         } else
684                 basefname = NULL;
685 #ifdef _IOFBF
686         if (basef != NULL)
687                 (void) setvbuf(basef, basebuf, _IOFBF, sizeof(basebuf));
688 #endif
689
690         /* pick up configuration */
691         if (getconf(dirf, pagf, &conf) < 0) {
692                 DEBUG(("dbminit: getconf failure\n"));
693                 (void) fclose(basef);
694                 (void) fclose(pagf);
695                 (void) fclose(dirf);
696                 free(pagfname);
697                 pagf = NULL;
698                 errno = EDOM;   /* kind of a kludge, but very portable */
699                 return(-1);
700         }
701         tagbits = conf.tagmask << conf.tagshift;
702         taghere = conf.tagenb << conf.tagshift;
703         tagboth = tagbits | taghere;
704         mybytemap(mybmap);
705         bytesame = 1;
706         for (i = 0; i < SOF; i++)
707                 if (mybmap[i] != conf.bytemap[i])
708                         bytesame = 0;
709
710         /* get first table into core, if it looks desirable and feasible */
711         s = (size_t)conf.tsize * SOF;
712         if (incore && (off_t)(s/SOF) == conf.tsize) {
713                 bufpagf = fopen(pagfname, (pagronly) ? "rb" : "r+b");
714                 if (bufpagf != NULL)
715                         corepag = getcore(bufpagf);
716         } else {
717                 bufpagf = NULL;
718                 corepag = NULL;
719         }
720         free(pagfname);
721
722         /* misc. setup */
723         crcinit();
724         written = 0;
725         prevp = FRESH;
726         DEBUG(("dbminit: succeeded\n"));
727         return(0);
728 }
729
730 /*
731  - enstring - concatenate two strings into a malloced area
732  */
733 static char *                   /* NULL if malloc fails */
734 enstring(s1, s2)
735 char *s1;
736 char *s2;
737 {
738         register char *p;
739
740         p = malloc((size_t)strlen(s1) + (size_t)strlen(s2) + 1);
741         if (p != NULL) {
742                 (void) strcpy(p, s1);
743                 (void) strcat(p, s2);
744         } else {
745                 DEBUG(("enstring(%s, %s) out of memory\n", s1, s2));
746         }
747         return(p);
748 }
749
750 /*
751  - dbmclose - close a database
752  */
753 int
754 dbmclose()
755 {
756         register int ret = 0;
757
758         if (pagf == NULL) {
759                 DEBUG(("dbmclose: not opened!\n"));
760                 return(-1);
761         }
762
763         if (fclose(pagf) == EOF) {
764                 DEBUG(("dbmclose: fclose(pagf) failed\n"));
765                 ret = -1;
766         }
767         pagf = basef;           /* ensure valid pointer; dbzsync checks it */
768         if (dbzsync() < 0)
769                 ret = -1;
770         if (bufpagf != NULL && fclose(bufpagf) == EOF) {
771                 DEBUG(("dbmclose: fclose(bufpagf) failed\n"));
772                 ret = -1;
773         }
774         if (corepag != NULL)
775                 free((char *)corepag);
776         corepag = NULL;
777         if (fclose(basef) == EOF) {
778                 DEBUG(("dbmclose: fclose(basef) failed\n"));
779                 ret = -1;
780         }
781         if (basefname != NULL)
782                 free(basefname);
783         basef = NULL;
784         pagf = NULL;
785         if (fclose(dirf) == EOF) {
786                 DEBUG(("dbmclose: fclose(dirf) failed\n"));
787                 ret = -1;
788         }
789
790         DEBUG(("dbmclose: %s\n", (ret == 0) ? "succeeded" : "failed"));
791         return(ret);
792 }
793
794 /*
795  - dbzsync - push all in-core data out to disk
796  */
797 int
798 dbzsync()
799 {
800         register int ret = 0;
801
802         if (pagf == NULL) {
803                 DEBUG(("dbzsync: not opened!\n"));
804                 return(-1);
805         }
806         if (!written)
807                 return(0);
808
809         if (corepag != NULL) {
810                 if (putcore(corepag, bufpagf) < 0) {
811                         DEBUG(("dbzsync: putcore failed\n"));
812                         ret = -1;
813                 }
814         }
815         if (!conf.olddbz)
816                 if (putconf(dirf, &conf) < 0)
817                         ret = -1;
818
819         DEBUG(("dbzsync: %s\n", (ret == 0) ? "succeeded" : "failed"));
820         return(ret);
821 }
822
823 /*
824  - dbzcancel - cancel writing of in-core data
825  * Mostly for use from child processes.
826  * Note that we don't need to futz around with stdio buffers, because we
827  * always fflush them immediately anyway and so they never have stale data.
828  */
829 int
830 dbzcancel()
831 {
832         if (pagf == NULL) {
833                 DEBUG(("dbzcancel: not opened!\n"));
834                 return(-1);
835         }
836
837         written = 0;
838         return(0);
839 }
840
841 /*
842  - dbzfetch - fetch() with case mapping built in
843  */
844 datum
845 dbzfetch(key)
846 datum key;
847 {
848         char buffer[DBZMAXKEY + 1];
849         datum mappedkey;
850         register size_t keysize;
851
852         DEBUG(("dbzfetch: (%s)\n", key.dptr));
853
854         /* Key is supposed to be less than DBZMAXKEY */
855         keysize = key.dsize;
856         if (keysize >= DBZMAXKEY) {
857                 keysize = DBZMAXKEY;
858                 DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY));
859         }
860
861         mappedkey.dptr = mapcase(buffer, key.dptr, keysize);
862         buffer[keysize] = '\0'; /* just a debug aid */
863         mappedkey.dsize = keysize;
864
865         return(fetch(mappedkey));
866 }
867
868 /*
869  - fetch - get an entry from the database
870  *
871  * Disgusting fine point, in the name of backward compatibility:  if the
872  * last character of "key" is a NUL, that character is (effectively) not
873  * part of the comparison against the stored keys.
874  */
875 datum                           /* dptr NULL, dsize 0 means failure */
876 fetch(key)
877 datum key;
878 {
879         char buffer[DBZMAXKEY + 1];
880         static off_t key_ptr;           /* return value points here */
881         datum output;
882         register size_t keysize;
883         register size_t cmplen;
884         register char *sepp;
885
886         DEBUG(("fetch: (%s)\n", key.dptr));
887         output.dptr = NULL;
888         output.dsize = 0;
889         prevp = FRESH;
890
891         /* Key is supposed to be less than DBZMAXKEY */
892         keysize = key.dsize;
893         if (keysize >= DBZMAXKEY) {
894                 keysize = DBZMAXKEY;
895                 DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY));
896         }
897
898         if (pagf == NULL) {
899                 DEBUG(("fetch: database not open!\n"));
900                 return(output);
901         } else if (basef == NULL) {     /* basef didn't exist yet */
902                 basef = latebase();
903                 if (basef == NULL)
904                         return(output);
905         }
906
907         cmplen = keysize;
908         sepp = &conf.fieldsep;
909         if (key.dptr[keysize-1] == '\0') {
910                 cmplen--;
911                 sepp = &buffer[keysize-1];
912         }
913         start(&srch, &key, FRESH);
914         while ((key_ptr = search(&srch)) != NOTFOUND) {
915                 DEBUG(("got 0x%lx\n", key_ptr));
916
917                 /* fetch the key */
918                 if (fseek(basef, key_ptr, SEEK_SET) != 0) {
919                         DEBUG(("fetch: seek failed\n"));
920                         return(output);
921                 }
922                 if (fread(buffer, 1, keysize, basef) != keysize) {
923                         DEBUG(("fetch: read failed\n"));
924                         return(output);
925                 }
926
927                 /* try it */
928                 buffer[keysize] = '\0';         /* terminated for DEBUG */
929                 (void) mapcase(buffer, buffer, keysize);
930                 DEBUG(("fetch: buffer (%s) looking for (%s) size = %d\n", 
931                                                 buffer, key.dptr, keysize));
932                 if (memcmp(key.dptr, buffer, cmplen) == 0 &&
933                                 (*sepp == conf.fieldsep || *sepp == '\0')) {
934                         /* we found it */
935                         output.dptr = (char *)&key_ptr;
936                         output.dsize = SOF;
937                         DEBUG(("fetch: successful\n"));
938                         return(output);
939                 }
940         }
941
942         /* we didn't find it */
943         DEBUG(("fetch: failed\n"));
944         prevp = &srch;                  /* remember where we stopped */
945         return(output);
946 }
947
948 /*
949  - latebase - try to open a base file that wasn't there at the start
950  */
951 static FILE *
952 latebase()
953 {
954         register FILE *it;
955
956         if (basefname == NULL) {
957                 DEBUG(("latebase: name foulup\n"));
958                 return(NULL);
959         }
960         it = fopen(basefname, "r");
961         if (it == NULL) {
962                 DEBUG(("latebase: still can't open base\n"));
963         } else {
964                 DEBUG(("latebase: late open succeeded\n"));
965                 free(basefname);
966                 basefname = NULL;
967 #ifdef _IOFBF
968                 (void) setvbuf(it, basebuf, _IOFBF, sizeof(basebuf));
969 #endif
970         }
971         return(it);
972 }
973
974 /*
975  - dbzstore - store() with case mapping built in
976  */
977 int
978 dbzstore(key, data)
979 datum key;
980 datum data;
981 {
982         char buffer[DBZMAXKEY + 1];
983         datum mappedkey;
984         register size_t keysize;
985
986         DEBUG(("dbzstore: (%s)\n", key.dptr));
987
988         /* Key is supposed to be less than DBZMAXKEY */
989         keysize = key.dsize;
990         if (keysize >= DBZMAXKEY) {
991                 DEBUG(("dbzstore: key size too big (%d)\n", key.dsize));
992                 return(-1);
993         }
994
995         mappedkey.dptr = mapcase(buffer, key.dptr, keysize);
996         buffer[keysize] = '\0'; /* just a debug aid */
997         mappedkey.dsize = keysize;
998
999         return(store(mappedkey, data));
1000 }
1001
1002 /*
1003  - store - add an entry to the database
1004  */
1005 int                             /* 0 success, -1 failure */
1006 store(key, data)
1007 datum key;
1008 datum data;
1009 {
1010         off_t value;
1011
1012         if (pagf == NULL) {
1013                 DEBUG(("store: database not open!\n"));
1014                 return(-1);
1015         } else if (basef == NULL) {     /* basef didn't exist yet */
1016                 basef = latebase();
1017                 if (basef == NULL)
1018                         return(-1);
1019         }
1020         if (pagronly) {
1021                 DEBUG(("store: database open read-only\n"));
1022                 return(-1);
1023         }
1024         if (data.dsize != SOF) {
1025                 DEBUG(("store: value size wrong (%d)\n", data.dsize));
1026                 return(-1);
1027         }
1028         if (key.dsize >= DBZMAXKEY) {
1029                 DEBUG(("store: key size too big (%d)\n", key.dsize));
1030                 return(-1);
1031         }
1032
1033         /* copy the value in to ensure alignment */
1034         (void) memcpy((char *)&value, data.dptr, SOF);
1035         DEBUG(("store: (%s, %ld)\n", key.dptr, (long)value));
1036         if (!okayvalue(value)) {
1037                 DEBUG(("store: reserved bit or overflow in 0x%lx\n", value));
1038                 return(-1);
1039         }
1040
1041         /* find the place, exploiting previous search if possible */
1042         start(&srch, &key, prevp);
1043         while (search(&srch) != NOTFOUND)
1044                 continue;
1045
1046         prevp = FRESH;
1047         conf.used[0]++;
1048         DEBUG(("store: used count %ld\n", conf.used[0]));
1049         written = 1;
1050         return(set(&srch, value));
1051 }
1052
1053 /*
1054  - dbzincore - control attempts to keep .pag file in core
1055  */
1056 int                             /* old setting */
1057 dbzincore(value)
1058 int value;
1059 {
1060         register int old = incore;
1061
1062         incore = value;
1063         return(old);
1064 }
1065
1066 /*
1067  - getconf - get configuration from .dir file
1068  */
1069 static int                      /* 0 success, -1 failure */
1070 getconf(df, pf, cp)
1071 register FILE *df;              /* NULL means just give me the default */
1072 register FILE *pf;              /* NULL means don't care about .pag */
1073 register struct dbzconfig *cp;
1074 {
1075         register int c;
1076         register int i;
1077         int err = 0;
1078
1079         c = (df != NULL) ? getc(df) : EOF;
1080         if (c == EOF) {         /* empty file, no configuration known */
1081                 cp->olddbz = 0;
1082                 if (df != NULL && pf != NULL && getc(pf) != EOF)
1083                         cp->olddbz = 1;
1084                 cp->tsize = DEFSIZE;
1085                 cp->fieldsep = '\t';
1086                 for (i = 0; i < NUSEDS; i++)
1087                         cp->used[i] = 0;
1088                 cp->valuesize = SOF;
1089                 mybytemap(cp->bytemap);
1090                 cp->casemap = DEFCASE;
1091                 cp->tagenb = TAGENB;
1092                 cp->tagmask = TAGMASK;
1093                 cp->tagshift = TAGSHIFT;
1094                 DEBUG(("getconf: defaults (%ld, %c, (0x%lx/0x%lx<<%d))\n",
1095                         cp->tsize, cp->casemap, cp->tagenb, 
1096                         cp->tagmask, cp->tagshift));
1097                 return(0);
1098         }
1099         (void) ungetc(c, df);
1100
1101         /* first line, the vital stuff */
1102         if (getc(df) != 'd' || getc(df) != 'b' || getc(df) != 'z')
1103                 err = -1;
1104         if (getno(df, &err) != dbzversion)
1105                 err = -1;
1106         cp->tsize = getno(df, &err);
1107         cp->fieldsep = getno(df, &err);
1108         while ((c = getc(df)) == ' ')
1109                 continue;
1110         cp->casemap = c;
1111         cp->tagenb = getno(df, &err);
1112         cp->tagmask = getno(df, &err);
1113         cp->tagshift = getno(df, &err);
1114         cp->valuesize = getno(df, &err);
1115         if (cp->valuesize != SOF) {
1116                 DEBUG(("getconf: wrong off_t size (%d)\n", cp->valuesize));
1117                 err = -1;
1118                 cp->valuesize = SOF;    /* to protect the loops below */
1119         }
1120         for (i = 0; i < cp->valuesize; i++)
1121                 cp->bytemap[i] = getno(df, &err);
1122         if (getc(df) != '\n')
1123                 err = -1;
1124         DEBUG(("size %ld, sep %d, cmap %c, tags 0x%lx/0x%lx<<%d, ", cp->tsize,
1125                         cp->fieldsep, cp->casemap, cp->tagenb, cp->tagmask,
1126                         cp->tagshift));
1127         DEBUG(("bytemap (%d)", cp->valuesize));
1128         for (i = 0; i < cp->valuesize; i++) {
1129                 DEBUG((" %d", cp->bytemap[i]));
1130         }
1131         DEBUG(("\n"));
1132
1133         /* second line, the usages */
1134         for (i = 0; i < NUSEDS; i++)
1135                 cp->used[i] = getno(df, &err);
1136         if (getc(df) != '\n')
1137                 err = -1;
1138         DEBUG(("used %ld %ld %ld...\n", cp->used[0], cp->used[1], cp->used[2]));
1139
1140         if (err < 0) {
1141                 DEBUG(("getconf error\n"));
1142                 return(-1);
1143         }
1144         return(0);
1145 }
1146
1147 /*
1148  - getno - get a long
1149  */
1150 static long
1151 getno(f, ep)
1152 FILE *f;
1153 int *ep;
1154 {
1155         register char *p;
1156 #       define  MAXN    50
1157         char getbuf[MAXN];
1158         register int c;
1159
1160         while ((c = getc(f)) == ' ')
1161                 continue;
1162         if (c == EOF || c == '\n') {
1163                 DEBUG(("getno: missing number\n"));
1164                 *ep = -1;
1165                 return(0);
1166         }
1167         p = getbuf;
1168         *p++ = c;
1169         while ((c = getc(f)) != EOF && c != '\n' && c != ' ')
1170                 if (p < &getbuf[MAXN-1])
1171                         *p++ = c;
1172         if (c == EOF) {
1173                 DEBUG(("getno: EOF\n"));
1174                 *ep = -1;
1175         } else
1176                 (void) ungetc(c, f);
1177         *p = '\0';
1178
1179         if (strspn(getbuf, "-1234567890") != strlen(getbuf)) {
1180                 DEBUG(("getno: `%s' non-numeric\n", getbuf));
1181                 *ep = -1;
1182         }
1183         return(atol(getbuf));
1184 }
1185
1186 /*
1187  - putconf - write configuration to .dir file
1188  */
1189 static int                      /* 0 success, -1 failure */
1190 putconf(f, cp)
1191 register FILE *f;
1192 register struct dbzconfig *cp;
1193 {
1194         register int i;
1195         register int ret = 0;
1196
1197         if (fseek(f, 0, SEEK_SET) != 0) {
1198                 DEBUG(("fseek failure in putconf\n"));
1199                 ret = -1;
1200         }
1201         fprintf(f, "dbz %d %ld %d %c %ld %ld %d %d", dbzversion,
1202                 (long)cp->tsize,
1203                 cp->fieldsep, cp->casemap, (long)cp->tagenb,
1204                 (long)cp->tagmask, cp->tagshift,
1205                 cp->valuesize);
1206
1207         for (i = 0; i < cp->valuesize; i++)
1208                 fprintf(f, " %d", cp->bytemap[i]);
1209         fprintf(f, "\n");
1210         for (i = 0; i < NUSEDS; i++)
1211                 fprintf(f, "%ld%c",
1212                         (long)cp->used[i], (i < NUSEDS-1) ? ' ' : '\n');
1213
1214
1215         (void) fflush(f);
1216         if (ferror(f))
1217                 ret = -1;
1218
1219         DEBUG(("putconf status %d\n", ret));
1220         return(ret);
1221 }
1222
1223 /*
1224  - getcore - try to set up an in-core copy of .pag file
1225  */
1226 static off_t *                  /* pointer to copy, or NULL */
1227 getcore(f)
1228 FILE *f;
1229 {
1230         register off_t *p;
1231         register size_t i;
1232         register size_t nread;
1233         register char *it;
1234
1235         it = malloc((size_t)conf.tsize * SOF);
1236         if (it == NULL) {
1237                 DEBUG(("getcore: malloc failed\n"));
1238                 return(NULL);
1239         }
1240
1241         nread = fread(it, SOF, (size_t)conf.tsize, f);
1242         if (ferror(f)) {
1243                 DEBUG(("getcore: read failed\n"));
1244                 free(it);
1245                 return(NULL);
1246         }
1247
1248         p = (off_t *)it + nread;
1249         i = (size_t)conf.tsize - nread;
1250         while (i-- > 0)
1251                 *p++ = VACANT;
1252         return((off_t *)it);
1253 }
1254
1255 /*
1256  - putcore - try to rewrite an in-core table
1257  */
1258 static int                      /* 0 okay, -1 fail */
1259 putcore(tab, f)
1260 off_t *tab;
1261 FILE *f;
1262 {
1263         if (fseek(f, 0, SEEK_SET) != 0) {
1264                 DEBUG(("fseek failure in putcore\n"));
1265                 return(-1);
1266         }
1267         (void) fwrite((char *)tab, SOF, (size_t)conf.tsize, f);
1268         (void) fflush(f);
1269         return((ferror(f)) ? -1 : 0);
1270 }
1271
1272 /*
1273  - start - set up to start or restart a search
1274  */
1275 static void
1276 start(sp, kp, osp)
1277 register struct searcher *sp;
1278 register datum *kp;
1279 register struct searcher *osp;          /* may be FRESH, i.e. NULL */
1280 {
1281         register long h;
1282
1283         h = hash(kp->dptr, kp->dsize);
1284         if (osp != FRESH && osp->hash == h) {
1285                 if (sp != osp)
1286                         *sp = *osp;
1287                 DEBUG(("search restarted\n"));
1288         } else {
1289                 sp->hash = h;
1290                 sp->tag = MKTAG(h / conf.tsize);
1291                 DEBUG(("tag 0x%lx\n", sp->tag));
1292                 sp->place = h % conf.tsize;
1293                 sp->tabno = 0;
1294                 sp->run = (conf.olddbz) ? conf.tsize : MAXRUN;
1295                 sp->aborted = 0;
1296         }
1297         sp->seen = 0;
1298 }
1299
1300 /*
1301  - search - conduct part of a search
1302  */
1303 static off_t                    /* NOTFOUND if we hit VACANT or error */
1304 search(sp)
1305 register struct searcher *sp;
1306 {
1307         register off_t dest;
1308         register off_t value;
1309         off_t val;              /* buffer for value (can't fread register) */
1310         register off_t place;
1311
1312         if (sp->aborted)
1313                 return(NOTFOUND);
1314
1315         for (;;) {
1316                 /* determine location to be examined */
1317                 place = sp->place;
1318                 if (sp->seen) {
1319                         /* go to next location */
1320                         if (--sp->run <= 0) {
1321                                 sp->tabno++;
1322                                 sp->run = MAXRUN;
1323                         }
1324                         place = (place+1)%conf.tsize + sp->tabno*conf.tsize;
1325                         sp->place = place;
1326                 } else
1327                         sp->seen = 1;   /* now looking at current location */
1328                 DEBUG(("search @ %ld\n", place));
1329
1330                 /* get the tagged value */
1331                 if (corepag != NULL && place < conf.tsize) {
1332                         DEBUG(("search: in core\n"));
1333                         value = MAPIN(corepag[place]);
1334                 } else {
1335                         /* seek, if necessary */
1336                         dest = place * SOF;
1337                         if (pagpos != dest) {
1338                                 if (fseek(pagf, dest, SEEK_SET) != 0) {
1339                                         DEBUG(("search: seek failed\n"));
1340                                         pagpos = -1;
1341                                         sp->aborted = 1;
1342                                         return(NOTFOUND);
1343                                 }
1344                                 pagpos = dest;
1345                         }
1346
1347                         /* read it */
1348                         if (fread((char *)&val, sizeof(val), 1, pagf) == 1)
1349                                 value = MAPIN(val);
1350                         else if (ferror(pagf)) {
1351                                 DEBUG(("search: read failed\n"));
1352                                 pagpos = -1;
1353                                 sp->aborted = 1;
1354                                 return(NOTFOUND);
1355                         } else
1356                                 value = VACANT;
1357
1358                         /* and finish up */
1359                         pagpos += sizeof(val);
1360                 }
1361
1362                 /* vacant slot is always cause to return */
1363                 if (value == VACANT) {
1364                         DEBUG(("search: empty slot\n"));
1365                         return(NOTFOUND);
1366                 };
1367
1368                 /* check the tag */
1369                 value = UNBIAS(value);
1370                 DEBUG(("got 0x%lx\n", value));
1371                 if (!HASTAG(value)) {
1372                         DEBUG(("tagless\n"));
1373                         return(value);
1374                 } else if (TAG(value) == sp->tag) {
1375                         DEBUG(("match\n"));
1376                         return(NOTAG(value));
1377                 } else {
1378                         DEBUG(("mismatch 0x%lx\n", TAG(value)));
1379                 }
1380         }
1381         /* NOTREACHED */
1382 }
1383
1384 /*
1385  - okayvalue - check that a value can be stored
1386  */
1387 static int                      /* predicate */
1388 okayvalue(value)
1389 off_t value;
1390 {
1391         if (HASTAG(value))
1392                 return(0);
1393 #ifdef OVERFLOW
1394         if (value == LONG_MAX)  /* BIAS() and UNBIAS() will overflow */
1395                 return(0);
1396 #endif
1397         return(1);
1398 }
1399
1400 /*
1401  - set - store a value into a location previously found by search
1402  */
1403 static int                      /* 0 success, -1 failure */
1404 set(sp, value)
1405 register struct searcher *sp;
1406 off_t value;
1407 {
1408         register off_t place = sp->place;
1409         register off_t v = value;
1410
1411         if (sp->aborted)
1412                 return(-1);
1413
1414         if (CANTAG(v) && !conf.olddbz) {
1415                 v |= sp->tag | taghere;
1416                 if (v != UNBIAS(VACANT))        /* BIAS(v) won't look VACANT */
1417 #ifdef OVERFLOW
1418                         if (v != LONG_MAX)      /* and it won't overflow */
1419 #endif
1420                         value = v;
1421         }
1422         DEBUG(("tagged value is 0x%lx\n", value));
1423         value = BIAS(value);
1424         value = MAPOUT(value);
1425
1426         /* If we have the index file in memory, use it */
1427         if (corepag != NULL && place < conf.tsize) {
1428                 corepag[place] = value;
1429                 DEBUG(("set: incore\n"));
1430                 return(0);
1431         }
1432
1433         /* seek to spot */
1434         pagpos = -1;            /* invalidate position memory */
1435         if (fseek(pagf, place * SOF, SEEK_SET) != 0) {
1436                 DEBUG(("set: seek failed\n"));
1437                 sp->aborted = 1;
1438                 return(-1);
1439         }
1440
1441         /* write in data */
1442         if (fwrite((char *)&value, SOF, 1, pagf) != 1) {
1443                 DEBUG(("set: write failed\n"));
1444                 sp->aborted = 1;
1445                 return(-1);
1446         }
1447         /* fflush improves robustness, and buffer re-use is rare anyway */
1448         if (fflush(pagf) == EOF) {
1449                 DEBUG(("set: fflush failed\n"));
1450                 sp->aborted = 1;
1451                 return(-1);
1452         }
1453
1454         DEBUG(("set: succeeded\n"));
1455         return(0);
1456 }
1457
1458 /*
1459  - mybytemap - determine this machine's byte map
1460  *
1461  * A byte map is an array of ints, sizeof(off_t) of them.  The 0th int
1462  * is the byte number of the high-order byte in my off_t, and so forth.
1463  */
1464 static void
1465 mybytemap(map)
1466 int map[];                      /* -> int[SOF] */
1467 {
1468         union {
1469                 off_t o;
1470                 char c[SOF];
1471         } u;
1472         register int *mp = &map[SOF];
1473         register int ntodo;
1474         register int i;
1475
1476         u.o = 1;
1477         for (ntodo = (int)SOF; ntodo > 0; ntodo--) {
1478                 for (i = 0; i < SOF; i++)
1479                         if (u.c[i] != 0)
1480                                 break;
1481                 if (i == SOF) {
1482                         /* trouble -- set it to *something* consistent */
1483                         DEBUG(("mybytemap: nonexistent byte %d!!!\n", ntodo));
1484                         for (i = 0; i < SOF; i++)
1485                                 map[i] = i;
1486                         return;
1487                 }
1488                 DEBUG(("mybytemap: byte %d\n", i));
1489                 *--mp = i;
1490                 while (u.c[i] != 0)
1491                         u.o <<= 1;
1492         }
1493 }
1494
1495 /*
1496  - bytemap - transform an off_t from byte ordering map1 to map2
1497  */
1498 static off_t                    /* transformed result */
1499 bytemap(ino, map1, map2)
1500 off_t ino;
1501 int *map1;
1502 int *map2;
1503 {
1504         union oc {
1505                 off_t o;
1506                 char c[SOF];
1507         };
1508         union oc in;
1509         union oc out;
1510         register int i;
1511
1512         in.o = ino;
1513         for (i = 0; i < SOF; i++)
1514                 out.c[map2[i]] = in.c[map1[i]];
1515         return(out.o);
1516 }
1517
1518 /*
1519  * This is a simplified version of the pathalias hashing function.
1520  * Thanks to Steve Belovin and Peter Honeyman
1521  *
1522  * hash a string into a long int.  31 bit crc (from andrew appel).
1523  * the crc table is computed at run time by crcinit() -- we could
1524  * precompute, but it takes 1 clock tick on a 750.
1525  *
1526  * This fast table calculation works only if POLY is a prime polynomial
1527  * in the field of integers modulo 2.  Since the coefficients of a
1528  * 32-bit polynomial won't fit in a 32-bit word, the high-order bit is
1529  * implicit.  IT MUST ALSO BE THE CASE that the coefficients of orders
1530  * 31 down to 25 are zero.  Happily, we have candidates, from
1531  * E. J.  Watson, "Primitive Polynomials (Mod 2)", Math. Comp. 16 (1962):
1532  *      x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + x^0
1533  *      x^31 + x^3 + x^0
1534  *
1535  * We reverse the bits to get:
1536  *      111101010000000000000000000000001 but drop the last 1
1537  *         f   5   0   0   0   0   0   0
1538  *      010010000000000000000000000000001 ditto, for 31-bit crc
1539  *         4   8   0   0   0   0   0   0
1540  */
1541
1542 #define POLY 0x48000000L        /* 31-bit polynomial (avoids sign problems) */
1543
1544 static long CrcTable[128];
1545
1546 /*
1547  - crcinit - initialize tables for hash function
1548  */
1549 static void
1550 crcinit()
1551 {
1552         register int i, j;
1553         register long sum;
1554
1555         for (i = 0; i < 128; ++i) {
1556                 sum = 0L;
1557                 for (j = 7 - 1; j >= 0; --j)
1558                         if (i & (1 << j))
1559                                 sum ^= POLY >> j;
1560                 CrcTable[i] = sum;
1561         }
1562         DEBUG(("crcinit: done\n"));
1563 }
1564
1565 /*
1566  - hash - Honeyman's nice hashing function
1567  */
1568 static long
1569 hash(name, size)
1570 register char *name;
1571 register int size;
1572 {
1573         register long sum = 0L;
1574
1575         while (size--) {
1576                 sum = (sum >> 7) ^ CrcTable[(sum ^ (*name++)) & 0x7f];
1577         }
1578         DEBUG(("hash: returns (%ld)\n", sum));
1579         return(sum);
1580 }
1581
1582 /*
1583  * case-mapping stuff
1584  *
1585  * Borrowed from C News, by permission of the authors.  Somewhat modified.
1586  *
1587  * We exploit the fact that we are dealing only with headers here, and
1588  * headers are limited to the ASCII characters by RFC822.  It is barely
1589  * possible that we might be dealing with a translation into another
1590  * character set, but in particular it's very unlikely for a header
1591  * character to be outside -128..255.
1592  *
1593  * Life would be a whole lot simpler if tolower() could safely and portably
1594  * be applied to any char.
1595  */
1596
1597 #define OFFSET  128             /* avoid trouble with negative chars */
1598
1599 /* must call casencmp before invoking TOLOW... */
1600 #define TOLOW(c)        (cmap[(c)+OFFSET])
1601
1602 /* ...but the use of it in CISTREQN is safe without the preliminary call (!) */
1603 /* CISTREQN is an optimised case-insensitive strncmp(a,b,n)==0; n > 0 */
1604 #define CISTREQN(a, b, n) \
1605         (TOLOW((a)[0]) == TOLOW((b)[0]) && casencmp(a, b, n) == 0)
1606
1607 #define MAPSIZE (256+OFFSET)
1608 static char cmap[MAPSIZE];      /* relies on init to '\0' */
1609 static int mprimed = 0;         /* has cmap been set up? */
1610
1611 /*
1612  - mapprime - set up case-mapping stuff
1613  */
1614 static void
1615 mapprime()
1616 {
1617         register char *lp;
1618         register char *up;
1619         register int c;
1620         register int i;
1621         static char lower[] = "abcdefghijklmnopqrstuvwxyz";
1622         static char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1623
1624         for (lp = lower, up = upper; *lp != '\0'; lp++, up++) {
1625                 c = *lp;
1626                 cmap[c+OFFSET] = c;
1627                 cmap[*up+OFFSET] = c;
1628         }
1629         for (i = 0; i < MAPSIZE; i++)
1630                 if (cmap[i] == '\0')
1631                         cmap[i] = (char)(i-OFFSET);
1632         mprimed = 1;
1633 }
1634
1635 /*
1636  - casencmp - case-independent strncmp
1637  */
1638 static int                      /* < == > 0 */
1639 casencmp(s1, s2, len)
1640 char *s1;
1641 char *s2;
1642 int len;
1643 {
1644         register char *p1;
1645         register char *p2;
1646         register int n;
1647
1648         if (!mprimed)
1649                 mapprime();
1650
1651         p1 = s1;
1652         p2 = s2;
1653         n = len;
1654         while (--n >= 0 && *p1 != '\0' && TOLOW(*p1) == TOLOW(*p2)) {
1655                 p1++;
1656                 p2++;
1657         }
1658         if (n < 0)
1659                 return(0);
1660
1661         /*
1662          * The following case analysis is necessary so that characters
1663          * which look negative collate low against normal characters but
1664          * high against the end-of-string NUL.
1665          */
1666         if (*p1 == '\0' && *p2 == '\0')
1667                 return(0);
1668         else if (*p1 == '\0')
1669                 return(-1);
1670         else if (*p2 == '\0')
1671                 return(1);
1672         else
1673                 return(TOLOW(*p1) - TOLOW(*p2));
1674 }
1675
1676 /*
1677  - mapcase - do case-mapped copy
1678  */
1679 static char *                   /* returns src or dst */
1680 mapcase(dst, src, siz)
1681 char *dst;                      /* destination, used only if mapping needed */
1682 char *src;                      /* source; src == dst is legal */
1683 size_t siz;
1684 {
1685         register char *s;
1686         register char *d;
1687         register char *c;       /* case break */
1688         register char *e;       /* end of source */
1689
1690
1691         c = cipoint(src, siz);
1692         if (c == NULL)
1693                 return(src);
1694
1695         if (!mprimed)
1696                 mapprime();
1697         s = src;
1698         e = s + siz;
1699         d = dst;
1700
1701         while (s < c)
1702                 *d++ = *s++;
1703         while (s < e)
1704                 *d++ = TOLOW(*s++);
1705
1706         return(dst);
1707 }
1708
1709 /*
1710  - cipoint - where in this message-ID does it become case-insensitive?
1711  *
1712  * The RFC822 code is not quite complete.  Absolute, total, full RFC822
1713  * compliance requires a horrible parsing job, because of the arcane
1714  * quoting conventions -- abc"def"ghi is not equivalent to abc"DEF"ghi,
1715  * for example.  There are three or four things that might occur in the
1716  * domain part of a message-id that are case-sensitive.  They don't seem
1717  * to ever occur in real news, thank Cthulhu.  (What?  You were expecting
1718  * a merciful and forgiving deity to be invoked in connection with RFC822?
1719  * Forget it; none of them would come near it.)
1720  */
1721 static char *                   /* pointer into s, or NULL for "nowhere" */
1722 cipoint(s, siz)
1723 char *s;
1724 size_t siz;
1725 {
1726         register char *p;
1727         static char post[] = "postmaster";
1728         static int plen = sizeof(post)-1;
1729
1730         switch (conf.casemap) {
1731         case '0':               /* unmapped, sensible */
1732                 return(NULL);
1733                 break;
1734         case 'C':               /* C News, RFC 822 conformant (approx.) */
1735                 p = memchr(s, '@', siz);
1736                 if (p == NULL)                  /* no local/domain split */
1737                         return(NULL);           /* assume all local */
1738                 else if (p - (s+1) == plen && CISTREQN(s+1, post, plen)) {
1739                         /* crazy -- "postmaster" is case-insensitive */
1740                         return(s);
1741                 } else
1742                         return(p);
1743                 break;
1744         case '=':               /* 2.11, neither sensible nor conformant */
1745                 return(s);      /* all case-insensitive */
1746                 break;
1747         }
1748
1749         DEBUG(("cipoint: unknown case mapping `%c'\n", conf.casemap));
1750         return(NULL);           /* just leave it alone */
1751 }
1752
1753 /*
1754  - dbzdebug - control dbz debugging at run time
1755  */
1756 int                             /* old value */
1757 dbzdebug(value)
1758 int value;
1759 {
1760 #ifdef DBZDEBUG
1761         register int old = debug;
1762
1763         debug = value;
1764         return(old);
1765 #else
1766         return(-1);
1767 #endif
1768 }