irc-bot/cdb.c

181 lines
3.5 KiB
C
Raw Normal View History

2012-11-09 22:55:45 -07:00
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "cdb.h"
2012-11-20 18:13:16 -07:00
#include "dump.h"
2012-11-09 22:55:45 -07:00
2012-11-19 14:53:00 -07:00
/*
*
* CDB Interface
*
*/
/* Why I am using stdio.h
* By Neale Pickett
* November, 2012
*
* I am not as clever as the people who maintain libc.
*
* THE END
*/
2012-11-09 22:55:45 -07:00
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
2012-11-19 14:53:00 -07:00
static uint32_t
2012-11-09 22:55:45 -07:00
hash(char *s, size_t len)
{
uint32_t h = 5381;
size_t i;
for (i = 0; i < len; i += 1) {
h = ((h << 5) + h) ^ s[i];
}
return h;
}
2012-11-19 14:53:00 -07:00
static uint32_t
read_u32le(FILE *f)
2012-11-09 22:55:45 -07:00
{
uint8_t d[4];
fread(d, 4, 1, f);
return ((d[0]<< 0) |
(d[1] << 8) |
(d[2] << 16) |
(d[3] << 24));
}
2012-11-20 18:13:16 -07:00
static uint32_t
read_buf(FILE *f, uint32_t fieldlen, char *buf, size_t buflen)
{
uint32_t size = min(buflen, fieldlen);
size_t r = fread(buf, 1, (size_t)size, f);
// Slurp up the rest
for (fieldlen -= r; fieldlen > 0; fieldlen -= 1) {
getc(f);
}
return size;
}
2012-11-09 22:55:45 -07:00
void
cdb_init(struct cdb_ctx *ctx, FILE *f)
{
ctx->f = f;
ctx->key = NULL;
2012-11-20 18:13:16 -07:00
ctx->hash_len = 1;
2012-11-09 22:55:45 -07:00
}
2012-11-20 18:13:16 -07:00
int
cdb_dump(struct cdb_ctx *ctx,
char *key, size_t *keylen,
char *val, size_t *vallen)
2012-11-09 22:55:45 -07:00
{
2012-11-20 18:13:16 -07:00
// Set hash_len to 0 to signal we're in position
if (ctx->hash_len != 0) {
// Find out where to stop reading
int i;
ctx->hash_len = 0;
ctx->hash_pos = 0xffffffff;
for (i = 0; i < 256; i += 1) {
uint32_t p;
fseek(ctx->f, i * 8, SEEK_SET);
p = read_u32le(ctx->f);
if (p < ctx->hash_pos) {
ctx->hash_pos = p;
}
}
fseek(ctx->f, 256 * 8, SEEK_SET);
} else {
long where = ftell(ctx->f);
2012-11-09 22:55:45 -07:00
2012-11-20 18:13:16 -07:00
if (where >= ctx->hash_pos) {
return EOF;
}
}
// Read the two buffers
{
uint32_t klen = read_u32le(ctx->f);
uint32_t vlen = read_u32le(ctx->f);
*keylen = read_buf(ctx->f, klen, key, *keylen);
*vallen = read_buf(ctx->f, vlen, val, *vallen);
}
return 0;
}
void
cdb_find(struct cdb_ctx *ctx, char *key, size_t keylen)
{
2012-11-09 22:55:45 -07:00
ctx->key = key;
ctx->keylen = keylen;
2012-11-20 18:13:16 -07:00
ctx->hash_val = hash(key, keylen);
// Read pointer
2012-11-09 22:55:45 -07:00
fseek(ctx->f, (ctx->hash_val % 256) * 8, SEEK_SET);
2012-11-19 14:53:00 -07:00
ctx->hash_pos = read_u32le(ctx->f);
ctx->hash_len = read_u32le(ctx->f);
2012-11-09 22:55:45 -07:00
ctx->entry = (ctx->hash_val / 256) % ctx->hash_len;
}
uint32_t
2012-11-20 18:13:16 -07:00
cdb_next(struct cdb_ctx *ctx, char *buf, size_t buflen)
2012-11-09 22:55:45 -07:00
{
uint32_t hashval;
uint32_t entry_pos;
uint32_t klen;
uint32_t dlen;
for (;;) {
2012-11-19 14:53:00 -07:00
fseek(ctx->f, ctx->hash_pos + (ctx->entry * 8), SEEK_SET);
ctx->entry = (ctx->entry + 1) % ctx->hash_len;
hashval = read_u32le(ctx->f);
entry_pos = read_u32le(ctx->f);
2012-11-09 22:55:45 -07:00
if (entry_pos == 0) {
break;
}
if (hashval != ctx->hash_val) {
continue;
}
fseek(ctx->f, entry_pos, SEEK_SET);
2012-11-19 14:53:00 -07:00
klen = read_u32le(ctx->f);
dlen = read_u32le(ctx->f);
2012-11-09 22:55:45 -07:00
if (klen == ctx->keylen) {
uint32_t i;
for (i = 0; i < klen; i += 1) {
int c = fgetc(ctx->f);
if (c != ctx->key[i]) {
break;
}
}
if (i < klen) {
continue;
}
2012-11-19 14:53:00 -07:00
if (buf) {
2012-11-20 18:13:16 -07:00
return read_buf(ctx->f, dlen, buf, buflen);
2012-11-19 14:53:00 -07:00
} else {
return dlen;
}
2012-11-09 22:55:45 -07:00
}
}
return 0;
}