📄 dbz.c
字号:
} else (void) fclose(f); /* and let dbminit do the work */ return(dbminit(name));}/* - dbminit - open a database, creating it (using defaults) if necessary * * We try to leave errno set plausibly, to the extent that underlying * functions permit this, since many people consult it if dbminit() fails. */int /* 0 success, -1 failure */dbminit(name)char *name;{ register int i; register size_t s; register char *dirfname; register char *pagfname; if (pagf != NULL) { DEBUG(("dbminit: dbminit already called once\n")); errno = 0; return(-1); } /* open the .dir file */ dirfname = enstring(name, dir); if (dirfname == NULL) return(-1); dirf = fopen(dirfname, "r+"); if (dirf == NULL) { dirf = fopen(dirfname, "r"); dirronly = 1; } else dirronly = 0; free(dirfname); if (dirf == NULL) { DEBUG(("dbminit: can't open .dir file\n")); return(-1); } /* open the .pag file */ pagfname = enstring(name, pag); if (pagfname == NULL) { (void) fclose(dirf); return(-1); } pagf = fopen(pagfname, "r+b"); if (pagf == NULL) { pagf = fopen(pagfname, "rb"); if (pagf == NULL) { DEBUG(("dbminit: .pag open failed\n")); (void) fclose(dirf); free(pagfname); return(-1); } pagronly = 1; } else if (dirronly) pagronly = 1; else pagronly = 0;#ifdef NOBUFFER /* * B News does not do adequate locking on its database accesses. * Why it doesn't get into trouble using dbm is a mystery. In any * case, doing unbuffered i/o does not cure the problem, but does * enormously reduce its incidence. */ (void) setbuf(pagf, (char *)NULL);#else#ifdef _IOFBF (void) setvbuf(pagf, (char *)pagbuf, _IOFBF, sizeof(pagbuf));#endif#endif pagpos = -1; /* don't free pagfname, need it below */ /* open the base file */ basef = fopen(name, "r"); if (basef == NULL) { DEBUG(("dbminit: basefile open failed\n")); basefname = enstring(name, ""); if (basefname == NULL) { (void) fclose(pagf); (void) fclose(dirf); free(pagfname); pagf = NULL; return(-1); } } else basefname = NULL;#ifdef _IOFBF if (basef != NULL) (void) setvbuf(basef, basebuf, _IOFBF, sizeof(basebuf));#endif /* pick up configuration */ if (getconf(dirf, pagf, &conf) < 0) { DEBUG(("dbminit: getconf failure\n")); (void) fclose(basef); (void) fclose(pagf); (void) fclose(dirf); free(pagfname); pagf = NULL; errno = EDOM; /* kind of a kludge, but very portable */ return(-1); } tagbits = conf.tagmask << conf.tagshift; taghere = conf.tagenb << conf.tagshift; tagboth = tagbits | taghere; mybytemap(mybmap); bytesame = 1; for (i = 0; i < SOF; i++) if (mybmap[i] != conf.bytemap[i]) bytesame = 0; /* get first table into core, if it looks desirable and feasible */ s = (size_t)conf.tsize * SOF; if (incore && (off_t)(s/SOF) == conf.tsize) { bufpagf = fopen(pagfname, (pagronly) ? "rb" : "r+b"); if (bufpagf != NULL) corepag = getcore(bufpagf); } else { bufpagf = NULL; corepag = NULL; } free(pagfname); /* misc. setup */ crcinit(); written = 0; prevp = FRESH; DEBUG(("dbminit: succeeded\n")); return(0);}/* - enstring - concatenate two strings into a malloced area */static char * /* NULL if malloc fails */enstring(s1, s2)char *s1;char *s2;{ register char *p; p = malloc((size_t)strlen(s1) + (size_t)strlen(s2) + 1); if (p != NULL) { (void) strcpy(p, s1); (void) strcat(p, s2); } else { DEBUG(("enstring(%s, %s) out of memory\n", s1, s2)); } return(p);}/* - dbmclose - close a database */intdbmclose(){ register int ret = 0; if (pagf == NULL) { DEBUG(("dbmclose: not opened!\n")); return(-1); } if (fclose(pagf) == EOF) { DEBUG(("dbmclose: fclose(pagf) failed\n")); ret = -1; } pagf = basef; /* ensure valid pointer; dbzsync checks it */ if (dbzsync() < 0) ret = -1; if (bufpagf != NULL && fclose(bufpagf) == EOF) { DEBUG(("dbmclose: fclose(bufpagf) failed\n")); ret = -1; } if (corepag != NULL) free((char *)corepag); corepag = NULL; if (fclose(basef) == EOF) { DEBUG(("dbmclose: fclose(basef) failed\n")); ret = -1; } if (basefname != NULL) free(basefname); basef = NULL; pagf = NULL; if (fclose(dirf) == EOF) { DEBUG(("dbmclose: fclose(dirf) failed\n")); ret = -1; } DEBUG(("dbmclose: %s\n", (ret == 0) ? "succeeded" : "failed")); return(ret);}/* - dbzsync - push all in-core data out to disk */intdbzsync(){ register int ret = 0; if (pagf == NULL) { DEBUG(("dbzsync: not opened!\n")); return(-1); } if (!written) return(0); if (corepag != NULL) { if (putcore(corepag, bufpagf) < 0) { DEBUG(("dbzsync: putcore failed\n")); ret = -1; } } if (!conf.olddbz) if (putconf(dirf, &conf) < 0) ret = -1; DEBUG(("dbzsync: %s\n", (ret == 0) ? "succeeded" : "failed")); return(ret);}/* - dbzcancel - cancel writing of in-core data * Mostly for use from child processes. * Note that we don't need to futz around with stdio buffers, because we * always fflush them immediately anyway and so they never have stale data. */intdbzcancel(){ if (pagf == NULL) { DEBUG(("dbzcancel: not opened!\n")); return(-1); } written = 0; return(0);}/* - dbzfetch - fetch() with case mapping built in */datumdbzfetch(key)datum key;{ char buffer[DBZMAXKEY + 1]; datum mappedkey; register size_t keysize; DEBUG(("dbzfetch: (%s)\n", key.dptr)); /* Key is supposed to be less than DBZMAXKEY */ keysize = key.dsize; if (keysize >= DBZMAXKEY) { keysize = DBZMAXKEY; DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY)); } mappedkey.dptr = mapcase(buffer, key.dptr, keysize); buffer[keysize] = '\0'; /* just a debug aid */ mappedkey.dsize = keysize; return(fetch(mappedkey));}/* - fetch - get an entry from the database * * Disgusting fine point, in the name of backward compatibility: if the * last character of "key" is a NUL, that character is (effectively) not * part of the comparison against the stored keys. */datum /* dptr NULL, dsize 0 means failure */fetch(key)datum key;{ char buffer[DBZMAXKEY + 1]; static off_t key_ptr; /* return value points here */ datum output; register size_t keysize; register size_t cmplen; register char *sepp; DEBUG(("fetch: (%s)\n", key.dptr)); output.dptr = NULL; output.dsize = 0; prevp = FRESH; /* Key is supposed to be less than DBZMAXKEY */ keysize = key.dsize; if (keysize >= DBZMAXKEY) { keysize = DBZMAXKEY; DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY)); } if (pagf == NULL) { DEBUG(("fetch: database not open!\n")); return(output); } else if (basef == NULL) { /* basef didn't exist yet */ basef = latebase(); if (basef == NULL) return(output); } cmplen = keysize; sepp = &conf.fieldsep; if (key.dptr[keysize-1] == '\0') { cmplen--; sepp = &buffer[keysize-1]; } start(&srch, &key, FRESH); while ((key_ptr = search(&srch)) != NOTFOUND) { DEBUG(("got 0x%lx\n", key_ptr)); /* fetch the key */ if (fseek(basef, key_ptr, SEEK_SET) != 0) { DEBUG(("fetch: seek failed\n")); return(output); } if (fread(buffer, 1, keysize, basef) != keysize) { DEBUG(("fetch: read failed\n")); return(output); } /* try it */ buffer[keysize] = '\0'; /* terminated for DEBUG */ (void) mapcase(buffer, buffer, keysize); DEBUG(("fetch: buffer (%s) looking for (%s) size = %d\n", buffer, key.dptr, keysize)); if (memcmp(key.dptr, buffer, cmplen) == 0 && (*sepp == conf.fieldsep || *sepp == '\0')) { /* we found it */ output.dptr = (char *)&key_ptr; output.dsize = SOF; DEBUG(("fetch: successful\n")); return(output); } } /* we didn't find it */ DEBUG(("fetch: failed\n")); prevp = &srch; /* remember where we stopped */ return(output);}/* - latebase - try to open a base file that wasn't there at the start */static FILE *latebase(){ register FILE *it; if (basefname == NULL) { DEBUG(("latebase: name foulup\n")); return(NULL); } it = fopen(basefname, "r"); if (it == NULL) { DEBUG(("latebase: still can't open base\n")); } else { DEBUG(("latebase: late open succeeded\n")); free(basefname); basefname = NULL;#ifdef _IOFBF (void) setvbuf(it, basebuf, _IOFBF, sizeof(basebuf));#endif } return(it);}/* - dbzstore - store() with case mapping built in */intdbzstore(key, data)datum key;datum data;{ char buffer[DBZMAXKEY + 1]; datum mappedkey; register size_t keysize; DEBUG(("dbzstore: (%s)\n", key.dptr)); /* Key is supposed to be less than DBZMAXKEY */ keysize = key.dsize; if (keysize >= DBZMAXKEY) { DEBUG(("dbzstore: key size too big (%d)\n", key.dsize)); return(-1); } mappedkey.dptr = mapcase(buffer, key.dptr, keysize); buffer[keysize] = '\0'; /* just a debug aid */ mappedkey.dsize = keysize; return(store(mappedkey, data));}/* - store - add an entry to the database */int /* 0 success, -1 failure */store(key, data)datum key;datum data;{ off_t value; if (pagf == NULL) { DEBUG(("store: database not open!\n")); return(-1); } else if (basef == NULL) { /* basef didn't exist yet */ basef = latebase(); if (basef == NULL) return(-1); } if (pagronly) { DEBUG(("store: database open read-only\n")); return(-1); } if (data.dsize != SOF) { DEBUG(("store: value size wrong (%d)\n", data.dsize)); return(-1); } if (key.dsize >= DBZMAXKEY) { DEBUG(("store: key size too big (%d)\n", key.dsize)); return(-1); } /* copy the value in to ensure alignment */ (void) memcpy((char *)&value, data.dptr, SOF); DEBUG(("store: (%s, %ld)\n", key.dptr, (long)value)); if (!okayvalue(value)) { DEBUG(("store: reserved bit or overflow in 0x%lx\n", value)); return(-1); } /* find the place, exploiting previous search if possible */ start(&srch, &key, prevp); while (search(&srch) != NOTFOUND) continue; prevp = FRESH; conf.used[0]++; DEBUG(("store: used count %ld\n", conf.used[0])); written = 1; return(set(&srch, value));}/* - dbzincore - control attempts to keep .pag file in core */int /* old setting */dbzincore(value)int value;{ register int old = incore; incore = value; return(old);}/* - getconf - get configuration from .dir file */static int /* 0 success, -1 failure */getconf(df, pf, cp)register FILE *df; /* NULL means just give me the default */register FILE *pf; /* NULL means don't care about .pag */register struct dbzconfig *cp;{ register int c; register int i; int err = 0; c = (df != NULL) ? getc(df) : EOF; if (c == EOF) { /* empty file, no configuration known */ cp->olddbz = 0; if (df != NULL && pf != NULL && getc(pf) != EOF) cp->olddbz = 1; cp->tsize = DEFSIZE; cp->fieldsep = '\t'; for (i = 0; i < NUSEDS; i++) cp->used[i] = 0; cp->valuesize = SOF; mybytemap(cp->bytemap); cp->casemap = DEFCASE; cp->tagenb = TAGENB; cp->tagmask = TAGMASK; cp->tagshift = TAGSHIFT; DEBUG(("getconf: defaults (%ld, %c, (0x%lx/0x%lx<<%d))\n", cp->tsize, cp->casemap, cp->tagenb, cp->tagmask, cp->tagshift)); return(0); } (void) ungetc(c, df); /* first line, the vital stuff */ if (getc(df) != 'd' || getc(df) != 'b' || getc(df) != 'z') err = -1; if (getno(df, &err) != dbzversion) err = -1; cp->tsize = getno(df, &err); cp->fieldsep = getno(df, &err); while ((c = getc(df)) == ' ') continue; cp->casemap = c; cp->tagenb = getno(df, &err); cp->tagmask = getno(df, &err); cp->tagshift = getno(df, &err); cp->valuesize = getno(df, &err); if (cp->valuesize != SOF) { DEBUG(("getconf: wrong off_t size (%d)\n", cp->valuesize)); err = -1; cp->valuesize = SOF; /* to protect the loops below */ } for (i = 0; i < cp->valuesize; i++) cp->bytemap[i] = getno(df, &err); if (getc(df) != '\n') err = -1; DEBUG(("size %ld, sep %d, cmap %c, tags 0x%lx/0x%lx<<%d, ", cp->tsize, cp->fieldsep, cp->casemap, cp->tagenb, cp->tagmask, cp->tagshift)); DEBUG(("bytemap (%d)", cp->valuesize)); for (i = 0; i < cp->valuesize; i++) { DEBUG((" %d", cp->bytemap[i])); } DEBUG(("\n")); /* second line, the usages */ for (i = 0; i < NUSEDS; i++) cp->used[i] = getno(df, &err); if (getc(df) != '\n') err = -1; DEBUG(("used %ld %ld %ld...\n", cp->used[0], cp->used[1], cp->used[2])); if (err < 0) { DEBUG(("getconf error\n")); return(-1); } return(0);}/* - getno - get a long */static longgetno(f, ep)FILE *f;int *ep;{ register char *p;# define MAXN 50 char getbuf[MAXN]; register int c; while ((c = getc(f)) == ' ') continue; if (c == EOF || c == '\n') { DEBUG(("getno: missing number\n")); *ep = -1; return(0); } p = getbuf; *p++ = c; while ((c = getc(f)) != EOF && c != '\n' && c != ' ') if (p < &getbuf[MAXN-1]) *p++ = c; if (c == EOF) { DEBUG(("getno: EOF\n")); *ep = -1; } else (void) ungetc(c, f); *p = '\0'; if (strspn(getbuf, "-1234567890") != strlen(getbuf)) { DEBUG(("getno: `%s' non-numeric\n", getbuf));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -