home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume19 / cnews2 / pch15apr90 < prev    next >
Internet Message Format  |  1990-06-07  |  47KB

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