diff --git a/cdb.c b/cdb.c new file mode 100644 index 0000000..ae5dcdd --- /dev/null +++ b/cdb.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include "cdb.h" + +/* Some things I use for debugging */ +#ifdef NODUMP +# define DUMPf(fmt, args...) +#else +# define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args) +#endif +#define DUMP() DUMPf("") +#define DUMP_u(v) DUMPf("%s = %u", #v, v) +#define DUMP_d(v) DUMPf("%s = %d", #v, v) +#define DUMP_x(v) DUMPf("%s = 0x%x", #v, v) +#define DUMP_s(v) DUMPf("%s = %s", #v, v) +#define DUMP_c(v) DUMPf("%s = %c", #v, v) +#define DUMP_p(v) DUMPf("%s = %p", #v, v) + +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif + +uint32_t +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; +} + +int +usage() +{ + fprintf(stderr, "Usage: infobot\n"); + + return 0; +} + +uint32_t +read_u32(FILE *f) +{ + uint8_t d[4]; + + fread(d, 4, 1, f); + return ((d[0]<< 0) | + (d[1] << 8) | + (d[2] << 16) | + (d[3] << 24)); +} + + +int +bufcmp(char *a, size_t alen, char *b, size_t blen) +{ + if (alen == blen) { + return memcmp(a, b, blen); + } else { + return alen - blen; + } +} + +void +cdb_init(struct cdb_ctx *ctx, FILE *f) +{ + ctx->f = f; + ctx->key = NULL; +} + +void +cdb_find(struct cdb_ctx *ctx, char *key, uint32_t keylen) +{ + ctx->hash_val = hash(key, keylen); + + ctx->key = key; + ctx->keylen = keylen; + + /* Read pointer */ + fseek(ctx->f, (ctx->hash_val % 256) * 8, SEEK_SET); + ctx->hash_pos = read_u32(ctx->f); + ctx->hash_len = read_u32(ctx->f); + ctx->entry = (ctx->hash_val / 256) % ctx->hash_len; +} + +uint32_t +cdb_next(struct cdb_ctx *ctx, char *buf, uint32_t buflen) +{ + uint32_t hashval; + uint32_t entry_pos; + uint32_t klen; + uint32_t dlen; + + for (;;) { + fseek(ctx->f, ctx->hash_pos + (ctx->entry++ * 8), SEEK_SET); + hashval = read_u32(ctx->f); + entry_pos = read_u32(ctx->f); + if (entry_pos == 0) { + break; + } + if (hashval != ctx->hash_val) { + continue; + } + + fseek(ctx->f, entry_pos, SEEK_SET); + klen = read_u32(ctx->f); + dlen = read_u32(ctx->f); + + 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; + } + + return fread(buf, 1, min(dlen, buflen), ctx->f); + } + } + + return 0; +} + + +int +main(int argc, char *argv[]) +{ + if (1 == argc) { + return usage(); + } + + { + struct cdb_ctx ctx; + char buf[8192]; + int32_t r; + + cdb_init(&ctx, stdin); + cdb_find(&ctx, argv[1], strlen(argv[1])); + while ((r = cdb_next(&ctx, buf, sizeof buf))) { + printf("%.*s\n", r, buf); + } + } + + return 0; +}