Annotation of GNUtools/libg++/libio/dbz/dbz.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.